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;
|
||||
__DSB();
|
||||
// wait for Tstab - at least 1us
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
while(++ctr < 0xff) nop();
|
||||
// calibration
|
||||
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;
|
||||
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
|
||||
ADC1->SR = 0;
|
||||
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);
|
||||
|
||||
CAN_status CAN_get_status(){
|
||||
int st = can_status;
|
||||
can_status = CAN_OK;
|
||||
return st;
|
||||
return can_status;
|
||||
}
|
||||
|
||||
// push next message into buffer; return 1 if buffer overfull
|
||||
@ -141,8 +139,10 @@ void CAN_setup(uint32_t speed){
|
||||
/* (12) Leave filter init */
|
||||
/* (13) Set error interrupts enable (& bus off) */
|
||||
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;
|
||||
}
|
||||
CAN1->MCR &=~ CAN_MCR_SLEEP; /* (3) */
|
||||
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) */
|
||||
@ -152,8 +152,10 @@ void CAN_setup(uint32_t speed){
|
||||
#endif
|
||||
CAN1->MCR &= ~CAN_MCR_INRQ; /* (5) */
|
||||
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;
|
||||
}
|
||||
// accept depending of monitor flag
|
||||
CAN1->FMR = CAN_FMR_FINIT; /* (7) */
|
||||
CAN1->FA1R = CAN_FA1R_FACT0; /* (8) */
|
||||
@ -218,6 +220,22 @@ void CAN_printerr(){
|
||||
}
|
||||
|
||||
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
|
||||
if(CAN1->RF0R & CAN_RF0R_FMP0){
|
||||
can_process_fifo(0);
|
||||
@ -225,14 +243,6 @@ void CAN_proc(){
|
||||
if(CAN1->RF1R & CAN_RF1R_FMP1){
|
||||
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){
|
||||
@ -290,28 +300,6 @@ CAN_status CAN_send(CAN_message *message){
|
||||
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){
|
||||
if(fifo_num > 1) return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// run command for my or broadcast ID
|
||||
if(msg.ID == the_conf.CANIDin || msg.ID == 0) parseCANcommand(&msg);
|
||||
if(flags.can_monitor && CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later
|
||||
*RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message
|
||||
}
|
||||
//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
|
||||
CAN1->RF0R &= ~CAN_RF0R_FOVR0;
|
||||
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){
|
||||
CAN1->RF1R &= ~CAN_RF1R_FOVR1;
|
||||
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_TERR2) CAN1->TSR |= CAN_TSR_ABRQ2;
|
||||
can_status = CAN_ERR;
|
||||
RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,8 +27,7 @@
|
||||
#define FIXDL(m) do{m->length = 8;}while(0)
|
||||
|
||||
/*********** START of all common functions list (for `funclist`) ***********/
|
||||
static errcodes ping(CAN_message *m){
|
||||
m->ID = the_conf.CANIDout; // change ID
|
||||
static errcodes ping(CAN_message _U_ *m){
|
||||
return ERR_OK; // send same message
|
||||
}
|
||||
// reset MCU
|
||||
@ -163,6 +162,7 @@ static errcodes u32setget(CAN_message *msg){
|
||||
case CMD_INCHNLS: val = inchannels(); ptr = &val; break;
|
||||
case CMD_OUTCHNLS: val = outchannels(); ptr = &val; 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;
|
||||
default: break;
|
||||
}
|
||||
@ -230,6 +230,7 @@ static const commonfunction funclist[CMD_AMOUNT] = {
|
||||
[CMD_INCHNLS] = {u32setget, 0, 0, 0},
|
||||
[CMD_OUTCHNLS] = {u32setget, 0, 0, 0},
|
||||
[CMD_MODBUSID] = {u32setget, 0, MODBUS_MAX_ID, 0}, // 0 - master!
|
||||
[CMD_MODBUSIDOUT] = {u32setget, 0, MODBUS_MAX_ID, 0},
|
||||
[CMD_MODBUSSPEED] = {u32setget, 1200, 115200, 0},
|
||||
};
|
||||
|
||||
@ -288,3 +289,25 @@ void run_can_cmd(CAN_message *msg){
|
||||
newline();
|
||||
#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
|
||||
#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)
|
||||
// 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
|
||||
#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)
|
||||
@ -75,15 +78,17 @@ enum{
|
||||
CMD_GETESW, // current ESW state, bounce-free
|
||||
CMD_GETESWNOW, // current ESW state, absolute
|
||||
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_FLAGS, // flags setter/getter
|
||||
CMD_INCHNLS, // all bits set are active supported IN channels
|
||||
CMD_OUTCHNLS, // all bits set are active supported OUT channels
|
||||
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
|
||||
// should be the last:
|
||||
CMD_AMOUNT // amount of CAN commands
|
||||
};
|
||||
|
||||
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 \
|
||||
,.usartspeed = 115200 \
|
||||
,.bouncetime = 50 \
|
||||
,.modbusID = MODBUS_MASTER_ID \
|
||||
,.modbusID = 1 \
|
||||
,.modbusIDout = 2 \
|
||||
,.modbusspeed = 9600 \
|
||||
,.flags.sw_send_relay_inv = 1 \
|
||||
}
|
||||
|
||||
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){
|
||||
int l = 0;
|
||||
while(r >= l){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
int mid = l + (r - l) / 2;
|
||||
const uint8_t *s = start + mid * stor_size;
|
||||
if(*((const uint16_t*)s) == stor_size){
|
||||
|
||||
@ -23,15 +23,21 @@
|
||||
#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0)
|
||||
#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG)
|
||||
|
||||
// maximal bit number of flags
|
||||
#define MAX_FLAG_BITNO (0)
|
||||
// maximal bit NUMBER (0 etc) of flags
|
||||
#define MAX_FLAG_BITNO (3)
|
||||
typedef union{
|
||||
uint32_t u32;
|
||||
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;
|
||||
|
||||
// ALL sw_send flags mask (without relay_inv)
|
||||
#define SW_SEND_MASK (0x0B)
|
||||
|
||||
/*
|
||||
* struct to save user configurations
|
||||
*/
|
||||
@ -45,6 +51,7 @@ typedef struct __attribute__((aligned(4))){
|
||||
uint32_t CANspeed; // CAN bus speed
|
||||
confflags_t flags; // different flags
|
||||
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
|
||||
} user_conf;
|
||||
|
||||
|
||||
Binary file not shown.
@ -20,6 +20,7 @@
|
||||
#include "canproto.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
#include "modbusrtu.h"
|
||||
/*
|
||||
#ifdef EBUG
|
||||
#include "strfunc.h"
|
||||
@ -116,14 +117,16 @@ void gpio_setup(void){
|
||||
void iwdg_setup(){
|
||||
uint32_t tmout = 16000000;
|
||||
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_WRITE_ACCESS;
|
||||
IWDG->PR = IWDG_PR_PR_1;
|
||||
IWDG->RLR = 1250;
|
||||
tmout = 16000000;
|
||||
while(IWDG->SR){if(--tmout == 0) break;}
|
||||
while(IWDG->SR){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(--tmout == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct{
|
||||
@ -263,22 +266,46 @@ void proc_esw(){
|
||||
else ESW_ab_values &= ~mask;
|
||||
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();
|
||||
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_U32(msg, ESW_ab_values);
|
||||
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_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);
|
||||
Tstart = Tms;
|
||||
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 "can.h"
|
||||
#include "canproto.h"
|
||||
#include "flash.h"
|
||||
#include "hardware.h"
|
||||
#include "modbusproto.h"
|
||||
@ -48,7 +49,6 @@ int main(void){
|
||||
uint32_t lastT = 0;
|
||||
CAN_message *can_mesg;
|
||||
StartHSE();
|
||||
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
|
||||
SysTick_Config(72000);
|
||||
flashstorage_init();
|
||||
gpio_setup(); // should be run before other peripherial setup
|
||||
@ -61,6 +61,19 @@ int main(void){
|
||||
iwdg_setup();
|
||||
#endif
|
||||
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){
|
||||
IWDG->KR = IWDG_REFRESH; // refresh watchdog
|
||||
if(Tms - lastT > 499){ // throw out short messages twice per second
|
||||
@ -69,15 +82,12 @@ int main(void){
|
||||
}
|
||||
proc_esw();
|
||||
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())){
|
||||
DBG("got CAN message\n");
|
||||
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){
|
||||
lastT = Tms;
|
||||
if(!lastT) lastT = 1;
|
||||
|
||||
@ -68,13 +68,12 @@ TRUE_INLINE void readdiscr(modbus_request *r){
|
||||
return;
|
||||
}
|
||||
uint8_t bytes[INMAXBYTES] = {0};
|
||||
int curidx = INMAXBYTES - 1;
|
||||
int vals = get_esw(INMAX+1);
|
||||
for(int i = 0; i < amount; ++i){
|
||||
bytes[--curidx] = vals & 0xff;
|
||||
for(int i = amount - 1; i > -1; --i){
|
||||
bytes[i] = vals & 0xff;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -122,7 +121,7 @@ TRUE_INLINE void readadc(modbus_request *r){
|
||||
uint16_t vals[ADC_CHANNELS];
|
||||
for(int i = r->startreg; i < nlast; ++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_send_response(&resp);
|
||||
@ -155,20 +154,21 @@ TRUE_INLINE void writereg(modbus_request *r){
|
||||
|
||||
// support ONLY write to ALL!
|
||||
// data - by bits, like in readcoil
|
||||
// N registers is N bits
|
||||
TRUE_INLINE void writecoils(modbus_request *r){
|
||||
if(r->startreg){
|
||||
senderr(r, ME_ILLEGAL_ADDRESS);
|
||||
return;
|
||||
}
|
||||
int amount = r->regno;
|
||||
if(amount == 0 || amount > OUTMAX || r->datalen > 4){
|
||||
int amount = (r->regno + 7) >> 3;
|
||||
if(amount == 0 || amount > OUTMAXBYTES || r->datalen < amount){
|
||||
senderr(r, ME_ILLEGAL_VALUE);
|
||||
return;
|
||||
}
|
||||
uint32_t v = 0;
|
||||
for(int i = 0; i < amount; ++i){
|
||||
v |= r->data[i];
|
||||
v <<= 8;
|
||||
v |= r->data[i];
|
||||
}
|
||||
if(set_relay(OUTMAX+1, v) < 0){
|
||||
senderr(r, ME_NACK);
|
||||
|
||||
@ -39,11 +39,12 @@ static void us(){
|
||||
}*/
|
||||
|
||||
// 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_Tx() do{LED(0); RS485_TX(); /*UART4->CR1 = (UART4->CR1 & ~USART_CR1_RE) | USART_CR1_TE;*/}while(0)
|
||||
#define _485_Rx() do{ DMA2_Channel5->CCR &= ~DMA_CCR_EN; RS485_RX(); \
|
||||
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 idatalen[2] = {0,0}; // received data line length (including '\n')
|
||||
|
||||
static volatile int modbus_rdy = 0 // received data ready
|
||||
,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;
|
||||
}
|
||||
}
|
||||
/*
|
||||
#ifdef EBUG
|
||||
DBG("Calc CRC: "); printuhex(crc); newline();
|
||||
#endif
|
||||
*/
|
||||
// CRC have swapped bytes, so we can just send it as *((uint16_t*)&data[x]) = CRC
|
||||
return crc;
|
||||
}
|
||||
@ -105,13 +108,13 @@ static int senddata(int l){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(--tmout == 0) return 0;
|
||||
}; // wait for previos buffer transmission
|
||||
_485_Tx();
|
||||
modbus_txrdy = 0;
|
||||
DMA2_Channel5->CCR &= ~DMA_CCR_EN;
|
||||
DMA2_Channel5->CMAR = (uint32_t) tbuf[tbufno]; // mem
|
||||
DMA2_Channel5->CNDTR = l + 2; // + CRC
|
||||
DMA2_Channel5->CCR |= DMA_CCR_EN;
|
||||
tbufno = !tbufno;
|
||||
_485_Tx();
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -133,12 +136,13 @@ int modbus_send_request(modbus_request *r){
|
||||
*curbuf++ = r->startreg >> 8; // H
|
||||
*curbuf++ = (uint8_t) r->startreg; // L
|
||||
*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->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);
|
||||
n += r->datalen;
|
||||
n += r->datalen + 1; // + data length byte
|
||||
}
|
||||
packCRC(tbuf[tbufno], n) = getCRC(tbuf[tbufno], n);
|
||||
return senddata(n);
|
||||
@ -207,62 +211,57 @@ int modbus_get_response(modbus_response* r){
|
||||
|
||||
// USART4: PC10 - Tx, PC11 - Rx
|
||||
void modbus_setup(uint32_t speed){
|
||||
uint32_t tmout = 16000000;
|
||||
// PC10 - Tx, PC11 - Rx
|
||||
RCC->APB1ENR |= RCC_APB1ENR_UART4EN;
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA2EN;
|
||||
GPIOC->CRH = (GPIOC->CRH & ~(CRH(10,0xf)|CRH(11,0xf))) |
|
||||
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->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
|
||||
NVIC_SetPriority(DMA2_Channel4_5_IRQn, 2);
|
||||
NVIC_EnableIRQ(DMA2_Channel4_5_IRQn);
|
||||
NVIC_SetPriority(UART4_IRQn, 2);
|
||||
NVIC_SetPriority(DMA2_Channel3_IRQn, 2);
|
||||
NVIC_EnableIRQ(DMA2_Channel3_IRQn);
|
||||
// setup uart4
|
||||
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
|
||||
uint32_t tmout = 16000000;
|
||||
while(!(UART4->SR & USART_SR_TC)){ // polling idle frame Transmission
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(--tmout == 0) break;
|
||||
}
|
||||
(void) UART4->DR; // clear IDLE etc
|
||||
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->CR3 = USART_CR3_DMAT; // enable DMA Tx
|
||||
UART4->CR1 |= USART_CR1_IDLEIE | USART_CR1_TCIE; // allow IDLE IRQ; TC IRQ for switching to Rx
|
||||
UART4->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; // enable DMA Tx & Rx
|
||||
NVIC_SetPriority(UART4_IRQn, 2);
|
||||
NVIC_EnableIRQ(UART4_IRQn);
|
||||
_485_Rx();
|
||||
}
|
||||
|
||||
void uart4_isr(){
|
||||
if(UART4->SR & USART_SR_IDLE){ // idle - end of frame
|
||||
usart_send("485: IDLE\n");
|
||||
DMA2_Channel3->CCR &= ~DMA_CCR_EN;
|
||||
modbus_rdy = 1;
|
||||
dlen = idatalen[rbufno];
|
||||
dlen = MODBUSBUFSZI - DMA2_Channel3->CNDTR;
|
||||
recvdata = rbuf[rbufno];
|
||||
// prepare other buffer
|
||||
rbufno = !rbufno;
|
||||
idatalen[rbufno] = 0;
|
||||
(void) UART4->DR; // clear IDLE flag by reading DR
|
||||
}else if(UART4->SR & USART_SR_RXNE){ // RX not emty - receive next char
|
||||
uint8_t rb = UART4->DR; // clear RXNE flag
|
||||
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){
|
||||
_485_Rx(); // receive next
|
||||
}else if(UART4->SR & USART_SR_TC){ // TC - switch to Rx
|
||||
if(modbus_txrdy){
|
||||
usart_send("->Rx\n");
|
||||
_485_Rx();
|
||||
}
|
||||
usart_send("485: TC\n");
|
||||
UART4->SR &= ~USART_SR_TC;
|
||||
}
|
||||
}
|
||||
|
||||
// Tx rdy
|
||||
void dma2_channel4_5_isr(){
|
||||
if(DMA2->ISR & DMA_ISR_TCIF5){ // Tx
|
||||
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
|
||||
#include <stdint.h>
|
||||
|
||||
// input and output buffers size
|
||||
#define MODBUSBUFSZI (64)
|
||||
// input and output buffers size: input buffer is greater as last symbol would be lost on Rx DMA IRQ
|
||||
#define MODBUSBUFSZI (68)
|
||||
#define MODBUSBUFSZO (64)
|
||||
|
||||
#define MODBUS_MASTER_ID (0)
|
||||
|
||||
@ -27,6 +27,54 @@
|
||||
#include "usart.h"
|
||||
#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 = {
|
||||
0
|
||||
};
|
||||
@ -39,15 +87,20 @@ typedef enum{
|
||||
TCMD_CANSEND, // send CAN message
|
||||
TCMD_CANSNIFFER, // sniff all CAN messages
|
||||
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 raw modbus data (CRC added auto)
|
||||
TCMD_MODBUS_SEND, // send modbus request
|
||||
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
|
||||
} text_cmd;
|
||||
|
||||
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)
|
||||
const char *help; // help message
|
||||
const char* const help; // help message
|
||||
} funcdescr;
|
||||
|
||||
// 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)"},
|
||||
// {"bounce", CMD_BOUNCE, "get/set bounce constant (ms)"},
|
||||
{NULL, 0, "CAN bus commands"},
|
||||
{"canbuserr", -TCMD_CANBUSERRPRNT, "print all CAN bus errors (a lot of if not connected)"},
|
||||
{"cansniff", -TCMD_CANSNIFFER, "switch CAN sniffer mode"},
|
||||
{"s", -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"},
|
||||
{&S_canbuserr, -TCMD_CANBUSERRPRNT, "print all CAN bus errors (a lot of if not connected)"},
|
||||
{&S_cansniff, -TCMD_CANSNIFFER, "switch CAN sniffer mode"},
|
||||
{&S_s, -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"},
|
||||
{NULL, 0, "Configuration"},
|
||||
{"bounce", CMD_BOUNCE, "set/get anti-bounce timeout (ms, max: 1000)"},
|
||||
{"canid", CMD_CANID, "set both (in/out) CAN ID / get in CAN ID"},
|
||||
{"canidin", CMD_CANIDin, "get/set input CAN ID"},
|
||||
{"canidout", CMD_CANIDout, "get/set output CAN ID"},
|
||||
{"canspeed", CMD_CANSPEED, "get/set CAN speed (bps)"},
|
||||
{"dumpconf", -TCMD_DUMPCONF, "dump current configuration"},
|
||||
{"eraseflash", CMD_ERASESTOR, "erase all flash storage"},
|
||||
{"flags", CMD_FLAGS, "set/get configuration flags (as one U32 without parameter or Nth bit with)"},
|
||||
{"modbusid", CMD_MODBUSID, "set/get modbus slave ID (1..247) or set it master (0)"},
|
||||
{"modbusspeed", CMD_MODBUSSPEED, "set/get modbus speed (1200..115200)"},
|
||||
{"saveconf", CMD_SAVECONF, "save configuration"},
|
||||
{"sw_send_relay", -TCMD_SW_SEND_RELAY, "change of IN will send also command to change OUT with `canidout`"},
|
||||
{"usartspeed", CMD_USARTSPEED, "get/set USART1 speed"},
|
||||
{&S_bounce, CMD_BOUNCE, "set/get anti-bounce timeout (ms, max: 1000)"},
|
||||
{&S_canid, CMD_CANID, "set both (in/out) CAN ID / get in CAN ID"},
|
||||
{&S_canidin, CMD_CANIDin, "get/set input CAN ID"},
|
||||
{&S_canidout, CMD_CANIDout, "get/set output CAN ID"},
|
||||
{&S_canspeed, CMD_CANSPEED, "get/set CAN speed (bps)"},
|
||||
{&S_dumpconf, -TCMD_DUMPCONF, "dump current configuration"},
|
||||
{&S_eraseflash, CMD_ERASESTOR, "erase all flash storage"},
|
||||
{&S_f_relay_inverted, -TCMD_RELAY_INV, "inverted state between relay and inputs"},
|
||||
{&S_f_send_esw_can, -TCMD_SW_SEND_CAN, "change of IN will send status over CAN with `canidin`"},
|
||||
{&S_f_send_relay_can, -TCMD_SW_SEND_RCAN, "change of IN will send also CAN command to change OUT with `canidout`"},
|
||||
{&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!)"},
|
||||
{&S_flags, CMD_FLAGS, "set/get configuration flags (as one U32 without parameter or Nth bit with)"},
|
||||
{&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"},
|
||||
{"adc", CMD_ADCRAW, "get raw ADC values for given channel"},
|
||||
{"esw", CMD_GETESW, "anti-bounce read inputs"},
|
||||
{"eswnow", CMD_GETESWNOW, "read current inputs' state"},
|
||||
{"led", CMD_LED, "work with onboard LED"},
|
||||
{"relay", CMD_RELAY, "get/set relay state (0 - off, 1 - on)"},
|
||||
{&S_adc, CMD_ADCRAW, "get raw ADC values for given channel"},
|
||||
{&S_esw, CMD_GETESW, "anti-bounce read inputs"},
|
||||
{&S_eswnow, CMD_GETESWNOW, "read current inputs' state"},
|
||||
{&S_led, CMD_LED, "work with onboard LED"},
|
||||
{&S_relay, CMD_RELAY, "get/set relay state (0 - off, 1 - on)"},
|
||||
{NULL, 0, "Other commands"},
|
||||
{"inchannels", CMD_INCHNLS, "get u32 with bits set on supported IN channels"},
|
||||
{"mcutemp", CMD_MCUTEMP, "get MCU temperature (*10degrC)"},
|
||||
{"modbus", -TCMD_MODBUS_SEND, "send modbus request, format: slaveID Fcode startReg numRegs"},
|
||||
{"outchannels", CMD_OUTCHNLS, "get u32 with bits set on supported OUT channels"},
|
||||
{"reset", CMD_RESET, "reset MCU"},
|
||||
{"time", CMD_TIME, "get/set time (1ms, 32bit)"},
|
||||
{"wdtest", -TCMD_WDTEST, "test watchdog"},
|
||||
{&S_inchannels, CMD_INCHNLS, "get u32 with bits set on supported IN channels"},
|
||||
{&S_mcutemp, CMD_MCUTEMP, "get MCU temperature (*10degrC)"},
|
||||
{&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'"},
|
||||
{&S_modbusraw, -TCMD_MODBUS_SEND_RAW, "send RAW modbus request (will send up to 62 bytes + calculated CRC)"},
|
||||
{&S_outchannels, CMD_OUTCHNLS, "get u32 with bits set on supported OUT channels"},
|
||||
{&S_reset, CMD_RESET, "reset MCU"},
|
||||
{&S_time, CMD_TIME, "get/set time (1ms, 32bit)"},
|
||||
{&S_wdtest, -TCMD_WDTEST, "test watchdog"},
|
||||
{NULL, 0, NULL} // last record
|
||||
};
|
||||
|
||||
@ -98,12 +156,13 @@ static void printhelp(){
|
||||
usart_send("parameter [CAN idx] - help\n");
|
||||
usart_send("--------------------------\n");
|
||||
while(c->help){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(!c->cmd){ // header
|
||||
usart_send("\n ");
|
||||
usart_send(c->help);
|
||||
usart_putchar(':');
|
||||
}else{
|
||||
usart_send(c->cmd);
|
||||
usart_send(*c->cmd);
|
||||
if(c->idx > -1){
|
||||
usart_send(" [");
|
||||
usart_send(u2str(c->idx));
|
||||
@ -128,7 +187,7 @@ static errcodes cansnif(const char *str, text_cmd _U_ cmd){
|
||||
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;
|
||||
}
|
||||
|
||||
@ -141,7 +200,7 @@ static errcodes canbuserr(const char *str, text_cmd _U_ cmd){
|
||||
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;
|
||||
}
|
||||
|
||||
@ -152,11 +211,7 @@ static errcodes wdtest(const char _U_ *str, text_cmd _U_ cmd){
|
||||
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){
|
||||
#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("\nuserconf_idx="); printi(currentconfidx);
|
||||
usart_send("\nuserconf_sz="); printu(the_conf.userconf_sz);
|
||||
usart_send("\ncanspeed="); printu(the_conf.CANspeed);
|
||||
usart_send("\ncanid_in="); printu(the_conf.CANIDin);
|
||||
usart_send("\ncanid_out="); printu(the_conf.CANIDout);
|
||||
/*for(int i = 0; i < ADC_TSENS; ++i){
|
||||
usart_send("\nadcmul"); usart_putchar('0'+i); usart_putchar('=');
|
||||
usart_send(float2str(the_conf.adcmul[i], 3));
|
||||
}*/
|
||||
usart_send("\nusartspeed="); printu(the_conf.usartspeed);
|
||||
usart_send("\nmodbus_id="); printu(the_conf.modbusID);
|
||||
usart_send("\nmodbusspeed="); printu(the_conf.modbusspeed);
|
||||
usart_send("\nbouncetime="); printu(the_conf.bouncetime);
|
||||
const char * const *p = bitfields;
|
||||
newline(); usart_send(S_canspeed); EQ(); printu(the_conf.CANspeed);
|
||||
newline(); usart_send(S_canidin); EQ(); printu(the_conf.CANIDin);
|
||||
newline(); usart_send(S_canidout); EQ(); printu(the_conf.CANIDout);
|
||||
newline(); usart_send(S_usartspeed); EQ(); printu(the_conf.usartspeed);
|
||||
newline(); usart_send(S_modbusid); EQ(); printu(the_conf.modbusID);
|
||||
newline(); usart_send(S_modbusidout); EQ(); printu(the_conf.modbusIDout);
|
||||
newline(); usart_send(S_modbusspeed); EQ(); printu(the_conf.modbusspeed);
|
||||
newline(); usart_send(S_bounce); EQ(); printu(the_conf.bouncetime);
|
||||
const char ** const *p = bitfields;
|
||||
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){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
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;
|
||||
++p;
|
||||
}
|
||||
@ -198,6 +251,7 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){
|
||||
int ctr = -1;
|
||||
canmsg.ID = 0xffff;
|
||||
do{
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
txt = omit_spaces(txt);
|
||||
uint32_t 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;
|
||||
uint32_t Tstart = Tms;
|
||||
while(Tms - Tstart < SEND_TIMEOUT_MS){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(CAN_OK == CAN_send(&canmsg)){
|
||||
return ERR_OK;
|
||||
}
|
||||
@ -234,13 +289,22 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){
|
||||
|
||||
// change configuration flags by one
|
||||
static errcodes confflags(const char _U_ *str, text_cmd cmd){
|
||||
if(str){
|
||||
if(str && *str){
|
||||
if(*str == '=') str = omit_spaces(str + 1);
|
||||
if(*str != '0' && *str != '1') return ERR_BADVAL;
|
||||
uint8_t val = *str - '0';
|
||||
switch(cmd){
|
||||
case TCMD_SW_SEND_RELAY:
|
||||
the_conf.flags.sw_send_relay_cmd = val;
|
||||
case TCMD_SW_SEND_CAN:
|
||||
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;
|
||||
default:
|
||||
return ERR_BADCMD;
|
||||
@ -248,21 +312,35 @@ static errcodes confflags(const char _U_ *str, text_cmd cmd){
|
||||
}
|
||||
uint8_t val = 0, idx = 0;
|
||||
switch(cmd){
|
||||
case TCMD_SW_SEND_RELAY:
|
||||
val = the_conf.flags.sw_send_relay_cmd;
|
||||
case TCMD_SW_SEND_CAN:
|
||||
val = the_conf.flags.sw_send_esw_can;
|
||||
idx = 0;
|
||||
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:
|
||||
return ERR_BADCMD;
|
||||
}
|
||||
usart_send(bitfields[idx]); usart_putchar('='); usart_putchar('0' + val);
|
||||
usart_send(*bitfields[idx]); EQ(); usart_putchar('0' + val);
|
||||
newline();
|
||||
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){
|
||||
modbus_request req = {0};
|
||||
uint8_t reqdata[MODBUSBUFSZO - 7] = {0};
|
||||
uint32_t N = 0;
|
||||
const char *n = getnum(txt, &N);
|
||||
if(n == txt || N > MODBUS_MAX_ID){
|
||||
@ -283,15 +361,53 @@ static errcodes modbussend(const char *txt, text_cmd _U_ cmd){
|
||||
}
|
||||
req.startreg = N;
|
||||
txt = n; n = getnum(txt, &N);
|
||||
if(n == txt || N == 0){
|
||||
usart_send("Need registers amount\n");
|
||||
if(n == txt){
|
||||
usart_send("Need registers amount or data bytes\n");
|
||||
return ERR_WRONGLEN;
|
||||
}
|
||||
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;
|
||||
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 ************/
|
||||
|
||||
// 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_CANSNIFFER] = cansnif,
|
||||
[TCMD_CANBUSERRPRNT] = canbuserr,
|
||||
[TCMD_SW_SEND_RELAY] = confflags,
|
||||
[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] = {
|
||||
@ -339,7 +459,8 @@ void cmd_parser(const char *str){
|
||||
if(l == 0) goto ret;
|
||||
cmd[l] = 0;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
#include <stm32f1.h>
|
||||
#include "hardware.h"
|
||||
|
||||
#define MAXCMDLEN (12)
|
||||
#define MAXCMDLEN (32)
|
||||
|
||||
// flags for some RS-232 comands
|
||||
typedef struct{
|
||||
@ -33,3 +33,4 @@ extern flags_t flags;
|
||||
|
||||
|
||||
void cmd_parser(const char *txt);
|
||||
|
||||
|
||||
@ -64,8 +64,6 @@ static char *_2str(uint32_t val, uint8_t minus){
|
||||
uint32_t x = val / 10;
|
||||
*(--bufptr) = (val - 10*x) + '0';
|
||||
val = x;
|
||||
//*(--bufptr) = val % 10 + '0';
|
||||
//val /= 10;
|
||||
}
|
||||
}
|
||||
if(minus) *(--bufptr) = '-';
|
||||
|
||||
@ -43,6 +43,7 @@ const char *getnum(const char *txt, uint32_t *N);
|
||||
const char *omit_spaces(const char *buf);
|
||||
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 printu(a) do{usart_send(u2str(a));}while(0)
|
||||
#define printi(a) do{usart_send(i2str(a));}while(0)
|
||||
|
||||
@ -56,18 +56,18 @@ int usart_getline(char **line){
|
||||
int usart_transmit(){
|
||||
register int l = odatalen[tbufno];
|
||||
if(!l) return 0;
|
||||
uint32_t tmout = 1600000;
|
||||
uint32_t tmout = 18000000;
|
||||
while(!usart_txrdy){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(--tmout == 0) return 0;
|
||||
}; // wait for previos buffer transmission
|
||||
usart_txrdy = 0;
|
||||
odatalen[tbufno] = 0;
|
||||
DMA1_Channel4->CCR &= ~DMA_CCR_EN;
|
||||
DMA1_Channel4->CMAR = (uint32_t) tbuf[tbufno]; // mem
|
||||
DMA1_Channel4->CNDTR = l;
|
||||
DMA1_Channel4->CCR |= DMA_CCR_EN;
|
||||
tbufno = !tbufno;
|
||||
odatalen[tbufno] = 0;
|
||||
return l;
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@ int usart_putchar(const char ch){
|
||||
int usart_send(const char *str){
|
||||
int l = 0;
|
||||
while(*str){
|
||||
IWDG->KR = IWDG_REFRESH;
|
||||
if(odatalen[tbufno] == UARTBUFSZO){
|
||||
if(!usart_transmit()) return 0;
|
||||
}
|
||||
@ -100,7 +101,6 @@ int usart_send(const char *str){
|
||||
*/
|
||||
|
||||
void usart_setup(uint32_t speed){
|
||||
uint32_t tmout = 16000000;
|
||||
// PA9 - Tx, PA10 - Rx
|
||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
|
||||
@ -116,7 +116,11 @@ void usart_setup(uint32_t speed){
|
||||
// setup usart1
|
||||
USART1->BRR = 72000000 / speed;
|
||||
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->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
|
||||
USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx
|
||||
|
||||
@ -21,8 +21,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
// input and output buffers size
|
||||
#define UARTBUFSZI (64)
|
||||
#define UARTBUFSZO (128)
|
||||
#define UARTBUFSZI (196)
|
||||
#define UARTBUFSZO (256)
|
||||
|
||||
#define usartrx() (usart_linerdy)
|
||||
#define usartovr() (usart_bufovr)
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
#define BUILD_NUMBER "85"
|
||||
#define BUILD_DATE "2024-09-24"
|
||||
#define BUILD_NUMBER "105"
|
||||
#define BUILD_DATE "2024-09-26"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user