Skip to content

Commit ad3cc87

Browse files
committed
SPI bus Low level driver
1 parent d45a0eb commit ad3cc87

File tree

4 files changed

+345
-1
lines changed

4 files changed

+345
-1
lines changed

src/platform/h563xx/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ target_sources(pslab-platform
33
adc_ll.c
44
led_ll.c
55
platform.c
6+
spi_ll.c
67
tim_ll.c
78
uart_ll.c
89
usb_ll.c
@@ -32,6 +33,7 @@ target_link_libraries(pslab-platform
3233
HAL::STM32::H5::GPIO
3334
HAL::STM32::H5::RCCEx
3435
HAL::STM32::H5::PWREx
36+
HAL::STM32::H5::SPIEx
3537
HAL::STM32::H5::TIMEx
3638
HAL::STM32::H5::UARTEx
3739
tinyusb

src/platform/h563xx/spi_ll.c

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
/**
2+
* @file spi_ll.c
3+
* @brief SPI hardware implementation for STM32H563xx
4+
*
5+
* This module handles initialization and operation of the SPI peripheral of
6+
* the STM32H5 microcontroller. It configures the hardware and dispatches SPI
7+
* interrupts to the hardware-independent SPI implementation.
8+
*
9+
* Implementation Details:
10+
* - Supports single SPI instance (SPI1)
11+
* - Configured for 8-bit data size
12+
* - DMA-based transmission and reception
13+
*
14+
* @author Tejas Garg
15+
* @date 2024-10-09
16+
*/
17+
18+
#include "stm32h5xx_hal.h"
19+
20+
#include "util/error.h"
21+
22+
#include "spi_ll.h"
23+
24+
enum { SPI_IRQ_PRIO = 4 }; // NVIC priority for SPI interrupts
25+
26+
/* SPI instance structure */
27+
typedef struct {
28+
SPI_HandleTypeDef *hspi;
29+
bool initialized;
30+
bool tx_in_progress;
31+
bool rx_in_progress;
32+
void (*tx_complete_callback)(void);
33+
void (*rx_complete_callback)(void);
34+
} SPIInstance;
35+
36+
/* HAL SPI handle */
37+
static SPI_HandleTypeDef g_hspi1 = { nullptr };
38+
static SPI_HandleTypeDef g_hspi2 = { nullptr };
39+
40+
/* DMA handles */
41+
static DMA_HandleTypeDef g_hdma_spi1_tx = { nullptr };
42+
static DMA_HandleTypeDef g_hdma_spi1_rx = { nullptr };
43+
static DMA_HandleTypeDef g_hdma_spi2_tx = { nullptr };
44+
static DMA_HandleTypeDef g_hdma_spi2_rx = { nullptr };
45+
46+
/* SPI instance configuration */
47+
static SPIInstance g_spi_instances[2] = {
48+
[SPI_BUS_0] = {
49+
.hspi = &g_hspi1,
50+
},
51+
[SPI_BUS_1] = {
52+
.hspi = &g_hspi2,
53+
},
54+
};
55+
56+
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
57+
{
58+
GPIO_InitTypeDef gpio_init = { 0 };
59+
60+
if (hspi->Instance == SPI1) {
61+
/* SPI1 clock enable */
62+
__HAL_RCC_SPI1_CLK_ENABLE();
63+
__HAL_RCC_GPIOA_CLK_ENABLE();
64+
__HAL_RCC_GPDMA1_CLK_ENABLE();
65+
66+
/* SPI1 GPIO Configuration: PA5=SCK, PA6=MISO, PA7=MOSI */
67+
gpio_init.Pin = GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
68+
gpio_init.Mode = GPIO_MODE_AF_PP;
69+
gpio_init.Pull = GPIO_NOPULL;
70+
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
71+
gpio_init.Alternate = GPIO_AF5_SPI1;
72+
HAL_GPIO_Init(GPIOA, &gpio_init);
73+
74+
/* Configure DMA for TX */
75+
g_hdma_spi1_tx.Instance = GPDMA1_Channel6;
76+
g_hdma_spi1_tx.Init.Request = GPDMA1_REQUEST_SPI1_TX;
77+
g_hdma_spi1_tx.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
78+
g_hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
79+
g_hdma_spi1_tx.Init.SrcInc = DMA_SINC_INCREMENTED;
80+
g_hdma_spi1_tx.Init.DestInc = DMA_DINC_FIXED;
81+
g_hdma_spi1_tx.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
82+
g_hdma_spi1_tx.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
83+
g_hdma_spi1_tx.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
84+
g_hdma_spi1_tx.Init.SrcBurstLength = 1;
85+
g_hdma_spi1_tx.Init.DestBurstLength = 1;
86+
g_hdma_spi1_tx.Init.TransferAllocatedPort =
87+
(DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0);
88+
g_hdma_spi1_tx.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
89+
g_hdma_spi1_tx.Init.Mode = DMA_NORMAL;
90+
HAL_DMA_Init(&g_hdma_spi1_tx);
91+
__HAL_LINKDMA(hspi, hdmatx, g_hdma_spi1_tx);
92+
93+
/* Configure DMA for RX */
94+
g_hdma_spi1_rx.Instance = GPDMA1_Channel7;
95+
g_hdma_spi1_rx.Init.Request = GPDMA1_REQUEST_SPI1_RX;
96+
g_hdma_spi1_rx.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
97+
g_hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
98+
g_hdma_spi1_rx.Init.SrcInc = DMA_SINC_FIXED;
99+
g_hdma_spi1_rx.Init.DestInc = DMA_DINC_INCREMENTED;
100+
g_hdma_spi1_rx.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
101+
g_hdma_spi1_rx.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
102+
g_hdma_spi1_rx.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
103+
g_hdma_spi1_rx.Init.SrcBurstLength = 1;
104+
g_hdma_spi1_rx.Init.DestBurstLength = 1;
105+
g_hdma_spi1_rx.Init.TransferAllocatedPort =
106+
(DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0);
107+
g_hdma_spi1_rx.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
108+
g_hdma_spi1_rx.Init.Mode = DMA_NORMAL;
109+
HAL_DMA_Init(&g_hdma_spi1_rx);
110+
__HAL_LINKDMA(hspi, hdmarx, g_hdma_spi1_rx);
111+
112+
/* SPI1 interrupt init */
113+
HAL_NVIC_SetPriority(SPI1_IRQn, SPI_IRQ_PRIO, 1);
114+
HAL_NVIC_EnableIRQ(SPI1_IRQn);
115+
116+
/* DMA interrupt init */
117+
HAL_NVIC_SetPriority(GPDMA1_Channel6_IRQn, SPI_IRQ_PRIO, 1);
118+
HAL_NVIC_EnableIRQ(GPDMA1_Channel6_IRQn);
119+
HAL_NVIC_SetPriority(GPDMA1_Channel7_IRQn, SPI_IRQ_PRIO, 1);
120+
HAL_NVIC_EnableIRQ(GPDMA1_Channel7_IRQn);
121+
122+
} else if (hspi->Instance == SPI2) {
123+
/* SPI2 GPIO Configuration: PB13=SCK, PB14=MISO, PB15=MOSI */
124+
gpio_init.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
125+
gpio_init.Mode = GPIO_MODE_AF_PP;
126+
gpio_init.Pull = GPIO_NOPULL;
127+
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
128+
gpio_init.Alternate = GPIO_AF5_SPI2;
129+
HAL_GPIO_Init(GPIOB, &gpio_init);
130+
131+
/* Configure DMA for TX */
132+
g_hdma_spi2_tx.Instance = GPDMA1_Channel6;
133+
g_hdma_spi2_tx.Init.Request = GPDMA1_REQUEST_SPI2_TX;
134+
g_hdma_spi2_tx.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
135+
g_hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
136+
g_hdma_spi2_tx.Init.SrcInc = DMA_SINC_INCREMENTED;
137+
g_hdma_spi2_tx.Init.DestInc = DMA_DINC_FIXED;
138+
g_hdma_spi2_tx.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
139+
g_hdma_spi2_tx.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
140+
g_hdma_spi2_tx.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
141+
g_hdma_spi2_tx.Init.SrcBurstLength = 1;
142+
g_hdma_spi2_tx.Init.DestBurstLength = 1;
143+
g_hdma_spi2_tx.Init.TransferAllocatedPort =
144+
(DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0);
145+
g_hdma_spi2_tx.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
146+
g_hdma_spi2_tx.Init.Mode = DMA_NORMAL;
147+
HAL_DMA_Init(&g_hdma_spi2_tx);
148+
__HAL_LINKDMA(hspi, hdmatx, g_hdma_spi2_tx);
149+
150+
/* Configure DMA for RX */
151+
g_hdma_spi2_rx.Instance = GPDMA1_Channel7;
152+
g_hdma_spi2_rx.Init.Request = GPDMA1_REQUEST_SPI2_RX;
153+
g_hdma_spi2_rx.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
154+
g_hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
155+
g_hdma_spi2_rx.Init.SrcInc = DMA_SINC_FIXED;
156+
g_hdma_spi2_rx.Init.DestInc = DMA_DINC_INCREMENTED;
157+
g_hdma_spi2_rx.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
158+
g_hdma_spi2_rx.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
159+
g_hdma_spi2_rx.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
160+
g_hdma_spi2_rx.Init.SrcBurstLength = 1;
161+
g_hdma_spi2_rx.Init.DestBurstLength = 1;
162+
g_hdma_spi2_rx.Init.TransferAllocatedPort =
163+
(DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT0);
164+
g_hdma_spi2_rx.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
165+
g_hdma_spi2_rx.Init.Mode = DMA_NORMAL;
166+
HAL_DMA_Init(&g_hdma_spi2_rx);
167+
__HAL_LINKDMA(hspi, hdmarx, g_hdma_spi2_rx);
168+
169+
/* SPI2 interrupt init */
170+
HAL_NVIC_SetPriority(SPI2_IRQn, SPI_IRQ_PRIO, 1);
171+
HAL_NVIC_EnableIRQ(SPI2_IRQn);
172+
173+
/* DMA interrupt init */
174+
HAL_NVIC_SetPriority(GPDMA1_Channel6_IRQn, SPI_IRQ_PRIO, 1);
175+
HAL_NVIC_EnableIRQ(GPDMA1_Channel6_IRQn);
176+
HAL_NVIC_SetPriority(GPDMA1_Channel7_IRQn, SPI_IRQ_PRIO, 1);
177+
HAL_NVIC_EnableIRQ(GPDMA1_Channel7_IRQn);
178+
}
179+
}
180+
181+
/**
182+
* @brief Initialize the SPI peripheral.
183+
*
184+
* @param bus SPI bus instance to initialize
185+
*/
186+
void SPI_LL_init(SPI_Bus bus)
187+
{
188+
if (bus >= SPI_BUS_COUNT) {
189+
THROW(ERROR_INVALID_ARGUMENT);
190+
}
191+
192+
SPIInstance *instance = &g_spi_instances[bus];
193+
if (instance->initialized) {
194+
return;
195+
}
196+
SPI_TypeDef *spi_instance[SPI_BUS_COUNT] = {
197+
[SPI_BUS_0] = SPI1,
198+
[SPI_BUS_1] = SPI2,
199+
};
200+
201+
/* Initialize SPI1 */
202+
instance->hspi->Instance = spi_instance[bus];
203+
204+
instance->hspi->Init.Mode = SPI_MODE_MASTER;
205+
instance->hspi->Init.Direction = SPI_DIRECTION_2LINES;
206+
instance->hspi->Init.DataSize = SPI_DATASIZE_8BIT;
207+
instance->hspi->Init.CLKPolarity = SPI_POLARITY_LOW;
208+
instance->hspi->Init.CLKPhase = SPI_PHASE_1EDGE;
209+
instance->hspi->Init.NSS = SPI_NSS_SOFT;
210+
instance->hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
211+
instance->hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
212+
instance->hspi->Init.TIMode = SPI_TIMODE_DISABLE;
213+
instance->hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
214+
215+
if (HAL_SPI_Init(instance->hspi) != HAL_OK) {
216+
THROW(ERROR_HARDWARE_FAULT);
217+
}
218+
219+
/* Configure NVIC for SPI interrupts */
220+
HAL_NVIC_SetPriority(SPI1_IRQn, SPI_IRQ_PRIO, 0);
221+
HAL_NVIC_EnableIRQ(SPI1_IRQn);
222+
223+
instance->tx_in_progress = false;
224+
instance->rx_in_progress = false;
225+
instance->tx_complete_callback = nullptr;
226+
instance->rx_complete_callback = nullptr;
227+
instance->initialized = true;
228+
}
229+
230+
/**
231+
* @brief Deinitialize the SPI peripheral.
232+
*
233+
* @param bus SPI bus instance to deinitialize
234+
*/
235+
void SPI_LL_deinit(SPI_Bus bus)
236+
{
237+
if (bus >= SPI_BUS_COUNT) {
238+
THROW(ERROR_INVALID_ARGUMENT);
239+
}
240+
241+
SPIInstance *instance = &g_spi_instances[bus];
242+
if (!instance->initialized) {
243+
return;
244+
}
245+
246+
/* Disable interrupts */
247+
if (bus == SPI_BUS_0) {
248+
HAL_NVIC_DisableIRQ(SPI1_IRQn);
249+
} else if (bus == SPI_BUS_1) {
250+
HAL_NVIC_DisableIRQ(SPI2_IRQn);
251+
}
252+
253+
/* Deinitialize SPI */
254+
if (HAL_SPI_DeInit(instance->hspi) != HAL_OK) {
255+
THROW(ERROR_HARDWARE_FAULT);
256+
}
257+
258+
instance->tx_in_progress = false;
259+
instance->rx_in_progress = false;
260+
instance->tx_complete_callback = nullptr;
261+
instance->rx_complete_callback = nullptr;
262+
instance->initialized = false;
263+
}
264+
265+
/**
266+
* @brief Transmit data over SPI.
267+
*
268+
* @param bus SPI bus instance to use
269+
* @param data Pointer to the data buffer to transmit
270+
* @param size Size of the data buffer
271+
*/
272+
void SPI_LL_transmit(SPI_Bus bus, uint8_t const *data, size_t size)
273+
{
274+
if (bus >= SPI_BUS_COUNT) {
275+
THROW(ERROR_INVALID_ARGUMENT);
276+
}
277+
278+
SPIInstance *instance = &g_spi_instances[bus];
279+
if (!instance->initialized) {
280+
THROW(ERROR_INVALID_ARGUMENT);
281+
}
282+
283+
// Start the transmission
284+
HAL_SPI_Transmit(instance->hspi, (uint8_t *)data, size, HAL_MAX_DELAY);
285+
}
286+
/**
287+
* @brief Receive data over SPI.
288+
*
289+
* @param bus SPI bus instance to use
290+
* @param data Pointer to the buffer to store received data
291+
* @param size Size of the data buffer
292+
*/
293+
294+
void SPI_LL_receive(SPI_Bus bus, uint8_t *data, size_t size)
295+
{
296+
if (bus >= SPI_BUS_COUNT) {
297+
THROW(ERROR_INVALID_ARGUMENT);
298+
}
299+
300+
SPIInstance *instance = &g_spi_instances[bus];
301+
if (!instance->initialized) {
302+
THROW(ERROR_INVALID_ARGUMENT);
303+
}
304+
305+
// Start the reception
306+
HAL_SPI_Receive(instance->hspi, data, size, HAL_MAX_DELAY);
307+
}

src/platform/h563xx/stm32h5xx_hal_conf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ extern "C" {
8585
// #define HAL_SDRAM_MODULE_ENABLED
8686
// #define HAL_SMARTCARD_MODULE_ENABLED
8787
// #define HAL_SMBUS_MODULE_ENABLED
88-
// #define HAL_SPI_MODULE_ENABLED
88+
#define HAL_SPI_MODULE_ENABLED
8989
// #define HAL_SRAM_MODULE_ENABLED
9090
#define HAL_TIM_MODULE_ENABLED
9191
#define HAL_UART_MODULE_ENABLED

src/platform/spi_ll.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @file spi_ll.h
3+
* @brief SPI low-level hardware interface for STM32H563xx
4+
*/
5+
6+
#ifndef SPI_LL_H
7+
#define SPI_LL_H
8+
9+
#include "stm32h5xx_hal.h"
10+
11+
/**
12+
* @brief SPI bus instance enumeration
13+
*/
14+
typedef enum { SPI_BUS_0 = 0, SPI_BUS_1 = 1, SPI_BUS_COUNT = 2 } SPI_Bus;
15+
16+
/**
17+
* @brief Initialize the SPI peripheral.
18+
*/
19+
void spi_ll_init(void);
20+
21+
/**
22+
* @brief Transmit data over SPI.
23+
* @param data Pointer to the data buffer to transmit.
24+
* @param size Size of the data buffer.
25+
*/
26+
void spi_ll_transmit(uint8_t *data, uint16_t size);
27+
28+
/**
29+
* @brief Receive data over SPI.
30+
* @param data Pointer to the buffer to store received data.
31+
* @param size Size of the data buffer.
32+
*/
33+
void spi_ll_receive(uint8_t *data, uint16_t size);
34+
35+
#endif /* SPI_LL_H */

0 commit comments

Comments
 (0)