Open FFBoard
Open source force feedback firmware
EncoderBissC.cpp
Go to the documentation of this file.
1/*
2 * EncoderBissC.cpp
3 *
4 * Created on: 19.12.2020
5 * Author: Leon
6 * Update : Yannick & Vincent
7 *
8 */
9
10#include "EncoderBissC.h"
11#include "CRC.h"
12#include "array"
13
14bool EncoderBissC::inUse = false;
16 .name = "BISS-C" ,
17 .id=CLSID_ENCODER_BISS
18};
19
21 return info;
22}
23
24std::array<uint8_t,64> EncoderBissC::tableCRC6n __attribute__((section (".ccmram")));
25
27 SPIDevice(ENCODER_SPI_PORT, ENCODER_SPI_PORT.getCsPins()[0]),
28 CommandHandler("bissenc",CLSID_ENCODER_BISS,0),
29 cpp_freertos::Thread("BISSENC",64,42) {
31
32
33 //Init CRC-6 table
35
37 this->spiPort.takeExclusive(true);
38 configSPI();
40 this->Start();
41}
42
44 bool first = true;
45 while(true){
46 requestNewDataSem.Take(); // Wait until a position is requested
47 waitData = true;
48 spiPort.receive_DMA(spi_buf, bytes, this); // Receive next frame
49 this->WaitForNotification(); // Wait until DMA is finished
50
51 if(updateFrame()){
52 int32_t halfres = 1<<(lenghtDataBit-1);
53 pos = newPos;
54 if(first){ // Prevent immediate multiturn update
56 first = false;
57 // If offset from current pos is more than half rotation add a multiturn count by setting previous position to the reloaded offset
58 }
59 //handle multiturn
60 if(pos-lastPos > halfres){
61 mtpos--;
62 }else if(lastPos-pos > halfres){
63 mtpos++;
64 }
65
66 lastPos = pos;
67 }else{
68 numErrors++;
69 }
70 waitData = false;
71 lastUpdateTick = HAL_GetTick();
72 if(useWaitSem)
74
75 }
76}
77
78
80 uint16_t buf;
81 if(Flash_Read(ADR_BISSENC_CONF1, &buf)){
82 this->lenghtDataBit = (buf & 0x1F)+1; // up to 32 bit. 5 bits
83 this->spiSpeed = ((buf >> 5) & 0x3) +1;
84 this->invertDirection = ((buf >> 7) & 1);
85 }
86 uint16_t restoredOffset = ( (uint16_t)(Flash_ReadDefault(ADR_BISSENC_OFS, 0) ));
87 posOffset = static_cast<int32_t>(restoredOffset) << std::max(0,(lenghtDataBit-16));
88}
89
91 uint16_t buf = std::max((this->lenghtDataBit-1),0) & 0x1F;
92 buf |= ((this->spiSpeed-1) & 0x3) << 5;
93 buf |= (this->invertDirection & 1) << 7;
94 Flash_Write(ADR_BISSENC_CONF1, buf);
95 int32_t scaledOfs = posOffset >> std::max(0,(lenghtDataBit-16));
96 Flash_Write(ADR_BISSENC_OFS, (uint16_t)(scaledOfs) );
97}
98
100
101 uint32_t prescale;
102 switch (spiSpeed) {
103 case 1 :
104 prescale = SPI_BAUDRATEPRESCALER_64;
105 break;
106 case 2 :
107 prescale = SPI_BAUDRATEPRESCALER_32;
108 break;
109 case 3 :
110 prescale = SPI_BAUDRATEPRESCALER_16;
111 break;
112 default :
113 prescale = SPI_BAUDRATEPRESCALER_16;
114 break;
115 }
116
117 SPIConfig* config = this->getSpiConfig();
118 // CS pin not used because bus must be always active and can't be shared!
119 config->peripheral.BaudRatePrescaler = prescale;
120 config->peripheral.FirstBit = SPI_FIRSTBIT_MSB;
121 config->peripheral.CLKPhase = SPI_PHASE_2EDGE;
122 config->peripheral.CLKPolarity = SPI_POLARITY_HIGH;
123 config->peripheral.DataSize = SPI_DATASIZE_8BIT;
124 config->cspol = true;
125 this->setSpiConfig(*config);
126 this->spiPort.configurePort(&config->peripheral);
127
128}
129
131 return !EncoderBissC::inUse && ENCODER_SPI_PORT.hasFreePins();
132}
133
135 setPos(0);
136 EncoderBissC::inUse = false;
137 this->spiPort.takeExclusive(false);
138}
139
141 memcpy(this->decod_buf,this->spi_buf,this->bytes);
142 this->NotifyFromISR();
143
144}
145
147 //port->takeSemaphore();
149}
150
152 //port->giveSemaphore();
154}
155
156
157
160}
161
162__attribute__((optimize("-Ofast")))
163bool EncoderBissC::updateFrame(){
164
165
166 //Put data into 64bit int to enable easy shifting
167 uint64_t rxData64;
168
169 // 32b operation reduces time needed
170 rxData64 = (uint64_t)__REV(decod_buf[0]) << 32;
171 rxData64 |= (uint64_t)__REV(decod_buf[1]);
172
173 // sample of rxData64
174 // like this 1100000000000000100001100111010000000101110111100000000000000000
175 rxData64 <<= __builtin_clzll(rxData64); // slice rxData to have a value starting with 1
176 rxData64 &= 0x3FFFFFFFFFFFFFFF; // remove the 2 first bit
177
178 // remove the first 1, count how many digit stay in buffer after removing the 0, if there is more than 32 digits,
179 // keep only 32st (on the left)
180 // 32 because the format is : (1+1+lenghtDataBit+1+1+6) - Align bitstream to left (Startbit, CDS, 22-bit Position, Error, Warning, CRC)
181 //int nbBit = log2(rxData64)+1;
182 int nbBit = 64-__builtin_clzll(rxData64); // Much faster than log2
183 if ( nbBit >= ( lenghtDataBit + 10 ) ) {
184 rxData64 >>= nbBit-( lenghtDataBit + 10 );
185 }
186
187 uint8_t crcRx = rxData64 & 0x3F; //extract last 6-bit digits to get CRC
188 uint32_t dataRx = (rxData64 >> 6) & ((1<<(lenghtDataBit + 2)) - 1); //Shift out CRC, AND with 24-bit mask to get raw data (position, error, warning)
189 uint8_t errorWarning = (dataRx & 0x3); // Error and warning are lowest 2 bits now
190 newPos = (dataRx >> 2) & ((1<<lenghtDataBit) - 1); //Shift out error and warning, AND with 22-bit mask to get position
191
192
193 uint8_t crc = 0; //CRC seed is 0b000000
194 crc = ((dataRx >> 30) & 0x03);
195 crc = tableCRC6n[((dataRx >> 24) & 0x3F) ^ crc];
196 crc = tableCRC6n[((dataRx >> 18) & 0x3F) ^ crc];
197 crc = tableCRC6n[((dataRx >> 12) & 0x3F) ^ crc];
198 crc = tableCRC6n[((dataRx >> 6) & 0x3F) ^ crc];
199 crc = tableCRC6n[((dataRx >> 0) & 0x3F) ^ crc];
200 crc = 0x3F & ~crc; //CRC is output inverted
201
202 bool crc_ok = crc == crcRx;
203 return crc_ok;
204}
205
207 if(!waitData){ // If a transfer is still in progress return the last result
208 requestNewDataSem.Give(); // Start transfer
209 if(useWaitSem && HAL_GetTick() - lastUpdateTick > waitThresh)
210 waitForUpdateSem.Take(waitThresh); // Wait a bit
211 }
212 int32_t curpos = pos + mtpos * getCpr();
213 return invertDirection ? -curpos : curpos;
214}
215
217 if(invertDirection){
218 return getPosAbs()+posOffset;
219 }else{
220 return getPosAbs()-posOffset;
221 }
222
223}
224
225void EncoderBissC::setPos(int32_t newpos){
226 if(invertDirection){
227 newpos = -newpos;
228 }
229 int32_t diff = ( pos - newpos);
230 mtpos = newpos / getCpr(); // Multiturn should be reset
231
232 posOffset = diff % getCpr(); // Always positive
233}
234
235
236
238 return 1<<lenghtDataBit;
239}
240
243 registerCommand("bits", EncoderBissC_commands::bits, "Bits of resolution",CMDFLAG_GET|CMDFLAG_SET);
244 registerCommand("speed", EncoderBissC_commands::speed, "SPI speed preset 1-3",CMDFLAG_GET|CMDFLAG_SET);
245 registerCommand("errors", EncoderBissC_commands::errors, "CRC error count",CMDFLAG_GET);
246 registerCommand("dir", EncoderBissC_commands::direction, "Invert direction",CMDFLAG_GET|CMDFLAG_SET);
247}
248
249CommandStatus EncoderBissC::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
250 switch(static_cast<EncoderBissC_commands>(cmd.cmdId)){
252 handleGetSet(cmd, replies, this->lenghtDataBit);
253 if(this->lenghtDataBit > 24 && this->spiSpeed >= 3){
254 this->spiSpeed = 2; // Drop SPI speed to prevent encoder from losing data.
255 }
256 break;
258 replies.emplace_back(numErrors);
259 break;
261 handleGetSet(cmd, replies, this->spiSpeed);
262 this->spiSpeed = clip(this->spiSpeed,1,3); // Limit from 1-3
263 if(cmd.type == CMDtype::set){
264 configSPI();
265 }
266 break;
267
269 handleGetSet(cmd, replies, this->invertDirection);
270 break;
271 default:
273 }
274 return CommandStatus::OK;
275
276}
void makeCrcTable(std::array< T, LEN > &table, const T crcpoly, const uint8_t bits, const bool refin=false, const bool refout=false)
Definition: CRC.h:36
CommandStatus
EncoderType
Definition: Encoder.h:27
std::array< uint8_t, 64 > EncoderBissC::tableCRC6n __attribute__((section(".ccmram")))
uint8_t crc
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
static CommandStatus handleGetSet(const ParsedCommand &cmd, std::vector< CommandReply > &replies, TVal &value)
int32_t lastPos
Definition: EncoderBissC.h:66
static ClassIdentifier info
Definition: EncoderBissC.h:26
void endSpiTransfer(SPIPort *port)
int32_t numErrors
Definition: EncoderBissC.h:76
const uint8_t POLY
Definition: EncoderBissC.h:74
void registerCommands()
static std::array< uint8_t, 64 > tableCRC6n
Definition: EncoderBissC.h:75
int32_t getPosAbs()
bool updateFrame()
void beginSpiTransfer(SPIPort *port)
uint32_t getCpr()
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
cpp_freertos::BinarySemaphore waitForUpdateSem
Definition: EncoderBissC.h:79
void spiRxCompleted(SPIPort *port) override
static bool isCreatable()
static const uint32_t waitThresh
Definition: EncoderBissC.h:58
uint32_t lastUpdateTick
Definition: EncoderBissC.h:64
void restoreFlash()
uint8_t spi_buf[bytes]
Definition: EncoderBissC.h:70
virtual ~EncoderBissC()
void configSPI()
static const bool useWaitSem
Definition: EncoderBissC.h:57
const ClassIdentifier getInfo()
Command handlers always have class infos. Works well with ChoosableClass.
int32_t pos
Definition: EncoderBissC.h:66
int32_t posOffset
Definition: EncoderBissC.h:66
bool invertDirection
Definition: EncoderBissC.h:62
void setPos(int32_t pos)
static bool inUse
Definition: EncoderBissC.h:77
static const uint8_t bytes
Definition: EncoderBissC.h:69
int32_t newPos
Definition: EncoderBissC.h:66
int32_t mtpos
Definition: EncoderBissC.h:67
void saveFlash()
int32_t getPos()
cpp_freertos::BinarySemaphore requestNewDataSem
Definition: EncoderBissC.h:78
uint32_t decod_buf[bytes/4]
Definition: EncoderBissC.h:71
EncoderType getEncoderType()
Definition: SPI.h:100
SPIPort & spiPort
Definition: SPI.h:124
void assertChipSelect()
Definition: SPI.cpp:373
virtual SPIConfig * getSpiConfig()
Definition: SPI.h:120
void clearChipSelect()
Definition: SPI.cpp:377
virtual void setSpiConfig(SPIConfig config)
Definition: SPI.h:123
Definition: SPI.h:43
void takeExclusive(bool exclusive)
Definition: SPI.cpp:216
void receive_DMA(uint8_t *buf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:117
void configurePort(SPI_InitTypeDef *config)
Definition: SPI.cpp:72
bool Take(TickType_t Timeout=portMAX_DELAY)
Definition: csemaphore.cpp:46
uint32_t WaitForNotification(TickType_t Timeout=portMAX_DELAY)
Definition: thread.hpp:246
T clip(T v, C l, C h)
Definition: cppmain.h:58
TVal Flash_ReadDefault(uint16_t adr, TVal def)
Definition: flash_helpers.h:36
bool Flash_Write(uint16_t adr, uint16_t dat)
bool Flash_Read(uint16_t adr, uint16_t *buf, bool checkempty=true)
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
const char * name
uint32_t cmdId
Definition: SPI.h:18
SPI_InitTypeDef peripheral
Definition: SPI.h:38
bool cspol
CSPOL=true === active low.
Definition: SPI.h:37