Skip to content

Commit ab80d13

Browse files
committed
[stm32wb, spi] Initial SPI implementation
1 parent 7fa52da commit ab80d13

7 files changed

Lines changed: 267 additions & 36 deletions

File tree

examples/stm32wb/stm32wb55xx_nucleo.c

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ whal_Gpio g_whalGpio = {
3030

3131
.cfg = &(whal_Stm32wbGpio_Cfg) {
3232
.clkCtrl = &g_whalClock,
33-
.clk = &(whal_Stm32wbRcc_Clk) {WHAL_STM32WB55_GPIOB_CLOCK},
33+
.clk = (const void *[2]) {
34+
&(whal_Stm32wbRcc_Clk){WHAL_STM32WB55_GPIOA_CLOCK},
35+
&(whal_Stm32wbRcc_Clk){WHAL_STM32WB55_GPIOB_CLOCK},
36+
},
37+
.clkCount = 2,
3438

35-
.pinCfg = (whal_Stm32wbGpio_PinCfg[3]) {
39+
.pinCfg = (whal_Stm32wbGpio_PinCfg[7]) {
3640
[LED_PIN] = { /* LED */
3741
.port = WHAL_STM32WB_GPIO_PORT_B,
3842
.pin = 5,
@@ -60,8 +64,44 @@ whal_Gpio g_whalGpio = {
6064
.pull = WHAL_STM32WB_GPIO_PULL_UP,
6165
.altFn = 7,
6266
},
67+
[SPI1_SCK_PIN] = { /* SPI1 SCK */
68+
.port = WHAL_STM32WB_GPIO_PORT_A,
69+
.pin = 5,
70+
.mode = WHAL_STM32WB_GPIO_MODE_ALTFN,
71+
.outType = WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL,
72+
.speed = WHAL_STM32WB_GPIO_SPEED_FAST,
73+
.pull = WHAL_STM32WB_GPIO_PULL_UP,
74+
.altFn = 5,
75+
},
76+
[SPI1_MISO_PIN] = { /* SPI1 MISO */
77+
.port = WHAL_STM32WB_GPIO_PORT_A,
78+
.pin = 6,
79+
.mode = WHAL_STM32WB_GPIO_MODE_ALTFN,
80+
.outType = WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL,
81+
.speed = WHAL_STM32WB_GPIO_SPEED_FAST,
82+
.pull = WHAL_STM32WB_GPIO_PULL_UP,
83+
.altFn = 5,
84+
},
85+
[SPI1_MOSI_PIN] = { /* SPI1 MOSI */
86+
.port = WHAL_STM32WB_GPIO_PORT_A,
87+
.pin = 7,
88+
.mode = WHAL_STM32WB_GPIO_MODE_ALTFN,
89+
.outType = WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL,
90+
.speed = WHAL_STM32WB_GPIO_SPEED_FAST,
91+
.pull = WHAL_STM32WB_GPIO_PULL_UP,
92+
.altFn = 5,
93+
},
94+
[CS_PIN] = { /* SPI1 CS */
95+
.port = WHAL_STM32WB_GPIO_PORT_A,
96+
.pin = 4,
97+
.mode = WHAL_STM32WB_GPIO_MODE_OUT,
98+
.outType = WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL,
99+
.speed = WHAL_STM32WB_GPIO_SPEED_LOW,
100+
.pull = WHAL_STM32WB_GPIO_PULL_UP,
101+
.altFn = 0,
102+
},
63103
},
64-
.pinCount = 3,
104+
.pinCount = 7,
65105
},
66106
};
67107

@@ -97,3 +137,12 @@ whal_Flash g_whalFlash = {
97137
.size = 0x100000,
98138
},
99139
};
140+
141+
whal_Spi g_whalSpi = {
142+
WHAL_STM32WB55_SPI1_DEVICE,
143+
144+
.cfg = &(whal_Stm32wbSpi_Cfg) {
145+
.clkCtrl = &g_whalClock,
146+
.clk = &(whal_Stm32wbRcc_Clk) {WHAL_STM32WB55_SPI1_CLOCK},
147+
},
148+
};

examples/stm32wb/stm32wb55xx_nucleo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ enum {
1313
LED_PIN,
1414
LPUART1_TX_PIN,
1515
LPUART1_RX_PIN,
16+
SPI1_SCK_PIN,
17+
SPI1_MISO_PIN,
18+
SPI1_MOSI_PIN,
19+
CS_PIN,
1620
};
1721

1822
/* RCC clock controller instance. */
@@ -30,5 +34,7 @@ extern whal_Uart g_whalUart;
3034
/* Flash controller instance. */
3135
extern whal_Flash g_whalFlash;
3236

37+
/* SPI controller instance. */
38+
extern whal_Spi g_whalSpi;
3339

3440
#endif /* STM32WB55XX_NUCLEO_H */

src/gpio/stm32wb_gpio.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,12 @@ whal_Error whal_Stm32wbGpio_Init(whal_Gpio *gpioDev)
109109
cfg = (whal_Stm32wbGpio_Cfg *)gpioDev->cfg;
110110
pinCfg = cfg->pinCfg;
111111

112-
/* Enable GPIO port clock before accessing registers */
113-
err = whal_Clock_Enable(cfg->clkCtrl, cfg->clk);
114-
if (err) {
115-
return err;
112+
for (size_t i = 0; i < cfg->clkCount; ++i) {
113+
/* Enable GPIO port clock before accessing registers */
114+
err = whal_Clock_Enable(cfg->clkCtrl, cfg->clk[i]);
115+
if (err) {
116+
return err;
117+
}
116118
}
117119

118120
/* Initialize each pin in the configuration array */
@@ -130,12 +132,15 @@ whal_Error whal_Stm32wbGpio_Deinit(whal_Gpio *gpioDev)
130132
{
131133
whal_Error err;
132134
whal_Stm32wbGpio_Cfg *cfg;
135+
133136
cfg = (whal_Stm32wbGpio_Cfg *)gpioDev->cfg;
134137

135-
/* Disable GPIO port clock */
136-
err = whal_Clock_Disable(cfg->clkCtrl, cfg->clk);
137-
if (err) {
138-
return err;
138+
for (size_t i = 0; i < cfg->clkCount; ++i) {
139+
/* Disable GPIO port clock */
140+
err = whal_Clock_Disable(cfg->clkCtrl, cfg->clk[i]);
141+
if (err) {
142+
return err;
143+
}
139144
}
140145

141146
return WHAL_SUCCESS;

src/spi/stm32wb_spi.c

Lines changed: 169 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,205 @@
11
#include <stdint.h>
22
#include <wolfHAL/spi/stm32wb_spi.h>
33
#include <wolfHAL/spi/spi.h>
4+
#include <wolfHAL/clock/clock.h>
45
#include <wolfHAL/error.h>
6+
#include <wolfHAL/regmap.h>
7+
#include <wolfHAL/bitops.h>
58

69
/*
7-
* STM32WB SPI Driver - Stub Implementation
10+
* STM32WB SPI Register Definitions
811
*
9-
* TODO: Implement SPI register configuration and data transfer.
12+
* The SPI peripheral provides full-duplex synchronous serial communication.
13+
* This driver configures it in master mode with software slave management
14+
* and 8-bit data frames.
1015
*/
1116

17+
/* Control Register 1 - master config, clock, enable */
18+
#define SSPI_CR1_REG 0x00
19+
#define SSPI_CR1_CPHA WHAL_MASK(0) /* Clock phase */
20+
#define SSPI_CR1_CPOL WHAL_MASK(1) /* Clock polarity */
21+
#define SSPI_CR1_MSTR WHAL_MASK(2) /* Master selection */
22+
#define SSPI_CR1_BR WHAL_MASK_RANGE(5, 3) /* Baud rate prescaler */
23+
#define SSPI_CR1_SPE WHAL_MASK(6) /* SPI enable */
24+
#define SSPI_CR1_SSI WHAL_MASK(8) /* Internal slave select */
25+
#define SSPI_CR1_SSM WHAL_MASK(9) /* Software slave management */
26+
27+
/* Control Register 2 - data size, FIFO threshold */
28+
#define SSPI_CR2_REG 0x04
29+
#define SSPI_CR2_DS WHAL_MASK_RANGE(11, 8) /* Data size (0111 = 8-bit) */
30+
#define SSPI_CR2_FRXTH WHAL_MASK(12) /* FIFO reception threshold */
31+
32+
/* Status Register */
33+
#define SSPI_SR_REG 0x08
34+
#define SSPI_SR_RXNE WHAL_MASK(0) /* Receive buffer not empty */
35+
#define SSPI_SR_TXE WHAL_MASK(1) /* Transmit buffer empty */
36+
#define SSPI_SR_BSY WHAL_MASK(7) /* Busy flag */
37+
38+
/* Data Register - 8/16-bit access */
39+
#define SSPI_DR_REG 0x0C
40+
#define SSPI_DR_MASK WHAL_MASK_RANGE(7, 0)
41+
42+
/* 8-bit data size value for DS field */
43+
#define SSPI_DS_8BIT 0x7
44+
45+
/*
46+
* Calculate the baud rate prescaler index for a target baud rate.
47+
*
48+
* SPI baud rate = fPCLK / (2 ^ (BR + 1))
49+
* BR=0 -> /2, BR=1 -> /4, BR=2 -> /8, ... BR=7 -> /256
50+
*
51+
* Returns the smallest prescaler that does not exceed the target baud.
52+
*/
53+
static uint32_t whal_Stm32wbSpi_CalcBr(size_t pclk, uint32_t targetBaud)
54+
{
55+
uint32_t br;
56+
57+
for (br = 0; br < 7; br++) {
58+
if ((pclk / (2u << br)) <= targetBaud) {
59+
return br;
60+
}
61+
}
62+
63+
return 7;
64+
}
65+
66+
/*
67+
* Configure SPI mode and baud rate, then enable the peripheral.
68+
* Must be called with SPE disabled.
69+
*/
70+
static void whal_Stm32wbSpi_ApplyComCfg(const whal_Regmap *reg,
71+
whal_Stm32wbSpi_Cfg *cfg,
72+
whal_Stm32wbSpi_ComCfg *comCfg)
73+
{
74+
size_t pclk;
75+
uint32_t cpol, cpha, br;
76+
77+
whal_Clock_GetRate(cfg->clkCtrl, &pclk);
78+
79+
br = whal_Stm32wbSpi_CalcBr(pclk, comCfg->baud);
80+
81+
cpol = (comCfg->mode >> 1) & 1;
82+
cpha = comCfg->mode & 1;
83+
84+
/* Disable SPE before reconfiguring */
85+
whal_Reg_Update(reg->base, SSPI_CR1_REG, SSPI_CR1_SPE,
86+
whal_SetBits(SSPI_CR1_SPE, 0));
87+
88+
/* Set mode and baud rate */
89+
whal_Reg_Update(reg->base, SSPI_CR1_REG,
90+
SSPI_CR1_CPOL | SSPI_CR1_CPHA | SSPI_CR1_BR,
91+
whal_SetBits(SSPI_CR1_CPOL, cpol) |
92+
whal_SetBits(SSPI_CR1_CPHA, cpha) |
93+
whal_SetBits(SSPI_CR1_BR, br));
94+
95+
/* Re-enable SPE */
96+
whal_Reg_Update(reg->base, SSPI_CR1_REG, SSPI_CR1_SPE,
97+
whal_SetBits(SSPI_CR1_SPE, 1));
98+
}
99+
12100
whal_Error whal_Stm32wbSpi_Init(whal_Spi *spiDev)
13101
{
14-
(void)spiDev;
102+
whal_Error err;
103+
whal_Stm32wbSpi_Cfg *cfg;
104+
const whal_Regmap *reg = &spiDev->regmap;
105+
106+
cfg = (whal_Stm32wbSpi_Cfg *)spiDev->cfg;
107+
108+
err = whal_Clock_Enable(cfg->clkCtrl, cfg->clk);
109+
if (err != WHAL_SUCCESS) {
110+
return err;
111+
}
112+
113+
/* Master mode with software slave management */
114+
whal_Reg_Update(reg->base, SSPI_CR1_REG,
115+
SSPI_CR1_MSTR | SSPI_CR1_SSM | SSPI_CR1_SSI,
116+
whal_SetBits(SSPI_CR1_MSTR, 1) |
117+
whal_SetBits(SSPI_CR1_SSM, 1) |
118+
whal_SetBits(SSPI_CR1_SSI, 1));
119+
120+
/* 8-bit data size and FIFO receive threshold for 8-bit */
121+
whal_Reg_Update(reg->base, SSPI_CR2_REG,
122+
SSPI_CR2_DS | SSPI_CR2_FRXTH,
123+
whal_SetBits(SSPI_CR2_DS, SSPI_DS_8BIT) |
124+
whal_SetBits(SSPI_CR2_FRXTH, 1));
125+
15126
return WHAL_SUCCESS;
16127
}
17128

18129
whal_Error whal_Stm32wbSpi_Deinit(whal_Spi *spiDev)
19130
{
20-
(void)spiDev;
131+
whal_Error err;
132+
const whal_Regmap *reg = &spiDev->regmap;
133+
whal_Stm32wbSpi_Cfg *cfg = (whal_Stm32wbSpi_Cfg *)spiDev->cfg;
134+
135+
/* Disable SPI */
136+
whal_Reg_Update(reg->base, SSPI_CR1_REG, SSPI_CR1_SPE,
137+
whal_SetBits(SSPI_CR1_SPE, 0));
138+
139+
err = whal_Clock_Disable(cfg->clkCtrl, cfg->clk);
140+
if (err) {
141+
return err;
142+
}
143+
21144
return WHAL_SUCCESS;
22145
}
23146

24147
whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uint8_t *tx,
25148
size_t txLen, uint8_t *rx, size_t rxLen)
26149
{
27-
(void)spiDev;
28-
(void)spiComCfg;
29-
(void)tx;
30-
(void)txLen;
31-
(void)rx;
32-
(void)rxLen;
150+
const whal_Regmap *reg = &spiDev->regmap;
151+
whal_Stm32wbSpi_Cfg *cfg = (whal_Stm32wbSpi_Cfg *)spiDev->cfg;
152+
whal_Stm32wbSpi_ComCfg *comCfg = (whal_Stm32wbSpi_ComCfg *)spiComCfg;
153+
size_t totalLen = txLen > rxLen ? txLen : rxLen;
154+
size_t status;
155+
size_t d;
156+
157+
whal_Stm32wbSpi_ApplyComCfg(reg, cfg, comCfg);
158+
159+
for (size_t i = 0; i < totalLen; i++) {
160+
if (txLen) {
161+
/* Wait for TX buffer empty */
162+
do {
163+
whal_Reg_Get(reg->base, SSPI_SR_REG, SSPI_SR_TXE, &status);
164+
} while (!status);
165+
166+
/* Write data or dummy byte */
167+
uint8_t txByte = (i >= txLen) ? tx[txLen-1] : tx[i];
168+
*(volatile uint8_t *)(reg->base + SSPI_DR_REG) = txByte;
169+
}
170+
171+
if (rxLen) {
172+
/* Wait for RX buffer not empty */
173+
do {
174+
whal_Reg_Get(reg->base, SSPI_SR_REG, SSPI_SR_RXNE, &status);
175+
} while (!status);
176+
177+
/* Read received byte */
178+
d = *(volatile uint8_t *)(reg->base + SSPI_DR_REG);
179+
if (i < rxLen) {
180+
rx[i] = (uint8_t)d;
181+
}
182+
}
183+
}
184+
185+
/* Wait for not busy */
186+
do {
187+
whal_Reg_Get(reg->base, SSPI_SR_REG, SSPI_SR_BSY, &status);
188+
} while (status);
189+
33190
return WHAL_SUCCESS;
34191
}
35192

36193
whal_Error whal_Stm32wbSpi_Send(whal_Spi *spiDev, void *spiComCfg, const uint8_t *data,
37194
size_t dataSz)
38195
{
39-
(void)spiDev;
40-
(void)spiComCfg;
41-
(void)data;
42-
(void)dataSz;
43-
return WHAL_SUCCESS;
196+
return whal_Stm32wbSpi_SendRecv(spiDev, spiComCfg, data, dataSz, NULL, 0);
44197
}
45198

46199
whal_Error whal_Stm32wbSpi_Recv(whal_Spi *spiDev, void *spiComCfg, uint8_t *data,
47200
size_t dataSz)
48201
{
49-
(void)spiDev;
50-
(void)spiComCfg;
51-
(void)data;
52-
(void)dataSz;
53-
return WHAL_SUCCESS;
202+
return whal_Stm32wbSpi_SendRecv(spiDev, spiComCfg, NULL, 0, data, dataSz);
54203
}
55204

56205
const whal_SpiDriver whal_Stm32wbSpi_Driver = {

wolfHAL/gpio/stm32wb_gpio.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ typedef struct {
104104
*/
105105
typedef struct {
106106
whal_Clock *clkCtrl; /* Clock controller for enabling GPIO clock */
107-
void *clk; /* Clock descriptor (whal_Stm32wbRcc_Clk) */
107+
const void **clk; /* Array of clock descriptors */
108+
size_t clkCount; /* Number of clock descriptors */
108109

109110
whal_Stm32wbGpio_PinCfg *pinCfg; /* Array of pin configurations */
110111
size_t pinCount; /* Number of pins to configure */

wolfHAL/platform/st/stm32wb55xx.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <wolfHAL/clock/stm32wb_rcc.h>
77
#include <wolfHAL/gpio/stm32wb_gpio.h>
88
#include <wolfHAL/uart/stm32wb_uart.h>
9+
#include <wolfHAL/spi/stm32wb_spi.h>
910
#include <wolfHAL/flash/stm32wb_flash.h>
1011

1112
/*
@@ -87,4 +88,8 @@
8788
.regOffset = 0x60, \
8889
.enableMask = (1 << 14)
8990

91+
#define WHAL_STM32WB55_SPI1_CLOCK \
92+
.regOffset = 0x60, \
93+
.enableMask = (1 << 12)
94+
9095
#endif /* WHAL_STM32WB55XX_H */

0 commit comments

Comments
 (0)