mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 10:45:11 +03:00
PEP emulation (didn't test yet)
This commit is contained in:
parent
8ea835d80f
commit
bc82142e87
Binary file not shown.
@ -122,6 +122,59 @@ Channel1 - ADC1.
|
||||
|
||||
## DMA2
|
||||
|
||||
# Other resources usage
|
||||
## Timers
|
||||
|
||||
- SysTick is 1ms system time counter (`Tms`).
|
||||
- TIM2 is 32bit timer with 2mks period (system timestamp for PEP emulation).
|
||||
|
||||
## CAN
|
||||
|
||||
CAN bus is primary interface.
|
||||
|
||||
## USB
|
||||
|
||||
USB (PL2303 emulation with iINTERFACE="canbusbta") used as alternate managing interface and for debugging.
|
||||
|
||||
## USART
|
||||
|
||||
USART1 can be used to operate with external encoder or other device over RS-422.
|
||||
|
||||
## SPI
|
||||
|
||||
- SPI1 used to work with external SSI encoder.
|
||||
- SPI2 used with some external things.
|
||||
|
||||
## I2C
|
||||
|
||||
not implemented yet
|
||||
|
||||
## ADC
|
||||
|
||||
ADC1 used to measure internal temperature (CH16) and external:
|
||||
|
||||
- CH1 - external power supply (raw value approx Uext/10).
|
||||
- CH2 - onboard 5V supply after DC-DC (raw value approx V/2).
|
||||
- CH3, CH4 - external inputs through dividers on RV1/R14 and RV2/R15.
|
||||
|
||||
## GPIO
|
||||
|
||||
GPIOA:
|
||||
|
||||
- PA4 - DIN - input of multiplexers U1 and U2.
|
||||
- PA5 - DEN0 - enable multiplexer U1.
|
||||
- PA6 - DEN1 - enable multiplexer U2.
|
||||
|
||||
GPIOB:
|
||||
|
||||
- PB0..PB2 - 3bit input address on multiplexer.
|
||||
|
||||
GPIOC:
|
||||
|
||||
- PC13 - buzzer (not implemented yet).
|
||||
- PC14 - relay.
|
||||
- PC15 - USB pullup.
|
||||
|
||||
# Text command protocol
|
||||
Text commands have format of `parameter[number][=setter]`. Where
|
||||
- *parameter* is any possible command,
|
||||
|
||||
@ -43,6 +43,14 @@ static errcodes time_getset(CAN_message *msg){
|
||||
*(uint32_t*)&msg->data[4] = Tms;
|
||||
return ERR_OK;
|
||||
}
|
||||
// get/set timestamp
|
||||
static errcodes timestamp_getset(CAN_message *msg){
|
||||
if(ISSETTER(msg->data)){
|
||||
TIM2->CNT = *(uint32_t*)&msg->data[4];
|
||||
}else FIXDL(msg);
|
||||
*(uint32_t*)&msg->data[4] = TIM2->CNT;
|
||||
return ERR_OK;
|
||||
}
|
||||
// get MCU T
|
||||
static errcodes mcut(CAN_message *msg){
|
||||
FIXDL(msg);
|
||||
@ -138,6 +146,11 @@ static errcodes encget(CAN_message *msg){
|
||||
if(read_encoder(msg->data + 4)) return ERR_OK;
|
||||
return ERR_CANTRUN;
|
||||
}
|
||||
// reinit encoder
|
||||
static errcodes encreinit(CAN_message _U_ *msg){
|
||||
encoder_setup();
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
// common uint32_t setter/getter
|
||||
static errcodes u32setget(CAN_message *msg){
|
||||
@ -204,6 +217,9 @@ static const commonfunction funclist[CMD_AMOUNT] = {
|
||||
[CMD_SPIINIT] = {initspi2, 0, 0, 0},
|
||||
[CMD_SPISEND] = {sendspi2, 0, 0, 5},
|
||||
[CMD_ENCGET] = {encget, 0, 0, 0},
|
||||
[CMD_EMULPEP] = {flagsetget, 0, 0, 0},
|
||||
[CMD_ENCREINIT] = {encreinit, 0, 0, 0},
|
||||
[CMD_TIMESTAMP] = {timestamp_getset, 0, 0xffffff, 0},
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -16,15 +16,23 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "can.h"
|
||||
#include "encoder.h"
|
||||
#include "flash.h"
|
||||
#include "gpio.h"
|
||||
#include "spi.h"
|
||||
#include "usart.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void encoder_setup(){
|
||||
if(FLAG(ENC_IS_SSI)) spi_setup(ENCODER_SPI);
|
||||
else usart_setup();
|
||||
if(FLAG(ENC_IS_SSI)){
|
||||
usart_deinit();
|
||||
spi_setup(ENCODER_SPI);
|
||||
}else{
|
||||
spi_deinit(ENCODER_SPI);
|
||||
usart_setup();
|
||||
}
|
||||
}
|
||||
|
||||
// read encoder value into buffer `outbuf`
|
||||
@ -34,3 +42,22 @@ int read_encoder(uint8_t outbuf[4]){
|
||||
*((uint32_t*)outbuf) = 0;
|
||||
return spi_writeread(ENCODER_SPI, outbuf, 4);
|
||||
}
|
||||
|
||||
// send encoder data
|
||||
void CANsendEnc(){
|
||||
CAN_message msg = {.data = {0}, .ID = the_conf.encoderID, .length = 8};
|
||||
if(!read_encoder(msg.data)) return;
|
||||
uint32_t ctr = TIM2->CNT;
|
||||
//msg.data[4] = 0;
|
||||
msg.data[5] = (ctr >> 16) & 0xff;
|
||||
msg.data[6] = (ctr >> 8 ) & 0xff;
|
||||
msg.data[7] = (ctr >> 0 ) & 0xff;
|
||||
CAN_send(&msg);
|
||||
}
|
||||
// send limit-switches data
|
||||
void CANsendLim(){
|
||||
CAN_message msg = {.data = {0}, .ID = the_conf.limitsID, .length = 8};
|
||||
msg.data[2] = getESW(0);
|
||||
msg.data[3] = getESW(1);
|
||||
CAN_send(&msg);
|
||||
}
|
||||
|
||||
@ -22,3 +22,5 @@
|
||||
|
||||
void encoder_setup();
|
||||
int read_encoder(uint8_t outbuf[4]);
|
||||
void CANsendEnc();
|
||||
void CANsendLim();
|
||||
|
||||
@ -46,7 +46,9 @@ user_conf the_conf = {
|
||||
.adcmul[2] = 1.f,
|
||||
.adcmul[3] = 1.f,
|
||||
.usartspeed = 115200,
|
||||
.flags = FLAGP(ENC_IS_SSI),
|
||||
.encoderID = 8,
|
||||
.limitsID = 0xe,
|
||||
.flags = FLAGP(ENC_IS_SSI) /*| FLAGP(EMULATE_PEP)*/,
|
||||
};
|
||||
|
||||
int currentconfidx = -1; // index of current configuration
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
// bit flags positions
|
||||
// encoder have SSI (1) or RS-422 (0)
|
||||
#define ENC_IS_SSI_BIT 0
|
||||
// old PEP behaviour
|
||||
#define EMULATE_PEP_BIT 1
|
||||
|
||||
// bit number
|
||||
#define FLAGBIT(f) (f ## _BIT)
|
||||
@ -53,6 +55,8 @@ typedef struct __attribute__((packed, aligned(4))){
|
||||
uint32_t bounce_ms; // debounce wait
|
||||
float adcmul[ADC_TSENS]; // ADC voltage multipliers
|
||||
uint32_t usartspeed; // USART1 speed (baud/s)
|
||||
uint16_t encoderID; // CANbus encoders' ID (PEP emulation)
|
||||
uint16_t limitsID; // CANbus limits' ID (PEP emulation)
|
||||
uint32_t flags; // bit flags
|
||||
} user_conf;
|
||||
|
||||
|
||||
@ -46,7 +46,17 @@ TRUE_INLINE void iwdg_setup(){
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void gpio_setup(){
|
||||
// setup TIM2 as 24-bit 2mks timestamp counter
|
||||
TRUE_INLINE void tim2_setup(){
|
||||
TIM2->CR1 = 0; // turn off timer
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // enable clocking
|
||||
TIM2->PSC = 143; // 500kHz
|
||||
TIM2->ARR = 0xffffff; // 24 bit counter from 0xffffff to 0
|
||||
// turn it on, downcounting
|
||||
TIM2->CR1 = TIM_CR1_CEN | TIM_CR1_DIR;
|
||||
}
|
||||
|
||||
TRUE_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; SWD - AF0 @PA13/14
|
||||
@ -73,6 +83,7 @@ static inline void gpio_setup(){
|
||||
}
|
||||
|
||||
void hw_setup(){
|
||||
tim2_setup();
|
||||
gpio_setup();
|
||||
adc_setup();
|
||||
USB_setup();
|
||||
|
||||
@ -20,6 +20,9 @@
|
||||
|
||||
#include <stm32f3.h>
|
||||
|
||||
// PEP emulation - period of encoder/esw data send - 70ms
|
||||
#define ENCODER_PERIOD (69)
|
||||
|
||||
// USB pullup
|
||||
#define USBPU_port GPIOC
|
||||
#define USBPU_pin (1<<15)
|
||||
|
||||
@ -50,6 +50,7 @@ TRUE_INLINE void showCANmessages(){
|
||||
|
||||
int main(void){
|
||||
char inbuff[MAXSTRLEN+1];
|
||||
uint32_t encT = 0; // time of ENC and LIM data sent (PEP emulation)
|
||||
USBPU_OFF();
|
||||
if(StartHSE()){
|
||||
SysTick_Config((uint32_t)72000); // 1ms
|
||||
@ -75,15 +76,6 @@ int main(void){
|
||||
CAN_reinit(0);
|
||||
}
|
||||
if(cansniffer) showCANmessages();
|
||||
/*if(bufovr){
|
||||
bufovr = 0;
|
||||
USB_sendstr("error=uartoverflow\n");
|
||||
}*/
|
||||
char *txt = NULL;
|
||||
if(usart_getline(&txt)){
|
||||
const char *ans = run_text_cmd(txt);
|
||||
if(ans) usart_send(ans);
|
||||
}
|
||||
int l = USB_receivestr(inbuff, MAXSTRLEN);
|
||||
if(l < 0) USB_sendstr("error=usboverflow\n");
|
||||
else if(l){
|
||||
@ -92,13 +84,22 @@ int main(void){
|
||||
}
|
||||
ESW_process();
|
||||
static uint8_t oldswitches[2] = {0};
|
||||
int send = 0;
|
||||
for(int i = 0; i < 2; ++i){
|
||||
uint8_t new = getESW(i);
|
||||
if(oldswitches[i] != new){
|
||||
send = 1;
|
||||
oldswitches[i] = new;
|
||||
USB_sendstr("ESW changed @"); printu(Tms);
|
||||
USB_sendstr("ESW"); USB_putbyte('0' + i);
|
||||
USB_sendstr(" changed @"); printu(Tms);
|
||||
USB_sendstr(" to "); printuhex(new); newline();
|
||||
}
|
||||
}
|
||||
if(FLAG(EMULATE_PEP)){
|
||||
if(Tms - encT > ENCODER_PERIOD){
|
||||
encT = Tms;
|
||||
CANsendEnc();
|
||||
} else if(send) CANsendLim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +69,9 @@ typedef enum{
|
||||
CMD_SPIINIT, // 16 - init SPI2
|
||||
CMD_SPISEND, // 17 - send 1..4 bytes over SPI
|
||||
CMD_ENCGET, // 18 - get encoder value
|
||||
CMD_EMULPEP, // 19 - emulate (1) / not (0) PEP
|
||||
CMD_ENCREINIT, // 20 - reinit encoder
|
||||
CMD_TIMESTAMP, // 21 - 2mks 24-bit timestamp
|
||||
CMD_AMOUNT // amount of CAN commands
|
||||
} can_cmd;
|
||||
|
||||
|
||||
@ -26,6 +26,9 @@
|
||||
|
||||
//#define SPIDR *((volatile uint8_t*)&SPI2->DR)
|
||||
|
||||
#define CHKIDX(idx) do{if(idx == 0 || idx > AMOUNT_OF_SPI) return;}while(0)
|
||||
#define CHKIDXR(idx) do{if(idx == 0 || idx > AMOUNT_OF_SPI) return 0;}while(0)
|
||||
|
||||
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)
|
||||
@ -38,7 +41,7 @@ static volatile SPI_TypeDef* const SPIs[AMOUNT_OF_SPI+1] = {NULL, SPI1, SPI2};
|
||||
// Channel 4 - SPI2 Rx
|
||||
// Channel 5 - SPI2 Tx
|
||||
void spi_setup(uint8_t idx){
|
||||
if(idx > AMOUNT_OF_SPI) return;
|
||||
CHKIDX(idx);
|
||||
volatile SPI_TypeDef *SPI = SPIs[idx];
|
||||
SPI->CR1 = 0; // clear EN
|
||||
SPI->CR2 = 0;
|
||||
@ -59,9 +62,9 @@ void spi_setup(uint8_t idx){
|
||||
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
|
||||
//RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
//SPI->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
|
||||
// Tx
|
||||
/*DMA1_Channel5->CPAR = (uint32_t)&(SPI2->DR); // hardware
|
||||
@ -82,8 +85,25 @@ void spi_setup(uint8_t idx){
|
||||
DBG("SPI works");
|
||||
}
|
||||
|
||||
// turn off given SPI channel and release GPIO
|
||||
void spi_deinit(uint8_t idx){
|
||||
CHKIDX(idx);
|
||||
volatile SPI_TypeDef *SPI = SPIs[idx];
|
||||
SPI->CR1 = 0;
|
||||
SPI->CR2 = 0;
|
||||
if(idx == 1){
|
||||
RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
|
||||
GPIOB->AFR[0] = GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL3 | GPIO_AFRL_AFRL4);
|
||||
GPIOB->MODER = GPIOB->MODER & ~(GPIO_MODER_MODER3 | GPIO_MODER_MODER4);
|
||||
}else if(idx == 2){
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_SPI2EN;
|
||||
GPIOB->AFR[1] = GPIOB->AFR[1] & ~(GPIO_AFRH_AFRH4 | GPIO_AFRH_AFRH5 | GPIO_AFRH_AFRH6 | GPIO_AFRH_AFRH7);
|
||||
GPIOB->MODER = GPIOB->MODER & ~(GPIO_MODER_MODER12 | GPIO_MODER_MODER13 | GPIO_MODER_MODER14 | GPIO_MODER_MODER15);
|
||||
}
|
||||
}
|
||||
|
||||
int spi_waitbsy(uint8_t idx){
|
||||
if(idx > AMOUNT_OF_SPI) return 0;
|
||||
CHKIDXR(idx);
|
||||
WAITX(SPIs[idx]->SR & SPI_SR_BSY);
|
||||
return 1;
|
||||
}
|
||||
@ -95,7 +115,7 @@ int spi_waitbsy(uint8_t idx){
|
||||
* @return 0 if failed
|
||||
*/
|
||||
int spi_writeread(uint8_t idx, uint8_t *data, uint32_t n){
|
||||
if(idx > AMOUNT_OF_SPI) return 0;
|
||||
CHKIDXR(idx);
|
||||
if(spi_status[idx] != SPI_READY || !data || !n){
|
||||
DBG("not ready");
|
||||
return 0;
|
||||
@ -146,7 +166,7 @@ int spi_writeread(uint8_t idx, uint8_t *data, uint32_t n){
|
||||
*/
|
||||
/*
|
||||
int spi_read(uint8_t idx, uint8_t *data, uint32_t n){
|
||||
if(idx > AMOUNT_OF_SPI) return 0;
|
||||
CHKIDXR(idx);
|
||||
if(spi_status[idx] != SPI_READY){
|
||||
DBG("not ready");
|
||||
return 0;
|
||||
|
||||
@ -29,6 +29,7 @@ typedef enum{
|
||||
|
||||
extern spiStatus spi_status[AMOUNT_OF_SPI+1];
|
||||
|
||||
void spi_deinit(uint8_t idx);
|
||||
void spi_setup(uint8_t idx);
|
||||
int spi_waitbsy(uint8_t idx);
|
||||
int spi_writeread(uint8_t idx, uint8_t *data, uint32_t n);
|
||||
|
||||
@ -58,16 +58,23 @@ static const funcdescr funclist[] = {
|
||||
{"cansnif", -TCMD_CANSNIF, "get/change sniffer state (0 - normal, 1 - sniffer)"},
|
||||
{"canspeed", CMD_CANSPEED, "get/set CAN speed (bps)"},
|
||||
{"dumpconf", -TCMD_DUMPCONF, "dump current configuration"},
|
||||
{"encget", CMD_ENCGET, "read encoder data"},
|
||||
{"encreinit", CMD_ENCREINIT, "reinit encoder"},
|
||||
{"encssi", CMD_ENCISSSI, "encoder is SSI (1) or RS-422 (0)"},
|
||||
{"esw", CMD_GETESW, "anti-bounce read ESW of channel 0 or 1"},
|
||||
{"eswblk", CMD_GETESW_BLK, "blocking read ESW of channel 0 or 1"},
|
||||
{"eraseflash", CMD_ERASESTOR, "erase all flash storage"},
|
||||
{"mcutemp", CMD_MCUTEMP, "get MCU temperature (*10degrC)"},
|
||||
{"pepemul", CMD_EMULPEP, "emulate (1) / not (0) PEP"},
|
||||
{"relay", CMD_RELAY, "get/set relay state (0 - off, 1 - on)"},
|
||||
{"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)"},
|
||||
{"spisend", CMD_SPISEND, "send 4 bytes over SPI2"},
|
||||
{"time", CMD_TIME, "get/set time (1ms, 32bit)"},
|
||||
{"timestamp", CMD_TIMESTAMP, "get/set timestamp (2mks, 24bit)"},
|
||||
{"usartspeed", CMD_USARTSPEED, "get/set USART1 speed"},
|
||||
{"wdtest", -TCMD_WDTEST, "test watchdog"},
|
||||
{NULL, 0, NULL} // last record
|
||||
};
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
static volatile int idatalen = 0; // received data line length (including '\n')
|
||||
|
||||
volatile int linerdy = 0, // received data ready
|
||||
static volatile int linerdy = 0, // received data ready
|
||||
dlen = 0, // length of data (including '\n') in current buffer
|
||||
bufovr = 0; // input buffer overfull
|
||||
|
||||
@ -65,9 +65,17 @@ void usart_send(const char *str){
|
||||
usart_sendn(str, L);
|
||||
}
|
||||
|
||||
// turn off USART1 and deinit GPIO
|
||||
void usart_deinit(){
|
||||
USART1->ICR = 0xffffffff;
|
||||
USART1->CR1 = 0;
|
||||
RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN;
|
||||
GPIOA->AFR[1] = GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2);
|
||||
GPIOA->MODER = GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10);
|
||||
}
|
||||
|
||||
// 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)) |
|
||||
|
||||
@ -23,9 +23,8 @@
|
||||
// input buffers size
|
||||
#define UARTBUFSZ (80)
|
||||
|
||||
extern volatile int linerdy, bufovr;
|
||||
|
||||
void usart_setup();
|
||||
void usart_deinit();
|
||||
int usart_getline(char **line);
|
||||
void usart_send(const char *str);
|
||||
void usart_sendn(const char *str, int L);
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
#define BUILD_NUMBER "80"
|
||||
#define BUILD_DATE "2024-03-07"
|
||||
#define BUILD_NUMBER "84"
|
||||
#define BUILD_DATE "2024-03-08"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user