From faeac9831881c1565350e4163902f09b0ab06dc9 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Wed, 2 Apr 2025 18:26:02 +0300 Subject: [PATCH] Working (but still dev-mode; need some more different configurators) --- F1:F103/BISS_C_encoders/bissC.c | 146 ++++++++++++++++++ F1:F103/BISS_C_encoders/bissC.h | 31 ++++ F1:F103/BISS_C_encoders/encoders.bin | Bin 11236 -> 12524 bytes F1:F103/BISS_C_encoders/encoders.creator.user | 2 +- F1:F103/BISS_C_encoders/encoders.files | 2 + F1:F103/BISS_C_encoders/flash.c | 11 +- F1:F103/BISS_C_encoders/flash.h | 8 + F1:F103/BISS_C_encoders/main.c | 122 ++++++++++----- F1:F103/BISS_C_encoders/proto.c | 137 ++++++++++++++-- F1:F103/BISS_C_encoders/proto.h | 9 ++ F1:F103/BISS_C_encoders/ringbuffer.h | 4 +- F1:F103/BISS_C_encoders/spi.c | 39 +++-- F1:F103/BISS_C_encoders/spi.h | 4 +- F1:F103/BISS_C_encoders/usb_descr.c | 2 +- F1:F103/BISS_C_encoders/usb_descr.h | 6 +- F1:F103/BISS_C_encoders/usb_dev.c | 38 +++-- F1:F103/BISS_C_encoders/usb_dev.h | 6 +- F1:F103/BISS_C_encoders/version.inc | 4 +- 18 files changed, 476 insertions(+), 95 deletions(-) create mode 100644 F1:F103/BISS_C_encoders/bissC.c create mode 100644 F1:F103/BISS_C_encoders/bissC.h diff --git a/F1:F103/BISS_C_encoders/bissC.c b/F1:F103/BISS_C_encoders/bissC.c new file mode 100644 index 0000000..78f03f1 --- /dev/null +++ b/F1:F103/BISS_C_encoders/bissC.c @@ -0,0 +1,146 @@ +/* + * This file is part of the encoders project. + * Copyright 2025 Edward V. Emelianov . + * + * 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 . + */ + +#include "bissC.h" +#include "usb_dev.h" +#ifdef EBUG +#include "strfunc.h" +#endif +#include "flash.h" + +#define MAX_BITSTREAM_UINTS 4 // 4 * 32 = 128 bits capacity +// min/max zeros before preambule +#define MINZEROS 4 +#define MAXZEROS 40 + +static uint32_t bitstream[MAX_BITSTREAM_UINTS] = {0}; + +// Get bit at position n from uint32_t array (MSB-first packing) +static inline uint8_t get_bit(uint8_t n) { + return (bitstream[n >> 5] >> (31 - (n & 0x1F))) & 1; +} + +// Convert bytes to packed uint32_t bitstream (MSB-first) +static void bytes_to_bitstream(const uint8_t *bytes, uint32_t num_bytes, uint32_t *num_bits) { + *num_bits = 0; + uint32_t current = 0; + uint32_t pos = 0; + + for(uint32_t i = 0; i < num_bytes; i++){ + for(int8_t j = 7; j >= 0; j--){ // MSB first + current = (current << 1) | ((bytes[i] >> j) & 1); + if (++(*num_bits) % 32 == 0){ + bitstream[pos++] = current; + current = 0; + } + } + } + /* 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 +static uint8_t compute_crc(uint8_t start_bit, uint8_t num_bits) { + uint8_t crc = 0x00; + for(uint32_t i = 0; i < num_bits; i++) { + uint8_t bit = get_bit(start_bit + i); + uint8_t msb = (crc >> 5) ^ bit; + crc = ((crc << 1) & 0x3F); + if (msb) crc ^= 0x03; + } + DBG("Compute CRC:"); + DBGs(uhex2str(crc)); + return crc; +} + +BiSS_Frame parse_biss_frame(const uint8_t *bytes, uint32_t num_bytes){ + BiSS_Frame frame = {0}; + uint32_t num_bits = 0; + register uint8_t enclen = the_conf.encbits; + + bytes_to_bitstream(bytes, num_bytes, &num_bits); + + // Preamble detection state machine + enum {SEARCH_START, SEARCH_ZERO, COUNT_ZEROS} state = SEARCH_START; + uint32_t zero_count = 0; + uint32_t data_start = 0; + int found = 0; + + for(uint32_t i = 0; i < num_bits && !found; i++){ + uint8_t curbit = get_bit(i); + switch(state){ + case SEARCH_START: + if(curbit){ + state = SEARCH_ZERO; + } + break; + case SEARCH_ZERO: + if(!curbit){ + state = COUNT_ZEROS; + zero_count = 1; + } + break; + case COUNT_ZEROS: + if(!curbit){ + zero_count++; + }else{ + if(zero_count >= MINZEROS && zero_count <= MAXZEROS){ + if((i + 1) < num_bits && !get_bit(i + 1)){ + data_start = i + 2; + found = 1; + } + } + state = SEARCH_START; + } + break; + } + } + + // Validate frame structure + if(!found || (data_start + enclen+8) > num_bits){ + frame.frame_valid = 0; + return frame; + } + DBG("Data start:"); + DBGs(u2str(data_start)); + // Extract 26-bit data + for(int i = 0; i < enclen; i++){ + frame.data <<= 1; + frame.data |= get_bit(data_start + i); + } + + // Extract 2-bit flags (INVERTED!) + frame.error = !get_bit(data_start + enclen); + frame.warning = !get_bit(data_start + enclen + 1); + + // Extract and validate CRC + uint8_t received_crc = 0; + for(uint32_t i = 0; i < 6; i++){ + received_crc <<= 1; + // CRC transmitted MSB and inverted! Include position data and EW bits + if(!get_bit(data_start + enclen + 2 + i)) received_crc |= 1; + } + DBG("received CRC:"); + DBGs(uhex2str(received_crc)); + frame.crc_valid = (compute_crc(data_start, enclen + 2) == received_crc); + frame.frame_valid = 1; + return frame; +} diff --git a/F1:F103/BISS_C_encoders/bissC.h b/F1:F103/BISS_C_encoders/bissC.h new file mode 100644 index 0000000..b7816eb --- /dev/null +++ b/F1:F103/BISS_C_encoders/bissC.h @@ -0,0 +1,31 @@ +/* + * This file is part of the encoders project. + * Copyright 2025 Edward V. Emelianov . + * + * 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 . + */ + +#pragma once + +#include + +typedef struct { + uint32_t data; // 26/32/36-bit data + uint8_t error : 1; // error flag (0 - error: bad value or high temperature) + uint8_t warning : 1; // warning flag (0 - warning: need to be cleaned) + uint8_t crc_valid : 1; // CRC validation result + uint8_t frame_valid : 1; // Overall frame validity +} BiSS_Frame; + +BiSS_Frame parse_biss_frame(const uint8_t *bytes, uint32_t num_bytes); diff --git a/F1:F103/BISS_C_encoders/encoders.bin b/F1:F103/BISS_C_encoders/encoders.bin index 93ac16a7649c40a033ba81e89915366f227a20d4..660b8d127ec30f1eeedb86a6fcda2bc583fd6a47 100755 GIT binary patch literal 12524 zcmd6NdstIfw)o!XoIHsd2r3}r3Bei&N&q`WZEHxv;SnH?v{N6QF;UPkMPLADm`-O5 zh%J41tKv95`f#e#>03eRt+#bRX{W8VGl|L+QAeh&L{0DXq@Xz?@V&jvMd<#bMC%;qBcmBv2QV5#BAF96p%y(&gxBY8n z_?ejz_}%_(-;v?F{r}h7QAO$_ZLPb_`mT7cII&! z0e3F#-$YYT@b&K8k6Z~)opU*c6jVYpZg0&`fhW9-q_<|+y)@R8!mF4S<+A`6BZ&eW zT8-Gm!dR1a*!@70un$?q{^_>Fa^aYJwtX1Y!gJN8yX<_o%0A5GM;F?MRaO|uUM%ks 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 diff --git a/F1:F103/BISS_C_encoders/encoders.creator.user b/F1:F103/BISS_C_encoders/encoders.creator.user index 7ce7566..1de570b 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/encoders.files b/F1:F103/BISS_C_encoders/encoders.files index 29882c6..ee57130 100644 --- a/F1:F103/BISS_C_encoders/encoders.files +++ b/F1:F103/BISS_C_encoders/encoders.files @@ -1,3 +1,5 @@ +bissC.c +bissC.h flash.c flash.h hardware.c diff --git a/F1:F103/BISS_C_encoders/flash.c b/F1:F103/BISS_C_encoders/flash.c index 5a64626..5b23653 100644 --- a/F1:F103/BISS_C_encoders/flash.c +++ b/F1:F103/BISS_C_encoders/flash.c @@ -27,13 +27,14 @@ extern const uint32_t __varsstart, _BLOCKSIZE; static const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE; static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here -#define USERCONF_INITIALIZER { \ - .userconf_sz = sizeof(user_conf) \ - } - static int write2flash(const void*, const void*, uint32_t); const user_conf *Flash_Data = (const user_conf *)(&__varsstart); -user_conf the_conf = USERCONF_INITIALIZER; +user_conf the_conf = { + .userconf_sz = sizeof(user_conf), + .flags.CPOL = 1, + .flags.BR = 4, + .encbits = 26 +}; 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 fb7c002..ae80899 100644 --- a/F1:F103/BISS_C_encoders/flash.h +++ b/F1:F103/BISS_C_encoders/flash.h @@ -27,6 +27,12 @@ // maximal size (in letters) of iInterface for settings #define MAX_IINTERFACE_SZ (16) +typedef struct{ + uint8_t CPOL : 1; + uint8_t CPHA : 1; + uint8_t BR : 3; +} flags_t; + /* * struct to save user configurations */ @@ -34,6 +40,8 @@ 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 } 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 8f9b5bf..3d0633d 100644 --- a/F1:F103/BISS_C_encoders/main.c +++ b/F1:F103/BISS_C_encoders/main.c @@ -16,25 +16,97 @@ * along with this program. If not, see . */ +#include "bissC.h" #include "flash.h" #include "hardware.h" #include "proto.h" #include "spi.h" #include "strfunc.h" -#include "usart.h" +//#include "usart.h" #include "usb_dev.h" volatile uint32_t Tms = 0; +static char inbuff[RBINSZ]; /* Called when systick fires */ void sys_tick_handler(void){ ++Tms; } -int main(){ - char inbuff[RBINSZ]; - uint32_t lastT = 0, lastS = 0; +// usefull data bytes: start/0+26bit+8bit=36 +#define USEFULL_DATA_BYTES (5) + +static void printResult(BiSS_Frame *result){ + if(result->frame_valid){ + CMDWR("Data: "); CMDWRn(uhex2str(result->data)); + if(result->error) CMDWRn("ERROR flag set"); + if(result->warning) CMDWRn("WARNING flag set"); + CMDWR("CRC is "); if(!result->crc_valid) CMDWR("NOT "); + CMDWRn("valid"); + }else CMDWRn("Invalid frame"); +} + +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'; + if(CDCready[iface]){ + int l = USB_receivestr(iface, inbuff, RBINSZ); + if(CDCready[I_CMD]){ + if(l){ + CMDWR("Enc"); USB_putbyte(I_CMD, ifacechr); + CMDWR(": "); + } + if(l < 0) CMDWRn("ERROR! USB buffer overflow or string was too long"); + else if(l){ + CMDWR("got string: '"); + CMDWR(inbuff); + CMDWR("'\n"); + } + } + } + if(!spi_read_enc(idx, encbuf)) return; + BiSS_Frame result = parse_biss_frame(encbuf, ENCODER_BUFSZ); + char *str = result.crc_valid ? u2str(result.data) : NULL; + uint8_t testflag = (idx) ? user_pars.testy : user_pars.testx; + if(CDCready[I_CMD]){ + if(testflag){ + if(Tms - lastMSG[idx] > 9999){ + USB_putbyte(I_CMD, ifacechr); + CMDWR(" 10sec stat: good="); + CMDWR(u2str(gotgood[idx])); + CMDWR(", bad="); + CMDWR(u2str(gotwrong[idx])); + CMDn(); + gotgood[idx] = 0; + gotwrong[idx] = 0; + lastMSG[idx] = Tms; + }else{ + if(str) ++gotgood[idx]; + else ++gotwrong[idx]; + } + }else{ + printResult(&result); + CMDWR("ENC"); USB_putbyte(I_CMD, ifacechr); + USB_putbyte(I_CMD, '='); + hexdump(I_CMD, encbuf, ENCODER_BUFSZ); + CMDWR(" ("); + if(str) CMDWR(str); + else CMDWR("wrong"); + CMDWR(")\n"); + } + } + if(CDCready[iface] && str && !result.error){ + USB_sendstr(iface, str); + USB_putbyte(iface, '\n'); + } + if(result.error) spi_setup(1+idx); // reinit SPI in case of error + if(testflag) spi_start_enc(idx); +} + +int main(){ + uint32_t lastT = 0;//, lastS = 0; StartHSE(); flashstorage_init(); hw_setup(); @@ -68,50 +140,18 @@ int main(){ #endif */ if(CDCready[I_CMD]){ - if(Tms - lastS > 9999){ + /*if(Tms - lastS > 9999){ USB_sendstr(I_CMD, "Tms="); USB_sendstr(I_CMD, u2str(Tms)); - newline(I_CMD); + 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); } - int showval = spi_read_enc(0, encbuf); - if(CDCready[I_CMD] && showval){ - CMDWR("ENCX="); - hexdump(I_CMD, encbuf, ENCODER_BUFSZ); - newline(I_CMD); - } - if(CDCready[I_X]){ - int l = USB_receivestr(I_X, inbuff, RBINSZ); - if(l < 0) CMDWRn("ERROR: encX USB buffer overflow or string was too long"); - else if(l){ - CMDWR("EncX got: '"); - CMDWR(inbuff); - CMDWR("'\n"); - } - if(showval) // send encoder data - hexdump(I_X, encbuf, ENCODER_BUFSZ); - } - showval = spi_read_enc(1, encbuf); - if(CDCready[I_CMD] && showval){ - CMDWR("ENCY="); - hexdump(I_CMD, encbuf, ENCODER_BUFSZ); - newline(I_CMD); - } - if(CDCready[I_Y]){ - int l = USB_receivestr(I_Y, inbuff, RBINSZ); - if(l < 0) CMDWRn("ERROR: encY USB buffer overflow or string was too long"); - else if(l){ - CMDWR("EncY got: '"); - CMDWR(inbuff); - CMDWR("'\n"); - } - if(showval) // send encoder data - hexdump(I_Y, encbuf, ENCODER_BUFSZ); - } + proc_enc(0); + proc_enc(1); } return 0; } diff --git a/F1:F103/BISS_C_encoders/proto.c b/F1:F103/BISS_C_encoders/proto.c index f02b134..8001187 100644 --- a/F1:F103/BISS_C_encoders/proto.c +++ b/F1:F103/BISS_C_encoders/proto.c @@ -25,6 +25,9 @@ #include "usb_dev.h" #include "version.inc" +// user runtime parameters +parameters_t user_pars = {0}; + // error codes typedef enum { ERR_OK, // no errors @@ -63,6 +66,12 @@ typedef enum{ C_spistat, C_spiinit, C_spideinit, + C_cpol, + C_cpha, + C_br, + C_encbits, + C_testX, + C_testY, C_AMOUNT } cmd_e; @@ -81,7 +90,6 @@ static const funcdescr_t commands[C_AMOUNT]; CMDWR(i2str(ival)); CMDn(); return ERR_SILENCE; }while(0) static errcode_e help(cmd_e idx, char* par); -static errcode_e dumpconf(cmd_e idx, char *par); static errcode_e dummy(cmd_e idx, char *par){ static int32_t val = -111; @@ -215,6 +223,110 @@ static errcode_e spideinit(_U_ cmd_e idx, _U_ char *par){ return ERR_SILENCE; } +static errcode_e setflags(cmd_e idx, char *par){ + if(par){ + if(*par < '0' || *par > '9') return ERR_BADPAR; + uint8_t val = *par - '0'; + 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; + 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)); + CMDn(); + return ERR_SILENCE; +} + +static errcode_e setboolpar(cmd_e idx, char *par){ + uint8_t val; + if(par){ + if(*par != '0' && *par != '1') return ERR_BADPAR; + val = *par - '0'; + switch(idx){ + case C_testX: + user_pars.testx = val; + break; + case C_testY: + user_pars.testy = val; + break; + default: + return ERR_BADCMD; + } + } + switch(idx){ + case C_testX: + val = user_pars.testx; + if(val) spi_start_enc(0); + break; + case C_testY: + val = user_pars.testy; + if(val) spi_start_enc(1); + 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 dumpconf(cmd_e _U_ idx, char _U_ *par){ + CMDWR("userconf_sz="); CMDWR(u2str(the_conf.userconf_sz)); + CMDWR("\ncurrentconfidx="); CMDWR(i2str(currentconfidx)); + 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); + return ERR_SILENCE; +} + // text commands static const funcdescr_t commands[C_AMOUNT] = { [C_dummy] = {"dummy", dummy}, @@ -235,17 +347,14 @@ 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_testX] = {"testx", setboolpar}, + [C_testY] = {"testy", setboolpar}, }; -static errcode_e dumpconf(cmd_e _U_ idx, char _U_ *par){ - CMDWR("userconf_sz="); CMDWR(u2str(the_conf.userconf_sz)); - CMDWR("\ncurrentconfidx="); CMDWR(i2str(currentconfidx)); - CMDn(); - for(int i = 0; i < bTotNumEndpoints; ++i) - setiface(C_setiface1 + i, NULL); - return ERR_SILENCE; -} - typedef struct{ int idx; // command index (if < 0 - just display `help` as grouping header) const char *help; // help message @@ -271,9 +380,15 @@ static const help_t helpmessages[] = { {C_spiinit, "init SPI"}, {C_spistat, "get status of both SPI interfaces"}, {-1, "Debug"}, + {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_fin, "reinit flash"}, {C_sendX, "send text string to X encoder's terminal"}, {C_sendY, "send text string to Y encoder's terminal"}, - {C_fin, "reinit flash"}, + {C_testX, "test X-axis throughput"}, + {C_testY, "test Y-axis throughput"}, {-1, NULL}, }; diff --git a/F1:F103/BISS_C_encoders/proto.h b/F1:F103/BISS_C_encoders/proto.h index 1a1ebfe..e1a0aee 100644 --- a/F1:F103/BISS_C_encoders/proto.h +++ b/F1:F103/BISS_C_encoders/proto.h @@ -18,4 +18,13 @@ #pragma once +#include + +typedef struct{ + uint8_t testx : 1; + uint8_t testy : 1; +} parameters_t; + +extern parameters_t user_pars; + void parse_cmd(char *cmd); diff --git a/F1:F103/BISS_C_encoders/ringbuffer.h b/F1:F103/BISS_C_encoders/ringbuffer.h index ed2cf95..5643b5a 100644 --- a/F1:F103/BISS_C_encoders/ringbuffer.h +++ b/F1:F103/BISS_C_encoders/ringbuffer.h @@ -25,12 +25,14 @@ #include #endif +#include + typedef struct{ uint8_t *data; // data buffer const int length; // its length int head; // head index int tail; // tail index - volatile int busy; // == TRUE if buffer is busy now + volatile atomic_int busy; // == TRUE if buffer is busy now } ringbuffer; int RB_read(ringbuffer *b, uint8_t *s, int len); diff --git a/F1:F103/BISS_C_encoders/spi.c b/F1:F103/BISS_C_encoders/spi.c index 9430a21..06bfb0f 100644 --- a/F1:F103/BISS_C_encoders/spi.c +++ b/F1:F103/BISS_C_encoders/spi.c @@ -17,9 +17,10 @@ */ #include - -#include "spi.h" #include // memcpy + +#include "flash.h" +#include "spi.h" #include "usb_dev.h" #ifdef EBUG #include "strfunc.h" @@ -31,7 +32,7 @@ spiStatus spi_status[AMOUNT_OF_SPI+1] = {0, SPI_NOTREADY, SPI_NOTREADY}; 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 < 360000)) IWDG->KR = IWDG_REFRESH; if(wctr==360000){ DBG("timeout"); return 0;}}while(0) +#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 freshdata[AMOUNT_OF_SPI] = {0}; @@ -46,13 +47,14 @@ void spi_setup(uint8_t idx){ SPI->CR2 = 0; RCC->AHBENR |= RCC_AHBENR_DMA1EN; volatile DMA_Channel_TypeDef *DMA = DMAs[idx]; + uint32_t clkflags = 0; if(idx == 1){ // PA5/PA6; 72MHz RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; RCC->APB2RSTR = RCC_APB2RSTR_SPI1RST; RCC->APB2RSTR = 0; // clear reset GPIOA->CRL = (GPIOA->CRL & ~(GPIO_CRL_CNF5 | GPIO_CRL_CNF6)) | CRL(5, CNF_AFPP|MODE_FAST) | CRL(6, CNF_FLINPUT); - SPI->CR1 = SPI_CR1_BR_1 | SPI_CR1_BR_2; // Fpclk/128 + clkflags = ((uint32_t)the_conf.flags.BR) << 3; NVIC_EnableIRQ(DMA1_Channel2_IRQn); // enable Rx interrupt }else if(idx == 2){ // PB13/PB14; 36MHz RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; @@ -60,11 +62,14 @@ void spi_setup(uint8_t idx){ RCC->APB1RSTR = 0; GPIOB->CRH = (GPIOB->CRH & ~(GPIO_CRH_CNF13 | GPIO_CRH_CNF14)) | CRH(13, CNF_AFPP|MODE_FAST) | CRH(14, CNF_FLINPUT); - SPI->CR1 = SPI_CR1_BR_0 | SPI_CR1_BR_2; // Fpclk/64 + clkflags = ((uint32_t)the_conf.flags.BR - 1) << 3; // freq/2 NVIC_EnableIRQ(DMA1_Channel4_IRQn); }else return; // err // Baudrate = 0b110 - fpclk/128 - SPI->CR1 |= SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_RXONLY; + // CPOL=1 (CLK is 1 on idle); CPHA=0 (capture in first front) + if(the_conf.flags.CPHA) clkflags |= SPI_CR1_CPHA; + if(the_conf.flags.CPOL) clkflags |= SPI_CR1_CPOL; + SPI->CR1 |= SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_RXONLY | clkflags; SPI->CR2 = SPI_CR2_RXDMAEN; DMA->CPAR = (uint32_t)&(SPI->DR); DMA->CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE; // mem inc, hw->mem, Rx complete and error interrupt @@ -76,8 +81,8 @@ 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"); + //DBGs(u2str(idx)); + //DBG("turn on SPI"); SPI->CR1 |= SPI_CR1_SPE; spi_status[idx] = SPI_BUSY; }else{ @@ -117,9 +122,9 @@ static int spi_waitbsy(uint8_t idx){ // just copy last read encoder value into `buf` // @return TRUE if got fresh data -int spi_read_enc(uint8_t encno, uint8_t buf[8]){ +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"); + //DBGs(u2str(encno)); DBG("Read encoder data"); memcpy(buf, encoderbuf[encno], ENCODER_BUFSZ); freshdata[encno] = 0; // clear fresh status return TRUE; @@ -130,16 +135,16 @@ int spi_read_enc(uint8_t encno, uint8_t buf[8]){ // 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"); + //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!"); + 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"); + //DBG("turn on spi"); spi_onoff(spiidx, 1); DMA->CCR |= DMA_CCR_EN; return TRUE; @@ -149,6 +154,7 @@ int spi_start_enc(int encodernum){ void dma1_channel2_isr(){ // turn off DMA DMA1_Channel2->CCR &= ~DMA_CCR_EN; + SPI1->CR1 &= ~SPI_CR1_SPE; if(DMA1->ISR & DMA_ISR_TEIF2){ DMA1->IFCR = DMA_IFCR_CTEIF2; } @@ -160,12 +166,13 @@ void dma1_channel2_isr(){ //encoderbuf[6] = (ctr >> 8 ) & 0xff; //encoderbuf[7] = (ctr >> 0 ) & 0xff; } - spi_onoff(1, 0); + spi_status[1] = SPI_READY; } void dma1_channel4_isr(){ // turn off DMA DMA1_Channel4->CCR &= ~DMA_CCR_EN; + SPI2->CR1 &= ~SPI_CR1_SPE; if(DMA1->ISR & DMA_ISR_TEIF4){ DMA1->IFCR = DMA_IFCR_CTEIF4; } @@ -173,6 +180,6 @@ void dma1_channel4_isr(){ DMA1->IFCR = DMA_IFCR_CTCIF4; freshdata[1] = 1; } - spi_onoff(2, 0); + spi_status[2] = SPI_READY; } diff --git a/F1:F103/BISS_C_encoders/spi.h b/F1:F103/BISS_C_encoders/spi.h index 950f771..f5a4f84 100644 --- a/F1:F103/BISS_C_encoders/spi.h +++ b/F1:F103/BISS_C_encoders/spi.h @@ -4,7 +4,7 @@ #define AMOUNT_OF_SPI (2) -#define ENCODER_BUFSZ (8) +#define ENCODER_BUFSZ (12) typedef enum{ SPI_NOTREADY, @@ -18,4 +18,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[8]); +int spi_read_enc(uint8_t encno, uint8_t buf[ENCODER_BUFSZ]); diff --git a/F1:F103/BISS_C_encoders/usb_descr.c b/F1:F103/BISS_C_encoders/usb_descr.c index 6237867..fd1688d 100644 --- a/F1:F103/BISS_C_encoders/usb_descr.c +++ b/F1:F103/BISS_C_encoders/usb_descr.c @@ -215,7 +215,7 @@ static void wr0(const uint8_t *buf, uint16_t size, uint16_t askedsize){ // 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; + uint32_t ctr = 10000; while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;}; if((USB->ISTR & USB_ISTR_CTR) == 0){ return; diff --git a/F1:F103/BISS_C_encoders/usb_descr.h b/F1:F103/BISS_C_encoders/usb_descr.h index b2778f5..8c0ffd2 100644 --- a/F1:F103/BISS_C_encoders/usb_descr.h +++ b/F1:F103/BISS_C_encoders/usb_descr.h @@ -45,9 +45,9 @@ #define USB_EP0BUFSZ 64 // virtual #define USB_EP1BUFSZ 10 -// Rx/Tx EPs: (512-64-128)/14 rouded to 8 -#define USB_RXBUFSZ 16 -#define USB_TXBUFSZ 16 +// Rx/Tx EPs: (512-64-128)/6 rouded to 8 +#define USB_RXBUFSZ 40 +#define USB_TXBUFSZ 64 // string descriptors enum{ diff --git a/F1:F103/BISS_C_encoders/usb_dev.c b/F1:F103/BISS_C_encoders/usb_dev.c index 269ee14..d9bcdfc 100644 --- a/F1:F103/BISS_C_encoders/usb_dev.c +++ b/F1:F103/BISS_C_encoders/usb_dev.c @@ -60,8 +60,8 @@ static uint8_t obuf[bTotNumEndpoints][RBOUTSZ], ibuf[bTotNumEndpoints][RBINSZ]; static volatile ringbuffer rbout[bTotNumEndpoints] = {OBUF(0), OBUF(1), OBUF(2)}; #define IBUF(N) {.data = ibuf[N], .length = RBINSZ, .head = 0, .tail = 0} static volatile ringbuffer rbin[bTotNumEndpoints] = {IBUF(0), IBUF(1), IBUF(2)}; -// last send data size -static volatile int lastdsz[bTotNumEndpoints] = {0}; +// last send data size (<0 if USB transfer ready) +static volatile int lastdsz[bTotNumEndpoints] = {-1, -1, -1}; static void chkin(uint8_t ifno){ if(bufovrfl[ifno]) return; // allow user to know that previous buffer was overflowed and cleared @@ -82,13 +82,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"); @@ -140,11 +146,13 @@ void WEAK clstate_handler(uint8_t ifno, uint16_t val){ DBGs(uhex2str(ifno)); DBGs(uhex2str(val)); CDCready[ifno] = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected + lastdsz[ifno] = -1; } // SEND_BREAK void WEAK break_handler(uint8_t ifno){ CDCready[ifno] = 0; + lastdsz[ifno] = -1; DBG("break_handler()"); DBGs(uhex2str(ifno)); } @@ -154,6 +162,7 @@ void WEAK break_handler(uint8_t ifno){ void set_configuration(){ DBG("set_configuration()"); for(int i = 0; i < bTotNumEndpoints; ++i){ + IWDG->KR = IWDG_REFRESH; int r = EP_Init(1+i, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_handler); if(r){ DBG("Can't init EP"); @@ -215,6 +224,7 @@ void usb_class_request(config_pack_t *req, uint8_t *data, uint16_t datalen){ int USB_sendall(uint8_t ifno){ while(lastdsz[ifno] > 0){ if(!CDCready[ifno]) return FALSE; + IWDG->KR = IWDG_REFRESH; } return TRUE; } @@ -224,13 +234,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(a > 0){ len -= a; buf += a; - } else if (a < 0) continue; // do nothing if buffer is in reading state - if(lastdsz[ifno] == 0) send_next(ifno); // need to run manually - all data sent, so no IRQ on IN + }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; } @@ -238,9 +252,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(l < 0) continue; + if(!CDCready[ifno]) return FALSE; + IWDG->KR = IWDG_REFRESH; + if(l == 0){ // overfull + if(lastdsz[ifno] < 0) send_next(ifno); + continue; + } } - if(lastdsz[ifno] == 0) send_next(ifno); // need to run manually - all data sent, so no IRQ on IN + // send line if got EOL + if(byte == '\n' && lastdsz[ifno] < 0) send_next(ifno); return TRUE; } diff --git a/F1:F103/BISS_C_encoders/usb_dev.h b/F1:F103/BISS_C_encoders/usb_dev.h index a785895..7f32ac6 100644 --- a/F1:F103/BISS_C_encoders/usb_dev.h +++ b/F1:F103/BISS_C_encoders/usb_dev.h @@ -48,8 +48,8 @@ void linecoding_handler(uint8_t ifno, usb_LineCoding *lc); // sizes of ringbuffers for outgoing and incoming data -#define RBOUTSZ (256) -#define RBINSZ (256) +#define RBOUTSZ (512) +#define RBINSZ (128) #define newline(ifno) USB_putbyte(ifno, '\n') #define USND(ifno, s) do{USB_sendstr(ifno, s); USB_putbyte(ifno, '\n');}while(0) @@ -61,7 +61,7 @@ void linecoding_handler(uint8_t ifno, usb_LineCoding *lc); #define STR_HELPER(s) #s #define STR(s) STR_HELPER(s) #define DBG(str) do{USB_sendstr(I_CMD, __FILE__ " (L" STR(__LINE__) "): " str); USB_putbyte(I_CMD, '\n');}while(0) -#define DBGs(str) do{USB_sendstr(I_CMD, str); USB_sendstr(I_CMD, "<--\n");}while(0) +#define DBGs(str) do{USB_sendstr(I_CMD, str); USB_sendstr(I_CMD, "\n");}while(0) #else #define DBG(s) #define DBGs(s) diff --git a/F1:F103/BISS_C_encoders/version.inc b/F1:F103/BISS_C_encoders/version.inc index 2872e58..2bcb422 100644 --- a/F1:F103/BISS_C_encoders/version.inc +++ b/F1:F103/BISS_C_encoders/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "73" -#define BUILD_DATE "2025-03-27" +#define BUILD_NUMBER "91" +#define BUILD_DATE "2025-04-02"