diff --git a/F3:F303/CANbus4BTA/BTA_CAN.bin b/F3:F303/CANbus4BTA/BTA_CAN.bin index 5397736..53faf23 100755 Binary files a/F3:F303/CANbus4BTA/BTA_CAN.bin and b/F3:F303/CANbus4BTA/BTA_CAN.bin differ diff --git a/F3:F303/CANbus4BTA/canbus4bta.creator.user b/F3:F303/CANbus4BTA/canbus4bta.creator.user index b114d45..d8ad98b 100644 --- a/F3:F303/CANbus4BTA/canbus4bta.creator.user +++ b/F3:F303/CANbus4BTA/canbus4bta.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F3:F303/CANbus4BTA/canbus4bta.files b/F3:F303/CANbus4BTA/canbus4bta.files index 4478816..73679a0 100644 --- a/F3:F303/CANbus4BTA/canbus4bta.files +++ b/F3:F303/CANbus4BTA/canbus4bta.files @@ -4,6 +4,8 @@ can.c can.h commonfunctions.c commonfunctions.h +encoder.c +encoder.h flash.c flash.h gpio.c @@ -14,6 +16,8 @@ main.c proto.h ringbuffer.c ringbuffer.h +spi.c +spi.h strfunc.c strfunc.h textfunctions.c diff --git a/F3:F303/CANbus4BTA/commonfunctions.c b/F3:F303/CANbus4BTA/commonfunctions.c index f4a828c..ca19889 100644 --- a/F3:F303/CANbus4BTA/commonfunctions.c +++ b/F3:F303/CANbus4BTA/commonfunctions.c @@ -19,9 +19,11 @@ #include "adc.h" #include "can.h" #include "commonfunctions.h" +#include "encoder.h" #include "flash.h" #include "gpio.h" #include "proto.h" +#include "spi.h" #include "usb.h" #define FIXDL(m) do{m->length = 8;}while(0) @@ -64,16 +66,6 @@ static errcodes adcv(CAN_message *msg){ *(uint32_t*)&msg->data[4] = (uint32_t) v; // or float?? return ERR_OK; } -// get/set CAN speed -static errcodes canspeed(CAN_message *msg){ - if(ISSETTER(msg->data)){ - uint32_t spd = *(uint32_t*)&msg->data[4]; - CAN_reinit(spd); - the_conf.CANspeed = CAN_speed(); - }else FIXDL(msg); - *(uint32_t*)&msg->data[4] = CAN_speed(); - return ERR_OK; -} // get/set CAN ID static errcodes canid(CAN_message *msg){ if(ISSETTER(msg->data)){ @@ -128,12 +120,56 @@ static errcodes esw(CAN_message *msg){ *(uint32_t*)&msg->data[4] = getESW(no); return ERR_OK; } -// bounce constant, ms -static errcodes bounce(CAN_message *msg){ +// init SPI2 +static errcodes initspi2(CAN_message _U_ *msg){ + spi_setup(2); + return ERR_OK; +} +// send/read 1..4 bytes +static errcodes sendspi2(CAN_message *msg){ + int n = msg->length - 4; + if(n < 1) return ERR_BADVAL; + if(spi_writeread(2, msg->data + 4, n)) return ERR_OK; + return ERR_CANTRUN; +} +// read encoder value and send over CAN +static errcodes encget(CAN_message *msg){ + FIXDL(msg); + if(read_encoder(msg->data + 4)) return ERR_OK; + return ERR_CANTRUN; +} + +// common uint32_t setter/getter +static errcodes u32setget(CAN_message *msg){ + uint16_t idx = *(uint16_t*)msg->data; + uint32_t *ptr = NULL; + switch(idx){ + case CMD_CANSPEED: ptr = &the_conf.CANspeed; break; + case CMD_BOUNCE: ptr = &the_conf.bounce_ms; break; + case CMD_USARTSPEED: ptr = &the_conf.usartspeed; break; + default: break; + } + if(!ptr) return ERR_CANTRUN; // unknown error if(ISSETTER(msg->data)){ - the_conf.bounce_ms = *(uint32_t*)&msg->data[4]; + *ptr = *(uint32_t*)&msg->data[4]; }else FIXDL(msg); - *(uint32_t*)&msg->data[4] = the_conf.bounce_ms; + *(uint32_t*)&msg->data[4] = *ptr; + return ERR_OK; +} +// common bitflag setter/getter +static errcodes flagsetget(CAN_message *msg){ + uint16_t idx = *(uint16_t*)msg->data; + uint8_t bit = 32; + switch(idx){ + case CMD_ENCISSSI: bit = FLAGBIT(ENC_IS_SSI); break; + default: break; + } + if(bit > 31) return ERR_CANTRUN; // unknown error + if(ISSETTER(msg->data)){ + if(msg->data[4]) the_conf.flags |= 1<data[4] = (the_conf.flags & (1<= CMD_AMOUNT || funclist[idx].fn == NULL){ // bad command index FORMERR(msg, ERR_BADCMD); return; } - // check minimal length (2 or 3) + // check minimal length if(funclist[idx].datalen > datalen){ FORMERR(msg, ERR_WRONGLEN); return; } diff --git a/F3:F303/CANbus4BTA/encoder.c b/F3:F303/CANbus4BTA/encoder.c new file mode 100644 index 0000000..3969cc7 --- /dev/null +++ b/F3:F303/CANbus4BTA/encoder.c @@ -0,0 +1,36 @@ +/* + * This file is part of the canbus4bta project. + * Copyright 2024 Edward V. Emelianov . + * + * 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 . + */ + +#include "encoder.h" +#include "flash.h" +#include "spi.h" +#include "usart.h" + + +void encoder_setup(){ + if(FLAG(ENC_IS_SSI)) spi_setup(ENCODER_SPI); + else usart_setup(); +} + +// read encoder value into buffer `outbuf` +// return TRUE if all OK +int read_encoder(uint8_t outbuf[4]){ + if(!FLAG(ENC_IS_SSI)) return FALSE; + *((uint32_t*)outbuf) = 0; + return spi_writeread(ENCODER_SPI, outbuf, 4); +} diff --git a/F3:F303/CANbus4BTA/encoder.h b/F3:F303/CANbus4BTA/encoder.h new file mode 100644 index 0000000..e935349 --- /dev/null +++ b/F3:F303/CANbus4BTA/encoder.h @@ -0,0 +1,24 @@ +/* + * This file is part of the canbus4bta project. + * Copyright 2024 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once + +#include + +void encoder_setup(); +int read_encoder(uint8_t outbuf[4]); diff --git a/F3:F303/CANbus4BTA/flash.c b/F3:F303/CANbus4BTA/flash.c index aa869be..0fbe9ed 100644 --- a/F3:F303/CANbus4BTA/flash.c +++ b/F3:F303/CANbus4BTA/flash.c @@ -31,23 +31,23 @@ const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE; static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here -#define USERCONF_INITIALIZER { \ - .userconf_sz = sizeof(user_conf) \ - ,.CANspeed = 100000 \ - ,.CANID = 0xaa \ - ,.bounce_ms = 50 \ - ,.adcmul[0] = 10.930f \ - ,.adcmul[1] = 2.028f \ - ,.adcmul[2] = 1.f \ - ,.adcmul[3] = 1.f \ - } - static int write2flash(const void*, const void*, uint32_t); // don't write `static` here, or get error: // 'memcpy' forming offset 8 is out of the bounds [0, 4] of object '__varsstart' with type 'uint32_t' const user_conf *Flash_Data = (const user_conf *)(&__varsstart); -user_conf the_conf = USERCONF_INITIALIZER; +user_conf the_conf = { + .userconf_sz = sizeof(user_conf), + .CANspeed = 100000, + .CANID = 0xaa, + .bounce_ms = 50, + .adcmul[0] = 10.930f, + .adcmul[1] = 2.028f, + .adcmul[2] = 1.f, + .adcmul[3] = 1.f, + .usartspeed = 115200, + .flags = FLAGP(ENC_IS_SSI), +}; int currentconfidx = -1; // index of current configuration @@ -179,9 +179,6 @@ int erase_storage(int npage){ FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; } - /*USB_sendstr("size/block size/nblocks/FLASH_SIZE: "); printu(flsz); - USB_putbyte('/'); printu(FLASH_blocksize); USB_putbyte('/'); - printu(nblocks); USB_putbyte('/'); printu(FLASH_SIZE); newline(); USB_sendall();*/ while(FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; FLASH->CR |= FLASH_CR_PER; diff --git a/F3:F303/CANbus4BTA/flash.h b/F3:F303/CANbus4BTA/flash.h index 4f5730f..fe0e8a4 100644 --- a/F3:F303/CANbus4BTA/flash.h +++ b/F3:F303/CANbus4BTA/flash.h @@ -28,6 +28,21 @@ #define FLASH_SIZE *((uint16_t*)FLASH_SIZE_BASE) +// bit flags positions +// encoder have SSI (1) or RS-422 (0) +#define ENC_IS_SSI_BIT 0 + +// bit number +#define FLAGBIT(f) (f ## _BIT) +// flag position +#define FLAGP(f) (1 << FLAGBIT(f)) +// flag value +#define FLAG(f) ((the_conf.flags & FLAGP(f)) ? 1 : 0) +// set flag +#define FLAGS(f) do{the_conf.flags |= FLAGP(f);}while(0) +// reset flag +#define FLAGR(f) do{the_conf.flags &= ~FLAGP(f);}while(0) + /* * struct to save user configurations */ @@ -35,8 +50,10 @@ typedef struct __attribute__((packed, aligned(4))){ uint16_t userconf_sz; // "magick number" uint16_t CANID; // identifier uint32_t CANspeed; // default CAN speed - uint32_t bounce_ms; // a + uint32_t bounce_ms; // debounce wait float adcmul[ADC_TSENS]; // ADC voltage multipliers + uint32_t usartspeed; // USART1 speed (baud/s) + uint32_t flags; // bit flags } user_conf; extern user_conf the_conf; // global user config (read from FLASH to RAM) diff --git a/F3:F303/CANbus4BTA/hardware.c b/F3:F303/CANbus4BTA/hardware.c index 2836d52..5989c59 100644 --- a/F3:F303/CANbus4BTA/hardware.c +++ b/F3:F303/CANbus4BTA/hardware.c @@ -49,25 +49,24 @@ TRUE_INLINE void iwdg_setup(){ static inline void gpio_setup(){ RELAY_OFF(); MUL_OFF(0); MUL_OFF(1); RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN; - // PWM - AF1 @PA7; USB - alternate function 14 @ pins PA11/PA12; USART1 = AF7 @PA9/10; SWD - AF0 @PA13/14 + // PWM - AF1 @PA7; USB - alternate function 14 @ pins PA11/PA12; SWD - AF0 @PA13/14 GPIOA->AFR[0] = AFRf(1, 7); - GPIOA->AFR[1] = AFRf(7, 9) | AFRf(7, 10) | AFRf(14, 11) | AFRf(14, 12); - // PA4 - din (PU in), USART1: PA10(Rx, pullup), PA9(Tx); USB - PA11, PA12; SWDIO - PA13, PA14; PA8 & PA15 - PU in + GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12); + // PA4 - din (PU in); USB - PA11, PA12; SWDIO - PA13, PA14; PA8 & PA15 - PU in GPIOA->PUPDR = (GPIOA->PUPDR & PUPD_CLR(4) & PUPD_CLR(8) & PUPD_CLR(10) & PUPD_CLR(15)) | PUPD_PU(4) | PUPD_PU(8) | PUPD_PU(10) | PUPD_PU(15); GPIOA->MODER = MODER_AI(0) | MODER_AI(1) | MODER_AI(2) | MODER_AI(3) | MODER_I(4) | MODER_O(5) | - MODER_O(6) | MODER_AF(7) | MODER_I(8) | MODER_AF(9) | MODER_AF(10) | MODER_AF(11) | + MODER_O(6) | MODER_AF(7) | MODER_I(8) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_I(15); GPIOA->OSPEEDR = OSPEED_HI(4) | OSPEED_MED(7) | OSPEED_MED(9) | OSPEED_MED(10) | OSPEED_HI(11) | OSPEED_HI(12) | OSPEED_HI(13) | OSPEED_HI(14); - // SPI for SSI: AF5 @PB3, PB4; I2C1: AF4 @PB6, PB7; CAN: AF9 @PB8, PB9; SPI2: AF5 @PB12..PB15 + // I2C1: AF4 @PB6, PB7; CAN: AF9 @PB8, PB9; SPI2: AF5 @PB12..PB15 GPIOB->AFR[0] = AFRf(5, 3) | AFRf(5, 4) | AFRf(4, 6) | AFRf(4, 7); - GPIOB->AFR[1] = AFRf(9, 8) | AFRf(9, 9) | AFRf(5, 12) | AFRf(5, 13) | AFRf(5, 14) | AFRf(5, 15); + GPIOB->AFR[1] = AFRf(9, 8) | AFRf(9, 9); // PB10,11 - PU in GPIOB->PUPDR = PUPD_PU(10) | PUPD_PU(11); - GPIOB->MODER = MODER_O(0) | MODER_O(1) | MODER_O(2) | MODER_AF(3) | MODER_AF(4) | MODER_AF(6) | MODER_AF(7) | - MODER_AF(8) | MODER_AF(9) | MODER_I(10) | MODER_I(11) | MODER_AF(12) | MODER_AF(13) | - MODER_AF(14) | MODER_AF(15); + GPIOB->MODER = MODER_O(0) | MODER_O(1) | MODER_O(2) | MODER_AF(6) | MODER_AF(7) | + MODER_AF(8) | MODER_AF(9) | MODER_I(10) | MODER_I(11); GPIOB->OSPEEDR = OSPEED_HI(3) | OSPEED_HI(4) | OSPEED_HI(6) | OSPEED_HI(7) | OSPEED_HI(8) | OSPEED_HI(9) | OSPEED_HI(12) | OSPEED_HI(13) | OSPEED_HI(14) | OSPEED_HI(15); GPIOC->MODER = MODER_O(13) | MODER_O(14) | MODER_O(15); @@ -76,7 +75,6 @@ static inline void gpio_setup(){ void hw_setup(){ gpio_setup(); adc_setup(); - //usart_setup(); - power it on only for encoders on RS-422 USB_setup(); #ifndef EBUG iwdg_setup(); diff --git a/F3:F303/CANbus4BTA/hardware.h b/F3:F303/CANbus4BTA/hardware.h index c1138cf..9da78f9 100644 --- a/F3:F303/CANbus4BTA/hardware.h +++ b/F3:F303/CANbus4BTA/hardware.h @@ -41,4 +41,7 @@ extern volatile uint32_t Tms; +// SPI1 is encoder, SPI2 is ext +#define ENCODER_SPI (1) + void hw_setup(); diff --git a/F3:F303/CANbus4BTA/main.c b/F3:F303/CANbus4BTA/main.c index 91aaeb8..56dd9bf 100644 --- a/F3:F303/CANbus4BTA/main.c +++ b/F3:F303/CANbus4BTA/main.c @@ -17,6 +17,7 @@ */ #include "can.h" +#include "encoder.h" #include "flash.h" #include "gpio.h" #include "hardware.h" @@ -60,6 +61,7 @@ int main(void){ hw_setup(); // getSwitches() and set module role & CAN ID CAN_setup(the_conf.CANspeed); + encoder_setup(); USBPU_ON(); while(1){ IWDG->KR = IWDG_REFRESH; diff --git a/F3:F303/CANbus4BTA/proto.h b/F3:F303/CANbus4BTA/proto.h index 677c4f9..186e3f7 100644 --- a/F3:F303/CANbus4BTA/proto.h +++ b/F3:F303/CANbus4BTA/proto.h @@ -64,6 +64,11 @@ typedef enum{ CMD_GETESW_BLK, // 11 - blocking read of ESW CMD_GETESW, // 12 - current ESW state, bounce-free CMD_BOUNCE, // 13 - get/set bounce constant (ms) + CMD_USARTSPEED, // 14 - get/set USART1 speed (if encoder on RS-422) + CMD_ENCISSSI, // 15 - encoder is SSI (1) or RS-422 (0) + CMD_SPIINIT, // 16 - init SPI2 + CMD_SPISEND, // 17 - send 1..4 bytes over SPI + CMD_ENCGET, // 18 - get encoder value CMD_AMOUNT // amount of CAN commands } can_cmd; diff --git a/F3:F303/CANbus4BTA/spi.c b/F3:F303/CANbus4BTA/spi.c new file mode 100644 index 0000000..2026617 --- /dev/null +++ b/F3:F303/CANbus4BTA/spi.c @@ -0,0 +1,198 @@ +/* + * This file is part of the canbus4bta project. + * Copyright 2024 Edward V. Emelianov . + * + * 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 . + */ + +#include "hardware.h" +#include "spi.h" + +#include "usb.h" +#ifdef EBUG +#include "strfunc.h" +#endif + +//#define SPIDR *((volatile uint8_t*)&SPI2->DR) + +spiStatus spi_status[AMOUNT_OF_SPI+1] = {0, SPI_NOTREADY, SPI_NOTREADY}; +static volatile SPI_TypeDef* const SPIs[AMOUNT_OF_SPI+1] = {NULL, SPI1, SPI2}; +#define WAITX(x) do{volatile uint32_t wctr = 0; while((x) && (++wctr < 360000)) IWDG->KR = IWDG_REFRESH; if(wctr==360000){ DBG("timeout"); return 0;}}while(0) + +// SPI DMA Rx buffer (set by spi_write_dma call) for SPI2 +//static uint8_t *rxbufptr = NULL; +//static uint32_t rxbuflen = 0; + +// init SPI to work with (only SPI2) and without DMA (both) +// Channel 4 - SPI2 Rx +// Channel 5 - SPI2 Tx +void spi_setup(uint8_t idx){ + if(idx > AMOUNT_OF_SPI) return; + volatile SPI_TypeDef *SPI = SPIs[idx]; + SPI->CR1 = 0; // clear EN + SPI->CR2 = 0; + if(idx == 1){ // PB3/PB4, without MOSI; SPI for SSI: AF5 @PB3, PB4 + GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL3 | GPIO_AFRL_AFRL4)) | + AFRf(5, 3) | AFRf(5, 4); + GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER3 | GPIO_MODER_MODER4)) | + MODER_AF(3) | MODER_AF(4); + RCC->APB1RSTR = RCC_APB2RSTR_SPI1RST; + RCC->APB1RSTR = 0; // clear reset + RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; + SPI->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_RXONLY; // software slave management (without hardware NSS pin); RX only + }else if(idx == 2){ // PB12..PB15 + GPIOB->AFR[1] = (GPIOB->AFR[1] & ~(GPIO_AFRH_AFRH4 | GPIO_AFRH_AFRH5 | GPIO_AFRH_AFRH6 | GPIO_AFRH_AFRH7)) | + AFRf(5, 12) | AFRf(5, 13) | AFRf(5, 14) | AFRf(5, 15); + GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER12 | GPIO_MODER_MODER13 | GPIO_MODER_MODER14 | GPIO_MODER_MODER15)) | + MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_AF(15); + RCC->APB1RSTR = RCC_APB1RSTR_SPI2RST; // reset SPI + RCC->APB1RSTR = 0; // clear reset + RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; + RCC->AHBENR |= RCC_AHBENR_DMA1EN; + SPI->CR2 = SPI_CR2_SSOE; // hardware NSS management + // setup SPI2 DMA + //SPI->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN; + // Tx + /*DMA1_Channel5->CPAR = (uint32_t)&(SPI2->DR); // hardware + DMA1_Channel5->CCR = DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TEIE; // memory increment, mem->hw, error interrupt + // Rx + DMA1_Channel4->CPAR = (uint32_t)&(SPI2->DR); + DMA1_Channel4->CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE; // mem inc, hw->mem, Rx complete and error interrupt + NVIC_EnableIRQ(DMA1_Channel4_IRQn); // enable Rx interrupt + NVIC_EnableIRQ(DMA1_Channel5_IRQn); // enable Tx interrupt + */ + }else return; // err + // Baudrate = 0b110 - fpclk/128 + SPI->CR1 |= SPI_CR1_MSTR | SPI_CR1_BR_2 | SPI_CR1_BR_1; + // DS=8bit; RXNE generates after 8bit of data in FIFO; + SPI->CR2 |= SPI_CR2_FRXTH | SPI_CR2_DS_2|SPI_CR2_DS_1|SPI_CR2_DS_0; + spi_status[idx] = SPI_READY; + SPI->CR1 |= SPI_CR1_SPE; + DBG("SPI works"); +} + +int spi_waitbsy(uint8_t idx){ + if(idx > AMOUNT_OF_SPI) return 0; + WAITX(SPIs[idx]->SR & SPI_SR_BSY); + return 1; +} + +/** + * @brief spi_writeread - send data over SPI (change data array with received bytes) + * @param data - data to write/read + * @param n - length of data + * @return 0 if failed + */ +int spi_writeread(uint8_t idx, uint8_t *data, uint32_t n){ + if(idx > AMOUNT_OF_SPI) return 0; + if(spi_status[idx] != SPI_READY || !data || !n){ + DBG("not ready"); + return 0; + } + for(uint32_t x = 0; x < n; ++x){ + WAITX(!(SPIs[idx]->SR & SPI_SR_TXE)); + *((volatile uint8_t*)&SPIs[idx]->DR) = data[x]; + WAITX(!(SPIs[idx]->SR & SPI_SR_RXNE)); + data[x] = *((volatile uint8_t*)&SPIs[idx]->DR); + } + return 1; +} + +/** + * @brief spi_send_dma - send data over SPI2 through DMA (used both for writing and reading) + * @param data - data to read + * @param rxbuf - pointer to receiving buffer (at least n bytes), can be also `data` (if `data` isn't const) + * @param n - length of data + * @return 0 if failed + * !!! `data` buffer can be changed only after SPI_READY flag! + */ +/*int spi_write_dma(const uint8_t *data, uint8_t *rxbuf, uint32_t n){ + if(spi_status[2] != SPI_READY) return 0; + if(!spi_waitbsy(2)) return 0; + rxbufptr = rxbuf; + rxbuflen = n; + // spi_setup(); - only so we can clear Rx FIFO! + DMA1_Channel5->CMAR = (uint32_t) data; + DMA1_Channel5->CNDTR = n; + // check if user want to receive data + if(rxbuf){ + DMA1_Channel4->CCR |= DMA_CCR_TCIE; + DMA1_Channel5->CCR &= ~DMA_CCR_TCIE; // turn off Tx ready interrupt + DMA1_Channel4->CMAR = (uint32_t) rxbuf; + DMA1_Channel4->CNDTR = n; + DMA1_Channel4->CCR |= DMA_CCR_EN; // turn on reception + }else DMA1_Channel5->CCR |= DMA_CCR_TCIE; // interrupt by Tx ready - user don't want reception + spi_status[2] = SPI_BUSY; + DMA1_Channel5->CCR |= DMA_CCR_EN; // turn on transmission + return 1; +}*/ + +/** + * @brief spi_read - read SPI2 data + * @param data - data to read + * @param n - length of data + * @return n + */ +/* +int spi_read(uint8_t idx, uint8_t *data, uint32_t n){ + if(idx > AMOUNT_OF_SPI) return 0; + if(spi_status[idx] != SPI_READY){ + DBG("not ready"); + return 0; + } + if(!spi_waitbsy(idx)) return 0; + // clear SPI Rx FIFO + for(int i = 0; i < 4; ++i) (void) SPIs[idx]->DR; + for(uint32_t x = 0; x < n; ++x){ + WAITX(!(SPIs[idx]->SR & SPI_SR_TXE)); + *((volatile uint8_t*)&SPIs[idx]->DR) = 0; + WAITX(!(SPIs[idx]->SR & SPI_SR_RXNE)); + data[x] = *((volatile uint8_t*)&SPIs[idx]->DR); + //USB_sendstr("rd got "); USB_sendstr(uhex2str(data[x])); + newline(); + } + return 1; +}*/ + +/** + * @brief spi_read_dma - got buffer read by DMA + * @param n (o) - length of rxbuffer + * @return amount of bytes read + */ +/*uint8_t *spi_read_dma(uint32_t *n){ + if(spi_status[2] != SPI_READY || rxbuflen == 0) return NULL; + if(n) *n = rxbuflen - DMA1_Channel4->CNDTR; // in case of error buffer would be underfull + rxbuflen = 0; // prevent consequent readings + return rxbufptr; +}*/ + +/* +// Rx ready interrupt +void dma1_channel4_isr(){ + spi_status[2] = SPI_READY; // ready independent on errors or Rx ready + DMA1->IFCR = DMA_IFCR_CTCIF4 | DMA_IFCR_CTEIF4; + // turn off DMA + DMA1_Channel4->CCR &= ~DMA_CCR_EN; + DMA1_Channel5->CCR &= ~DMA_CCR_EN; +} + +// Tx ready interrupt +void dma1_channel5_isr(){ + spi_status[2] = SPI_READY; // ready independent on errors or Tx ready + DMA1->IFCR = DMA_IFCR_CTCIF5 | DMA_IFCR_CTEIF5; + // turn off DMA + DMA1_Channel4->CCR &= ~DMA_CCR_EN; + DMA1_Channel5->CCR &= ~DMA_CCR_EN; +} +*/ diff --git a/F3:F303/CANbus4BTA/spi.h b/F3:F303/CANbus4BTA/spi.h new file mode 100644 index 0000000..e617fa6 --- /dev/null +++ b/F3:F303/CANbus4BTA/spi.h @@ -0,0 +1,37 @@ +/* + * This file is part of the canbus4bta project. + * Copyright 2024 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once +#include + +#define AMOUNT_OF_SPI (2) + +typedef enum{ + SPI_NOTREADY, + SPI_READY, + SPI_BUSY +} spiStatus; + +extern spiStatus spi_status[AMOUNT_OF_SPI+1]; + +void spi_setup(uint8_t idx); +int spi_waitbsy(uint8_t idx); +int spi_writeread(uint8_t idx, uint8_t *data, uint32_t n); +//int spi_write_dma(const uint8_t *data, uint8_t *rxbuf, uint32_t n); +//int spi_read(uint8_t idx, uint8_t *data, uint32_t n); +//uint8_t *spi_read_dma(uint32_t *n); diff --git a/F3:F303/CANbus4BTA/textfunctions.c b/F3:F303/CANbus4BTA/textfunctions.c index d1615e4..bf6638c 100644 --- a/F3:F303/CANbus4BTA/textfunctions.c +++ b/F3:F303/CANbus4BTA/textfunctions.c @@ -66,6 +66,7 @@ static const funcdescr funclist[] = { {"reset", CMD_RESET, "reset MCU"}, {"s", -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"}, {"saveconf", CMD_SAVECONF, "save configuration"}, + {"spiinit", CMD_SPIINIT, "init SPI2"}, {"time", CMD_TIME, "get/set time (ms)"}, {"wdtest", -TCMD_WDTEST, "test watchdog"}, {NULL, 0, NULL} // last record @@ -79,6 +80,12 @@ static errcodes wdtest(const char _U_ *str){ return ERR_OK; } +// names of bit flags (ordered from LSE of[0]) +static const char * const bitfields[] = { + "encisSSI", + NULL +}; + static errcodes dumpconf(const char _U_ *str){ #ifdef EBUG uint32_t sz = FLASH_SIZE*1024; @@ -95,6 +102,15 @@ static errcodes dumpconf(const char _U_ *str){ USB_sendstr("\nadcmul"); USB_putbyte('0'+i); USB_putbyte('='); USB_sendstr(float2str(the_conf.adcmul[i], 3)); } + USB_sendstr("\nusartspeed="); printu(the_conf.usartspeed); + const char * const *p = bitfields; + int bit = 0; + while(p){ + newline(); + USB_sendstr(*p); USB_putbyte('='); USB_putbyte((the_conf.flags & (1< 31) break; + ++p; + } //#define PROPNAME(nm) do{newline(); USB_sendstr(nm); USB_putbyte(cur); USB_putbyte('=');}while(0) //#undef PROPNAME newline(); diff --git a/F3:F303/CANbus4BTA/usart.c b/F3:F303/CANbus4BTA/usart.c index e0c14b8..40b84d0 100644 --- a/F3:F303/CANbus4BTA/usart.c +++ b/F3:F303/CANbus4BTA/usart.c @@ -16,8 +16,9 @@ * along with this program. If not, see . */ -#include "stm32f3.h" +#include #include "hardware.h" +#include "flash.h" #include "usart.h" #include @@ -64,11 +65,16 @@ void usart_send(const char *str){ usart_sendn(str, L); } +// USART1: PA10(Rx, pullup), PA9(Tx); USART1 = AF7 @PA9/10; void usart_setup(){ // clock + GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10)) | + MODER_AF(9) | MODER_AF(10); + GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) | + AFRf(7, 9) | AFRf(7, 10); RCC->APB2ENR |= RCC_APB2ENR_USART1EN; USART1->ICR = 0xffffffff; // clear all flags - USART1->BRR = SysFreq / 115200; + USART1->BRR = SysFreq / the_conf.usartspeed; USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; // 1start,8data,nstop; enable Rx,Tx,USART uint32_t tmout = 16000000; while(!(USART1->ISR & USART_ISR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission diff --git a/F3:F303/CANbus4BTA/version.inc b/F3:F303/CANbus4BTA/version.inc index 7893c4b..cb5140d 100644 --- a/F3:F303/CANbus4BTA/version.inc +++ b/F3:F303/CANbus4BTA/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "68" -#define BUILD_DATE "2024-01-08" +#define BUILD_NUMBER "80" +#define BUILD_DATE "2024-03-07"