mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-03-20 08:40:57 +03:00
add SPI, not working yet (also need to set SPOL/SPHA etc)
This commit is contained in:
@@ -44,13 +44,13 @@
|
|||||||
typedef struct __attribute__((packed, aligned(4))){
|
typedef struct __attribute__((packed, aligned(4))){
|
||||||
uint16_t userconf_sz; // "magick number"
|
uint16_t userconf_sz; // "magick number"
|
||||||
uint16_t CANspeed; // default CAN speed (in kBaud!!!)
|
uint16_t CANspeed; // default CAN speed (in kBaud!!!)
|
||||||
|
uint32_t SPIspeed; // SPI speed, baud
|
||||||
uint16_t iInterface[InterfacesAmount][MAX_IINTERFACE_SZ]; // we store Interface name here in UTF!
|
uint16_t iInterface[InterfacesAmount][MAX_IINTERFACE_SZ]; // we store Interface name here in UTF!
|
||||||
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
|
||||||
usartconf_t usartconfig;
|
usartconf_t usartconfig;
|
||||||
uint8_t I2Cspeed;
|
uint8_t I2Cspeed; // I2C speed index
|
||||||
//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)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "gpio.h"
|
#include "gpio.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "pwm.h"
|
#include "pwm.h"
|
||||||
|
#include "spi.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
|
|
||||||
static uint16_t monitor_mask[2] = {0}; // pins to monitor == 1 (ONLY GPIO and ADC)
|
static uint16_t monitor_mask[2] = {0}; // pins to monitor == 1 (ONLY GPIO and ADC)
|
||||||
@@ -83,6 +84,7 @@ static const pinprops_t pin_props[2][16] = {
|
|||||||
#define CANPWM(x) ((x) & (1<<FUNC_PWM))
|
#define CANPWM(x) ((x) & (1<<FUNC_PWM))
|
||||||
|
|
||||||
static uint8_t haveI2C = 0; // ==1 if chkpinconf found I2C
|
static uint8_t haveI2C = 0; // ==1 if chkpinconf found I2C
|
||||||
|
static uint8_t haveSPI = 0;
|
||||||
|
|
||||||
// return pin_props[port][pin].funcs for listing or -1 if disabled
|
// return pin_props[port][pin].funcs for listing or -1 if disabled
|
||||||
int pinfuncs(uint8_t port, uint8_t pin){
|
int pinfuncs(uint8_t port, uint8_t pin){
|
||||||
@@ -142,7 +144,7 @@ int get_usart_index(uint8_t port, uint8_t pin, usart_props_t *p){
|
|||||||
// return -1 if pin can't I2C, or return 0 and fill `p`
|
// return -1 if pin can't I2C, or return 0 and fill `p`
|
||||||
int get_i2c_index(uint8_t port, uint8_t pin, i2c_props_t *p){
|
int get_i2c_index(uint8_t port, uint8_t pin, i2c_props_t *p){
|
||||||
if(port > 1 || pin > 15 || !CANI2C(pin_props[port][pin].funcs)) return -1;
|
if(port > 1 || pin > 15 || !CANI2C(pin_props[port][pin].funcs)) return -1;
|
||||||
int idx = -1; // I2C1 is alone
|
int idx = -1; // later we can add SPI2 support
|
||||||
i2c_props_t curprops = {0};
|
i2c_props_t curprops = {0};
|
||||||
if(port == 1){ // only GPIOB
|
if(port == 1){ // only GPIOB
|
||||||
switch(pin){
|
switch(pin){
|
||||||
@@ -170,6 +172,47 @@ int get_i2c_index(uint8_t port, uint8_t pin, i2c_props_t *p){
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_spi_index(uint8_t port, uint8_t pin, spi_props_t *p){
|
||||||
|
if(port > 1 || pin > 15 || !CANSPI(pin_props[port][pin].funcs)) return -1;
|
||||||
|
int idx = -1;
|
||||||
|
spi_props_t curprops = {0};
|
||||||
|
if(port == 0){ // PA5-7 (SCK-MISO-MOSI)
|
||||||
|
switch(pin){
|
||||||
|
case 5:
|
||||||
|
idx = 0;
|
||||||
|
curprops.issck =1;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
idx = 0;
|
||||||
|
curprops.ismiso = 1;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
idx = 0;
|
||||||
|
curprops.ismosi = 1;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}else if(port == 1){ // PB3-5 (SCK-MISO-MOSI)
|
||||||
|
switch(pin){
|
||||||
|
case 3:
|
||||||
|
idx = 0;
|
||||||
|
curprops.issck =1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
idx = 0;
|
||||||
|
curprops.ismiso = 1;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
idx = 0;
|
||||||
|
curprops.ismosi = 1;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(p) *p = curprops;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
// default config
|
// default config
|
||||||
static void defconfig(pinconfig_t *cfg){
|
static void defconfig(pinconfig_t *cfg){
|
||||||
if(!cfg) return;
|
if(!cfg) return;
|
||||||
@@ -196,7 +239,9 @@ int chkpinconf(){
|
|||||||
}
|
}
|
||||||
int active_usart = -1; // number of USART if user selects it (we can't check it by UC->idx)
|
int active_usart = -1; // number of USART if user selects it (we can't check it by UC->idx)
|
||||||
int active_i2c = -1;
|
int active_i2c = -1;
|
||||||
uint8_t i2c_scl_pin = 0xFF, i2c_sda_pin = 0xFF; // to check SCL/SDA collisions and (SCL&SDA)
|
int active_spi = -1;
|
||||||
|
i2c_props_t i2cprops = {0};
|
||||||
|
spi_props_t spiprops = {0};
|
||||||
for(int port = 0; port < 2; ++port){
|
for(int port = 0; port < 2; ++port){
|
||||||
for(int pin = 0; pin < 16; ++pin){
|
for(int pin = 0; pin < 16; ++pin){
|
||||||
pinconfig_t *cfg = &pinconfig[port][pin];
|
pinconfig_t *cfg = &pinconfig[port][pin];
|
||||||
@@ -267,20 +312,60 @@ int chkpinconf(){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ip.isscl){
|
if(ip.isscl){
|
||||||
if(i2c_scl_pin != 0xFF){ // two SCLs
|
if(i2cprops.isscl){ // two SCLs
|
||||||
defconfig(cfg);
|
defconfig(cfg);
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i2c_scl_pin = (port << 4) | pin;
|
i2cprops.isscl = 1;
|
||||||
}
|
}
|
||||||
if(ip.issda){
|
if(ip.issda){
|
||||||
if(i2c_sda_pin != 0xFF){ // two SDAs
|
if(i2cprops.issda){ // two SDAs
|
||||||
defconfig(cfg);
|
defconfig(cfg);
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i2c_sda_pin = (port << 4) | pin;
|
i2cprops.issda = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FUNC_SPI:{
|
||||||
|
spi_props_t sp;
|
||||||
|
int spi_idx = get_spi_index(port, pin, &sp);
|
||||||
|
if(spi_idx < 0){
|
||||||
|
defconfig(cfg);
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(active_spi == -1) active_spi = spi_idx;
|
||||||
|
else if(active_spi != spi_idx){
|
||||||
|
defconfig(cfg);
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(sp.issck){
|
||||||
|
if(spiprops.issck){
|
||||||
|
defconfig(cfg);
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spiprops.issck = 1;
|
||||||
|
}
|
||||||
|
if(sp.ismiso){
|
||||||
|
if(spiprops.ismiso){
|
||||||
|
defconfig(cfg);
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spiprops.ismiso = 1;
|
||||||
|
}
|
||||||
|
if(sp.ismosi){
|
||||||
|
if(spiprops.ismosi){
|
||||||
|
defconfig(cfg);
|
||||||
|
ret = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spiprops.ismosi = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -302,12 +387,23 @@ int chkpinconf(){
|
|||||||
}
|
}
|
||||||
// check active I2C
|
// check active I2C
|
||||||
if(active_i2c != -1){
|
if(active_i2c != -1){
|
||||||
if(i2c_scl_pin == 0xFF || i2c_sda_pin == 0xFF){
|
if(i2cprops.isscl && i2cprops.issda){
|
||||||
|
haveI2C = 1;
|
||||||
|
}else{
|
||||||
DBG("Need two pins for I2C\n");
|
DBG("Need two pins for I2C\n");
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
haveI2C = 0;
|
haveI2C = 0;
|
||||||
}else haveI2C = 1;
|
}
|
||||||
}else i2c_stop();
|
}
|
||||||
|
if(active_spi != -1){
|
||||||
|
if(spiprops.issck && (spiprops.ismiso || spiprops.ismosi)){
|
||||||
|
haveSPI = 1;
|
||||||
|
}else{
|
||||||
|
DBG("SPI needs SCK and MOSI or MISO\n");
|
||||||
|
ret = FALSE;
|
||||||
|
haveSPI = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,6 +551,8 @@ int gpio_reinit(){
|
|||||||
}else usart_stop();
|
}else usart_stop();
|
||||||
if(haveI2C) i2c_setup((i2c_speed_t) the_conf.I2Cspeed);
|
if(haveI2C) i2c_setup((i2c_speed_t) the_conf.I2Cspeed);
|
||||||
else i2c_stop();
|
else i2c_stop();
|
||||||
|
if(haveSPI) spi_setup(the_conf.SPIspeed);
|
||||||
|
else spi_stop();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,11 +97,17 @@ typedef struct{
|
|||||||
uint8_t istx : 1;
|
uint8_t istx : 1;
|
||||||
} usart_props_t;
|
} usart_props_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct{
|
||||||
uint8_t isscl : 1;
|
uint8_t isscl : 1;
|
||||||
uint8_t issda : 1;
|
uint8_t issda : 1;
|
||||||
} i2c_props_t;
|
} i2c_props_t;
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
uint8_t issck : 1;
|
||||||
|
uint8_t ismiso : 1;
|
||||||
|
uint8_t ismosi : 1;
|
||||||
|
} spi_props_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
typedef struct{
|
typedef struct{
|
||||||
uint32_t speed;
|
uint32_t speed;
|
||||||
@@ -121,6 +127,7 @@ int get_curpinconf(uint8_t port, uint8_t pin, pinconfig_t *c);
|
|||||||
|
|
||||||
int get_usart_index(uint8_t port, uint8_t pin, usart_props_t *p);
|
int get_usart_index(uint8_t port, uint8_t pin, usart_props_t *p);
|
||||||
int get_i2c_index(uint8_t port, uint8_t pin, i2c_props_t *p);
|
int get_i2c_index(uint8_t port, uint8_t pin, i2c_props_t *p);
|
||||||
|
int get_spi_index(uint8_t port, uint8_t pin, spi_props_t *p);
|
||||||
|
|
||||||
int gpio_reinit();
|
int gpio_reinit();
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ extern "C"{
|
|||||||
#include "gpioproto.h"
|
#include "gpioproto.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "pwm.h"
|
#include "pwm.h"
|
||||||
|
#include "spi.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
#undef USBIF
|
#undef USBIF
|
||||||
#define USBIF IGPIO
|
#define USBIF IGPIO
|
||||||
@@ -68,6 +69,7 @@ static uint8_t hex_input_mode = 0; // ==0 for text input, 1 for HEX + text in qu
|
|||||||
COMMAND(saveconf, "save current user configuration into flash") \
|
COMMAND(saveconf, "save current user configuration into flash") \
|
||||||
COMMAND(sendcan, "send all after '=' to CAN USB interface") \
|
COMMAND(sendcan, "send all after '=' to CAN USB interface") \
|
||||||
COMMAND(setiface, "set/get name of interface x (0 - CAN, 1 - GPIO)") \
|
COMMAND(setiface, "set/get name of interface x (0 - CAN, 1 - GPIO)") \
|
||||||
|
COMMAND(SPI, "transfer SPI data: SPI=data (hex)") \
|
||||||
COMMAND(storeconf, "save config to flash") \
|
COMMAND(storeconf, "save config to flash") \
|
||||||
COMMAND(time, "show current time (ms)") \
|
COMMAND(time, "show current time (ms)") \
|
||||||
COMMAND(USART, "Read USART data or send (USART=hex)") \
|
COMMAND(USART, "Read USART data or send (USART=hex)") \
|
||||||
@@ -334,6 +336,7 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
|
|||||||
bool monitor = false;
|
bool monitor = false;
|
||||||
uint16_t *pending_u16 = NULL; // pointer to uint16_t 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
|
||||||
uint32_t *pending_u32 = NULL; // -//- for uint32_t
|
uint32_t *pending_u32 = NULL; // -//- for uint32_t
|
||||||
|
uint32_t wU32 = UINT32_MAX; // for pending
|
||||||
usartconf_t UsartConf;
|
usartconf_t UsartConf;
|
||||||
if(!get_curusartconf(&UsartConf)) return ERR_CANTRUN;
|
if(!get_curusartconf(&UsartConf)) return ERR_CANTRUN;
|
||||||
char *saveptr, *token = strtok_r(setter, DELIM_, &saveptr);
|
char *saveptr, *token = strtok_r(setter, DELIM_, &saveptr);
|
||||||
@@ -390,7 +393,7 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
|
|||||||
pending_u16 = &curconf.threshold;
|
pending_u16 = &curconf.threshold;
|
||||||
break;
|
break;
|
||||||
case MISC_SPEED:
|
case MISC_SPEED:
|
||||||
pending_u32 = &UsartConf.speed; // also used for I2C speed!
|
pending_u32 = &wU32;
|
||||||
break;
|
break;
|
||||||
case MISC_TEXT: // what to do, if textproto is set, but user wants binary?
|
case MISC_TEXT: // what to do, if textproto is set, but user wants binary?
|
||||||
UsartConf.textproto = 1;
|
UsartConf.textproto = 1;
|
||||||
@@ -411,10 +414,16 @@ static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){
|
|||||||
|
|
||||||
// check periferial settings before refresh pin data
|
// check periferial settings before refresh pin data
|
||||||
// check current USART settings
|
// check current USART settings
|
||||||
if(func_set == FUNC_USART && !chkusartconf(&UsartConf)) return ERR_BADVAL;
|
if(func_set == FUNC_USART){
|
||||||
if(func_set == FUNC_I2C){ // check speed
|
if(wU32 != UINT32_MAX) UsartConf.speed = wU32;
|
||||||
i2c_speed_t s = (UsartConf.speed > I2C_SPEED_1M) ? I2C_SPEED_10K : static_cast <i2c_speed_t> (UsartConf.speed);
|
if(!chkusartconf(&UsartConf)) return ERR_BADVAL;
|
||||||
the_conf.I2Cspeed = static_cast <uint8_t> (s);
|
}else if(func_set == FUNC_I2C){ // check speed
|
||||||
|
if(wU32 != UINT32_MAX){
|
||||||
|
i2c_speed_t s = (wU32 > I2C_SPEED_1M) ? I2C_SPEED_10K : static_cast <i2c_speed_t> (wU32);
|
||||||
|
the_conf.I2Cspeed = static_cast <uint8_t> (s);
|
||||||
|
}
|
||||||
|
}else if(func_set == FUNC_SPI){
|
||||||
|
if(wU32 != UINT32_MAX) the_conf.SPIspeed = wU32;
|
||||||
}
|
}
|
||||||
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
|
||||||
@@ -603,6 +612,10 @@ static errcodes_t cmd_dumpconf(const char _U_ *cmd, char _U_ *args){
|
|||||||
}
|
}
|
||||||
NL();
|
NL();
|
||||||
}
|
}
|
||||||
|
if(SPI1->CR1 & SPI_CR1_SPE){
|
||||||
|
SEND("spispeed=");
|
||||||
|
SENDn(u2str(the_conf.SPIspeed));
|
||||||
|
}
|
||||||
#undef S
|
#undef S
|
||||||
#undef SP
|
#undef SP
|
||||||
return ERR_AMOUNT;
|
return ERR_AMOUNT;
|
||||||
@@ -866,6 +879,7 @@ static errcodes_t cmd_pinout(const char _U_ *cmd, char *args){
|
|||||||
pwmtimer_t tp; // timers' pins
|
pwmtimer_t tp; // timers' pins
|
||||||
usart_props_t up; // USARTs' pins
|
usart_props_t up; // USARTs' pins
|
||||||
i2c_props_t ip; // I2C's pins
|
i2c_props_t ip; // I2C's pins
|
||||||
|
spi_props_t sp;
|
||||||
|
|
||||||
SEND("\nConfigurable pins (check collisions if functions have same name!):\n");
|
SEND("\nConfigurable pins (check collisions if functions have same name!):\n");
|
||||||
for(int port = 0; port < 2; ++port){
|
for(int port = 0; port < 2; ++port){
|
||||||
@@ -880,14 +894,17 @@ static errcodes_t cmd_pinout(const char _U_ *cmd, char *args){
|
|||||||
if(listmask == 0xff) SEND("GPIO"); // don't send "GPIO" for specific choice
|
if(listmask == 0xff) SEND("GPIO"); // don't send "GPIO" for specific choice
|
||||||
if(mask & (1 << FUNC_AIN)){ SEND(COMMA); SEND(str_keywords[STR_AIN]); }
|
if(mask & (1 << FUNC_AIN)){ SEND(COMMA); SEND(str_keywords[STR_AIN]); }
|
||||||
if(mask & (1 << FUNC_USART)){ // USARTn_aX (n - 1/2, a - R/T)
|
if(mask & (1 << FUNC_USART)){ // USARTn_aX (n - 1/2, a - R/T)
|
||||||
SEND(", ");
|
|
||||||
int idx = get_usart_index(port, pin, &up);
|
int idx = get_usart_index(port, pin, &up);
|
||||||
SEND(str_keywords[STR_USART]); PUTCHAR('1' + idx);
|
SEND(COMMA); SEND(str_keywords[STR_USART]); PUTCHAR('1' + idx);
|
||||||
PUTCHAR('_'); PUTCHAR(up.isrx ? 'R' : 'T'); PUTCHAR('X');
|
PUTCHAR('_'); PUTCHAR(up.isrx ? 'R' : 'T'); PUTCHAR('X');
|
||||||
}
|
}
|
||||||
if(mask & (1 << FUNC_SPI)){
|
if(mask & (1 << FUNC_SPI)){
|
||||||
SEND(COMMA); SEND(str_keywords[STR_SPI]);
|
int idx = get_spi_index(port, pin, &sp);
|
||||||
// TODO: MISO/MOSI/SCL
|
SEND(COMMA); SEND(str_keywords[STR_SPI]); PUTCHAR('1' + idx);
|
||||||
|
PUTCHAR('_');
|
||||||
|
if(sp.ismiso) SEND("MISO");
|
||||||
|
else if(sp.ismosi) SEND("MOSI");
|
||||||
|
else SEND("SCK");
|
||||||
}
|
}
|
||||||
if(mask & (1 << FUNC_I2C)){
|
if(mask & (1 << FUNC_I2C)){
|
||||||
int idx = get_i2c_index(port, pin, &ip);
|
int idx = get_i2c_index(port, pin, &ip);
|
||||||
@@ -908,6 +925,21 @@ static errcodes_t cmd_pinout(const char _U_ *cmd, char *args){
|
|||||||
return ERR_AMOUNT;
|
return ERR_AMOUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_SPI(const char *cmd, char *args){
|
||||||
|
if(!args) return ERR_BADVAL;
|
||||||
|
if(!(SPI1->CR1 & SPI_CR1_SPE)) return ERR_CANTRUN;
|
||||||
|
char *setter = splitargs(args, NULL);
|
||||||
|
if(!setter) return ERR_BADVAL;
|
||||||
|
int len = parse_hex_data(setter, curbuf, MAXSTRLEN);
|
||||||
|
if(len <= 0) return ERR_BADVAL;
|
||||||
|
int got = spi_transfer(curbuf, curbuf, len);
|
||||||
|
if(-1 == got) return ERR_CANTRUN;
|
||||||
|
if(0 == got) return ERR_BUSY;
|
||||||
|
CMDEQ();
|
||||||
|
hexdump(sendfun, curbuf, got);
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr uint32_t hash(const char* str, uint32_t h = 0){
|
constexpr uint32_t hash(const char* str, uint32_t h = 0){
|
||||||
return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h;
|
return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "gpioproto.h"
|
#include "gpioproto.h"
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
|
||||||
|
const uint32_t peripherial_clock = 48000000;
|
||||||
uint8_t ledsON = 0;
|
uint8_t ledsON = 0;
|
||||||
|
|
||||||
TRUE_INLINE void pins_setup(){ // setup some common GPIO
|
TRUE_INLINE void pins_setup(){ // setup some common GPIO
|
||||||
@@ -35,8 +36,10 @@ TRUE_INLINE void pins_setup(){ // setup some common GPIO
|
|||||||
void hardware_setup(){
|
void hardware_setup(){
|
||||||
// enable all active GPIO clocking
|
// enable all active GPIO clocking
|
||||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMA1EN;
|
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMA1EN;
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN;
|
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN |
|
||||||
RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM14EN | RCC_APB1ENR_I2C1EN;
|
RCC_APB2ENR_SPI1EN;
|
||||||
|
RCC->APB1ENR |= RCC_APB1ENR_USART2EN | RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM14EN |
|
||||||
|
RCC_APB1ENR_I2C1EN;
|
||||||
pins_setup();
|
pins_setup();
|
||||||
adc_setup();
|
adc_setup();
|
||||||
GPIO_init();
|
GPIO_init();
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
|
|
||||||
extern volatile uint32_t Tms;
|
extern volatile uint32_t Tms;
|
||||||
|
extern const uint32_t peripherial_clock;
|
||||||
extern uint8_t ledsON;
|
extern uint8_t ledsON;
|
||||||
|
|
||||||
void hardware_setup();
|
void hardware_setup();
|
||||||
|
|||||||
76
F0:F030,F042,F072/usbcan_gpio/spi.c
Normal file
76
F0:F030,F042,F072/usbcan_gpio/spi.c
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the usbcangpio project.
|
||||||
|
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stm32f0.h>
|
||||||
|
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
// get best prescaler to fit given frequency
|
||||||
|
static uint16_t get_baudrate_prescaler(uint32_t speed_hz){
|
||||||
|
uint32_t freq = peripherial_clock;
|
||||||
|
uint32_t best_i = 7;
|
||||||
|
uint32_t best_err = 0xFFFFFFFF;
|
||||||
|
for(int i = 0; i < 8; i++){
|
||||||
|
freq >>= 1;
|
||||||
|
uint32_t err = (freq > speed_hz) ? (freq - speed_hz) : (speed_hz - freq);
|
||||||
|
if(err < best_err){
|
||||||
|
best_err = err;
|
||||||
|
best_i = i;
|
||||||
|
}else if(err > best_err) break;
|
||||||
|
}
|
||||||
|
return best_i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Master, 8bit, CPOL=0, CPHA=0, MSB first
|
||||||
|
void spi_setup(uint32_t speed){ // speed in Hz
|
||||||
|
RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;
|
||||||
|
RCC->APB2RSTR = 0;
|
||||||
|
SPI1->CR1 = 0;
|
||||||
|
uint16_t br = get_baudrate_prescaler(speed);
|
||||||
|
SPI1->CR1 = SPI_CR1_MSTR | (br << 3) | SPI_CR1_SSM | SPI_CR1_SSI;
|
||||||
|
SPI1->CR2 = SPI_CR2_SSOE;
|
||||||
|
SPI1->CR1 |= SPI_CR1_SPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spi_stop(){
|
||||||
|
SPI1->CR1 &= ~SPI_CR1_SPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return -1 if SPI isn't run or got error
|
||||||
|
int spi_transfer(const uint8_t *tx, uint8_t *rx, int len){
|
||||||
|
if(len < 1 || !(SPI1->CR1 & SPI_CR1_SPE)) return -1;
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < len; ++i){
|
||||||
|
uint32_t timeout = 1000000;
|
||||||
|
while(!(SPI1->SR & SPI_SR_TXE)){
|
||||||
|
if (--timeout == 0) return -1; // error by timeout: TX isn't ready
|
||||||
|
}
|
||||||
|
uint8_t out = (tx) ? tx[i] : 0;
|
||||||
|
*(uint8_t*)&SPI1->DR = out; // ÚÁÐÉÓØ × DR
|
||||||
|
timeout = 1000000;
|
||||||
|
while(!(SPI1->SR & SPI_SR_RXNE)){
|
||||||
|
if(--timeout == 0) return 0;
|
||||||
|
}
|
||||||
|
uint8_t in = *(uint8_t*)&SPI1->DR; // ÞÔÅÎÉÅ ÉÚ DR
|
||||||
|
if(rx) rx[i] = in;
|
||||||
|
}
|
||||||
|
//while(SPI1->SR & SPI_SR_BSY){ }
|
||||||
|
return i;
|
||||||
|
}
|
||||||
25
F0:F030,F042,F072/usbcan_gpio/spi.h
Normal file
25
F0:F030,F042,F072/usbcan_gpio/spi.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the usbcangpio project.
|
||||||
|
* Copyright 2026 Edward V. Emelianov <edward.emelianoff@gmail.com>.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void spi_setup(uint32_t speed); // speed in Hz
|
||||||
|
void spi_stop();
|
||||||
|
int spi_transfer(const uint8_t *tx, uint8_t *rx, int len);
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
|
#include "hardware.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
|
|
||||||
@@ -101,13 +102,12 @@ int usart_config(usartconf_t *uc){
|
|||||||
if(curUSARTidx != -1) usart_stop(); // disable previous USART if enabled
|
if(curUSARTidx != -1) usart_stop(); // disable previous USART if enabled
|
||||||
uint8_t No = usartconfig.idx;
|
uint8_t No = usartconfig.idx;
|
||||||
volatile USART_TypeDef *U = Usarts[No];
|
volatile USART_TypeDef *U = Usarts[No];
|
||||||
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 / (usartconfig.speed);
|
U->BRR = peripherial_clock / (usartconfig.speed);
|
||||||
usartconfig.speed= peripheral_clock / U->BRR; // fix for real speed
|
usartconfig.speed = peripherial_clock / U->BRR; // fix for real speed
|
||||||
uint32_t cr1 = 0, cr3 = 0;
|
uint32_t cr1 = 0, cr3 = 0;
|
||||||
textformat = usartconfig.textproto;
|
textformat = usartconfig.textproto;
|
||||||
monitor = usartconfig.monitor;
|
monitor = usartconfig.monitor;
|
||||||
|
|||||||
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-17T00:10:23. -->
|
<!-- Written by QtCreator 18.0.2, 2026-03-17T23:56:25. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ pwm.c
|
|||||||
pwm.h
|
pwm.h
|
||||||
ringbuffer.c
|
ringbuffer.c
|
||||||
ringbuffer.h
|
ringbuffer.h
|
||||||
|
spi.c
|
||||||
|
spi.h
|
||||||
strfunc.c
|
strfunc.c
|
||||||
strfunc.h
|
strfunc.h
|
||||||
usart.c
|
usart.c
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "217"
|
#define BUILD_NUMBER "221"
|
||||||
#define BUILD_DATE "2026-03-17"
|
#define BUILD_DATE "2026-03-17"
|
||||||
|
|||||||
Reference in New Issue
Block a user