|
1 | 1 | #include <stdint.h> |
2 | 2 | #include <wolfHAL/spi/stm32wb_spi.h> |
3 | 3 | #include <wolfHAL/spi/spi.h> |
| 4 | +#include <wolfHAL/clock/clock.h> |
4 | 5 | #include <wolfHAL/error.h> |
| 6 | +#include <wolfHAL/regmap.h> |
| 7 | +#include <wolfHAL/bitops.h> |
5 | 8 |
|
6 | 9 | /* |
7 | | - * STM32WB SPI Driver - Stub Implementation |
| 10 | + * STM32WB SPI Register Definitions |
8 | 11 | * |
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. |
10 | 15 | */ |
11 | 16 |
|
| 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 | + |
12 | 104 | whal_Error whal_Stm32wbSpi_Init(whal_Spi *spiDev) |
13 | 105 | { |
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 | + |
15 | 135 | return WHAL_SUCCESS; |
16 | 136 | } |
17 | 137 |
|
18 | 138 | whal_Error whal_Stm32wbSpi_Deinit(whal_Spi *spiDev) |
19 | 139 | { |
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 | + |
21 | 160 | return WHAL_SUCCESS; |
22 | 161 | } |
23 | 162 |
|
24 | 163 | whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uint8_t *tx, |
25 | 164 | size_t txLen, uint8_t *rx, size_t rxLen) |
26 | 165 | { |
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 | + |
33 | 214 | return WHAL_SUCCESS; |
34 | 215 | } |
35 | 216 |
|
36 | 217 | whal_Error whal_Stm32wbSpi_Send(whal_Spi *spiDev, void *spiComCfg, const uint8_t *data, |
37 | 218 | size_t dataSz) |
38 | 219 | { |
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); |
44 | 221 | } |
45 | 222 |
|
46 | 223 | whal_Error whal_Stm32wbSpi_Recv(whal_Spi *spiDev, void *spiComCfg, uint8_t *data, |
47 | 224 | size_t dataSz) |
48 | 225 | { |
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); |
54 | 228 | } |
55 | 229 |
|
56 | 230 | const whal_SpiDriver whal_Stm32wbSpi_Driver = { |
|
0 commit comments