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 2741aab..e41fd58 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 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"