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 uint16_t conf_int = Flash_ReadDefault(ADR_MTENC_CONF1, 0);
56 offset = Flash_ReadDefault(ADR_MTENC_OFS, 0) << 2;
57 uint8_t cspin = conf_int & 0x3;
58 MtEncoderSPI_mode mode = static_cast<MtEncoderSPI_mode>(conf_int >> 8);
61 setSpiSpeed((conf_int >> 2) & 0x3);
62}
63
65 uint16_t conf_int = this->cspin & 0x3;
66 conf_int |= (this->spiSpeedPreset & 0x3) << 2;
67 conf_int |= ((uint8_t)mode & 0xf) << 8;
68 Flash_Write(ADR_MTENC_CONF1, conf_int);
69 Flash_Write(ADR_MTENC_OFS, offset >> 2);
70}
71
72
74 while(true){
75 requestNewDataSem.Take(); // Wait until a position is requested
76 //spiPort.receive_DMA(spi_buf, bytes, this); // Receive next frame
78 this->WaitForNotification(); // Wait until DMA is finished
79
81 int overflowLim = getCpr() >> 1;
82 if(curAngleInt-lastAngleInt > overflowLim){ // Underflowed
83 rotations--;
84 }
85 else if(lastAngleInt-curAngleInt > overflowLim){ // Overflowed
86 rotations++;
87 }
89
90 curPos = rotations * getCpr() + curAngleInt; // Update position
91 }else{
92 errors++;
93 }
94 waitForUpdateSem.Give();
95 updateInProgress = false;
96 }
97}
98
100 spiPort.freeCsPin(this->spiConfig.cs);
101 this->cspin = std::min<uint8_t>(spiPort.getCsPins().size(), cspin);
102 this->spiConfig.cs = *spiPort.getCsPin(this->cspin);
103 initSPI();
104 spiPort.reserveCsPin(this->spiConfig.cs);
105}
106
108 spiPort.takeSemaphore();
109
110 spiPort.configurePort(&this->spiConfig.peripheral);
111 spiPort.giveSemaphore();
112}
113
117uint8_t MtEncoderSPI::readSpi(uint16_t addr){
119 uint8_t txbuf[2] = {(uint8_t)(addr | 0x80),0};
120 uint8_t rxbuf[2] = {0,0};
121 spiPort.transmitReceive(txbuf, rxbuf, 2, this,100);
122 return rxbuf[1];
123 }else if(mode == MtEncoderSPI_mode::mt6835){
124 uint8_t txbuf[3] = {(uint8_t)((addr & 0xf00) | 0x30),(uint8_t)(addr & 0xff),0};
125 uint8_t rxbuf[3] = {0,0,0};
126 spiPort.transmitReceive(txbuf, rxbuf, 3, this,100);
127 return rxbuf[2];
128 }
129}
130
131void MtEncoderSPI::writeSpi(uint16_t addr,uint8_t data){
133 uint8_t txbuf[2] = {(uint8_t)(addr & 0xff),data};
134 spiPort.transmit(txbuf, 2, this,100);
135 }else if(mode == MtEncoderSPI_mode::mt6835){
136 uint8_t txbuf[3] = {(uint8_t)((addr & 0xf00) | 0x60),(uint8_t)(addr & 0xff),data};
137 spiPort.transmit(txbuf, 3, this,100);
138 }
139
140}
141
147 return false;
148 }
150 uint8_t txbuf[3] = {0xC0,0x00,0x00};
151 uint8_t rxbuf[3] = {0,0,0};
152 spiPort.transmitReceive(txbuf, rxbuf, 3, this,100);
153 return rxbuf[2] == 0x55;
154 }
155 return false;
156}
157
159 offset = curPos - pos;
160}
161
162
164
167 //updateAngleStatusCb();
168 memcpy(rxbuf,rxbuf_t,sizeof(rxbuf));
169 }
170}
171
172
177
179 uint8_t txbufNew[5] = {0x03 | 0x80,0,0,0,0};
180 memcpy(this->txbuf,txbufNew,5);
181 spiPort.transmitReceive_DMA(txbuf, rxbuf_t, 4, this);
182 }else if(mode == MtEncoderSPI_mode::mt6835){
183 uint8_t txbufNew[6] = {0xA0,0x03,0,0,0,0};
184 memcpy(this->txbuf,txbufNew,6);
185 spiPort.transmitReceive_DMA(txbuf, rxbuf_t, 6, this);
186 }
187
188
189}
190
192 bool parity_ok = false;
193
195 uint32_t angle17_10 = rxbuf[1];
196 uint32_t angle9_4 = rxbuf[2];
197 uint32_t angle3_0 = rxbuf[3];
198
199 // Parity check byte 2
200 uint8_t pc1 = angle17_10 ^ angle17_10 >> 1;
201 pc1 = pc1 ^ pc1 >> 2;
202 pc1 = pc1 ^ pc1 >> 4;
203
204 uint8_t pc1_2 = angle9_4 ^ angle9_4 >> 1;
205 pc1_2 = pc1_2 ^ pc1_2 >> 2;
206 pc1_2 = pc1_2 ^ pc1_2 >> 4;
207
208 // Parity check byte 1
209 angle3_0 = angle3_0 >> 2; // shift 2
210 uint8_t pc2 = (angle3_0) ^ (angle3_0) >> 1;
211 pc2 = pc2 ^ pc2 >> 2;
212 pc2 = pc2 ^ pc2 >> 4;
213
214 nomag = (angle9_4 & 0x02) >> 1;
215 overspeed = (angle3_0 & 0x04) >> 2;
216 angle9_4 = (angle9_4 & 0xFC) >> 2;
217 angle3_0 = angle3_0 >> 2;//(angle3_0 & 0xF0) >> 4;
218
219
220 parity_ok = !(pc2 & 1) && ((pc1 & 1) == (pc1_2 & 1));
221
222 curAngleInt = (angle17_10 << 10) | (angle9_4 << 4) | (angle3_0);
223
224 }else if(mode == MtEncoderSPI_mode::mt6835){
225 uint32_t angle20_13 = rxbuf[2];
226 uint32_t angle12_5 = rxbuf[3];
227 uint32_t angle4_0 = (rxbuf[4] & 0xF8) >> 3;
228
229 uint8_t status = rxbuf[4] & 0x7;
230 nomag = (status & 0x02) >> 1;
231 overspeed = (status & 0x01);
232 uint8_t crc = rxbuf[5];
233
234 curAngleInt = (angle20_13 << 13) | (angle12_5 << 5) | (angle4_0);
235 uint8_t calccrc = calculateCrc8(tableCRC, rxbuf+2, 3, 0);
236 parity_ok = calccrc == crc;
237 }
238
239
240 this->updateInProgress = false;
241
242 return parity_ok; // ok if both bytes have even parity
243}
244
246
247 return getPosAbs() - offset;
248}
249
251 if(updateInProgress){ // If a transfer is still in progress return the last result
252 return curPos;
253 }
254 updateInProgress = true;
255 requestNewDataSem.Give(); // Start transfer
256 waitForUpdateSem.Take(10); // Wait a bit
257
258 return curPos;
259}
260
262 switch(mode){
264 return 262144;
266 return 2097152;
267 default:
268 return 0; // Not possible
269 }
270}
271
273 this->mode = mode;
274 // Reset variables
275 this->curPos = 0;
276 this->curAngleInt = 0;
277 this->lastAngleInt = 0;
278 this->rotations = 0;
279 this->errors = 0;
280 this->nomag = false;
281 this->overspeed = false;
282}
283
284void MtEncoderSPI::setSpiSpeed(uint8_t preset){
285 if(preset == spiSpeedPreset){
286 return; // Ignore if no change
287 }
289 this->spiConfig.peripheral.BaudRatePrescaler = spiPort.getClosestPrescaler(spispeeds[spiSpeedPreset]).first;
290 initSPI();
291}
292
293
294CommandStatus MtEncoderSPI::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
295 switch(static_cast<MtEncoderSPI_commands>(cmd.cmdId)){
297 if(cmd.type==CMDtype::get){
298 replies.emplace_back(this->cspin+1);
299 }else if(cmd.type==CMDtype::set){
300 this->setCsPin(cmd.val-1);
301 }else{
302 return CommandStatus::ERR;
303 }
304 break;
305
307 if(cmd.type==CMDtype::get){
308 replies.emplace_back(getPos());
309 }else if(cmd.type==CMDtype::set){
310 this->setPos(cmd.val);
311 }else{
312 return CommandStatus::ERR;
313 }
314 break;
316 replies.emplace_back(errors);
317 break;
319 if(cmd.type==CMDtype::get){
320 replies.emplace_back((uint8_t)mode);
321 }else if(cmd.type==CMDtype::set){
322 this->setMode((MtEncoderSPI_mode)cmd.val);
323 }else if(cmd.type==CMDtype::info){
324 replies.emplace_back("MT6825:0\nMT6835:1");
325 }else{
326 return CommandStatus::ERR;
327 }
328 break;
329
331 {
332 if(cmd.type == CMDtype::get){
333 replies.emplace_back(spiSpeedPreset);
334 }else if(cmd.type == CMDtype::set){
335 setSpiSpeed(cmd.val);
336 }else if(cmd.type == CMDtype::info){
337 for(uint8_t i = 0; i<spispeeds.size();i++){
338 replies.emplace_back(std::to_string(this->spiPort.getClosestPrescaler(spispeeds[i]).second) + ":" + std::to_string(i)+"\n");
339 }
340 }else{
341 return CommandStatus::ERR;
342 }
343 break;
344 }
346 {
347 if(cmd.type == CMDtype::getat){
348 replies.emplace_back(readSpi(cmd.adr));
349 }else if(cmd.type == CMDtype::setat){
350 writeSpi(cmd.adr, cmd.val);
351 }else{
352 return CommandStatus::ERR;
353 }
354 break;
355 }
357 {
358 if(cmd.type == CMDtype::get){
359 replies.emplace_back(saveEeprom() ? 1 : 0);
360 }
361 break;
362 }
363 default:
365 }
366
367 return CommandStatus::OK;
368}
369
370#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
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:124
SPIDevice(SPIPort &port, OutputPin csPin)
Definition SPI.cpp:332
SPIConfig spiConfig
Definition SPI.h:125
Definition SPI.h:43
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