Skyward boardcore
Loading...
Searching...
No Matches
VN100Spi.cpp
Go to the documentation of this file.
1/* Copyright (c) 2024 Skyward Experimental Rocketry
2 * Author: Fabrizio Monti
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "VN100Spi.h"
24
26#include <interfaces/endianness.h>
27#include <utils/Debug.h>
28
29namespace Boardcore
30{
31
32VN100Spi::VN100Spi(SPIBus& bus, miosix::GpioPin csPin,
33 SPIBusConfig busConfiguration, uint16_t syncOutSkipFactor)
34 : spiSlave(bus, csPin, busConfiguration),
35 syncOutSkipFactor(syncOutSkipFactor)
36{
37}
38
40{
41 if (isInit)
42 {
43 LOG_ERR(logger, "init() should be called once");
45 return false;
46 }
47
48 // First communication after startup might fail
49 // Send dummy data to clean up
50 sendDummyPacket();
51
52 if (!checkModelNumber())
53 {
54 LOG_ERR(logger, "Got bad CHIPID");
56 return false;
57 }
58
59 miosix::delayUs(100);
60
61 if (!setInterrupt())
62 {
63 LOG_ERR(logger, "Unable to set data ready interrupt");
65 return false;
66 }
67
68 // Wait to ensure that enough time has passed before the next operation
69 miosix::delayUs(100);
70
71 isInit = true;
73 return true;
74}
75
76bool VN100Spi::checkModelNumber()
77{
78 int i = 0;
80 for (i = 0; i < VN100SpiDefs::MODEL_NUMBER_SIZE; ++i)
81 buf[i] = 0;
82
84 reinterpret_cast<uint8_t*>(buf),
87 {
88 // An error occurred while attempting to service the request
89 LOG_ERR(logger, "Error while reading CHIPID");
90 TRACE("Error code: %u\n", err);
91 return false;
92 }
93
94 // Check the model number
95 if (strncmp(VN100SpiDefs::MODEL_NUMBER, buf,
96 strlen(VN100SpiDefs::MODEL_NUMBER)) != 0)
97 {
98 LOG_ERR(logger, "Error, invalid CHIPID");
99 TRACE("%s != %s\n", VN100SpiDefs::MODEL_NUMBER, buf);
100 return false;
101 }
102
103 return true;
104}
105
106void VN100Spi::sendDummyPacket()
107{
108 SPITransaction transaction(spiSlave);
109 transaction.write32(0);
110
117 miosix::Thread::sleep(1);
118}
119
120bool VN100Spi::setInterrupt()
121{
139 // Init struct and set default values
140 VN100SpiDefs::SynchronizationData sData;
141 sData.syncInMode = 3; // Set to: count number of trigger events on SYNC_IN.
142 sData.syncInEdge = 0; // Trigger on rising edge
143 sData.syncInSkipFactor = 0; // Don't skip
144
145 // Set needed values
146 sData.syncOutMode = 3; // Trigger when attitude measurements are available
147 sData.syncOutPolarity = 1; // Positive output pulse on the SyncOut pin
148 sData.syncOutSkipFactor = syncOutSkipFactor;
149 sData.syncOutPulseWidth = VN100SpiDefs::SYNC_OUT_PULSE_WIDTH;
150
151 VN100SpiDefs::VNErrors err = writeRegister(
152 VN100SpiDefs::REG_SYNC, reinterpret_cast<uint8_t*>(&sData),
153 sizeof(VN100SpiDefs::SynchronizationData));
154
156 {
157 TRACE("setInterrupt() failed, error: %u\n", err);
158 return false;
159 }
160
161 return true;
162}
163
164bool VN100Spi::selfTest() { return true; }
165
167{
168 D(assert(isInit && "init() was not called"));
169
170 // Reset any errors.
172
173 VN100SpiData data;
178
179 if (!getSample(data))
180 {
181 // An error occurred while gathering data
183 return lastSample;
184 }
185
186 return data;
187}
188
189bool VN100Spi::getSample(VN100SpiData& data)
190{
191 VN100SpiDefs::RawImuQuatData rawData;
192
195 reinterpret_cast<uint8_t*>(&rawData), sizeof(rawData));
196
198 {
199 // An error occurred while reading data
200 TRACE("getSample() failed, error: %u\n", err);
201 return false;
202 }
203
204 // Get measurements from raw data
205 data.quaternionX = rawData.quatX;
206 data.quaternionY = rawData.quatY;
207 data.quaternionZ = rawData.quatZ;
208 data.quaternionW = rawData.quatW;
209 data.magneticFieldX = rawData.magX;
210 data.magneticFieldY = rawData.magY;
211 data.magneticFieldZ = rawData.magZ;
212 data.accelerationX = rawData.accX;
213 data.accelerationY = rawData.accY;
214 data.accelerationZ = rawData.accZ;
215 data.angularSpeedX = rawData.gyrX;
216 data.angularSpeedY = rawData.gyrY;
217 data.angularSpeedZ = rawData.gyrZ;
218
219 return true;
220}
221
223{
224 TemperatureData data;
225
226 VN100SpiDefs::RawTempPressData rawData;
227
228 // Get timestamp
230
233 reinterpret_cast<uint8_t*>(&rawData), sizeof(rawData));
234
236 {
237 // An error occurred while reading data
238 TRACE("getTemperature() failed, error: %u\n", err);
239 return data;
240 }
241
242 // Get measurement from raw data
243 data.temperature = rawData.temp;
244
245 return data;
246}
247
249{
250 PressureData data;
251
252 VN100SpiDefs::RawTempPressData rawData;
253
254 // Get timestamp
256
259 reinterpret_cast<uint8_t*>(&rawData), sizeof(rawData));
260
262 {
263 // An error occurred while reading data
264 TRACE("getPressure() failed, error: %u\n", err);
265 return data;
266 }
267
268 // Get measurement from raw data
269 data.pressure = rawData.press;
270
271 return data;
272}
273
274VN100SpiDefs::VNErrors VN100Spi::readRegister(const uint8_t regId,
275 uint8_t* payloadBuf,
276 const uint32_t payloadSize)
277{
295 const uint32_t requestPacket =
296 (VN100SpiDefs::READ_REG << 24) | // Read register command
297 (regId << 16); // Id of the register
298
299 // Send request packet
300 spiSlave.bus.select(spiSlave.cs);
301 spiSlave.bus.write32(requestPacket);
302 spiSlave.bus.deselect(spiSlave.cs);
303
304 // Wait at least 100us
305 miosix::delayUs(100);
306
307 // Read response
308 spiSlave.bus.select(spiSlave.cs);
309
310 // Discard the first 3 bytes of the response
312 (VN100SpiDefs::VNErrors)(spiSlave.bus.read32() & 255);
313
315 {
316 // An error occurred while attempting to service the request
317 spiSlave.bus.deselect(spiSlave.cs);
318 return err;
319 }
320
321 spiSlave.bus.read(payloadBuf, payloadSize);
322
323 spiSlave.bus.deselect(spiSlave.cs);
324
326}
327
328VN100SpiDefs::VNErrors VN100Spi::writeRegister(const uint8_t regId,
329 const uint8_t* payloadBuf,
330 const uint32_t payloadSize)
331{
349 const uint32_t requestPacket =
350 (VN100SpiDefs::WRITE_REG << 24) | // Read register command
351 (regId << 16); // Id of the register
352
353 // Send request packet
354 spiSlave.bus.select(spiSlave.cs);
355 spiSlave.bus.write32(requestPacket);
356 spiSlave.bus.write(payloadBuf, payloadSize);
357 spiSlave.bus.deselect(spiSlave.cs);
358
359 // Wait at least 100us
360 miosix::delayUs(100);
361
362 // Read response
363 spiSlave.bus.select(spiSlave.cs);
364
365 // Discard the first 3 bytes of the response
366 uint8_t err = spiSlave.bus.read32() & 255;
367
368 spiSlave.bus.deselect(spiSlave.cs);
369
370 return (VN100SpiDefs::VNErrors)err;
371}
372
373} // namespace Boardcore
#define TRACE(...)
Definition Debug.h:58
#define D(x)
Definition Debug.h:57
#define LOG_ERR(logger,...)
SensorErrors lastError
Definition Sensor.h:54
Driver for STM32 low level SPI peripheral.
Definition SPIBus.h:61
virtual void write32(uint32_t data)=0
Writes 32 bits to the bus.
virtual void deselect(GpioType cs)=0
Deselects the slave.
virtual uint8_t read()=0
Reads 8 bits from the bus.
virtual void select(GpioType cs)=0
Selects the slave.
virtual uint32_t read32()=0
Reads 32 bits from the bus.
virtual void write(uint8_t data)=0
Writes 8 bits to the bus.
bool selfTest() override
Performs self test for the sensor.
Definition VN100Spi.cpp:164
VN100Spi(SPIBus &bus, miosix::GpioPin csPin, SPIBusConfig busConfiguration, uint16_t syncOutSkipFactor)
VN100 constructor.
Definition VN100Spi.cpp:32
PressureData getPressure()
Retrieve pressure data from the sensor [kPa].
Definition VN100Spi.cpp:248
VN100SpiData sampleImpl() override
Gather data from the sensor.
Definition VN100Spi.cpp:166
bool init() override
Initialize the sensor.
Definition VN100Spi.cpp:39
TemperatureData getTemperature()
Retrieve temperature data from the sensor [°C].
Definition VN100Spi.cpp:222
uint64_t getTimestamp()
Returns the current timer value in microseconds.
const char *const MODEL_NUMBER
The expected model number to be red from the sensor.
@ REG_MODEL_NUMBER
WhoAmI register.
@ REG_SYNC
Used to set data ready interrupt.
@ REG_TEMP_PRESS_DATA
Temperature and pressure data register.
const int MODEL_NUMBER_SIZE
Size of the buffer used to retrieve the model number from the sensor. It corresponds to the size of t...
VNErrors
Error codes of the sensor.
const uint32_t SYNC_OUT_PULSE_WIDTH
Width of the SyncOut pulse in nanoseconds. Now is set to 1 millisecond.
This file includes all the types the logdecoder script will decode.
@ INVALID_WHOAMI
Definition SensorData.h:40
SPI Bus configuration for a specific slave.
GpioType cs
Chip select pin.
SPIBusInterface & bus
Bus on which the slave is connected.
Data type class for VN100 Spi.