Skip to content

Commit efb4294

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

7 files changed

Lines changed: 292 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: 194 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,230 @@
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+
whal_Error err;
75+
size_t pclk;
76+
uint32_t cpol, cpha, br;
77+
78+
err = whal_Clock_GetRate(cfg->clkCtrl, &pclk);
79+
if (err) {
80+
return;
81+
}
82+
83+
br = whal_Stm32wbSpi_CalcBr(pclk, comCfg->baud);
84+
85+
cpol = (comCfg->mode >> 1) & 1;
86+
cpha = comCfg->mode & 1;
87+
88+
/* Disable SPE before reconfiguring */
89+
whal_Reg_Update(reg->base, SSPI_CR1_REG, SSPI_CR1_SPE,
90+
whal_SetBits(SSPI_CR1_SPE, 0));
91+
92+
/* Set mode and baud rate */
93+
whal_Reg_Update(reg->base, SSPI_CR1_REG,
94+
SSPI_CR1_CPOL | SSPI_CR1_CPHA | SSPI_CR1_BR,
95+
whal_SetBits(SSPI_CR1_CPOL, cpol) |
96+
whal_SetBits(SSPI_CR1_CPHA, cpha) |
97+
whal_SetBits(SSPI_CR1_BR, br));
98+
99+
/* Re-enable SPE */
100+
whal_Reg_Update(reg->base, SSPI_CR1_REG, SSPI_CR1_SPE,
101+
whal_SetBits(SSPI_CR1_SPE, 1));
102+
}
103+
12104
whal_Error whal_Stm32wbSpi_Init(whal_Spi *spiDev)
13105
{
14-
(void)spiDev;
106+
whal_Error err;
107+
whal_Stm32wbSpi_Cfg *cfg;
108+
const whal_Regmap *reg;
109+
110+
if (!spiDev || !spiDev->cfg) {
111+
return WHAL_EINVAL;
112+
}
113+
114+
reg = &spiDev->regmap;
115+
cfg = (whal_Stm32wbSpi_Cfg *)spiDev->cfg;
116+
117+
err = whal_Clock_Enable(cfg->clkCtrl, cfg->clk);
118+
if (err != WHAL_SUCCESS) {
119+
return err;
120+
}
121+
122+
/* Master mode with software slave management */
123+
whal_Reg_Update(reg->base, SSPI_CR1_REG,
124+
SSPI_CR1_MSTR | SSPI_CR1_SSM | SSPI_CR1_SSI,
125+
whal_SetBits(SSPI_CR1_MSTR, 1) |
126+
whal_SetBits(SSPI_CR1_SSM, 1) |
127+
whal_SetBits(SSPI_CR1_SSI, 1));
128+
129+
/* 8-bit data size and FIFO receive threshold for 8-bit */
130+
whal_Reg_Update(reg->base, SSPI_CR2_REG,
131+
SSPI_CR2_DS | SSPI_CR2_FRXTH,
132+
whal_SetBits(SSPI_CR2_DS, SSPI_DS_8BIT) |
133+
whal_SetBits(SSPI_CR2_FRXTH, 1));
134+
15135
return WHAL_SUCCESS;
16136
}
17137

18138
whal_Error whal_Stm32wbSpi_Deinit(whal_Spi *spiDev)
19139
{
20-
(void)spiDev;
140+
whal_Error err;
141+
const whal_Regmap *reg;
142+
whal_Stm32wbSpi_Cfg *cfg;
143+
144+
if (!spiDev || !spiDev->cfg) {
145+
return WHAL_EINVAL;
146+
}
147+
148+
reg = &spiDev->regmap;
149+
cfg = (whal_Stm32wbSpi_Cfg *)spiDev->cfg;
150+
151+
/* Disable SPI */
152+
whal_Reg_Update(reg->base, SSPI_CR1_REG, SSPI_CR1_SPE,
153+
whal_SetBits(SSPI_CR1_SPE, 0));
154+
155+
err = whal_Clock_Disable(cfg->clkCtrl, cfg->clk);
156+
if (err) {
157+
return err;
158+
}
159+
21160
return WHAL_SUCCESS;
22161
}
23162

24163
whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uint8_t *tx,
25164
size_t txLen, uint8_t *rx, size_t rxLen)
26165
{
27-
(void)spiDev;
28-
(void)spiComCfg;
29-
(void)tx;
30-
(void)txLen;
31-
(void)rx;
32-
(void)rxLen;
166+
const whal_Regmap *reg;
167+
whal_Stm32wbSpi_Cfg *cfg;
168+
whal_Stm32wbSpi_ComCfg *comCfg;
169+
170+
if (!spiDev || !spiDev->cfg || !spiComCfg) {
171+
return WHAL_EINVAL;
172+
}
173+
174+
reg = &spiDev->regmap;
175+
cfg = (whal_Stm32wbSpi_Cfg *)spiDev->cfg;
176+
comCfg = (whal_Stm32wbSpi_ComCfg *)spiComCfg;
177+
size_t totalLen = txLen > rxLen ? txLen : rxLen;
178+
size_t status;
179+
size_t d;
180+
181+
whal_Stm32wbSpi_ApplyComCfg(reg, cfg, comCfg);
182+
183+
for (size_t i = 0; i < totalLen; i++) {
184+
if (txLen && tx) {
185+
/* Wait for TX buffer empty */
186+
do {
187+
whal_Reg_Get(reg->base, SSPI_SR_REG, SSPI_SR_TXE, &status);
188+
} while (!status);
189+
190+
/* Write data or dummy byte */
191+
uint8_t txByte = (i >= txLen) ? tx[txLen-1] : tx[i];
192+
*(volatile uint8_t *)(reg->base + SSPI_DR_REG) = txByte;
193+
}
194+
195+
if (rxLen && rx) {
196+
/* Wait for RX buffer not empty */
197+
do {
198+
whal_Reg_Get(reg->base, SSPI_SR_REG, SSPI_SR_RXNE, &status);
199+
} while (!status);
200+
201+
/* Read received byte */
202+
d = *(volatile uint8_t *)(reg->base + SSPI_DR_REG);
203+
if (i < rxLen) {
204+
rx[i] = (uint8_t)d;
205+
}
206+
}
207+
}
208+
209+
/* Wait for not busy */
210+
do {
211+
whal_Reg_Get(reg->base, SSPI_SR_REG, SSPI_SR_BSY, &status);
212+
} while (status);
213+
33214
return WHAL_SUCCESS;
34215
}
35216

36217
whal_Error whal_Stm32wbSpi_Send(whal_Spi *spiDev, void *spiComCfg, const uint8_t *data,
37218
size_t dataSz)
38219
{
39-
(void)spiDev;
40-
(void)spiComCfg;
41-
(void)data;
42-
(void)dataSz;
43-
return WHAL_SUCCESS;
220+
return whal_Stm32wbSpi_SendRecv(spiDev, spiComCfg, data, dataSz, NULL, 0);
44221
}
45222

46223
whal_Error whal_Stm32wbSpi_Recv(whal_Spi *spiDev, void *spiComCfg, uint8_t *data,
47224
size_t dataSz)
48225
{
49-
(void)spiDev;
50-
(void)spiComCfg;
51-
(void)data;
52-
(void)dataSz;
53-
return WHAL_SUCCESS;
226+
uint8_t dummyByte = 0xFF;
227+
return whal_Stm32wbSpi_SendRecv(spiDev, spiComCfg, &dummyByte, 1, data, dataSz);
54228
}
55229

56230
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 */

0 commit comments

Comments
 (0)