some fixes of old bugs

This commit is contained in:
Edward Emelianov 2025-02-05 17:49:07 +03:00
parent a22776d487
commit 6eb0662f69
28 changed files with 1467 additions and 566 deletions

View File

@ -325,7 +325,7 @@ will be never implemented).
### absposN (35) GS ### absposN (35) GS
Absolute stepper position in steps, setter just changes current value. E.g. you want to set current position 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`. as zero (be carefull: `gotoz` will zero position again on a zero-point limit switch). Maximum absolute value is `maxstepsN`.
### accelN (17) GS ### accelN (17) GS
Stepper acceleration/deceleration on ramp (steps/s^2), only positive. Maximum value is `ACCELMAXSTEPS` from `flash.h`. Stepper acceleration/deceleration on ramp (steps/s^2), only positive. Maximum value is `ACCELMAXSTEPS` from `flash.h`.
### adcN (4) G ### adcN (4) G
ADC value (N=0..3). ADC value (N=0..3).
@ -349,7 +349,7 @@ 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`. On empy message return `NO ID given, send nothing!` (and stops flooding), or `Message parsed OK`.
### canfloodT N ### canfloodT N
Flood period, N in milliseconds (N >= 0ms). Flood period, N in milliseconds (N >= 0ms).
### canid [ID] ### canid [ID]
Get or set CAN ID of device. Default CAN ID is "1". Get or set CAN ID of device. Default CAN ID is "1".
### canignore [ID] ### canignore [ID]
Software ignore list (max 10 IDs), negative to delete all, non-negative to add next. Software ignore list (max 10 IDs), negative to delete all, non-negative to add next.
@ -370,8 +370,8 @@ 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). 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 ### canstat
Get CAN bus status: values of registers `CAN->MSR`, `CAN->TSR`, `CAN->RF0R` and `CAN->RF1F`. Get CAN bus status: values of registers `CAN->MSR`, `CAN->TSR`, `CAN->RF0R` and `CAN->RF1F`.
### diagn[N] (37) G * ### diagn[N] (37) G
DIAG state of motor N (or all)\n" DIAG state of motor N (or all, in this case motor 0 is LSB of answer etc.). One means "all OK", zero is error state.
### drvtypeN (45) GS ### 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. 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 ### dumperr
@ -420,7 +420,7 @@ Dump motors' state codes (for getter `stateN`):
5 - stalled (not used here!) 5 - stalled (not used here!)
6 - error 6 - error
### emstop[N] (29 with `N` and 31 without) ### emstop[N] (29)
Emergency stop Nth motor or all (if `N` absent). Returns `OK` or error text. Emergency stop Nth motor or all (if `N` absent). Returns `OK` or error text.
### eraseflash [=N] (38) ### eraseflash [=N] (38)
Erase flash data storage (full or only N'th page of it). Use this option only if you have problems Erase flash data storage (full or only N'th page of it). Use this option only if you have problems
@ -429,8 +429,11 @@ when try to save current configuration.
Get end-switches state. Return two bits (for limit switches 0 and 1): 1 means "active", 0 - "passive". Get end-switches state. Return two bits (for limit switches 0 and 1): 1 means "active", 0 - "passive".
If you use SPI-based driver, only one switch available, so return will be 1-bit. If you use SPI-based driver, only one switch available, so return will be 1-bit.
### eswreactN (24) GS ### eswreactN (24) GS
End-switches reaction: 0 - ignore, 1 - stop on any limit switch (both 0 and 1; moving will be available only backwards), End-switches (limit-switches) reaction: 0 - ignore both limits;
2 - stop only on switch 0. You can modify this values on-the-fly (but only when steppers aren't moving). This can be usefull, 1 - ignore ESW1, stop on ESW0 only when moving to negative direction;
2 - stop on any limit switch independently from direction;
3 - stop only on switch corresponding to moving direction (i.e. ESW0 for negative and ESW1 for positive).
You can modify this values on-the-fly (but only when steppers aren't moving). This can be usefull,
for example, to rotate filter turret into given position using switch 1 to both as limit switch and position stopper. for example, to rotate filter turret into given position using switch 1 to both as limit switch and position stopper.
But even in state 0 (ignore) active state of both switches estimates as error and you won't be able to move motor. But even in state 0 (ignore) active state of both switches estimates as error and you won't be able to move motor.
### gotoN (26) GS ### gotoN (26) GS
@ -440,9 +443,10 @@ Find zero position & refresh counters. The motor would rotate in reverse directi
steps (parameter `maxsteps` of configuration) is exhausted. steps (parameter `maxsteps` of configuration) is exhausted.
### gpioconfN* GS ### gpioconfN* GS
GPIO configuration (0 - PUin, 1 - PPout, 2 - ODout), N=0..2. GPIO configuration (0 - PUin, 1 - PPout, 2 - ODout), N=0..2.
### gpio[N]* (12) GS ### gpio[N] (12) GS
GPIO values, N=0..2. Without `N` run for all GPIOs (each byte is state: 0/1). GPIO values, N=0..2. Without `N` run for all GPIOs (each bit is state: 0/1, started from LSB which is zero channel).
By default GPIOs are pulled up inputs. By default GPIOs are pulled up inputs, so setters won't do any effect. To reconfigure them as outputs use gpioconf when (if)
it will be available.
### help ### help
Show this help. Show this help.
### maxspeedN (18) GS ### maxspeedN (18) GS

View File

@ -126,9 +126,11 @@ uint16_t getADCval(int nch){
PIX_SORT(p[4], p[2]) ; PIX_SORT(p[4], p[2]) ;
#undef PIX_SORT #undef PIX_SORT
#undef PIX_SWAP #undef PIX_SWAP
/*
#ifdef EBUG #ifdef EBUG
DBG("val: "); printu(p[4]); newline(); DBG("val: "); printu(p[4]); newline();
#endif #endif
*/
return p[4]; return p[4];
} }
@ -136,9 +138,11 @@ uint16_t getADCval(int nch){
int32_t getADCvoltage(int nch){ int32_t getADCvoltage(int nch){
float v = getADCval(nch) * 3.3; float v = getADCval(nch) * 3.3;
v /= 4.096f; // 12bit ADC v /= 4.096f; // 12bit ADC
/*
#ifdef EBUG #ifdef EBUG
DBG("v="); printf(v); newline(); DBG("v="); printf(v); newline();
#endif #endif
*/
return (uint32_t) v; return (uint32_t) v;
} }
@ -150,9 +154,11 @@ int32_t getMCUtemp(){
temperature *= (110.f - 30.f); temperature *= (110.f - 30.f);
temperature /= (float)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR); temperature /= (float)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR);
temperature += 30.f; temperature += 30.f;
/*
#ifdef EBUG #ifdef EBUG
DBG("t="); printf(temperature); newline(); DBG("t="); printf(temperature); newline();
#endif #endif
*/
return (uint32_t) (temperature*1000.f); return (uint32_t) (temperature*1000.f);
} }
@ -160,8 +166,10 @@ int32_t getMCUtemp(){
int32_t getVdd(){ int32_t getVdd(){
float vdd = ((float) *VREFINT_CAL_ADDR) * 3.3f; // 3.3V float vdd = ((float) *VREFINT_CAL_ADDR) * 3.3f; // 3.3V
vdd /= getADCval(ADC_VREF); vdd /= getADCval(ADC_VREF);
/*
#ifdef EBUG #ifdef EBUG
DBG("vdd="); printf(vdd); newline(); DBG("vdd="); printf(vdd); newline();
#endif #endif
*/
return (uint32_t) (vdd * 1000.f); return (uint32_t) (vdd * 1000.f);
} }

View File

@ -21,7 +21,7 @@
#include "flash.h" #include "flash.h"
#include "hardware.h" #include "hardware.h"
#include "strfunc.h" #include "strfunc.h"
#include "usb.h" #include "usb_dev.h"
#ifdef EBUG #ifdef EBUG
#include "proto.h" #include "proto.h"
#endif #endif
@ -350,7 +350,7 @@ TRUE_INLINE void parseCANcommand(CAN_message *msg){
#ifdef EBUG #ifdef EBUG
USB_sendstr("Index = "); USB_sendstr(u2str(Index)); newline(); USB_sendstr("Index = "); USB_sendstr(u2str(Index)); newline();
#endif #endif
if(Index >= CCMD_AMOUNT){ if(Index >= CCMD_AMOUNT || !cancmdlist[Index]){
formerr(msg, ERR_BADCMD); formerr(msg, ERR_BADCMD);
goto sendmessage; goto sendmessage;
} }
@ -440,14 +440,14 @@ static void can_process_fifo(uint8_t fifo_num){
void usb_lp_can1_rx0_isr(){ // Rx FIFO0 (overrun) void usb_lp_can1_rx0_isr(){ // Rx FIFO0 (overrun)
if(CAN->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun if(CAN->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun
CAN->RF0R &= ~CAN_RF0R_FOVR0; CAN->RF0R = CAN_RF0R_FOVR0;
can_status = CAN_FIFO_OVERRUN; can_status = CAN_FIFO_OVERRUN;
} }
} }
void can1_rx1_isr(){ // Rx FIFO1 (overrun) void can1_rx1_isr(){ // Rx FIFO1 (overrun)
if(CAN->RF1R & CAN_RF1R_FOVR1){ if(CAN->RF1R & CAN_RF1R_FOVR1){
CAN->RF1R &= ~CAN_RF1R_FOVR1; CAN->RF1R = CAN_RF1R_FOVR1;
can_status = CAN_FIFO_OVERRUN; can_status = CAN_FIFO_OVERRUN;
} }
} }
@ -457,7 +457,7 @@ void can1_sce_isr(){ // status changed
#ifdef EBUG #ifdef EBUG
last_err_code = CAN->ESR; last_err_code = CAN->ESR;
#endif #endif
CAN->MSR &= ~CAN_MSR_ERRI; CAN->MSR = CAN_MSR_ERRI; // clear flag
// request abort for problem mailbox // request abort for problem mailbox
if(CAN->TSR & CAN_TSR_TERR0) CAN->TSR |= CAN_TSR_ABRQ0; if(CAN->TSR & CAN_TSR_TERR0) CAN->TSR |= CAN_TSR_ABRQ0;
if(CAN->TSR & CAN_TSR_TERR1) CAN->TSR |= CAN_TSR_ABRQ1; if(CAN->TSR & CAN_TSR_TERR1) CAN->TSR |= CAN_TSR_ABRQ1;

View File

@ -25,7 +25,7 @@
#include "pdnuart.h" #include "pdnuart.h"
#include "proto.h" #include "proto.h"
#include "steppers.h" #include "steppers.h"
#include "usb.h" #include "usb_dev.h"
#define NOPARCHK(par) do{if(PARBASE(par) != CANMESG_NOPAR) return ERR_BADPAR;}while(0) #define NOPARCHK(par) do{if(PARBASE(par) != CANMESG_NOPAR) return ERR_BADPAR;}while(0)
@ -36,10 +36,10 @@
extern volatile uint32_t Tms; extern volatile uint32_t Tms;
// common functions for CAN and USB (or CAN only functions) // common functions for CAN and USB (or CAN only functions)
/*
static errcodes cu_nosuchfn(uint8_t _U_ par, int32_t _U_ *val){ static errcodes cu_nosuchfn(uint8_t _U_ par, int32_t _U_ *val){
return ERR_BADCMD; return ERR_BADCMD;
} }*/
errcodes cu_abspos(uint8_t _U_ par, int32_t _U_ *val){ errcodes cu_abspos(uint8_t _U_ par, int32_t _U_ *val){
uint8_t n; CHECKN(n, par); uint8_t n; CHECKN(n, par);
@ -87,8 +87,23 @@ errcodes cu_button(uint8_t par, int32_t *val){
return (uint8_t) keystate(n, (uint32_t*)val); return (uint8_t) keystate(n, (uint32_t*)val);
} }
errcodes cu_diagn(uint8_t _U_ par, int32_t _U_ *val){ errcodes cu_diagn(uint8_t par, int32_t *val){
return ERR_BADCMD; uint8_t n = PARBASE(par);
#if MOTORSNO > 8
#error "Change this code!"
#endif
if(n == CANMESG_NOPAR){ // all motors
n = 0;
for(int i = MOTORSNO-1; i > -1; --i){
n <<= 1;
n |= motdiagn(i);
}
*val = n;
return ERR_OK;
}
CHECKN(n, par);
*val = motdiagn(n);
return ERR_OK;
} }
errcodes cu_drvtype(uint8_t par, int32_t *val){ errcodes cu_drvtype(uint8_t par, int32_t *val){
@ -102,17 +117,18 @@ errcodes cu_drvtype(uint8_t par, int32_t *val){
return ERR_OK; return ERR_OK;
} }
errcodes cu_emstop(uint8_t _U_ par, int32_t _U_ *val){ errcodes cu_emstop(uint8_t par, int32_t _U_ *val){
uint8_t n; CHECKN(n, par); uint8_t n = PARBASE(par);
if(n == CANMESG_NOPAR){
for(int i = 0; i < MOTORSNO; ++i)
emstopmotor(i);
return ERR_OK;
}
CHECKN(n, par);
emstopmotor(n); emstopmotor(n);
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)){
@ -168,9 +184,8 @@ TRUE_INLINE void setextpar(uint8_t val, uint8_t i){
} }
} }
// TODO: do it right errcodes cu_gpio(uint8_t par, int32_t *val){
errcodes cu_gpio(uint8_t _U_ par, int32_t _U_ *val){ #if EXTNO > 8
#if EXTNO > 4
#error "change the code!!!" #error "change the code!!!"
#endif #endif
uint8_t n = PARBASE(par); uint8_t n = PARBASE(par);
@ -182,16 +197,22 @@ errcodes cu_gpio(uint8_t _U_ par, int32_t _U_ *val){
#ifdef EBUG #ifdef EBUG
USND("ALL\n"); USND("ALL\n");
#endif #endif
uint8_t *arr = (uint8_t*)val; uint8_t g = (uint8_t)*val;
if(ISSETTER(par)){ if(ISSETTER(par)){
for(int i = 0; i < EXTNO; ++i) for(int i = 0; i < EXTNO; ++i){
setextpar(arr[i], i); setextpar(g & 1, i);
g >>= 1;
}
} }
for(int i = 0; i < EXTNO; ++i){ g = 0;
arr[i] = EXT_CHK(i); for(int i = EXTNO-1; i > -1; --i){
g <<= 1;
g |= EXT_CHK(i);
} }
*val = g;
return ERR_OK; return ERR_OK;
}else if(n > EXTNO-1) return ERR_BADPAR; }else if(n > EXTNO-1) return ERR_BADPAR;
// single channel setter/getter
if(ISSETTER(par)) if(ISSETTER(par))
setextpar((uint8_t)*val, n); setextpar((uint8_t)*val, n);
*val = (int32_t) EXT_CHK(n); *val = (int32_t) EXT_CHK(n);
@ -302,7 +323,7 @@ errcodes cu_motcurrent(uint8_t par, int32_t *val){
motflags_t *f = the_conf.motflags; motflags_t *f = the_conf.motflags;
if(f->drvtype == DRVTYPE_UART){ if(f->drvtype == DRVTYPE_UART){
if(!pdnuart_setcurrent(n, *val)) return ERR_CANTRUN; if(!pdnuart_setcurrent(n, *val)) return ERR_CANTRUN;
} } else return ERR_BADCMD;
} }
*val = the_conf.motcurrent[n]; *val = the_conf.motcurrent[n];
return ERR_OK; return ERR_OK;
@ -435,8 +456,6 @@ errcodes cu_vfive(uint8_t par, int32_t *val){
const fpointer cancmdlist[CCMD_AMOUNT] = { const fpointer cancmdlist[CCMD_AMOUNT] = {
// different commands // different commands
[CCMD_PING] = cu_ping, [CCMD_PING] = cu_ping,
[CCMD_RELAY] = cu_nosuchfn,
[CCMD_BUZZER] = cu_nosuchfn,
[CCMD_ADC] = cu_adc, [CCMD_ADC] = cu_adc,
[CCMD_BUTTONS] = cu_button, [CCMD_BUTTONS] = cu_button,
[CCMD_ESWSTATE] = cu_esw, [CCMD_ESWSTATE] = cu_esw,
@ -444,19 +463,15 @@ const fpointer cancmdlist[CCMD_AMOUNT] = {
[CCMD_MCUVDD] = cu_mcuvdd, [CCMD_MCUVDD] = cu_mcuvdd,
[CCMD_RESET] = cu_reset, [CCMD_RESET] = cu_reset,
[CCMD_TIMEFROMSTART] = cu_time, [CCMD_TIMEFROMSTART] = cu_time,
[CCMD_PWM] = cu_nosuchfn,
[CCMD_EXT] = cu_gpio, [CCMD_EXT] = cu_gpio,
// configuration // configuration
[CCMD_SAVECONF] = cu_saveconf, [CCMD_SAVECONF] = cu_saveconf,
[CCMD_ENCSTEPMIN] = cu_nosuchfn,
[CCMD_ENCSTEPMAX] = cu_nosuchfn,
[CCMD_MICROSTEPS] = cu_microsteps, [CCMD_MICROSTEPS] = cu_microsteps,
[CCMD_ACCEL] = cu_accel, [CCMD_ACCEL] = cu_accel,
[CCMD_MAXSPEED] = cu_maxspeed, [CCMD_MAXSPEED] = cu_maxspeed,
[CCMD_MINSPEED] = cu_minspeed, [CCMD_MINSPEED] = cu_minspeed,
[CCMD_SPEEDLIMIT] = cu_speedlimit, [CCMD_SPEEDLIMIT] = cu_speedlimit,
[CCMD_MAXSTEPS] = cu_maxsteps, [CCMD_MAXSTEPS] = cu_maxsteps,
[CCMD_ENCREV] = cu_nosuchfn,
[CCMD_MOTFLAGS] = cu_motflags, [CCMD_MOTFLAGS] = cu_motflags,
[CCMD_ESWREACT] = cu_eswreact, [CCMD_ESWREACT] = cu_eswreact,
// motor's commands // motor's commands
@ -464,61 +479,58 @@ const fpointer cancmdlist[CCMD_AMOUNT] = {
[CCMD_RELPOS] = cu_relpos, [CCMD_RELPOS] = cu_relpos,
[CCMD_RELSLOW] = cu_relslow, [CCMD_RELSLOW] = cu_relslow,
[CCMD_EMERGSTOP] = cu_emstop, [CCMD_EMERGSTOP] = cu_emstop,
[CCMD_EMERGSTOPALL] = cu_emstop, // without args
[CCMD_STOP] = cu_stop, [CCMD_STOP] = cu_stop,
[CCMD_REINITMOTORS] = cu_motreinit, [CCMD_REINITMOTORS] = cu_motreinit,
[CCMD_MOTORSTATE] = cu_state, [CCMD_MOTORSTATE] = cu_state,
[CCMD_ENCPOS] = cu_nosuchfn,
[CCMD_SETPOS] = cu_abspos, [CCMD_SETPOS] = cu_abspos,
[CCMD_GOTOZERO] = cu_gotoz, [CCMD_GOTOZERO] = cu_gotoz,
[CCMD_MOTMUL] = cu_motmul, [CCMD_MOTMUL] = cu_motmul,
[CCMD_DIAGN] = cu_diagn, [CCMD_DIAGN] = cu_diagn,
[CCMD_ERASEFLASH] = cu_eraseflash, [CCMD_ERASEFLASH] = cu_eraseflash,
[CCMD_UDATA] = cu_udata, // [CCMD_UDATA] = cu_udata,
[CCMD_USARTSTATUS] = cu_usartstatus, // [CCMD_USARTSTATUS] = cu_usartstatus,
[CCMD_VDRIVE] = cu_vdrive, [CCMD_VDRIVE] = cu_vdrive,
[CCMD_VFIVE] = cu_vfive [CCMD_VFIVE] = cu_vfive
// Leave all commands upper for back-compatability with 3steppers // Leave all commands upper for back-compatability with 3steppers
}; };
const char* cancmds[CCMD_AMOUNT] = { const char* cancmds[CCMD_AMOUNT] = {
[CCMD_PING] = "ping", [CCMD_PING] = STR_PING,
[CCMD_ADC] = "adc", [CCMD_ADC] = STR_ADC,
[CCMD_BUTTONS] = "button", [CCMD_BUTTONS] = STR_BUTTON,
[CCMD_ESWSTATE] = "esw", [CCMD_ESWSTATE] = STR_ESW,
[CCMD_MCUT] = "mcut", [CCMD_MCUT] = STR_MCUT,
[CCMD_MCUVDD] = "mcuvdd", [CCMD_MCUVDD] = STR_MCUVDD,
[CCMD_RESET] = "reset", [CCMD_RESET] = STR_RESET,
[CCMD_TIMEFROMSTART] = "time", [CCMD_TIMEFROMSTART] = STR_TIME,
[CCMD_EXT] = "gpio", [CCMD_EXT] = STR_GPIO,
[CCMD_SAVECONF] = "saveconf", [CCMD_SAVECONF] = STR_SAVECONF,
[CCMD_MICROSTEPS] = "microsteps", [CCMD_MICROSTEPS] = STR_MICROSTEPS,
[CCMD_ACCEL] = "accel", [CCMD_ACCEL] = STR_ACCEL,
[CCMD_MAXSPEED] = "maxspeed", [CCMD_MAXSPEED] = STR_MAXSPEED,
[CCMD_MINSPEED] = "minspeed", [CCMD_MINSPEED] = STR_MINSPEED,
[CCMD_SPEEDLIMIT] = "speedlimit", [CCMD_SPEEDLIMIT] = STR_SPEEDLIMIT,
[CCMD_MAXSTEPS] = "maxsteps", [CCMD_MAXSTEPS] = STR_MAXSTEPS,
[CCMD_MOTFLAGS] = "motflags", [CCMD_MOTFLAGS] = STR_MOTFLAGS,
[CCMD_ESWREACT] = "eswreact", [CCMD_ESWREACT] = STR_ESWREACT,
[CCMD_ABSPOS] = "goto", [CCMD_ABSPOS] = STR_GOTO,
[CCMD_RELPOS] = "relpos", [CCMD_RELPOS] = STR_RELPOS,
[CCMD_RELSLOW] = "relslow", [CCMD_RELSLOW] = STR_RELSLOW,
[CCMD_EMERGSTOP] = "emstop N", [CCMD_EMERGSTOP] = STR_EMSTOP,
[CCMD_EMERGSTOPALL] = "emstop all", [CCMD_STOP] = STR_STOP,
[CCMD_STOP] = "stop", [CCMD_REINITMOTORS] = STR_MOTREINIT,
[CCMD_REINITMOTORS] = "motreinit", [CCMD_MOTORSTATE] = STR_STATE,
[CCMD_MOTORSTATE] = "state", [CCMD_SETPOS] = STR_ABSPOS,
[CCMD_SETPOS] = "abspos", [CCMD_GOTOZERO] = STR_GOTOZ,
[CCMD_GOTOZERO] = "gotoz", [CCMD_MOTMUL] = STR_MOTMUL,
[CCMD_MOTMUL] = "motmul", [CCMD_DIAGN] = STR_DIAGN,
[CCMD_DIAGN] = "diagn", [CCMD_ERASEFLASH] = STR_ERASEFLASH,
[CCMD_ERASEFLASH] = "eraseflash", // [CCMD_UDATA] = STR_UDATA,
[CCMD_UDATA] = "udata", // [CCMD_USARTSTATUS] = STR_USARTSTATUS,
[CCMD_USARTSTATUS] = "usartstatus", [CCMD_VDRIVE] = STR_VDRIVE,
[CCMD_VDRIVE] = "vdrive", [CCMD_VFIVE] = STR_VFIVE,
[CCMD_VFIVE] = "vfive", [CCMD_PDN] = STR_PDN,
[CCMD_PDN] = "pdn", [CCMD_MOTNO] = STR_MOTNO,
[CCMD_MOTNO] = "motno", [CCMD_DRVTYPE] = STR_DRVTYPE,
[CCMD_DRVTYPE] = "drvtype", [CCMD_MOTCURRENT] = STR_MOTCURRENT,
[CCMD_MOTCURRENT] = "motcurrent",
}; };

View File

@ -52,8 +52,8 @@ typedef errcodes (*fpointer)(uint8_t par, int32_t *val);
enum{ enum{
CCMD_NONE // omit zero CCMD_NONE // omit zero
,CCMD_PING // ping device ,CCMD_PING // ping device
,CCMD_RELAY // relay on/off ,CCMD_RESERVED0 //
,CCMD_BUZZER // buzzer on/off ,CCMD_RESERVED1 //
,CCMD_ADC // ADC ch# ,CCMD_ADC // ADC ch#
,CCMD_BUTTONS // buttons ,CCMD_BUTTONS // buttons
,CCMD_ESWSTATE // end-switches state ,CCMD_ESWSTATE // end-switches state
@ -61,18 +61,18 @@ enum{
,CCMD_MCUVDD // MCU Vdd ,CCMD_MCUVDD // MCU Vdd
,CCMD_RESET // software reset ,CCMD_RESET // software reset
,CCMD_TIMEFROMSTART // get time from start ,CCMD_TIMEFROMSTART // get time from start
,CCMD_PWM // PWM value ,CCMD_RESERVED2 //
,CCMD_EXT // value on EXTx outputs ,CCMD_EXT // value on EXTx outputs
,CCMD_SAVECONF // save configuration ,CCMD_SAVECONF // save configuration
,CCMD_ENCSTEPMIN // min ticks of encoder per one step ,CCMD_RESERVED3 //
,CCMD_ENCSTEPMAX // max ticks of encoder per one step ,CCMD_RESERVED4 //
,CCMD_MICROSTEPS // get/set microsteps ,CCMD_MICROSTEPS // get/set microsteps
,CCMD_ACCEL // set/get acceleration/deceleration ,CCMD_ACCEL // set/get acceleration/deceleration
,CCMD_MAXSPEED // set/get maximal speed ,CCMD_MAXSPEED // set/get maximal speed
,CCMD_MINSPEED // set/get minimal speed ,CCMD_MINSPEED // set/get minimal speed
,CCMD_SPEEDLIMIT // get limit of speed for current microsteps settings ,CCMD_SPEEDLIMIT // get limit of speed for current microsteps settings
,CCMD_MAXSTEPS // max steps (-max..+max) ,CCMD_MAXSTEPS // max steps (-max..+max)
,CCMD_ENCREV // encoder's pulses per revolution ,CCMD_RESERVED5 //
,CCMD_MOTFLAGS // motor flags ,CCMD_MOTFLAGS // motor flags
,CCMD_ESWREACT // ESW reaction flags ,CCMD_ESWREACT // ESW reaction flags
,CCMD_REINITMOTORS // re-init motors after configuration changing ,CCMD_REINITMOTORS // re-init motors after configuration changing
@ -81,7 +81,7 @@ enum{
,CCMD_RELSLOW // change relative position at lowest speed ,CCMD_RELSLOW // change relative position at lowest speed
,CCMD_EMERGSTOP // stop moving NOW ,CCMD_EMERGSTOP // stop moving NOW
,CCMD_STOP // smooth motor stop ,CCMD_STOP // smooth motor stop
,CCMD_EMERGSTOPALL // emergency stop for all motors ,CCMD_RESERVED6 //
,CCMD_GOTOZERO // go to zero's ESW ,CCMD_GOTOZERO // go to zero's ESW
,CCMD_MOTORSTATE // motor state ,CCMD_MOTORSTATE // motor state
,CCMD_ENCPOS // position of encoder (independing on settings) ,CCMD_ENCPOS // position of encoder (independing on settings)
@ -113,7 +113,6 @@ 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

@ -23,7 +23,7 @@
#include "proto.h" #include "proto.h"
#include "steppers.h" #include "steppers.h"
#include "strfunc.h" #include "strfunc.h"
#include "usb.h" #include "usb_dev.h"
extern const uint32_t __varsstart, _BLOCKSIZE; extern const uint32_t __varsstart, _BLOCKSIZE;
@ -32,7 +32,7 @@ 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_SIMPLE} #define DEFMF {.donthold = 1, .drvtype = DRVTYPE_UART}
#define USERCONF_INITIALIZER { \ #define USERCONF_INITIALIZER { \
.userconf_sz = sizeof(user_conf) \ .userconf_sz = sizeof(user_conf) \
@ -45,6 +45,7 @@ static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here
,.maxsteps = {500000,500000,500000,500000,500000,500000,500000,500000}\ ,.maxsteps = {500000,500000,500000,500000,500000,500000,500000,500000}\
,.motflags = {DEFMF,DEFMF,DEFMF,DEFMF,DEFMF,DEFMF,DEFMF,DEFMF} \ ,.motflags = {DEFMF,DEFMF,DEFMF,DEFMF,DEFMF,DEFMF,DEFMF,DEFMF} \
,.ESW_reaction = {ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE} \ ,.ESW_reaction = {ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE,ESW_IGNORE} \
,.motcurrent = {31,31,31,31,31,31,31,31} \
} }
static int write2flash(const void*, const void*, uint32_t); static int write2flash(const void*, const void*, uint32_t);

View File

@ -63,10 +63,10 @@ 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" SHOULD ALWAYS BE FIRST!!!1111
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
uint32_t maxsteps[MOTORSNO]; // maximal amount of steps
uint16_t microsteps[MOTORSNO]; // microsteps amount per step uint16_t microsteps[MOTORSNO]; // microsteps amount per step
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)

View File

@ -84,6 +84,10 @@ extern const uint32_t EXTpins[EXTNO];
#define EXT_TOGGLE(x) do{ pin_toggle(EXTports[x], EXTpins[x]); }while(0) #define EXT_TOGGLE(x) do{ pin_toggle(EXTports[x], EXTpins[x]); }while(0)
#define EXT_CHK(x) (pin_read(EXTports[x], EXTpins[x])) #define EXT_CHK(x) (pin_read(EXTports[x], EXTpins[x]))
// DIAG output of motors (PE2) & its multiplexer (PE3 - 0, PE4 - 1, PE5 - 2)
#define DIAG() (GPIOE->IDR & (1<<2) ? 0 : 1)
#define DIAGMUL(x) do{ register uint32_t v = x&7; GPIOE->BSRR = (v | (((~v)&7)<<16))<<3; }while(0)
extern volatile TIM_TypeDef *mottimers[MOTORSNO]; extern volatile TIM_TypeDef *mottimers[MOTORSNO];
extern volatile uint32_t Tms; extern volatile uint32_t Tms;

View File

@ -249,6 +249,12 @@ static void build(strhash *H, int hno, int hlen){
} }
fprintf(source, "%s", ffooter); fprintf(source, "%s", ffooter);
fclose(source); fclose(source);
fprintf(header, "\n\n");
for(int i = 0; i < hlen; ++i){
char *m = macroname(H[i].str);
fprintf(header, "#define STR_%-*s \"%s\"\n", lmax, m, H[i].str);
}
fclose(header); fclose(header);
} }

View File

@ -77,3 +77,66 @@ extern char lastcmd[];
#define CMD_USARTSTATUS (4007098968) #define CMD_USARTSTATUS (4007098968)
#define CMD_VDRIVE (2172773525) #define CMD_VDRIVE (2172773525)
#define CMD_VFIVE (3017477285) #define CMD_VFIVE (3017477285)
#define STR_ABSPOS "abspos"
#define STR_ACCEL "accel"
#define STR_ADC "adc"
#define STR_BUTTON "button"
#define STR_CANERRCODES "canerrcodes"
#define STR_CANFILTER "canfilter"
#define STR_CANFLOOD "canflood"
#define STR_CANFLOODT "canfloodT"
#define STR_CANID "canid"
#define STR_CANIGNORE "canignore"
#define STR_CANINCRFLOOD "canincrflood"
#define STR_CANPAUSE "canpause"
#define STR_CANREINIT "canreinit"
#define STR_CANRESUME "canresume"
#define STR_CANSEND "cansend"
#define STR_CANSPEED "canspeed"
#define STR_CANSTAT "canstat"
#define STR_DIAGN "diagn"
#define STR_DRVTYPE "drvtype"
#define STR_DUMPCMD "dumpcmd"
#define STR_DUMPCONF "dumpconf"
#define STR_DUMPERR "dumperr"
#define STR_DUMPMOT "dumpmot"
#define STR_DUMPMOTFLAGS "dumpmotflags"
#define STR_DUMPSTATES "dumpstates"
#define STR_EMSTOP "emstop"
#define STR_ERASEFLASH "eraseflash"
#define STR_ESW "esw"
#define STR_ESWREACT "eswreact"
#define STR_GOTO "goto"
#define STR_GOTOZ "gotoz"
#define STR_GPIO "gpio"
#define STR_GPIOCONF "gpioconf"
#define STR_HELP "help"
#define STR_MAXSPEED "maxspeed"
#define STR_MAXSTEPS "maxsteps"
#define STR_MCUT "mcut"
#define STR_MCUVDD "mcuvdd"
#define STR_MICROSTEPS "microsteps"
#define STR_MINSPEED "minspeed"
#define STR_MOTCURRENT "motcurrent"
#define STR_MOTFLAGS "motflags"
#define STR_MOTMUL "motmul"
#define STR_MOTNO "motno"
#define STR_MOTREINIT "motreinit"
#define STR_PDN "pdn"
#define STR_PING "ping"
#define STR_RELPOS "relpos"
#define STR_RELSLOW "relslow"
#define STR_RESET "reset"
#define STR_SAVECONF "saveconf"
#define STR_SCREEN "screen"
#define STR_SPEEDLIMIT "speedlimit"
#define STR_STATE "state"
#define STR_STOP "stop"
#define STR_TIME "time"
#define STR_TMCBUS "tmcbus"
#define STR_UDATA "udata"
#define STR_USARTSTATUS "usartstatus"
#define STR_VDRIVE "vdrive"
#define STR_VFIVE "vfive"

View File

@ -15,7 +15,7 @@
"cansend - send data over CAN: send ID byte0 .. byteN (N<8)\n" "cansend - send data over CAN: send ID byte0 .. byteN (N<8)\n"
"canspeed - GS CAN speed (reinit if setter)\n" "canspeed - GS CAN speed (reinit if setter)\n"
"canstat - G CAN status\n" "canstat - G CAN status\n"
"diagn[N]* - G DIAG state of motor N (or all)\n" "diagn[N] - G DIAG state of motor N (or all)\n"
"drvtypeN - GS driver type (0 - only step/dir, 1 - UART, 2 - SPI, 3 - reserved)\n" "drvtypeN - GS driver type (0 - only step/dir, 1 - UART, 2 - SPI, 3 - reserved)\n"
"dumperr - dump error codes\n" "dumperr - dump error codes\n"
"dumpcmd - dump command codes\n" "dumpcmd - dump command codes\n"
@ -26,11 +26,11 @@
"emstop[N] - emergency stop motor N or all\n" "emstop[N] - emergency stop motor N or all\n"
"eraseflash [=N] - erase flash data storage (full or only N'th page of it)\n" "eraseflash [=N] - erase flash data storage (full or only N'th page of it)\n"
"esw[N] - G end-switches state\n" "esw[N] - G end-switches state\n"
"eswreactN - GS end-switches reaction (0 - ignore, 1 - stop@any, 2 - stop@zero)\n" "eswreactN - GS end-switches reaction (0 - ignore, 1 - ignore ESW1 and stop@0 only when moving negative, 2 - stop@any, 3 - stop@dir)\n"
"gotoN - GS move motor to given absolute position\n" "gotoN - GS move motor to given absolute position\n"
"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" "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"

View File

@ -24,7 +24,7 @@
#include "pdnuart.h" #include "pdnuart.h"
#include "proto.h" #include "proto.h"
#include "steppers.h" #include "steppers.h"
#include "usb.h" #include "usb_dev.h"
#define MAXSTRLEN RBINSZ #define MAXSTRLEN RBINSZ
@ -49,7 +49,7 @@ int main(void){
CAN_setup(the_conf.CANspeed); CAN_setup(the_conf.CANspeed);
adc_setup(); adc_setup();
pdnuart_setup(); pdnuart_setup();
init_steppers(); // steppers will be initted later, in process_steppers()
USBPU_ON(); USBPU_ON();
uint32_t ctr = 0; uint32_t ctr = 0;
CAN_message *can_mesg; CAN_message *can_mesg;
@ -83,11 +83,13 @@ int main(void){
int l = USB_receivestr(inbuff, MAXSTRLEN); int l = USB_receivestr(inbuff, MAXSTRLEN);
if(l < 0) USB_sendstr("USB_BUF_OVERFLOW\n"); if(l < 0) USB_sendstr("USB_BUF_OVERFLOW\n");
else if(l){ else if(l){
/*
#ifdef EBUG #ifdef EBUG
USB_sendstr("USB GOT:\n"); USB_sendstr("USB GOT:\n");
USB_sendstr(inbuff); USB_sendstr(inbuff);
USB_sendstr("\n--------\n"); USB_sendstr("\n--------\n");
#endif #endif
*/
const char *ans = cmd_parser(inbuff); const char *ans = cmd_parser(inbuff);
if(ans) USB_sendstr(ans); if(ans) USB_sendstr(ans);
} }

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 14.0.1, 2024-09-02T18:20:26. --> <!-- Written by QtCreator 14.0.2, 2024-11-13T08:41:23. -->
<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,9 +39,9 @@
<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>
@ -50,10 +50,10 @@
<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">1</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>
@ -78,7 +78,7 @@
<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">true</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"/>
@ -93,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/F303-nolib/Multistepper</value> <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/ELECTRONICS/STM32/F3-srcs/Multistepper</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">
@ -108,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">
@ -121,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>
@ -130,15 +130,15 @@
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/> <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value> <value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/> <valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value> <value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
</valuemap> </valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value> <value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<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>

View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 8.0.2, 2023-01-18T20:42:42. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{7bd84e39-ca37-46d3-be9d-99ebea85bc0d}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">false</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">2</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">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.Id">{65a14f9e-e008-4c1b-89df-4eaa4774b6e3}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/Big/Data/00__Electronics/STM32/F303-nolib/blink</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Default</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@ -28,6 +28,10 @@ strfunc.h
tmc2209.h tmc2209.h
usb.c usb.c
usb.h usb.h
usb_descr.c
usb_descr.h
usb_dev.c
usb_dev.h
usb_lib.c usb_lib.c
usb_lib.h usb_lib.h
usbhw.c usbhw.c

View File

@ -70,7 +70,10 @@ void pdnuart_setup(){
} }
static int rwreg(uint8_t reg, uint32_t data, int w){ static int rwreg(uint8_t reg, uint32_t data, int w){
if(motorno >= MOTORSNO || reg & 0x80) return FALSE; if(motorno >= MOTORSNO || reg & 0x80){
DBG("Wrong motno or reg");
return FALSE;
}
uint32_t x = Tms; uint32_t x = Tms;
while(Tms - x < 1); while(Tms - x < 1);
int no = motorno >> 2; int no = motorno >> 2;
@ -90,13 +93,24 @@ static int rwreg(uint8_t reg, uint32_t data, int w){
calcCRC(outbuf, nbytes); calcCRC(outbuf, nbytes);
++nbytes; ++nbytes;
for(int i = 0; i < nbytes; ++i){ for(int i = 0; i < nbytes; ++i){
IWDG->KR = IWDG_REFRESH;
/*
#ifdef EBUG
USB_sendstr("Send byte "); USB_putbyte('0'+i); USB_sendstr(": "); printuhex(outbuf[i]); newline(); USB_sendstr("Send byte "); USB_putbyte('0'+i); USB_sendstr(": "); printuhex(outbuf[i]); newline();
#endif
*/
USART[no]->TDR = outbuf[i]; // transmit USART[no]->TDR = outbuf[i]; // transmit
while(!(USART[no]->ISR & USART_ISR_TXE)); while(!(USART[no]->ISR & USART_ISR_TXE));
int l = 0; int l = 0;
for(; l < 10000; ++l) if(USART[no]->ISR & USART_ISR_RXNE) break; for(; l < 10000; ++l) if(USART[no]->ISR & USART_ISR_RXNE) break;
// clear Rx
(void) USART[no]->RDR;
/*
#ifdef EBUG
if(l == 10000) USND("Nothing received"); if(l == 10000) USND("Nothing received");
else {USB_sendstr("Rcv: "); printuhex(USART[no]->RDR); newline();} else {USB_sendstr("Rcv: "); printuhex(USART[no]->RDR); newline();}
#endif
*/
} }
return TRUE; return TRUE;
} }
@ -113,10 +127,18 @@ int pdnuart_readreg(uint8_t reg, uint32_t *data){
uint8_t buf[8]; uint8_t buf[8];
int no = motorno >> 2; int no = motorno >> 2;
for(int i = 0; i < 8; ++i){ for(int i = 0; i < 8; ++i){
IWDG->KR = IWDG_REFRESH;
while(!(USART[no]->ISR & USART_ISR_RXNE)) while(!(USART[no]->ISR & USART_ISR_RXNE))
if(Tms - Tstart > PDNU_TMOUT) return FALSE; if(Tms - Tstart > PDNU_TMOUT){
DBG("Read timeout");
return FALSE;
}
buf[i] = USART[no]->RDR; buf[i] = USART[no]->RDR;
USB_sendstr("byte: "); printuhex(buf[i]); newline(); /*
#ifdef EBUG
USB_sendstr("Read byte: "); printuhex(buf[i]); newline();
#endif
*/
} }
uint32_t o = 0; uint32_t o = 0;
for(int i = 3; i < 7; ++i){ for(int i = 3; i < 7; ++i){
@ -153,9 +175,12 @@ int pdnuart_setmotno(uint8_t no){
// write val into IHOLD_IRUN over UART to n'th motor // write val into IHOLD_IRUN over UART to n'th motor
int pdnuart_setcurrent(uint8_t no, uint8_t val){ int pdnuart_setcurrent(uint8_t no, uint8_t val){
TMC2209_ihold_irun_reg_t regval; TMC2209_ihold_irun_reg_t regval = {0};
if(!readregister(no, TMC2209Reg_IHOLD_IRUN, &regval.value)) return FALSE; // IHOLD_IRUN is write-only register, so we should write all values!!!
//if(!readregister(no, TMC2209Reg_IHOLD_IRUN, &regval.value)) return FALSE;
if(the_conf.motflags[no].donthold == 0) regval.ihold = (1+val)/2; // hold current
regval.irun = val; regval.irun = val;
regval.iholddelay = 1; // 2^18 clock delay before power down motor
return writeregister(no, TMC2209Reg_IHOLD_IRUN, regval.value); return writeregister(no, TMC2209Reg_IHOLD_IRUN, regval.value);
} }
@ -172,12 +197,12 @@ int pdnuart_microsteps(uint8_t no, uint32_t val){
// init driver number `no`, return FALSE if failed // init driver number `no`, return FALSE if failed
int pdnuart_init(uint8_t no){ int pdnuart_init(uint8_t no){
TMC2209_gconf_reg_t gconf; TMC2209_gconf_reg_t gconf;
if(!pdnuart_microsteps(no, the_conf.microsteps[no])) return FALSE;
if(!pdnuart_setcurrent(no, the_conf.motcurrent[no])) return FALSE;
if(!readregister(no, TMC2209Reg_GCONF, &gconf.value)) return FALSE; if(!readregister(no, TMC2209Reg_GCONF, &gconf.value)) return FALSE;
gconf.pdn_disable = 1; // PDN now is UART gconf.pdn_disable = 1; // PDN now is UART
gconf.mstep_reg_select = 1; // microsteps are by MSTEP gconf.mstep_reg_select = 1; // microsteps are by MSTEP
if(!writeregister(no, TMC2209Reg_GCONF, gconf.value)) return FALSE; if(!writeregister(no, TMC2209Reg_GCONF, gconf.value)) return FALSE;
if(!pdnuart_microsteps(no, the_conf.microsteps[no])) return FALSE;
if(!pdnuart_setcurrent(no, the_conf.motcurrent[no])) return FALSE;
return TRUE; return TRUE;
} }

View File

@ -403,9 +403,10 @@ static const char* motfl[MOTFLAGS_AMOUNT] = {
"6,7: drvtype - driver type (0 - only step/dir, 1 - UART, 2 - SPI, 3 - reserved)" "6,7: drvtype - driver type (0 - only step/dir, 1 - UART, 2 - SPI, 3 - reserved)"
}; };
static const char *eswfl[ESW_AMOUNT] = { static const char *eswfl[ESW_AMOUNT] = {
[ESW_IGNORE] = "ignore end-switches", [ESW_IGNORE] = "ignore both end-switches",
[ESW_IGNORE1] = "ignore ESW1, ESW0 stops only when negative mowing",
[ESW_ANYSTOP] = "stop @ esw in any moving direction", [ESW_ANYSTOP] = "stop @ esw in any moving direction",
[ESW_STOPMINUS] = "stop only when moving in given direction (e.g. to minus @ESW0)" [ESW_STOPDIR] = "stop only when moving in given direction (e.g. to minus @ESW0)"
}; };
int fn_dumpmotflags(uint32_t _U_ hash, char _U_ *args){ // "dumpmotflags" (36159640) int fn_dumpmotflags(uint32_t _U_ hash, char _U_ *args){ // "dumpmotflags" (36159640)
USB_sendstr("Motor flags:"); USB_sendstr("Motor flags:");
@ -479,11 +480,13 @@ static int canusb_function(uint32_t hash, char *args){
uint32_t N; uint32_t N;
int32_t val = 0; int32_t val = 0;
uint8_t par = CANMESG_NOPAR; uint8_t par = CANMESG_NOPAR;
/*
DBG("CMD: hash="); DBG("CMD: hash=");
#ifdef EBUG #ifdef EBUG
printu(hash); USB_sendstr(", args="); printu(hash); USB_sendstr(", args=");
USND(args); USND(args);
#endif #endif
*/
if(*args){ if(*args){
const char *n = getnum(args, &N); const char *n = getnum(args, &N);
if(n != args){ // get parameter if(n != args){ // get parameter
@ -502,10 +505,12 @@ static int canusb_function(uint32_t hash, char *args){
} }
} }
} }
/*
#ifdef EBUG #ifdef EBUG
USB_sendstr("par="); printuhex(par); USB_sendstr("par="); printuhex(par);
USB_sendstr(", val="); printi(val); newline(); USB_sendstr(", val="); printi(val); newline();
#endif #endif
*/
switch(hash){ switch(hash){
case CMD_ADC: case CMD_ADC:
e = cu_adc(par, &val); e = cu_adc(par, &val);
@ -553,8 +558,7 @@ 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:
if(par == CANMESG_NOPAR) e = cu_emstopall(par, &val); e = cu_emstop(par, &val);
else e = cu_emstop(par, &val);
if(e == ERR_OK){ USND("OK"); return RET_GOOD;} if(e == ERR_OK){ USND("OK"); return RET_GOOD;}
break; break;
case CMD_ESWREACT: case CMD_ESWREACT:

View File

@ -21,7 +21,16 @@
#include <stdint.h> #include <stdint.h>
#include "strfunc.h" #include "strfunc.h"
#include "usb.h" #include "usb_dev.h"
#define STR_HELPER(s) #s
#define STR(s) STR_HELPER(s)
#ifdef EBUG
#define DBG(str) do{USB_sendstr(__FILE__ " (L" STR(__LINE__) "): " str); newline();}while(0)
#else
#define DBG(str)
#endif
#define printu(x) do{USB_sendstr(u2str(x));}while(0) #define printu(x) do{USB_sendstr(u2str(x));}while(0)
#define printi(x) do{USB_sendstr(i2str(x));}while(0) #define printi(x) do{USB_sendstr(i2str(x));}while(0)

View File

@ -18,11 +18,13 @@
#include "flash.h" #include "flash.h"
#include "hardware.h" #include "hardware.h"
#include "hdr.h"
#include "pdnuart.h" #include "pdnuart.h"
#include "proto.h" #include "proto.h"
#include "steppers.h" #include "steppers.h"
#include "strfunc.h" #include "strfunc.h"
#include "usb.h" #include "tmc2209.h"
#include "usb_dev.h"
// goto zero stages // goto zero stages
typedef enum{ typedef enum{
@ -174,10 +176,13 @@ static int esw_block(uint8_t i){
uint8_t s = ESW_state(i); uint8_t s = ESW_state(i);
if(s){ // ESW active if(s){ // ESW active
switch(ESW_reaction[i]){ switch(ESW_reaction[i]){
case ESW_IGNORE1:
if(motdir[i] == -1 && (s & 1)) ret = TRUE; // stop @ESW0
break;
case ESW_ANYSTOP: // stop motor in any direction case ESW_ANYSTOP: // stop motor in any direction
ret = TRUE; ret = TRUE;
break; break;
case ESW_STOPMINUS: // stop only @ given direction case ESW_STOPDIR: // stop only @ given direction
if(motdir[i] == -1 && (s & 1)) ret = TRUE; // stop @ESW0 if(motdir[i] == -1 && (s & 1)) ret = TRUE; // stop @ESW0
if(motdir[i] == 1 && (s & 2)) ret = TRUE; // stop @ESW1 if(motdir[i] == 1 && (s & 2)) ret = TRUE; // stop @ESW1
break; break;
@ -262,6 +267,15 @@ stp_state getmotstate(uint8_t i){
return state[i]; return state[i];
} }
// get DIAGN input
uint8_t motdiagn(uint8_t i){
if(i > MOTORSNO-1) return 0;
DIAGMUL(i);
// small stupid pause
for(int _ = 0; _ < 1000; ++_) nop();
return DIAG();
}
// count steps @tim 14/15/16 // count steps @tim 14/15/16
void addmicrostep(uint8_t i){ void addmicrostep(uint8_t i){
static volatile uint16_t microsteps[MOTORSNO] = {0}; // current microsteps position static volatile uint16_t microsteps[MOTORSNO] = {0}; // current microsteps position
@ -310,7 +324,34 @@ void addmicrostep(uint8_t i){
// check state of i`th stepper // check state of i`th stepper
static void chkstepper(int i){ static void chkstepper(int i){
int32_t i32; int32_t i32;
uint32_t u32;
static uint8_t stopctr[MOTORSNO] = {0}; // counters for encoders/position zeroing after stopping @ esw static uint8_t stopctr[MOTORSNO] = {0}; // counters for encoders/position zeroing after stopping @ esw
// check DIAGN only for UART/SPI
if(the_conf.motflags[i].drvtype == DRVTYPE_UART || the_conf.motflags[i].drvtype == DRVTYPE_SPI){
if(motdiagn(i) && state[i] != STP_ERR){ // error occured - DIAGN is low
DBG("Oldstate: "); USB_putbyte('0' + state[i]); newline();
char Nm = '0'+i;
USB_sendstr(STR_STATE); USB_putbyte(Nm); USB_sendstr("=6\n");
switch(the_conf.motflags[i].drvtype){
case DRVTYPE_UART:
pdnuart_setmotno(i);
if(pdnuart_readreg(TMC2209Reg_GSTAT, &u32)){
USB_sendstr("GSTAT"); USB_putbyte(Nm); USB_putbyte('=');
USB_sendstr(u2str(u32)); newline();
}
if(pdnuart_readreg(TMC2209Reg_DRV_STATUS, &u32)){
USB_sendstr("DRV_STATUS"); USB_putbyte(Nm); USB_putbyte('=');
USB_sendstr(u2str(u32)); newline();
}
break;
default:
break;
}
emstopmotor(i);
state[i] = STP_ERR;
return;
}
}
#ifdef EBUG #ifdef EBUG
if(stp[i]){ if(stp[i]){
stp[i] = 0; stp[i] = 0;
@ -391,13 +432,14 @@ static void chkstepper(int i){
mvzerostate[i] = M0RELAX; mvzerostate[i] = M0RELAX;
ESW_reaction[i] = the_conf.ESW_reaction[i]; ESW_reaction[i] = the_conf.ESW_reaction[i];
}else{ }else{
DBG("->SLOW+");
mvzerostate[i] = M0SLOW; mvzerostate[i] = M0SLOW;
stopctr[i] = 0; stopctr[i] = 0;
} }
} }
break; break;
case M0SLOW: case M0SLOW:
if(0 == ESW_state(i)){ // moved out of limit switch - can stop if(0 == (ESW_state(i) & 1)){ // moved out of limit switch - can stop
emstopmotor(i); emstopmotor(i);
} }
if((state[i] == STP_RELAX || state[i] == STP_STALL) && ++stopctr[i] > 5){ // wait at least 50ms if((state[i] == STP_RELAX || state[i] == STP_STALL) && ++stopctr[i] > 5){ // wait at least 50ms
@ -417,8 +459,8 @@ static void chkstepper(int i){
errcodes motor_goto0(uint8_t i){ errcodes motor_goto0(uint8_t i){
errcodes e = motor_absmove(i, -the_conf.maxsteps[i]); errcodes e = motor_absmove(i, -the_conf.maxsteps[i]);
if(ERR_OK != e){ if(ERR_OK != e){
if(!ESW_state(i)) return e; // not @ limit switch -> error if(!esw_block(i)) return e; // limit switch not block -> error
}else ESW_reaction[i] = ESW_STOPMINUS; }else ESW_reaction[i] = ESW_IGNORE1;
mvzerostate[i] = M0FAST; mvzerostate[i] = M0FAST;
return e; return e;
} }
@ -452,6 +494,8 @@ void process_steppers(){
static uint32_t Tlast = 0; static uint32_t Tlast = 0;
if(Tms - Tlast < MOTCHKINTERVAL) return; // hit every 10ms if(Tms - Tlast < MOTCHKINTERVAL) return; // hit every 10ms
Tlast = Tms; Tlast = Tms;
static int firstrun = 1;
if(firstrun){ firstrun = 0; init_steppers(); return; }
for(int i = 0; i < MOTORSNO; ++i){ for(int i = 0; i < MOTORSNO; ++i){
chkstepper(i); chkstepper(i);
} }

View File

@ -42,9 +42,10 @@ typedef enum{
// end-switches reaction // end-switches reaction
enum{ enum{
ESW_IGNORE, // don't stop @ end-switch ESW_IGNORE, // don't stop @ any end-switch
ESW_IGNORE1, // ignore ESW1
ESW_ANYSTOP, // stop @ esw in any moving direction ESW_ANYSTOP, // stop @ esw in any moving direction
ESW_STOPMINUS, // stop only when moving in given direction (e.g. to minus @ESW0) ESW_STOPDIR, // stop only when moving in given direction (e.g. to minus @ESW0 or to plus @ESW1)
ESW_AMOUNT // number of records ESW_AMOUNT // number of records
}; };
@ -68,4 +69,5 @@ uint8_t geteswreact(uint8_t i);
void emstopmotor(uint8_t i); void emstopmotor(uint8_t i);
void stopmotor(uint8_t i); void stopmotor(uint8_t i);
stp_state getmotstate(uint8_t i); stp_state getmotstate(uint8_t i);
uint8_t motdiagn(uint8_t i);
void process_steppers(); void process_steppers();

View File

@ -0,0 +1,210 @@
/*
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "usb_descr.h"
// low/high for uint16_t
#define L16(x) (x & 0xff)
#define H16(x) (x >> 8)
static const uint8_t USB_DeviceDescriptor[] = {
USB_DT_DEVICE_SIZE, // bLength
USB_DT_DEVICE, // bDescriptorType
L16(bcdUSB), // bcdUSB_L
H16(bcdUSB), // bcdUSB_H
USB_CLASS_MISC, // bDeviceClass
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0BUFSZ, // bMaxPacketSize
L16(idVendor), // idVendor_L
H16(idVendor), // idVendor_H
L16(idProduct), // idProduct_L
H16(idProduct), // idProduct_H
L16(bcdDevice_Ver), // bcdDevice_Ver_L
H16(bcdDevice_Ver), // bcdDevice_Ver_H
iMANUFACTURER_DESCR, // iManufacturer - indexes of string descriptors in array
iPRODUCT_DESCR, // iProduct
iSERIAL_DESCR, // iSerial
bNumConfigurations // bNumConfigurations
};
static const uint8_t USB_DeviceQualifierDescriptor[] = {
USB_DT_QUALIFIER_SIZE, //bLength
USB_DT_QUALIFIER, // bDescriptorType
L16(bcdUSB), // bcdUSB_L
H16(bcdUSB), // bcdUSB_H
USB_CLASS_PER_INTERFACE, // bDeviceClass
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0BUFSZ, // bMaxPacketSize0
bNumConfigurations, // bNumConfigurations
0 // Reserved
};
#define wTotalLength (USB_DT_CONFIG_SIZE + (bNumInterfaces * USB_DT_INTERFACE_SIZE) + (bTotNumEndpoints * USB_DT_ENDPOINT_SIZE) + (bNumCsInterfaces * USB_DT_CS_INTERFACE_SIZE) - 1)
static const uint8_t USB_ConfigDescriptor[] = {
// Configuration Descriptor
USB_DT_CONFIG_SIZE, // bLength: Configuration Descriptor size
USB_DT_CONFIG, // bDescriptorType: Configuration
L16(wTotalLength), // wTotalLength.L :no of returned bytes
H16(wTotalLength), // wTotalLength.H
bNumInterfaces, // bNumInterfaces
1, // bConfigurationValue: Current configuration value
0, // iConfiguration: Index of string descriptor describing the configuration or 0
BusPowered, // bmAttributes - Bus powered
50, // MaxPower in 2mA units
//---------------------------------------------------------------------------
// Virtual command Interface Descriptor
USB_DT_INTERFACE_SIZE, // bLength: Interface Descriptor size
USB_DT_INTERFACE, // bDescriptorType: Interface
0, // bInterfaceNumber: Number of Interface
0, // bAlternateSetting: Alternate setting
1, // bNumEndpoints: one for this
USB_CLASS_COMM, // bInterfaceClass
2, // bInterfaceSubClass: ACM
1, // bInterfaceProtocol: Common AT commands
iINTERFACE_DESCR1, // iInterface
// ---- CS Interfaces
USB_DT_CS_INTERFACE_SIZE, // bLength
USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
0, // bDescriptorSubtype: Header Func Desc
0x10, // bcdCDC: spec release number
1, // bDataInterface
USB_DT_CS_INTERFACE_SIZE, // bLength
USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
1, // bDescriptorSubtype: Call Management Func Desc
0, // bmCapabilities: D0+D1
1, // bDataInterface
USB_DT_CS_INTERFACE_SIZE-1, // bLength
USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
2, // bDescriptorSubtype: Abstract Control Management desc
2, // bmCapabilities
USB_DT_CS_INTERFACE_SIZE, // bLength
USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE
6, // bDescriptorSubtype: Union func desc
0, // bMasterInterface: Communication class interface
1, // bSlaveInterface0: Data Class Interface
// Virtual endpoint 1 Descriptor
USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size
USB_DT_ENDPOINT, // bDescriptorType: Endpoint
0x8A, // bEndpointAddress IN10
USB_BM_ATTR_INTERRUPT, // bmAttributes: Interrupt
L16(USB_EP1BUFSZ), // wMaxPacketSize LO
H16(USB_EP1BUFSZ), // wMaxPacketSize HI
0x10, // bInterval: 16ms
//---------------------------------------------------------------------------
// Data interface
USB_DT_INTERFACE_SIZE, // bLength: Interface Descriptor size
USB_DT_INTERFACE, // bDescriptorType: Interface
1, // bInterfaceNumber: Number of Interface
0, // bAlternateSetting: Alternate setting
2, // bNumEndpoints: in and out
USB_CLASS_DATA, // bInterfaceClass
2, // bInterfaceSubClass: ACM
0, // bInterfaceProtocol
0, // iInterface
//Endpoint IN1 Descriptor
USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size
USB_DT_ENDPOINT, // bDescriptorType: Endpoint
0x81, // bEndpointAddress: IN1
USB_BM_ATTR_BULK, // bmAttributes: Bulk
L16(USB_TXBUFSZ), // wMaxPacketSize LO
H16(USB_TXBUFSZ), // wMaxPacketSize HI
0, // bInterval: ignore for Bulk transfer
// Endpoint OUT1 Descriptor
USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size
USB_DT_ENDPOINT, // bDescriptorType: Endpoint
0x01, // bEndpointAddress: OUT1
USB_BM_ATTR_BULK, // bmAttributes: Bulk
L16(USB_RXBUFSZ), // wMaxPacketSize LO
H16(USB_RXBUFSZ), // wMaxPacketSize HI
0, // bInterval: ignore for Bulk transfer
};
//const uint8_t HID_ReportDescriptor[];
_USB_LANG_ID_(LD, LANG_US);
_USB_STRING_(SD, u"0.0.1");
_USB_STRING_(MD, u"eddy@sao.ru");
_USB_STRING_(PD, u"USB CDC Controller");
_USB_STRING_(ID, u"multistepper");
static const void* const StringDescriptor[iDESCR_AMOUNT] = {
[iLANGUAGE_DESCR] = &LD,
[iMANUFACTURER_DESCR] = &MD,
[iPRODUCT_DESCR] = &PD,
[iSERIAL_DESCR] = &SD,
[iINTERFACE_DESCR1] = &ID
};
static void wr0(const uint8_t *buf, uint16_t size, uint16_t askedsize){
if(askedsize < size) size = askedsize; // shortened request
if(size < USB_EP0BUFSZ){
EP_WriteIRQ(0, buf, size);
return;
}
while(size){
uint16_t l = size;
if(l > USB_EP0BUFSZ) l = USB_EP0BUFSZ;
EP_WriteIRQ(0, buf, l);
buf += l;
size -= l;
uint8_t needzlp = (l == USB_EP0BUFSZ) ? 1 : 0;
if(size || needzlp){ // send last data buffer
uint16_t epstatus = KEEP_DTOG(USB->EPnR[0]);
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
^ USB_EPnR_STAT_TX;
uint32_t ctr = 1000000;
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
if((USB->ISTR & USB_ISTR_CTR) == 0){
return;
}
if(needzlp) EP_WriteIRQ(0, NULL, 0);
}
}
}
void get_descriptor(config_pack_t *pack){
uint8_t descrtype = pack->wValue >> 8,
descridx = pack->wValue & 0xff;
switch(descrtype){
case DEVICE_DESCRIPTOR:
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor), pack->wLength);
break;
case CONFIGURATION_DESCRIPTOR:
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor), pack->wLength);
break;
case STRING_DESCRIPTOR:
if(descridx < iDESCR_AMOUNT){
wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx]), pack->wLength);
}else{
EP_WriteIRQ(0, NULL, 0);
}
break;
case DEVICE_QUALIFIER_DESCRIPTOR:
wr0(USB_DeviceQualifierDescriptor, sizeof(USB_DeviceQualifierDescriptor), pack->wLength);
break;
/* case HID_REPORT_DESCRIPTOR:
wr0(HID_ReportDescriptor, sizeof(HID_ReportDescriptor), pack->wLength);
break;*/
default:
break;
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include "usb_lib.h"
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
// bcdUSB: 1.10
#define bcdUSB 0x0110
// Class - Misc (EF), subclass - common (2), protocol - interface association descr (1)
#define bDeviceSubClass 0x02
#define bDeviceProtocol 0x01
#define idVendor 0x0483
#define idProduct 0x5740
#define bcdDevice_Ver 0x0200
#define bNumConfigurations 1
// amount of interfaces and endpoints (except 0) used
#define bNumInterfaces 2
#define bTotNumEndpoints 3
#define bNumCsInterfaces 4
// powered
#define BusPowered (1<<7)
#define SelfPowered (1<<6)
#define RemoteWakeup (1<<5)
// buffer sizes
// for USB FS EP0 buffers are from 8 to 64 bytes long
#define USB_EP0BUFSZ 64
#define USB_EP1BUFSZ 10
// Rx/Tx EPs
#define USB_RXBUFSZ 64
#define USB_TXBUFSZ 64
// string descriptors
enum{
iLANGUAGE_DESCR,
iMANUFACTURER_DESCR,
iPRODUCT_DESCR,
iSERIAL_DESCR,
iINTERFACE_DESCR1,
iDESCR_AMOUNT
};
void get_descriptor(config_pack_t *pack);

View File

@ -0,0 +1,240 @@
/*
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "ringbuffer.h"
#include "usb_descr.h"
#include "usb_dev.h"
// Class-Specific Control Requests
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
#define SET_COMM_FEATURE 0x02 // unused
#define GET_COMM_FEATURE 0x03 // unused
#define CLEAR_COMM_FEATURE 0x04 // unused
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
#define SEND_BREAK 0x23
// control line states
#define CONTROL_DTR 0x01
#define CONTROL_RTS 0x02
// inbuf overflow when receiving
static volatile uint8_t bufovrfl = 0;
// receive buffer: hold data until chkin() call
static uint8_t volatile rcvbuf[USB_RXBUFSZ];
static uint8_t volatile rcvbuflen = 0;
// line coding
usb_LineCoding WEAK lineCoding = {115200, 0, 0, 8};
// CDC configured and ready to use
volatile uint8_t CDCready = 0;
// ring buffers for incoming and outgoing data
static uint8_t obuf[RBOUTSZ], ibuf[RBINSZ];
static volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0};
static volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0};
// last send data size
static volatile int lastdsz = 0;
static void chkin(){
if(bufovrfl) return; // allow user to know that previous buffer was overflowed and cleared
if(!rcvbuflen) return;
int w = RB_write((ringbuffer*)&rbin, (uint8_t*)rcvbuf, rcvbuflen);
if(w < 0){
return;
}
if(w != rcvbuflen) bufovrfl = 1;
rcvbuflen = 0;
uint16_t status = KEEP_DTOG(USB->EPnR[1]); // don't change DTOG
USB->EPnR[1] = (status & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_RX)) ^ USB_EPnR_STAT_RX; // prepare to get next data portion
}
// called from transmit EP to send next data portion or by user - when new transmission starts
static void send_next(){
uint8_t usbbuff[USB_TXBUFSZ];
int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ);
if(buflen == 0){
if(lastdsz == 64) EP_Write(1, NULL, 0); // send ZLP after 64 bits packet when nothing more to send
lastdsz = 0;
return;
}else if(buflen < 0){
lastdsz = 0;
return;
}
EP_Write(1, (uint8_t*)usbbuff, buflen);
lastdsz = buflen;
}
// data IN/OUT handler
static void rxtx_handler(){
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
if(RX_FLAG(epstatus)){ // receive data
if(rcvbuflen){
bufovrfl = 1; // lost last data
rcvbuflen = 0;
}
rcvbuflen = EP_Read(1, (uint8_t*)rcvbuf);
USB->EPnR[1] = epstatus & ~(USB_EPnR_CTR_RX | USB_EPnR_STAT_RX | USB_EPnR_STAT_TX); // keep RX in STALL state until read data
chkin(); // try to write current data into RXbuf if it's not busy
}else{ // tx successfull
USB->EPnR[1] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
send_next();
}
}
// weak handlers: change them somewhere else if you want to setup USART
// SET_LINE_CODING
void WEAK linecoding_handler(usb_LineCoding *lc){
lineCoding = *lc;
}
// SET_CONTROL_LINE_STATE
void WEAK clstate_handler(uint16_t val){
CDCready = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected
}
// SEND_BREAK
void WEAK break_handler(){
CDCready = 0;
}
// USB is configured: setup endpoints
void set_configuration(){
EP_Init(1, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_handler); // IN1 and OUT1
}
// PL2303 CLASS request
void usb_class_request(config_pack_t *req, uint8_t *data, uint16_t datalen){
uint8_t recipient = REQUEST_RECIPIENT(req->bmRequestType);
uint8_t dev2host = (req->bmRequestType & 0x80) ? 1 : 0;
switch(recipient){
case REQ_RECIPIENT_INTERFACE:
switch(req->bRequest){
case SET_LINE_CODING:
if(!data || !datalen) break; // wait for data
if(datalen == sizeof(usb_LineCoding))
linecoding_handler((usb_LineCoding*)data);
break;
case GET_LINE_CODING:
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
break;
case SET_CONTROL_LINE_STATE:
clstate_handler(req->wValue);
break;
case SEND_BREAK:
break_handler();
break;
default:
break;
}
break;
default:
if(dev2host) EP_WriteIRQ(0, NULL, 0);
}
if(!dev2host) EP_WriteIRQ(0, NULL, 0);
}
// blocking send full content of ring buffer
int USB_sendall(){
while(lastdsz > 0){
if(!CDCready) return FALSE;
}
return TRUE;
}
// put `buf` into queue to send
int USB_send(const uint8_t *buf, int len){
if(!buf || !CDCready || !len) return FALSE;
while(len){
int a = RB_write((ringbuffer*)&rbout, buf, len);
if(a > 0){
len -= a;
buf += a;
} else if (a < 0) continue; // do nothing if buffer is in reading state
if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN
}
return TRUE;
}
int USB_putbyte(uint8_t byte){
if(!CDCready) return FALSE;
int l = 0;
while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){
if(l < 0) continue;
}
if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN
return TRUE;
}
int USB_sendstr(const char *string){
if(!string || !CDCready) return FALSE;
int len = 0;
const char *b = string;
while(*b++) ++len;
if(!len) return FALSE;
return USB_send((const uint8_t*)string, len);
}
/**
* @brief USB_receive - get binary data from receiving ring-buffer
* @param buf (i) - buffer for received data
* @param len - length of `buf`
* @return amount of received bytes (negative, if overfull happened)
*/
int USB_receive(uint8_t *buf, int len){
chkin();
if(bufovrfl){
while(1 != RB_clearbuf((ringbuffer*)&rbin));
bufovrfl = 0;
return -1;
}
int sz = RB_read((ringbuffer*)&rbin, buf, len);
if(sz < 0) return 0; // buffer in writting state
return sz;
}
/**
* @brief USB_receivestr - get string up to '\n' and replace '\n' with 0
* @param buf - receiving buffer
* @param len - its length
* @return strlen or negative value indicating overflow (if so, string won't be ends with 0 and buffer should be cleared)
*/
int USB_receivestr(char *buf, int len){
chkin();
if(bufovrfl){
while(1 != RB_clearbuf((ringbuffer*)&rbin));
bufovrfl = 0;
return -1;
}
int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len);
if(l < 1){
if(rbin.length == RB_datalen((ringbuffer*)&rbin)){ // buffer is full but no '\n' found
while(1 != RB_clearbuf((ringbuffer*)&rbin));
return -1;
}
return 0;
}
if(l == 0) return 0;
buf[l-1] = 0; // replace '\n' with strend
return l;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stm32f3.h>
#include "usb_lib.h"
typedef struct {
uint32_t dwDTERate;
uint8_t bCharFormat;
#define USB_CDC_1_STOP_BITS 0
#define USB_CDC_1_5_STOP_BITS 1
#define USB_CDC_2_STOP_BITS 2
uint8_t bParityType;
#define USB_CDC_NO_PARITY 0
#define USB_CDC_ODD_PARITY 1
#define USB_CDC_EVEN_PARITY 2
#define USB_CDC_MARK_PARITY 3
#define USB_CDC_SPACE_PARITY 4
uint8_t bDataBits;
} __attribute__ ((packed)) usb_LineCoding;
extern usb_LineCoding lineCoding;
extern volatile uint8_t CDCready;
void break_handler();
void clstate_handler(uint16_t val);
void linecoding_handler(usb_LineCoding *lc);
// sizes of ringbuffers for outgoing and incoming data
#define RBOUTSZ (1024)
#define RBINSZ (1024)
#define newline() USB_putbyte('\n')
#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0)
int USB_sendall();
int USB_send(const uint8_t *buf, int len);
int USB_putbyte(uint8_t byte);
int USB_sendstr(const char *string);
int USB_receive(uint8_t *buf, int len);
int USB_receivestr(char *buf, int len);

View File

@ -15,280 +15,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdint.h> #include <stdint.h>
#include "usb.h"
#include "usb_lib.h"
#include "usbhw.h"
ep_t endpoints[STM32ENDPOINTS]; #include "usb_lib.h"
#include "usb_descr.h"
#include "usb_dev.h"
static ep_t endpoints[STM32ENDPOINTS];
static uint16_t USB_Addr = 0; static uint16_t USB_Addr = 0;
static usb_LineCoding lineCoding = {115200, 0, 0, 8}; static uint8_t setupdatabuf[EP0DATABUF_SIZE];
uint8_t ep0databuf[EP0DATABUF_SIZE], setupdatabuf[EP0DATABUF_SIZE]; static config_pack_t *setup_packet = (config_pack_t*) setupdatabuf;
config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; volatile uint8_t usbON = 0; // device is configured and active
usb_LineCoding getLineCoding(){return lineCoding;}
volatile uint8_t usbON = 0; // device disconnected from terminal
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
#define bcdUSB_L 0x10
#define bcdUSB_H 0x01
#define bDeviceClass 0
#define bDeviceSubClass 0
#define bDeviceProtocol 0
#define bNumConfigurations 1
static const uint8_t USB_DeviceDescriptor[] = {
18, // bLength
0x01, // bDescriptorType - Device descriptor
bcdUSB_L, // bcdUSB_L - 1.10
bcdUSB_H, // bcdUSB_H
bDeviceClass, // bDeviceClass - USB_COMM
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0_BUFSZ, // bMaxPacketSize
0x7b, // idVendor_L PL2303: VID=0x067b, PID=0x2303
0x06, // idVendor_H
0x03, // idProduct_L
0x23, // idProduct_H
0x00, // bcdDevice_Ver_L
0x03, // bcdDevice_Ver_H
iMANUFACTURER_DESCR, // iManufacturer
iPRODUCT_DESCR, // iProduct
iSERIAL_DESCR, // iSerialNumber
bNumConfigurations // bNumConfigurations
};
static const uint8_t USB_DeviceQualifierDescriptor[] = {
10, //bLength
0x06, // bDescriptorType - Device qualifier
bcdUSB_L, // bcdUSB_L
bcdUSB_H, // bcdUSB_H
bDeviceClass, // bDeviceClass
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0_BUFSZ, // bMaxPacketSize0
bNumConfigurations, // bNumConfigurations
0x00 // Reserved
};
static const uint8_t USB_ConfigDescriptor[] = {
/*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */
0x02, /* bDescriptorType: Configuration */
39, /* wTotalLength:no of returned bytes */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0xa0, /* bmAttributes - Bus powered, Remote wakeup */
0x32, /* MaxPower 100 mA */
/*---------------------------------------------------------------------------*/
/*Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: Interface */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x03, /* bNumEndpoints: 3 endpoints used */
0xff, /* bInterfaceClass */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
iINTERFACE_DESCR, /* iInterface: */
///////////////////////////////////////////////////
/*Endpoint 1 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x81, /* bEndpointAddress IN1 */
0x03, /* bmAttributes: Interrupt */
0x0a, /* wMaxPacketSize LO: */
0x00, /* wMaxPacketSize HI: */
0x01, /* bInterval: */
/*Endpoint OUT2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x02, /* bEndpointAddress: OUT2 */
0x02, /* bmAttributes: Bulk */
(USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
(USB_RXBUFSZ >> 8),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN3 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x83, /* bEndpointAddress IN3 */
0x02, /* bmAttributes: Bulk */
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
(USB_TXBUFSZ >> 8),
0x00, /* bInterval: ignore for Bulk transfer */
};
_USB_LANG_ID_(LD, LANG_US);
_USB_STRING_(SD, u"0.0.1");
_USB_STRING_(MD, u"Prolific Technology Inc.");
_USB_STRING_(PD, u"USB-Serial Controller");
_USB_STRING_(ID, u"USB-STM32");
static void const *StringDescriptor[iDESCR_AMOUNT] = {
[iLANGUAGE_DESCR] = &LD,
[iMANUFACTURER_DESCR] = &MD,
[iPRODUCT_DESCR] = &PD,
[iSERIAL_DESCR] = &SD,
[iINTERFACE_DESCR] = &ID
};
/*
* default handlers
*/
// SET_LINE_CODING
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
}
// SET_CONTROL_LINE_STATE
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
}
// SEND_BREAK
void WEAK break_handler(){
}
// handler of vendor requests
void WEAK vendor_handler(config_pack_t *packet){
uint16_t c;
if(packet->bmRequestType & 0x80){ // read
switch(packet->wValue){
case 0x8484:
c = 2;
break;
case 0x0080:
c = 1;
break;
case 0x8686:
c = 0xaa;
break;
default:
c = 0;
}
EP_WriteIRQ(0, (uint8_t*)&c, 1);
}else{ // write ZLP
c = 0;
EP_WriteIRQ(0, (uint8_t *)&c, 0);
}
}
static void wr0(const uint8_t *buf, uint16_t size){
if(setup_packet->wLength < size) size = setup_packet->wLength; // shortened request
if(size < endpoints[0].txbufsz){
EP_WriteIRQ(0, buf, size);
return;
}
while(size){
uint16_t l = size;
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
EP_WriteIRQ(0, buf, l);
buf += l;
size -= l;
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
if(size || needzlp){ // send last data buffer
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
^ USB_EPnR_STAT_TX;
uint32_t ctr = 1000000;
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
if((USB->ISTR & USB_ISTR_CTR) == 0){
return;
}
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
}
}
}
static inline void get_descriptor(){
uint8_t descrtype = setup_packet->wValue >> 8,
descridx = setup_packet->wValue & 0xff;
switch(descrtype){
case DEVICE_DESCRIPTOR:
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
break;
case CONFIGURATION_DESCRIPTOR:
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
break;
case STRING_DESCRIPTOR:
if(descridx < iDESCR_AMOUNT) wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx]));
else EP_WriteIRQ(0, (uint8_t*)0, 0);
break;
case DEVICE_QUALIFIER_DESCRIPTOR:
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
break;
default:
break;
}
}
static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
static inline void std_d2h_req(){ static inline void std_d2h_req(){
uint16_t status = 0; // bus powered uint16_t st = 0;
switch(setup_packet->bRequest){ switch(setup_packet->bRequest){
case GET_DESCRIPTOR: case GET_DESCRIPTOR:
get_descriptor(); get_descriptor(setup_packet);
break; break;
case GET_STATUS: case GET_STATUS:
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered EP_WriteIRQ(0, (uint8_t *)&st, 2); // send status: Bus Powered
break; break;
case GET_CONFIGURATION: case GET_CONFIGURATION:
EP_WriteIRQ(0, (uint8_t*)&configuration, 1); EP_WriteIRQ(0, (uint8_t*)&configuration, 1);
break; break;
default: default:
EP_WriteIRQ(0, NULL, 0);
break; break;
} }
} }
// interrupt IN handler (never used?)
static void EP1_Handler(){
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX
else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX);
// clear CTR
epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX));
USB->EPnR[1] = epstatus;
}
// data IN/OUT handlers
static void transmit_Handler(){ // EP3IN
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]);
// clear CTR keep DTOGs & STATs
USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr
send_next();
}
static uint8_t volatile rcvbuf[USB_RXBUFSZ];
static uint8_t volatile rcvbuflen = 0;
void chkin(){
if(bufovrfl) return;
if(!rcvbuflen) return;
int w = RB_write((ringbuffer*)&rbin, (uint8_t*)rcvbuf, rcvbuflen);
if(w < 0) return;
if(w != rcvbuflen) bufovrfl = 1;
rcvbuflen = 0;
uint16_t status = KEEP_DTOG(USB->EPnR[2]); // don't change DTOG
USB->EPnR[2] = status ^ USB_EPnR_STAT_RX;
}
// receiver reads data from local buffer and only then ACK'ed
static void receive_Handler(){ // EP2OUT
uint16_t status = KEEP_DTOG_STAT(USB->EPnR[2]); // don't change DTOG and NACK
if(rcvbuflen){
bufovrfl = 1; // lost last data
rcvbuflen = 0;
}
rcvbuflen = EP_Read(2, (uint8_t*)rcvbuf);
USB->EPnR[2] = status & ~USB_EPnR_CTR_RX;
}
static inline void std_h2d_req(){ static inline void std_h2d_req(){
switch(setup_packet->bRequest){ switch(setup_packet->bRequest){
case SET_ADDRESS: case SET_ADDRESS:
@ -298,15 +55,58 @@ static inline void std_h2d_req(){
case SET_CONFIGURATION: case SET_CONFIGURATION:
// Now device configured // Now device configured
configuration = setup_packet->wValue; configuration = setup_packet->wValue;
EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit set_configuration();
EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data usbON = 1;
EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data
break; break;
default: default:
break; break;
} }
} }
void WEAK usb_standard_request(){
uint8_t recipient = REQUEST_RECIPIENT(setup_packet->bmRequestType);
uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0;
switch(recipient){
case REQ_RECIPIENT_DEVICE:
if(dev2host){
std_d2h_req();
}else{
std_h2d_req();
}
break;
case REQ_RECIPIENT_INTERFACE:
if(dev2host && setup_packet->bRequest == GET_DESCRIPTOR){
get_descriptor(setup_packet);
}
break;
case REQ_RECIPIENT_ENDPOINT:
if(setup_packet->bRequest == CLEAR_FEATURE){
}else{ /* wrong */ }
break;
default:
break;
}
if(!dev2host) EP_WriteIRQ(0, NULL, 0);
}
void WEAK usb_class_request(config_pack_t *req, uint8_t _U_ *data, uint16_t _U_ datalen){
switch(req->bRequest){
case GET_INTERFACE:
break;
case SET_CONFIGURATION: // set featuring by req->wValue
break;
default:
break;
}
if(0 == (setup_packet->bmRequestType & 0x80)) // host2dev
EP_WriteIRQ(0, NULL, 0);
}
void WEAK usb_vendor_request(config_pack_t _U_ *packet, uint8_t _U_ *data, uint16_t _U_ datalen){
if(0 == (setup_packet->bmRequestType & 0x80)) // host2dev
EP_WriteIRQ(0, NULL, 0);
}
/* /*
bmRequestType: 76543210 bmRequestType: 76543210
7 direction: 0 - host->device, 1 - device->host 7 direction: 0 - host->device, 1 - device->host
@ -316,67 +116,50 @@ bmRequestType: 76543210
/** /**
* Endpoint0 (control) handler * Endpoint0 (control) handler
*/ */
void EP0_Handler(){ static void EP0_Handler(){
uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications uint8_t ep0dbuflen = 0;
uint8_t reqtype = setup_packet->bmRequestType & 0x7f; uint8_t ep0databuf[EP0DATABUF_SIZE];
uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; uint16_t epstatus = KEEP_DTOG(USB->EPnR[0]); // EP0R on input -> return this value after modifications
int rxflag = RX_FLAG(epstatus); int rxflag = RX_FLAG(epstatus);
if(rxflag && SETUP_FLAG(epstatus)){ //if(rxflag){ }
switch(reqtype){ // check direction
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit)
if(dev2host){ if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
std_d2h_req(); EP_Read(0, setupdatabuf);
}else{ // interrupt handler will be called later
std_h2d_req(); }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
EP_WriteIRQ(0, (uint8_t *)0, 0); //if(endpoints[0].rx_cnt){ }
} ep0dbuflen = EP_Read(0, ep0databuf);
break;
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
if(setup_packet->bRequest == CLEAR_FEATURE){
EP_WriteIRQ(0, (uint8_t *)0, 0);
}
break;
case VENDOR_REQUEST_TYPE:
vendor_handler(setup_packet);
break;
case CONTROL_REQUEST_TYPE:
switch(setup_packet->bRequest){
case GET_LINE_CODING:
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
break;
case SET_LINE_CODING: // omit this for next stage, when data will come
break;
case SET_CONTROL_LINE_STATE:
usbON = 1;
clstate_handler(setup_packet->wValue);
break;
case SEND_BREAK:
usbON = 0;
break_handler();
break;
default:
break;
}
if(setup_packet->bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement
break;
default:
EP_WriteIRQ(0, (uint8_t *)0, 0);
}
}else if(rxflag){ // got data over EP0 or host acknowlegement
if(endpoints[0].rx_cnt){
if(setup_packet->bRequest == SET_LINE_CODING){
linecoding_handler((usb_LineCoding*)ep0databuf);
} }
}
if(rxflag){
uint8_t reqtype = REQUEST_TYPE(setup_packet->bmRequestType);
switch(reqtype){
case REQ_TYPE_STANDARD:
if(SETUP_FLAG(epstatus)){
usb_standard_request();
}else{ }
break;
case REQ_TYPE_CLASS:
usb_class_request(setup_packet, ep0databuf, ep0dbuflen);
break;
case REQ_TYPE_VENDOR:
usb_vendor_request(setup_packet, ep0databuf, ep0dbuflen);
break;
default:
EP_WriteIRQ(0, NULL, 0);
break;
} }
} else if(TX_FLAG(epstatus)){ // package transmitted }
if(TX_FLAG(epstatus)){
// now we can change address after enumeration // now we can change address after enumeration
if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){ if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){
USB->DADDR = USB_DADDR_EF | USB_Addr; USB->DADDR = USB_DADDR_EF | USB_Addr;
usbON = 0; usbON = 0;
} }
} }
epstatus = KEEP_DTOG(USB->EPnR[0]); //epstatus = KEEP_DTOG(USB->EPnR[0]);
if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP or data transmission
else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
// keep DTOGs, clear CTR_RX,TX, set RX VALID // keep DTOGs, clear CTR_RX,TX, set RX VALID
USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
@ -418,9 +201,9 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
*/ */
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
EP_WriteIRQ(number, buf, size); EP_WriteIRQ(number, buf, size);
uint16_t status = KEEP_DTOG(USB->EPnR[number]); uint16_t epstatus = KEEP_DTOG(USB->EPnR[number]);
// keep DTOGs, clear CTR_TX & set TX VALID to start transmission // keep DTOGs and RX stat, clear CTR_TX & set TX VALID to start transmission
USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX; USB->EPnR[number] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_RX)) ^ USB_EPnR_STAT_TX;
} }
/* /*
@ -461,11 +244,11 @@ static uint16_t lastaddr = LASTADDR_DEFAULT;
*/ */
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){
if(number >= STM32ENDPOINTS) return 4; // out of configured amount if(number >= STM32ENDPOINTS) return 4; // out of configured amount
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large if(txsz > USB_BTABLE_SIZE/ACCESSZ || rxsz > USB_BTABLE_SIZE/ACCESSZ) return 1; // buffer too large
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE/ACCESSZ) return 2; // out of btable if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE/ACCESSZ) return 2; // out of btable
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1; USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
if(rxsz & 1 || rxsz > USB_BTABLE_SIZE) return 3; // wrong rx buffer size if(rxsz & 1) return 3; // wrong rx buffer size
uint16_t countrx = 0; uint16_t countrx = 0;
if(rxsz < 64) countrx = rxsz / 2; if(rxsz < 64) countrx = rxsz / 2;
else{ else{
@ -487,60 +270,95 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*f
// standard IRQ handler // standard IRQ handler
void USB_IRQ(){ void USB_IRQ(){
uint32_t CNTR = USB->CNTR;
USB->CNTR = 0;
if(USB->ISTR & USB_ISTR_RESET){ if(USB->ISTR & USB_ISTR_RESET){
usbON = 0; usbON = 0;
// Reinit registers // Reinit registers
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM;
// Endpoint 0 - CONTROL // Endpoint 0 - CONTROL
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
lastaddr = LASTADDR_DEFAULT; lastaddr = LASTADDR_DEFAULT;
// clear address, leave only enable bit // clear address, leave only enable bit
USB->DADDR = USB_DADDR_EF; USB->DADDR = USB_DADDR_EF;
if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){
return;
}
USB->ISTR = ~USB_ISTR_RESET; USB->ISTR = ~USB_ISTR_RESET;
if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0BUFSZ, USB_EP0BUFSZ, EP0_Handler)){
return;
};
} }
if(USB->ISTR & USB_ISTR_CTR){ if(USB->ISTR & USB_ISTR_CTR){
// EP number // EP number
uint8_t n = USB->ISTR & USB_ISTR_EPID; uint8_t n = USB->ISTR & USB_ISTR_EPID;
// copy status register
uint16_t epstatus = USB->EPnR[n];
// copy received bytes amount // copy received bytes amount
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
// check direction
if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit)
if(n == 0){ // control endpoint
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
EP_Read(0, setupdatabuf);
// interrupt handler will be called later
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
EP_Read(0, ep0databuf);
}
}
}
// call EP handler // call EP handler
if(endpoints[n].func) endpoints[n].func(endpoints[n]); if(endpoints[n].func) endpoints[n].func();
}
if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
#ifndef STM32F0
CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM); // clear suspend flags
#else
CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM);
#endif
USB->ISTR = ~USB_ISTR_WKUP;
} }
if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
usbON = 0; usbON = 0;
#ifndef STM32F0 #ifndef STM32F0
USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE; CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM;
#else #else
USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE; CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM;
#endif #endif
CNTR &= ~(USB_CNTR_SUSPM);
USB->ISTR = ~USB_ISTR_SUSP; USB->ISTR = ~USB_ISTR_SUSP;
} }
if(USB->ISTR & USB_ISTR_WKUP){ // wakeup USB->CNTR = CNTR; // rewoke interrupts
#ifndef STM32F0
USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE); // clear suspend flags
#else
USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE);
#endif
USB->ISTR = ~USB_ISTR_WKUP;
}
} }
// here we suppose that all PIN settings done in hw_setup earlier
void USB_setup(){
#if defined STM32F3
NVIC_DisableIRQ(USB_LP_IRQn);
// remap USB LP & Wakeup interrupts to 75 and 76 - works only on pure F303
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // enable tacting of SYSCFG
SYSCFG->CFGR1 |= SYSCFG_CFGR1_USB_IT_RMP;
#elif defined STM32F1
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
#elif defined STM32F0
NVIC_DisableIRQ(USB_IRQn);
RCC->APB1ENR |= RCC_APB1ENR_CRSEN;
RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB
RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48
uint32_t tmout = 16000000;
while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break;}
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
CRS->CFGR &= ~CRS_CFGR_SYNCSRC;
CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source
CRS->CR |= CRS_CR_AUTOTRIMEN; // enable auto trim
CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only
RCC->CFGR |= RCC_CFGR_SW;
#endif
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
//??
USB->CNTR = USB_CNTR_FRES; // Force USB Reset
for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms
USB->CNTR = 0;
USB->BTABLE = 0;
USB->DADDR = 0;
USB->ISTR = 0;
USB->CNTR = USB_CNTR_RESETM; // allow only reset interrupts
#if defined STM32F3
NVIC_EnableIRQ(USB_LP_IRQn);
#elif defined STM32F1
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
#elif defined STM32F0
USB->BCDR |= USB_BCDR_DPPU;
NVIC_EnableIRQ(USB_IRQn);
#endif
}
#if defined STM32F3 #if defined STM32F3
void usb_lp_isr() __attribute__ ((alias ("USB_IRQ"))); void usb_lp_isr() __attribute__ ((alias ("USB_IRQ")));
#elif defined STM32F1 #elif defined STM32F1

View File

@ -16,63 +16,255 @@
*/ */
#pragma once #pragma once
#include <stdint.h>
#include <wchar.h> #include <wchar.h>
#include "usbhw.h"
#ifndef _U_
#define _U_ __attribute__((unused))
#endif
/******************************************************************
* Hardware registers etc *
*****************************************************************/
#if defined STM32F0
#include <stm32f0.h>
#elif defined STM32F1
#include <stm32f1.h>
// there's no this define in standard header
#define USB_BASE ((uint32_t)0x40005C00)
#elif defined STM32F3
#include <stm32f3.h>
#endif
// max endpoints number
#define STM32ENDPOINTS 8
/**
* Buffers size definition
**/
// F0 - USB2_16; F1 - USB1_16; F3 - 1/2 depending on series
#if !defined USB1_16 && !defined USB2_16
#if defined STM32F0
#define USB2_16
#elif defined STM32F1
#define USB1_16
#else
#error "Can't determine USB1_16 or USB2_16, define by hands"
#endif
#endif
// BTABLE_SIZE FOR STM32F3:
// In STM32F303/302xB/C, 512 bytes SRAM is not shared with CAN.
// In STM32F302x6/x8 and STM32F30xxD/E, 726 bytes dedicated SRAM and 256 bytes shared SRAM with CAN i.e.
// 1Kbytes dedicated SRAM in case CAN is disabled.
// remember, that USB_BTABLE_SIZE will be divided by ACCESSZ, so don't divide it twice for 32-bit addressing
#ifdef NOCAN
#if defined STM32F0
#define USB_BTABLE_SIZE 1024
#elif defined STM32F3
#define USB_BTABLE_SIZE 726
//#warning "Please, check real buffer size due to docs"
#else
#error "define STM32F0 or STM32F3"
#endif
#else // !NOCAN: F0/F3 with CAN or F1 (can't simultaneously run CAN and USB)
#if defined STM32F0
#define USB_BTABLE_SIZE 768
#elif defined STM32F3
#define USB_BTABLE_SIZE 726
//#warning "Please, check real buffer size due to docs"
#else // STM32F103: 1024 bytes but with 32-bit addressing
#define USB_BTABLE_SIZE 1024
#endif
#endif // NOCAN
// first 64 bytes of USB_BTABLE are registers!
#define USB_BTABLE_BASE 0x40006000
#define USB ((USB_TypeDef *) USB_BASE)
#ifdef USB_BTABLE
#undef USB_BTABLE
#endif
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
#define USB_ISTR_EPID 0x0000000F
#define USB_FNR_LSOF_0 0x00000800
#define USB_FNR_lSOF_1 0x00001000
#define USB_LPMCSR_BESL_0 0x00000010
#define USB_LPMCSR_BESL_1 0x00000020
#define USB_LPMCSR_BESL_2 0x00000040
#define USB_LPMCSR_BESL_3 0x00000080
#define USB_EPnR_CTR_RX 0x00008000
#define USB_EPnR_DTOG_RX 0x00004000
#define USB_EPnR_STAT_RX 0x00003000
#define USB_EPnR_STAT_RX_0 0x00001000
#define USB_EPnR_STAT_RX_1 0x00002000
#define USB_EPnR_SETUP 0x00000800
#define USB_EPnR_EP_TYPE 0x00000600
#define USB_EPnR_EP_TYPE_0 0x00000200
#define USB_EPnR_EP_TYPE_1 0x00000400
#define USB_EPnR_EP_KIND 0x00000100
#define USB_EPnR_CTR_TX 0x00000080
#define USB_EPnR_DTOG_TX 0x00000040
#define USB_EPnR_STAT_TX 0x00000030
#define USB_EPnR_STAT_TX_0 0x00000010
#define USB_EPnR_STAT_TX_1 0x00000020
#define USB_EPnR_EA 0x0000000F
#define USB_COUNTn_RX_BLSIZE 0x00008000
#define USB_COUNTn_NUM_BLOCK 0x00007C00
#define USB_COUNTn_RX 0x0000003F
#define USB_TypeDef USB_TypeDef_custom
typedef struct {
__IO uint32_t EPnR[STM32ENDPOINTS];
__IO uint32_t RESERVED[STM32ENDPOINTS];
__IO uint32_t CNTR;
__IO uint32_t ISTR;
__IO uint32_t FNR;
__IO uint32_t DADDR;
__IO uint32_t BTABLE;
#ifdef STM32F0
__IO uint32_t LPMCSR;
__IO uint32_t BCDR;
#endif
} USB_TypeDef;
// F303 D/E have 2x16 access scheme
typedef struct{
#if defined USB2_16
__IO uint16_t USB_ADDR_TX;
__IO uint16_t USB_COUNT_TX;
__IO uint16_t USB_ADDR_RX;
__IO uint16_t USB_COUNT_RX;
#define ACCESSZ (1)
#define BUFTYPE uint8_t
#elif defined USB1_16
__IO uint32_t USB_ADDR_TX;
__IO uint32_t USB_COUNT_TX;
__IO uint32_t USB_ADDR_RX;
__IO uint32_t USB_COUNT_RX;
#define ACCESSZ (2)
#define BUFTYPE uint16_t
#else
#error "Define USB1_16 or USB2_16"
#endif
} USB_EPDATA_TypeDef;
typedef struct{
__IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
} USB_BtableDef;
#define EP0DATABUF_SIZE (64) #define EP0DATABUF_SIZE (64)
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8) #define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
// bmRequestType & 0x7f /******************************************************************
#define STANDARD_DEVICE_REQUEST_TYPE 0 * Defines from usb.h *
#define STANDARD_ENDPOINT_REQUEST_TYPE 2 *****************************************************************/
#define VENDOR_REQUEST_TYPE 0x40
#define CONTROL_REQUEST_TYPE 0x21 /*
// bRequest, standard; for bmRequestType == 0x80 * Device and/or Interface Class codes
*/
#define USB_CLASS_PER_INTERFACE 0
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PRINTER 7
#define USB_CLASS_PTP 6
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_DATA 10
#define USB_CLASS_MISC 0xef
#define USB_CLASS_VENDOR_SPEC 0xff
/*
* Descriptor types
*/
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_QUALIFIER 0x06
#define USB_DT_IAD 0x0B
#define USB_DT_HID 0x21
#define USB_DT_REPORT 0x22
#define USB_DT_PHYSICAL 0x23
#define USB_DT_CS_INTERFACE 0x24
#define USB_DT_HUB 0x29
/*
* Descriptor sizes per descriptor type
*/
#define USB_DT_DEVICE_SIZE 18
#define USB_DT_CONFIG_SIZE 9
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_HID_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_QUALIFIER_SIZE 10
#define USB_DT_CS_INTERFACE_SIZE 5
#define USB_DT_IAD_SIZE 8
// bmRequestType & 0x80 == dev2host (1) or host2dev (0)
// recipient: bmRequestType & 0x1f
#define REQUEST_RECIPIENT(b) (b & 0x1f)
#define REQ_RECIPIENT_DEVICE 0
#define REQ_RECIPIENT_INTERFACE 1
#define REQ_RECIPIENT_ENDPOINT 2
#define REQ_RECIPIENT_OTHER 3
// type: [bmRequestType & 0x60 >> 5]
#define REQUEST_TYPE(b) ((b&0x60)>>5)
#define REQ_TYPE_STANDARD 0
#define REQ_TYPE_CLASS 1
#define REQ_TYPE_VENDOR 2
#define REQ_TYPE_RESERVED 3
//#define VENDOR_REQUEST 0x01
// standard device requests
#define GET_STATUS 0x00 #define GET_STATUS 0x00
#define GET_DESCRIPTOR 0x06
#define GET_CONFIGURATION 0x08
// for bmRequestType == 0
#define CLEAR_FEATURE 0x01 #define CLEAR_FEATURE 0x01
#define SET_FEATURE 0x03 // unused #define SET_FEATURE 0x03
#define SET_ADDRESS 0x05 #define SET_ADDRESS 0x05
#define SET_DESCRIPTOR 0x07 // unused #define GET_DESCRIPTOR 0x06
#define SET_DESCRIPTOR 0x07
#define GET_CONFIGURATION 0x08
#define SET_CONFIGURATION 0x09 #define SET_CONFIGURATION 0x09
// for bmRequestType == 0x81, 1 or 0xB2 // and some standard interface requests
#define GET_INTERFACE 0x0A // unused #define GET_INTERFACE 0x0A
#define SET_INTERFACE 0x0B // unused #define SET_INTERFACE 0x0B
#define SYNC_FRAME 0x0C // unused // and some standard endpoint requests
#define VENDOR_REQUEST 0x01 // unused #define SYNC_FRAME 0x0C
// Class-Specific Control Requests
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
#define SET_COMM_FEATURE 0x02 // unused
#define GET_COMM_FEATURE 0x03 // unused
#define CLEAR_COMM_FEATURE 0x04 // unused
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
#define SEND_BREAK 0x23
// control line states
#define CONTROL_DTR 0x01
#define CONTROL_RTS 0x02
// string descriptors
enum{
iLANGUAGE_DESCR,
iMANUFACTURER_DESCR,
iPRODUCT_DESCR,
iSERIAL_DESCR,
iINTERFACE_DESCR,
iDESCR_AMOUNT
};
// Types of descriptors // Types of descriptors
#define DEVICE_DESCRIPTOR 0x01 #define DEVICE_DESCRIPTOR 0x01
#define CONFIGURATION_DESCRIPTOR 0x02 #define CONFIGURATION_DESCRIPTOR 0x02
#define STRING_DESCRIPTOR 0x03 #define STRING_DESCRIPTOR 0x03
#define DEVICE_QUALIFIER_DESCRIPTOR 0x06 #define DEVICE_QUALIFIER_DESCRIPTOR 0x06
#define DEBUG_DESCRIPTOR 0x0a
#define HID_REPORT_DESCRIPTOR 0x22
// EP types for EP_init
#define EP_TYPE_BULK 0x00
#define EP_TYPE_CONTROL 0x01
#define EP_TYPE_ISO 0x02
#define EP_TYPE_INTERRUPT 0x03
// EP types for descriptors
#define USB_BM_ATTR_CONTROL 0x00
#define USB_BM_ATTR_ISO 0x01
#define USB_BM_ATTR_BULK 0x02
#define USB_BM_ATTR_INTERRUPT 0x03
/******************************************************************
* Other stuff *
*****************************************************************/
#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX) #define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX) #define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
@ -82,12 +274,6 @@ enum{
#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) #define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) #define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
// EP types
#define EP_TYPE_BULK 0x00
#define EP_TYPE_CONTROL 0x01
#define EP_TYPE_ISO 0x02
#define EP_TYPE_INTERRUPT 0x03
#define LANG_US (uint16_t)0x0409 #define LANG_US (uint16_t)0x0409
#define _USB_STRING_(name, str) \ #define _USB_STRING_(name, str) \
@ -101,7 +287,6 @@ static const struct name \
name = {sizeof(name), 0x03, str} name = {sizeof(name), 0x03, str}
#define _USB_LANG_ID_(name, lng_id) \ #define _USB_LANG_ID_(name, lng_id) \
\
static const struct name \ static const struct name \
{ \ { \
uint8_t bLength; \ uint8_t bLength; \
@ -129,44 +314,15 @@ typedef struct{
unsigned rx_cnt : 10; // received data counter unsigned rx_cnt : 10; // received data counter
} ep_t; } ep_t;
typedef struct {
uint32_t dwDTERate;
uint8_t bCharFormat;
#define USB_CDC_1_STOP_BITS 0
#define USB_CDC_1_5_STOP_BITS 1
#define USB_CDC_2_STOP_BITS 2
uint8_t bParityType;
#define USB_CDC_NO_PARITY 0
#define USB_CDC_ODD_PARITY 1
#define USB_CDC_EVEN_PARITY 2
#define USB_CDC_MARK_PARITY 3
#define USB_CDC_SPACE_PARITY 4
uint8_t bDataBits;
} __attribute__ ((packed)) usb_LineCoding;
typedef struct {
uint8_t bmRequestType;
uint8_t bNotificationType;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__ ((packed)) usb_cdc_notification;
extern ep_t endpoints[];
extern volatile uint8_t usbON; extern volatile uint8_t usbON;
extern config_pack_t *setup_packet;
extern uint8_t ep0databuf[], setupdatabuf[];
void EP0_Handler();
void USB_setup();
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size);
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size); void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
int EP_Read(uint8_t number, uint8_t *buf); int EP_Read(uint8_t number, uint8_t *buf);
usb_LineCoding getLineCoding();
void linecoding_handler(usb_LineCoding *lc); // could be [re]defined in usb_dev.c
void clstate_handler(uint16_t val); extern void usb_class_request(config_pack_t *packet, uint8_t *data, uint16_t datalen);
void break_handler(); extern void usb_vendor_request(config_pack_t *packet, uint8_t *data, uint16_t datalen);
void vendor_handler(config_pack_t *packet); extern void set_configuration();
void chkin();
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "164" #define BUILD_NUMBER "192"
#define BUILD_DATE "2024-09-02" #define BUILD_DATE "2025-02-05"