Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Stm32SPI.cxx
1
36#include "Stm32SPI.hxx"
37
38#if defined(STM32F072xB) || defined(STM32F091xC)
39#include "stm32f0xx_ll_rcc.h"
40#elif defined(STM32F103xB)
41#include "stm32f1xx_ll_rcc.h"
42#elif defined(STM32F303xC) || defined(STM32F303xE)
43#include "stm32f3xx_ll_rcc.h"
44#elif defined(STM32L432xx) || defined(STM32L431xx)
45#include "stm32l4xx_ll_rcc.h"
46#elif defined(STM32F767xx)
47#include "stm32f7xx_ll_rcc.h"
48#elif defined(STM32G0B1xx)
49#include "stm32g0xx_ll_rcc.h"
50#else
51#error Dont know what STM32 chip you have.
52#endif
53
54#define SPI_DEFAULT_TIMEOUT 100u
55
56// Enables the clock and resets the SPI peripheral.
57static void spi_reset(SPI_TypeDef *port)
58{
59 switch ((unsigned)port)
60 {
61 default:
62 DIE("Unknown SPI port requested.");
63#ifdef SPI1
64 case SPI1_BASE:
65 __HAL_RCC_SPI1_CLK_ENABLE();
66 __HAL_RCC_SPI1_FORCE_RESET();
67 __HAL_RCC_SPI1_RELEASE_RESET();
68 break;
69#endif
70#ifdef SPI2
71 case SPI2_BASE:
72 __HAL_RCC_SPI2_CLK_ENABLE();
73 __HAL_RCC_SPI2_FORCE_RESET();
74 __HAL_RCC_SPI2_RELEASE_RESET();
75 break;
76#endif
77#ifdef SPI3
78 case SPI3_BASE:
79 __HAL_RCC_SPI3_CLK_ENABLE();
80 __HAL_RCC_SPI3_FORCE_RESET();
81 __HAL_RCC_SPI3_RELEASE_RESET();
82 break;
83#endif
84#ifdef SPI4
85 case SPI4_BASE:
86 __HAL_RCC_SPI4_CLK_ENABLE();
87 __HAL_RCC_SPI4_FORCE_RESET();
88 __HAL_RCC_SPI4_RELEASE_RESET();
89 break;
90#endif
91#ifdef SPI5
92 case SPI5_BASE:
93 __HAL_RCC_SPI5_CLK_ENABLE();
94 __HAL_RCC_SPI5_FORCE_RESET();
95 __HAL_RCC_SPI5_RELEASE_RESET();
96 break;
97#endif
98#ifdef SPI6
99 case SPI6_BASE:
100 __HAL_RCC_SPI6_CLK_ENABLE();
101 __HAL_RCC_SPI6_FORCE_RESET();
102 __HAL_RCC_SPI6_RELEASE_RESET();
103 break;
104#endif
105#ifdef SPI7
106 case SPI7_BASE:
107 __HAL_RCC_SPI7_CLK_ENABLE();
108 __HAL_RCC_SPI7_FORCE_RESET();
109 __HAL_RCC_SPI7_RELEASE_RESET();
110 break;
111#endif
112#ifdef SPI8
113 case SPI8_BASE:
114 __HAL_RCC_SPI8_CLK_ENABLE();
115 __HAL_RCC_SPI8_FORCE_RESET();
116 __HAL_RCC_SPI8_RELEASE_RESET();
117 break;
118#endif
119 }
120}
121
122Stm32SPI::Stm32SPI(const char *name, SPI_TypeDef *port, uint32_t interrupt,
123 ChipSelectMethod cs_assert, ChipSelectMethod cs_deassert,
124 OSMutex *bus_lock)
125 : SPI(name, cs_assert, cs_deassert, bus_lock)
126{
127 spi_reset(port);
128 memset(&spiHandle_, 0, sizeof(spiHandle_));
129
130 spiHandle_.Instance = port;
131
133}
134
135static const uint32_t baud_rate_table[] =
136{
137 2, SPI_BAUDRATEPRESCALER_2, //
138 4, SPI_BAUDRATEPRESCALER_4, //
139 8, SPI_BAUDRATEPRESCALER_8, //
140 16, SPI_BAUDRATEPRESCALER_16, //
141 32, SPI_BAUDRATEPRESCALER_32, //
142 64, SPI_BAUDRATEPRESCALER_64, //
143 128, SPI_BAUDRATEPRESCALER_128, //
144 256, SPI_BAUDRATEPRESCALER_256, //
145 0, 0 //
146};
147
149{
150 // Deinit if needed.
151 if (spiHandle_.State != HAL_SPI_STATE_RESET)
152 {
153 HAL_SPI_DeInit(&spiHandle_);
154 }
155
156 // Computes the lowest divisor that gets us under the desired max speed Hz.
157 uint32_t pclock = 0; //cm3_cpu_clock_hz; //HAL_RCC_GetPCLK1Freq();
159 pclock = __LL_RCC_CALC_PCLK1_FREQ(configCPU_CLOCK_HZ, LL_RCC_GetAPB1Prescaler());
160 unsigned ofs = 0;
161 while (baud_rate_table[ofs] && ((pclock / baud_rate_table[ofs]) > speedHz))
162 {
163 ofs += 2;
164 }
165 if (baud_rate_table[ofs] == 0)
166 {
167 return -EINVAL;
168 // DIE("Could not find an appropriate SPI clock divider.");
169 }
170 spiHandle_.Init.BaudRatePrescaler = baud_rate_table[ofs + 1];
171
172 spiHandle_.Init.Direction = SPI_DIRECTION_2LINES;
173
174 if (mode & SPI_CPOL)
175 {
176 // clk one when idle CPOL = 1
177 spiHandle_.Init.CLKPolarity = SPI_POLARITY_HIGH;
178 }
179 else
180 {
181 // clk zero when idle CPOL = 0
182 spiHandle_.Init.CLKPolarity = SPI_POLARITY_LOW;
183 }
184
185 if (mode & SPI_CPHA)
186 {
187 // sample on trailing edge CPHA = 1
188 spiHandle_.Init.CLKPhase = SPI_PHASE_2EDGE;
189 }
190 else
191 {
192 // sample on leading edge CPHA = 0
193 spiHandle_.Init.CLKPhase = SPI_PHASE_1EDGE;
194 }
195
196 switch (bitsPerWord)
197 {
198 default:
199 return -EINVAL;
200 // DIE("Unknown data size.");
201 // Note there are more data sizes available, just to keep the code
202 // size reasonable we don't add all options.
203 case 7:
204 spiHandle_.Init.DataSize = SPI_DATASIZE_7BIT;
205 break;
206 case 0:
207 case 8:
208 spiHandle_.Init.DataSize = SPI_DATASIZE_8BIT;
209 break;
210 case 9:
211 spiHandle_.Init.DataSize = SPI_DATASIZE_9BIT;
212 break;
213 case 16:
214 spiHandle_.Init.DataSize = SPI_DATASIZE_16BIT;
215 break;
216 }
217
218 if (lsbFirst)
219 {
220 spiHandle_.Init.FirstBit = SPI_FIRSTBIT_LSB;
221 }
222 else
223 {
224 spiHandle_.Init.FirstBit = SPI_FIRSTBIT_MSB;
225 }
226 spiHandle_.Init.NSS = SPI_NSS_SOFT;
227 spiHandle_.Init.TIMode = SPI_TIMODE_DISABLE;
228 spiHandle_.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
229 spiHandle_.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
230 spiHandle_.Init.CRCPolynomial = 7;
231 spiHandle_.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
232 spiHandle_.Init.Mode = SPI_MODE_MASTER;
233
234 if (HAL_SPI_Init(&spiHandle_) != HAL_OK)
235 {
236 /* Initialization Error -- invalid arguments*/
237 return -EINVAL;
238 }
239
240 return 0;
241}
242
247int Stm32SPI::transfer(struct spi_ioc_transfer *msg)
248{
249 if (!msg->len)
250 {
251 return 0;
252 }
253 HAL_StatusTypeDef ret = HAL_OK;
254 unsigned bytes = msg->len;
255 if (!msg->tx_buf)
256 {
257 // doing receive
258 if (msg->rx_buf & 1)
259 {
260 ret = HAL_SPI_Receive(
261 &spiHandle_, (uint8_t *)msg->rx_buf, 1, SPI_DEFAULT_TIMEOUT);
262 ++msg->rx_buf;
263 --msg->len;
264 }
265 if (ret == HAL_OK && msg->len)
266 {
267 ret = HAL_SPI_Receive(&spiHandle_, (uint8_t *)msg->rx_buf, msg->len,
268 SPI_DEFAULT_TIMEOUT);
269 }
270 }
271 else if (!msg->rx_buf)
272 {
273 // doing transmit
274 if (msg->tx_buf & 1)
275 {
276 ret = HAL_SPI_Transmit(
277 &spiHandle_, (uint8_t *)msg->tx_buf, 1, SPI_DEFAULT_TIMEOUT);
278 ++msg->tx_buf;
279 --msg->len;
280 }
281 if (ret == HAL_OK && msg->len)
282 {
283 ret = HAL_SPI_Transmit(&spiHandle_, (uint8_t *)msg->tx_buf,
284 msg->len, SPI_DEFAULT_TIMEOUT);
285 }
286 // Wait for transmit to complete
287 while (__HAL_SPI_GET_FLAG(&spiHandle_, SPI_FLAG_BSY))
288 {
289 }
290 // Flush receive buffer otherwise an upcoming receive will get weird
291 // stuff.
292 while (__HAL_SPI_GET_FLAG(&spiHandle_, SPI_FLAG_RXNE))
293 {
294 *(__IO uint8_t *)&spiHandle_.Instance->DR;
295 }
296
297 }
298 else
299 {
300 // doing both TX and RX
301 if ((msg->rx_buf & 1) && (msg->tx_buf & 1))
302 {
303 ret = HAL_SPI_TransmitReceive(&spiHandle_, (uint8_t *)msg->tx_buf,
304 (uint8_t *)msg->rx_buf, 1, SPI_DEFAULT_TIMEOUT);
305 ++msg->tx_buf;
306 ++msg->rx_buf;
307 --msg->len;
308 }
309 if ((msg->rx_buf & 1) || (msg->tx_buf & 1))
310 {
311 // Cannot have differently aligned TX and RX buffer.
312 return -EINVAL;
313 }
314 if (ret == HAL_OK && msg->len)
315 {
316 ret = HAL_SPI_TransmitReceive(&spiHandle_, (uint8_t *)msg->tx_buf,
317 (uint8_t *)msg->rx_buf, msg->len, SPI_DEFAULT_TIMEOUT);
318 }
319 }
320 if (ret != HAL_OK)
321 {
322 return -EIO;
323 }
324 return bytes;
325}
This class provides a mutex API.
Definition OS.hxx:427
Private data for an SPI device.
Definition SPI.hxx:53
uint8_t mode
one of four SPI modes
Definition SPI.hxx:196
uint32_t speedHz
Max default speed in Hz.
Definition SPI.hxx:190
bool lsbFirst
transmit LSB first if true
Definition SPI.hxx:199
uint8_t bitsPerWord
number of bits per word transaction
Definition SPI.hxx:193
int update_configuration() override
Update the configuration of the bus.
Definition Stm32SPI.cxx:148
SPI_HandleTypeDef spiHandle_
Stm32 HAL device structure.
Definition Stm32SPI.hxx:94
int transfer(struct spi_ioc_transfer *msg) override
Method to transmit/receive the data.
Definition Stm32SPI.cxx:247
Stm32SPI()
Default constructor.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143