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 93ac16a..660b8d1 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 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"