almost ready but have IWDG reset when trying to send data over RS-232 in CANbus flooding

This commit is contained in:
Edward Emelianov 2024-09-26 17:53:16 +03:00
parent 03772fce3a
commit b9942f2e9f
19 changed files with 388 additions and 188 deletions

View File

@ -47,12 +47,13 @@ void adc_setup(){
ADC1->CR2 |= ADC_CR2_ADON; ADC1->CR2 |= ADC_CR2_ADON;
__DSB(); __DSB();
// wait for Tstab - at least 1us // wait for Tstab - at least 1us
IWDG->KR = IWDG_REFRESH;
while(++ctr < 0xff) nop(); while(++ctr < 0xff) nop();
// calibration // calibration
ADC1->CR2 |= ADC_CR2_RSTCAL; ADC1->CR2 |= ADC_CR2_RSTCAL;
ctr = 0; while((ADC1->CR2 & ADC_CR2_RSTCAL) && ++ctr < 0xfffff); ctr = 0; while((ADC1->CR2 & ADC_CR2_RSTCAL) && ++ctr < 0xfffff) IWDG->KR = IWDG_REFRESH;
ADC1->CR2 |= ADC_CR2_CAL; ADC1->CR2 |= ADC_CR2_CAL;
ctr = 0; while((ADC1->CR2 & ADC_CR2_CAL) && ++ctr < 0xfffff); ctr = 0; while((ADC1->CR2 & ADC_CR2_CAL) && ++ctr < 0xfffff) IWDG->KR = IWDG_REFRESH;
// clear possible errors and start // clear possible errors and start
ADC1->SR = 0; ADC1->SR = 0;
ADC1->CR2 |= ADC_CR2_SWSTART; ADC1->CR2 |= ADC_CR2_SWSTART;

View File

@ -48,9 +48,7 @@ static CAN_status can_status = CAN_STOP;
static void can_process_fifo(uint8_t fifo_num); static void can_process_fifo(uint8_t fifo_num);
CAN_status CAN_get_status(){ CAN_status CAN_get_status(){
int st = can_status; return can_status;
can_status = CAN_OK;
return st;
} }
// push next message into buffer; return 1 if buffer overfull // push next message into buffer; return 1 if buffer overfull
@ -141,8 +139,10 @@ void CAN_setup(uint32_t speed){
/* (12) Leave filter init */ /* (12) Leave filter init */
/* (13) Set error interrupts enable (& bus off) */ /* (13) Set error interrupts enable (& bus off) */
CAN1->MCR |= CAN_MCR_INRQ; /* (1) */ CAN1->MCR |= CAN_MCR_INRQ; /* (1) */
while((CAN1->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) /* (2) */ while((CAN1->MSR & CAN_MSR_INAK) != CAN_MSR_INAK){ /* (2) */
IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) break; if(--tmout == 0) break;
}
CAN1->MCR &=~ CAN_MCR_SLEEP; /* (3) */ CAN1->MCR &=~ CAN_MCR_SLEEP; /* (3) */
CAN1->MCR |= CAN_MCR_ABOM; /* allow automatically bus-off */ CAN1->MCR |= CAN_MCR_ABOM; /* allow automatically bus-off */
CAN1->BTR = (CAN_TBS2-1) << 20 | (CAN_TBS1-1) << 16 | (CAN_BIT_OSC/speed - 1); //| CAN_BTR_SILM | CAN_BTR_LBKM; /* (4) */ CAN1->BTR = (CAN_TBS2-1) << 20 | (CAN_TBS1-1) << 16 | (CAN_BIT_OSC/speed - 1); //| CAN_BTR_SILM | CAN_BTR_LBKM; /* (4) */
@ -152,8 +152,10 @@ void CAN_setup(uint32_t speed){
#endif #endif
CAN1->MCR &= ~CAN_MCR_INRQ; /* (5) */ CAN1->MCR &= ~CAN_MCR_INRQ; /* (5) */
tmout = 16000000; tmout = 16000000;
while((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) /* (6) */ while((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK){ /* (6) */
IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) break; if(--tmout == 0) break;
}
// accept depending of monitor flag // accept depending of monitor flag
CAN1->FMR = CAN_FMR_FINIT; /* (7) */ CAN1->FMR = CAN_FMR_FINIT; /* (7) */
CAN1->FA1R = CAN_FA1R_FACT0; /* (8) */ CAN1->FA1R = CAN_FA1R_FACT0; /* (8) */
@ -218,6 +220,22 @@ void CAN_printerr(){
} }
void CAN_proc(){ void CAN_proc(){
IWDG->KR = IWDG_REFRESH;
if((CAN1->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF))
|| can_status != CAN_READY){ // much errors - restart CAN BUS
if(flags.can_printoff){
const char *e;
switch(can_status){
case CAN_ERR: e = "ERRI"; break;
case CAN_FIFO_OVERRUN: e = "FIFO_OVERRUN"; break;
default: e = "UNKNOWN";
}
usart_send("canerror=");
usart_send(e); newline();
CAN_printerr();
}
CAN_reinit(0);
}
// check for messages in FIFO0 & FIFO1 // check for messages in FIFO0 & FIFO1
if(CAN1->RF0R & CAN_RF0R_FMP0){ if(CAN1->RF0R & CAN_RF0R_FMP0){
can_process_fifo(0); can_process_fifo(0);
@ -225,14 +243,6 @@ void CAN_proc(){
if(CAN1->RF1R & CAN_RF1R_FMP1){ if(CAN1->RF1R & CAN_RF1R_FMP1){
can_process_fifo(1); can_process_fifo(1);
} }
IWDG->KR = IWDG_REFRESH;
if(CAN1->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS
if(flags.can_printoff){
usart_send("error=canerr\n");
CAN_printerr();
}
CAN_reinit(0);
}
} }
CAN_status CAN_send(CAN_message *message){ CAN_status CAN_send(CAN_message *message){
@ -290,28 +300,6 @@ CAN_status CAN_send(CAN_message *message){
return CAN_OK; return CAN_OK;
} }
/**
* @brief parseCANcommand - parser
* @param msg - incoming message @ my CANID
* FORMAT:
* 0 1 2 3 4 5 6 7
* [CMD][PAR][errcode][VALUE]
* CMD - uint16_t, PAR - uint8_t, errcode - one of CAN_errcodes, VALUE - int32_t
* `errcode` of incoming message doesn't matter
* incoming data may have variable length
*/
TRUE_INLINE void parseCANcommand(CAN_message *msg){
msg->ID = the_conf.CANIDout; // set output ID for all output messages
// check PING
if(msg->length != 0) run_can_cmd(msg);
uint32_t Tstart = Tms;
while(Tms - Tstart < SEND_TIMEOUT_MS){
if(CAN_OK == CAN_send(msg)) return;
IWDG->KR = IWDG_REFRESH;
}
usart_send("error=canbusy\n");
}
static void can_process_fifo(uint8_t fifo_num){ static void can_process_fifo(uint8_t fifo_num){
if(fifo_num > 1) return; if(fifo_num > 1) return;
CAN_FIFOMailBox_TypeDef *box = &CAN1->sFIFOMailBox[fifo_num]; CAN_FIFOMailBox_TypeDef *box = &CAN1->sFIFOMailBox[fifo_num];
@ -355,9 +343,8 @@ static void can_process_fifo(uint8_t fifo_num){
dat[0] = lb & 0xff; dat[0] = lb & 0xff;
} }
} }
// run command for my or broadcast ID IWDG->KR = IWDG_REFRESH;
if(msg.ID == the_conf.CANIDin || msg.ID == 0) parseCANcommand(&msg); if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later
if(flags.can_monitor && CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later
*RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message *RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message
} }
//if(*RFxR & CAN_RF0R_FULL0) *RFxR &= ~CAN_RF0R_FULL0; //if(*RFxR & CAN_RF0R_FULL0) *RFxR &= ~CAN_RF0R_FULL0;
@ -368,6 +355,7 @@ void usb_lp_can_rx0_isr(){ // Rx FIFO0 (overrun)
if(CAN1->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun if(CAN1->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun
CAN1->RF0R &= ~CAN_RF0R_FOVR0; CAN1->RF0R &= ~CAN_RF0R_FOVR0;
can_status = CAN_FIFO_OVERRUN; can_status = CAN_FIFO_OVERRUN;
RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
} }
} }
@ -375,6 +363,7 @@ void can_rx1_isr(){ // Rx FIFO1 (overrun)
if(CAN1->RF1R & CAN_RF1R_FOVR1){ if(CAN1->RF1R & CAN_RF1R_FOVR1){
CAN1->RF1R &= ~CAN_RF1R_FOVR1; CAN1->RF1R &= ~CAN_RF1R_FOVR1;
can_status = CAN_FIFO_OVERRUN; can_status = CAN_FIFO_OVERRUN;
RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
} }
} }
@ -386,5 +375,6 @@ void can_sce_isr(){ // status changed
if(CAN1->TSR & CAN_TSR_TERR1) CAN1->TSR |= CAN_TSR_ABRQ1; if(CAN1->TSR & CAN_TSR_TERR1) CAN1->TSR |= CAN_TSR_ABRQ1;
if(CAN1->TSR & CAN_TSR_TERR2) CAN1->TSR |= CAN_TSR_ABRQ2; if(CAN1->TSR & CAN_TSR_TERR2) CAN1->TSR |= CAN_TSR_ABRQ2;
can_status = CAN_ERR; can_status = CAN_ERR;
RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
} }
} }

View File

@ -27,8 +27,7 @@
#define FIXDL(m) do{m->length = 8;}while(0) #define FIXDL(m) do{m->length = 8;}while(0)
/*********** START of all common functions list (for `funclist`) ***********/ /*********** START of all common functions list (for `funclist`) ***********/
static errcodes ping(CAN_message *m){ static errcodes ping(CAN_message _U_ *m){
m->ID = the_conf.CANIDout; // change ID
return ERR_OK; // send same message return ERR_OK; // send same message
} }
// reset MCU // reset MCU
@ -163,6 +162,7 @@ static errcodes u32setget(CAN_message *msg){
case CMD_INCHNLS: val = inchannels(); ptr = &val; break; case CMD_INCHNLS: val = inchannels(); ptr = &val; break;
case CMD_OUTCHNLS: val = outchannels(); ptr = &val; break; case CMD_OUTCHNLS: val = outchannels(); ptr = &val; break;
case CMD_MODBUSID: ptr = &the_conf.modbusID; break; case CMD_MODBUSID: ptr = &the_conf.modbusID; break;
case CMD_MODBUSIDOUT: ptr = &the_conf.modbusIDout; break;
case CMD_MODBUSSPEED: ptr = &the_conf.modbusspeed; break; case CMD_MODBUSSPEED: ptr = &the_conf.modbusspeed; break;
default: break; default: break;
} }
@ -230,6 +230,7 @@ static const commonfunction funclist[CMD_AMOUNT] = {
[CMD_INCHNLS] = {u32setget, 0, 0, 0}, [CMD_INCHNLS] = {u32setget, 0, 0, 0},
[CMD_OUTCHNLS] = {u32setget, 0, 0, 0}, [CMD_OUTCHNLS] = {u32setget, 0, 0, 0},
[CMD_MODBUSID] = {u32setget, 0, MODBUS_MAX_ID, 0}, // 0 - master! [CMD_MODBUSID] = {u32setget, 0, MODBUS_MAX_ID, 0}, // 0 - master!
[CMD_MODBUSIDOUT] = {u32setget, 0, MODBUS_MAX_ID, 0},
[CMD_MODBUSSPEED] = {u32setget, 1200, 115200, 0}, [CMD_MODBUSSPEED] = {u32setget, 1200, 115200, 0},
}; };
@ -288,3 +289,25 @@ void run_can_cmd(CAN_message *msg){
newline(); newline();
#endif #endif
} }
/**
* @brief parseCANcommand - parser
* @param msg - incoming message @ my CANID
* FORMAT:
* 0 1 2 3 4 5 6 7
* [CMD][PAR][errcode][VALUE]
* CMD - uint16_t, PAR - uint8_t, errcode - one of CAN_errcodes, VALUE - int32_t
* `errcode` of incoming message doesn't matter
* incoming data may have variable length
*/
void parseCANcommand(CAN_message *msg){
// check PING
if(msg->length != 0) run_can_cmd(msg);
uint32_t Tstart = Tms;
// send answer
while(Tms - Tstart < SEND_TIMEOUT_MS){
if(CAN_OK == CAN_send(msg)) return;
IWDG->KR = IWDG_REFRESH;
}
usart_send("error=canbusy\n");
}

View File

@ -48,6 +48,9 @@ typedef enum{
// set command bytes in CAN message // set command bytes in CAN message
#define MSG_SET_CMD(msg, cmd) do{*((uint16_t*)msg.data) = (cmd);}while(0) #define MSG_SET_CMD(msg, cmd) do{*((uint16_t*)msg.data) = (cmd);}while(0)
#define MSGP_SET_CMD(msg, cmd) do{*((uint16_t*)msg->data) = (cmd);}while(0) #define MSGP_SET_CMD(msg, cmd) do{*((uint16_t*)msg->data) = (cmd);}while(0)
// set command parameter number
#define MSG_SET_PARNO(msg, n) do{msg.data[2] = (n);}while(0)
#define MSGP_SET_PARNO(msg, n) do{msg->data[2] = (n);}while(0)
// set error // set error
#define MSG_SET_ERR(msg, err) do{msg.data[3] = (err);}while(0) #define MSG_SET_ERR(msg, err) do{msg.data[3] = (err);}while(0)
#define MSGP_SET_ERR(msg, err) do{msg->data[3] = (err);}while(0) #define MSGP_SET_ERR(msg, err) do{msg->data[3] = (err);}while(0)
@ -75,15 +78,17 @@ enum{
CMD_GETESW, // current ESW state, bounce-free CMD_GETESW, // current ESW state, bounce-free
CMD_GETESWNOW, // current ESW state, absolute CMD_GETESWNOW, // current ESW state, absolute
CMD_BOUNCE, // get/set bounce constant (ms) CMD_BOUNCE, // get/set bounce constant (ms)
CMD_USARTSPEED, // get/set USART1 speed (if encoder on RS-422) CMD_USARTSPEED, // get/set USART1 speed
CMD_LED, // onboard LED CMD_LED, // onboard LED
CMD_FLAGS, // flags setter/getter CMD_FLAGS, // flags setter/getter
CMD_INCHNLS, // all bits set are active supported IN channels CMD_INCHNLS, // all bits set are active supported IN channels
CMD_OUTCHNLS, // all bits set are active supported OUT channels CMD_OUTCHNLS, // all bits set are active supported OUT channels
CMD_MODBUSID, // set/get modbus slave ID (or 0 if master) CMD_MODBUSID, // set/get modbus slave ID (or 0 if master)
CMD_MODBUSIDOUT,// slave ID to send modbus relay command if IN changes
CMD_MODBUSSPEED,// speed of modbus interface CMD_MODBUSSPEED,// speed of modbus interface
// should be the last: // should be the last:
CMD_AMOUNT // amount of CAN commands CMD_AMOUNT // amount of CAN commands
}; };
void run_can_cmd(CAN_message *msg); void run_can_cmd(CAN_message *msg);
void parseCANcommand(CAN_message *msg);

View File

@ -35,8 +35,10 @@ static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here
,.CANIDout = 2 \ ,.CANIDout = 2 \
,.usartspeed = 115200 \ ,.usartspeed = 115200 \
,.bouncetime = 50 \ ,.bouncetime = 50 \
,.modbusID = MODBUS_MASTER_ID \ ,.modbusID = 1 \
,.modbusIDout = 2 \
,.modbusspeed = 9600 \ ,.modbusspeed = 9600 \
,.flags.sw_send_relay_inv = 1 \
} }
static int write2flash(const void*, const void*, uint32_t); static int write2flash(const void*, const void*, uint32_t);
@ -57,6 +59,7 @@ int currentconfidx = -1; // index of current configuration
static int binarySearch(int r, const uint8_t *start, int stor_size){ static int binarySearch(int r, const uint8_t *start, int stor_size){
int l = 0; int l = 0;
while(r >= l){ while(r >= l){
IWDG->KR = IWDG_REFRESH;
int mid = l + (r - l) / 2; int mid = l + (r - l) / 2;
const uint8_t *s = start + mid * stor_size; const uint8_t *s = start + mid * stor_size;
if(*((const uint16_t*)s) == stor_size){ if(*((const uint16_t*)s) == stor_size){

View File

@ -23,15 +23,21 @@
#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0) #define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0)
#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) #define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG)
// maximal bit number of flags // maximal bit NUMBER (0 etc) of flags
#define MAX_FLAG_BITNO (0) #define MAX_FLAG_BITNO (3)
typedef union{ typedef union{
uint32_t u32; uint32_t u32;
struct{ struct{
uint32_t sw_send_relay_cmd; // switching ESW state will send also CMD_RELAY command with CANID_OUT uint32_t sw_send_esw_can : 1; // 0 - if ESW state changes, send message over CAN with CANID_IN
uint32_t sw_send_relay_can : 1; // 1 - switching ESW state will send CMD_RELAY command with CANID_OUT
uint32_t sw_send_relay_inv : 1; // 2 - sw_send should be inverted related to current inputs value
uint32_t sw_send_relay_modbus : 1; // 3 - 1 for modbus
}; };
} confflags_t; } confflags_t;
// ALL sw_send flags mask (without relay_inv)
#define SW_SEND_MASK (0x0B)
/* /*
* struct to save user configurations * struct to save user configurations
*/ */
@ -45,6 +51,7 @@ typedef struct __attribute__((aligned(4))){
uint32_t CANspeed; // CAN bus speed uint32_t CANspeed; // CAN bus speed
confflags_t flags; // different flags confflags_t flags; // different flags
uint32_t modbusID; // MODBUS-RTU ID (0 for master) uint32_t modbusID; // MODBUS-RTU ID (0 for master)
uint32_t modbusIDout; // MODBUS-RTU slave ID to send relay command when IN changes
uint32_t modbusspeed; // Speed of modbus interface uint32_t modbusspeed; // Speed of modbus interface
} user_conf; } user_conf;

Binary file not shown.

View File

@ -20,6 +20,7 @@
#include "canproto.h" #include "canproto.h"
#include "flash.h" #include "flash.h"
#include "hardware.h" #include "hardware.h"
#include "modbusrtu.h"
/* /*
#ifdef EBUG #ifdef EBUG
#include "strfunc.h" #include "strfunc.h"
@ -116,14 +117,16 @@ void gpio_setup(void){
void iwdg_setup(){ void iwdg_setup(){
uint32_t tmout = 16000000; uint32_t tmout = 16000000;
RCC->CSR |= RCC_CSR_LSION; RCC->CSR |= RCC_CSR_LSION;
while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY) if(--tmout == 0) break;
IWDG->KR = IWDG_START; IWDG->KR = IWDG_START;
IWDG->KR = IWDG_WRITE_ACCESS; IWDG->KR = IWDG_WRITE_ACCESS;
IWDG->PR = IWDG_PR_PR_1; IWDG->PR = IWDG_PR_PR_1;
IWDG->RLR = 1250; IWDG->RLR = 1250;
tmout = 16000000; tmout = 16000000;
while(IWDG->SR){if(--tmout == 0) break;} while(IWDG->SR){
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) break;
}
} }
typedef struct{ typedef struct{
@ -263,22 +266,46 @@ void proc_esw(){
else ESW_ab_values &= ~mask; else ESW_ab_values &= ~mask;
lastET[i] = Tms; lastET[i] = Tms;
} }
if(oldesw != ESW_ab_values){ if(oldesw != ESW_ab_values && (the_conf.flags.u32 & SW_SEND_MASK)){ // State changes and need to send info
//usart_send("esw="); usart_send(u2str(ESW_ab_values)); newline(); //usart_send("esw="); usart_send(u2str(ESW_ab_values)); newline();
CAN_message msg = {.ID = the_conf.CANIDout, .length = 8}; if(the_conf.flags.sw_send_esw_can){
CAN_message msg = {.ID = the_conf.CANIDin, .length = 8, .data = {0}};
MSG_SET_CMD(msg, CMD_GETESW); MSG_SET_CMD(msg, CMD_GETESW);
MSG_SET_U32(msg, ESW_ab_values); MSG_SET_U32(msg, ESW_ab_values);
uint32_t Tstart = Tms; uint32_t Tstart = Tms;
while(Tms - Tstart < SEND_TIMEOUT_MS){ while(Tms - Tstart < SEND_TIMEOUT_MS){
IWDG->KR = IWDG_REFRESH;
if(CAN_OK == CAN_send(&msg)) break; if(CAN_OK == CAN_send(&msg)) break;
} }
if(the_conf.flags.sw_send_relay_cmd){ // send also CMD_RELAY }
uint32_t v = ESW_ab_values;
if(the_conf.flags.sw_send_relay_inv) v = ~v;
if(the_conf.flags.sw_send_relay_can){ // send also CMD_RELAY
CAN_message msg = {.ID = the_conf.CANIDout, .length = 8, .data = {0}};
MSG_SET_U32(msg, v);
MSG_SET_CMD(msg, CMD_RELAY); MSG_SET_CMD(msg, CMD_RELAY);
Tstart = Tms; MSG_SET_PARNO(msg, SETTER_FLAG | NO_PARNO);
uint32_t Tstart = Tms;
while(Tms - Tstart < SEND_TIMEOUT_MS){ while(Tms - Tstart < SEND_TIMEOUT_MS){
IWDG->KR = IWDG_REFRESH;
if(CAN_OK == CAN_send(&msg)) break; if(CAN_OK == CAN_send(&msg)) break;
} }
} }
if(the_conf.flags.sw_send_relay_modbus && the_conf.modbusID == MODBUS_MASTER_ID){
modbus_request r = {.ID = the_conf.modbusIDout,
.Fcode = MC_WRITE_MUL_COILS,
.startreg = 0,
.regno = OUTMAX+1,
.datalen = OUTMAXBYTES
};
uint8_t data[OUTMAXBYTES];
r.data = data;
for(int i = OUTMAXBYTES - 1; i > -1; --i){
data[i] = (uint8_t) v;
v >>= 8;
}
modbus_send_request(&r);
}
} }
} }

View File

@ -18,6 +18,7 @@
#include "adc.h" #include "adc.h"
#include "can.h" #include "can.h"
#include "canproto.h"
#include "flash.h" #include "flash.h"
#include "hardware.h" #include "hardware.h"
#include "modbusproto.h" #include "modbusproto.h"
@ -48,7 +49,6 @@ int main(void){
uint32_t lastT = 0; uint32_t lastT = 0;
CAN_message *can_mesg; CAN_message *can_mesg;
StartHSE(); StartHSE();
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
SysTick_Config(72000); SysTick_Config(72000);
flashstorage_init(); flashstorage_init();
gpio_setup(); // should be run before other peripherial setup gpio_setup(); // should be run before other peripherial setup
@ -61,6 +61,19 @@ int main(void){
iwdg_setup(); iwdg_setup();
#endif #endif
usart_send("START\n"); usart_send("START\n");
if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
usart_send("IWDGRSTF=1\n");
}
if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured
usart_send("SFTRSTF=1\n");
}
if(RCC->CSR & RCC_CSR_PORRSTF){ // POR/RDR
usart_send("PORRSTF=1\n");
}
if(RCC->CSR & RCC_CSR_PINRSTF){ // reset by pin NRST
usart_send("PINRSTF=1\n");
}
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
while (1){ while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(Tms - lastT > 499){ // throw out short messages twice per second if(Tms - lastT > 499){ // throw out short messages twice per second
@ -69,15 +82,12 @@ int main(void){
} }
proc_esw(); proc_esw();
CAN_proc(); CAN_proc();
CAN_status st = CAN_get_status();
if(st == CAN_FIFO_OVERRUN){
usart_send("CAN bus fifo overrun occured!\n");
}else if(st == CAN_ERR){
usart_send("Some CAN error occured\n");
}
while((can_mesg = CAN_messagebuf_pop())){ while((can_mesg = CAN_messagebuf_pop())){
DBG("got CAN message\n"); DBG("got CAN message\n");
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
// run command for my or broadcast ID
if(can_mesg->ID == the_conf.CANIDin || can_mesg->ID == 0)
parseCANcommand(can_mesg);
if(flags.can_monitor){ if(flags.can_monitor){
lastT = Tms; lastT = Tms;
if(!lastT) lastT = 1; if(!lastT) lastT = 1;

View File

@ -68,13 +68,12 @@ TRUE_INLINE void readdiscr(modbus_request *r){
return; return;
} }
uint8_t bytes[INMAXBYTES] = {0}; uint8_t bytes[INMAXBYTES] = {0};
int curidx = INMAXBYTES - 1;
int vals = get_esw(INMAX+1); int vals = get_esw(INMAX+1);
for(int i = 0; i < amount; ++i){ for(int i = amount - 1; i > -1; --i){
bytes[--curidx] = vals & 0xff; bytes[i] = vals & 0xff;
vals >>= 8; vals >>= 8;
} }
modbus_response resp = {.Fcode = r->Fcode, .ID = the_conf.modbusID, .data = bytes+curidx, .datalen = amount}; modbus_response resp = {.Fcode = r->Fcode, .ID = the_conf.modbusID, .data = bytes, .datalen = amount};
modbus_send_response(&resp); modbus_send_response(&resp);
} }
@ -122,7 +121,7 @@ TRUE_INLINE void readadc(modbus_request *r){
uint16_t vals[ADC_CHANNELS]; uint16_t vals[ADC_CHANNELS];
for(int i = r->startreg; i < nlast; ++i){ for(int i = r->startreg; i < nlast; ++i){
uint16_t v = getADCval(i); uint16_t v = getADCval(i);
vals[i] = __builtin_bswap16(v); vals[i - r->startreg] = __builtin_bswap16(v);
} }
modbus_response resp = {.Fcode = r->Fcode, .ID = the_conf.modbusID, .data = (uint8_t*) vals, .datalen = r->regno * 2}; modbus_response resp = {.Fcode = r->Fcode, .ID = the_conf.modbusID, .data = (uint8_t*) vals, .datalen = r->regno * 2};
modbus_send_response(&resp); modbus_send_response(&resp);
@ -155,20 +154,21 @@ TRUE_INLINE void writereg(modbus_request *r){
// support ONLY write to ALL! // support ONLY write to ALL!
// data - by bits, like in readcoil // data - by bits, like in readcoil
// N registers is N bits
TRUE_INLINE void writecoils(modbus_request *r){ TRUE_INLINE void writecoils(modbus_request *r){
if(r->startreg){ if(r->startreg){
senderr(r, ME_ILLEGAL_ADDRESS); senderr(r, ME_ILLEGAL_ADDRESS);
return; return;
} }
int amount = r->regno; int amount = (r->regno + 7) >> 3;
if(amount == 0 || amount > OUTMAX || r->datalen > 4){ if(amount == 0 || amount > OUTMAXBYTES || r->datalen < amount){
senderr(r, ME_ILLEGAL_VALUE); senderr(r, ME_ILLEGAL_VALUE);
return; return;
} }
uint32_t v = 0; uint32_t v = 0;
for(int i = 0; i < amount; ++i){ for(int i = 0; i < amount; ++i){
v |= r->data[i];
v <<= 8; v <<= 8;
v |= r->data[i];
} }
if(set_relay(OUTMAX+1, v) < 0){ if(set_relay(OUTMAX+1, v) < 0){
senderr(r, ME_NACK); senderr(r, ME_NACK);

View File

@ -39,11 +39,12 @@ static void us(){
}*/ }*/
// switch to Rx/Tx: // switch to Rx/Tx:
#define _485_Rx() do{LED(1); RS485_RX(); /*UART4->CR1 = (UART4->CR1 & ~USART_CR1_TE) | USART_CR1_RE;*/}while(0) #define _485_Rx() do{ DMA2_Channel5->CCR &= ~DMA_CCR_EN; RS485_RX(); \
#define _485_Tx() do{LED(0); RS485_TX(); /*UART4->CR1 = (UART4->CR1 & ~USART_CR1_RE) | USART_CR1_TE;*/}while(0) DMA2_Channel3->CMAR = (uint32_t) rbuf[rbufno]; DMA2_Channel3->CNDTR = MODBUSBUFSZI; \
DMA2_Channel3->CCR |= DMA_CCR_EN;}while(0)
#define _485_Tx() do{ RS485_TX(); }while(0)
static volatile int modbus_txrdy = 1; static volatile int modbus_txrdy = 1;
static volatile int idatalen[2] = {0,0}; // received data line length (including '\n')
static volatile int modbus_rdy = 0 // received data ready static volatile int modbus_rdy = 0 // received data ready
,dlen = 0 // length of data (including '\n') in current buffer ,dlen = 0 // length of data (including '\n') in current buffer
@ -68,9 +69,11 @@ static uint16_t getCRC(uint8_t *data, int l){
}else crc >>= 1; }else crc >>= 1;
} }
} }
/*
#ifdef EBUG #ifdef EBUG
DBG("Calc CRC: "); printuhex(crc); newline(); DBG("Calc CRC: "); printuhex(crc); newline();
#endif #endif
*/
// CRC have swapped bytes, so we can just send it as *((uint16_t*)&data[x]) = CRC // CRC have swapped bytes, so we can just send it as *((uint16_t*)&data[x]) = CRC
return crc; return crc;
} }
@ -105,13 +108,13 @@ static int senddata(int l){
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) return 0; if(--tmout == 0) return 0;
}; // wait for previos buffer transmission }; // wait for previos buffer transmission
_485_Tx();
modbus_txrdy = 0; modbus_txrdy = 0;
DMA2_Channel5->CCR &= ~DMA_CCR_EN; DMA2_Channel5->CCR &= ~DMA_CCR_EN;
DMA2_Channel5->CMAR = (uint32_t) tbuf[tbufno]; // mem DMA2_Channel5->CMAR = (uint32_t) tbuf[tbufno]; // mem
DMA2_Channel5->CNDTR = l + 2; // + CRC DMA2_Channel5->CNDTR = l + 2; // + CRC
DMA2_Channel5->CCR |= DMA_CCR_EN; DMA2_Channel5->CCR |= DMA_CCR_EN;
tbufno = !tbufno; tbufno = !tbufno;
_485_Tx();
return l; return l;
} }
@ -133,12 +136,13 @@ int modbus_send_request(modbus_request *r){
*curbuf++ = r->startreg >> 8; // H *curbuf++ = r->startreg >> 8; // H
*curbuf++ = (uint8_t) r->startreg; // L *curbuf++ = (uint8_t) r->startreg; // L
*curbuf++ = r->regno >> 8; // H *curbuf++ = r->regno >> 8; // H
*curbuf = (uint8_t) r->regno; // L *curbuf++ = (uint8_t) r->regno; // L
// if r->datalen == 0 - this is responce for request with fcode > 4 // if r->datalen == 0 - this is responce for request with fcode > 4
if((r->Fcode == MC_WRITE_MUL_COILS || r->Fcode == MC_WRITE_MUL_REGS) && r->datalen){ // request with data if((r->Fcode == MC_WRITE_MUL_COILS || r->Fcode == MC_WRITE_MUL_REGS) && r->datalen){ // request with data
*(++curbuf) = r->datalen; if(r->datalen > MODBUSBUFSZO - 7) return -1;
*curbuf++ = r->datalen;
memcpy(curbuf, r->data, r->datalen); memcpy(curbuf, r->data, r->datalen);
n += r->datalen; n += r->datalen + 1; // + data length byte
} }
packCRC(tbuf[tbufno], n) = getCRC(tbuf[tbufno], n); packCRC(tbuf[tbufno], n) = getCRC(tbuf[tbufno], n);
return senddata(n); return senddata(n);
@ -207,62 +211,57 @@ int modbus_get_response(modbus_response* r){
// USART4: PC10 - Tx, PC11 - Rx // USART4: PC10 - Tx, PC11 - Rx
void modbus_setup(uint32_t speed){ void modbus_setup(uint32_t speed){
uint32_t tmout = 16000000;
// PC10 - Tx, PC11 - Rx // PC10 - Tx, PC11 - Rx
RCC->APB1ENR |= RCC_APB1ENR_UART4EN; RCC->APB1ENR |= RCC_APB1ENR_UART4EN;
RCC->AHBENR |= RCC_AHBENR_DMA2EN; RCC->AHBENR |= RCC_AHBENR_DMA2EN;
GPIOC->CRH = (GPIOC->CRH & ~(CRH(10,0xf)|CRH(11,0xf))) | GPIOC->CRH = (GPIOC->CRH & ~(CRH(10,0xf)|CRH(11,0xf))) |
CRH(10, CNF_AFPP|MODE_NORMAL) | CRH(11, CNF_FLINPUT|MODE_INPUT); CRH(10, CNF_AFPP|MODE_NORMAL) | CRH(11, CNF_FLINPUT|MODE_INPUT);
// UART4 Tx DMA - Channel5 (Rx - channel 3) // UART4 Tx DMA - Channel5, Rx - channel 3
DMA2_Channel5->CPAR = (uint32_t) &UART4->DR; // periph DMA2_Channel5->CPAR = (uint32_t) &UART4->DR; // periph
DMA2_Channel5->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq DMA2_Channel5->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq
DMA2_Channel3->CPAR = (uint32_t) &UART4->DR;
DMA2_Channel3->CCR = DMA_CCR_MINC | DMA_CCR_TCIE;
// Tx CNDTR set @ each transmission due to data size // Tx CNDTR set @ each transmission due to data size
NVIC_SetPriority(DMA2_Channel4_5_IRQn, 2); NVIC_SetPriority(DMA2_Channel4_5_IRQn, 2);
NVIC_EnableIRQ(DMA2_Channel4_5_IRQn); NVIC_EnableIRQ(DMA2_Channel4_5_IRQn);
NVIC_SetPriority(UART4_IRQn, 2); NVIC_SetPriority(DMA2_Channel3_IRQn, 2);
NVIC_EnableIRQ(DMA2_Channel3_IRQn);
// setup uart4 // setup uart4
UART4->BRR = 36000000 / speed; // APB1 is 36MHz UART4->BRR = 36000000 / speed; // APB1 is 36MHz
UART4->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART UART4->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
uint32_t tmout = 16000000;
while(!(UART4->SR & USART_SR_TC)){ // polling idle frame Transmission while(!(UART4->SR & USART_SR_TC)){ // polling idle frame Transmission
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) break; if(--tmout == 0) break;
} }
(void) UART4->DR; // clear IDLE etc
UART4->SR = 0; // clear flags UART4->SR = 0; // clear flags
UART4->CR1 |= USART_CR1_RXNEIE | USART_CR1_IDLEIE | USART_CR1_TCIE; // allow Rx and IDLE IRQ; TC IRQ for switching to Rx UART4->CR1 |= USART_CR1_IDLEIE | USART_CR1_TCIE; // allow IDLE IRQ; TC IRQ for switching to Rx
UART4->CR3 = USART_CR3_DMAT; // enable DMA Tx UART4->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; // enable DMA Tx & Rx
NVIC_SetPriority(UART4_IRQn, 2);
NVIC_EnableIRQ(UART4_IRQn); NVIC_EnableIRQ(UART4_IRQn);
_485_Rx(); _485_Rx();
} }
void uart4_isr(){ void uart4_isr(){
if(UART4->SR & USART_SR_IDLE){ // idle - end of frame if(UART4->SR & USART_SR_IDLE){ // idle - end of frame
usart_send("485: IDLE\n"); DMA2_Channel3->CCR &= ~DMA_CCR_EN;
modbus_rdy = 1; modbus_rdy = 1;
dlen = idatalen[rbufno]; dlen = MODBUSBUFSZI - DMA2_Channel3->CNDTR;
recvdata = rbuf[rbufno]; recvdata = rbuf[rbufno];
// prepare other buffer // prepare other buffer
rbufno = !rbufno; rbufno = !rbufno;
idatalen[rbufno] = 0;
(void) UART4->DR; // clear IDLE flag by reading DR (void) UART4->DR; // clear IDLE flag by reading DR
}else if(UART4->SR & USART_SR_RXNE){ // RX not emty - receive next char _485_Rx(); // receive next
uint8_t rb = UART4->DR; // clear RXNE flag }else if(UART4->SR & USART_SR_TC){ // TC - switch to Rx
if(idatalen[rbufno] < MODBUSBUFSZI){ // put next char into buf
rbuf[rbufno][idatalen[rbufno]++] = rb;
usart_send("485: "); usart_putchar(rb); newline();
}else{ // buffer overrun
bufovr = 1;
idatalen[rbufno] = 0;
}
}else if(UART4->SR & USART_SR_TC){
if(modbus_txrdy){ if(modbus_txrdy){
usart_send("->Rx\n");
_485_Rx(); _485_Rx();
} }
usart_send("485: TC\n");
UART4->SR &= ~USART_SR_TC; UART4->SR &= ~USART_SR_TC;
} }
} }
// Tx rdy
void dma2_channel4_5_isr(){ void dma2_channel4_5_isr(){
if(DMA2->ISR & DMA_ISR_TCIF5){ // Tx if(DMA2->ISR & DMA_ISR_TCIF5){ // Tx
DMA2->IFCR = DMA_IFCR_CTCIF5; // clear TC flag DMA2->IFCR = DMA_IFCR_CTCIF5; // clear TC flag
@ -270,3 +269,13 @@ void dma2_channel4_5_isr(){
} }
} }
// Rx full
void dma2_channel3_isr(){
if(DMA2->ISR & DMA_ISR_TCIF3){
DMA2_Channel3->CCR &= ~DMA_CCR_EN;
DMA2->IFCR = DMA_IFCR_CTCIF3;
bufovr = 1;
_485_Rx();
}
}

View File

@ -19,8 +19,8 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
// input and output buffers size // input and output buffers size: input buffer is greater as last symbol would be lost on Rx DMA IRQ
#define MODBUSBUFSZI (64) #define MODBUSBUFSZI (68)
#define MODBUSBUFSZO (64) #define MODBUSBUFSZO (64)
#define MODBUS_MASTER_ID (0) #define MODBUS_MASTER_ID (0)

View File

@ -27,6 +27,54 @@
#include "usart.h" #include "usart.h"
#include "version.inc" #include "version.inc"
// constants with commands and flags
static const char* S_adc = "adc";
static const char* S_bounce = "bounce";
static const char* S_canbuserr = "canbuserr";
static const char* S_canid = "canid";
static const char* S_canidin = "canidin";
static const char* S_canidout = "canidout";
static const char* S_cansniff = "cansniff";
static const char* S_canspeed = "canspeed";
static const char* S_dumpconf = "dumpconf";
static const char* S_eraseflash = "eraseflash";
static const char* S_esw = "esw";
static const char* S_eswnow = "eswnow";
static const char* S_flags = "flags";
static const char* S_inchannels = "inchannels";
static const char* S_led = "led";
static const char* S_mcutemp = "mcutemp";
static const char* S_modbusid = "modbusid";
static const char* S_modbusidout = "modbusidout";
static const char* S_modbus = "modbus";
static const char* S_modbusraw = "modbusraw";
static const char* S_modbusspeed = "modbusspeed";
static const char* S_outchannels = "outchannels";
static const char* S_relay = "relay";
static const char* S_reset = "reset";
static const char* S_saveconf = "saveconf";
static const char* S_s = "s";
static const char* S_time = "time";
static const char* S_usartspeed = "usartspeed";
static const char* S_wdtest = "wdtest";
// names of bit flags (ordered from LSE of[0])
static const char* S_f_relay_inverted = "f_relay_inverted";
static const char* S_f_send_esw_can = "f_send_esw_can";
static const char* S_f_send_relay_can = "f_send_relay_can";
static const char* S_f_send_relay_modbus = "f_send_relay_modbus";
// bitfield names should be in order of bit fields in confflags_t!
static const char ** const bitfields[] = {
&S_f_send_esw_can,
&S_f_send_relay_can,
&S_f_relay_inverted,
&S_f_send_relay_modbus,
NULL
};
// runtime flags
flags_t flags = { flags_t flags = {
0 0
}; };
@ -39,15 +87,20 @@ typedef enum{
TCMD_CANSEND, // send CAN message TCMD_CANSEND, // send CAN message
TCMD_CANSNIFFER, // sniff all CAN messages TCMD_CANSNIFFER, // sniff all CAN messages
TCMD_CANBUSERRPRNT, // pring all errors of bus TCMD_CANBUSERRPRNT, // pring all errors of bus
TCMD_SW_SEND_RELAY, // change of IN will send also command to change OUT TCMD_MODBUS_SEND, // send modbus request
TCMD_MODBUS_SEND, // send raw modbus data (CRC added auto) TCMD_MODBUS_SEND_RAW,// send raw modbus data (CRC added auto)
// change bit flags
TCMD_SW_SEND_CAN, // change of IN will send its current state over CAN
TCMD_SW_SEND_RCAN, // change of IN will send command to change OUT by CAN
TCMD_RELAY_INV, // inverted state between relay and inputs when send over CAN/MODBUS
TCMD_SW_SEND_RMODBUS,// modbus analog (if master)
TCMD_AMOUNT TCMD_AMOUNT
} text_cmd; } text_cmd;
typedef struct{ typedef struct{
const char *cmd; // command, if NULL - only display help message const char** const cmd; // command, if NULL - only display help message
int idx; // index in CAN cmd or text cmd list (if negative) int idx; // index in CAN cmd or text cmd list (if negative)
const char *help; // help message const char* const help; // help message
} funcdescr; } funcdescr;
// list of all text functions; should be sorted and can be grouped (`help` is header when cmd == NULL) // list of all text functions; should be sorted and can be grouped (`help` is header when cmd == NULL)
@ -57,37 +110,42 @@ static const funcdescr funclist[] = {
// {"adcv", CMD_ADCV, "get ADC voltage of channel 0..3 (*100V)"}, // {"adcv", CMD_ADCV, "get ADC voltage of channel 0..3 (*100V)"},
// {"bounce", CMD_BOUNCE, "get/set bounce constant (ms)"}, // {"bounce", CMD_BOUNCE, "get/set bounce constant (ms)"},
{NULL, 0, "CAN bus commands"}, {NULL, 0, "CAN bus commands"},
{"canbuserr", -TCMD_CANBUSERRPRNT, "print all CAN bus errors (a lot of if not connected)"}, {&S_canbuserr, -TCMD_CANBUSERRPRNT, "print all CAN bus errors (a lot of if not connected)"},
{"cansniff", -TCMD_CANSNIFFER, "switch CAN sniffer mode"}, {&S_cansniff, -TCMD_CANSNIFFER, "switch CAN sniffer mode"},
{"s", -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"}, {&S_s, -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"},
{NULL, 0, "Configuration"}, {NULL, 0, "Configuration"},
{"bounce", CMD_BOUNCE, "set/get anti-bounce timeout (ms, max: 1000)"}, {&S_bounce, CMD_BOUNCE, "set/get anti-bounce timeout (ms, max: 1000)"},
{"canid", CMD_CANID, "set both (in/out) CAN ID / get in CAN ID"}, {&S_canid, CMD_CANID, "set both (in/out) CAN ID / get in CAN ID"},
{"canidin", CMD_CANIDin, "get/set input CAN ID"}, {&S_canidin, CMD_CANIDin, "get/set input CAN ID"},
{"canidout", CMD_CANIDout, "get/set output CAN ID"}, {&S_canidout, CMD_CANIDout, "get/set output CAN ID"},
{"canspeed", CMD_CANSPEED, "get/set CAN speed (bps)"}, {&S_canspeed, CMD_CANSPEED, "get/set CAN speed (bps)"},
{"dumpconf", -TCMD_DUMPCONF, "dump current configuration"}, {&S_dumpconf, -TCMD_DUMPCONF, "dump current configuration"},
{"eraseflash", CMD_ERASESTOR, "erase all flash storage"}, {&S_eraseflash, CMD_ERASESTOR, "erase all flash storage"},
{"flags", CMD_FLAGS, "set/get configuration flags (as one U32 without parameter or Nth bit with)"}, {&S_f_relay_inverted, -TCMD_RELAY_INV, "inverted state between relay and inputs"},
{"modbusid", CMD_MODBUSID, "set/get modbus slave ID (1..247) or set it master (0)"}, {&S_f_send_esw_can, -TCMD_SW_SEND_CAN, "change of IN will send status over CAN with `canidin`"},
{"modbusspeed", CMD_MODBUSSPEED, "set/get modbus speed (1200..115200)"}, {&S_f_send_relay_can, -TCMD_SW_SEND_RCAN, "change of IN will send also CAN command to change OUT with `canidout`"},
{"saveconf", CMD_SAVECONF, "save configuration"}, {&S_f_send_relay_modbus, -TCMD_SW_SEND_RMODBUS, "change of IN will send also MODBUS command to change OUT with `modbusidout` (only for master!)"},
{"sw_send_relay", -TCMD_SW_SEND_RELAY, "change of IN will send also command to change OUT with `canidout`"}, {&S_flags, CMD_FLAGS, "set/get configuration flags (as one U32 without parameter or Nth bit with)"},
{"usartspeed", CMD_USARTSPEED, "get/set USART1 speed"}, {&S_modbusid, CMD_MODBUSID, "set/get modbus slave ID (1..247) or set it master (0)"},
{&S_modbusidout, CMD_MODBUSIDOUT, "set/get modbus slave ID (0..247) to send relay commands"},
{&S_modbusspeed, CMD_MODBUSSPEED, "set/get modbus speed (1200..115200)"},
{&S_saveconf, CMD_SAVECONF, "save configuration"},
{&S_usartspeed, CMD_USARTSPEED, "get/set USART1 speed"},
{NULL, 0, "IN/OUT"}, {NULL, 0, "IN/OUT"},
{"adc", CMD_ADCRAW, "get raw ADC values for given channel"}, {&S_adc, CMD_ADCRAW, "get raw ADC values for given channel"},
{"esw", CMD_GETESW, "anti-bounce read inputs"}, {&S_esw, CMD_GETESW, "anti-bounce read inputs"},
{"eswnow", CMD_GETESWNOW, "read current inputs' state"}, {&S_eswnow, CMD_GETESWNOW, "read current inputs' state"},
{"led", CMD_LED, "work with onboard LED"}, {&S_led, CMD_LED, "work with onboard LED"},
{"relay", CMD_RELAY, "get/set relay state (0 - off, 1 - on)"}, {&S_relay, CMD_RELAY, "get/set relay state (0 - off, 1 - on)"},
{NULL, 0, "Other commands"}, {NULL, 0, "Other commands"},
{"inchannels", CMD_INCHNLS, "get u32 with bits set on supported IN channels"}, {&S_inchannels, CMD_INCHNLS, "get u32 with bits set on supported IN channels"},
{"mcutemp", CMD_MCUTEMP, "get MCU temperature (*10degrC)"}, {&S_mcutemp, CMD_MCUTEMP, "get MCU temperature (*10degrC)"},
{"modbus", -TCMD_MODBUS_SEND, "send modbus request, format: slaveID Fcode startReg numRegs"}, {&S_modbus, -TCMD_MODBUS_SEND, "send modbus request with format \"slaveID fcode regaddr nregs [N data]\", to send zeros you can omit rest of 'data'"},
{"outchannels", CMD_OUTCHNLS, "get u32 with bits set on supported OUT channels"}, {&S_modbusraw, -TCMD_MODBUS_SEND_RAW, "send RAW modbus request (will send up to 62 bytes + calculated CRC)"},
{"reset", CMD_RESET, "reset MCU"}, {&S_outchannels, CMD_OUTCHNLS, "get u32 with bits set on supported OUT channels"},
{"time", CMD_TIME, "get/set time (1ms, 32bit)"}, {&S_reset, CMD_RESET, "reset MCU"},
{"wdtest", -TCMD_WDTEST, "test watchdog"}, {&S_time, CMD_TIME, "get/set time (1ms, 32bit)"},
{&S_wdtest, -TCMD_WDTEST, "test watchdog"},
{NULL, 0, NULL} // last record {NULL, 0, NULL} // last record
}; };
@ -98,12 +156,13 @@ static void printhelp(){
usart_send("parameter [CAN idx] - help\n"); usart_send("parameter [CAN idx] - help\n");
usart_send("--------------------------\n"); usart_send("--------------------------\n");
while(c->help){ while(c->help){
IWDG->KR = IWDG_REFRESH;
if(!c->cmd){ // header if(!c->cmd){ // header
usart_send("\n "); usart_send("\n ");
usart_send(c->help); usart_send(c->help);
usart_putchar(':'); usart_putchar(':');
}else{ }else{
usart_send(c->cmd); usart_send(*c->cmd);
if(c->idx > -1){ if(c->idx > -1){
usart_send(" ["); usart_send(" [");
usart_send(u2str(c->idx)); usart_send(u2str(c->idx));
@ -128,7 +187,7 @@ static errcodes cansnif(const char *str, text_cmd _U_ cmd){
CAN_sniffer((uint8_t)U); CAN_sniffer((uint8_t)U);
} }
} }
usart_send("cansniff="); usart_putchar('0' + flags.can_monitor); newline(); usart_send(S_cansniff); EQ(); usart_putchar('0' + flags.can_monitor); newline();
return ERR_OK; return ERR_OK;
} }
@ -141,7 +200,7 @@ static errcodes canbuserr(const char *str, text_cmd _U_ cmd){
flags.can_printoff = U; flags.can_printoff = U;
} }
} }
usart_send("canbuserr="); usart_putchar('0' + flags.can_printoff); newline(); usart_send(S_canbuserr); EQ(); usart_putchar('0' + flags.can_printoff); newline();
return ERR_OK; return ERR_OK;
} }
@ -152,11 +211,7 @@ static errcodes wdtest(const char _U_ *str, text_cmd _U_ cmd){
return ERR_OK; return ERR_OK;
} }
// names of bit flags (ordered from LSE of[0])
static const char * const bitfields[] = {
"sw_send_relay_cmd",
NULL
};
static errcodes dumpconf(const char _U_ *str, text_cmd _U_ cmd){ static errcodes dumpconf(const char _U_ *str, text_cmd _U_ cmd){
#ifdef EBUG #ifdef EBUG
@ -168,23 +223,21 @@ static errcodes dumpconf(const char _U_ *str, text_cmd _U_ cmd){
usart_send("userconf_addr="); printuhex((uint32_t)Flash_Data); usart_send("userconf_addr="); printuhex((uint32_t)Flash_Data);
usart_send("\nuserconf_idx="); printi(currentconfidx); usart_send("\nuserconf_idx="); printi(currentconfidx);
usart_send("\nuserconf_sz="); printu(the_conf.userconf_sz); usart_send("\nuserconf_sz="); printu(the_conf.userconf_sz);
usart_send("\ncanspeed="); printu(the_conf.CANspeed); newline(); usart_send(S_canspeed); EQ(); printu(the_conf.CANspeed);
usart_send("\ncanid_in="); printu(the_conf.CANIDin); newline(); usart_send(S_canidin); EQ(); printu(the_conf.CANIDin);
usart_send("\ncanid_out="); printu(the_conf.CANIDout); newline(); usart_send(S_canidout); EQ(); printu(the_conf.CANIDout);
/*for(int i = 0; i < ADC_TSENS; ++i){ newline(); usart_send(S_usartspeed); EQ(); printu(the_conf.usartspeed);
usart_send("\nadcmul"); usart_putchar('0'+i); usart_putchar('='); newline(); usart_send(S_modbusid); EQ(); printu(the_conf.modbusID);
usart_send(float2str(the_conf.adcmul[i], 3)); newline(); usart_send(S_modbusidout); EQ(); printu(the_conf.modbusIDout);
}*/ newline(); usart_send(S_modbusspeed); EQ(); printu(the_conf.modbusspeed);
usart_send("\nusartspeed="); printu(the_conf.usartspeed); newline(); usart_send(S_bounce); EQ(); printu(the_conf.bouncetime);
usart_send("\nmodbus_id="); printu(the_conf.modbusID); const char ** const *p = bitfields;
usart_send("\nmodbusspeed="); printu(the_conf.modbusspeed);
usart_send("\nbouncetime="); printu(the_conf.bouncetime);
const char * const *p = bitfields;
int bit = 0; int bit = 0;
usart_send("\nflags="); usart_putchar('='); printuhex(the_conf.flags.u32); newline(); usart_send(S_flags); printuhex(the_conf.flags.u32);
while(*p){ while(*p){
IWDG->KR = IWDG_REFRESH;
newline(); usart_putchar(' '); newline(); usart_putchar(' ');
usart_send(*p); usart_putchar('='); usart_putchar((the_conf.flags.u32 & (1<<bit)) ? '1' : '0'); usart_send(**p); EQ(); usart_putchar((the_conf.flags.u32 & (1<<bit)) ? '1' : '0');
if(++bit > MAX_FLAG_BITNO) break; if(++bit > MAX_FLAG_BITNO) break;
++p; ++p;
} }
@ -198,6 +251,7 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){
int ctr = -1; int ctr = -1;
canmsg.ID = 0xffff; canmsg.ID = 0xffff;
do{ do{
IWDG->KR = IWDG_REFRESH;
txt = omit_spaces(txt); txt = omit_spaces(txt);
uint32_t N; uint32_t N;
const char *n = getnum(txt, &N); const char *n = getnum(txt, &N);
@ -225,6 +279,7 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){
canmsg.length = (uint8_t) ctr; canmsg.length = (uint8_t) ctr;
uint32_t Tstart = Tms; uint32_t Tstart = Tms;
while(Tms - Tstart < SEND_TIMEOUT_MS){ while(Tms - Tstart < SEND_TIMEOUT_MS){
IWDG->KR = IWDG_REFRESH;
if(CAN_OK == CAN_send(&canmsg)){ if(CAN_OK == CAN_send(&canmsg)){
return ERR_OK; return ERR_OK;
} }
@ -234,13 +289,22 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){
// change configuration flags by one // change configuration flags by one
static errcodes confflags(const char _U_ *str, text_cmd cmd){ static errcodes confflags(const char _U_ *str, text_cmd cmd){
if(str){ if(str && *str){
if(*str == '=') str = omit_spaces(str + 1); if(*str == '=') str = omit_spaces(str + 1);
if(*str != '0' && *str != '1') return ERR_BADVAL; if(*str != '0' && *str != '1') return ERR_BADVAL;
uint8_t val = *str - '0'; uint8_t val = *str - '0';
switch(cmd){ switch(cmd){
case TCMD_SW_SEND_RELAY: case TCMD_SW_SEND_CAN:
the_conf.flags.sw_send_relay_cmd = val; the_conf.flags.sw_send_esw_can = val;
break;
case TCMD_SW_SEND_RCAN:
the_conf.flags.sw_send_relay_can = val;
break;
case TCMD_RELAY_INV:
the_conf.flags.sw_send_relay_inv = val;
break;
case TCMD_SW_SEND_RMODBUS:
the_conf.flags.sw_send_relay_modbus = val;
break; break;
default: default:
return ERR_BADCMD; return ERR_BADCMD;
@ -248,21 +312,35 @@ static errcodes confflags(const char _U_ *str, text_cmd cmd){
} }
uint8_t val = 0, idx = 0; uint8_t val = 0, idx = 0;
switch(cmd){ switch(cmd){
case TCMD_SW_SEND_RELAY: case TCMD_SW_SEND_CAN:
val = the_conf.flags.sw_send_relay_cmd; val = the_conf.flags.sw_send_esw_can;
idx = 0; idx = 0;
break; break;
case TCMD_SW_SEND_RCAN:
val = the_conf.flags.sw_send_relay_can;
idx = 1;
break;
case TCMD_RELAY_INV:
val = the_conf.flags.sw_send_relay_inv;
idx = 2;
break;
case TCMD_SW_SEND_RMODBUS:
val = the_conf.flags.sw_send_relay_modbus;
idx = 3;
break;
default: default:
return ERR_BADCMD; return ERR_BADCMD;
} }
usart_send(bitfields[idx]); usart_putchar('='); usart_putchar('0' + val); usart_send(*bitfields[idx]); EQ(); usart_putchar('0' + val);
newline(); newline();
return ERR_OK; return ERR_OK;
} }
// format: slaveID Fcode startReg numRegs // format: slaveID Fcode startReg numRegs [N data];
// to send zeros you can omit rest of 'data'
static errcodes modbussend(const char *txt, text_cmd _U_ cmd){ static errcodes modbussend(const char *txt, text_cmd _U_ cmd){
modbus_request req = {0}; modbus_request req = {0};
uint8_t reqdata[MODBUSBUFSZO - 7] = {0};
uint32_t N = 0; uint32_t N = 0;
const char *n = getnum(txt, &N); const char *n = getnum(txt, &N);
if(n == txt || N > MODBUS_MAX_ID){ if(n == txt || N > MODBUS_MAX_ID){
@ -283,15 +361,53 @@ static errcodes modbussend(const char *txt, text_cmd _U_ cmd){
} }
req.startreg = N; req.startreg = N;
txt = n; n = getnum(txt, &N); txt = n; n = getnum(txt, &N);
if(n == txt || N == 0){ if(n == txt){
usart_send("Need registers amount\n"); usart_send("Need registers amount or data bytes\n");
return ERR_WRONGLEN; return ERR_WRONGLEN;
} }
req.regno = N; req.regno = N;
txt = n; n = getnum(txt, &N);
if((req.Fcode == MC_WRITE_MUL_COILS || req.Fcode == MC_WRITE_MUL_REGS)){ // request with data
if(txt == n){
usart_send("Need amount of data for given fcode\n");
return ERR_WRONGLEN;
}
if(N == 0 || N > MODBUSBUFSZO - 7){
usart_send("Data length too big\n");
return ERR_BADVAL;
}
req.datalen = N;
for(int i = 0; i < req.datalen; ++i){
txt = n; n = getnum(txt, &N);
if(txt == n) break;
reqdata[i] = N;
}
req.data = reqdata;
}else if(n != txt){
usart_send("multiple data allows only for fcode 0x0f and 0x10; ignore other data\n");
}
if(modbus_send_request(&req) < 1) return ERR_CANTRUN; if(modbus_send_request(&req) < 1) return ERR_CANTRUN;
return ERR_OK; return ERR_OK;
} }
// raw data format
static errcodes modbussendraw(const char *txt, text_cmd _U_ cmd){
uint32_t N = 0;
uint8_t reqdata[MODBUSBUFSZO], datalen = 0;
for(; datalen < MODBUSBUFSZO; ++datalen){
const char *n = getnum(txt, &N);
if(n == txt) break;
reqdata[datalen] = N;
txt = n;
}
if(datalen == 0){
usart_send("Need data bytes\n");
return ERR_WRONGLEN;
}
if(modbus_send(reqdata, datalen) != datalen) return ERR_CANTRUN;
return ERR_OK;
}
/************ END of all text functions list ************/ /************ END of all text functions list ************/
// in `textfn` arg `str` is the rest of input string (spaces-omitted) after command // in `textfn` arg `str` is the rest of input string (spaces-omitted) after command
@ -303,8 +419,12 @@ static textfn textfunctions[TCMD_AMOUNT] = {
[TCMD_CANSEND] = cansend, [TCMD_CANSEND] = cansend,
[TCMD_CANSNIFFER] = cansnif, [TCMD_CANSNIFFER] = cansnif,
[TCMD_CANBUSERRPRNT] = canbuserr, [TCMD_CANBUSERRPRNT] = canbuserr,
[TCMD_SW_SEND_RELAY] = confflags,
[TCMD_MODBUS_SEND] = modbussend, [TCMD_MODBUS_SEND] = modbussend,
[TCMD_MODBUS_SEND_RAW] = modbussendraw,
[TCMD_SW_SEND_CAN] = confflags,
[TCMD_SW_SEND_RCAN] = confflags,
[TCMD_RELAY_INV] = confflags,
[TCMD_SW_SEND_RMODBUS] = confflags,
}; };
static const char* const errors_txt[ERR_AMOUNT] = { static const char* const errors_txt[ERR_AMOUNT] = {
@ -339,7 +459,8 @@ void cmd_parser(const char *str){
if(l == 0) goto ret; if(l == 0) goto ret;
cmd[l] = 0; cmd[l] = 0;
while(c->help){ while(c->help){
if(c->cmd && 0 == strcmp(c->cmd, cmd)){ IWDG->KR = IWDG_REFRESH;
if(c->cmd && 0 == strcmp(*c->cmd, cmd)){
idx = c->idx; idx = c->idx;
break; break;
} }

View File

@ -21,7 +21,7 @@
#include <stm32f1.h> #include <stm32f1.h>
#include "hardware.h" #include "hardware.h"
#define MAXCMDLEN (12) #define MAXCMDLEN (32)
// flags for some RS-232 comands // flags for some RS-232 comands
typedef struct{ typedef struct{
@ -33,3 +33,4 @@ extern flags_t flags;
void cmd_parser(const char *txt); void cmd_parser(const char *txt);

View File

@ -64,8 +64,6 @@ static char *_2str(uint32_t val, uint8_t minus){
uint32_t x = val / 10; uint32_t x = val / 10;
*(--bufptr) = (val - 10*x) + '0'; *(--bufptr) = (val - 10*x) + '0';
val = x; val = x;
//*(--bufptr) = val % 10 + '0';
//val /= 10;
} }
} }
if(minus) *(--bufptr) = '-'; if(minus) *(--bufptr) = '-';

View File

@ -43,6 +43,7 @@ const char *getnum(const char *txt, uint32_t *N);
const char *omit_spaces(const char *buf); const char *omit_spaces(const char *buf);
const char *getint(const char *txt, int32_t *I); const char *getint(const char *txt, int32_t *I);
#define EQ() do{usart_putchar('=');}while(0)
#define newline() do{usart_putchar('\n');}while(0) #define newline() do{usart_putchar('\n');}while(0)
#define printu(a) do{usart_send(u2str(a));}while(0) #define printu(a) do{usart_send(u2str(a));}while(0)
#define printi(a) do{usart_send(i2str(a));}while(0) #define printi(a) do{usart_send(i2str(a));}while(0)

View File

@ -56,18 +56,18 @@ int usart_getline(char **line){
int usart_transmit(){ int usart_transmit(){
register int l = odatalen[tbufno]; register int l = odatalen[tbufno];
if(!l) return 0; if(!l) return 0;
uint32_t tmout = 1600000; uint32_t tmout = 18000000;
while(!usart_txrdy){ while(!usart_txrdy){
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) return 0; if(--tmout == 0) return 0;
}; // wait for previos buffer transmission }; // wait for previos buffer transmission
usart_txrdy = 0; usart_txrdy = 0;
odatalen[tbufno] = 0;
DMA1_Channel4->CCR &= ~DMA_CCR_EN; DMA1_Channel4->CCR &= ~DMA_CCR_EN;
DMA1_Channel4->CMAR = (uint32_t) tbuf[tbufno]; // mem DMA1_Channel4->CMAR = (uint32_t) tbuf[tbufno]; // mem
DMA1_Channel4->CNDTR = l; DMA1_Channel4->CNDTR = l;
DMA1_Channel4->CCR |= DMA_CCR_EN; DMA1_Channel4->CCR |= DMA_CCR_EN;
tbufno = !tbufno; tbufno = !tbufno;
odatalen[tbufno] = 0;
return l; return l;
} }
@ -82,6 +82,7 @@ int usart_putchar(const char ch){
int usart_send(const char *str){ int usart_send(const char *str){
int l = 0; int l = 0;
while(*str){ while(*str){
IWDG->KR = IWDG_REFRESH;
if(odatalen[tbufno] == UARTBUFSZO){ if(odatalen[tbufno] == UARTBUFSZO){
if(!usart_transmit()) return 0; if(!usart_transmit()) return 0;
} }
@ -100,7 +101,6 @@ int usart_send(const char *str){
*/ */
void usart_setup(uint32_t speed){ void usart_setup(uint32_t speed){
uint32_t tmout = 16000000;
// PA9 - Tx, PA10 - Rx // PA9 - Tx, PA10 - Rx
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->AHBENR |= RCC_AHBENR_DMA1EN; RCC->AHBENR |= RCC_AHBENR_DMA1EN;
@ -116,7 +116,11 @@ void usart_setup(uint32_t speed){
// setup usart1 // setup usart1
USART1->BRR = 72000000 / speed; USART1->BRR = 72000000 / speed;
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission uint32_t tmout = 16000000;
while(!(USART1->SR & USART_SR_TC)){
IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) break;
} // polling idle frame Transmission
USART1->SR = 0; // clear flags USART1->SR = 0; // clear flags
USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx

View File

@ -21,8 +21,8 @@
#include <stdint.h> #include <stdint.h>
// input and output buffers size // input and output buffers size
#define UARTBUFSZI (64) #define UARTBUFSZI (196)
#define UARTBUFSZO (128) #define UARTBUFSZO (256)
#define usartrx() (usart_linerdy) #define usartrx() (usart_linerdy)
#define usartovr() (usart_bufovr) #define usartovr() (usart_bufovr)

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "85" #define BUILD_NUMBER "105"
#define BUILD_DATE "2024-09-24" #define BUILD_DATE "2024-09-26"