diff --git a/F1:F103/BISS_C_encoders/Readme.md b/F1:F103/BISS_C_encoders/Readme.md index 37a3b12..992452f 100644 --- a/F1:F103/BISS_C_encoders/Readme.md +++ b/F1:F103/BISS_C_encoders/Readme.md @@ -1,5 +1,124 @@ Get data from 2 encoders by BISS-C protocol =========================================== +This device works with two BISS-C encoders (resolution from 8 to 32 bit). + +If you want to test readout from device, run `./testDev /dev/encoder_X0` or `./testDev /dev/encoder_X0`. + +** Encoder cable pinout: + +* 1 - NC or shield +* 2 - CLK_A - positive of SSI clock out +* 3 - CLC_B - negative of SSI clock out +* 4 - NC or shield +* 5 - +5V - 5V power for sensor (at least 250mA) +* 6 - DATA_A - positive of data in +* 7 - DATA_B - negative of data in +* 8 - NC +* 9 - Gnd - common ground + + +** Device interfaces + +After connection you will see device 0483:5740 with three CDC interfaces. Each interface +have its own `iInterface` field, by default they are: + +* encoder_cmd - configure/command/debugging interface +* encoder_X - X sensor output +* encoder_Y - Y sensor output + +Add to udev-rules file `99-myHW.rules` which will create symlinks to each interface in `/dev/` directory. +You can change all three `iInterface` values and store them in device' flash memory. + +The readout of encoders depends on settings. If you save in flash `autom=1`, readout of both encoders +will repeat each `amperiod` milliseconds. Also you always can ask for readout sending any '\n'-terminated +data into encoder's interface or running commands `readenc`, `readX` or `readY` in command interface. + + +** Protocol + +The device have simple text protocol, each text string should be closed by '\n'. +Base format is 'param [ = value]', where 'param' could be command to run some procedure +or getter, 'value' is setter. + +Answer for all getters is 'param=value'. Here are answers for setters and procedures: + +* OK - all OK +* FAIL - procedure failed to run +* BADCMD - your entered wrong command +* BADPAR - parameter of setter is out of allowable range + +Some procedures (like 'help' or 'readenc') returns a lot of data after calling. + + +*** Base commands on command interface + +These are commands for directrly work with SPI interfaces: + +* readenc - read both encoders once +* readX - read X encoder once +* readY - read Y encoder once +* help - show full help +* reset - reset MCU +* spideinit - deinit SPI +* spiinit - init SPI +* spistat - get status of both SPI interfaces + + +*** Configuration commands + +This set of commands allows to change current configuration (remember: each time SPI configuration changes +you need to run `spiinit`) and store it into flash memory. + +* autom - turn on or off automonitoring +* amperiod - period of monitoring, 1..255 milliseconds +* BR - change SPI BR register (1 - 18MHz ... 7 - 281kHz) +* CPHA - change CPHA value (0/1) +* CPOL - change CPOL value (0/1) +* dumpconf - dump current configuration +* encbits - set encoder data bits amount (26/32) +* encbufsz - change encoder auxiliary buffer size (8..32 bytes) +* erasestorage - erase full storage or current page (=n) +* maxzeros - maximal amount of zeros in preamble +* minzeros - minimal amount of zeros in preamble +* setiface1 - set name of first (command) interface +* setiface2 - set name of second (axis X) interface +* setiface3 - set name of third (axis Y) interface +* storeconf - store configuration in flash memory + +Here is example of default configuration ouput (`dumpconf`): + +``` +userconf_sz=108 +currentconfidx=-1 +setiface1= +setiface2= +setiface3= +autom=0 +amperiod=1 +BR=4 +CPHA=0 +CPOL=1 +encbits=26 +encbufsz=12 +maxzeros=50 +minzeros=4 +``` + +`userconf_sz` is some type of "magick sequence" to find start of last record in flash memory. +`currentconfidx` shows number of record (-1 means that the storage is empty and you see default values). +Empty field of `setifaceX` means default interface name. + + +*** Debugging commands + +Some of these commands could be usefull when you're trying to play with settings or want to measure maximal +readout speed for encoders (when each reading starts immediately after parsing previous result). + +* dummy - dummy integer setter/getter +* fin - reinit flash (e.g. to restore last configuration) +* sendx - send text string to X encoder's terminal +* sendy - send text string to Y encoder's terminal +* testx - test X-axis throughput +* testy - test Y-axis throughput -tl;dr diff --git a/F1:F103/BISS_C_encoders/bissC.c b/F1:F103/BISS_C_encoders/bissC.c index 78f03f1..e158458 100644 --- a/F1:F103/BISS_C_encoders/bissC.c +++ b/F1:F103/BISS_C_encoders/bissC.c @@ -17,16 +17,14 @@ */ #include "bissC.h" -#include "usb_dev.h" +#include "flash.h" #ifdef EBUG #include "strfunc.h" #endif -#include "flash.h" +#include "spi.h" +#include "usb_dev.h" -#define MAX_BITSTREAM_UINTS 4 // 4 * 32 = 128 bits capacity -// min/max zeros before preambule -#define MINZEROS 4 -#define MAXZEROS 40 +#define MAX_BITSTREAM_UINTS (ENCODER_BUFSZ_MAX / 4) // ENCODER_BUFSZ_MAX bits capacity static uint32_t bitstream[MAX_BITSTREAM_UINTS] = {0}; @@ -50,11 +48,6 @@ static void bytes_to_bitstream(const uint8_t *bytes, uint32_t num_bytes, uint32_ } } } - /* Store remaining bits if any - if(*num_bits % 32 != 0){ - current <<= (32 - (*num_bits % 32)); - bitstream[pos] = current; - }*/ } // Compute CRC-6 using polynomial x^6 + x + 1 @@ -102,7 +95,7 @@ BiSS_Frame parse_biss_frame(const uint8_t *bytes, uint32_t num_bytes){ if(!curbit){ zero_count++; }else{ - if(zero_count >= MINZEROS && zero_count <= MAXZEROS){ + if(zero_count >= the_conf.minzeros && zero_count <= the_conf.maxzeros){ if((i + 1) < num_bits && !get_bit(i + 1)){ data_start = i + 2; found = 1; diff --git a/F1:F103/BISS_C_encoders/bissC.h b/F1:F103/BISS_C_encoders/bissC.h index b7816eb..d1de0d5 100644 --- a/F1:F103/BISS_C_encoders/bissC.h +++ b/F1:F103/BISS_C_encoders/bissC.h @@ -20,6 +20,11 @@ #include +#include "spi.h" +#if ENCRESOL_MAX > 32 +#error "Change full code. Current don't support more than 32 bits of encoder resolution." +#endif + typedef struct { uint32_t data; // 26/32/36-bit data uint8_t error : 1; // error flag (0 - error: bad value or high temperature) diff --git a/F1:F103/BISS_C_encoders/encoders.bin b/F1:F103/BISS_C_encoders/encoders.bin index 660b8d1..41a4e13 100755 Binary files a/F1:F103/BISS_C_encoders/encoders.bin and b/F1:F103/BISS_C_encoders/encoders.bin differ diff --git a/F1:F103/BISS_C_encoders/encoders.creator.user b/F1:F103/BISS_C_encoders/encoders.creator.user index 1de570b..f99097b 100644 --- a/F1:F103/BISS_C_encoders/encoders.creator.user +++ b/F1:F103/BISS_C_encoders/encoders.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F1:F103/BISS_C_encoders/flash.c b/F1:F103/BISS_C_encoders/flash.c index 5b23653..8e8f9e4 100644 --- a/F1:F103/BISS_C_encoders/flash.c +++ b/F1:F103/BISS_C_encoders/flash.c @@ -33,7 +33,11 @@ user_conf the_conf = { .userconf_sz = sizeof(user_conf), .flags.CPOL = 1, .flags.BR = 4, - .encbits = 26 + .encbits = 26, + .encbufsz = 12, + .minzeros = 4, + .maxzeros = 50, + .monittime = 1, }; int currentconfidx = -1; // index of current configuration diff --git a/F1:F103/BISS_C_encoders/flash.h b/F1:F103/BISS_C_encoders/flash.h index ae80899..cf4b5ff 100644 --- a/F1:F103/BISS_C_encoders/flash.h +++ b/F1:F103/BISS_C_encoders/flash.h @@ -27,10 +27,17 @@ // maximal size (in letters) of iInterface for settings #define MAX_IINTERFACE_SZ (16) +// min/max zeros before preambule +#define MINZEROS_MIN 2 +#define MINZEROS_MAX 60 +#define MAXZEROS_MIN 4 +#define MAXZEROS_MAX 120 + typedef struct{ uint8_t CPOL : 1; uint8_t CPHA : 1; uint8_t BR : 3; + uint8_t monit: 1; // auto monitoring of encoder each `monittime` milliseconds } flags_t; /* @@ -40,8 +47,12 @@ typedef struct __attribute__((packed, aligned(4))){ uint16_t userconf_sz; // "magick number" uint16_t iInterface[bTotNumEndpoints][MAX_IINTERFACE_SZ]; // hryunikod! uint8_t iIlengths[bTotNumEndpoints]; - flags_t flags; // flags: CPOL, CPHA etc uint8_t encbits; // encoder bits: 26 or 32 + uint8_t encbufsz; // encoder buffer size (up to ENCODER_BUFSZ_MAX) + uint8_t minzeros; // min/max zeros in preamble when searching start of record + uint8_t maxzeros; + uint8_t monittime; // auto monitoring period (ms) + flags_t flags; // flags: CPOL, CPHA etc } user_conf; extern user_conf the_conf; diff --git a/F1:F103/BISS_C_encoders/main.c b/F1:F103/BISS_C_encoders/main.c index 3d0633d..d3f43bc 100644 --- a/F1:F103/BISS_C_encoders/main.c +++ b/F1:F103/BISS_C_encoders/main.c @@ -27,6 +27,7 @@ volatile uint32_t Tms = 0; static char inbuff[RBINSZ]; +static uint32_t monitT[2] = {0}; /* Called when systick fires */ void sys_tick_handler(void){ @@ -47,7 +48,6 @@ static void printResult(BiSS_Frame *result){ } static void proc_enc(uint8_t idx){ - uint8_t encbuf[ENCODER_BUFSZ]; static uint32_t lastMSG[2], gotgood[2], gotwrong[2]; int iface = idx ? I_Y : I_X; char ifacechr = idx ? 'Y' : 'X'; @@ -65,9 +65,11 @@ static void proc_enc(uint8_t idx){ CMDWR("'\n"); } } + if(l > 0) spi_start_enc(idx); // start encoder reading on each request from given interface } - if(!spi_read_enc(idx, encbuf)) return; - BiSS_Frame result = parse_biss_frame(encbuf, ENCODER_BUFSZ); + uint8_t *encbuf = spi_read_enc(idx); + if(!encbuf) return; + BiSS_Frame result = parse_biss_frame(encbuf, the_conf.encbufsz); char *str = result.crc_valid ? u2str(result.data) : NULL; uint8_t testflag = (idx) ? user_pars.testy : user_pars.testx; if(CDCready[I_CMD]){ @@ -86,11 +88,11 @@ static void proc_enc(uint8_t idx){ if(str) ++gotgood[idx]; else ++gotwrong[idx]; } - }else{ + }else if(!the_conf.flags.monit){ printResult(&result); CMDWR("ENC"); USB_putbyte(I_CMD, ifacechr); USB_putbyte(I_CMD, '='); - hexdump(I_CMD, encbuf, ENCODER_BUFSZ); + hexdump(I_CMD, encbuf, the_conf.encbufsz); CMDWR(" ("); if(str) CMDWR(str); else CMDWR("wrong"); @@ -102,22 +104,17 @@ static void proc_enc(uint8_t idx){ USB_putbyte(iface, '\n'); } if(result.error) spi_setup(1+idx); // reinit SPI in case of error - if(testflag) spi_start_enc(idx); + if(the_conf.flags.monit) monitT[idx] = Tms; + else if(testflag) spi_start_enc(idx); } int main(){ - uint32_t lastT = 0;//, lastS = 0; + uint32_t lastT = 0; StartHSE(); flashstorage_init(); hw_setup(); USBPU_OFF(); SysTick_Config(72000); -/* -#ifdef EBUG - usart_setup(); - uint32_t tt = 0; -#endif -*/ USB_setup(); #ifndef EBUG iwdg_setup(); @@ -129,29 +126,18 @@ int main(){ LED_blink(LED0); lastT = Tms; } -/* -#ifdef EBUG - if(Tms != tt){ - __disable_irq(); - usart_transmit(); - tt = Tms; - __enable_irq(); - } -#endif -*/ if(CDCready[I_CMD]){ - /*if(Tms - lastS > 9999){ - USB_sendstr(I_CMD, "Tms="); - USB_sendstr(I_CMD, u2str(Tms)); - CMDn(); - lastS = Tms; - }*/ int l = USB_receivestr(I_CMD, inbuff, RBINSZ); if(l < 0) CMDWRn("ERROR: CMD USB buffer overflow or string was too long"); else if(l) parse_cmd(inbuff); } proc_enc(0); proc_enc(1); + if(the_conf.flags.monit){ + for(int i = 0; i < 2; ++i){ + if(Tms - monitT[i] >= the_conf.monittime) spi_start_enc(i); + } + } } return 0; } diff --git a/F1:F103/BISS_C_encoders/openocd.cfg b/F1:F103/BISS_C_encoders/openocd.cfg index a43a499..7533dd1 100644 --- a/F1:F103/BISS_C_encoders/openocd.cfg +++ b/F1:F103/BISS_C_encoders/openocd.cfg @@ -1,94 +1,4 @@ set FLASH_SIZE 0x10000 source [find interface/stlink.cfg] - - -# script for stm32f1x family - -# -# stm32 devices support both JTAG and SWD transports. -# -source [find target/swj-dp.tcl] -source [find mem_helper.tcl] - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME stm32f1x -} - -set _ENDIAN little - -# Work-area is a space in RAM used for flash programming -# By default use 4kB (as found on some STM32F100s) -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x1000 -} - -# Allow overriding the Flash bank size -if { [info exists FLASH_SIZE] } { - set _FLASH_SIZE $FLASH_SIZE -} else { - # autodetect size - set _FLASH_SIZE 0 -} - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - if { [using_jtag] } { - # See STM Document RM0008 Section 26.6.3 - set _CPUTAPID 0x2ba01477 - } { - # this is the SW-DP tap id not the jtag tap id - set _CPUTAPID 0x2ba01477 - } -} - -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu - -if {[using_jtag]} { - jtag newtap $_CHIPNAME bs -irlen 5 -} - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap - -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -# flash size will be probed -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME - -# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz -adapter_khz 1000 - -adapter_nsrst_delay 100 -if {[using_jtag]} { - jtag_ntrst_delay 100 -} - -reset_config srst_nogate - -if {![using_hla]} { - # if srst is not fitted use SYSRESETREQ to - # perform a soft reset - cortex_m reset_config sysresetreq -} - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP | - # DBG_STANDBY | DBG_STOP | DBG_SLEEP - mmw 0xE0042004 0x00000307 0 -} - -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0042004 0x00000020 0 -} +source [find target/stm32f1x.cfg] diff --git a/F1:F103/BISS_C_encoders/openocd.cfg_ b/F1:F103/BISS_C_encoders/openocd.cfg_ deleted file mode 100644 index 7533dd1..0000000 --- a/F1:F103/BISS_C_encoders/openocd.cfg_ +++ /dev/null @@ -1,4 +0,0 @@ -set FLASH_SIZE 0x10000 - -source [find interface/stlink.cfg] -source [find target/stm32f1x.cfg] diff --git a/F1:F103/BISS_C_encoders/proto.c b/F1:F103/BISS_C_encoders/proto.c index 8001187..b99ac90 100644 --- a/F1:F103/BISS_C_encoders/proto.c +++ b/F1:F103/BISS_C_encoders/proto.c @@ -72,6 +72,11 @@ typedef enum{ C_encbits, C_testX, C_testY, + C_encbufsz, + C_minzeros, + C_maxzeros, + C_autom, + C_amperiod, C_AMOUNT } cmd_e; @@ -223,58 +228,64 @@ static errcode_e spideinit(_U_ cmd_e idx, _U_ char *par){ return ERR_SILENCE; } -static errcode_e setflags(cmd_e idx, char *par){ +static errcode_e setuintpar(cmd_e idx, char *par){ + uint32_t val; if(par){ - if(*par < '0' || *par > '9') return ERR_BADPAR; - uint8_t val = *par - '0'; + if(par == getnum(par, &val)) return ERR_BADPAR; switch(idx){ - case C_cpha: - if(val > 1) return ERR_BADPAR; - the_conf.flags.CPHA = val; - break; - case C_cpol: - if(val > 1) return ERR_BADPAR; - the_conf.flags.CPOL = val; - break; + case C_br: + if(val == 0 || val > 7) return ERR_BADPAR; + the_conf.flags.BR = val; + break; + case C_encbits: + if(val < ENCRESOL_MIN || val > ENCRESOL_MAX) return ERR_BADPAR; // don't support less than 8 of more than 32 + the_conf.encbits = val; + break; + case C_encbufsz: + if(val < 8 || val > ENCODER_BUFSZ_MAX) return ERR_BADPAR; + the_conf.encbufsz = val; + break; + case C_minzeros: + if(val < MINZEROS_MIN || val > MINZEROS_MAX) return ERR_BADPAR; + the_conf.minzeros = val; + break; + case C_maxzeros: + if(val < MAXZEROS_MIN || val > MAXZEROS_MAX) return ERR_BADPAR; + the_conf.maxzeros = val; + break; + case C_amperiod: + if(val > 255 || val == 0) return ERR_BADPAR; + the_conf.monittime = val; + break; + default: + return ERR_BADCMD; + } + } + CMDWR(commands[idx].cmd); + USB_putbyte(I_CMD, '='); + switch(idx){ case C_br: - if(val == 0 || val > 7) return ERR_BADPAR; - the_conf.flags.BR = val; + val = the_conf.flags.BR; + break; + case C_encbits: + val = the_conf.encbits; + break; + case C_encbufsz: + val = the_conf.encbufsz; + break; + case C_minzeros: + val = the_conf.minzeros; + break; + case C_maxzeros: + val = the_conf.maxzeros; + break; + case C_amperiod: + val = the_conf.monittime; break; default: return ERR_BADCMD; - } } - uint8_t val = 0; - switch(idx){ - case C_cpha: - val = the_conf.flags.CPHA; - break; - case C_cpol: - val = the_conf.flags.CPOL; - break; - case C_br: - val = the_conf.flags.BR; - break; - default: - return ERR_BADCMD; - } - CMDWR(commands[idx].cmd); - USB_putbyte(I_CMD, '='); - USB_putbyte(I_CMD, '0' + val); - CMDn(); - return ERR_SILENCE; -} - -static errcode_e encbits(cmd_e idx, char *par){ - if(par){ - uint32_t N; - if(par == getnum(par, &N)) return ERR_BADPAR; - if(N < 26 || N > 32) return ERR_BADPAR; // don't support less than 26 of more than 32 - the_conf.encbits = N; - } - CMDWR(commands[idx].cmd); - USB_putbyte(I_CMD, '='); - CMDWR(u2str(the_conf.encbits)); + CMDWR(u2str(val)); CMDn(); return ERR_SILENCE; } @@ -285,25 +296,43 @@ static errcode_e setboolpar(cmd_e idx, char *par){ if(*par != '0' && *par != '1') return ERR_BADPAR; val = *par - '0'; switch(idx){ + case C_cpha: + the_conf.flags.CPHA = val; + break; + case C_cpol: + the_conf.flags.CPOL = val; + break; case C_testX: user_pars.testx = val; - break; + if(val) spi_start_enc(0); + break; case C_testY: user_pars.testy = val; - break; + if(val) spi_start_enc(1); + break; + case C_autom: + the_conf.flags.monit = val; + break; default: return ERR_BADCMD; } } switch(idx){ + case C_cpha: + val = the_conf.flags.CPHA; + break; + case C_cpol: + val = the_conf.flags.CPOL; + break; case C_testX: val = user_pars.testx; - if(val) spi_start_enc(0); - break; + break; case C_testY: val = user_pars.testy; - if(val) spi_start_enc(1); - break; + break; + case C_autom: + val = the_conf.flags.monit; + break; default: return ERR_BADCMD; } @@ -320,10 +349,15 @@ static errcode_e dumpconf(cmd_e _U_ idx, char _U_ *par){ CMDn(); for(int i = 0; i < bTotNumEndpoints; ++i) setiface(C_setiface1 + i, NULL); - setflags(C_br, NULL); - setflags(C_cpha, NULL); - setflags(C_cpol, NULL); - encbits(C_encbits, NULL); + setboolpar(C_autom, NULL); + setuintpar(C_amperiod, NULL); + setuintpar(C_br, NULL); + setboolpar(C_cpha, NULL); + setboolpar(C_cpol, NULL); + setuintpar(C_encbits, NULL); + setuintpar(C_encbufsz, NULL); + setuintpar(C_maxzeros, NULL); + setuintpar(C_minzeros, NULL); return ERR_SILENCE; } @@ -347,12 +381,17 @@ static const funcdescr_t commands[C_AMOUNT] = { [C_spistat] = {"spistat", spistat}, [C_spiinit] = {"spiinit", spiinit}, [C_spideinit] = {"spideinit", spideinit}, - [C_cpol] = {"CPOL", setflags}, - [C_cpha] = {"CPHA", setflags}, - [C_br] = {"BR", setflags}, - [C_encbits] = {"encbits", encbits}, + [C_cpol] = {"CPOL", setboolpar}, + [C_cpha] = {"CPHA", setboolpar}, + [C_br] = {"BR", setuintpar}, + [C_encbits] = {"encbits", setuintpar}, [C_testX] = {"testx", setboolpar}, [C_testY] = {"testy", setboolpar}, + [C_encbufsz] = {"encbufsz", setuintpar}, + [C_minzeros] = {"minzeros", setuintpar}, + [C_maxzeros] = {"maxzeros", setuintpar}, + [C_autom] = {"autom", setboolpar}, + [C_amperiod] = {"amperiod", setuintpar}, }; typedef struct{ @@ -362,28 +401,33 @@ typedef struct{ // SHOUL be sorted and grouped static const help_t helpmessages[] = { - {-1, "Configuration"}, - {C_dumpconf, "dump current configuration"}, - {C_erasestorage, "erase full storage or current page (=n)"}, - {C_setiface1, "set name of first (command) interface"}, - {C_setiface2, "set name of second (axis X) interface"}, - {C_setiface3, "set name of third (axis Y) interface"}, - {C_storeconf, "store configuration in flash memory"}, - {-1, "Different commands"}, - {C_dummy, "dummy integer setter/getter"}, - {C_encstart, "start reading encoders"}, - {C_encX, "read only X encoder"}, - {C_encY, "read only Y encoder"}, + {-1, "Base commands"}, + {C_encstart, "read both encoders once"}, + {C_encX, "read X encoder once"}, + {C_encY, "read Y encoder once"}, {C_help, "show this help"}, {C_reset, "reset MCU"}, {C_spideinit, "deinit SPI"}, {C_spiinit, "init SPI"}, {C_spistat, "get status of both SPI interfaces"}, - {-1, "Debug"}, + {-1, "Configuration"}, + {C_autom, "turn on or off automonitoring"}, + {C_amperiod, "period (ms) of monitoring, 1..255"}, {C_br, "change SPI BR register (1 - 18MHz ... 7 - 281kHz)"}, {C_cpha, "change CPHA value (0/1)"}, {C_cpol, "change CPOL value (0/1)"}, - {C_encbits, "set encoder data bits amount"}, + {C_dumpconf, "dump current configuration"}, + {C_encbits, "set encoder data bits amount (26/32)"}, + {C_encbufsz, "change encoder auxiliary buffer size (8..32 bytes)"}, + {C_erasestorage, "erase full storage or current page (=n)"}, + {C_maxzeros, "maximal amount of zeros in preamble"}, + {C_minzeros, "minimal amount of zeros in preamble"}, + {C_setiface1, "set name of first (command) interface"}, + {C_setiface2, "set name of second (axis X) interface"}, + {C_setiface3, "set name of third (axis Y) interface"}, + {C_storeconf, "store configuration in flash memory"}, + {-1, "Debug commands"}, + {C_dummy, "dummy integer setter/getter"}, {C_fin, "reinit flash"}, {C_sendX, "send text string to X encoder's terminal"}, {C_sendY, "send text string to Y encoder's terminal"}, diff --git a/F1:F103/BISS_C_encoders/spi.c b/F1:F103/BISS_C_encoders/spi.c index 06bfb0f..0a5ba10 100644 --- a/F1:F103/BISS_C_encoders/spi.c +++ b/F1:F103/BISS_C_encoders/spi.c @@ -34,7 +34,7 @@ static volatile SPI_TypeDef* const SPIs[AMOUNT_OF_SPI+1] = {NULL, SPI1, SPI2}; static volatile DMA_Channel_TypeDef * const DMAs[AMOUNT_OF_SPI+1] = {NULL, DMA1_Channel2, DMA1_Channel4}; #define WAITX(x) do{volatile uint32_t wctr = 0; while((x) && (++wctr < 3600)) IWDG->KR = IWDG_REFRESH; if(wctr==3600){ DBG("timeout"); return 0;}}while(0) -static uint8_t encoderbuf[AMOUNT_OF_SPI][ENCODER_BUFSZ] = {0}; +static uint8_t encoderbuf[AMOUNT_OF_SPI][ENCODER_BUFSZ_MAX] = {0}; static uint8_t freshdata[AMOUNT_OF_SPI] = {0}; // init SPI to work RX-only with DMA @@ -81,8 +81,6 @@ void spi_onoff(uint8_t idx, uint8_t on){ CHKIDX(idx); volatile SPI_TypeDef *SPI = SPIs[idx]; if(on){ - //DBGs(u2str(idx)); - //DBG("turn on SPI"); SPI->CR1 |= SPI_CR1_SPE; spi_status[idx] = SPI_BUSY; }else{ @@ -114,20 +112,15 @@ static int spi_waitbsy(uint8_t idx){ DBG("Busy - turn off"); spi_onoff(idx, 0); // turn off SPI if it's busy } - //DBGs(u2str(idx)); - //DBG("wait busy"); - //WAITX(SPIs[idx]->SR & SPI_SR_BSY); return 1; } // just copy last read encoder value into `buf` -// @return TRUE if got fresh data -int spi_read_enc(uint8_t encno, uint8_t buf[ENCODER_BUFSZ]){ - if(encno > 1 || !freshdata[encno]) return FALSE; - //DBGs(u2str(encno)); DBG("Read encoder data"); - memcpy(buf, encoderbuf[encno], ENCODER_BUFSZ); +// @return pointer to buffer if got fresh data +uint8_t *spi_read_enc(uint8_t encno){ + if(encno > 1 || !freshdata[encno]) return NULL; freshdata[encno] = 0; // clear fresh status - return TRUE; + return encoderbuf[encno]; } // start encoder reading over DMA @@ -135,16 +128,12 @@ int spi_read_enc(uint8_t encno, uint8_t buf[ENCODER_BUFSZ]){ // here `encodernum` is 0 (SPI1) or 1 (SPI2), not 1/2 as SPI index! int spi_start_enc(int encodernum){ int spiidx = encodernum + 1; - //DBG("start enc"); if(spiidx < 1 || spiidx > AMOUNT_OF_SPI) return FALSE; if(spi_status[spiidx] != SPI_READY) return FALSE; if(!spi_waitbsy(spiidx)) return FALSE; - if(SPI1->CR1 & SPI_CR1_SPE){ DBG("spi1 works!");} - if(SPI2->CR1 & SPI_CR1_SPE){ DBG("spi2 works!");} volatile DMA_Channel_TypeDef *DMA = DMAs[spiidx]; DMA->CMAR = (uint32_t) encoderbuf[encodernum]; - DMA->CNDTR = ENCODER_BUFSZ; - //DBG("turn on spi"); + DMA->CNDTR = the_conf.encbufsz; spi_onoff(spiidx, 1); DMA->CCR |= DMA_CCR_EN; return TRUE; @@ -159,12 +148,8 @@ void dma1_channel2_isr(){ DMA1->IFCR = DMA_IFCR_CTEIF2; } if(DMA1->ISR & DMA_ISR_TCIF2){ - //uint32_t ctr = TIM2->CNT; DMA1->IFCR = DMA_IFCR_CTCIF2; freshdata[0] = 1; - //encoderbuf[5] = (ctr >> 16) & 0xff; - //encoderbuf[6] = (ctr >> 8 ) & 0xff; - //encoderbuf[7] = (ctr >> 0 ) & 0xff; } spi_status[1] = SPI_READY; } diff --git a/F1:F103/BISS_C_encoders/spi.h b/F1:F103/BISS_C_encoders/spi.h index f5a4f84..e4e630f 100644 --- a/F1:F103/BISS_C_encoders/spi.h +++ b/F1:F103/BISS_C_encoders/spi.h @@ -2,9 +2,13 @@ #pragma once #include +// two SPI interfaces for two sensors #define AMOUNT_OF_SPI (2) - -#define ENCODER_BUFSZ (12) +// static buffer size +#define ENCODER_BUFSZ_MAX (32) +// encoder resolution +#define ENCRESOL_MIN (8) +#define ENCRESOL_MAX (32) typedef enum{ SPI_NOTREADY, @@ -18,4 +22,4 @@ void spi_onoff(uint8_t idx, uint8_t on); void spi_deinit(uint8_t idx); void spi_setup(uint8_t idx); int spi_start_enc(int encodernum); -int spi_read_enc(uint8_t encno, uint8_t buf[ENCODER_BUFSZ]); +uint8_t *spi_read_enc(uint8_t encno); diff --git a/F1:F103/BISS_C_encoders/usart.c b/F1:F103/BISS_C_encoders/usart.c deleted file mode 100644 index 5722fb0..0000000 --- a/F1:F103/BISS_C_encoders/usart.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * usart.c - * - * Copyright 2018 Edward V. Emelianoff - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include - -#include "stm32f1.h" -#include "usart.h" -#include "ringbuffer.h" - -extern volatile uint32_t Tms; -// buffers for out ringbuffer and DMA send -static uint8_t buf[UARTBUFSZ], txbuf[UARTBUFSZ]; -static ringbuffer ringbuf = {.data = buf, .length = UARTBUFSZ}; - -static volatile int usart_txrdy = 1; // transmission done - -// transmit current tbuf -void usart_transmit(){ - if(RB_hasbyte(&ringbuf, '\n') < 0 || !usart_txrdy) return; - int L = 0, l = 0; - do{ - l = RB_readto(&ringbuf, '\n', txbuf + L, UARTBUFSZ - L); - if(l > 0) L += l; - }while(l > 0 && L < UARTBUFSZ); - if(L < 1) return; - usart_txrdy = 0; - if(L < UARTBUFSZ-1){ - txbuf[L++] = '$'; txbuf[L++] = '\n'; - } - DMA1_Channel4->CCR &= ~DMA_CCR_EN; - DMA1_Channel4->CMAR = (uint32_t) txbuf; // mem - DMA1_Channel4->CNDTR = L; - DMA1_Channel4->CCR |= DMA_CCR_EN; -} - -void usart_putchar(const char ch){ - RB_write(&ringbuf, (const uint8_t*)&ch, 1); -} - -void usart_send(const char *str){ - int l = strlen(str); - if(RB_datalen(&ringbuf) > UARTBUFSZ/2) usart_transmit(); - RB_write(&ringbuf, (const uint8_t*)str, l); -} - -/* - * USART speed: baudrate = Fck/(USARTDIV) - * USARTDIV stored in USART->BRR - * - * for 72MHz USARTDIV=72000/f(kboud); so for 115200 USARTDIV=72000/115.2=625 -> BRR=0x271 - * 9600: BRR = 7500 (0x1D4C) - */ - -void usart_setup(){ - uint32_t tmout = 16000000; - // PA9 - Tx, PA10 - Rx - RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN; - RCC->AHBENR |= RCC_AHBENR_DMA1EN; - GPIOA->CRH |= CRH(9, CNF_AFPP|MODE_NORMAL) | CRH(10, CNF_FLINPUT|MODE_INPUT); - - // USART1 Tx DMA - Channel4 (Rx - channel 5) - DMA1_Channel4->CPAR = (uint32_t) &USART1->DR; // periph - DMA1_Channel4->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq - // Tx CNDTR set @ each transmission due to data size - NVIC_SetPriority(DMA1_Channel4_IRQn, 3); - NVIC_EnableIRQ(DMA1_Channel4_IRQn); - NVIC_SetPriority(USART1_IRQn, 0); - // setup usart1 - USART1->BRR = 72000000 / 4000000; - USART1->CR1 = USART_CR1_TE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART - while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission - USART1->SR = 0; // clear flags - USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ - USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx -} - -void dma1_channel4_isr(){ - if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx - DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag - usart_txrdy = 1; - } -} diff --git a/F1:F103/BISS_C_encoders/version.inc b/F1:F103/BISS_C_encoders/version.inc index 2bcb422..aebe739 100644 --- a/F1:F103/BISS_C_encoders/version.inc +++ b/F1:F103/BISS_C_encoders/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "91" -#define BUILD_DATE "2025-04-02" +#define BUILD_NUMBER "96" +#define BUILD_DATE "2025-04-04" diff --git a/F1:F103/USB_New_concept/USB_NEW_concept_7inone/usb_dev.c b/F1:F103/USB_New_concept/USB_NEW_concept_7inone/usb_dev.c index 7122e2d..0791a90 100644 --- a/F1:F103/USB_New_concept/USB_NEW_concept_7inone/usb_dev.c +++ b/F1:F103/USB_New_concept/USB_NEW_concept_7inone/usb_dev.c @@ -78,13 +78,19 @@ static void chkin(uint8_t ifno){ static void send_next(uint8_t ifno){ uint8_t usbbuff[USB_TXBUFSZ]; int buflen = RB_read((ringbuffer*)&rbout[ifno], (uint8_t*)usbbuff, USB_TXBUFSZ); + if(!CDCready[ifno]){ + lastdsz[ifno] = -1; + return; + } if(buflen == 0){ - if(lastdsz[ifno] == 64) EP_Write(1+ifno, NULL, 0); // send ZLP after 64 bits packet when nothing more to send - lastdsz[ifno] = 0; + if(lastdsz[ifno] == USB_TXBUFSZ){ + EP_Write(1+ifno, NULL, 0); // send ZLP after 64 bits packet when nothing more to send + lastdsz[ifno] = 0; + }else lastdsz[ifno] = -1; // OK. User can start sending data return; }else if(buflen < 0){ DBG("Buff busy"); - lastdsz[ifno] = 0; + lastdsz[ifno] = -1; return; } DBG("Got data in buf"); @@ -221,14 +227,17 @@ int USB_send(uint8_t ifno, const uint8_t *buf, int len){ if(!buf || !CDCready[ifno] || !len) return FALSE; DBG("USB_send"); while(len){ + if(!CDCready[ifno]) return FALSE; IWDG->KR = IWDG_REFRESH; int a = RB_write((ringbuffer*)&rbout[ifno], buf, len); - if(lastdsz[ifno] == 0) send_next(ifno); // need to run manually - all data sent, so no IRQ on IN if(a > 0){ len -= a; buf += a; - } else if (a < 0) continue; // do nothing if buffer is in reading state + }else if(a == 0){ // overfull + if(lastdsz[ifno] < 0) send_next(ifno); + } } + if(buf[len-1] == '\n' && lastdsz[ifno] < 0) send_next(ifno); return TRUE; } @@ -236,10 +245,15 @@ int USB_putbyte(uint8_t ifno, uint8_t byte){ if(!CDCready[ifno]) return FALSE; int l = 0; while((l = RB_write((ringbuffer*)&rbout[ifno], &byte, 1)) != 1){ + if(!CDCready[ifno]) return FALSE; IWDG->KR = IWDG_REFRESH; - if(lastdsz[ifno] == 0) send_next(ifno); // need to run manually - all data sent, so no IRQ on IN - if(l < 0) continue; + if(l == 0){ // overfull + if(lastdsz[ifno] < 0) send_next(ifno); + continue; + } } + // send line if got EOL + if(byte == '\n' && lastdsz[ifno] < 0) send_next(ifno); return TRUE; } diff --git a/F1:F103/USB_New_concept/USB_NEW_concept_CDC/usb_dev.c b/F1:F103/USB_New_concept/USB_NEW_concept_CDC/usb_dev.c index 942694c..da97f94 100644 --- a/F1:F103/USB_New_concept/USB_NEW_concept_CDC/usb_dev.c +++ b/F1:F103/USB_New_concept/USB_NEW_concept_CDC/usb_dev.c @@ -75,13 +75,19 @@ static void chkin(){ static void send_next(){ uint8_t usbbuff[USB_TXBUFSZ]; int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ); + if(!CDCready){ + lastdsz = -1; + return; + } if(buflen == 0){ - if(lastdsz == 64) EP_Write(1, NULL, 0); // send ZLP after 64 bits packet when nothing more to send - lastdsz = 0; + if(lastdsz == USB_TXBUFSZ){ + EP_Write(1, NULL, 0); // send ZLP after 64 bits packet when nothing more to send + lastdsz = 0; + }else lastdsz = -1; return; }else if(buflen < 0){ DBG("Buff busy"); - lastdsz = 0; + lastdsz = -1; return; } DBG("Got data in buf"); @@ -193,14 +199,17 @@ int USB_send(const uint8_t *buf, int len){ if(!buf || !CDCready || !len) return FALSE; DBG("USB_send"); while(len){ + if(!CDCready) return FALSE; IWDG->KR = IWDG_REFRESH; int a = RB_write((ringbuffer*)&rbout, buf, len); - if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN if(a > 0){ len -= a; buf += a; - } else if (a < 0) continue; // do nothing if buffer is in reading state + }else if(a == 0){ // overfull + if(lastdsz < 0) send_next(); + } } + if(buf[len-1] == '\n' && lastdsz < 0) send_next(); return TRUE; } @@ -208,10 +217,14 @@ int USB_putbyte(uint8_t byte){ if(!CDCready) return FALSE; int l = 0; while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){ + if(!CDCready) return FALSE; IWDG->KR = IWDG_REFRESH; - if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN - if(l < 0) continue; + if(l == 0){ // overfull + if(lastdsz < 0) send_next(); + continue; + } } + if(byte == '\n' && lastdsz < 0) send_next(); return TRUE; } diff --git a/F1:F103/USB_New_concept/USB_NEW_concept_PL2303/usb_dev.c b/F1:F103/USB_New_concept/USB_NEW_concept_PL2303/usb_dev.c index 5b3fd40..4949d00 100644 --- a/F1:F103/USB_New_concept/USB_NEW_concept_PL2303/usb_dev.c +++ b/F1:F103/USB_New_concept/USB_NEW_concept_PL2303/usb_dev.c @@ -81,12 +81,18 @@ static void chkin(){ static void send_next(){ uint8_t usbbuff[USB_TXBUFSZ]; int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ); + if(!CDCready){ + lastdsz = -1; + return; + } if(buflen == 0){ - if(lastdsz == 64) EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send - lastdsz = 0; + if(lastdsz == 64){ + EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send + lastdsz = 0; + } else lastdsz = -1; // OK. User can start sending data return; }else if(buflen < 0){ - lastdsz = 0; + lastdsz = -1; return; } EP_Write(3, (uint8_t*)usbbuff, buflen); @@ -231,16 +237,19 @@ int USB_sendall(){ // put `buf` into queue to send int USB_send(const uint8_t *buf, int len){ if(!buf || !CDCready || !len) return FALSE; - DBG("send"); + DBG("USB_send"); while(len){ + if(!CDCready) return FALSE; IWDG->KR = IWDG_REFRESH; int a = RB_write((ringbuffer*)&rbout, buf, len); - if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN if(a > 0){ len -= a; buf += a; - } else if (a < 0) continue; // do nothing if buffer is in reading state + }else if(a == 0){ // overfull + if(lastdsz < 0) send_next(); } + } + if(buf[len-1] == '\n' && lastdsz < 0) send_next(); return TRUE; } @@ -248,10 +257,15 @@ int USB_putbyte(uint8_t byte){ if(!CDCready) return FALSE; int l = 0; while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){ + if(!CDCready) return FALSE; IWDG->KR = IWDG_REFRESH; - if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN - if(l < 0) continue; + if(l == 0){ // overfull + if(lastdsz < 0) send_next(); + continue; + } } + // send line if got EOL + if(byte == '\n' && lastdsz < 0) send_next(); return TRUE; }