From 07c30fffc8d403378c173a40f54d756778ce5ae3 Mon Sep 17 00:00:00 2001 From: Kizarm Date: Tue, 15 Oct 2024 19:26:19 +0200 Subject: [PATCH] add cdc usart --- V203/usb/ch32v203/usart.cpp | 89 +++++++++++++++++++++++++++++++++ V203/usb/common/ctrlinterface.h | 1 + V203/usb/common/mirror.h | 60 ++++++++++++++++++++++ V203/usb/common/usart.h | 22 ++++++++ V203/usb/usart/Makefile | 52 +++++++++++++++++++ V203/usb/usart/ch32v203 | 1 + V203/usb/usart/common | 1 + V203/usb/usart/hack.c | 21 ++++++++ V203/usb/usart/main.cpp | 25 +++++++++ V203/usb/usart/test/Makefile | 24 +++++++++ V203/usb/usart/test/baud.cpp | 14 ++++++ V203/usb/usart/test/main.cpp | 45 +++++++++++++++++ V203/usb/usart/test/usart.cpp | 84 +++++++++++++++++++++++++++++++ V203/usb/usart/test/usart.h | 32 ++++++++++++ V203/usb/usart/usb_desc.cpp | 83 ++++++++++++++++++++++++++++++ V203/usb/usart/usb_desc.h | 66 ++++++++++++++++++++++++ 16 files changed, 620 insertions(+) create mode 100644 V203/usb/ch32v203/usart.cpp create mode 100644 V203/usb/common/mirror.h create mode 100644 V203/usb/common/usart.h create mode 100644 V203/usb/usart/Makefile create mode 120000 V203/usb/usart/ch32v203 create mode 120000 V203/usb/usart/common create mode 100644 V203/usb/usart/hack.c create mode 100644 V203/usb/usart/main.cpp create mode 100644 V203/usb/usart/test/Makefile create mode 100644 V203/usb/usart/test/baud.cpp create mode 100644 V203/usb/usart/test/main.cpp create mode 100644 V203/usb/usart/test/usart.cpp create mode 100644 V203/usb/usart/test/usart.h create mode 100644 V203/usb/usart/usb_desc.cpp create mode 100644 V203/usb/usart/usb_desc.h diff --git a/V203/usb/ch32v203/usart.cpp b/V203/usb/ch32v203/usart.cpp new file mode 100644 index 0000000..30c17a8 --- /dev/null +++ b/V203/usb/ch32v203/usart.cpp @@ -0,0 +1,89 @@ +#include "system.h" +#include "../common/usart.h" +static Usart * pInstance = nullptr; + +extern "C" { + [[gnu::interrupt]] void USART1_IRQHandler (void); +}; +void USART1_IRQHandler (void) { + if (pInstance) pInstance->irq(); +}; + +Usart::Usart(const uint32_t _baud) noexcept : BaseLayer (), tx_ring () { + pInstance = this; + // 1. Clock Enable + RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto { + r.B.USART1EN = SET; + r.B.IOPAEN = SET; + //r.B.AFIOEN = SET; // není nutné + return r.R; + }); + // 2. GPIO Alternate Config - default TX/PA9, RX/PA10 + GPIOA.CFGHR.modify([](GPIOA_Type::CFGHR_DEF & r) -> auto { + r.B.MODE9 = 1u; + r.B.CNF9 = 2u; // or 3u for open drain + r.B.MODE10 = 0u; + r.B.CNF10 = 1u; // floating input + return r.R; + }); + RCC.APB2PRSTR.B.USART1RST = SET; + RCC.APB2PRSTR.B.USART1RST = RESET; + // 5. USART registry 8.bit bez parity + USART1.CTLR1.modify([] (USART1_Type::CTLR1_DEF & r) -> auto { + r.B.RE = SET; + r.B.TE = SET; + r.B.RXNEIE = SET; + return r.R; + }); + USART1.CTLR2.modify ([](USART1_Type::CTLR2_DEF & r) -> auto { + r.B.STOP = 0u; + return r.R; + }); + SetBaud(_baud); + // NVIC + NVIC.EnableIRQ (USART1_IRQn); + USART1.CTLR1.B.UE = SET; // nakonec povolit globálně +} +void Usart::irq () { + volatile USART1_Type::STATR_DEF status (USART1.STATR); // načti status přerušení + char rdata, tdata; + + if (status.B.TXE) { // od vysílače + if (tx_ring.Read (tdata)) { // pokud máme data + USART1.DATAR.B.DR = (uint8_t) tdata; // zapíšeme do výstupu + } else { // pokud ne + USART1.CTLR1.B.TXEIE = RESET; + } + } + if (status.B.RXNE) { // od přijímače + rdata = (USART1.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(data); + SetBaud(lc->baud); // Pouze změníme rychlost, ostatní parametry ingorujme + } return true; + // Ostatní IOCtrl zatím nebudeme obsluhovat, je to celkem zbytečné + default : break; + }; + return false; +} diff --git a/V203/usb/common/ctrlinterface.h b/V203/usb/common/ctrlinterface.h index 291407a..ca6bc9d 100644 --- a/V203/usb/common/ctrlinterface.h +++ b/V203/usb/common/ctrlinterface.h @@ -7,6 +7,7 @@ enum CTRL_TYPES_DEF { USB_USART_SET_DTR_RTS, USB_USART_INIT, }; +static_assert (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, "Bad ENDIAN"); struct USB_CDC_LineCoding { uint32_t baud; uint8_t stop, parity, data; diff --git a/V203/usb/common/mirror.h b/V203/usb/common/mirror.h new file mode 100644 index 0000000..26f48ce --- /dev/null +++ b/V203/usb/common/mirror.h @@ -0,0 +1,60 @@ +#ifndef MIRROR_H +#define MIRROR_H + +#include +#include "baselayer.h" + +/** + * @file + * @brief Obraceč datového toku. + * @class Mirror + * @brief Obraceč datového toku má 2 třídy. + * + * TwoTop je vlastní obraceč, dědí vlastnosti BaseLayer, pouze metoda Up je přetížena - + * to je to vlastní převrácení. Hlavní třída Mirror, jejíž instance je pak v kódu použita + * obsahuje 2 rovnocenné instance třídy TwoTop, které musí být ve stacku vždy navrchu. + * První část stacku volá Up jedné instance, druhá Up té druhé. Proto tam musí být dvě. + * Podobně by šel udělat něco jako Fork, odbočení datového toku. + + * A zase - všechny metody jsou tak jednoduché, že jsou celé v hlavičce, tedy inline. + * + * @class TwoTop + * @brief Vlastní obraceč. + * Ono to vypadá hodně zmateně, ale používá se to snadno - dokonce to funguje. + * +*/ + +class TwoTop : public BaseLayer { + public: + /// Konstruktor + explicit TwoTop () noexcept : BaseLayer (), x (nullptr) {}; + /// Setter pro x + void setX (BaseLayer & bl) { x = & bl; }; + /// Přetížení metody Up, nic jiného není potřeba + uint32_t Up (const char* data, uint32_t len) { + if (!x) return 0; // pro jistotu + // To, co přišlo zespoda, pošlu druhou instancí zase dolů + return x->Down (data, len); + }; + private: + /// Fakticky ukazatel na druhou instanci TwoTop + BaseLayer * x; +}; + +class Mirror { + public: + /// Konstruktor + explicit Mirror () noexcept : L(), R() { + L.setX (R); R.setX (L); + }; + /** + Zřetězení voláme 2x. Poprvé pro jednu +=, podruhé -= pro druhou instanci TwoTop. + Protože je tato třída navrchu (vlevo), operátor nic nevrací. + */ + void operator += (BaseLayer& bl) { L += bl; return; }; + void operator -= (BaseLayer& bl) { R += bl; return; }; + private: + TwoTop L, R; //!< 2 instance Top +}; + +#endif // MIRROR_H diff --git a/V203/usb/common/usart.h b/V203/usb/common/usart.h new file mode 100644 index 0000000..6fc190e --- /dev/null +++ b/V203/usb/common/usart.h @@ -0,0 +1,22 @@ +#ifndef USART_H +#define USART_H +#include "fifo.h" +#include "baselayer.h" +#include "ctrlinterface.h" +/** @class Usart + * @brief Sériový port. + * + */ +class Usart : public BaseLayer, public CDC_CtrlInterface { + FIFO tx_ring; + public: + explicit Usart (const uint32_t baud = 9600) noexcept; + uint32_t Down (const char * data, const uint32_t len) override; + void SetBaud (const uint32_t baud) const; + // Obsluha přerušení musí být veřejná. + void irq (void); + // Přetížení pro CDC. + bool IOCtrl (const CTRL_TYPES_DEF type, const void * data, const uint32_t len) override; +}; + +#endif // USART_H diff --git a/V203/usb/usart/Makefile b/V203/usb/usart/Makefile new file mode 100644 index 0000000..b4d75db --- /dev/null +++ b/V203/usb/usart/Makefile @@ -0,0 +1,52 @@ +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 hack.o +OBJS += usb_desc.o cdc_class.o usart.o + +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/V203/usb/usart/ch32v203 b/V203/usb/usart/ch32v203 new file mode 120000 index 0000000..7650c85 --- /dev/null +++ b/V203/usb/usart/ch32v203 @@ -0,0 +1 @@ +../ch32v203/ \ No newline at end of file diff --git a/V203/usb/usart/common b/V203/usb/usart/common new file mode 120000 index 0000000..8332399 --- /dev/null +++ b/V203/usb/usart/common @@ -0,0 +1 @@ +../common/ \ No newline at end of file diff --git a/V203/usb/usart/hack.c b/V203/usb/usart/hack.c new file mode 100644 index 0000000..391b7bf --- /dev/null +++ b/V203/usb/usart/hack.c @@ -0,0 +1,21 @@ +#include +#include +typedef __SIZE_TYPE__ size_t; +size_t strlen (const char *s) { + size_t l = 0; + while (*s++) l++; + return l; +} +void *memcpy (void *dest, const void *src, size_t n) { + const char *s = (const char *) src; + char *d = (char *) dest; + int i; + for (i=0; i +#include +#include "usart.h" + +void UsartClass::setBaud (int baud) { + struct termios2 tio; + + ioctl(fd, TCGETS2, &tio); + tio.c_cflag &= ~CBAUD; + tio.c_cflag |= BOTHER; + tio.c_ispeed = baud; + tio.c_ospeed = baud; + ioctl(fd, TCSETS2, &tio); +} diff --git a/V203/usb/usart/test/main.cpp b/V203/usb/usart/test/main.cpp new file mode 100644 index 0000000..91f80ca --- /dev/null +++ b/V203/usb/usart/test/main.cpp @@ -0,0 +1,45 @@ +#include "usart.h" +#include +#include +#include + +class Top : public BaseLayer { + static constexpr int max = 1024; + volatile unsigned index; + int passcnt; + char buffer [max]; + public: + explicit Top () : BaseLayer(), index(0u), passcnt(0) {} + void puts (const char * str) { + const unsigned l = strlen(str); + Down(str, l); + } + uint32_t Up(const char * data, const uint32_t len) override { + for (unsigned n=0; n +#include +#include +#include +#include +#include +#include +#include +#include "usart.h" + +UsartClass::UsartClass (const char * name, const int baudrate) : BaseLayer() { + id = name; + running = false; + fd = ::open (id, O_RDWR); + if (fd < 0) return; + + timeout = 12'000'000 / baudrate; // cca pro 1 byte + + struct termios LineFlags; + int attr = tcgetattr (fd, &LineFlags); + if (attr) { + printf ("Nelze zjistit parametry portu %s\r\n", name); + ::close (fd); + return; + } + // nastaveni komunikacnich parametru do struct termios + LineFlags.c_iflag = IGNPAR /* | IXON | IXOFF*/; // ignoruj chyby parity + LineFlags.c_oflag = 0; // normalni nastaveni + LineFlags.c_cflag = CS8 | CREAD | CLOCAL; // 8-bit, povol prijem + LineFlags.c_lflag = 0; // Raw input bez echa + LineFlags.c_cc [VMIN] = 1; // minimalni pocet znaku pro cteni + LineFlags.c_cc [VTIME] = 1; // read timeout 0.1 s + + tcsetattr (fd, TCSANOW, &LineFlags); + fcntl (fd, F_SETFL, 0); + + int flag = TIOCM_DTR; + ioctl(fd, TIOCMBIS, & flag); + + setBaud(baudrate); + + printf ("Port %s opened (%d) at %d Bd\r\n", id, fd, baudrate); + usleep (10000); + running = true; + pthread_create (&rc, NULL, UsartClass::UsartHandler, this); +} + +UsartClass::~UsartClass() { + running = false; + pthread_cancel (rc); + + int flag = TIOCM_DTR; + ioctl(fd, TIOCMBIC, & flag); + + ::close (fd); + printf ("Port %s closed\r\n", id); +} +uint32_t UsartClass::Up (const char * data, uint32_t len) { + return BaseLayer::Up (data, len); +} + +uint32_t UsartClass::Down (const char * data, uint32_t len) { + if (!running) return 0; + const unsigned maxchunk = 32; // USB bulk len (64) je moc + unsigned offset = 0, remain = len; + while (remain) { + const unsigned chunk = remain > maxchunk ? maxchunk : remain; + const unsigned writn = ::write (fd, data + offset, chunk); + usleep (timeout * writn); // závisí na baud rate + offset += writn; + remain -= writn; + } + return offset; +} + +void UsartClass::ReadLoop (void) { + int n; + while (running) { + // Nutno číst po jednom nebo použít timer, jinak to po prvním čtení zdechne. + n = ::read (fd, rxbuf, 1); + if (!n) continue; + Up (rxbuf, n); + } +} diff --git a/V203/usb/usart/test/usart.h b/V203/usb/usart/test/usart.h new file mode 100644 index 0000000..813c63f --- /dev/null +++ b/V203/usb/usart/test/usart.h @@ -0,0 +1,32 @@ +#ifndef USARTCLASS_H +#define USARTCLASS_H + +#include +#include "../common/baselayer.h" + +static constexpr unsigned BUFLEN = 1024u; +// Bottom +class UsartClass : public BaseLayer { + public: + UsartClass (const char* name, const int baudrate); + uint32_t Up (const char* data, uint32_t len); + uint32_t Down(const char* data, uint32_t len); + virtual ~UsartClass (); + protected: + void ReadLoop (void); + static void* UsartHandler (void* p) { + UsartClass* inst = (UsartClass*) p; + inst->ReadLoop(); + return nullptr; + }; + void setBaud (int baud); + public: + bool running; + private: + const char * id; //!< Identifikátor třídy pro ladění + char rxbuf[BUFLEN]; + int fd; + int timeout; + pthread_t rc; +}; +#endif // USARTCLASS_H diff --git a/V203/usb/usart/usb_desc.cpp b/V203/usb/usart/usb_desc.cpp new file mode 100644 index 0000000..c8bbca0 --- /dev/null +++ b/V203/usb/usart/usb_desc.cpp @@ -0,0 +1,83 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : usb_desc.c + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/20 + * Description : usb device descriptor,configuration descriptor, + * string descriptors and other descriptors. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#include "usb_desc.h" + +/* Device Descriptor */ +const uint8_t MyDevDescr[] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x10, 0x01, // bcdUSB 1.10 + 0x02, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + DEF_USBD_UEP0_SIZE, // bMaxPacketSize0 64 + (uint8_t)DEF_USB_VID, (uint8_t)(DEF_USB_VID >> 8), // idVendor 0x1A86 + (uint8_t)DEF_USB_PID, (uint8_t)(DEF_USB_PID >> 8), // idProduct 0x5537 + DEF_IC_PRG_VER, 0x00, // bcdDevice 0.01 + 0x01, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x03, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +/* Configuration Descriptor */ +const uint8_t MyCfgDescr[] = +{ + /* Configure descriptor */ + 0x09, 0x02, 0x43, 0x00, 0x02, 0x01, 0x00, 0x80, 0x32, + + /* Interface 0 (CDC) descriptor */ + 0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x01, 0x00, + + /* Functional Descriptors */ + 0x05, 0x24, 0x00, 0x10, 0x01, + + /* Length/management descriptor (data class interface 1) */ + 0x05, 0x24, 0x01, 0x00, 0x01, + 0x04, 0x24, 0x02, 0x02, + 0x05, 0x24, 0x06, 0x00, 0x01, + + /* Interrupt upload endpoint descriptor */ + 0x07, 0x05, 0x81, 0x03, (uint8_t)DEF_USBD_ENDP1_SIZE, (uint8_t)( DEF_USBD_ENDP1_SIZE >> 8 ), 0x01, + + /* Interface 1 (data interface) descriptor */ + 0x09, 0x04, 0x01, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00, + + /* Endpoint descriptor */ + 0x07, 0x05, 0x02, 0x02, (uint8_t)DEF_USBD_ENDP2_SIZE, (uint8_t)( DEF_USBD_ENDP2_SIZE >> 8 ), 0x00, + + /* Endpoint descriptor */ + 0x07, 0x05, 0x83, 0x02, (uint8_t)DEF_USBD_ENDP3_SIZE, (uint8_t)( DEF_USBD_ENDP3_SIZE >> 8 ), 0x00, +}; +#define DEF_STRDESC(p,n) w_text<(sizeof(p)>>1)>n={sizeof(n)-2u,3u,{p}} +template struct w_text { + uint8_t len, typ; + const char16_t str [N]; +}; +static const DEF_STRDESC((u"Kizarm Labs."), str_1); +static const DEF_STRDESC((u"USB <=> USART"),str_2); +static const DEF_STRDESC((u"0002"), str_3); +/* Language Descriptor */ +static const uint8_t LangDescr[] = { + 0x04, 0x03, 0x09, 0x04 +}; +const uint8_t * StringDescArray [DEF_MAX_STRINGS] = { + LangDescr, + reinterpret_cast (&str_1), + reinterpret_cast (&str_2), + reinterpret_cast (&str_3), +}; + + diff --git a/V203/usb/usart/usb_desc.h b/V203/usb/usart/usb_desc.h new file mode 100644 index 0000000..9b578b9 --- /dev/null +++ b/V203/usb/usart/usb_desc.h @@ -0,0 +1,66 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : usb_desc.h + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/20 + * Description : header file of usb_desc.c +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#ifndef USER_USB_DESC_H_ +#define USER_USB_DESC_H_ + +#include + +/******************************************************************************/ +/* global define */ +/* file version */ +#define DEF_FILE_VERSION 0x01 +/* usb device info define */ +#define DEF_USB_VID 0x1A86 +#define DEF_USB_PID 0xFE0C +/* USB device descriptor, device serial number(bcdDevice) */ +#define DEF_IC_PRG_VER DEF_FILE_VERSION + +/******************************************************************************/ +/* usb device endpoint size define */ +#define DEF_USBD_UEP0_SIZE 64 /* usb hs/fs device end-point 0 size */ +/* FS */ +#define DEF_USBD_FS_PACK_SIZE 64 /* usb fs device max bluk/int pack size */ +#define DEF_USBD_FS_ISO_PACK_SIZE 1023 /* usb fs device max iso pack size */ +/* LS */ +#define DEF_USBD_LS_UEP0_SIZE 8 /* usb ls device end-point 0 size */ +#define DEF_USBD_LS_PACK_SIZE 64 /* usb ls device max int pack size */ + +/* Pack size */ +#define DEF_USBD_ENDP1_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_ENDP2_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_ENDP3_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_ENDP4_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_ENDP5_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_ENDP6_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_ENDP7_SIZE DEF_USBD_FS_PACK_SIZE + +/******************************************************************************/ +/* usb device Descriptor length, length of usb descriptors, if one descriptor not + * exists , set the length to 0 */ +#define DEF_USBD_DEVICE_DESC_LEN ((uint8_t)MyDevDescr[0]) +#define DEF_USBD_CONFIG_DESC_LEN ((uint16_t)MyCfgDescr[2] + (uint16_t)(MyCfgDescr[3] << 8)) +#define DEF_USBD_REPORT_DESC_LEN 0 + +#define DEF_MAX_STRINGS (4) +/******************************************************************************/ +/* external variables */ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + extern const uint8_t MyDevDescr[ ]; + extern const uint8_t MyCfgDescr[ ]; + extern const uint8_t * StringDescArray [DEF_MAX_STRINGS]; +#ifdef __cplusplus +}; +#endif // __cplusplus +#endif /* USER_USB_DESC_H_ */