FX3U code ready

This commit is contained in:
Edward Emelianov 2024-09-27 15:46:12 +03:00
parent b9942f2e9f
commit 1b73ebad2c
8 changed files with 346 additions and 55 deletions

View File

@ -1,16 +1,20 @@
A usefull thing made of chineese FX3U clone A usefull thing made of chineese FX3U clone
=========================================== ===========================================
Works over RS-232 (default: 115200, 8N1) or CAN (default 250000 baud). Works over RS-232 (default: 115200, 8N1), CAN (default: 250000 baud)
or MODBUS-RTU (default: 9600, 8N1).
You can see pinout table in file `hardware.c`. You can see pinout table in file `hardware.c`.
## Serial protocol (each string ends with '\n'). ## Serial protocol (each string ends with '\n').
(TODO: add new) Values in parentheses after flags command is its bit number in whole uint32_t.
E.g. to reset flag "f_relay_inverted" you can call `f_relay_inverted=0` or
`flags2=0`.
``` ```
commands format: parameter[number][=setter] commands format: parameter[number][=setter]
parameter [CAN idx] - help parameter [CAN idx] - help
-------------------------- --------------------------
@ -18,6 +22,7 @@ parameter [CAN idx] - help
CAN bus commands: CAN bus commands:
canbuserr - print all CAN bus errors (a lot of if not connected) canbuserr - print all CAN bus errors (a lot of if not connected)
cansniff - switch CAN sniffer mode cansniff - switch CAN sniffer mode
s - send CAN message: ID 0..8 data bytes
Configuration: Configuration:
bounce [14] - set/get anti-bounce timeout (ms, max: 1000) bounce [14] - set/get anti-bounce timeout (ms, max: 1000)
@ -27,6 +32,14 @@ canidout [8] - get/set output CAN ID
canspeed [5] - get/set CAN speed (bps) canspeed [5] - get/set CAN speed (bps)
dumpconf - dump current configuration dumpconf - dump current configuration
eraseflash [10] - erase all flash storage eraseflash [10] - erase all flash storage
f_relay_inverted (2) - inverted state between relay and inputs
f_send_esw_can (0) - change of IN will send status over CAN with `canidin`
f_send_relay_can (1) - change of IN will send also CAN command to change OUT with `canidout`
f_send_relay_modbus (3) - change of IN will send also MODBUS command to change OUT with `modbusidout` (only for master!)
flags [17] - set/get configuration flags (as one U32 without parameter or Nth bit with)
modbusid [20] - set/get modbus slave ID (1..247) or set it master (0)
modbusidout [21] - set/get modbus slave ID (0..247) to send relay commands
modbusspeed [22] - set/get modbus speed (1200..115200)
saveconf [9] - save configuration saveconf [9] - save configuration
usartspeed [15] - get/set USART1 speed usartspeed [15] - get/set USART1 speed
@ -38,18 +51,26 @@ led [16] - work with onboard LED
relay [11] - get/set relay state (0 - off, 1 - on) relay [11] - get/set relay state (0 - off, 1 - on)
Other commands: Other commands:
inchannels [18] - get u32 with bits set on supported IN channels
mcutemp [3] - get MCU temperature (*10degrC) mcutemp [3] - get MCU temperature (*10degrC)
modbus - send modbus request with format "slaveID fcode regaddr nregs [N data]", to send zeros you can omit rest of 'data'
modbusraw - send RAW modbus request (will send up to 62 bytes + calculated CRC)
outchannels [19] - get u32 with bits set on supported OUT channels
reset [1] - reset MCU reset [1] - reset MCU
s - send CAN message: ID 0..8 data bytes
time [2] - get/set time (1ms, 32bit) time [2] - get/set time (1ms, 32bit)
wdtest - test watchdog wdtest - test watchdog
error=badcmd
``` ```
Value in square brackets is CAN bus command code. Value in square brackets is CAN bus command code.
The INs are changed compared to original "FX3U" clone: instead of the absent IN8 I use the on-board
button "RUN".
## CAN bus protocol ## CAN bus protocol
Default CAN speed is 250kbaud. Default CAN ID: 1 and 2 for slave.
All data in little-endian format! All data in little-endian format!
BYTE - MEANING BYTE - MEANING
@ -62,6 +83,13 @@ BYTE - MEANING
4..7 - (int32_t) - data. 4..7 - (int32_t) - data.
When device receives CAN packet with its ID or ID=0 ("broadcast" message) it check this packet, perform some action and sends answer
(usually - getter). If command can't be execute or have wrong data (bad command, bad parameter number etc) the device sends back
the same packet with error code inserted.
When runnming getter you can send only three bytes: command code and parameter number. Sending "no parameter" instead of parno
means in some commands "all data" (e.g. get/set all relays or get all inputs).
### CAN bus error codes ### CAN bus error codes
0 - `ERR_OK` - all OK, 0 - `ERR_OK` - all OK,
@ -76,7 +104,271 @@ BYTE - MEANING
5 - `ERR_CANTRUN` - can't run given command due to bad parameters or other reason. 5 - `ERR_CANTRUN` - can't run given command due to bad parameters or other reason.
### CAN bus command codes
Number - enum from canproto.h - text command analog
0 - CMD_PING - ping
1- CMD_RESET - reset
2 - CMD_TIME - time
3 - CMD_MCUTEMP - mcutemp
4 - CMD_ADCRAW - adc
5 - CMD_CANSPEED - canspeed
6 - CMD_CANID - canid
7 - CMD_CANIDin - canidin
8 - CMD_CANIDout - canidout
9 - CMD_SAVECONF - saveconf
10 - CMD_ERASESTOR - eraseflash
11 - CMD_RELAY - relay
12 - CMD_GETESW - esw
13 - CMD_GETESWNOW - eswnow
14 - CMD_BOUNCE - bounce
15 - CMD_USARTSPEED - usartspeed
16 - CMD_LED - led
17 - CMD_FLAGS - flags
18 - CMD_INCHNLS - inchannels
19 - CMD_OUTCHNLS - outchannels
20 - CMD_MODBUSID - modbusid
21 - CMD_MODBUSIDOUT - modbusidout
22 - CMD_MODBUSSPEED - modbusspeed
### Examples of CAN commands (bytes of data transmitted with given ID)
(all data in HEX)
Get current time: "02 00 00". Answer something like "02 00 00 00 de ad be ef", where last four bytes
is time value (in milliseconds) from powering on.
Set relay number 5: "0b 00 85 00 01 00 00 00", answer: "0b 00 05 00 01 00 00 00".
Set relays 0..3 and reset other: "0b 00 ff 00 07 00 00 00", answer: "0b 00 7f 00 07 00 00 00".
Changing flags is the same as for text command: with parameter number (0..31) it will only change given
bit value, without ("no par" - 0x7f) will change all bits like whole uint32_t.
## MODBUS-RTU protocol ## MODBUS-RTU protocol
(TODO) The device can work as master or slave. Default format is 9600-8N1. BIG ENDIAN (like standard requires).
Default device ID is 1 ans 2 for target of "relay command" (if ID would be changed to 0 and flag `f_send_relay_modbus` set.
To run in master mode you should set its modbus ID to zero. Command `modbus` lets you to send strict
formal modbus packet in format "slaveID fcode regaddr nregs [N data]" (all are space-delimited numbers in
decimal, hexadecimal (e.g. 0xFF), octal (e.g. 075) or binary (e.g. 0b1100110) format.
Here "slaveID" - one byte; "fcode" - one byte; "regaddr" - two bytes big endian; "nregs" - two bytes big endian;
"N" - one byte; "data" - N bytes.
Optional data bytes allowed only for "multiple" functions. In case of simple setters "nregs" is two bytes data
sent to slave.
The command `modbusraw` will not check your data, just add CRC and send into bus.
In master mode you can activate flag `f_send_relay_modbus`. In this case each time the IN state changes
device will send command with ID=`modbusidout` to change corresponding relays. So, like for CAN commands
you can bind several devices to transmit IN states of one to OUT states of another.
If `modbusidout` is zero, master will send broadcasting command. Slaves non answer for broadcast, only making
required action.
The hardware realisation of modbus based on UART4. Both input and output works over DMA, signal of packet end
is IDLE interrupt. This device doesn't supports full modbus protocol realisation: no 3.5 idle frames as packet
end; no long packets (input buffer is 68 bytes, allowing no more that 67 bytes; output buffer is 64 bytes, allowing
no more that 64 bytes). Maximal modbus slave ID is 247. You can increase in/out buffers size changing value of
macros `MODBUSBUFSZI` and `MODBUSBUFSZO` in `modbusrtu.h`.
In slave mode device doesn't support whole CAN-bus commands range. Next I describe allowed commands.
There are five holding registers. "[R]" means read-only, "[W]" - write-only, "[RW]" - read and write.
0 - MR_RESET [W] - reset MCU.
1 - MR_TIME [RW] - read or set MCU time (milliseconds, uint32_t).
2 - MR_LED [RW] - read or change on-board LED state.
3 - MR_INCHANNELS [R] - get uint32_t value where each N-th bit means availability of N-th IN channel
(e.g. if 9th channel is physically absent 9th bit would be 0).
### Supported functional codes
#### 01 - read coil
Read state of all relays. Obligatory regaddr="00 00", nregs="00 N", where "N" is 8-multiple
number (in case of 10-relay module: 8 or 16). You will reseive N/8 bytes of data with relays' status (e.g. most
lest significant bit is state or relay0, next - relay1 and so on).
Example: "01 01 00 00 00 10" - read state of all relays. If only relay 10 active you will
receive: "01 01 02 04 00".
Errors: "02" - "regaddr" isn't zero; "03" - N isn't multiple of 8 or too large.
#### 02 - read discrete input
Read state of all discrete inputs. Input/output parameters are the same like for "read coil".
Example: "01 02 00 00 00 08" - read 8 first INs. Answer if first 4 inputs active (disconnected):
"01 02 01 0f".
Errors: like for "read coil".
#### 03 - read holding register
You can read value of non write-only registers. You can read only one register by time.
Example: "01 03 00 01 00 01" - read time. Answer: "01 03 04 00 15 53 01", where 0x00155301 is 1397.505 seconds
from device start.
Errors: "02" - "regaddr" is wrong, "03" - "regno" isn't 1.
#### 04 - read input register
Read "nregs" ADC channels starting from "regaddr" number.
Example: "01 04 00 05 00 04" - read channels 5..8.
Answer: "01 04 08 08 6c 00 21 00 33 00 41" - got 0x86c (2156) for 5th channel and so on.
Errors: "02" - wrong starting number, "03" - wrong amount (zero or N+start > last channel available).
#### 05 - write coil
Change single relay state. "nregs" is value (0 - off, non-0 - on), "regaddr" is relay number.
Example: "01 05 00 03 00 01" - turn 3rd relay on. Answer: "01 05 00 03 00 01".
Errors: "02" - wrong relay number.
#### 06 - write holding register
Write data to non read-only register (reset MCU, change time value or turn LED on/off).
Example: "01 06 00 02 00 01" - turn LED on. Answer: "01 06 00 02 00 01".
Errors: "02" - wrong register.
#### 0f - write multiple coils
Change state of all relays by once. Here "regaddr" should be "00 00",
"nregs" should be multiple of 8, "N" should be equal ("nregs"+7)/8. Each data bit means nth relay state.
Example: "01 0f 00 00 00 08 01 ff" - turn on relays 0..7.
Answer: "01 0f 00 00 00 08".
Errors: "02" - "regaddr" isn't zero, "03" - wrong amount of relays, "07" - can't change relay values.
#### 10 - write multiple registers
You can write only four "registers" by once changing appropriate uint32_t value.
The only "register" you can change is 01 - MR_TIME. "nregs" should be equal 1.
Example: "01 10 00 01 00 01 04 00 00 00 00" - clears Tms counter, starting time from zero.
Answer: "01 10 00 01 00 01".
Errors: "02" - wrong register.
### Error codes
01 - ME_ILLEGAL_FUNCION - The function code received in the request is not an authorized action for the slave.
02 - ME_ILLEGAL_ADDRESS - The data address received by the slave is not an authorized address for the slave.
03 - ME_ILLEGAL_VALUE - The value in the request data field is not an authorized value for the slave.
04 - ME_SLAVE_FAILURE - The slave fails to perform a requested action because of an unrecoverable error.
05 - ME_ACK - The slave accepts the request but needs a long time to process it.
06 - ME_SLAVE_BUSY - The slave is busy processing another command.
07 - ME_NACK - The slave cannot perform the programming request sent by the master.
08 - ME_PARITY_ERROR - Memory parity error: slave is almost dead.
# Short programming guide
## Adding a new value to flash storage
All storing values described in structure `user_conf` (`flash.h`). You can add there any new value
but be carefull with 32-bit alignment. Bit flags stored as union `confflags_t` combining 32-bit and 1-bit access.
After you add this new value don't forget to add setter/getter and string describing it in function `dumpconf`.
Text protocol allows you to work with flags by their semantic name. So to add some flag you should also modify
`proto.c`:
- add text constant with flag name;
- add address of this constant into `bitfields` array (according to bit order in flags);
- add appropriate enum into `text_cmd`;
- add appropriate string into `funclist`: pointer to string constant, enum field and help text;
- modify function `confflags` for setter/getter of new flag.
## Adding a new command
All base commands are processed in files `canproto.c` and `proto.c`. `modbusproto.c` is for modbus-specific commands.
To add CAN/serial command you should first add a field to anonimous enum in `canproto.h`, which will be number code of
given CANbus command. Codes of serial-only commands are stored in enum `text_cmd` of file `proto.c`.
### Add both CAN/serial command
- add enum in `canproto.c`;
- add string const with text name of this command in `proto.c`;
- add string to `funclist` with address of string const, enum and help;
- add command handler into `canproto.c` and describer into array `funclist` (index should be equal
to command code, struct consists from pointer to handler, minimal and maximal value and minimal data length
of can packet). If min==max then argument wouldn't be checked.
The handler returns one of `errcodes` and have as argument only pointer to `CAN_message` structure.
So, serial command parser before call this handler creates CAN packet from user data.
Format of command is next: "cmd[X][=VAL]", where "cmd" is command text, "X" - optional parameter,
"VAL" - value for setter. So the packet would be "C C P 0 VAL0 VAL1 VAL2 VAL3", where
"C" - command code, "P" - parameter number (or 0x7f" if X is omit) OR'ed with 0x80 for setter,
VALx - xth byte (little endian) of user value.
For setting/getting uint32_t paramegers (especially configuration parameters) you can use handler `u32setget`.
For bit flags - `flagsetget`.
To work with bit-flags by particular name use `confflags` handler of `proto.c`.
### Add serial-only command
In this case there's no CAN handler. You work only with `proto.c`.
- add enum in `text_cmd`;
- add string const with text name of this command;
- add string to `funclist` with address of string const, enum and help;
- add command handler;
- add pointer to this handler into `textfunctions` array.
Handler also returns one of `errcodes`, but have next arguments:
- `const char *txt` - all text (excluding spaces in beginning) after command in user string;
- `text_cmd command` - number of command (useful when you have common handler for several commands).
## Working with modbus
All exceptions and functional codes described as enums in `modbusrtu.h`.
To form request or responce use structs `modbus_request` and `modbus_responce`. `data` fields in this
structs is big-endian storing bytes in order like they will be sent via RS-485.
Amount of data bytes should be not less then `datalen` value. For requests that don't need data,
`data` may be NULL regardless `datalen` (for Fcode <= 6). `regno` is amount of registers or
data written to register dependent on `Fcode`.
The responce struct of error codes have NULL in `data` and `datalen` is appropriate exception code.
All high-level commands are in `modbusproto.c`. To add new `register` you should edit `modbus_regusters`
enum in `modbusproto.h`.
The main parsing pipeline is `parse_modbus_request` in `modbusproto.c`.
Here you can add parsing of new functional codes.
To work with new "registers" edit `readreg`, `writereg` or `writeregs`.

View File

@ -119,8 +119,8 @@ void CAN_setup(uint32_t speed){
else if(speed > CAN_MAX_SPEED) speed = CAN_MAX_SPEED; else if(speed > CAN_MAX_SPEED) speed = CAN_MAX_SPEED;
uint32_t tmout = 16000000; uint32_t tmout = 16000000;
// Configure GPIO: PD0 - CAN_Rx, PD1 - CAN_Tx // Configure GPIO: PD0 - CAN_Rx, PD1 - CAN_Tx
AFIO->MAPR |= AFIO_MAPR_CAN_REMAP_REMAP3; // I don't know why, but without AFIO_MAPR_SWJ_CFG_DISABLE here JTAG works (despite on turning it off in hardware.c)!
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_DISABLE; // I don't know why, but without this string JTAG works (despite on turning it off in hardware.c)! AFIO->MAPR |= AFIO_MAPR_CAN_REMAP_REMAP3 | AFIO_MAPR_SWJ_CFG_DISABLE;
GPIOD->CRL = (GPIOD->CRL & ~(CRL(0,0xf)|CRL(1,0xf))) | GPIOD->CRL = (GPIOD->CRL & ~(CRL(0,0xf)|CRL(1,0xf))) |
CRL(0, CNF_FLINPUT | MODE_INPUT) | CRL(1, CNF_AFPP | MODE_NORMAL); CRL(0, CNF_FLINPUT | MODE_INPUT) | CRL(1, CNF_AFPP | MODE_NORMAL);
/* Enable the peripheral clock CAN */ /* Enable the peripheral clock CAN */
@ -171,9 +171,9 @@ void CAN_setup(uint32_t speed){
CAN1->IER |= CAN_IER_ERRIE | CAN_IER_FOVIE0 | CAN_IER_FOVIE1 | CAN_IER_BOFIE; /* (13) */ CAN1->IER |= CAN_IER_ERRIE | CAN_IER_FOVIE0 | CAN_IER_FOVIE1 | CAN_IER_BOFIE; /* (13) */
/* Configure IT */ /* Configure IT */
NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 0); // RX FIFO0 IRQ NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 4); // RX FIFO0 IRQ
NVIC_SetPriority(CAN1_RX1_IRQn, 0); // RX FIFO1 IRQ NVIC_SetPriority(CAN1_RX1_IRQn, 4); // RX FIFO1 IRQ
NVIC_SetPriority(CAN1_SCE_IRQn, 0); // RX status changed IRQ NVIC_SetPriority(CAN1_SCE_IRQn, 4); // RX status changed IRQ
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_EnableIRQ(CAN1_RX1_IRQn); NVIC_EnableIRQ(CAN1_RX1_IRQn);
NVIC_EnableIRQ(CAN1_SCE_IRQn); NVIC_EnableIRQ(CAN1_SCE_IRQn);
@ -192,10 +192,7 @@ void CAN_sniffer(uint8_t issniffer){
void CAN_printerr(){ void CAN_printerr(){
uint32_t last_err_code = CAN1->ESR; uint32_t last_err_code = CAN1->ESR;
if(!last_err_code){ if(!last_err_code) return;
usart_send("No errors\n");
return;
}
usart_send("Receive error counter: "); usart_send("Receive error counter: ");
usart_send(u2str((last_err_code & CAN_ESR_REC)>>24)); usart_send(u2str((last_err_code & CAN_ESR_REC)>>24));
usart_send("\nTransmit error counter: "); usart_send("\nTransmit error counter: ");
@ -226,6 +223,7 @@ void CAN_proc(){
if(flags.can_printoff){ if(flags.can_printoff){
const char *e; const char *e;
switch(can_status){ switch(can_status){
case CAN_STOP: e = "STOP"; break;
case CAN_ERR: e = "ERRI"; break; case CAN_ERR: e = "ERRI"; break;
case CAN_FIFO_OVERRUN: e = "FIFO_OVERRUN"; break; case CAN_FIFO_OVERRUN: e = "FIFO_OVERRUN"; break;
default: e = "UNKNOWN"; default: e = "UNKNOWN";
@ -234,7 +232,8 @@ void CAN_proc(){
usart_send(e); newline(); usart_send(e); newline();
CAN_printerr(); CAN_printerr();
} }
CAN_reinit(0); if(can_status == CAN_FIFO_OVERRUN) can_status = CAN_READY;
else 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){
@ -345,7 +344,7 @@ static void can_process_fifo(uint8_t fifo_num){
} }
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later if(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;
*RFxR = 0; // clear FOVR & FULL *RFxR = 0; // clear FOVR & FULL
@ -353,28 +352,25 @@ static void can_process_fifo(uint8_t fifo_num){
void usb_lp_can_rx0_isr(){ // Rx FIFO0 (overrun) 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; // clear flag
can_status = CAN_FIFO_OVERRUN; can_status = CAN_FIFO_OVERRUN;
RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
} }
} }
void can_rx1_isr(){ // Rx FIFO1 (overrun) 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; // clear flag
can_status = CAN_FIFO_OVERRUN; can_status = CAN_FIFO_OVERRUN;
RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
} }
} }
void can_sce_isr(){ // status changed void can_sce_isr(){ // status changed
if(CAN1->MSR & CAN_MSR_ERRI){ // Error if(CAN1->MSR & CAN_MSR_ERRI){ // Error
CAN1->MSR &= ~CAN_MSR_ERRI; CAN1->MSR = CAN_MSR_ERRI; // clear flag
// request abort for problem mailbox // request abort for problem mailbox
if(CAN1->TSR & CAN_TSR_TERR0) CAN1->TSR |= CAN_TSR_ABRQ0; if(CAN1->TSR & CAN_TSR_TERR0) CAN1->TSR |= CAN_TSR_ABRQ0;
if(CAN1->TSR & CAN_TSR_TERR1) CAN1->TSR |= CAN_TSR_ABRQ1; if(CAN1->TSR & CAN_TSR_TERR1) CAN1->TSR |= CAN_TSR_ABRQ1;
if(CAN1->TSR & CAN_TSR_TERR2) CAN1->TSR |= CAN_TSR_ABRQ2; if(CAN1->TSR & CAN_TSR_TERR2) CAN1->TSR |= CAN_TSR_ABRQ2;
can_status = CAN_ERR; can_status = CAN_ERR;
RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
} }
} }

View File

@ -220,9 +220,9 @@ static const commonfunction funclist[CMD_AMOUNT] = {
[CMD_CANIDout] = {canidout, 1, 0x7ff, 0}, [CMD_CANIDout] = {canidout, 1, 0x7ff, 0},
[CMD_SAVECONF] = {saveconf, 0, 0, 0}, [CMD_SAVECONF] = {saveconf, 0, 0, 0},
[CMD_ERASESTOR] = {erasestor, 0, 0, 0}, [CMD_ERASESTOR] = {erasestor, 0, 0, 0},
[CMD_RELAY] = {relay, 0, INT32_MAX, 0}, [CMD_RELAY] = {relay, 0, 0, 0},
[CMD_GETESW] = {eswg, 0, INT32_MAX, 0}, [CMD_GETESW] = {eswg, 0, 0, 0},
[CMD_GETESWNOW] = {esw, 0, INT32_MAX, 0}, [CMD_GETESWNOW] = {esw, 0, 0, 0},
[CMD_BOUNCE] = {u32setget, 0, 1000, 0}, [CMD_BOUNCE] = {u32setget, 0, 1000, 0},
[CMD_USARTSPEED] = {u32setget, 1200, 3000000, 0}, [CMD_USARTSPEED] = {u32setget, 1200, 3000000, 0},
[CMD_LED] = {led, 0, 0, 0}, [CMD_LED] = {led, 0, 0, 0},

Binary file not shown.

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 13.0.1, 2024-06-04T14:30:38. --> <!-- Written by QtCreator 14.0.1, 2024-09-27T15:44:53. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
<value type="QByteArray">{7bd84e39-ca37-46d3-be9d-99ebea85bc0d}</value> <value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
</data> </data>
<data> <data>
<variable>ProjectExplorer.Project.ActiveTarget</variable> <variable>ProjectExplorer.Project.ActiveTarget</variable>
@ -39,21 +39,21 @@
<value type="int" key="EditorConfiguration.PaddingMode">1</value> <value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value> <value type="int" key="EditorConfiguration.PreferAfterWhitespaceComments">0</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value> <value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value> <value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value> <value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value> <value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value> <value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value> <value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value> <value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value> <value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value> <value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value> <value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value> <value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value> <value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">false</value> <value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value> <value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value> <value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value> <value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value> <value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value> <value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
</valuemap> </valuemap>
@ -69,15 +69,17 @@
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value> <value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value> <value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap> </valuemap>
<value type="bool" key="AutoTest.ApplyFilter">false</value>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/> <valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<valuelist type="QVariantList" key="AutoTest.PathFilters"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value> <value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value> <value type="bool" key="AutoTest.UseGlobal">true</value>
<valuemap type="QVariantMap" key="ClangTools"> <valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value> <value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value> <value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value> <value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">8</value> <value type="int" key="ClangTools.ParallelJobs">4</value>
<value type="bool" key="ClangTools.PreferConfigFile">true</value> <value type="bool" key="ClangTools.PreferConfigFile">false</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/> <valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/> <valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/> <valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
@ -91,12 +93,12 @@
<value type="QString" key="DeviceType">Desktop</value> <value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{65a14f9e-e008-4c1b-89df-4eaa4774b6e3}</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value> <value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> <value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> <value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Big/Data/00__Electronics/STM32/F1-nolib/CAR_CANbus/WindShield</value> <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/ELECTRONICS/STM32/F1-srcs/usbcan</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets"> <valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
@ -106,8 +108,8 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap> </valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value> <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap> </valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1"> <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
@ -119,8 +121,8 @@
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap> </valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value> <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap> </valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value> <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
@ -135,8 +137,8 @@
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0"> <valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value> <value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap> </valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value> <value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
@ -148,9 +150,7 @@
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0"> <valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value> <value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value> <value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Valgrind.Callgrind.CostFormat">0</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value> <value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="QList&lt;int&gt;" key="Analyzer.Valgrind.VisibleErrorKinds"></value>
<valuelist type="QVariantList" key="CustomOutputParsers"/> <valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value> <value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/> <valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>

View File

@ -85,8 +85,10 @@ void gpio_setup(void){
// PD0 & PD1 (CAN) setup in can.c; PA9 & PA10 (USART) in usart.c // PD0 & PD1 (CAN) setup in can.c; PA9 & PA10 (USART) in usart.c
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN |
RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN; RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN;
// Turn off JTAG/SWD to use PA14 // Turn off JTAG/SWD to use PA14 (I don't know why, but here it doesn't work, need to repeat in can.c)
#ifndef EBUG
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_DISABLE; AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_DISABLE;
#endif
// be sure that all OK // be sure that all OK
// __ISB(); // __ISB();
// __DSB(); // __DSB();

View File

@ -115,15 +115,16 @@ void usart_setup(uint32_t speed){
NVIC_SetPriority(USART1_IRQn, 0); NVIC_SetPriority(USART1_IRQn, 0);
// 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_UE | USART_CR1_TE | USART_CR1_RE; // 1start,8data,nstop; enable Rx/Tx
uint32_t tmout = 16000000; uint32_t tmout = 16000000;
while(!(USART1->SR & USART_SR_TC)){ while(!(USART1->SR & USART_SR_TC)){ // polling idle frame Transmission
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) break; if(--tmout == 0) break;
} // polling idle frame Transmission }
(void) USART1->DR; // clear IDLE etc
USART1->SR = 0; // clear flags USART1->SR = 0; // clear flags
USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx
USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ
NVIC_EnableIRQ(USART1_IRQn); NVIC_EnableIRQ(USART1_IRQn);
} }

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "105" #define BUILD_NUMBER "116"
#define BUILD_DATE "2024-09-26" #define BUILD_DATE "2024-09-27"