diff --git a/V203F6P6/ch32v203/usart.cpp b/V203F6P6/ch32v203/usart.cpp new file mode 100644 index 0000000..7595481 --- /dev/null +++ b/V203F6P6/ch32v203/usart.cpp @@ -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 auto { + r.B.RE = RESET; + r.B.TCIE = SET; // po povolení přerušení okamžitě přeruší + return r.R; + }); + return n; +} + diff --git a/V203F6P6/common/usart.h b/V203F6P6/common/usart.h index 7ae814c..9c761e5 100644 --- a/V203F6P6/common/usart.h +++ b/V203F6P6/common/usart.h @@ -5,17 +5,18 @@ /** @class Usart * @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 { FIFO tx_ring; public: explicit Usart (const uint32_t baud = 9600) noexcept; uint32_t Down (const char * data, const uint32_t len) override; - void SetRS485 (const bool polarity) const; - - void irq (void); - void SetHalfDuplex (const bool on) const; + + void irq (void); }; #endif // USART_H diff --git a/V203F6P6/usart/Makefile b/V203F6P6/usart/Makefile new file mode 100644 index 0000000..20bee8e --- /dev/null +++ b/V203F6P6/usart/Makefile @@ -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 diff --git a/V203F6P6/usart/ch32v203 b/V203F6P6/usart/ch32v203 new file mode 120000 index 0000000..7650c85 --- /dev/null +++ b/V203F6P6/usart/ch32v203 @@ -0,0 +1 @@ +../ch32v203/ \ No newline at end of file diff --git a/V203F6P6/usart/common b/V203F6P6/usart/common new file mode 120000 index 0000000..8332399 --- /dev/null +++ b/V203F6P6/usart/common @@ -0,0 +1 @@ +../common/ \ No newline at end of file diff --git a/V203F6P6/usart/main.cpp b/V203F6P6/usart/main.cpp new file mode 100644 index 0000000..191eb7a --- /dev/null +++ b/V203F6P6/usart/main.cpp @@ -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