Continue to write USB protocol documentation and fix bugs in code.

This commit is contained in:
Edward Emelianov 2024-08-16 12:37:11 +03:00
parent 018f0d4b33
commit b10fb37c58
19 changed files with 321 additions and 65 deletions

View File

@ -4,6 +4,7 @@ MCU := F303xd
# change this linking script depending on particular MCU model, # change this linking script depending on particular MCU model,
LDSCRIPT := stm32f303xD.ld LDSCRIPT := stm32f303xD.ld
DEFINES := -DUSB2_16 DEFINES := -DUSB2_16
#DEFINES := -DUSB1_16
include ../makefile.f3 include ../makefile.f3
include ../../makefile.stm32 include ../../makefile.stm32

View File

@ -9,7 +9,7 @@ Eighth stepper could be changed to 8 dependent multiplexed. Based on STM32F303VD
### Sorted by pin number ### Sorted by pin number
|**Pin #**|**Pin name **| **function**| **settings** |**comment ** | | Pin # | Pin name | function | settings | comment |
|---------|-------------|-------------|---------------|---------------------| |---------|-------------|-------------|---------------|---------------------|
| 1 | PE2 | DIAG | in | `diag` output of TMC| | 1 | PE2 | DIAG | in | `diag` output of TMC|
| 2 | PE3 | MUL0 | slow out | multiplexer address | | 2 | PE3 | MUL0 | slow out | multiplexer address |
@ -113,23 +113,36 @@ Eighth stepper could be changed to 8 dependent multiplexed. Based on STM32F303VD
| 100 | (VDD) | | | | | 100 | (VDD) | | | |
### Some comments. ### Some comments.
_DIAG_ input used to detect problems with TMC drivers (multiplexed by _MUL_ outputs). **DIAG** input used to detect problems with TMC drivers (multiplexed by **MUL** outputs).
Each motor have next control signals: _EN_ - enable driver, _DIR_ - rotation direction, _STEP_ - microstepping clock signal, _L0_ - zero end-switch, _L1_ - max end-switch (or Cable Select for SPI-based TMC).
_MOTMUL_ - external multiplexer or other GPIO signals (e.g. to manage of 64 stepper motors). Each motor have next control signals: **EN** - enable driver, **DIR** - rotation direction, **STEP** - microstepping clock signal, **L0** - zero end-switch,
_ADC1 in_ - four external ADC signals (0..3.3V). **L1** - max end-switch (or Cable Select for SPI-based TMC).
_SPI1_ used to manage TMC drivers in case of SPI-based.
_USART1_ - to connect external something (master or slave). **MOTMUL** - external multiplexer or other GPIO signals (e.g. to manage of 64 stepper motors).
_OUT_ - external GPIO.
_USART2 Tx_ used to manage USART-based TMC (numbers 0-3). **ADC1 in** - four external ADC signals (0..3.3V).
_USART3 Tx_ used to manage USART-based TMC (numbers 4-7).
_SCRN_ - control signals for SPI TFT screen. **SPI1** used to manage TMC drivers in case of SPI-based.
_BTN_ - external button, keypad, joystick etc. Two of them could be connected to I2C devices.
_USB_ and _CAN_ used as main device control buses. **USART1** - to connect external something (master or slave).
_SW_ used as debugging/sewing; also (I remember about USB pullup only after end of PCB design) _SWDIO_ used as USB pullup (so the device have no USB in debug mode - when BTN0 and BTN1 are pressed at start).
**OUT** - external GPIO.
**USART2 Tx** used to manage USART-based TMC (numbers 0-3).
**USART3 Tx** used to manage USART-based TMC (numbers 4-7).
**SCRN** - control signals for SPI TFT screen.
**BTN** - external button, keypad, joystick etc. Two of them could be connected to I2C devices.
**USB** and **CAN** used as main device control buses.
**SW** used as debugging/flashing.
### Sorted by ports (with AF numbers). ### Sorted by ports (with AF numbers).
|**Pin #**|**Pin name **| **function**| **settings** |**comment ** | | Pin # | Pin name | function | settings | comment |
|---------|-------------|-------------|---------------|---------------------| |---------|-------------|-------------|---------------|---------------------|
| 23 | PA0 | ADC1 in1 | ADC | External ADC inputs | | 23 | PA0 | ADC1 in1 | ADC | External ADC inputs |
| 24 | PA1 | ADC1 in2 | ADC | | | 24 | PA1 | ADC1 in2 | ADC | |
@ -216,18 +229,233 @@ _SW_ used as debugging/sewing; also (I remember about USB pullup only after end
| 10 | PF9 | M0 STEP | AF3 (T15ch1) | clock of motor | | 10 | PF9 | M0 STEP | AF3 (T15ch1) | clock of motor |
| 11 | PF10 | M0 EN | slow out | l-s 0 or CS of SPI | | 11 | PF10 | M0 EN | slow out | l-s 0 or CS of SPI |
## DMA usage ## DMA usage
* ADC1 - DMA1_ch1 * ADC1 - DMA1_ch1
* ADC2 - DMA2_ch1 * ADC2 - DMA2_ch1
* USART2 (PDN-UART for drivers 0..3) - DMA1_ch6 (Rx), DMA1_ch7 (Tx)
* USART3 (PDN-UART for drivers 4..7) - DMA1_ch3 (Rx), DMA1_ch2 (Tx)
* SPI2 (screen) - DMA1_ch4 (Rx), DMA1_ch5 (Tx) [or may be dedicated to USART1]
# Other stepper drivers connection
## DRV8825 # Stepper drivers connection
Solder jumpers E2, B and A to connect ~RST and ~SLP to 3.3V.
Microstepping selection produced by soldering H2 (bit0), G2 (bit1) and/or C (bit2). After changing stepper type by soldering/desoldering appropriate jumpers, don't forget to change their types in settings
(and save settings in MSU flash memory after checking it with `dumpconf`).
Connection diagram for soldering jumpers shown on reverse side of PCB.
Jumpers **A**, **B** and **C** allow to short the contacts of driver's pins 6 (CLK / DCO / ~SLEEP), 5 (PDN_UART / SDO / ~RESET) and 4
(SPREAD / CS / M2), respectively.
Jumper **D1** connects MCU UART output with jumper **E1**, **D2** connects MCU MISO with same contact of **E1**.
Jumpers **E1** and **E2** allows to pullup pin 5 of driver to be connected with 3.3V or UART/MISO.
Jumper **F1** allows to connect pin 4 to CS line. **F2** connects pin 4 to 3.3V.
Jumper **G1** connects pin 3 (MS2 / SCK / M1) to SCK line. **G2** connects this pin to 3.3V.
Jumper **H1** connects pin pin 2 (MS1 / SDI / M0) to MOSI line **H2** connects it to 3.3V.
So, depending on driver type and its mode you can solder these jumpers so, than driver can work over PDN-UART, SPI or configuration
pins can select microstepping directly.
## DRV8825 and other simplest drivers
Solder jumpers **E2**, **B** and **A** to connect **~RST** and **~SLP** to 3.3V.
Microstepping selection produced by soldering **H2** (bit0), **G2** (bit1) and/or **C** (bit2).
## TMC2209 and other PDN-UART based
Solder jumpers **D1** and **E1** to connect MCU UART2/UART3 to PDN-UART pin of driver. Solder jumpers **G2**/**H2** according
address table (X - soldered, O - not soldered):
| Address | G2 | H2 |
|:-------:|:-----:|:-----:|
| 0 | **O** | **O** |
| 1 | **O** | **X** |
| 2 | **X** | **O** |
| 3 | **X** | **X** |
| 4 | **O** | **O** |
| 5 | **O** | **X** |
| 6 | **X** | **O** |
| 7 | **X** | **X** |
## TMC2130 and other SPI based
(not negotiated yet)
Solder jumpers **D2** and **E1** to connect MISO, **F1** to connect CS, **G1** for SCK and **H1** for MOSI.
# Protocol
## Errors
Error codes are in brackets:
- **OK** (0) - all OK;
- **BADPAR** (1) - bad parameter (`N`) value (e.g. greater than max available or absent);
- **BADVAL** (2) - bad setter value (absent, text or over range);
- **WRONGLEN** (3) - (only for CAN bus, you can't meet in text protocol) wrong CAN message length;
- **BADCMD** (4) - unknown command, in case of USB proto user will see full command list instead of this error;
- **CANTRUN** (5) - can't run required function.
## USB
Used simple text protocol each string should contain one command and ends with `'\n'`.
Uppercase N at the end of command means parameter number (No of motor, button, ADC channel etc).
Getters and action commands have simplest format `command[N]`: some commands have no parameter,
other have two variants - with and without parameter; wariant without parameter will act on all
parameters (e.g. getter for all buttons) - in this case `N` enclosed in square brackets.
Setters have format `command[N] = value`. The `value` is integer number, so in case floating values
you need to multiply it by 1000 and write result. So, voltage and temperature are measured in millivolts
and thousandths of degC respectively.
Some commands (especially that have no CAN analogue) have non-standard format described later.
They are not intended to be used in automatic control systems, only in manual mode.
Answer for every (excluding special) setter and getter in case of success is `command[N]=value`
showing current value for getter or new value for setter.
In case of error you will see one of error mesages (message `OK` with errcode=0 usually not shown).
Also you can get such answers:
- `BADCMD` - wrong command (not in dictionary);
- `BADARGS` - bad arguments format (e.g. for command `cansend` etc);
- `FAIL` - if something wrong and parser got impermissible error code.
In following list letter `G` means "getter", `S` - "setter", no of them - custom USB-only command.
The number in brackets is CAN command code. The asterisk following command means that it isn't implemented yet (and maybe
will be never implemented).
### absposN (35) GS
Absolute stepper position in steps, setter just changes current value. E.g. you want to set current position
as zero (be carefull: `gotoz` will zero position again on a zero-point limit switch). Maximum absolute value is `maxstepsN`.
### accelN (17) GS
Stepper acceleration/deceleration on ramp (steps/s^2), only positive. Maximum value is `ACCELMAXSTEPS` from `flash.h`.
### adcN (4) G
ADC value (N=0..3).
### buttonN (5) G
Given (N=0..6) buttons' state. If number is right, returns two strings: `buttonN=state` (where `state` is
`none`, `press`, `hold` or `release`) and `buttontmN=time` (where `time` is time from start of last event).
!!!NOTE: Button numbering starts from 0, not 1 as shown on PCB!!!
### canerrcodes
Print last CAN errcodes.
Print "No errors" or last error code.
### canfilter DATA
CAN bus hardware filters, format: bank# FIFO# mode(M/I) num0 [num1 [num2 [num3]]] .
By default have two filters allowing to listen any CAN ID:
Filter 0, FIFO0 in MASK mode: ID=0x01, MASK=0x01
Filter 1, FIFO1 in MASK mode: ID=0x00, MASK=0x01
### canflood ID DATA
Send or clear (if empty) flood message: ID byte0 ... byteN.
On empy message return `NO ID given, send nothing!` (and stops flooding), or `Message parsed OK`.
### canfloodT N
Flood period, N in milliseconds (N >= 0ms).
### canid [ID]
Get or set CAN ID of device. Default CAN ID is "1".
### canignore [ID]
Software ignore list (max 10 IDs), negative to delete all, non-negative to add next.
### canincrflood ID
Send incremental flood message with given ID. Message have uint32_t little endian type and increments
for each packet starting from 0. Empty command stops flooding (`canflood` too).
### canpause
Pause filtered IN packets displaying. Returns `Pause CAN messages`.
### canreinit
Reinit CAN with last settings. Returns `OK`.
### canresume
Resume filtered IN packets displaying, returns `RESUME CAN messages`.
### cansend ID [data]
Send data over CAN with given ID. If `data` is omitted, send empty message.
In case of absence of `ACK` you can get message `CAN bus is off, try to restart it`.
### canspeed N
CAN bus speed (in kbps, 50 <= N <= 1500)
In case of setter, store new speed value in global parameters (and if you call `saveconf` later, it will be saved in flash memory).
### canstat
Get CAN bus status: values of registers `CAN->MSR`, `CAN->TSR`, `CAN->RF0R` and `CAN->RF1F`.
### diagn[N] (37) G *
DIAG state of motor N (or all)\n"
### drvtypeN (45) GS
Nth driver type (0 - only step/dir, 1 - UART, 2 - SPI, 3 - reserved). This parameter is taken from `.drvtype` bits of `motflags` settings parameter.
### dumperr
Dump error codes. Returns:
Error codes:
0 - OK
1 - BADPAR
2 - BADVAL
3 - WRONGLEN
4 - BADCMD
5 - CANTRUN
### dumpcmd
Dump command codes. Returns all list of CAN bus command codes.
### dumpconf
Dump current configuration. Returns a lot of information both common (like CAN bus speed, ID and so on) and
for each motor driver. You can call independeng getters for each of this parameter.
### dumpmotflags
Dump motor flags' bits (for `motflagsN`) and reaction to limit switches (`eswreact`) values:
Motor flags:
bit0 - 0: reverse - invert motor's rotation
bit1 - 1: [reserved]
bit2 - 2: [reserved]
bit3 - 3: donthold - clear motor's power after stop
bit4 - 4: eswinv - inverse end-switches (1->0 instead of 0->1)
bit5 - 5: [reserved]
bit6 - 6,7: drvtype - driver type (0 - only step/dir, 1 - UART, 2 - SPI, 3 - reserved)
End-switches reaction:
0 - ignore end-switches
1 - stop @ esw in any moving direction
2 - stop only when moving in given direction (e.g. to minus @ESW0)
### dumpstates
Dump motors' state codes (for getter `stateN`):
Motor's state codes:
0 - relax
1 - acceleration
2 - moving
3 - moving at lowest speed
4 - deceleration
5 - stalled (not used here!)
6 - error
### emstop[N] (29 with `N` and 31 without)
Emergency stop Nth motor or all (if `N` absent). Returns `OK` or error text.
"eraseflash [=N] (38) erase flash data storage (full or only N'th page of it)\n"
"esw[N] (6) G end-switches state\n"
"eswreactN (24) GS end-switches reaction (0 - ignore, 1 - stop@any, 2 - stop@zero)\n"
"gotoN (26) GS move motor to given absolute position\n"
"gotozN (32) find zero position & refresh counters\n"
"gpioconfN* - GS GPIO configuration (0 - PUin, 1 - PPout, 2 - ODout), N=0..2\n"
"gpioN* (12) GS GPIO values, N=0..2\n"
help
"maxspeedN (18) GS max speed (steps per sec)\n"
"maxstepsN (21) GS max steps (from zero ESW)\n"
"mcut (7) G MCU T\n"
"mcuvdd (8) G MCU Vdd\n"
"microstepsN (16) GS microsteps settings (2^0..2^9)\n"
"minspeedN (19) min speed (steps per sec)\n"
"motcurrentN (46) GS motor current (1..32 for 1/32..32/32 of max current)\n"
"motflagsN (23) motorN flags\n"
"motmul* (36) GS external multiplexer status (<0 - disable, 0..7 - enable and set address)\n"
"motno (44) GS motor number for next `pdn` commands\n"
"motreinit (25) re-init motors after configuration changed\n"
"pdnN (43) GS read/write TMC2209 registers over uart @ motor0\n"
"ping (1)- echo given command back\n"
"relposN (27) GS relative move (get remaining)\n"
"relslowN (28) GS like 'relpos' but with slowest speed\n"
"reset (9) software reset\n"
"saveconf (13) save current configuration\n"
"screen* - GS screen enable (1) or disable (0)\n"
"speedlimit (20) G limiting speed for current microsteps setting\n"
"stateN (33) G motor state (0-relax, 1-accel, 2-move, 3-mvslow, 4-decel, 5-stall, 6-err)\n"
"stopN (30) stop motor with deceleration\n"
"time (10) G time from start (ms)\n"
"tmcbus* - GS TMC control bus (0 - USART, 1 - SPI)\n"
"udata* (39) GS data by usart in slave mode (text strings, '\\n'-terminated)\n"
"usartstatus* (40) GS status of USART1 (0 - off, 1 - master, 2 - slave)\n"
"vdrive (41) G approx voltage on Vdrive\n"
"vfive (42) G approx voltage on 5V bus\n"
## CAN bus
Default CAN ID is 1.

View File

@ -37,6 +37,7 @@ static int8_t first_nonfree_idx = -1; // index of first data cell
static uint16_t oldspeed = 100; // speed of last init static uint16_t oldspeed = 100; // speed of last init
uint32_t floodT = FLOOD_PERIOD_MS; // flood period in ms uint32_t floodT = FLOOD_PERIOD_MS; // flood period in ms
static uint8_t incrflood = 0; // ==1 for incremental flooding static uint8_t incrflood = 0; // ==1 for incremental flooding
static uint32_t incrmessagectr = 0; // counter for incremental flooding
static uint32_t last_err_code = 0; static uint32_t last_err_code = 0;
static CAN_status can_status = CAN_STOP; static CAN_status can_status = CAN_STOP;
@ -130,7 +131,7 @@ so if TBS1=4 and TBS2=3, sum=8, bit sampling freq is 48/8 = 6MHz
void CAN_setup(uint16_t speed){ void CAN_setup(uint16_t speed){
if(speed == 0) speed = oldspeed; if(speed == 0) speed = oldspeed;
else if(speed < 50) speed = 50; else if(speed < 50) speed = 50;
else if(speed > 3000) speed = 3000; else if(speed > 1500) speed = 1500;
oldspeed = speed; oldspeed = speed;
uint32_t tmout = 10000; uint32_t tmout = 10000;
/* Enable the peripheral clock CAN */ /* Enable the peripheral clock CAN */
@ -240,7 +241,6 @@ void CAN_proc(){
CAN_setup(0); CAN_setup(0);
} }
static uint32_t lastFloodTime = 0; static uint32_t lastFloodTime = 0;
static uint32_t incrmessagectr = 0;
if(flood_msg && (Tms - lastFloodTime) >= floodT){ // flood every ~5ms if(flood_msg && (Tms - lastFloodTime) >= floodT){ // flood every ~5ms
lastFloodTime = Tms; lastFloodTime = Tms;
CAN_send(flood_msg->data, flood_msg->length, flood_msg->ID); CAN_send(flood_msg->data, flood_msg->length, flood_msg->ID);
@ -305,8 +305,11 @@ CAN_status CAN_send(uint8_t *msg, uint8_t len, uint16_t target_id){
} }
void CAN_flood(CAN_message *msg, int incr){ void CAN_flood(CAN_message *msg, int incr){
if(incr){ incrflood = 1; return; } if(incr){
incrflood = 0; incrmessagectr = 0;
incrflood = 1;
return;
}else incrflood = 0;
if(!msg) flood_msg = NULL; if(!msg) flood_msg = NULL;
else{ else{
memcpy(&loc_flood_msg, msg, sizeof(CAN_message)); memcpy(&loc_flood_msg, msg, sizeof(CAN_message));

View File

@ -108,6 +108,11 @@ errcodes cu_emstop(uint8_t _U_ par, int32_t _U_ *val){
return ERR_OK; return ERR_OK;
} }
errcodes cu_emstopall(uint8_t _U_ par, int32_t _U_ *val){
for(int i = 0; i < MOTORSNO; ++i) emstopmotor(i);
return ERR_OK;
}
errcodes cu_eraseflash(uint8_t _U_ par, int32_t _U_ *val){ errcodes cu_eraseflash(uint8_t _U_ par, int32_t _U_ *val){
NOPARCHK(par); NOPARCHK(par);
if(ISSETTER(par)){ if(ISSETTER(par)){

View File

@ -113,6 +113,7 @@ errcodes cu_canid(uint8_t par, int32_t *val);
errcodes cu_diagn(uint8_t par, int32_t *val); errcodes cu_diagn(uint8_t par, int32_t *val);
errcodes cu_drvtype(uint8_t par, int32_t *val); errcodes cu_drvtype(uint8_t par, int32_t *val);
errcodes cu_emstop(uint8_t par, int32_t *val); errcodes cu_emstop(uint8_t par, int32_t *val);
errcodes cu_emstopall(uint8_t par, int32_t *val);
errcodes cu_eraseflash(uint8_t par, int32_t *val); errcodes cu_eraseflash(uint8_t par, int32_t *val);
errcodes cu_esw(uint8_t par, int32_t *val); errcodes cu_esw(uint8_t par, int32_t *val);
errcodes cu_eswreact(uint8_t par, int32_t *val); errcodes cu_eswreact(uint8_t par, int32_t *val);

View File

@ -32,12 +32,12 @@ static const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE;
// max amount of Config records stored (will be recalculate in flashstorage_init() // max amount of Config records stored (will be recalculate in flashstorage_init()
static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here
#define DEFMF {.donthold = 1, .drvtype = DRVTYPE_UART} #define DEFMF {.donthold = 1, .drvtype = DRVTYPE_SIMPLE}
#define USERCONF_INITIALIZER { \ #define USERCONF_INITIALIZER { \
.userconf_sz = sizeof(user_conf) \ .userconf_sz = sizeof(user_conf) \
,.CANspeed = 100 \ ,.CANspeed = 100 \
,.CANID = 0xaa \ ,.CANID = 1 \
,.microsteps = {32,32,32,32,32,32,32,32}\ ,.microsteps = {32,32,32,32,32,32,32,32}\
,.accel = {500,500,500,500,500,500,500,500} \ ,.accel = {500,500,500,500,500,500,500,500} \
,.maxspd = {2000,2000,2000,2000,2000,2000,2000,2000} \ ,.maxspd = {2000,2000,2000,2000,2000,2000,2000,2000} \
@ -203,8 +203,8 @@ int erase_storage(int npage){
int fn_dumpconf(uint32_t _U_ hash, char _U_ *args){ // "dumpconf" (3271513185) int fn_dumpconf(uint32_t _U_ hash, char _U_ *args){ // "dumpconf" (3271513185)
#ifdef EBUG #ifdef EBUG
USB_sendstr("flashsize="); printu(FLASH_SIZE); USB_putbyte('*'); USB_sendstr("flashsize="); printu(FLASH_SIZE); USB_sendstr("kB\nblocksize=");
printu(FLASH_blocksize); USB_putbyte('='); printu(FLASH_SIZE*FLASH_blocksize); printu(FLASH_blocksize);
newline(); newline();
#endif #endif
USB_sendstr("userconf_addr="); printuhex((uint32_t)Flash_Data); USB_sendstr("userconf_addr="); printuhex((uint32_t)Flash_Data);
@ -230,7 +230,7 @@ int fn_dumpconf(uint32_t _U_ hash, char _U_ *args){ // "dumpconf" (3271513185)
printu(the_conf.motcurrent[i]); printu(the_conf.motcurrent[i]);
PROPNAME("motflags"); PROPNAME("motflags");
printuhex(*((uint8_t*)&the_conf.motflags[i])); printuhex(*((uint8_t*)&the_conf.motflags[i]));
PROPNAME("eswreaction"); PROPNAME("eswreact");
printu(the_conf.ESW_reaction[i]); printu(the_conf.ESW_reaction[i]);
#undef PROPNAME #undef PROPNAME
} }

View File

@ -63,6 +63,7 @@ typedef struct{
* struct to save user configurations * struct to save user configurations
*/ */
typedef struct __attribute__((packed, aligned(4))){ typedef struct __attribute__((packed, aligned(4))){
uint32_t maxsteps[MOTORSNO]; // maximal amount of steps
uint16_t userconf_sz; // "magick number" uint16_t userconf_sz; // "magick number"
uint16_t CANspeed; // default CAN speed uint16_t CANspeed; // default CAN speed
uint16_t CANID; // identifier uint16_t CANID; // identifier
@ -70,11 +71,9 @@ typedef struct __attribute__((packed, aligned(4))){
uint16_t accel[MOTORSNO]; // acceleration/deceleration (steps/s^2) uint16_t accel[MOTORSNO]; // acceleration/deceleration (steps/s^2)
uint16_t maxspd[MOTORSNO]; // max motor speed (steps per second) uint16_t maxspd[MOTORSNO]; // max motor speed (steps per second)
uint16_t minspd[MOTORSNO]; // min motor speed (steps per second) uint16_t minspd[MOTORSNO]; // min motor speed (steps per second)
uint32_t maxsteps[MOTORSNO]; // maximal amount of steps
motflags_t motflags[MOTORSNO]; // motor's flags motflags_t motflags[MOTORSNO]; // motor's flags
uint8_t ESW_reaction[MOTORSNO]; // end-switches reaction (esw_react) uint8_t ESW_reaction[MOTORSNO]; // end-switches reaction (esw_react)
uint8_t motcurrent[MOTORSNO]; // IRUN as fraction of max current (1..32) uint8_t motcurrent[MOTORSNO]; // IRUN as fraction of max current (1..32)
uint8_t isSPI; // ==1 if there's SPI drivers instead of UART
} user_conf; } user_conf;
extern user_conf the_conf; // global user config (read from FLASH to RAM) extern user_conf the_conf; // global user config (read from FLASH to RAM)

View File

@ -76,7 +76,7 @@ static IRQn_Type motirqs[MOTORSNO] = {
// return two bits: 0 - ESW0, 1 - ESW1 (if inactive -> 1; if active -> 0) // return two bits: 0 - ESW0, 1 - ESW1 (if inactive -> 1; if active -> 0)
uint8_t ESW_state(uint8_t MOTno){ uint8_t ESW_state(uint8_t MOTno){
uint8_t val = 0; uint8_t val = 0;
if(the_conf.isSPI){ // only ESW0 used if(the_conf.motflags[MOTno].drvtype == DRVTYPE_SPI){ // only ESW0 used
val = ((ESWports[MOTno][0]->IDR & ESWpins[MOTno][0]) ? 1 : 0); val = ((ESWports[MOTno][0]->IDR & ESWpins[MOTno][0]) ? 1 : 0);
if(the_conf.motflags[MOTno].eswinv) val ^= 1; if(the_conf.motflags[MOTno].eswinv) val ^= 1;
return val; return val;

View File

@ -170,14 +170,13 @@ static char *fnname(const char *cmd){
static const char *fhdr = static const char *fhdr =
"int parsecmd(const char *str){\n\ "int parsecmd(const char *str){\n\
char cmd[CMD_MAXLEN + 1];\n\
if(!str || !*str) return RET_CMDNOTFOUND;\n\ if(!str || !*str) return RET_CMDNOTFOUND;\n\
int i = 0;\n\ int i = 0;\n\
while(*str > '@' && i < CMD_MAXLEN){ cmd[i++] = *str++; }\n\ while(*str > '@' && i < CMD_MAXLEN){ lastcmd[i++] = *str++; }\n\
cmd[i] = 0;\n\ lastcmd[i] = 0;\n\
while(*str && *str <= ' ') ++str;\n\ while(*str && *str <= ' ') ++str;\n\
char *args = (char*) str;\n\ char *args = (char*) str;\n\
uint32_t h = hashf(cmd);\n\ uint32_t h = hashf(lastcmd);\n\
switch(h){\n\n" switch(h){\n\n"
; ;
static const char *ffooter = static const char *ffooter =
@ -195,12 +194,15 @@ static const char *headercontent =
#endif\n\n\ #endif\n\n\
#define CMD_MAXLEN (32)\n\n\ #define CMD_MAXLEN (32)\n\n\
enum{\n\ enum{\n\
RET_HELP = -3,\n\
RET_CMDNOTFOUND = -2,\n\ RET_CMDNOTFOUND = -2,\n\
RET_WRONGCMD = -1,\n\ RET_WRONGCMD = -1,\n\
RET_BAD = 0,\n\ RET_GOOD = 0,\n\
RET_GOOD = 1\n\ RET_BAD = 1\n\
};\n\n\ };\n\n\
int parsecmd(const char *cmdwargs);\n\n"; int parsecmd(const char *cmdwargs);\n\n\
extern char lastcmd[];\n\n";
static const char *sw = static const char *sw =
" case CMD_%s:\n\ " case CMD_%s:\n\
return fn_%s(h, args);\n\ return fn_%s(h, args);\n\
@ -213,7 +215,8 @@ static const char *srchdr =
#include \"%s\"\n\n\ #include \"%s\"\n\n\
#ifndef WAL\n\ #ifndef WAL\n\
#define WAL __attribute__ ((weak, alias (\"__f1\")))\n\ #define WAL __attribute__ ((weak, alias (\"__f1\")))\n\
#endif\n\nstatic int __f1(uint32_t _U_ h, char _U_ *a){return 1;}\n\n" #endif\n\nstatic int __f1(uint32_t _U_ h, char _U_ *a){return 1;}\n\n\
char lastcmd[CMD_MAXLEN + 1];\n\n"
; ;
static void build(strhash *H, int hno, int hlen){ static void build(strhash *H, int hno, int hlen){

View File

@ -8,10 +8,10 @@
#define WAL __attribute__ ((weak, alias ("__f1"))) #define WAL __attribute__ ((weak, alias ("__f1")))
#endif #endif
char lastcmd[CMD_MAXLEN + 1];
static int __f1(uint32_t _U_ h, char _U_ *a){return 1;} static int __f1(uint32_t _U_ h, char _U_ *a){return 1;}
char lastcmd[CMD_MAXLEN + 1];
int fn_abspos(uint32_t _U_ hash, char _U_ *args) WAL; // "abspos" (3056382221) int fn_abspos(uint32_t _U_ hash, char _U_ *args) WAL; // "abspos" (3056382221)
int fn_accel(uint32_t _U_ hash, char _U_ *args) WAL; // "accel" (1490521981) int fn_accel(uint32_t _U_ hash, char _U_ *args) WAL; // "accel" (1490521981)
@ -76,6 +76,8 @@ int fn_gpio(uint32_t _U_ hash, char _U_ *args) WAL; // "gpio" (4286324660)
int fn_gpioconf(uint32_t _U_ hash, char _U_ *args) WAL; // "gpioconf" (1309721562) int fn_gpioconf(uint32_t _U_ hash, char _U_ *args) WAL; // "gpioconf" (1309721562)
int fn_help(uint32_t _U_ hash, char _U_ *args) WAL; // "help" (4288288686)
int fn_maxspeed(uint32_t _U_ hash, char _U_ *args) WAL; // "maxspeed" (1498078812) int fn_maxspeed(uint32_t _U_ hash, char _U_ *args) WAL; // "maxspeed" (1498078812)
int fn_maxsteps(uint32_t _U_ hash, char _U_ *args) WAL; // "maxsteps" (1506667002) int fn_maxsteps(uint32_t _U_ hash, char _U_ *args) WAL; // "maxsteps" (1506667002)
@ -244,6 +246,9 @@ int parsecmd(const char *str){
case CMD_GPIOCONF: case CMD_GPIOCONF:
return fn_gpioconf(h, args); return fn_gpioconf(h, args);
break; break;
case CMD_HELP:
return fn_help(h, args);
break;
case CMD_MAXSPEED: case CMD_MAXSPEED:
return fn_maxspeed(h, args); return fn_maxspeed(h, args);
break; break;

View File

@ -5,10 +5,11 @@
#define CMD_MAXLEN (32) #define CMD_MAXLEN (32)
enum{ enum{
RET_HELP = -3,
RET_CMDNOTFOUND = -2, RET_CMDNOTFOUND = -2,
RET_WRONGCMD = -1, RET_WRONGCMD = -1,
RET_BAD = 0, RET_GOOD = 0,
RET_GOOD = 1 RET_BAD = 1
}; };
int parsecmd(const char *cmdwargs); int parsecmd(const char *cmdwargs);
@ -47,6 +48,7 @@ extern char lastcmd[];
#define CMD_GOTOZ (3178103736) #define CMD_GOTOZ (3178103736)
#define CMD_GPIO (4286324660) #define CMD_GPIO (4286324660)
#define CMD_GPIOCONF (1309721562) #define CMD_GPIOCONF (1309721562)
#define CMD_HELP (4288288686)
#define CMD_MAXSPEED (1498078812) #define CMD_MAXSPEED (1498078812)
#define CMD_MAXSTEPS (1506667002) #define CMD_MAXSTEPS (1506667002)
#define CMD_MCUT (4022718) #define CMD_MCUT (4022718)

View File

@ -30,6 +30,7 @@
"gotozN - find zero position & refresh counters\n" "gotozN - find zero position & refresh counters\n"
"gpioconfN* - GS GPIO configuration (0 - PUin, 1 - PPout, 2 - ODout), N=0..2\n" "gpioconfN* - GS GPIO configuration (0 - PUin, 1 - PPout, 2 - ODout), N=0..2\n"
"gpioN* - GS GPIO values, N=0..2\n" "gpioN* - GS GPIO values, N=0..2\n"
"help - print this help\n"
"maxspeedN - GS max speed (steps per sec)\n" "maxspeedN - GS max speed (steps per sec)\n"
"maxstepsN - GS max steps (from zero ESW)\n" "maxstepsN - GS max steps (from zero ESW)\n"
"mcut - G MCU T\n" "mcut - G MCU T\n"

View File

@ -8,3 +8,5 @@ gcc hdr.c test.c strfunc.c -o test
./test "esw45 = some text" ./test "esw45 = some text"
./test "goto 55 = " ./test "goto 55 = "
./test "stop 3256" ./test "stop 3256"
./test "mcut"

BIN
F3:F303/Multistepper/hashgen/test Executable file

Binary file not shown.

View File

@ -7,9 +7,9 @@
static int noargs(uint32_t hash){ static int noargs(uint32_t hash){
switch(hash){ switch(hash){
case CMD_REBOOT: printf("REBOOT\n"); break; case CMD_RESET: printf("REBOOT\n"); break;
case CMD_TIME: printf("TIME!\n"); break; case CMD_TIME: printf("TIME!\n"); break;
case CMD_TEMP: printf("Temp\n"); break; case CMD_MCUT: printf("Temp\n"); break;
default: printf("Unknown hash 0x%x\n", hash); return 0; default: printf("Unknown hash 0x%x\n", hash); return 0;
} }
return 1; return 1;
@ -30,7 +30,7 @@ static int withparno(uint32_t hash, char *args){
switch(hash){ switch(hash){
case CMD_ESW: fname = "ESW"; break; case CMD_ESW: fname = "ESW"; break;
case CMD_GOTO: fname = "GOTO"; break; case CMD_GOTO: fname = "GOTO"; break;
case CMD_POS: fname = "POS"; break; case CMD_ABSPOS: fname = "ABSPOS"; break;
case CMD_STOP: fname = "STOP"; break; case CMD_STOP: fname = "STOP"; break;
default: fname = "unknown"; default: fname = "unknown";
} }

View File

@ -30,6 +30,7 @@ goto
gotoz gotoz
gpioconf gpioconf
gpio gpio
help
maxspeed maxspeed
maxsteps maxsteps
mcut mcut

View File

@ -288,6 +288,7 @@ int fn_canfilter(uint32_t _U_ hash, char *args){
int fn_canflood(uint32_t _U_ hash, char *args){ int fn_canflood(uint32_t _U_ hash, char *args){
CAN_flood(parseCANmsg(args), 0); CAN_flood(parseCANmsg(args), 0);
USB_sendstr("Simple flooding is ON (send with empty ID to stop)\n");
return RET_GOOD; return RET_GOOD;
} }
@ -333,8 +334,8 @@ int fn_canerrcodes(uint32_t _U_ hash, char _U_ *args){
} }
int fn_canincrflood(uint32_t _U_ hash, char _U_ *args){ int fn_canincrflood(uint32_t _U_ hash, char _U_ *args){
CAN_flood(NULL, 1); CAN_flood(parseCANmsg(args), 1);
USB_sendstr("Incremental flooding is ON ('F' to off)\n"); USB_sendstr("Incremental flooding is ON (send with empty ID to stop)\n");
return RET_GOOD; return RET_GOOD;
} }
@ -346,18 +347,17 @@ int fn_canspeed(uint32_t _U_ hash, char _U_ *args){
return RET_GOOD; return RET_GOOD;
} }
if(N < 50){ if(N < 50){
USB_sendstr("canspeed="); USND("Lower speed is 50kbps");
USB_sendstr(u2str(CAN_speed()));
newline();
return RET_GOOD; return RET_GOOD;
}else if(N > 3000){ }else if(N > 1500){
USB_sendstr("Highest speed is 3000kbps"); USND("Highest speed is 1500kbps");
return RET_GOOD; return RET_GOOD;
} }
CAN_reinit((uint16_t)N); CAN_reinit((uint16_t)N);
// theconf.canspeed = N; uint32_t regval = 4500 / N;
the_conf.CANspeed = 4500 * regval;
USB_sendstr("Reinit CAN bus with speed "); USB_sendstr("Reinit CAN bus with speed ");
printu(N); USB_sendstr("kbps"); newline(); printu(the_conf.CANspeed); USB_sendstr("kbps"); newline();
return RET_GOOD; return RET_GOOD;
} }
@ -529,7 +529,8 @@ static int canusb_function(uint32_t hash, char *args){
} }
USB_sendstr("button"); USB_putbyte('0'+PARBASE(par)); USB_sendstr("button"); USB_putbyte('0'+PARBASE(par));
USB_putbyte('='); USB_sendstr(kstate); USB_putbyte('='); USB_sendstr(kstate);
USB_sendstr("\nbuttontm="); USB_sendstr(u2str(val)); USB_sendstr("\nbuttontm"); USB_putbyte('0'+PARBASE(par));
USB_putbyte('='); USB_sendstr(u2str(val));
newline(); newline();
return RET_GOOD; return RET_GOOD;
break; break;
@ -552,7 +553,9 @@ static int canusb_function(uint32_t hash, char *args){
e = cu_drvtype(par, &val); e = cu_drvtype(par, &val);
break; break;
case CMD_EMSTOP: case CMD_EMSTOP:
e = cu_emstop(par, &val); if(par == CANMESG_NOPAR) e = cu_emstopall(par, &val);
else e = cu_emstop(par, &val);
if(e == ERR_OK){ USND("OK"); return RET_GOOD;}
break; break;
case CMD_ESWREACT: case CMD_ESWREACT:
e = cu_eswreact(par, &val); e = cu_eswreact(par, &val);
@ -682,6 +685,7 @@ int fn_goto(uint32_t _U_ hash, char _U_ *args) AL; //* "goto" (4286309438)
int fn_gotoz(uint32_t _U_ hash, char _U_ *args) AL; //* "gotoz" (3178103736) int fn_gotoz(uint32_t _U_ hash, char _U_ *args) AL; //* "gotoz" (3178103736)
int fn_gpio(uint32_t _U_ hash, char _U_ *args) AL; //* "gpio" (4286324660) int fn_gpio(uint32_t _U_ hash, char _U_ *args) AL; //* "gpio" (4286324660)
int fn_gpioconf(uint32_t _U_ hash, char _U_ *args) AL; //* "gpioconf" (1309721562) int fn_gpioconf(uint32_t _U_ hash, char _U_ *args) AL; //* "gpioconf" (1309721562)
int fn_help(uint32_t _U_ hash, char _U_ *args){return RET_HELP;} // "help" (4288288686)
int fn_maxspeed(uint32_t _U_ hash, char _U_ *args) AL; //* "maxspeed" (1498078812) int fn_maxspeed(uint32_t _U_ hash, char _U_ *args) AL; //* "maxspeed" (1498078812)
int fn_maxsteps(uint32_t _U_ hash, char _U_ *args) AL; //* "maxsteps" (1506667002) int fn_maxsteps(uint32_t _U_ hash, char _U_ *args) AL; //* "maxsteps" (1506667002)
int fn_mcut(uint32_t _U_ hash, char _U_ *args) AL; // "mcut" (4022718) int fn_mcut(uint32_t _U_ hash, char _U_ *args) AL; // "mcut" (4022718)
@ -717,8 +721,9 @@ int fn_vfive(uint32_t _U_ hash, char _U_ *args) AL; // "vfive" (3017477285)
const char *cmd_parser(const char *txt){ const char *cmd_parser(const char *txt){
int ret = parsecmd(txt); int ret = parsecmd(txt);
switch(ret){ switch(ret){
case RET_CMDNOTFOUND: return helpstring; break; case RET_HELP: return helpstring; break;
case RET_WRONGCMD: return "Wrong command parameters\n"; break; case RET_CMDNOTFOUND: return "BADCMD\n"; break;
case RET_WRONGCMD: return "BADARGS\n"; break;
case RET_GOOD: return NULL; break; case RET_GOOD: return NULL; break;
default: return "FAIL\n"; break; default: return "FAIL\n"; break;
} }

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "114" #define BUILD_NUMBER "119"
#define BUILD_DATE "2024-08-15" #define BUILD_DATE "2024-08-16"