diff --git a/F0:F030,F042,F072/usbcan_gpio/Makefile b/F0:F030,F042,F072/usbcan_gpio/Makefile index f9d8d4b..2bb8a42 100644 --- a/F0:F030,F042,F072/usbcan_gpio/Makefile +++ b/F0:F030,F042,F072/usbcan_gpio/Makefile @@ -1,10 +1,10 @@ BINARY := usbcangpio # MCU code -#MCU := F072xB -MCU := F042x6 +MCU := F072xB +#MCU := F042x6 # change this linking script depending on particular MCU model, -#LDSCRIPT := stm32f072xB.ld -LDSCRIPT := stm32f042x6.ld +LDSCRIPT := stm32f072x8.ld +#LDSCRIPT := stm32f042x6.ld DEFINES := -DUSB2_16 diff --git a/F0:F030,F042,F072/usbcan_gpio/canproto.c b/F0:F030,F042,F072/usbcan_gpio/canproto.c index cacfe94..012a8f1 100644 --- a/F0:F030,F042,F072/usbcan_gpio/canproto.c +++ b/F0:F030,F042,F072/usbcan_gpio/canproto.c @@ -387,8 +387,10 @@ static void CommandParser(char *txt){ break; #ifdef STM32F072xB case 'D': - USB_sendstr("Go into DFU mode\n"); - USB_sendall(); + SEND("Go into DFU mode\n"); + USB_sendall(ICAN); + uint32_t t = Tms; + while(Tms - t < 2000){IWDG->KR = IWDG_REFRESH;} Jump2Boot(); break; #endif diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.c b/F0:F030,F042,F072/usbcan_gpio/gpio.c index 83215e3..ff86226 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpio.c +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.c @@ -27,13 +27,6 @@ static uint16_t monitor_mask[2] = {0}; // pins to monitor == 1 (ONLY GPIO and ADC) static uint16_t oldstates[2][16] = {0}; // previous state (16 bits - as some pins could be analog) -// strings for keywords -const char *str_keywords[] = { -#define KW(x) [STR_ ## x] = #x, - KEYWORDS -#undef KW -}; - // intermediate buffer to change pin's settings by user request; after checking in will be copied to the_conf static pinconfig_t pinconfig[2][16] = {0}; static uint8_t pinconfig_notinited = 1; // ==0 after first memcpy from the_conf to pinconfig @@ -207,7 +200,8 @@ int chkpinconf(){ } // now check USART configuration if(active_usart != -1){ - if(chkusartconf(&UC)) ret = FALSE; + UC.idx = active_usart; + if(!chkusartconf(&UC)) ret = FALSE; }else{ get_defusartconf(&UC); // clear global configuration the_conf.usartconfig = UC; @@ -318,7 +312,7 @@ int gpio_reinit(){ int shift4 = pin << 4; gpio->AFR[0] = (gpio->AFR[0] & ~(0xf << shift4)) | (cfg->afno << shift4); }else{ - int shift4 = (pin - 8) << 4; + int shift4 = (pin - 8) << 2; gpio->AFR[1] = (gpio->AFR[1] & ~(0xf << shift4)) | (cfg->afno << shift4); } if(cfg->monitor && cfg->mode != MODE_AF){ diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.h b/F0:F030,F042,F072/usbcan_gpio/gpio.h index d4cfc54..b66eef5 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpio.h +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.h @@ -99,32 +99,6 @@ typedef struct{ } spiconfig_t; */ -// strings for keywords -extern const char *str_keywords[]; -#define KEYWORDS \ -KW(AIN) \ -KW(IN) \ -KW(OUT) \ -KW(AF) \ -KW(PU)\ -KW(PD) \ -KW(FL) \ -KW(PP) \ -KW(OD) \ -KW(USART) \ -KW(SPI) \ -KW(I2C) \ -KW(MONITOR) \ -KW(THRESHOLD) \ -KW(SPEED) \ -KW(TEXT) - -enum{ // indexes of string keywords -#define KW(k) STR_ ## k, - KEYWORDS -#undef KW -}; - int is_disabled(uint8_t port, uint8_t pin); int chkpinconf(); diff --git a/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp b/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp index 23a3ab1..41611bb 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp +++ b/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp @@ -25,7 +25,6 @@ extern "C"{ #include "adc.h" #include "can.h" #include "flash.h" -#include "gpioproto.h" #include "gpio.h" #include "gpioproto.h" #include "usart.h" @@ -36,6 +35,10 @@ extern "C"{ extern volatile uint32_t Tms; +static uint8_t curbuf[MAXSTRLEN]; // buffer for receiving data from USART etc + +static uint8_t usart_text = 0; // ==1 for text USART proto + // TODO: add analog threshold! // list of all commands and handlers @@ -56,9 +59,8 @@ extern volatile uint32_t Tms; COMMAND(setiface, "set/get name of interface x (0 - CAN, 1 - GPIO)") \ COMMAND(storeconf, "save config to flash") \ COMMAND(time, "show current time (ms)") \ - COMMAND(vdd, "get approx Vdd value (V*100)") - -// COMMAND(USART, "Read USART data or send (USART=hex)") + COMMAND(vdd, "get approx Vdd value (V*100)") \ + COMMAND(USART, "Read USART data or send (USART=hex)") // COMMAND(usartconf, "set USART params (e.g. usartconf=115200 8N1)") // COMMAND(SPI, "Read SPI data or send (SPI=hex)") // COMMAND(spiconf, "set SPI params") @@ -99,7 +101,42 @@ enum MiscValues{ MISC_MONITOR = 1, MISC_THRESHOLD, MISC_SPEED, - MISC_TEXT + MISC_TEXT, + MISC_BIN +}; + +// TODO: add HEX input? + +#define KEYWORDS \ +KW(AIN) \ + KW(IN) \ + KW(OUT) \ + KW(AF) \ + KW(PU)\ + KW(PD) \ + KW(FL) \ + KW(PP) \ + KW(OD) \ + KW(USART) \ + KW(SPI) \ + KW(I2C) \ + KW(MONITOR) \ + KW(THRESHOLD) \ + KW(SPEED) \ + KW(TEXT) \ + KW(BIN) \ + + enum{ // indexes of string keywords +#define KW(k) STR_ ## k, + KEYWORDS +#undef KW + }; + +// strings for keywords +static const char *str_keywords[] = { +#define KW(x) [STR_ ## x] = #x, + KEYWORDS +#undef KW }; static const Keyword keywords[] = { @@ -120,17 +157,19 @@ static const Keyword keywords[] = { KEY(THRESHOLD, GROUP_MISC, MISC_THRESHOLD) KEY(SPEED, GROUP_MISC, MISC_SPEED) KEY(TEXT, GROUP_MISC, MISC_TEXT) + KEY(BIN, GROUP_MISC, MISC_BIN) #undef K }; #define NUM_KEYWORDS (sizeof(keywords)/sizeof(keywords[0])) static const char* errtxt[ERR_AMOUNT] = { - [ERR_OK] = "OK", - [ERR_BADCMD] = "BADCMD", - [ERR_BADPAR] = "BADPAR", - [ERR_BADVAL] = "BADVAL", - [ERR_WRONGLEN] = "WRONGLEN", - [ERR_CANTRUN] = "CANTRUN", + [ERR_OK] = "OK", + [ERR_BADCMD] = "BADCMD", + [ERR_BADPAR] = "BADPAR", + [ERR_BADVAL] = "BADVAL", + [ERR_WRONGLEN] = "WRONGLEN", + [ERR_CANTRUN] = "CANTRUN", + [ERR_BUSY] = "BUSY", }; static const char *pinhelp = @@ -141,6 +180,9 @@ static const char *pinhelp = " FUNC: USART or SPI (enable alternate function and configure peripheal)\n" " MISC: MONITOR - send data by USB as only state changed\n" " THRESHOLD (ADC only) - monitoring threshold, ADU\n" + " SPEED - interface speed/frequency\n" + " TEXT - USART means data as text ('\n'-separated strings)\n" + " BIN - USART means data as binary (output: HEX)\n" "\n" ; @@ -197,7 +239,10 @@ static bool argsvals(char *args, int32_t *parno, int32_t *parval){ // `PAx = ` also printed there static void pin_getter(uint8_t port, uint8_t pin){ int16_t val = pin_in(port, pin); - if(val < 0) SENDn(errtxt[ERR_CANTRUN]); + if(val < 0){ + SENDn(errtxt[ERR_CANTRUN]); + return; + } SEND(port == 0 ? "PA" : "PB"); SEND(u2str((uint32_t)pin)); SEND(EQ); SENDn(u2str((uint32_t)val)); } @@ -284,6 +329,9 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ case MISC_TEXT: // what to do, if textproto is set, but user wants binary? UsartConf.textproto = 1; break; + case MISC_BIN: // clear text flag + UsartConf.textproto = 0; + break; } break; } @@ -342,7 +390,13 @@ static errcodes_t cmd_PB(const char *cmd, char *args){ } static errcodes_t cmd_reinit(const char _U_ *cmd, char _U_ *args){ - if(gpio_reinit()) return ERR_OK; + if(gpio_reinit()){ + usartconf_t UC; + if(get_curusartconf(&UC)){ + usart_text = UC.textproto; + } + return ERR_OK; + } SEND("Can't reinit: check your configuration!\n"); return ERR_AMOUNT; } @@ -573,6 +627,44 @@ static errcodes_t cmd_help(const char _U_ *cmd, char _U_ *args){ return ERR_AMOUNT; } +static int sendfun(const char *s){ + if(!s) return 0; + return USB_sendstr(IGPIO, s); +} + +static void sendusartdata(const uint8_t *buf, int len){ + if(!buf || len < 1) return; + SEND(str_keywords[STR_USART]); SEND(EQ); + if(usart_text){ + USB_send(IGPIO, curbuf, len); + if(curbuf[len-1] != '\n') NL(); + }else{ + NL(); + hexdump(sendfun, (uint8_t*)curbuf, len); + } +} + +static errcodes_t cmd_USART(const char _U_ *cmd, char *args){ + if(!args) return ERR_BADVAL; + char *setter = splitargs(args, NULL); + if(setter){ + DBG("Try to send over USART\n"); + int l = strlen(setter); + if(usart_text){ // add '\n' as we removed it @ parser + if(setter[l-1] != '\n') setter[l++] = '\n'; + } + l = usart_send((uint8_t*)setter, l); + if(l < 0) return ERR_BUSY; + else if(l == 0) return ERR_CANTRUN; + return ERR_OK; + } // getter: try to read + int l = usart_receive(curbuf, MAXSTRLEN); + if(l < 0) return ERR_CANTRUN; + if(l > 0) sendusartdata(curbuf, l); + // or silence: nothing to read + return ERR_AMOUNT; +} + constexpr uint32_t hash(const char* str, uint32_t h = 0){ return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h; } @@ -599,9 +691,8 @@ static const char *CommandParser(char *str){ } void GPIO_process(){ - char inbuff[MAXSTRLEN]; - int l = RECV(inbuff, MAXSTRLEN); - // TODO: check SPI/USART/I2C + int l; + // TODO: check SPI/I2C etc for(uint8_t port = 0; port < 2; ++port){ uint16_t alert = gpio_alert(port); if(alert == 0) continue; @@ -610,11 +701,13 @@ void GPIO_process(){ if(alert & pinmask) pin_getter(port, i); } } - usart_process(NULL, 0); + l = usart_process(curbuf, MAXSTRLEN); + if(l > 0) sendusartdata(curbuf, l); + l = RECV((char*)curbuf, MAXSTRLEN); if(l == 0) return; if(l < 0) SEND("ERROR: USB buffer overflow or string was too long\n"); else{ - const char *ans = CommandParser(inbuff); + const char *ans = CommandParser((char*)curbuf); if(ans) SENDn(ans); } } diff --git a/F0:F030,F042,F072/usbcan_gpio/gpioproto.h b/F0:F030,F042,F072/usbcan_gpio/gpioproto.h index 6f5478e..2facea9 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpioproto.h +++ b/F0:F030,F042,F072/usbcan_gpio/gpioproto.h @@ -26,6 +26,7 @@ typedef enum{ ERR_BADVAL, // wrong value (for setter) ERR_WRONGLEN, // wrong message length ERR_CANTRUN, // can't run given command due to bad parameters or other + ERR_BUSY, // target interface busy, try later ERR_AMOUNT // amount of error codes or "send nothing" } errcodes_t; diff --git a/F0:F030,F042,F072/usbcan_gpio/hardware.c b/F0:F030,F042,F072/usbcan_gpio/hardware.c index 4b9e796..45f312d 100644 --- a/F0:F030,F042,F072/usbcan_gpio/hardware.c +++ b/F0:F030,F042,F072/usbcan_gpio/hardware.c @@ -34,9 +34,9 @@ TRUE_INLINE void gpio_setup(){ // setup some common GPIO void hardware_setup(){ // enable all active GPIO clocking - RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; - RCC->APB1ENR |= RCC_APB2ENR_USART1EN; - RCC->APB2ENR |= RCC_APB1ENR_USART2EN; + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMA1EN; + RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN; + RCC->APB1ENR |= RCC_APB1ENR_USART2EN; gpio_setup(); //gpio_reinit(); adc_setup(); diff --git a/F0:F030,F042,F072/usbcan_gpio/main.c b/F0:F030,F042,F072/usbcan_gpio/main.c index 0d2e39e..56e6659 100644 --- a/F0:F030,F042,F072/usbcan_gpio/main.c +++ b/F0:F030,F042,F072/usbcan_gpio/main.c @@ -32,6 +32,7 @@ void sys_tick_handler(void){ int main(void){ sysreset(); SysTick_Config(6000, 1); + StartHSE(); flashstorage_init(); hardware_setup(); USB_setup(); diff --git a/F0:F030,F042,F072/usbcan_gpio/usart.c b/F0:F030,F042,F072/usbcan_gpio/usart.c index fa572e4..85be3a6 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usart.c +++ b/F0:F030,F042,F072/usbcan_gpio/usart.c @@ -32,8 +32,8 @@ static uint8_t inbuffer[DMARXBUFSZ]; // DMA in buffer static uint8_t rbbuffer[RXRBSZ]; // for in ringbuffer static uint8_t outbuffer[DMATXBUFSZ]; // DMA out buffer -static uint8_t TXrdy = 1; // TX DMA ready -static uint8_t RXrdy = 0; // == 1 when got IDLE or '\n' (only when `monitoring` is on +static volatile uint8_t TXrdy = 1; // TX DMA ready +static volatile uint8_t RXrdy = 0; // == 1 when got IDLE or '\n' (only when `monitoring` is on static uint8_t textformat = 0; // out by '\n'-terminated lines static uint8_t monitor = 0; // monitor USART rx static int dma_read_idx = 0; // start of data in DMA inbuffers @@ -108,18 +108,19 @@ int usart_config(usartconf_t *uc){ // Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8. U->BRR = peripheral_clock / (usartconfig.speed); usartconfig.speed= peripheral_clock / U->BRR; // fix for real speed - uint32_t cr1 = 0; - // format: 8N1, so CR2 used only for character match (if need) - if(usartconfig.monitor){ - if(usartconfig.textproto){ - U->CR2 = USART_CR2_ADD_VAL('\n'); - cr1 |= USART_CR1_CMIE; - }else cr1 |= USART_CR1_IDLEIE; // monitor binary data by IDLE flag - } + uint32_t cr1 = 0, cr3 = 0; textformat = usartconfig.textproto; monitor = usartconfig.monitor; // Enable transmitter, receiver, and interrupts (optional) - if(usartconfig.RXen) cr1 |= USART_CR1_RE; + if(usartconfig.RXen){ + cr1 |= USART_CR1_RE; + cr3 |= USART_CR3_DMAR; + // format: 8N1, so CR2 used only for character match (if need) + if(usartconfig.textproto){ + U->CR2 = USART_CR2_ADD_VAL('\n'); // buffer text data by EOL + cr1 |= USART_CR1_CMIE; + }else cr1 |= USART_CR1_IDLEIE; // buffer binary data by IDLE flag + } if(usartconfig.TXen){ cr1 |= USART_CR1_TE; // DMA Tx @@ -127,9 +128,11 @@ int usart_config(usartconf_t *uc){ T->CCR = 0; T->CPAR = (uint32_t) &U->TDR; T->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; + cr3 |= USART_CR3_DMAT; } // Main config U->CR1 = cr1; + U->CR3 = cr3; curUSARTidx = No; // all OK -> copy to global config the_conf.usartconfig = usartconfig; @@ -140,26 +143,21 @@ int usart_config(usartconf_t *uc){ int usart_start(){ if(curUSARTidx == -1) return FALSE; volatile USART_TypeDef *U = Usarts[curUSARTidx]; - if(monitor) NVIC_EnableIRQ(UIRQs[curUSARTidx]); + NVIC_EnableIRQ(UIRQs[curUSARTidx]); // copy to ring buffer after each '\n' in text mode or IDLE in binary NVIC_EnableIRQ(DMA1_Channel4_5_IRQn); // reset Rx DMA if(U->CR1 & USART_CR1_RE){ volatile DMA_Channel_TypeDef *R = DMA1_Channel5; dma_read_idx = 0; R->CCR = 0; - R->CPAR = (uint32_t) U->RDR; + RB_clearbuf(&RBin); + R->CPAR = (uint32_t) &U->RDR; R->CMAR = (uint32_t) inbuffer; R->CNDTR = DMARXBUFSZ; R->CCR = DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_EN; - RB_clearbuf(&RBin); } U->CR1 |= USART_CR1_UE; // enable USARTx U->ICR = 0xFFFFFFFF; // Clear flags - // Wait for the idle frame to complete (optional) - uint32_t tmout = 16000000; - while(!(U->ISR & USART_ISR_TC)){ - if (--tmout == 0) break; - } TXrdy = 1; return TRUE; } @@ -208,33 +206,36 @@ int usart_process(uint8_t *buf, int len){ if(curUSARTidx == -1 || !(Usarts[curUSARTidx]->CR1 & USART_CR1_UE)) return -1; // none activated or started int ret = 0; // returned value // Input data - int write_idx = DMARXBUFSZ - DMA1_Channel5->CNDTR; // next symbol to be written + int remained = DMA1_Channel5->CNDTR; + int write_idx = DMARXBUFSZ - remained; // next symbol to be written int available = (write_idx - dma_read_idx); // length of data available + int monitored_len = available; + uint8_t locmonitor = monitor; // if `buf` not pointed, set this flag to zero if(available < 0) available += DMARXBUFSZ; // write to the left of read if(available){ - if(RXrdy){ + if(locmonitor){ if(buf && len > 0){ - if(len < available) available = len; - }else RXrdy = 0; + if(len < monitored_len) monitored_len = len; + }else locmonitor = 0; } // TODO: force copying data to "async" buffer in case of overflow danger if(available >= (DMARXBUFSZ/2) || RXrdy){ // enough data or lonely couple of bytes but need to show // copy data in one or two chunks (wrap handling) int wrOK = FALSE; if(dma_read_idx + available <= DMARXBUFSZ){ // head before tail - if(RXrdy){ - memcpy(buf, &inbuffer[dma_read_idx], available); - ret = available; + if(locmonitor){ + memcpy(buf, &inbuffer[dma_read_idx], monitored_len); + ret = monitored_len; wrOK = TRUE; }else{ if(available == RB_write(&RBin, &inbuffer[dma_read_idx], available)) wrOK = TRUE; } }else{ // head after tail - two chunks int first = DMARXBUFSZ - dma_read_idx; - if(RXrdy){ + if(locmonitor){ memcpy(buf, &inbuffer[dma_read_idx], first); - memcpy(buf, inbuffer, available - first); - ret = available; + memcpy(buf, inbuffer, monitored_len - first); + ret = monitored_len; wrOK = TRUE; }else{ if((first == RB_write(&RBin, &inbuffer[dma_read_idx], first)) && @@ -297,9 +298,9 @@ static void usart_isr(){ } void dma1_channel4_5_isr(){ // TX ready, channel5 - if(DMA1->ISR & DMA_ISR_TCIF5){ + if(DMA1->ISR & DMA_ISR_TCIF4){ TXrdy = 1; - DMA1->IFCR = DMA_IFCR_CTCIF5; + DMA1->IFCR = DMA_IFCR_CTCIF4; DMA1_Channel4->CCR &= ~DMA_CCR_EN; // disable DMA channel until next send } } diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin index e41fd58..ed09300 100755 Binary files a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin and b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin differ diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user index b138528..aa40037 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user +++ b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F0:F030,F042,F072/usbcan_gpio/version.inc b/F0:F030,F042,F072/usbcan_gpio/version.inc index 1100d14..2c30622 100644 --- a/F0:F030,F042,F072/usbcan_gpio/version.inc +++ b/F0:F030,F042,F072/usbcan_gpio/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "156" -#define BUILD_DATE "2026-03-12" +#define BUILD_NUMBER "173" +#define BUILD_DATE "2026-03-14"