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 d2ffc33..7607b60 100755 Binary files a/F3:F303/InterfaceBoard/multiiface.bin and b/F3:F303/InterfaceBoard/multiiface.bin differ 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;