add usart
This commit is contained in:
parent
10092fa305
commit
b122c8a79b
6 changed files with 210 additions and 5 deletions
90
V203F6P6/ch32v203/usart.cpp
Normal file
90
V203F6P6/ch32v203/usart.cpp
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#include "system.h"
|
||||||
|
#include "usart.h"
|
||||||
|
static Usart * pInstance = nullptr;
|
||||||
|
static constexpr unsigned HCLK = SYSTEM_CORE_CLOCK >> 1;
|
||||||
|
extern "C" {
|
||||||
|
[[gnu::interrupt]] extern void USART2_IRQHandler (void);
|
||||||
|
};
|
||||||
|
void USART2_IRQHandler (void) {
|
||||||
|
if (pInstance) pInstance->irq();
|
||||||
|
};
|
||||||
|
|
||||||
|
Usart::Usart(const uint32_t _baud) noexcept : BaseLayer (), tx_ring () {
|
||||||
|
pInstance = this;
|
||||||
|
// 1. Clock Enable
|
||||||
|
RCC.APB1PCENR.B.USART2EN = SET;
|
||||||
|
RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto {
|
||||||
|
r.B.IOPAEN = SET;
|
||||||
|
r.B.IOPBEN = SET;
|
||||||
|
//r.B.AFIOEN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// 2. GPIO Alternate Config - default TX/PA2, RX/PA3, DEN/PB1 (TXEN=H)
|
||||||
|
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.MODE2 = 1u;
|
||||||
|
r.B.CNF2 = 2u; // or 3u for open drain
|
||||||
|
r.B.MODE3 = 0u;
|
||||||
|
r.B.CNF3 = 1u; // floating input
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
GPIOB.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.MODE1 = 1u;
|
||||||
|
r.B.CNF1 = 0u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
RCC.APB1PRSTR.B.USART2RST = SET;
|
||||||
|
RCC.APB1PRSTR.B.USART2RST = RESET;
|
||||||
|
// 5. USART registry 8.bit bez parity
|
||||||
|
USART2.CTLR1.modify([] (USART1_Type::CTLR1_DEF & r) -> auto {
|
||||||
|
r.B.RE = SET;
|
||||||
|
r.B.TE = SET;
|
||||||
|
r.B.RXNEIE = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
USART2.CTLR2.modify ([](USART1_Type::CTLR2_DEF & r) -> auto {
|
||||||
|
r.B.STOP = 0u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
const uint32_t tmp = HCLK / _baud;
|
||||||
|
USART2.BRR.R = tmp;
|
||||||
|
// NVIC
|
||||||
|
NVIC.EnableIRQ (USART2_IRQn);
|
||||||
|
USART2.CTLR1.B.UE = SET; // nakonec povolit globálně
|
||||||
|
}
|
||||||
|
void Usart::irq () {
|
||||||
|
volatile USART1_Type::STATR_DEF status (USART2.STATR); // načti status přerušení
|
||||||
|
char rdata, tdata;
|
||||||
|
|
||||||
|
if (status.B.TC) { // od vysílače
|
||||||
|
if (tx_ring.Read (tdata)) { // pokud máme data
|
||||||
|
USART2.DATAR.B.DR = (uint8_t) tdata; // zapíšeme do výstupu
|
||||||
|
} else { // pokud ne
|
||||||
|
// Předpoklad je half-duplex i.e. RS485, jinak jen zakázat TCIE
|
||||||
|
rdata = (USART2.DATAR.B.DR); // dummy read
|
||||||
|
USART2.CTLR1.modify([](USART1_Type::CTLR1_DEF & r) -> auto {
|
||||||
|
r.B.RE = SET; // povol prijem
|
||||||
|
r.B.TCIE = RESET; // je nutné zakázat přerušení od vysílače
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
GPIOB.BSHR.B.BR1 = SET; // ukončit vysílání na linku
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status.B.RXNE) { // od přijímače
|
||||||
|
rdata = (USART2.DATAR.B.DR); // načteme data
|
||||||
|
Up (&rdata, 1u); // a pošleme dál
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t Usart::Down(const char * data, const uint32_t len) {
|
||||||
|
unsigned n = 0u;
|
||||||
|
for (n=0u; n<len; n++) {
|
||||||
|
if (!tx_ring.Write(data[n])) break;
|
||||||
|
}
|
||||||
|
GPIOB.BSHR.B.BS1 = SET; // nastavit vysílání na linku
|
||||||
|
USART2.CTLR1.modify([](USART1_Type::CTLR1_DEF & r) -> auto {
|
||||||
|
r.B.RE = RESET;
|
||||||
|
r.B.TCIE = SET; // po povolení přerušení okamžitě přeruší
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
|
@ -5,17 +5,18 @@
|
||||||
/** @class Usart
|
/** @class Usart
|
||||||
* @brief Sériový port.
|
* @brief Sériový port.
|
||||||
*
|
*
|
||||||
* Zde RS485, jen výstup.
|
* Zde RS485, vstup i výstup.
|
||||||
|
* Při vysílání je zakázán příjem a to jak v software, tak v hardware.
|
||||||
|
* Tady u toho typu je pin řízení směru přenosu dělán čistě softwarově,
|
||||||
|
* překrytí je minimální, zdá se že to nevadí.
|
||||||
*/
|
*/
|
||||||
class Usart : public BaseLayer {
|
class Usart : public BaseLayer {
|
||||||
FIFO<char, 64> tx_ring;
|
FIFO<char, 64> tx_ring;
|
||||||
public:
|
public:
|
||||||
explicit Usart (const uint32_t baud = 9600) noexcept;
|
explicit Usart (const uint32_t baud = 9600) noexcept;
|
||||||
uint32_t Down (const char * data, const uint32_t len) override;
|
uint32_t Down (const char * data, const uint32_t len) override;
|
||||||
void SetRS485 (const bool polarity) const;
|
|
||||||
|
void irq (void);
|
||||||
void irq (void);
|
|
||||||
void SetHalfDuplex (const bool on) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // USART_H
|
#endif // USART_H
|
||||||
|
|
53
V203F6P6/usart/Makefile
Normal file
53
V203F6P6/usart/Makefile
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
TARGET?= ch32v203
|
||||||
|
|
||||||
|
TOOL ?= gcc
|
||||||
|
#TOOL ?= clang
|
||||||
|
|
||||||
|
PRJ = example
|
||||||
|
|
||||||
|
VPATH = . ./$(TARGET) ./common
|
||||||
|
BLD = ./build/
|
||||||
|
DFLAGS = -d
|
||||||
|
LFLAGS = -g
|
||||||
|
LDLIBS =
|
||||||
|
BFLAGS = --strip-unneeded
|
||||||
|
|
||||||
|
CFLAGS = -MMD -Wall -Wno-parentheses -ggdb -fno-exceptions -ffunction-sections -fdata-sections
|
||||||
|
CFLAGS+= -I. -I./$(TARGET) -I./common
|
||||||
|
DEL = rm -f
|
||||||
|
|
||||||
|
# zdrojaky
|
||||||
|
OBJS = main.o usart.o print.o
|
||||||
|
#OBJS +=
|
||||||
|
|
||||||
|
include $(TARGET)/$(TOOL).mk
|
||||||
|
BOBJS = $(addprefix $(BLD),$(OBJS))
|
||||||
|
|
||||||
|
all: $(BLD) $(PRJ).elf
|
||||||
|
# ... atd.
|
||||||
|
-include $(BLD)*.d
|
||||||
|
# linker
|
||||||
|
$(PRJ).elf: $(BOBJS)
|
||||||
|
-@echo [LD $(TOOL),$(TARGET)] $@
|
||||||
|
@$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(LDLIBS)
|
||||||
|
-@echo "size:"
|
||||||
|
@$(SIZE) $(PRJ).elf
|
||||||
|
-@echo "listing:"
|
||||||
|
$(DUMP) $(DFLAGS) $(PRJ).elf > $(PRJ).lst
|
||||||
|
-@echo "OK."
|
||||||
|
$(COPY) $(BFLAGS) -O binary $(PRJ).elf $(PRJ).bin
|
||||||
|
# preloz co je potreba
|
||||||
|
$(BLD)%.o: %.c
|
||||||
|
-@echo [CC $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CC) -std=gnu99 -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD)%.o: %.cpp
|
||||||
|
-@echo [CX $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD):
|
||||||
|
mkdir $(BLD)
|
||||||
|
flash: $(PRJ).elf
|
||||||
|
minichlink -w $(PRJ).bin flash -b
|
||||||
|
# vycisti
|
||||||
|
clean:
|
||||||
|
$(DEL) $(BLD)* *.lst *.bin *.elf *.map *~
|
||||||
|
.PHONY: all clean flash run
|
1
V203F6P6/usart/ch32v203
Symbolic link
1
V203F6P6/usart/ch32v203
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../ch32v203/
|
1
V203F6P6/usart/common
Symbolic link
1
V203F6P6/usart/common
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../common/
|
59
V203F6P6/usart/main.cpp
Normal file
59
V203F6P6/usart/main.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include "system.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "usart.h"
|
||||||
|
#include "print.h"
|
||||||
|
/*********************************************************************************
|
||||||
|
Sériový port na CH32V203F6P6 je příklad jak by z dokumentace člověka klepla pepka.
|
||||||
|
Podle DS to má jen jeden sériový port, ale vývody USART1 nejsou nijak vyvedeny
|
||||||
|
z pouzdra. Tak zkusíte USART2, a ejhle, ono to funguje.
|
||||||
|
**********************************************************************************/
|
||||||
|
#if 0
|
||||||
|
class TEST : public BaseLayer { // Testovací třída pro test příjmu - OK.
|
||||||
|
static constexpr unsigned buflen = 64u;
|
||||||
|
char buffer [buflen];
|
||||||
|
unsigned rx_index;
|
||||||
|
GpioClass & led;
|
||||||
|
public:
|
||||||
|
explicit TEST (GpioClass & io) noexcept : BaseLayer(), rx_index(0u), led(io) {}
|
||||||
|
uint32_t Up(const char * data, const uint32_t len) override {
|
||||||
|
for (unsigned n=0u; n<len; n++) {
|
||||||
|
const char c = data [n];
|
||||||
|
if (c == '\r') { // Enter
|
||||||
|
Down ("\r\n", 2);
|
||||||
|
Down (buffer, rx_index); // Vrátí obsah bufferu na novém řádku
|
||||||
|
Down ("\r\n", 2);
|
||||||
|
rx_index = 0u;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buffer [rx_index] = c;
|
||||||
|
const bool b = rx_index & 1u;
|
||||||
|
led << b; // Po každém znaku změní stav
|
||||||
|
rx_index += 1u;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
static constexpr unsigned timeout = 100'000;
|
||||||
|
static GpioClass led (GPIOB, 8);
|
||||||
|
static Usart serial (57600);
|
||||||
|
static Print cout;
|
||||||
|
//static TEST test (led);
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
led << true;
|
||||||
|
delay_init();
|
||||||
|
//test += serial;
|
||||||
|
cout += serial;
|
||||||
|
int passcnt = 0;
|
||||||
|
for (;;) {
|
||||||
|
delay_us(timeout);
|
||||||
|
|
||||||
|
cout << "pass : " << passcnt << EOL;
|
||||||
|
const bool b = passcnt & 1;
|
||||||
|
led << b;
|
||||||
|
passcnt += 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue