Open FFBoard
Open source force feedback firmware
Loading...
Searching...
No Matches
MtEncoderSPI.cpp
Go to the documentation of this file.
1/*
2 * MtEncoderSPI.cpp
3 *
4 * Created on: 02.11.2021
5 * Author: Yannick
6 */
7
8#include "MtEncoderSPI.h"
9#include "constants.h"
10#include "CRC.h"
11#ifdef MTENCODERSPI
12bool MtEncoderSPI::inUse = false;
13
15 .name = "MagnTek SPI" ,
16 .id=CLSID_ENCODER_MTSPI,
17 };
21
22std::array<uint8_t,256> MtEncoderSPI::tableCRC __attribute__((section (".ccmram")));
23
24MtEncoderSPI::MtEncoderSPI() : SPIDevice(ENCODER_SPI_PORT,ENCODER_SPI_PORT.getFreeCsPins()[0]), CommandHandler("mtenc",CLSID_ENCODER_MTSPI,0),cpp_freertos::Thread("MTENC",256,42) {
26 this->spiConfig.peripheral.BaudRatePrescaler = spiPort.getClosestPrescaler(10e6).first; // 10MHz max
27 this->spiConfig.peripheral.FirstBit = SPI_FIRSTBIT_MSB;
28 this->spiConfig.peripheral.CLKPhase = SPI_PHASE_2EDGE;
29 this->spiConfig.peripheral.CLKPolarity = SPI_POLARITY_HIGH;
30 this->spiConfig.cspol = true;
31
32 //Init CRC-8 table
33 makeCrcTable(tableCRC,POLY,8); // Mt6825, Poly X8+X2+X (+1)
34
35 restoreFlash(); // Also configures SPI port
36 spiPort.reserveCsPin(this->spiConfig.cs);
37
39 registerCommand("cs", MtEncoderSPI_commands::cspin, "CS pin",CMDFLAG_GET | CMDFLAG_SET);
40 registerCommand("pos", MtEncoderSPI_commands::pos, "Position",CMDFLAG_GET | CMDFLAG_SET);
41 registerCommand("errors", MtEncoderSPI_commands::errors, "Parity error count",CMDFLAG_GET);
42 registerCommand("mode", MtEncoderSPI_commands::mode, "Encoder mode (MT6825=0;MT6835=1)",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
43 registerCommand("speed", MtEncoderSPI_commands::speed, "SPI speed preset",CMDFLAG_GET | CMDFLAG_SET | CMDFLAG_INFOSTRING);
44 registerCommand("reg", MtEncoderSPI_commands::reg, "Read/Write register",CMDFLAG_GETADR | CMDFLAG_SETADR | CMDFLAG_DEBUG);
45 registerCommand("save", MtEncoderSPI_commands::save, "Save to memory",CMDFLAG_GET | CMDFLAG_DEBUG);
46 this->Start();
47}
48
50 MtEncoderSPI::inUse = false;
51 spiPort.freeCsPin(this->spiConfig.cs);
52}
53
55
56 uint16_t conf_int = Flash_ReadDefault(ADR_MTENC_CONF1, 0);
57
58 uint8_t cspin = conf_int & 0x3;
59 MtEncoderSPI_mode mode = static_cast<MtEncoderSPI_mode>(conf_int >> 8);
60
61 uint8_t offsetShift = 2;
63 offsetShift = 5;
64 }
65 offset = Flash_ReadDefault(ADR_MTENC_OFS, 0) << offsetShift;
68 setSpiSpeed((conf_int >> 2) & 0x3);
69}
70
72 uint8_t offsetShift = 2;
74 offsetShift = 5;
75 }
76 uint16_t conf_int = this->cspin & 0x3;
77 conf_int |= (this->spiSpeedPreset & 0x3) << 2;
78 conf_int |= ((uint8_t)mode & 0xf) << 8;
79 Flash_Write(ADR_MTENC_CONF1, conf_int);
80 Flash_Write(ADR_MTENC_OFS, offset >> offsetShift);
81}
82
83
85 while(true){
86 requestNewDataSem.Take(); // Wait until a position is requested
87 //spiPort.receive_DMA(spi_buf, bytes, this); // Receive next frame
89 this->WaitForNotification(); // Wait until DMA is finished
90
92 int overflowLim = getCpr() >> 1;
93 if(curAngleInt-lastAngleInt > overflowLim){ // Underflowed
94 rotations--;
95 }
96 else if(lastAngleInt-curAngleInt > overflowLim){ // Overflowed
97 rotations++;
98 }
100
101 curPos = rotations * getCpr() + curAngleInt; // Update position
102 }else{
103 errors++;
104 }
105 lastUpdateTick = HAL_GetTick();
106 waitForUpdateSem.Give();
107 updateInProgress = false;
108 }
109}
110
112 spiPort.freeCsPin(this->spiConfig.cs);
113 this->cspin = std::min<uint8_t>(spiPort.getCsPins().size(), cspin);
114 this->spiConfig.cs = *spiPort.getCsPin(this->cspin);
115 initSPI();
116 spiPort.reserveCsPin(this->spiConfig.cs);
117}
118
120 spiPort.takeSemaphore();
121
122 spiPort.configurePort(&this->spiConfig.peripheral);
123 spiPort.giveSemaphore();
124}
125
129uint8_t MtEncoderSPI::readSpi(uint16_t addr){
131 uint8_t txbuf[2] = {(uint8_t)(addr | 0x80),0};
132 uint8_t rxbuf[2] = {0,0};
133 spiPort.transmitReceive(txbuf, rxbuf, 2, this,100);
134 return rxbuf[1];
135 }else if(mode == MtEncoderSPI_mode::mt6835){
136 uint8_t txbuf[3] = {(uint8_t)((addr & 0xf00) | 0x30),(uint8_t)(addr & 0xff),0};
137 uint8_t rxbuf[3] = {0,0,0};
138 spiPort.transmitReceive(txbuf, rxbuf, 3, this,100);
139 return rxbuf[2];
140 }
141}
142
143void MtEncoderSPI::writeSpi(uint16_t addr,uint8_t data){
145 uint8_t txbuf[2] = {(uint8_t)(addr & 0xff),data};
146 spiPort.transmit(txbuf, 2, this,100);
147 }else if(mode == MtEncoderSPI_mode::mt6835){
148 uint8_t txbuf[3] = {(uint8_t)((addr & 0xf00) | 0x60),(uint8_t)(addr & 0xff),data};
149 spiPort.transmit(txbuf, 3, this,100);
150 }
151
152}
153
159 return false;
160 }
162 uint8_t txbuf[3] = {0xC0,0x00,0x00};
163 uint8_t rxbuf[3] = {0,0,0};
164 spiPort.transmitReceive(txbuf, rxbuf, 3, this,100);
165 return rxbuf[2] == 0x55;
166 }
167 return false;
168}
169
171 offset = curPos - pos;
172}
173
174
176
179 //updateAngleStatusCb();
180 memcpy(rxbuf,rxbuf_t,sizeof(rxbuf));
181 }
182}
183
184
189
191 uint8_t txbufNew[5] = {0x03 | 0x80,0,0,0,0};
192 memcpy(this->txbuf,txbufNew,5);
193 spiPort.transmitReceive_DMA(txbuf, rxbuf_t, 4, this);
194 }else if(mode == MtEncoderSPI_mode::mt6835){
195 uint8_t txbufNew[6] = {0xA0,0x03,0,0,0,0};
196 memcpy(this->txbuf,txbufNew,6);
197 spiPort.transmitReceive_DMA(txbuf, rxbuf_t, 6, this);
198 }
199
200
201}
202
204 bool parity_ok = false;
205
207 uint32_t angle17_10 = rxbuf[1];
208 uint32_t angle9_4 = rxbuf[2];
209 uint32_t angle3_0 = rxbuf[3];
210
211 // Parity check byte 2
212 uint8_t pc1 = angle17_10 ^ angle17_10 >> 1;
213 pc1 = pc1 ^ pc1 >> 2;
214 pc1 = pc1 ^ pc1 >> 4;
215
216 uint8_t pc1_2 = angle9_4 ^ angle9_4 >> 1;
217 pc1_2 = pc1_2 ^ pc1_2 >> 2;
218 pc1_2 = pc1_2 ^ pc1_2 >> 4;
219
220 // Parity check byte 1
221 angle3_0 = angle3_0 >> 2; // shift 2
222 uint8_t pc2 = (angle3_0) ^ (angle3_0) >> 1;
223 pc2 = pc2 ^ pc2 >> 2;
224 pc2 = pc2 ^ pc2 >> 4;
225
226 nomag = (angle9_4 & 0x02) >> 1;
227 overspeed = (angle3_0 & 0x04) >> 2;
228 angle9_4 = (angle9_4 & 0xFC) >> 2;
229 angle3_0 = angle3_0 >> 2;//(angle3_0 & 0xF0) >> 4;
230
231
232 parity_ok = !(pc2 & 1) && ((pc1 & 1) == (pc1_2 & 1));
233
234 curAngleInt = (angle17_10 << 10) | (angle9_4 << 4) | (angle3_0);
235
236 }else if(mode == MtEncoderSPI_mode::mt6835){
237 uint32_t angle20_13 = rxbuf[2];
238 uint32_t angle12_5 = rxbuf[3];
239 uint32_t angle4_0 = (rxbuf[4] & 0xF8) >> 3;
240
241 uint8_t status = rxbuf[4] & 0x7;
242 nomag = (status & 0x02) >> 1;
243 overspeed = (status & 0x01);
244 uint8_t crc = rxbuf[5];
245
246 curAngleInt = (angle20_13 << 13) | (angle12_5 << 5) | (angle4_0);
247 uint8_t calccrc = calculateCrc8(tableCRC, rxbuf+2, 3, 0);
248 parity_ok = calccrc == crc;
249 }
250
251
252 this->updateInProgress = false;
253
254 return parity_ok; // ok if both bytes have even parity
255}
256
258
259 return getPosAbs() - offset;
260}
261
263 if(updateInProgress){ // If a transfer is still in progress return the last result
264 return curPos;
265 }
266 updateInProgress = true;
267 requestNewDataSem.Give(); // Start transfer
268 if(HAL_GetTick() - lastUpdateTick > waitThresh)
269 waitForUpdateSem.Take(waitThresh); // Wait a bit
270
271 return curPos;
272}
273
275 switch(mode){
277 return 262144;
279 return 2097152;
280 default:
281 return 0; // Not possible
282 }
283}
284
286 this->mode = mode;
287 // Reset variables
288 this->curPos = 0;
289 this->curAngleInt = 0;
290 this->lastAngleInt = 0;
291 this->rotations = 0;
292 this->errors = 0;
293 this->nomag = false;
294 this->overspeed = false;
295}
296
297void MtEncoderSPI::setSpiSpeed(uint8_t preset){
298 if(preset == spiSpeedPreset){
299 return; // Ignore if no change
300 }
302 this->spiConfig.peripheral.BaudRatePrescaler = spiPort.getClosestPrescaler(spispeeds[spiSpeedPreset]).first;
303 initSPI();
304}
305
306
307CommandStatus MtEncoderSPI::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
308 switch(static_cast<MtEncoderSPI_commands>(cmd.cmdId)){
310 if(cmd.type==CMDtype::get){
311 replies.emplace_back(this->cspin+1);
312 }else if(cmd.type==CMDtype::set){
313 this->setCsPin(cmd.val-1);
314 }else{
315 return CommandStatus::ERR;
316 }
317 break;
318
320 if(cmd.type==CMDtype::get){
321 replies.emplace_back(getPos());
322 }else if(cmd.type==CMDtype::set){
323 this->setPos(cmd.val);
324 }else{
325 return CommandStatus::ERR;
326 }
327 break;
329 replies.emplace_back(errors);
330 break;
332 if(cmd.type==CMDtype::get){
333 replies.emplace_back((uint8_t)mode);
334 }else if(cmd.type==CMDtype::set){
335 this->setMode((MtEncoderSPI_mode)cmd.val);
336 }else if(cmd.type==CMDtype::info){
337 replies.emplace_back("MT6825:0\nMT6835:1");
338 }else{
339 return CommandStatus::ERR;
340 }
341 break;
342
344 {
345 if(cmd.type == CMDtype::get){
346 replies.emplace_back(spiSpeedPreset);
347 }else if(cmd.type == CMDtype::set){
348 setSpiSpeed(cmd.val);
349 }else if(cmd.type == CMDtype::info){
350 for(uint8_t i = 0; i<spispeeds.size();i++){
351 replies.emplace_back(std::to_string(this->spiPort.getClosestPrescaler(spispeeds[i]).second) + ":" + std::to_string(i)+"\n");
352 }
353 }else{
354 return CommandStatus::ERR;
355 }
356 break;
357 }
359 {
360 if(cmd.type == CMDtype::getat){
361 replies.emplace_back(readSpi(cmd.adr));
362 }else if(cmd.type == CMDtype::setat){
363 writeSpi(cmd.adr, cmd.val);
364 }else{
365 return CommandStatus::ERR;
366 }
367 break;
368 }
370 {
371 if(cmd.type == CMDtype::get){
372 replies.emplace_back(saveEeprom() ? 1 : 0);
373 }
374 break;
375 }
376 default:
378 }
379
380 return CommandStatus::OK;
381}
382
383#endif
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
uint8_t calculateCrc8(std::array< uint8_t, 256 > &crctable, uint8_t *buf, uint16_t len, uint8_t crc=0)
Definition CRC.cpp:13
CommandStatus
uint8_t crc
std::array< uint8_t, 256 > MtEncoderSPI::tableCRC __attribute__((section(".ccmram")))
void registerCommand(const char *cmd, const ID cmdid, const char *help=nullptr, uint32_t flags=0)
CommandHandler(const char *clsname, uint16_t clsid, uint8_t instance=0)
int32_t getPos() override
virtual ~MtEncoderSPI()
MtEncoderSPI_mode mode
uint32_t lastUpdateTick
static const uint32_t waitThresh
bool updateInProgress
uint8_t rxbuf_t[6]
uint8_t rxbuf[6]
uint32_t getCpr() override
cpp_freertos::BinarySemaphore requestNewDataSem
void saveFlash() override
static bool inUse
cpp_freertos::BinarySemaphore waitForUpdateSem
uint8_t readSpi(uint16_t addr)
int32_t getPosAbs() override
const std::array< float, 3 > spispeeds
uint8_t cspin
void setPos(int32_t pos)
const uint8_t POLY
void writeSpi(uint16_t addr, uint8_t data)
int32_t curPos
void setMode(MtEncoderSPI_mode mode)
int32_t curAngleInt
void setSpiSpeed(uint8_t preset)
const ClassIdentifier getInfo()
void restoreFlash() override
uint32_t errors
void updateAngleStatus()
int32_t rotations
int32_t lastAngleInt
void spiTxRxCompleted(SPIPort *port)
int32_t offset
uint8_t spiSpeedPreset
bool updateAngleStatusCb()
void setCsPin(uint8_t cspin)
static ClassIdentifier info
uint8_t txbuf[6]
CommandStatus command(const ParsedCommand &cmd, std::vector< CommandReply > &replies)
static std::array< uint8_t, 256 > tableCRC
SPIPort & spiPort
Definition SPI.h:125
SPIDevice(SPIPort &port, OutputPin csPin)
Definition SPI.cpp:333
SPIConfig spiConfig
Definition SPI.h:126
Definition SPI.h:44
uint32_t WaitForNotification(TickType_t Timeout=portMAX_DELAY)
Definition thread.hpp:246
Thread(const std::string Name, uint16_t StackDepth, UBaseType_t Priority)
Definition cthread.cpp:56
T clip(T v, C l, C h)
Definition cppmain.h:58
static struct @024127060247016123033304002117326322243354210111 data
TVal Flash_ReadDefault(uint16_t adr, TVal def)
bool Flash_Write(uint16_t adr, uint16_t dat)
static void * memcpy(void *dst, const void *src, size_t n)
Definition ringbuffer.c:8