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 = SPI_BAUDRATEPRESCALER_4; // 4 = 10MHz 8 = 5MHz
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
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 this->Start();
44}
45
47 MtEncoderSPI::inUse = false;
48 spiPort.freeCsPin(this->spiConfig.cs);
49}
50
52 uint16_t conf_int = Flash_ReadDefault(ADR_MTENC_CONF1, 0);
53 offset = Flash_ReadDefault(ADR_MTENC_OFS, 0) << 2;
54 uint8_t cspin = conf_int & 0xF;
55 MtEncoderSPI_mode mode = static_cast<MtEncoderSPI_mode>(conf_int >> 8);
58}
59
61 uint16_t conf_int = this->cspin & 0xF;
62 conf_int |= ((uint8_t)mode & 0xf) << 8;
63 Flash_Write(ADR_MTENC_CONF1, conf_int);
64 Flash_Write(ADR_MTENC_OFS, offset >> 2);
65}
66
67
69 while(true){
70 requestNewDataSem.Take(); // Wait until a position is requested
71 //spiPort.receive_DMA(spi_buf, bytes, this); // Receive next frame
73 this->WaitForNotification(); // Wait until DMA is finished
74
76 int overflowLim = getCpr() >> 1;
77 if(curAngleInt-lastAngleInt > overflowLim){ // Underflowed
78 rotations--;
79 }
80 else if(lastAngleInt-curAngleInt > overflowLim){ // Overflowed
81 rotations++;
82 }
84
85 curPos = rotations * getCpr() + curAngleInt; // Update position
86 }else{
87 errors++;
88 }
89 waitForUpdateSem.Give();
90 updateInProgress = false;
91 }
92}
93
95 spiPort.freeCsPin(this->spiConfig.cs);
96 this->cspin = std::min<uint8_t>(spiPort.getCsPins().size(), cspin);
97 this->spiConfig.cs = *spiPort.getCsPin(this->cspin);
98 initSPI();
99 spiPort.reserveCsPin(this->spiConfig.cs);
100}
101
103 spiPort.takeSemaphore();
104
105 spiPort.configurePort(&this->spiConfig.peripheral);
106 spiPort.giveSemaphore();
107}
108
112uint8_t MtEncoderSPI::readSpi(uint16_t addr){
114 uint8_t txbuf[2] = {(uint8_t)(addr | 0x80),0};
115 uint8_t rxbuf[2] = {0,0};
116 spiPort.transmitReceive(txbuf, rxbuf, 2, this,100);
117 }else if(mode == MtEncoderSPI_mode::mt6835){
118 uint8_t txbuf[3] = {(uint8_t)((addr & 0xf00) | 0x30),(uint8_t)(addr & 0xff),0};
119 uint8_t rxbuf[3] = {0,0,0};
120 spiPort.transmitReceive(txbuf, rxbuf, 3, this,100);
121 }
122
123 return rxbuf[1];
124}
125
126void MtEncoderSPI::writeSpi(uint16_t addr,uint8_t data){
128 uint8_t txbuf[2] = {(uint8_t)(addr & 0xff),data};
129 spiPort.transmit(txbuf, 2, this,100);
130 }else if(mode == MtEncoderSPI_mode::mt6835){
131 uint8_t txbuf[3] = {(uint8_t)((addr & 0xf00) | 0x60),(uint8_t)(addr & 0xff),data};
132 spiPort.transmit(txbuf, 3, this,100);
133 }
134
135}
136
138 offset = curPos - pos;
139}
140
141
143
146 //updateAngleStatusCb();
147 memcpy(rxbuf,rxbuf_t,sizeof(rxbuf));
148 }
149}
150
151
156
157
158
160 uint8_t txbufNew[5] = {0x03 | 0x80,0,0,0,0};
161 memcpy(this->txbuf,txbufNew,5);
162 spiPort.transmitReceive_DMA(txbuf, rxbuf_t, 4, this);
163 }else if(mode == MtEncoderSPI_mode::mt6835){
164 uint8_t txbufNew[6] = {0xA0,0x03,0,0,0,0};
165 memcpy(this->txbuf,txbufNew,6);
166 spiPort.transmitReceive_DMA(txbuf, rxbuf_t, 6, this);
167 }
168
169
170}
171
173 bool parity_ok = false;
174
176 uint32_t angle17_10 = rxbuf[1];
177 uint32_t angle9_4 = rxbuf[2];
178 uint32_t angle3_0 = rxbuf[3];
179
180 // Parity check byte 2
181 uint8_t pc1 = angle17_10 ^ angle17_10 >> 1;
182 pc1 = pc1 ^ pc1 >> 2;
183 pc1 = pc1 ^ pc1 >> 4;
184
185 uint8_t pc1_2 = angle9_4 ^ angle9_4 >> 1;
186 pc1_2 = pc1_2 ^ pc1_2 >> 2;
187 pc1_2 = pc1_2 ^ pc1_2 >> 4;
188
189 // Parity check byte 1
190 angle3_0 = angle3_0 >> 2; // shift 2
191 uint8_t pc2 = (angle3_0) ^ (angle3_0) >> 1;
192 pc2 = pc2 ^ pc2 >> 2;
193 pc2 = pc2 ^ pc2 >> 4;
194
195 nomag = (angle9_4 & 0x02) >> 1;
196 overspeed = (angle3_0 & 0x04) >> 2;
197 angle9_4 = (angle9_4 & 0xFC) >> 2;
198 angle3_0 = angle3_0 >> 2;//(angle3_0 & 0xF0) >> 4;
199
200
201 parity_ok = !(pc2 & 1) && ((pc1 & 1) == (pc1_2 & 1));
202
203 curAngleInt = (angle17_10 << 10) | (angle9_4 << 4) | (angle3_0);
204
205 }else if(mode == MtEncoderSPI_mode::mt6835){
206 uint32_t angle20_13 = rxbuf[2];
207 uint32_t angle12_5 = rxbuf[3];
208 uint32_t angle4_0 = (rxbuf[4] & 0xF8) >> 3;
209
210 uint8_t status = rxbuf[4] & 0x7;
211 nomag = (status & 0x02) >> 1;
212 overspeed = (status & 0x01);
213 uint8_t crc = rxbuf[5];
214
215 curAngleInt = (angle20_13 << 13) | (angle12_5 << 5) | (angle4_0);
216 uint8_t calccrc = calculateCrc8(tableCRC, rxbuf+2, 3, 0);
217 parity_ok = calccrc == crc;
218 }
219
220
221 this->updateInProgress = false;
222
223 return parity_ok; // ok if both bytes have even parity
224}
225
227
228 return getPosAbs() - offset;
229}
230
232 if(updateInProgress){ // If a transfer is still in progress return the last result
233 return curPos;
234 }
235 updateInProgress = true;
236 requestNewDataSem.Give(); // Start transfer
237 waitForUpdateSem.Take(10); // Wait a bit
238
239 return curPos;
240}
241
243 switch(mode){
245 return 262144;
247 return 2097152;
248 default:
249 return 0; // Not possible
250 }
251}
252
254 this->mode = mode;
255 // Reset variables
256 this->curPos = 0;
257 this->curAngleInt = 0;
258 this->lastAngleInt = 0;
259 this->rotations = 0;
260 this->errors = 0;
261 this->nomag = false;
262 this->overspeed = false;
263}
264
265
266CommandStatus MtEncoderSPI::command(const ParsedCommand& cmd,std::vector<CommandReply>& replies){
267 switch(static_cast<MtEncoderSPI_commands>(cmd.cmdId)){
269 if(cmd.type==CMDtype::get){
270 replies.emplace_back(this->cspin+1);
271 }else if(cmd.type==CMDtype::set){
272 this->setCsPin(cmd.val-1);
273 }else{
274 return CommandStatus::ERR;
275 }
276 break;
277
279 if(cmd.type==CMDtype::get){
280 replies.emplace_back(getPos());
281 }else if(cmd.type==CMDtype::set){
282 this->setPos(cmd.val);
283 }else{
284 return CommandStatus::ERR;
285 }
286 break;
288 replies.emplace_back(errors);
289 break;
291 if(cmd.type==CMDtype::get){
292 replies.emplace_back((uint8_t)mode);
293 }else if(cmd.type==CMDtype::set){
294 this->setMode((MtEncoderSPI_mode)cmd.val);
295 }else if(cmd.type==CMDtype::info){
296 replies.emplace_back("MT6825:0\nMT6835:1");
297 }else{
298 return CommandStatus::ERR;
299 }
300 break;
301 default:
303 }
304
305 return CommandStatus::OK;
306}
307
308#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
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
const ClassIdentifier getInfo()
void restoreFlash() override
uint32_t errors
void updateAngleStatus()
int32_t rotations
int32_t lastAngleInt
void spiTxRxCompleted(SPIPort *port)
int32_t offset
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
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