STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
board_spi.c
Go to the documentation of this file.
1#include "board_spi.h"
2
3#include <string.h>
4
5#include "board.h"
6#include "cmsis_os2.h"
7#include "main.h"
8
13
14typedef struct {
17 uint16_t cs_pin;
18 GPIO_TypeDef* busy_port; /* SX1262 only: commands wait for BUSY low */
19 uint16_t busy_pin;
21
22/* Pin names come from the .ioc labels (main.h). A device with spi == NULL is
23 * not routed yet and every call on it returns NOT_CONFIGURED. */
33
34/* One lock per SPI peripheral, indexed SPI1..SPI4. */
36
37static int bus_index(const SPI_HandleTypeDef* spi) {
38 if (spi == &hspi1)
39 return 0;
40 if (spi == &hspi2)
41 return 1;
42 if (spi == &hspi3)
43 return 2;
44 if (spi == &hspi4)
45 return 3;
46 return -1;
47}
48
50 if ((unsigned)device >= BOARD_SPI_COUNT || !routes[device].spi) {
51 return NULL;
52 }
53 return &routes[device];
54}
55
56bool board_spi_init(void) {
57 static const osMutexAttr_t attr = {"spi_bus", osMutexPrioInherit, NULL, 0};
58 for (int i = 0; i < 4; ++i) {
59 if (!bus_locks[i]) {
60 bus_locks[i] = osMutexNew(&attr);
61 if (!bus_locks[i]) {
62 return false;
63 }
64 }
65 }
66 return true;
67}
68
70 return route(device);
71}
72
74 const board_spi_route_t* r = route(device);
75 if (!r)
76 return 0;
77 uint8_t cpol = r->spi->Init.CLKPolarity == SPI_POLARITY_HIGH ? 2U : 0U;
78 uint8_t cpha = r->spi->Init.CLKPhase == SPI_PHASE_2EDGE ? 1U : 0U;
79 return (uint8_t)(cpol | cpha);
80}
81
83 const board_spi_route_t* r = route(device);
84 if (!r)
85 return 0;
86 uint32_t kernel = HAL_RCCEx_GetPeriphCLKFreq(
88 /* H7 SPI_CFG1_MBR: prescaler code n divides by 2^(n+1). */
89 uint32_t code =
90 (r->spi->Init.BaudRatePrescaler & SPI_CFG1_MBR) >> SPI_CFG1_MBR_Pos;
91 return kernel >> (code + 1U);
92}
93
95 uint32_t deadline_ms) {
96 const board_spi_route_t* r = route(device);
97 if (!r)
100 if (!lock)
102 /* 1 kHz tick: ticks == ms. */
103 return osMutexAcquire(lock, board_ms_left(deadline_ms)) == osOK
106}
107
109 const board_spi_route_t* r = route(device);
110 if (r && bus_locks[bus_index(r->spi)]) {
112 }
113}
114
116 uint32_t deadline_ms) {
117 if (!r->busy_port)
118 return BOARD_SPI_OK;
119 while (HAL_GPIO_ReadPin(r->busy_port, r->busy_pin) == GPIO_PIN_SET) {
120 if (board_deadline_passed(deadline_ms))
121 return BOARD_SPI_TIMEOUT;
122 }
123 return BOARD_SPI_OK;
124}
125
126/* Full-duplex transfer in chunks so tx/rx may be NULL without a len-sized
127 * buffer. CS is not touched here. */
128static board_spi_status_t shift(const board_spi_route_t* r, const uint8_t* tx,
129 uint8_t* rx, uint16_t len,
130 uint32_t deadline_ms) {
131 static uint8_t ones[16];
132 static uint8_t sink[16];
133 memset(ones, 0xFF, sizeof(ones));
134 while (len) {
135 uint16_t n = len;
136 const uint8_t* out = tx;
137 uint8_t* in = rx;
138 if (!tx || !rx) {
139 n = n > sizeof(ones) ? (uint16_t)sizeof(ones) : n;
140 if (!tx)
141 out = ones;
142 if (!rx)
143 in = sink;
144 }
145 uint32_t left = board_ms_left(deadline_ms);
146 if (!left)
147 return BOARD_SPI_TIMEOUT;
149 HAL_SPI_TransmitReceive(r->spi, (uint8_t*)out, in, n, left);
150 if (st == HAL_TIMEOUT)
151 return BOARD_SPI_TIMEOUT;
152 if (st != HAL_OK)
153 return BOARD_SPI_ERROR;
154 len = (uint16_t)(len - n);
155 if (tx)
156 tx += n;
157 if (rx)
158 rx += n;
159 }
160 return BOARD_SPI_OK;
161}
162
164 uint8_t* rx, uint16_t len,
165 uint32_t deadline_ms) {
166 const board_spi_route_t* r = route(device);
167 if (!r)
169 board_spi_status_t st = wait_busy_low(r, deadline_ms);
170 if (st != BOARD_SPI_OK)
171 return st;
172 HAL_GPIO_WritePin(r->cs_port, r->cs_pin, GPIO_PIN_RESET);
173 st = shift(r, tx, rx, len, deadline_ms);
174 HAL_GPIO_WritePin(r->cs_port, r->cs_pin, GPIO_PIN_SET);
175 return st;
176}
177
179 const uint8_t* tx, uint8_t* rx,
180 uint16_t len, uint32_t deadline_ms) {
181 board_spi_status_t st = board_spi_lock(device, deadline_ms);
182 if (st != BOARD_SPI_OK)
183 return st;
184 st = board_spi_frame(device, tx, rx, len, deadline_ms);
185 board_spi_unlock(device);
186 return st;
187}
188
190 const board_spi_route_t* r = route(device);
191 if (r)
192 HAL_GPIO_WritePin(r->cs_port, r->cs_pin, GPIO_PIN_RESET);
193}
194
196 const board_spi_route_t* r = route(device);
197 if (r)
198 HAL_GPIO_WritePin(r->cs_port, r->cs_pin, GPIO_PIN_SET);
199}
200
202 uint8_t* rx, uint16_t len,
203 uint32_t deadline_ms) {
204 const board_spi_route_t* r = route(device);
205 if (!r)
207 return shift(r, tx, rx, len, deadline_ms);
208}
209
211 uint16_t len, uint32_t deadline_ms) {
212 const board_spi_route_t* r = route(device);
213 if (!r)
215 HAL_GPIO_WritePin(r->cs_port, r->cs_pin, GPIO_PIN_SET);
216 return shift(r, NULL, NULL, len, deadline_ms);
217}
218
219/* ---- self-test adapter ------------------------------------------------- */
220
221static board_spi_device_t from_self_test(uint16_t device_id) {
222 switch (device_id) {
224 return BOARD_SPI_IMU;
226 return BOARD_SPI_HIGH_G;
228 return BOARD_SPI_BARO;
230 return BOARD_SPI_ETH;
232 return BOARD_SPI_RADIO;
233 default:
234 return BOARD_SPI_COUNT;
235 }
236}
237
239 self_test_reply_t r = {result, diag};
240 return r;
241}
242
244 void* context, uint16_t device_id, uint8_t mode, uint32_t max_hz,
245 self_test_spi_frame_t* frames, uint8_t count, uint32_t budget_ms) {
246 (void)context;
247 board_spi_device_t device = from_self_test(device_id);
248 if (!board_spi_routed(device) || !frames) {
250 }
251 /* Never talk to a chip with the wrong clock polarity/phase or too fast
252 * a clock: the bus is configured once, in the .ioc. */
253 if (board_spi_mode(device) != mode || board_spi_clock_hz(device) > max_hz) {
255 }
256 uint32_t deadline = board_now_ms() + budget_ms;
257 board_spi_status_t st = board_spi_lock(device, deadline);
258 if (st != BOARD_SPI_OK) {
261 0);
262 }
263 /* Locked from here: every path below must unlock. */
264 for (uint8_t i = 0; st == BOARD_SPI_OK && i < count; ++i) {
265 st = board_spi_frame(device, frames[i].tx, frames[i].rx,
266 frames[i].length, deadline);
267 }
268 board_spi_unlock(device);
269 switch (st) {
270 case BOARD_SPI_OK:
271 return st_reply(SELF_TEST_PASS, 0);
273 return st_reply(SELF_TEST_TIMEOUT, 0);
276 default:
277 return st_reply(SELF_TEST_FAIL, 0);
278 }
279}
#define IMU_CS_GPIO_Port
Definition main.h:180
#define ETH_CS_GPIO_Port
Definition main.h:121
#define RADIO_BUSY_GPIO_Port
Definition main.h:106
#define BARO_CS_Pin
Definition main.h:175
#define ACCEL_CS_GPIO_Port
Definition main.h:178
#define ACCEL_CS_Pin
Definition main.h:177
#define BARO_CS_GPIO_Port
Definition main.h:176
#define RADIO_BUSY_Pin
Definition main.h:105
#define NAND_CS_GPIO_Port
Definition main.h:68
#define RADIO_CS_Pin
Definition main.h:103
#define IMU_CS_Pin
Definition main.h:179
#define NAND_CS_Pin
Definition main.h:67
#define RADIO_CS_GPIO_Port
Definition main.h:104
#define ETH_CS_Pin
Definition main.h:120
uint32_t board_now_ms(void)
Definition board.c:24
static bool board_deadline_passed(uint32_t deadline_ms)
Definition board.h:42
static uint32_t board_ms_left(uint32_t deadline_ms)
Definition board.h:47
static route_t routes[]
Definition board_exti.c:13
board_spi_status_t board_spi_idle_clocks(board_spi_device_t device, uint16_t len, uint32_t deadline_ms)
Definition board_spi.c:210
self_test_reply_t board_spi_self_test_exchange(void *context, uint16_t device_id, uint8_t mode, uint32_t max_hz, self_test_spi_frame_t *frames, uint8_t count, uint32_t budget_ms)
Definition board_spi.c:243
static board_spi_device_t from_self_test(uint16_t device_id)
Definition board_spi.c:221
static osMutexId_t bus_locks[4]
Definition board_spi.c:35
bool board_spi_init(void)
Definition board_spi.c:56
static int bus_index(const SPI_HandleTypeDef *spi)
Definition board_spi.c:37
board_spi_status_t board_spi_frame(board_spi_device_t device, const uint8_t *tx, uint8_t *rx, uint16_t len, uint32_t deadline_ms)
Definition board_spi.c:163
void board_spi_deselect(board_spi_device_t device)
Definition board_spi.c:195
board_spi_status_t board_spi_lock(board_spi_device_t device, uint32_t deadline_ms)
Definition board_spi.c:94
board_spi_status_t board_spi_transfer(board_spi_device_t device, const uint8_t *tx, uint8_t *rx, uint16_t len, uint32_t deadline_ms)
Definition board_spi.c:178
void board_spi_unlock(board_spi_device_t device)
Definition board_spi.c:108
bool board_spi_routed(board_spi_device_t device)
Definition board_spi.c:69
static const board_spi_route_t * route(board_spi_device_t device)
Definition board_spi.c:49
board_spi_status_t board_spi_shift(board_spi_device_t device, const uint8_t *tx, uint8_t *rx, uint16_t len, uint32_t deadline_ms)
Definition board_spi.c:201
static board_spi_status_t wait_busy_low(const board_spi_route_t *r, uint32_t deadline_ms)
Definition board_spi.c:115
uint32_t board_spi_clock_hz(board_spi_device_t device)
Definition board_spi.c:82
uint8_t board_spi_mode(board_spi_device_t device)
Definition board_spi.c:73
static board_spi_status_t shift(const board_spi_route_t *r, const uint8_t *tx, uint8_t *rx, uint16_t len, uint32_t deadline_ms)
Definition board_spi.c:128
void board_spi_select(board_spi_device_t device)
Definition board_spi.c:189
static self_test_reply_t st_reply(self_test_result_t result, int32_t diag)
Definition board_spi.c:238
board_spi_device_t
Definition board_spi.h:26
@ BOARD_SPI_COUNT
Definition board_spi.h:33
@ BOARD_SPI_ETH
Definition board_spi.h:30
@ BOARD_SPI_NAND
Definition board_spi.h:32
@ BOARD_SPI_BARO
Definition board_spi.h:29
@ BOARD_SPI_IMU
Definition board_spi.h:27
@ BOARD_SPI_HIGH_G
Definition board_spi.h:28
@ BOARD_SPI_RADIO
Definition board_spi.h:31
board_spi_status_t
Definition board_spi.h:36
@ BOARD_SPI_TIMEOUT
Definition board_spi.h:38
@ BOARD_SPI_NOT_CONFIGURED
Definition board_spi.h:40
@ BOARD_SPI_OK
Definition board_spi.h:37
@ BOARD_SPI_ERROR
Definition board_spi.h:39
void * osMutexId_t
Definition cmsis_os2.h:220
#define osMutexPrioInherit
Priority inherit protocol.
Definition cmsis_os2.h:194
@ osOK
Operation completed successfully.
Definition cmsis_os2.h:199
osMutexId_t osMutexNew(const osMutexAttr_t *attr)
Create and Initialize a Mutex object.
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
Acquire a Mutex or timeout if it is locked.
osStatus_t osMutexRelease(osMutexId_t mutex_id)
Release a Mutex that was acquired by osMutexAcquire.
static void sink(void *ctx, uint8_t type, const void *data, uint8_t len)
Definition flight_e2e.c:246
GPIO_PinState HAL_GPIO_ReadPin(const GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
@ GPIO_PIN_SET
@ GPIO_PIN_RESET
#define SPI_CFG1_MBR_Pos
#define SPI_CFG1_MBR
Master baud rate.
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint64_t PeriphClk)
#define RCC_PERIPHCLK_SPI45
#define RCC_PERIPHCLK_SPI123
#define SPI_PHASE_2EDGE
#define SPI_POLARITY_HIGH
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, const uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
struct __SPI_HandleTypeDef SPI_HandleTypeDef
SPI handle Structure definition.
#define NULL
Definition usbd_def.h:44
size_type count(const key_type &key) const
Definition json.hpp:19264
json_pointer result
Definition json.hpp:14064
SPI_HandleTypeDef hspi1
Definition main.c:56
SPI_HandleTypeDef hspi2
Definition main.c:57
SPI_HandleTypeDef hspi4
Definition main.c:59
SPI_HandleTypeDef hspi3
Definition main.c:58
static osMutexId_t lock
Definition mode.c:11
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:24474
@ SELF_TEST_DEVICE_ETHERNET
@ SELF_TEST_DEVICE_IMU
@ SELF_TEST_DEVICE_HIGH_G
@ SELF_TEST_DEVICE_RADIO
@ SELF_TEST_DEVICE_BAROMETER
self_test_result_t
@ SELF_TEST_FAIL
@ SELF_TEST_NOT_CONFIGURED
@ SELF_TEST_PASS
@ SELF_TEST_TIMEOUT
HAL_StatusTypeDef
HAL Status structures definition.
@ HAL_TIMEOUT
@ HAL_OK
General Purpose I/O.
GPIO_TypeDef * cs_port
Definition board_spi.c:16
uint16_t cs_pin
Definition board_spi.c:17
GPIO_TypeDef * busy_port
Definition board_spi.c:18
uint16_t busy_pin
Definition board_spi.c:19
SPI_HandleTypeDef * spi
Definition board_spi.c:15
Attributes structure for mutex.
Definition cmsis_os2.h:269
static boot_report_t r