mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-03-20 00:30:57 +03:00
cont
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
|
#include "usart.h"
|
||||||
#include "usb_descr.h"
|
#include "usb_descr.h"
|
||||||
|
|
||||||
// register with flash size (in blocks)
|
// 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)!
|
uint8_t iIlengths[InterfacesAmount]; // length in BYTES (symbols amount x2)!
|
||||||
// gpio settings
|
// gpio settings
|
||||||
pinconfig_t pinconfig[2][16]; // GPIOA, GPIOB
|
pinconfig_t pinconfig[2][16]; // GPIOA, GPIOB
|
||||||
usartconfig_t usartconfig;
|
usartconf_t usartconfig;
|
||||||
spiconfig_t spiconfig;
|
//spiconfig_t spiconfig;
|
||||||
} user_conf;
|
} user_conf;
|
||||||
|
|
||||||
extern user_conf the_conf; // global user config (read from FLASH to RAM)
|
extern user_conf the_conf; // global user config (read from FLASH to RAM)
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ const char *str_keywords[] = {
|
|||||||
#undef KW
|
#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
|
// TODO: remove AFmask, make function to get right AF number by pin's FuncValues
|
||||||
typedef struct{
|
typedef struct{
|
||||||
uint8_t funcs; // bitmask according to enum FuncNames
|
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)
|
[1] = { .funcs = 0b00000001, .AF = {0}}, // PA1: ADC1, AF2 (TIM2_CH2)
|
||||||
[2] = { .funcs = 0b00000011, .AF = {_U(1)}}, // PA2: ADC2, AF2 (TIM2_CH3), AF1 (USART2_TX)
|
[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)
|
[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)
|
[5] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA5: ADC5, AF9 (SPI1_SCK)
|
||||||
[6] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA6: ADC6, SPI1_MISO (AF0)
|
[6] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA6: ADC6, AF0 (SPI1_MISO)
|
||||||
[7] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA7: ADC7, SPI1_MOSI (AF0)
|
[7] = { .funcs = 0b00000101, .AF = {_S(0)}}, // PA7: ADC7, AF0 (SPI1_MOSI)
|
||||||
[9] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA9: USART1_TX (AF1)
|
[9] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA9: AF1 (USART1_TX)
|
||||||
[10] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA10: USART1_RX (AF1)
|
[10] = { .funcs = 0b00000010, .AF = {_U(1)}}, // PA10: AF1 (USART1_RX)
|
||||||
},
|
},
|
||||||
[1] = { // PORT B
|
[1] = { // PORT B
|
||||||
[0] = { .funcs = 0b00000001, .AF = {0}}, // PB0: ADC8, TIM3_CH3 (AF1), TIM1_CH2N (AF2)
|
[0] = { .funcs = 0b00000001, .AF = {0}}, // PB0: ADC8, AF1 (TIM3_CH3), AF2 (TIM1_CH2N)
|
||||||
[1] = { .funcs = 0b00000001, .AF = {0}}, // PB1: ADC9, TIM14_CH1 (AF0), TIM3_CH4 (AF1), TIM1_CH3N (AF2)
|
[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
|
[2] = { .funcs = 0b00000000, .AF = {0}}, // PB2: nothing except GPIO
|
||||||
[3] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB3: SPI1_SCK (AF0), TIM2_CH2 (AF2)
|
[3] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB3: AF0, (SPI1_SCK), AF2 (TIM2_CH2)
|
||||||
[4] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB4: SPI1_MISO (AF0), TIM3_CH1 (AF1)
|
[4] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB4: AF0 (SPI1_MISO), AF1 (TIM3_CH1)
|
||||||
[5] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB5: SPI1_MOSI (AF0), TIM3_CH2 (AF1)
|
[5] = { .funcs = 0b00000100, .AF = {_S(0)}}, // PB5: AF0 (SPI1_MOSI), AF1 (TIM3_CH2)
|
||||||
[6] = { .funcs = 0b00001010, .AF = {_U(0), _I(1)}}, // PB6: USART1_TX (AF0), I2C1_SCL (AF1), TIM16_CH1N (AF2)
|
[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: USART1_RX (AF0), I2C1_SDA (AF1), TIM17_CH1N (AF2)
|
[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: I2C1_SCL (AF1), TIM2_CH3 (AF2)
|
[10] = { .funcs = 0b00001000, .AF = {_I(1)}}, // PB10: AF1 (I2C1_SCL), AF2 (TIM2_CH3)
|
||||||
[11] = { .funcs = 0b00001000, .AF = {_I(1)}}, // PB11: I2C1_SDA (AF1), TIM2_CH4 (AF2)
|
[11] = { .funcs = 0b00001000, .AF = {_I(1)}}, // PB11: AF1 (I2C1_SDA), AF2 (TIM2_CH4)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#undef _U
|
#undef _U
|
||||||
#undef _S
|
#undef _S
|
||||||
#undef _I
|
#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<<cfg->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(port > 1 || pin > 15) return FALSE;
|
||||||
if(the_conf.pinconfig[port][pin].enable) return FALSE;
|
if(the_conf.pinconfig[port][pin].enable) return FALSE;
|
||||||
return TRUE;
|
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
|
* @brief set_pinfunc - check if alternate function `afno` allowed on given pin
|
||||||
* @param port - 0 for GPIOA and 1 for GPIOB
|
* @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){
|
int set_pinfunc(uint8_t port, uint8_t pin, pinconfig_t *pcfg){
|
||||||
DBG("set_pinfunc()\n");
|
DBG("set_pinfunc()\n");
|
||||||
|
CHKPINCONFIG();
|
||||||
if(is_disabled(port, pin) || !pcfg){
|
if(is_disabled(port, pin) || !pcfg){
|
||||||
DBG("Disabled?\n");
|
DBG("Disabled?\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -131,7 +276,7 @@ int set_pinfunc(uint8_t port, uint8_t pin, pinconfig_t *pcfg){
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
pcfg->enable = 1; // don't forget to set enable flag!
|
pcfg->enable = 1; // don't forget to set enable flag!
|
||||||
the_conf.pinconfig[port][pin] = *pcfg;
|
pinconfig[port][pin] = *pcfg;
|
||||||
DBG("All OK\n");
|
DBG("All OK\n");
|
||||||
return TRUE;
|
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
|
// 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(){
|
int gpio_reinit(){
|
||||||
bzero(monitor_mask, sizeof(monitor_mask));
|
bzero(monitor_mask, sizeof(monitor_mask));
|
||||||
bzero(oldstates, sizeof(oldstates));
|
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++){
|
for(int port = 0; port < 2; port++){
|
||||||
GPIO_TypeDef *gpio = (port == 0) ? GPIOA : GPIOB;
|
GPIO_TypeDef *gpio = (port == 0) ? GPIOA : GPIOB;
|
||||||
for(int pin = 0; pin < 16; pin++){
|
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;
|
if(!cfg->enable) continue;
|
||||||
const pinprops_t *props = &pin_props[port][pin];
|
|
||||||
if(cfg->mode == MODE_AF && (cfg->af >= FUNC_AMOUNT ||
|
|
||||||
!((1<<cfg->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;
|
int shift2 = pin << 1;
|
||||||
gpio->MODER = (gpio->MODER & ~(3 << shift2))| (cfg->mode << shift2);
|
gpio->MODER = (gpio->MODER & ~(3 << shift2))| (cfg->mode << shift2);
|
||||||
gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (cfg->otype << pin);
|
gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (cfg->otype << pin);
|
||||||
@@ -195,18 +330,22 @@ int gpio_reinit(){
|
|||||||
oldstates[port][pin] = getADCval(chan);
|
oldstates[port][pin] = getADCval(chan);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
// ÃÉÆÒÏ×ÏÊ ÒÅÖÉÍ ÓÏÈÒÁÎÑÅÍ ÔÅËÕÝÅÅ ÓÏÓÔÏÑÎÉÅ IDR
|
// save old state for regular GPIO
|
||||||
oldstates[port][pin] = (gpio->IDR >> pin) & 1;
|
oldstates[port][pin] = (gpio->IDR >> pin) & 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: configure USART, SPI etc
|
// if all OK, copy to the_conf
|
||||||
if(UC.No && usart_config(&UC)){
|
if(tocopy) memcpy(the_conf.pinconfig, pinconfig, sizeof(pinconfig));
|
||||||
if(!usart_start()) return FALSE;
|
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 ret;
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get MODER for current pin
|
// get MODER for current pin
|
||||||
|
|||||||
@@ -89,14 +89,7 @@ typedef struct{
|
|||||||
uint16_t threshold; // threshold for ADC measurement
|
uint16_t threshold; // threshold for ADC measurement
|
||||||
} pinconfig_t;
|
} 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{
|
typedef struct{
|
||||||
uint32_t speed;
|
uint32_t speed;
|
||||||
uint8_t cpol : 1;
|
uint8_t cpol : 1;
|
||||||
@@ -104,6 +97,7 @@ typedef struct{
|
|||||||
uint8_t lsbfirst : 1;
|
uint8_t lsbfirst : 1;
|
||||||
uint8_t enabled : 1;
|
uint8_t enabled : 1;
|
||||||
} spiconfig_t;
|
} spiconfig_t;
|
||||||
|
*/
|
||||||
|
|
||||||
// strings for keywords
|
// strings for keywords
|
||||||
extern const char *str_keywords[];
|
extern const char *str_keywords[];
|
||||||
@@ -121,7 +115,9 @@ KW(USART) \
|
|||||||
KW(SPI) \
|
KW(SPI) \
|
||||||
KW(I2C) \
|
KW(I2C) \
|
||||||
KW(MONITOR) \
|
KW(MONITOR) \
|
||||||
KW(THRESHOLD)
|
KW(THRESHOLD) \
|
||||||
|
KW(SPEED) \
|
||||||
|
KW(TEXT)
|
||||||
|
|
||||||
enum{ // indexes of string keywords
|
enum{ // indexes of string keywords
|
||||||
#define KW(k) STR_ ## k,
|
#define KW(k) STR_ ## k,
|
||||||
@@ -129,8 +125,14 @@ enum{ // indexes of string keywords
|
|||||||
#undef KW
|
#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 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 gpio_reinit();
|
||||||
|
|
||||||
int pin_out(uint8_t port, uint8_t pin, uint8_t newval);
|
int pin_out(uint8_t port, uint8_t pin, uint8_t newval);
|
||||||
int16_t pin_in(uint8_t port, uint8_t pin);
|
int16_t pin_in(uint8_t port, uint8_t pin);
|
||||||
uint16_t gpio_alert(uint8_t port);
|
uint16_t gpio_alert(uint8_t port);
|
||||||
|
|||||||
@@ -97,7 +97,9 @@ enum KeywordGroup {
|
|||||||
|
|
||||||
enum MiscValues{
|
enum MiscValues{
|
||||||
MISC_MONITOR = 1,
|
MISC_MONITOR = 1,
|
||||||
MISC_THRESHOLD
|
MISC_THRESHOLD,
|
||||||
|
MISC_SPEED,
|
||||||
|
MISC_TEXT
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Keyword keywords[] = {
|
static const Keyword keywords[] = {
|
||||||
@@ -116,6 +118,8 @@ static const Keyword keywords[] = {
|
|||||||
KEY(I2C, GROUP_FUNC, FUNC_I2C)
|
KEY(I2C, GROUP_FUNC, FUNC_I2C)
|
||||||
KEY(MONITOR, GROUP_MISC, MISC_MONITOR)
|
KEY(MONITOR, GROUP_MISC, MISC_MONITOR)
|
||||||
KEY(THRESHOLD, GROUP_MISC, MISC_THRESHOLD)
|
KEY(THRESHOLD, GROUP_MISC, MISC_THRESHOLD)
|
||||||
|
KEY(SPEED, GROUP_MISC, MISC_SPEED)
|
||||||
|
KEY(TEXT, GROUP_MISC, MISC_TEXT)
|
||||||
#undef K
|
#undef K
|
||||||
};
|
};
|
||||||
#define NUM_KEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
|
#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
|
// complex setter: parse properties
|
||||||
uint8_t mode_set = 0xFF, pull_set = 0xFF, otype_set = 0xFF, func_set = 0xFF;
|
uint8_t mode_set = 0xFF, pull_set = 0xFF, otype_set = 0xFF, func_set = 0xFF;
|
||||||
bool monitor = false;
|
bool monitor = false;
|
||||||
uint16_t *pending_num = NULL; // pointer to UINT16 value, if !NULL, next token should be a number
|
uint16_t *pending_u16 = NULL; // pointer to uint16_t value, if !NULL, next token should be a number
|
||||||
pinconfig_t curconf = the_conf.pinconfig[port][pin]; // copy old config
|
uint32_t *pending_u32 = NULL; // -//- for uint32_t
|
||||||
char *saveptr, *token = strtok_r(setter, " ,", &saveptr);
|
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){
|
while(token){
|
||||||
if(pending_num){
|
if(pending_u16){
|
||||||
int32_t val;
|
uint32_t val;
|
||||||
char *end = getint(token, &val);
|
char *end = getnum(token, &val);
|
||||||
if(end == token || val < 0 || val > 0xFFFF) return ERR_BADVAL;
|
if(end == token || val > 0xFFFF) return ERR_BADVAL;
|
||||||
*pending_num = (uint16_t)val;
|
*pending_u16 = (uint16_t)val;
|
||||||
pending_num = NULL; // reset
|
pending_u16 = NULL; // reset
|
||||||
token = strtok_r(NULL, " ,", &saveptr);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@@ -258,17 +276,28 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
|
|||||||
monitor = true;
|
monitor = true;
|
||||||
break;
|
break;
|
||||||
case MISC_THRESHOLD:
|
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;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(i == NUM_KEYWORDS) return ERR_BADVAL; // not found
|
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(func_set != 0xFF) mode_set = MODE_AF;
|
||||||
if(mode_set == 0xFF) return ERR_BADVAL; // user forgot to set mode
|
if(mode_set == 0xFF) return ERR_BADVAL; // user forgot to set mode
|
||||||
// set defaults
|
// set defaults
|
||||||
@@ -296,8 +325,7 @@ static errcodes_t parse_pin_command(const char *cmd, char *args){
|
|||||||
char *setter = splitargs(args, &pin);
|
char *setter = splitargs(args, &pin);
|
||||||
DBG("args="); DBG(args); DBG(", pin="); DBG(i2str(pin)); DBG(", setter="); DBG(setter); DBGNL();
|
DBG("args="); DBG(args); DBG(", pin="); DBG(i2str(pin)); DBG(", setter="); DBG(setter); DBGNL();
|
||||||
if(pin < 0 || pin > 15) return ERR_BADPAR;
|
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(is_disabled(port, pin)) return ERR_CANTRUN; // prohibited pin
|
||||||
if(!pcfg->enable) return ERR_CANTRUN; // prohibited pin
|
|
||||||
if(!setter){ // simple getter -> get value and return ERR_AMOUNT as silence
|
if(!setter){ // simple getter -> get value and return ERR_AMOUNT as silence
|
||||||
DBG("Getter\n");
|
DBG("Getter\n");
|
||||||
pin_getter(port, pin);
|
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++){
|
for(int pin = 0; pin < 16; pin++){
|
||||||
pinconfig_t *p = &the_conf.pinconfig[port][pin];
|
pinconfig_t *p = &the_conf.pinconfig[port][pin];
|
||||||
if(!p->enable) continue;
|
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){
|
switch(p->mode){
|
||||||
#define S(k) SEND(str_keywords[STR_ ## k])
|
#define S(k) SEND(str_keywords[STR_ ## k])
|
||||||
#define SP(k) do{PUTCHAR(' '); S(k);}while(0)
|
#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
|
// Monitor
|
||||||
if(p->monitor) SP(MONITOR);
|
if(p->monitor) SP(MONITOR);
|
||||||
NL();
|
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
|
// here are usart/spi/i2c configurations
|
||||||
#if 0
|
#if 0
|
||||||
bool usart_enabled = false;
|
bool usart_enabled = false;
|
||||||
@@ -449,6 +485,8 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return ERR_AMOUNT;
|
return ERR_AMOUNT;
|
||||||
|
#undef S
|
||||||
|
#undef SP
|
||||||
}
|
}
|
||||||
|
|
||||||
static errcodes_t cmd_setiface(const char* cmd, char *args){
|
static errcodes_t cmd_setiface(const char* cmd, char *args){
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <stm32f0.h>
|
#include <stm32f0.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "usart.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 volatile USART_TypeDef* const Usarts[USARTSNO] = {USART1, USART2};
|
||||||
static uint8_t const UIRQs[USARTSNO] = {USART1_IRQn, USART2_IRQn};
|
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
|
* @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
|
* @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)
|
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()!
|
// 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
|
if(curUSARTidx != -1) usart_stop(); // disable previous USART if enabled
|
||||||
uint8_t No = usartconf->No;
|
uint8_t No = usartconfig.idx;
|
||||||
if(No >= USARTSNO || No < 1 || usartconf->speed < USART_MIN_SPEED) return FALSE;
|
|
||||||
--No; // now this is an INDEX!
|
|
||||||
volatile USART_TypeDef *U = Usarts[No];
|
volatile USART_TypeDef *U = Usarts[No];
|
||||||
uint32_t peripheral_clock = 48000000;
|
uint32_t peripheral_clock = 48000000;
|
||||||
// Disable USART while configuring
|
// Disable USART while configuring
|
||||||
U->CR1 = 0;
|
U->CR1 = 0;
|
||||||
U->ICR = 0xFFFFFFFF; // Clear all interrupt flags
|
U->ICR = 0xFFFFFFFF; // Clear all interrupt flags
|
||||||
// Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8.
|
// Assuming oversampling by 16 (default after reset). For higher baud rates you might use by 8.
|
||||||
U->BRR = peripheral_clock / (usartconf->speed);
|
U->BRR = peripheral_clock / (usartconfig.speed);
|
||||||
usartconf->speed= peripheral_clock / U->BRR; // fix for real speed
|
usartconfig.speed= peripheral_clock / U->BRR; // fix for real speed
|
||||||
uint32_t cr1 = 0;
|
uint32_t cr1 = 0;
|
||||||
// format: 8N1, so CR2 used only for character match (if need)
|
// format: 8N1, so CR2 used only for character match (if need)
|
||||||
if(usartconf->monitor){
|
if(usartconfig.monitor){
|
||||||
if(usartconf->textproto){
|
if(usartconfig.textproto){
|
||||||
U->CR2 = USART_CR2_ADD_VAL('\n');
|
U->CR2 = USART_CR2_ADD_VAL('\n');
|
||||||
cr1 |= USART_CR1_CMIE;
|
cr1 |= USART_CR1_CMIE;
|
||||||
}else cr1 |= USART_CR1_IDLEIE; // monitor binary data by IDLE flag
|
}else cr1 |= USART_CR1_IDLEIE; // monitor binary data by IDLE flag
|
||||||
}
|
}
|
||||||
textformat = usartconf->textproto;
|
textformat = usartconfig.textproto;
|
||||||
monitor = usartconf->monitor;
|
monitor = usartconfig.monitor;
|
||||||
// Enable transmitter, receiver, and interrupts (optional)
|
// Enable transmitter, receiver, and interrupts (optional)
|
||||||
if(usartconf->Rxen) cr1 |= USART_CR1_RE;
|
if(usartconfig.RXen) cr1 |= USART_CR1_RE;
|
||||||
if(usartconf->Txen){
|
if(usartconfig.TXen){
|
||||||
cr1 |= USART_CR1_TE;
|
cr1 |= USART_CR1_TE;
|
||||||
// DMA Tx
|
// DMA Tx
|
||||||
volatile DMA_Channel_TypeDef *T = DMA1_Channel4;
|
volatile DMA_Channel_TypeDef *T = DMA1_Channel4;
|
||||||
@@ -87,6 +131,8 @@ int usart_config(usartconf_t *usartconf){
|
|||||||
// Main config
|
// Main config
|
||||||
U->CR1 = cr1;
|
U->CR1 = cr1;
|
||||||
curUSARTidx = No;
|
curUSARTidx = No;
|
||||||
|
// all OK -> copy to global config
|
||||||
|
the_conf.usartconfig = usartconfig;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,20 +28,26 @@
|
|||||||
|
|
||||||
#define USART_MIN_SPEED 1024
|
#define USART_MIN_SPEED 1024
|
||||||
#define USART_MAX_SPEED 1000000
|
#define USART_MAX_SPEED 1000000
|
||||||
|
#define USART_DEFAULT_SPEED 9600
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
uint32_t speed; // baudrate
|
uint32_t speed; // baudrate
|
||||||
uint8_t No : 2; // Usart number (1/2)
|
uint8_t idx : 1; // Usart idx (0/1 for USART1/USART2)
|
||||||
uint8_t Rxen : 1; // enable rx
|
uint8_t RXen : 1; // enable rx
|
||||||
uint8_t Txen : 1; // enable tx
|
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 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)
|
uint8_t monitor : 1; // async output by incoming (over '\n', IDLE or buffer full)
|
||||||
} usartconf_t;
|
} usartconf_t;
|
||||||
|
|
||||||
int usart_config(usartconf_t *config);
|
int usart_config(usartconf_t *config);
|
||||||
|
int chkusartconf(usartconf_t *c);
|
||||||
|
|
||||||
int usart_start();
|
int usart_start();
|
||||||
void usart_stop();
|
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_process(uint8_t *buf, int len);
|
||||||
|
|
||||||
int usart_receive(uint8_t *buf, int len);
|
int usart_receive(uint8_t *buf, int len);
|
||||||
|
|||||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 18.0.2, 2026-03-11T23:40:18. -->
|
<!-- Written by QtCreator 18.0.2, 2026-03-13T00:12:36. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "146"
|
#define BUILD_NUMBER "156"
|
||||||
#define BUILD_DATE "2026-03-11"
|
#define BUILD_DATE "2026-03-12"
|
||||||
|
|||||||
Reference in New Issue
Block a user