From 3ff87427acb69a68c5fa53a88aa4b07fea021361 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Sun, 15 Feb 2026 23:32:29 +0300 Subject: [PATCH] partial work for interrupt-driven --- F3:F303/InterfaceBoard/main.c | 22 ++- F3:F303/InterfaceBoard/multiiface.bin | Bin 15908 -> 17208 bytes .../InterfaceBoard/multiiface.creator.user | 2 +- F3:F303/InterfaceBoard/proto.c | 16 ++- F3:F303/InterfaceBoard/usart.c | 129 ++++++++++++------ F3:F303/InterfaceBoard/usart.h | 3 +- F3:F303/InterfaceBoard/usb_dev.c | 9 +- F3:F303/InterfaceBoard/version.inc | 2 +- F3:F303/inc/Fx/stm32f3.h | 4 +- 9 files changed, 134 insertions(+), 53 deletions(-) diff --git a/F3:F303/InterfaceBoard/main.c b/F3:F303/InterfaceBoard/main.c index 5494e4a..583dc4c 100644 --- a/F3:F303/InterfaceBoard/main.c +++ b/F3:F303/InterfaceBoard/main.c @@ -32,6 +32,7 @@ void sys_tick_handler(void){ int main(void){ char inbuff[MAXSTRLEN+1]; + uint8_t oldcdc[InterfacesAmount] = {0}; if(StartHSE()){ SysTick_Config((uint32_t)72000); // 1ms }else{ @@ -43,26 +44,37 @@ int main(void){ USBPU_OFF(); USB_setup(); //uint32_t ctr = Tms; + //usb_LineCoding lc = {9600, 0, 0, 8}; + //for(int i = 0; i < 5; ++i) usart_config(i, &lc); USBPU_ON(); - int maxno = (Config_mode) ? ICFG : InterfacesAmount; while(1){ // Put here code working WITOUT USB connected if(!usbON) continue; - usarts_process(); // - for(int i = 0; i < maxno; ++i){ // just echo for first time + usarts_process(); + /*for(int i = 0; i < 6; ++i){ // just echo for first time if(!CDCready[i]) continue; int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN); if(l) USB_send(i, (uint8_t*)inbuff, l); - } + }*/ // and here is code what should run when USB connected if(Config_mode && CDCready[ICFG]){ - /*if(Tms - ctr > 999){ + /*if(Tms - ctr > 4999){ ctr = Tms; CFGWR("I'm alive\n"); }*/ + for(int i = 0; i < ICFG; ++i){ + if(oldcdc[i] != CDCready[i]){ + CFGWR("Interface "); USB_putbyte(ICFG, '1' + i); + USB_putbyte(ICFG, ' '); + if(!CDCready[i]) CFGWR("dis"); + CFGWR("connected\n"); + oldcdc[i] = CDCready[i]; + } + } int l = USB_receivestr(ICFG, inbuff, MAXSTRLEN); if(l < 0) CFGWR("ERROR: USB buffer overflow or string was too long\n"); else if(l){ + CFGWR("PARSING...\n"); const char *ans = parse_cmd(inbuff); if(ans) CFGWRn(ans); } diff --git a/F3:F303/InterfaceBoard/multiiface.bin b/F3:F303/InterfaceBoard/multiiface.bin index d2ffc333662b3ad14bd94452f4ab07e1541269ce..7607b60421823c71cba257f6b80b67fc1e467398 100755 GIT binary patch delta 6117 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 U3Oji#;K(N}8+EjNoZ#300)n>+oT+H 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 diff --git a/F3:F303/InterfaceBoard/multiiface.creator.user b/F3:F303/InterfaceBoard/multiiface.creator.user index 2b96e51..1fa8b47 100644 --- a/F3:F303/InterfaceBoard/multiiface.creator.user +++ b/F3:F303/InterfaceBoard/multiiface.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F3:F303/InterfaceBoard/proto.c b/F3:F303/InterfaceBoard/proto.c index 660eb49..08317e3 100644 --- a/F3:F303/InterfaceBoard/proto.c +++ b/F3:F303/InterfaceBoard/proto.c @@ -21,6 +21,7 @@ #include "flash.h" #include "strfunc.h" +#include "usart.h" #include "usb_dev.h" #include "version.inc" @@ -35,6 +36,7 @@ extern volatile uint32_t Tms; const char *helpstring = "https://github.com/eddyem/stm32samples/tree/master/F3:F303/InterfaceBoard build#" BUILD_NUMBER " @ " BUILD_DATE "\n" + "1..5x - send data over IF1..5\n" "d - dump flash\n" "ix - rename interface number x (0..6)\n" "Ex - erase full storage (witout x) or only page x\n" @@ -90,11 +92,23 @@ static const char* erpg(const char *str){ return sOKn; } -const char *parse_cmd(const char *buf){ +static void sendoverU(uint8_t ifno, char *str){ + int len = strlen(str); + CFGWR("try to send "); CFGWRn(str); + str[len] = '\n'; + len = usart_send(ifno, (const uint8_t*)str, len+1); + CFGWR("sent "); CFGWR(i2str(len)); CFGWR("bytes\n"); +} + +const char *parse_cmd(char *buf){ if(!buf || !*buf) return NULL; if(strlen(buf) > 1){ // "long" commands char c = *buf++; + if(c > '0' && c < '6'){ + sendoverU(c - '1', buf); + return NULL; + } switch(c){ case 'E': return erpg(buf); diff --git a/F3:F303/InterfaceBoard/usart.c b/F3:F303/InterfaceBoard/usart.c index a7260ab..23ec043 100644 --- a/F3:F303/InterfaceBoard/usart.c +++ b/F3:F303/InterfaceBoard/usart.c @@ -32,12 +32,12 @@ typedef struct { volatile USART_TypeDef *instance; // U[S]ARTx uint32_t pclk_freq; // APB1/APB2 frequency - int16_t IRQn; // IRQ number for enable/disable (maybe 0 for DMA-driven channels) + int16_t UIRQn; // USART IRQ number + int16_t DIRQn; // DMA Tx IRQ number (for DMA-driven) volatile DMA_TypeDef *dma_controller; // DMA1/DMA2 or NULL if not used volatile DMA_Channel_TypeDef *dma_rx_channel; // e.g., DMA_Channel_5 or NULL if not used volatile DMA_Channel_TypeDef *dma_tx_channel; // e.g., DMA_Channel_4 or NULL if not used uint32_t TTCflag; // Tx transfer complete flag - uint32_t RTCflag; // Rx transfer complete flag volatile GPIO_TypeDef *DEport; // if RS485 - DE GPIO port (NULL for RS-232 or RS-422) uint32_t DEpin; // -//- pin } USART_Config; @@ -52,11 +52,11 @@ typedef struct { // IF6[5]: (CAN) // IF7[6]: (SPI) static const USART_Config UC[USARTSNO] = { - [0] = {.instance = USART3, .pclk_freq = 72000000, USART3_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel3, .dma_tx_channel = DMA1_Channel2, .TTCflag = DMA_ISR_TCIF3, .RTCflag = DMA_ISR_TCIF3, .DEport = GPIOB, .DEpin = 1<<14 }, - [1] = {.instance = USART1, .pclk_freq = 36000000, USART1_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel5, .dma_tx_channel = DMA1_Channel4, .TTCflag = DMA_ISR_TCIF5, .RTCflag = DMA_ISR_TCIF4, .DEport = GPIOB, .DEpin = 1<<0 }, - [2] = {.instance = USART2, .pclk_freq = 72000000, USART2_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel6, .dma_tx_channel = DMA1_Channel7, .TTCflag = DMA_ISR_TCIF6, .RTCflag = DMA_ISR_TCIF7, .DEport = GPIOB, .DEpin = 1<<1 }, - [3] = {.instance = UART4, .pclk_freq = 72000000, UART4_IRQn, .dma_controller = DMA2, .dma_rx_channel = DMA2_Channel3, .dma_tx_channel = DMA2_Channel5, .TTCflag = DMA_ISR_TCIF3, .RTCflag = DMA_ISR_TCIF5 }, - [4] = {.instance = UART5, .pclk_freq = 72000000, UART5_IRQn }, // no DMA + [0] = {.instance = USART3, .pclk_freq = 36000000, .UIRQn = USART3_IRQn, .DIRQn = DMA1_Channel2_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel3, .dma_tx_channel = DMA1_Channel2, .TTCflag = DMA_ISR_TCIF2, .DEport = GPIOB, .DEpin = 1<<14 }, + [1] = {.instance = USART1, .pclk_freq = 72000000, .UIRQn = USART1_IRQn, .DIRQn = DMA1_Channel4_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel5, .dma_tx_channel = DMA1_Channel4, .TTCflag = DMA_ISR_TCIF4, .DEport = GPIOB, .DEpin = 1<<0 }, + [2] = {.instance = USART2, .pclk_freq = 36000000, .UIRQn = USART2_IRQn, .DIRQn = DMA1_Channel7_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel6, .dma_tx_channel = DMA1_Channel7, .TTCflag = DMA_ISR_TCIF7, .DEport = GPIOB, .DEpin = 1<<1 }, + [3] = {.instance = UART4, .pclk_freq = 36000000, .UIRQn = UART4_IRQn, .DIRQn = DMA2_Channel5_IRQn, .dma_controller = DMA2, .dma_rx_channel = DMA2_Channel3, .dma_tx_channel = DMA2_Channel5, .TTCflag = DMA_ISR_TCIF5 }, + [4] = {.instance = UART5, .pclk_freq = 36000000, .UIRQn = UART5_IRQn }, // no DMA }; // buffers for DMA or interrupt-driven data management @@ -66,13 +66,13 @@ static uint8_t outbuffers[USARTSNO][DMATXBUFSZ]; static uint16_t outbufidx[USARTSNO] = {0}; // index of next char to transmit over interrupt static uint16_t outbuflen[USARTSNO] = {0}; // length of data to transmit over interrupt [equal 0 if nothing to send] static uint8_t need2send[USARTSNO] = {0}; // flags from IDLE interrupt to send data portion - +static uint8_t TXrdy[USARTSNO] = {1,1,1,1,1}; // TX DMA ready // there's no way to tell recipient about overfull, so we will just "eat" spare data! /** * @brief usart_config - configure US[A]RT based on usb_LineCoding - * @param ifNo - interface index [0..6] + * @param ifNo - interface index [0..4] * @param lc (io) - linecoding (modified to real speeds) */ void usart_config(uint8_t ifNo, usb_LineCoding *lc){ @@ -148,7 +148,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){ // Write CR2 (stop bits) U->CR2 = cr2; // Enable transmitter, receiver, and interrupts (optional) - cr1 |= USART_CR1_RE | USART_CR1_UE; + cr1 |= USART_CR1_RE; if(cfg->DEport){ RX485(cfg->DEport, cfg->DEpin); cr1 |= USART_CR1_TCIE; @@ -160,7 +160,7 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){ // Tx DMA T->CCR = 0; T->CPAR = (uint32_t) &U->TDR; - T->CCR = DMA_CCR_MINC | DMA_CCR_DIR; // | DMA_CCR_TCIE; + T->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // Rx DMA R->CCR = 0; R->CPAR = (uint32_t) &U->RDR; @@ -171,10 +171,9 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){ U->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; cr1 |= USART_CR1_IDLEIE; // enable idle interrupt to force small portions of data into ringbuffer }else{ - cr1 |= USART_CR1_RXNEIE | USART_CR1_TXEIE; // interrupt-driven + cr1 |= USART_CR1_RXNEIE; // interrupt-driven inbufidx[ifNo] = 0; outbufidx[ifNo] = 0; - NVIC_EnableIRQ(cfg->IRQn); } U->CR1 = cr1; @@ -186,6 +185,15 @@ void usart_config(uint8_t ifNo, usb_LineCoding *lc){ U->ICR = 0xFFFFFFFF; // Clear flags again } +// start when received DTR +void usart_start(uint8_t ifNo){ + if(ifNo >= USARTSNO || UC[ifNo].instance == NULL) return; + const USART_Config *cfg = &UC[ifNo]; + cfg->instance->CR1 |= USART_CR1_UE; + NVIC_EnableIRQ(cfg->UIRQn); + if(cfg->dma_controller) NVIC_EnableIRQ(cfg->DIRQn); +} + /** * @brief usart_stop - turn off U[S]ART for given interface * @param ifNo - interface number @@ -198,11 +206,18 @@ void usart_stop(uint8_t ifNo){ if(cfg->dma_controller){ cfg->dma_tx_channel->CCR = 0; cfg->dma_rx_channel->CCR = 0; + NVIC_DisableIRQ(cfg->DIRQn); }else{ - NVIC_DisableIRQ(cfg->IRQn); + NVIC_DisableIRQ(cfg->UIRQn); } } +static void msg(const char *txt, uint8_t ifno, int l){ + if(!Config_mode) return; + CFGWR("IF"); USB_putbyte(ICFG, '1' + ifno); CFGWR(": "); + CFGWR(txt); CFGWR(" ("); CFGWR(i2str(l)); CFGWR(" bytes)\n"); +} + /** * @brief usarts_process - send/receive processing * Try to send data from output ringbuffer, check input DMA buffer and full input ringbuffer @@ -219,6 +234,7 @@ void usarts_process(){ register int l = DMARXBUFSZ - R->CNDTR; if(l){ // have some input data -> send and restart DMA if(USB_send(i, inbuffers[i], l)){ + msg("USART -> USB over DMA", i, l); // restart DMA only in case of succesfull sent or if failed, but have ability of buffer overfull R->CMAR = (uint32_t) inbuffers[i]; R->CNDTR = DMARXBUFSZ; @@ -229,11 +245,11 @@ void usarts_process(){ R->CCR |= DMA_CCR_EN; // re-enable DMA } // Output data - if(cfg->dma_controller->ISR & cfg->RTCflag){ // ready to send new data + if(TXrdy[i]){ // ready to send new data int got = USB_receive(i, outbuffers[i], DMATXBUFSZ); if(got > 0){ // send next data portion volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel; - cfg->dma_controller->IFCR = cfg->RTCflag; // now we can clear TC flag (TC and CTC are the same) + //cfg->dma_controller->IFCR = cfg->TTCflag; // now we can clear TC flag (TC and CTC are the same) T->CCR &= ~DMA_CCR_EN; T->CMAR = (uint32_t) outbuffers[i]; T->CNDTR = got; @@ -243,6 +259,8 @@ void usarts_process(){ cfg->instance->CR1 |= USART_CR1_TE; } T->CCR |= DMA_CCR_EN; // start new transmission + TXrdy[i] = 0; + msg("USB -> USART over DMA", i, got); } } }else{ // interrupt-driven @@ -250,16 +268,16 @@ void usarts_process(){ volatile USART_TypeDef *U = cfg->instance; U->CR1 &= ~USART_CR1_RXNEIE; // temporarily disable interrupt register int l = inbufidx[i]; - if(DMARXBUFSZ - l > DMARXBUFSZ/2 || need2send[i]){ + if(l > DMARXBUFSZ/2 || need2send[i]){ if(l && USB_send(i, inbuffers[i], l)){ need2send[i] = 0; inbufidx[i] = 0; + msg("USART -> USB over irq", i, l); } } U->CR1 |= USART_CR1_RXNEIE; // restore irq reaction // output data - U->CR1 &= ~USART_CR1_TXEIE; - if(outbuflen[i] == 0){ + if(TXrdy[i]){ int got = USB_receive(i, outbuffers[i], DMATXBUFSZ); if(got > 0){ if(cfg->DEport){ // switch to Tx @@ -269,14 +287,51 @@ void usarts_process(){ } outbufidx[i] = 1; // continue from next symbol outbuflen[i] = got; + TXrdy[i] = 0; U->TDR = outbuffers[i][0]; // start transmission + U->CR1 |= USART_CR1_TXEIE; // enable TXE interrupt + msg("USB -> USART over irq", i, got); } } - U->CR1 |= USART_CR1_TXEIE; } } } +// Use this function only for debug purpose +int usart_send(uint8_t ifNo, const uint8_t *data, int len){ + if(ifNo >= USARTSNO || !data || len < 1) return 0; + if(TXrdy[ifNo] == 0) return -1; // busy + const USART_Config *cfg = &UC[ifNo]; + if(len > DMATXBUFSZ) len = DMATXBUFSZ; + memcpy(outbuffers[ifNo], data, len); + if(cfg->dma_controller){ + volatile DMA_Channel_TypeDef *T = cfg->dma_tx_channel; + //cfg->dma_controller->IFCR = cfg->TTCflag; // now we can clear TC flag (TC and CTC are the same) + T->CCR &= ~DMA_CCR_EN; + T->CMAR = (uint32_t) outbuffers[ifNo]; + T->CNDTR = len; + if(cfg->DEport){ // switch to Tx + TX485(cfg->DEport, cfg->DEpin); + cfg->instance->CR1 &= ~USART_CR1_RE; + cfg->instance->CR1 |= USART_CR1_TE; + } + T->CCR |= DMA_CCR_EN; // start new transmission + TXrdy[ifNo] = 0; + }else{ + volatile USART_TypeDef *U = cfg->instance; + if(cfg->DEport){ // switch to Tx + TX485(cfg->DEport, cfg->DEpin); + U->CR1 &= ~USART_CR1_RE; + U->CR1 |= USART_CR1_TE; + } + outbufidx[ifNo] = 1; // continue from next symbol + outbuflen[ifNo] = len; + U->TDR = outbuffers[ifNo][0]; // start transmission + U->CR1 |= USART_CR1_TXEIE; // enable TXE interrupt + } + return len; +} + /** * @brief usart_isr - U[S]ART interrupt: IDLE (for DMA-driven) or * @param ifno - interface index @@ -293,8 +348,11 @@ static void usart_isr(uint8_t ifno){ U->ICR = USART_ICR_IDLECF; } if(U->ISR & USART_ISR_TXE){ // send next byte if need - if(outbuflen[ifno] < outbufidx[ifno]){ + if(outbuflen[ifno] > outbufidx[ifno]){ U->TDR = outbuffers[ifno][ outbufidx[ifno]++ ]; + }else{ + U->CR1 &= ~USART_CR1_TXEIE; // disable interrupt: no data to send + TXrdy[ifno] = 1; } } if(U->ISR & USART_ISR_TC){ // switch RS-485 to Rx after transmission complete @@ -307,22 +365,15 @@ static void usart_isr(uint8_t ifno){ } } -void usart1_exti25_isr(){ - usart_isr(1); -} +// U[S]ART interrupts (for DMA-driven - only IDLE, for interrupt-driven: RXNE and TXE) +void usart1_exti25_isr(){ usart_isr(1); } +void usart2_exti26_isr(){ usart_isr(2); } +void usart3_exti28_isr(){ usart_isr(0); } +void uart4_exti34_isr(){ usart_isr(3); } +void uart5_exti35_isr(){ usart_isr(4); } -void usart2_exti26_isr(){ - usart_isr(2); -} - -void usart3_exti28_isr(){ - usart_isr(0); -} - -void uart4_exti34_isr(){ - usart_isr(3); -} - -void uart5_exti35_isr(){ - usart_isr(4); -} +// DMA Tx interrupts (to arm ready flag) +void dma1_channel2_isr(){ TXrdy[1] = 1; DMA1->IFCR = DMA_IFCR_CTCIF2; } +void dma1_channel4_isr(){ TXrdy[2] = 1; DMA1->IFCR = DMA_IFCR_CTCIF4; } +void dma1_channel7_isr(){ TXrdy[0] = 1; DMA1->IFCR = DMA_IFCR_CTCIF7; } +void dma2_channel5_isr(){ TXrdy[3] = 1; DMA2->IFCR = DMA_IFCR_CTCIF5; } diff --git a/F3:F303/InterfaceBoard/usart.h b/F3:F303/InterfaceBoard/usart.h index 4ba8902..1ff82b6 100644 --- a/F3:F303/InterfaceBoard/usart.h +++ b/F3:F303/InterfaceBoard/usart.h @@ -29,9 +29,10 @@ #define USARTTXRBSZ 256 void usart_config(uint8_t ifNo, usb_LineCoding *lc); +void usart_start(uint8_t ifNo); void usart_stop(uint8_t ifNo); void usarts_process(); int usart_send(uint8_t ifNo, const uint8_t *data, int len); -int usart_receive(uint8_t ifNo, uint8_t *data, int len); +//int usart_receive(uint8_t ifNo, uint8_t *data, int len); diff --git a/F3:F303/InterfaceBoard/usb_dev.c b/F3:F303/InterfaceBoard/usb_dev.c index 9ea8d29..b08dcfd 100644 --- a/F3:F303/InterfaceBoard/usb_dev.c +++ b/F3:F303/InterfaceBoard/usb_dev.c @@ -117,8 +117,9 @@ static void rxtx_handler(){ // SET_LINE_CODING void linecoding_handler(uint8_t ifno, usb_LineCoding *lc){ - usart_config(ifno, lc); // lc would be real speed! lineCoding[ifno] = *lc; + usart_config(ifno, &lineCoding[ifno]); // lc would be real speed! + usart_start(ifno); } // clear IN/OUT buffers on connection @@ -137,8 +138,10 @@ static void clearbufs(uint8_t ifno){ void clstate_handler(uint8_t ifno, uint16_t val){ CDCready[ifno] = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected lastdsz[ifno] = -1; - if(val) clearbufs(ifno); - else usart_stop(ifno); // turn of USART (if it is @ this interface) + if(val){ + clearbufs(ifno); + usart_start(ifno); + }else usart_stop(ifno); // turn of USART (if it is @ this interface) } // SEND_BREAK - disconnect interface and clear its buffers diff --git a/F3:F303/InterfaceBoard/version.inc b/F3:F303/InterfaceBoard/version.inc index 24a9816..b91822d 100644 --- a/F3:F303/InterfaceBoard/version.inc +++ b/F3:F303/InterfaceBoard/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "65" +#define BUILD_NUMBER "97" #define BUILD_DATE "2026-02-15" diff --git a/F3:F303/inc/Fx/stm32f3.h b/F3:F303/inc/Fx/stm32f3.h index 79b3c61..2b8623b 100644 --- a/F3:F303/inc/Fx/stm32f3.h +++ b/F3:F303/inc/Fx/stm32f3.h @@ -123,8 +123,8 @@ TRUE_INLINE int StartHSE(){ // system bus 72MHz from PLL WAITWHILE(!(RCC->CR & RCC_CR_PLLRDY)); // Select PLL as system clock source RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL; - // select system clock as I2C source - RCC->CFGR3 |= RCC_CFGR3_I2C1SW_SYSCLK | RCC_CFGR3_I2C1SW_SYSCLK; + // select system clock as I2C source (default: HSI) + RCC->CFGR3 |= RCC_CFGR3_I2C1SW_SYSCLK | RCC_CFGR3_I2C2SW_SYSCLK; // Wait till PLL is used as system clock source WAITWHILE((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); SysFreq = 72000000;