mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 10:45:11 +03:00
almost ready but have IWDG reset when trying to send data over RS-232 in CANbus flooding
This commit is contained in:
parent
03772fce3a
commit
b9942f2e9f
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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");
|
||||||
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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){
|
||||||
|
|||||||
@ -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.
@ -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){
|
||||||
MSG_SET_CMD(msg, CMD_GETESW);
|
CAN_message msg = {.ID = the_conf.CANIDin, .length = 8, .data = {0}};
|
||||||
MSG_SET_U32(msg, ESW_ab_values);
|
MSG_SET_CMD(msg, CMD_GETESW);
|
||||||
uint32_t Tstart = Tms;
|
MSG_SET_U32(msg, ESW_ab_values);
|
||||||
while(Tms - Tstart < SEND_TIMEOUT_MS){
|
uint32_t Tstart = Tms;
|
||||||
if(CAN_OK == CAN_send(&msg)) break;
|
|
||||||
}
|
|
||||||
if(the_conf.flags.sw_send_relay_cmd){ // send also CMD_RELAY
|
|
||||||
MSG_SET_CMD(msg, CMD_RELAY);
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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_PARNO(msg, SETTER_FLAG | NO_PARNO);
|
||||||
|
uint32_t Tstart = Tms;
|
||||||
|
while(Tms - Tstart < SEND_TIMEOUT_MS){
|
||||||
|
IWDG->KR = IWDG_REFRESH;
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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,12 +419,16 @@ 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] = {
|
||||||
[ERR_OK] = "OK"
|
[ERR_OK] = "OK"
|
||||||
,[ERR_BADPAR] = "badpar"
|
,[ERR_BADPAR] = "badpar"
|
||||||
,[ERR_BADVAL] = "badval"
|
,[ERR_BADVAL] = "badval"
|
||||||
,[ERR_WRONGLEN] = "wronglen"
|
,[ERR_WRONGLEN] = "wronglen"
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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) = '-';
|
||||||
@ -257,8 +255,8 @@ const char *getint(const char *txt, int32_t *I){
|
|||||||
int32_t sign = 1;
|
int32_t sign = 1;
|
||||||
uint32_t U;
|
uint32_t U;
|
||||||
if(*s == '-'){
|
if(*s == '-'){
|
||||||
sign = -1;
|
sign = -1;
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
const char *nxt = getnum(s, &U);
|
const char *nxt = getnum(s, &U);
|
||||||
if(nxt == s) return txt;
|
if(nxt == s) return txt;
|
||||||
|
|||||||
@ -43,7 +43,8 @@ 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 newline() do{usart_putchar('\n');}while(0)
|
#define EQ() do{usart_putchar('=');}while(0)
|
||||||
#define printu(a) do{usart_send(u2str(a));}while(0)
|
#define newline() do{usart_putchar('\n');}while(0)
|
||||||
#define printi(a) do{usart_send(i2str(a));}while(0)
|
#define printu(a) do{usart_send(u2str(a));}while(0)
|
||||||
|
#define printi(a) do{usart_send(i2str(a));}while(0)
|
||||||
#define printuhex(a) do{usart_send(uhex2str(a));}while(0)
|
#define printuhex(a) do{usart_send(uhex2str(a));}while(0)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "85"
|
#define BUILD_NUMBER "105"
|
||||||
#define BUILD_DATE "2024-09-24"
|
#define BUILD_DATE "2024-09-26"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user