From 14f544374a6e270440082be10ce8dd6a01778e51 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Fri, 13 Mar 2026 00:15:18 +0300 Subject: [PATCH] cont --- F0:F030,F042,F072/usbcan_gpio/flash.h | 5 +- F0:F030,F042,F072/usbcan_gpio/gpio.c | 211 +++++++++++++++--- F0:F030,F042,F072/usbcan_gpio/gpio.h | 20 +- F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp | 76 +++++-- F0:F030,F042,F072/usbcan_gpio/usart.c | 74 ++++-- F0:F030,F042,F072/usbcan_gpio/usart.h | 22 +- F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin | Bin 21048 -> 22652 bytes .../usbcan_gpio/usbcangpio.creator.user | 2 +- F0:F030,F042,F072/usbcan_gpio/version.inc | 4 +- 9 files changed, 323 insertions(+), 91 deletions(-) diff --git a/F0:F030,F042,F072/usbcan_gpio/flash.h b/F0:F030,F042,F072/usbcan_gpio/flash.h index 6004eb6..439b1e1 100644 --- a/F0:F030,F042,F072/usbcan_gpio/flash.h +++ b/F0:F030,F042,F072/usbcan_gpio/flash.h @@ -25,6 +25,7 @@ #include #include "gpio.h" +#include "usart.h" #include "usb_descr.h" // register with flash size (in blocks) @@ -47,8 +48,8 @@ typedef struct __attribute__((packed, aligned(4))){ uint8_t iIlengths[InterfacesAmount]; // length in BYTES (symbols amount x2)! // gpio settings pinconfig_t pinconfig[2][16]; // GPIOA, GPIOB - usartconfig_t usartconfig; - spiconfig_t spiconfig; + usartconf_t usartconfig; + //spiconfig_t spiconfig; } user_conf; extern user_conf the_conf; // global user config (read from FLASH to RAM) diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.c b/F0:F030,F042,F072/usbcan_gpio/gpio.c index ec5cfee..83215e3 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpio.c +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.c @@ -34,6 +34,11 @@ const char *str_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 +#define CHKPINCONFIG() do{if(pinconfig_notinited) chkpinconf();}while(0) + // TODO: remove AFmask, make function to get right AF number by pin's FuncValues typedef struct{ uint8_t funcs; // bitmask according to enum FuncNames @@ -56,35 +61,174 @@ static const pinprops_t pin_props[2][16] = { [1] = { .funcs = 0b00000001, .AF = {0}}, // PA1: ADC1, AF2 (TIM2_CH2) [2] = { .funcs = 0b00000011, .AF = {_U(1)}}, // PA2: ADC2, AF2 (TIM2_CH3), AF1 (USART2_TX) [3] = { .funcs = 0b00000011, .AF = {_U(1)}}, // PA3: ADC3, AF2 (TIM2_CH4), AF1 (USART2_RX) - [5] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA5: ADC5, SPI1_SCK (AF0) - [6] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA6: ADC6, SPI1_MISO (AF0) - [7] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA7: ADC7, SPI1_MOSI (AF0) - [9] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA9: USART1_TX (AF1) - [10] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA10: USART1_RX (AF1) + [5] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA5: ADC5, AF9 (SPI1_SCK) + [6] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA6: ADC6, AF0 (SPI1_MISO) + [7] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA7: ADC7, AF0 (SPI1_MOSI) + [9] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA9: AF1 (USART1_TX) + [10] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA10: AF1 (USART1_RX) }, [1] = { // PORT B - [0] = { .funcs = 0b00000001, .AF = {0}}, // PB0: ADC8, TIM3_CH3 (AF1), TIM1_CH2N (AF2) - [1] = { .funcs = 0b00000001, .AF = {0}}, // PB1: ADC9, TIM14_CH1 (AF0), TIM3_CH4 (AF1), TIM1_CH3N (AF2) + [0] = { .funcs = 0b00000001, .AF = {0}}, // PB0: ADC8, AF1 (TIM3_CH3), AF2 (TIM1_CH2N) + [1] = { .funcs = 0b00000001, .AF = {0}}, // PB1: ADC9, AF0 (TIM14_CH1), AF1 (TIM3_CH4), AF2 (TIM1_CH3N) [2] = { .funcs = 0b00000000, .AF = {0}}, // PB2: nothing except GPIO - [3] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB3: SPI1_SCK (AF0), TIM2_CH2 (AF2) - [4] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB4: SPI1_MISO (AF0), TIM3_CH1 (AF1) - [5] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB5: SPI1_MOSI (AF0), TIM3_CH2 (AF1) - [6] = { .funcs = 0b00001010, .AF = {_U(0), _I(1)}}, // PB6: USART1_TX (AF0), I2C1_SCL (AF1), TIM16_CH1N (AF2) - [7] = { .funcs = 0b00001010, .AF = {_U(0), _I(1)}}, // PB7: USART1_RX (AF0), I2C1_SDA (AF1), TIM17_CH1N (AF2) - [10] = { .funcs = 0b00001000, .AF = {_I(1)}}, // PB10: I2C1_SCL (AF1), TIM2_CH3 (AF2) - [11] = { .funcs = 0b00001000, .AF = {_I(1)}}, // PB11: I2C1_SDA (AF1), TIM2_CH4 (AF2) + [3] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB3: AF0, (SPI1_SCK), AF2 (TIM2_CH2) + [4] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB4: AF0 (SPI1_MISO), AF1 (TIM3_CH1) + [5] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB5: AF0 (SPI1_MOSI), AF1 (TIM3_CH2) + [6] = { .funcs = 0b00001010, .AF = {_U(0), _I(1)}}, // PB6: AF0 (USART1_TX), AF1 (I2C1_SCL), AF2 (TIM16_CH1N) + [7] = { .funcs = 0b00001010, .AF = {_U(0), _I(1)}}, // PB7: AF0 (USART1_RX), AF1 (I2C1_SDA), AF2 (TIM17_CH1N) + [10] = { .funcs = 0b00001000, .AF = {_I(1)}}, // PB10: AF1 (I2C1_SCL), AF2 (TIM2_CH3) + [11] = { .funcs = 0b00001000, .AF = {_I(1)}}, // PB11: AF1 (I2C1_SDA), AF2 (TIM2_CH4) } }; #undef _U #undef _S #undef _I -static int is_disabled(uint8_t port, uint8_t pin){ + +typedef struct{ + uint8_t isrx : 1; + uint8_t istx : 1; +} usart_props_t; +/** + * @brief get_usart_index - get USART index (0 or 1 for USART1 or USART2) by given pin + * @param port + * @param pin + * @return -1 if error + */ +static int get_usart_index(uint8_t port, uint8_t pin, usart_props_t *p){ + int idx = -1; + usart_props_t curprops = {0}; + if(port == 0){ // GPIOA + switch(pin){ + case 2: // USART2_TX + idx = 1; + curprops.istx = 1; + break; + case 3: // USART2_RX + idx = 1; + curprops.isrx = 1; + break; + case 9: // USART1_TX + idx = 0; + curprops.istx = 1; + break; + case 10: // USART1_RX + idx = 0; + curprops.isrx = 1; + break; + default: + break; + } + }else if(port == 1){ // GPIOB + switch(pin){ + case 6: // USART1_TX + idx = 0; + curprops.istx = 1; + break; + case 7: // USART1_RX + idx = 0; + curprops.isrx = 1; + break; + default: + break; + } + } + if(p) *p = curprops; + return idx; +} + +// default config +static void defconfig(pinconfig_t *cfg){ + if(!cfg) return; + cfg->af = FUNC_AIN; + cfg->afno = 0; + cfg->mode = MODE_INPUT; + cfg->monitor = 0; + cfg->speed = SPEED_LOW; + cfg->pull = PULL_NONE; +} + +// check current pin configuration; in case of errors set default values (floating input) +int chkpinconf(){ + int ret = TRUE; + if(pinconfig_notinited){ + memcpy(pinconfig, the_conf.pinconfig, sizeof(pinconfig)); + pinconfig_notinited = 0; + } + usartconf_t UC; + if(!get_curusartconf(&UC)){ + get_defusartconf(&UC); + }else{ // got current config -> clear `RXen`, `TXen` and `monitor`: if none appeared, turn OFF USART! + UC.RXen = 0; UC.TXen = 0; UC.monitor = 0; + } + int active_usart = -1; // number of USART if user selects it (we can't check it by UC->idx) + for(int port = 0; port < 2; ++port){ + for(int pin = 0; pin < 16; ++pin){ + pinconfig_t *cfg = &pinconfig[port][pin]; + if(!cfg->enable) continue; + const pinprops_t *props = &pin_props[port][pin]; + // wrong configuration -> don't mind AF, make FLIN + if(cfg->mode == MODE_AF){ + if(cfg->af >= FUNC_AMOUNT || !((1<af) & props->funcs)){ + DBG("Wrong AF config -> FL IN\n"); + defconfig(cfg); + ret = FALSE; + }else{ // set afno to proper number + cfg->afno = props->AF[cfg->af]; + switch(cfg->af){ + case FUNC_USART:{ + usart_props_t up; + int usart_idx = get_usart_index(port, pin, &up); + if(usart_idx < 0){ // error -> defaults + DBG("no USART on this pin\n"); + defconfig(cfg); + ret = FALSE; + break; + } + if(active_usart == -1){ + active_usart = usart_idx; + }else if(active_usart != usart_idx){ + // User tries to configure Rx/Tx on different USARTs + DBG("USART conflicted!\n"); + defconfig(cfg); + ret = FALSE; + break; + } + if(up.isrx) UC.RXen = 1; + else if(up.istx) UC.TXen = 1; + if(cfg->monitor) UC.monitor = 1; + } + break; + default: break; // later fill other functions + } + } + } + } + } + // now check USART configuration + if(active_usart != -1){ + if(chkusartconf(&UC)) ret = FALSE; + }else{ + get_defusartconf(&UC); // clear global configuration + the_conf.usartconfig = UC; + } + return ret; +} + +int is_disabled(uint8_t port, uint8_t pin){ if(port > 1 || pin > 15) return FALSE; if(the_conf.pinconfig[port][pin].enable) return FALSE; return TRUE; } +// return current conf from local `pinconfig` +int get_curpinconf(uint8_t port, uint8_t pin, pinconfig_t *c){ + CHKPINCONFIG(); + if(!c || port > 1 || pin > 15) return FALSE; + *c = pinconfig[port][pin]; + return TRUE; +} + /** * @brief set_pinfunc - check if alternate function `afno` allowed on given pin * @param port - 0 for GPIOA and 1 for GPIOB @@ -94,6 +238,7 @@ static int is_disabled(uint8_t port, uint8_t pin){ */ int set_pinfunc(uint8_t port, uint8_t pin, pinconfig_t *pcfg){ DBG("set_pinfunc()\n"); + CHKPINCONFIG(); if(is_disabled(port, pin) || !pcfg){ DBG("Disabled?\n"); return FALSE; @@ -131,7 +276,7 @@ int set_pinfunc(uint8_t port, uint8_t pin, pinconfig_t *pcfg){ return FALSE; } pcfg->enable = 1; // don't forget to set enable flag! - the_conf.pinconfig[port][pin] = *pcfg; + pinconfig[port][pin] = *pcfg; DBG("All OK\n"); return TRUE; } @@ -153,27 +298,17 @@ TRUE_INLINE int8_t get_adc_channel(uint8_t port, uint8_t pin){ } // reinit all GPIO registers due to config; also configure (if need) USART1/2, SPI1 and I2C1 +// return FALSE if found some errors in current configuration (and it was fixed to default) int gpio_reinit(){ bzero(monitor_mask, sizeof(monitor_mask)); bzero(oldstates, sizeof(oldstates)); - usartconf_t UC = {0}; // fill next + int ret = TRUE; + int tocopy = chkpinconf(); // if config is wrong, don't copy it to flash for(int port = 0; port < 2; port++){ GPIO_TypeDef *gpio = (port == 0) ? GPIOA : GPIOB; for(int pin = 0; pin < 16; pin++){ - pinconfig_t *cfg = &the_conf.pinconfig[port][pin]; + pinconfig_t *cfg = &pinconfig[port][pin]; if(!cfg->enable) continue; - const pinprops_t *props = &pin_props[port][pin]; - if(cfg->mode == MODE_AF && (cfg->af >= FUNC_AMOUNT || - !((1<af) & props->funcs) || - (cfg->afno != props->AF[cfg->af]))){ // wrong configuration -> don't mind AF, make FLIN - DBG("Wrong AF config -> FL IN\n"); - cfg->af = FUNC_AIN; - cfg->afno = 0; - cfg->mode = MODE_INPUT; - cfg->monitor = 0; - cfg->speed = SPEED_LOW; - cfg->pull = PULL_NONE; - } int shift2 = pin << 1; gpio->MODER = (gpio->MODER & ~(3 << shift2))| (cfg->mode << shift2); gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (cfg->otype << pin); @@ -195,18 +330,22 @@ int gpio_reinit(){ oldstates[port][pin] = getADCval(chan); } }else{ - // цифровой режим  сохраняем текущее состояние IDR + // save old state for regular GPIO oldstates[port][pin] = (gpio->IDR >> pin) & 1; } } } } - // TODO: configure USART, SPI etc - if(UC.No && usart_config(&UC)){ - if(!usart_start()) return FALSE; + // if all OK, copy to the_conf + if(tocopy) memcpy(the_conf.pinconfig, pinconfig, sizeof(pinconfig)); + else ret = FALSE; + // TODO: configure SPI etc + usartconf_t usc; + if(get_curusartconf(&usc) && (usc.RXen | usc.TXen)){ + if(!usart_config(NULL)) ret = FALSE; + else if(!usart_start()) ret = FALSE; } - // also chech cfg->monitor! - return TRUE; + return ret; } // get MODER for current pin diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.h b/F0:F030,F042,F072/usbcan_gpio/gpio.h index 10ce618..d4cfc54 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpio.h +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.h @@ -89,14 +89,7 @@ typedef struct{ uint16_t threshold; // threshold for ADC measurement } pinconfig_t; -typedef struct{ - uint32_t baudrate; - uint8_t databits; // 8 or 9 - char parity; // 'N','E','O' - uint8_t stopbits; // 1 or 2 - uint8_t enabled; // is USART active (flag `monitor` taken from pinconfig_t also as Rx/Tx enable) -} usartconfig_t; - +/* typedef struct{ uint32_t speed; uint8_t cpol : 1; @@ -104,6 +97,7 @@ typedef struct{ uint8_t lsbfirst : 1; uint8_t enabled : 1; } spiconfig_t; +*/ // strings for keywords extern const char *str_keywords[]; @@ -121,7 +115,9 @@ KW(USART) \ KW(SPI) \ KW(I2C) \ KW(MONITOR) \ -KW(THRESHOLD) +KW(THRESHOLD) \ +KW(SPEED) \ +KW(TEXT) enum{ // indexes of string keywords #define KW(k) STR_ ## k, @@ -129,8 +125,14 @@ enum{ // indexes of string keywords #undef KW }; +int is_disabled(uint8_t port, uint8_t pin); +int chkpinconf(); + int set_pinfunc(uint8_t port, uint8_t pin, pinconfig_t *pcfg); +int get_curpinconf(uint8_t port, uint8_t pin, pinconfig_t *c); + int gpio_reinit(); + int pin_out(uint8_t port, uint8_t pin, uint8_t newval); int16_t pin_in(uint8_t port, uint8_t pin); uint16_t gpio_alert(uint8_t port); diff --git a/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp b/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp index d13c4e7..23a3ab1 100644 --- a/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp +++ b/F0:F030,F042,F072/usbcan_gpio/gpioproto.cpp @@ -97,7 +97,9 @@ enum KeywordGroup { enum MiscValues{ MISC_MONITOR = 1, - MISC_THRESHOLD + MISC_THRESHOLD, + MISC_SPEED, + MISC_TEXT }; static const Keyword keywords[] = { @@ -116,6 +118,8 @@ static const Keyword keywords[] = { KEY(I2C, GROUP_FUNC, FUNC_I2C) KEY(MONITOR, GROUP_MISC, MISC_MONITOR) KEY(THRESHOLD, GROUP_MISC, MISC_THRESHOLD) + KEY(SPEED, GROUP_MISC, MISC_SPEED) + KEY(TEXT, GROUP_MISC, MISC_TEXT) #undef K }; #define NUM_KEYWORDS (sizeof(keywords)/sizeof(keywords[0])) @@ -214,17 +218,31 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ // complex setter: parse properties uint8_t mode_set = 0xFF, pull_set = 0xFF, otype_set = 0xFF, func_set = 0xFF; bool monitor = false; - uint16_t *pending_num = NULL; // pointer to UINT16 value, if !NULL, next token should be a number - pinconfig_t curconf = the_conf.pinconfig[port][pin]; // copy old config - char *saveptr, *token = strtok_r(setter, " ,", &saveptr); + uint16_t *pending_u16 = NULL; // pointer to uint16_t value, if !NULL, next token should be a number + uint32_t *pending_u32 = NULL; // -//- for uint32_t + usartconf_t UsartConf; + if(!get_curusartconf(&UsartConf)) return ERR_CANTRUN; + pinconfig_t curconf; + if(!get_curpinconf(port, pin, &curconf)) return ERR_BADVAL; // copy current config +#define DELIM_ " ," + char *saveptr, *token = strtok_r(setter, DELIM_, &saveptr); while(token){ - if(pending_num){ - int32_t val; - char *end = getint(token, &val); - if(end == token || val < 0 || val > 0xFFFF) return ERR_BADVAL; - *pending_num = (uint16_t)val; - pending_num = NULL; // reset - token = strtok_r(NULL, " ,", &saveptr); + if(pending_u16){ + uint32_t val; + char *end = getnum(token, &val); + if(end == token || val > 0xFFFF) return ERR_BADVAL; + *pending_u16 = (uint16_t)val; + pending_u16 = NULL; // reset + token = strtok_r(NULL, DELIM_, &saveptr); + continue; + } + if(pending_u32){ + uint32_t val; + char *end = getnum(token, &val); + if(end == token) return ERR_BADVAL; + *pending_u32 = val; + pending_u32 = NULL; + token = strtok_r(NULL, DELIM_, &saveptr); continue; } size_t i = 0; @@ -258,17 +276,28 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ monitor = true; break; case MISC_THRESHOLD: - pending_num = &curconf.threshold; + pending_u16 = &curconf.threshold; + break; + case MISC_SPEED: + pending_u32 = &UsartConf.speed; + break; + case MISC_TEXT: // what to do, if textproto is set, but user wants binary? + UsartConf.textproto = 1; break; } + break; } break; } } if(i == NUM_KEYWORDS) return ERR_BADVAL; // not found - token = strtok_r(NULL, " ,", &saveptr); + token = strtok_r(NULL, DELIM_, &saveptr); } - if(pending_num) return ERR_BADVAL; // no number that we waiting for + if(pending_u16 || pending_u32) return ERR_BADVAL; // no number that we waiting for + +// check periferial settings before refresh pin data + // check current USART settings + if(func_set == FUNC_USART && !chkusartconf(&UsartConf)) return ERR_BADVAL; if(func_set != 0xFF) mode_set = MODE_AF; if(mode_set == 0xFF) return ERR_BADVAL; // user forgot to set mode // set defaults @@ -296,8 +325,7 @@ static errcodes_t parse_pin_command(const char *cmd, char *args){ char *setter = splitargs(args, &pin); DBG("args="); DBG(args); DBG(", pin="); DBG(i2str(pin)); DBG(", setter="); DBG(setter); DBGNL(); if(pin < 0 || pin > 15) return ERR_BADPAR; - pinconfig_t *pcfg = &the_conf.pinconfig[port][pin]; // just to check if pin can be configured - if(!pcfg->enable) return ERR_CANTRUN; // prohibited pin + if(is_disabled(port, pin)) return ERR_CANTRUN; // prohibited pin if(!setter){ // simple getter -> get value and return ERR_AMOUNT as silence DBG("Getter\n"); pin_getter(port, pin); @@ -363,7 +391,7 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){ for(int pin = 0; pin < 16; pin++){ pinconfig_t *p = &the_conf.pinconfig[port][pin]; if(!p->enable) continue; - PUTCHAR('P'); PUTCHAR(port_letter); SEND(i2str(pin)); PUTCHAR('='); + PUTCHAR('P'); PUTCHAR(port_letter); SEND(i2str(pin)); SEND(EQ); switch(p->mode){ #define S(k) SEND(str_keywords[STR_ ## k]) #define SP(k) do{PUTCHAR(' '); S(k);}while(0) @@ -409,10 +437,18 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){ // Monitor if(p->monitor) SP(MONITOR); NL(); -#undef S -#undef SP } } + usartconf_t U = the_conf.usartconfig; + if(U.RXen || U.TXen){ // USART enabled -> tell config + S(USART); SEND(EQ); + S(SPEED); PUTCHAR(' '); SEND(u2str(U.speed)); + if(U.textproto) SP(TEXT); + if(U.monitor) SP(MONITOR); + if(U.TXen && !U.RXen) SEND(" TXONLY"); + else if(!U.TXen && U.RXen) SEND(" RXONLY"); + NL(); + } // here are usart/spi/i2c configurations #if 0 bool usart_enabled = false; @@ -449,6 +485,8 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){ } #endif return ERR_AMOUNT; +#undef S +#undef SP } static errcodes_t cmd_setiface(const char* cmd, char *args){ diff --git a/F0:F030,F042,F072/usbcan_gpio/usart.c b/F0:F030,F042,F072/usbcan_gpio/usart.c index 9bab9fb..fa572e4 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usart.c +++ b/F0:F030,F042,F072/usbcan_gpio/usart.c @@ -19,6 +19,7 @@ #include #include +#include "flash.h" #include "ringbuffer.h" #include "usart.h" @@ -43,40 +44,83 @@ static ringbuffer RBin = {.data = rbbuffer, .length = RXRBSZ}; static volatile USART_TypeDef* const Usarts[USARTSNO] = {USART1, USART2}; static uint8_t const UIRQs[USARTSNO] = {USART1_IRQn, USART2_IRQn}; +static usartconf_t usartconfig; +static uint8_t usartconfig_notinited = 1; +#define CHKUSARTCONFIG() do{if(usartconfig_notinited) chkusartconf(NULL);}while(0) + +// check config and if all OK, copy to local; if c == NULL, check local config and set defaults to wrong values +// return FALSE if some parameters was changed to default (in this case not copy to local) +int chkusartconf(usartconf_t *c){ + int ret = TRUE; + if(usartconfig_notinited){ + usartconfig = the_conf.usartconfig; + usartconfig_notinited = 0; + } + uint8_t copyto = TRUE; + if(!c){ + copyto = FALSE; + c = &usartconfig; + } + if(c->speed < USART_MIN_SPEED || c->speed > USART_MAX_SPEED){ + c->speed = USART_DEFAULT_SPEED; + ret = FALSE; + } + // another tests could be here (like stopbits etc, if you wish) + if(ret && copyto) usartconfig = *c; + return ret; +} + +// just give default speed +void get_defusartconf(usartconf_t *c){ + if(!c) return; + bzero(c, sizeof(usartconf_t)); + c->speed = USART_DEFAULT_SPEED; +} + +int get_curusartconf(usartconf_t *c){ + CHKUSARTCONFIG(); + if(!c) return FALSE; + *c = usartconfig; + return TRUE; +} + /** * @brief usart_config - configure US[A]RT based on usb_LineCoding - * @param usartconf (io) - (modified to real speeds) + * @param usartconf (io) - (modified to real speeds); if NULL - get current * @return TRUE if all OK */ -int usart_config(usartconf_t *usartconf){ +int usart_config(usartconf_t *uc){ + CHKUSARTCONFIG(); + if(uc && !chkusartconf(uc)) return FALSE; + if(0 == usartconfig.RXen && 0 == usartconfig.TXen){ // no Rx/Tx + usart_stop(); + return FALSE; + } SYSCFG->CFGR1 |= SYSCFG_CFGR1_USART1RX_DMA_RMP | SYSCFG_CFGR1_USART1TX_DMA_RMP; // both USARTs on DMA1ch4(tx)/5(rx) // all clocking and GPIO config should be done in hardware_setup() & gpio_reinit()! - if(!usartconf) return FALSE; if(curUSARTidx != -1) usart_stop(); // disable previous USART if enabled - uint8_t No = usartconf->No; - if(No >= USARTSNO || No < 1 || usartconf->speed < USART_MIN_SPEED) return FALSE; - --No; // now this is an INDEX! + uint8_t No = usartconfig.idx; volatile USART_TypeDef *U = Usarts[No]; uint32_t peripheral_clock = 48000000; // Disable USART while configuring U->CR1 = 0; U->ICR = 0xFFFFFFFF; // Clear all interrupt flags // Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8. - U->BRR = peripheral_clock / (usartconf->speed); - usartconf->speed= peripheral_clock / U->BRR; // fix for real speed + 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(usartconf->monitor){ - if(usartconf->textproto){ + 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 } - textformat = usartconf->textproto; - monitor = usartconf->monitor; + textformat = usartconfig.textproto; + monitor = usartconfig.monitor; // Enable transmitter, receiver, and interrupts (optional) - if(usartconf->Rxen) cr1 |= USART_CR1_RE; - if(usartconf->Txen){ + if(usartconfig.RXen) cr1 |= USART_CR1_RE; + if(usartconfig.TXen){ cr1 |= USART_CR1_TE; // DMA Tx volatile DMA_Channel_TypeDef *T = DMA1_Channel4; @@ -87,6 +131,8 @@ int usart_config(usartconf_t *usartconf){ // Main config U->CR1 = cr1; curUSARTidx = No; + // all OK -> copy to global config + the_conf.usartconfig = usartconfig; return TRUE; } diff --git a/F0:F030,F042,F072/usbcan_gpio/usart.h b/F0:F030,F042,F072/usbcan_gpio/usart.h index 5f3b10b..f5e1e77 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usart.h +++ b/F0:F030,F042,F072/usbcan_gpio/usart.h @@ -21,27 +21,33 @@ #include // DMA linear buffers for Rx/Tx -#define DMARXBUFSZ 128 -#define DMATXBUFSZ 128 +#define DMARXBUFSZ 128 +#define DMATXBUFSZ 128 // incoming ring buffer - only if there's a lot of data in DMA RX buffer -#define RXRBSZ 256 +#define RXRBSZ 256 -#define USART_MIN_SPEED 1024 -#define USART_MAX_SPEED 1000000 +#define USART_MIN_SPEED 1024 +#define USART_MAX_SPEED 1000000 +#define USART_DEFAULT_SPEED 9600 typedef struct{ uint32_t speed; // baudrate - uint8_t No : 2; // Usart number (1/2) - uint8_t Rxen : 1; // enable rx - uint8_t Txen : 1; // enable tx + uint8_t idx : 1; // Usart idx (0/1 for USART1/USART2) + uint8_t RXen : 1; // enable rx + uint8_t TXen : 1; // enable tx uint8_t textproto : 1; // match '\n' and force output by lines (if there's enough place in buffers and monitor == 1) uint8_t monitor : 1; // async output by incoming (over '\n', IDLE or buffer full) } usartconf_t; int usart_config(usartconf_t *config); +int chkusartconf(usartconf_t *c); + int usart_start(); void usart_stop(); +int get_curusartconf(usartconf_t *c); +void get_defusartconf(usartconf_t *c); + int usart_process(uint8_t *buf, int len); int usart_receive(uint8_t *buf, int len); diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin index 2741aab1efeb18cd5f09e08b0c83eef8b7f7f637..e41fd58ea5a2eea3861349fd8ec01f7879db8834 100755 GIT binary patch delta 12473 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 diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user index da59294..b138528 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 68c5f07..1100d14 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 "146" -#define BUILD_DATE "2026-03-11" +#define BUILD_NUMBER "156" +#define BUILD_DATE "2026-03-12"