Home | Projects | Notes > MCU Peripheral Drivers > SPI Driver (stm32f407xx_spi_driver.h/.c
)
stm32f407xx_spi_driver.h/.c
)
SPI initialization
SPI peripheral clock control
SPI Tx
SPI Rx
SPI interrupt configuration & handling
Other SPI management APIs
SPI_DeviceMode
Master / slave
SPI_BusConfig
Full-duplex (default) / half-duplex / simplex
SPI_DFF
8-bit data format (default) / 16-bit data format
Shift register width will be decided accordingly.
SPI_CPHA
Defaults to 0
SPI_CPOL
Defaults to 0
SPI_SSM
Software slave management (SSM = 1) / Hardware slave management (SSM = 0)
SPI_SCLKSpeed
Required serial clock speed
stm32f407xx_spi_driver.h
Path: Project/Drivers/Inc/
xxxxxxxxxx
1721/*******************************************************************************
2 * File : stm32f407xx_spi_driver.h
3 * Brief : STM32F407xx MCU specific SPI driver header file
4 * Author ; Kyungjae Lee
5 * Date : May 21, 2023
6 *
7 * Note : This code includes only the features that are necessary for my
8 * personal projects.
9 * ****************************************************************************/
10
11
12
13
14
15
16/*******************************************************************************
17 * SPIx peripheral structures
18 ******************************************************************************/
19
20/* SPIx peripheral configuration structure */
21typedef struct
22{
23 uint8_t SPI_DeviceMode; /* Available values @SPI_DeviceMode */
24 uint8_t SPI_BusConfig; /* Available values @SPI_BusConfig */
25 uint8_t SPI_SCLKSpeed; /* Available values @SPI_SCKLSpeed */
26 uint8_t SPI_DFF; /* Available values @SPI_DFF */
27 uint8_t SPI_CPOL; /* Available values @SPI_CPOL */
28 uint8_t SPI_CPHA; /* Available values @SPI_CPHA */
29 uint8_t SPI_SSM; /* Available values @SPI_SSM */
30} SPI_Config_TypeDef;
31
32/* SPIx peripheral handle structure */
33typedef struct
34{
35 SPI_TypeDef *pSPIx; /* Holds the base address of the SPIx(x:0,1,2) peripheral */
36 SPI_Config_TypeDef SPI_Config; /* SPIx peripheral configuration structure */
37 uint8_t volatile *pTxBuffer; /* App's Tx buffer address */
38 uint8_t volatile *pRxBuffer; /* App's Rx buffer address */
39 uint32_t TxLen; /* Number of bytes left to transmit */
40 uint32_t RxLen; /* Number of bytes left to receive */
41 uint8_t TxState; /* Available values @SPI_ApplicationStateus */
42 uint8_t RxState; /* Available values @SPI_ApplicationStateus */
43} SPI_Handle_TypeDef;
44
45/**
46 * @SPI_ApplicationStatus
47 */
48
49
50
51
52/**
53 * @SPI_ApplicationEvents
54 */
55
56
57
58
59
60/**
61 * @SPI_DeviceMode
62 * Note: SPI_CR1 MSTR bit[2] - Master selection
63 */
64
65
66
67/**
68 * @SPI_BusConfig
69 */
70
71
72//#define SPI_BUS_CONFIG_SIMPLEX_TX_ONLY 2 // Simply removing Rx line = Same config as FD
73
74
75/**
76 * @SPI_CLKSpeed
77 * Note: SPI_CR1 BR[5:3] - Baud rate control
78 */
79
80
81
82
83
84
85
86
87
88/**
89 * @SPI_DFF
90 * Note: SPI_CR1 DFF bit[11] - Data frame format/
91 */
92/* Default */
93
94
95/**
96 * @SPI_CPOL
97 * Note: SPI_CR1 CPOL bit[1] - Clock polarity
98 */
99/* Default */
100
101
102/**
103 * @SPI_CPHA
104 * Note: SPI_CR1 CPHA bit[0] - Clock phase
105 */
106/* Default */
107
108
109/**
110 * @SPI_SSM
111 * Note: SPI_CR1 SSM bit[9] - Software slave management
112 */
113/* Default */
114
115
116
117/*******************************************************************************
118 * APIs supported by the SPI driver
119 * (See function definitions for more information)
120 ******************************************************************************/
121
122/**
123 * Peripheral clock setup
124 */
125void SPI_PeriClockControl(SPI_TypeDef *pSPIx, uint8_t state);
126
127/**
128 * Init and De-init
129 */
130void SPI_Init(SPI_Handle_TypeDef *pSPIHandle);
131void SPI_DeInit(SPI_TypeDef *pSPIx); /* Utilize RCC_AHBxRSTR (AHBx peripheral reset register) */
132
133/**
134 * Data send and receive
135 * - Blocking type: Non-interrupt based
136 * - Non-blocking type: interrupt based
137 * - DMA based (Will not be considered in this project)
138 *
139 * Note: Standard practice for choosing the size of 'length' variable is uint32_t or greater
140 */
141void SPI_TxBlocking(SPI_TypeDef *pSPIx, uint8_t *pTxBuffer, uint32_t len);
142void SPI_RxBlocking(SPI_TypeDef *pSPIx, uint8_t *pRxBuffer, uint32_t len);
143
144uint8_t SPI_TxInterrupt(SPI_Handle_TypeDef *pSPIHandle, uint8_t volatile *pTxBuffer, uint32_t len);
145uint8_t SPI_RxInterrupt(SPI_Handle_TypeDef *pSPIHandle, uint8_t volatile *pRxBuffer, uint32_t len);
146
147/**
148 * IRQ configuration and ISR handling
149 */
150void SPI_IRQInterruptConfig(uint8_t irqNumber, uint8_t state);
151void SPI_IRQPriorityConfig(uint8_t irqNumber, uint32_t irqPriority);
152void SPI_IRQHandling(SPI_Handle_TypeDef *pSPIHandle);
153
154/**
155 * Other peripheral control APIs
156 */
157void SPI_PeriControl(SPI_TypeDef *pSPIx, uint8_t state);
158void SPI_SSIConfig(SPI_TypeDef *pSPIx, uint8_t state);
159void SPI_SSOEConfig(SPI_TypeDef *pSPIx, uint8_t state);
160void SPI_ClearOVRFlag(SPI_TypeDef *pSPIx);
161void SPI_CloseTx(SPI_Handle_TypeDef *pSPIHandle);
162void SPI_CloseRx(SPI_Handle_TypeDef *pSPIHandle);
163
164/**
165 * Application callback functions (Must be implemented by application)
166 * Note: Since the driver does not know in which application this function will be
167 * implemented, it is good idea to give a weak function definition.
168 */
169void SPI_ApplicationEventCallback(SPI_Handle_TypeDef *pSPIHandle, uint8_t appEvent);
170
171
172/* STM32F407XX_SPI_DRIVER_H */
stm32f407xx_spi_driver.c
Path: Project/Drivers/Src/
xxxxxxxxxx
6861/*******************************************************************************
2 * File : stm32f407xx_spi_driver.c
3 * Brief : STM32F407xx MCU specific SPI driver source file
4 * Author ; Kyungjae Lee
5 * Date : May 21, 2023
6 *
7 * Note : This code includes only the features that are necessary for my
8 * personal projects.
9 * ****************************************************************************/
10
11
12
13/* Private helper functions */
14static void SPI_TXE_InterruptHandle(SPI_Handle_TypeDef *pSPIHandle);
15static void SPI_RXNE_InterruptHandle(SPI_Handle_TypeDef *pSPIHandle);
16static void SPI_OVR_InterruptHandle(SPI_Handle_TypeDef *pSPIHandle);
17
18/*******************************************************************************
19 * APIs supported by the SPI driver
20 * (See function definitions for more information)
21 ******************************************************************************/
22
23/**
24 * SPI_PeriClockControl()
25 * Brief : Enables or disables peripheral clock for SPIx
26 * Param : @pSPIx - base address of SPIx peripheral
27 * @state - ENABLE or DISABLE macro
28 * Retval : None
29 * Note : N/A
30 */
31void SPI_PeriClockControl(SPI_TypeDef *pSPIx, uint8_t state)
32{
33 if (state == ENABLE)
34 {
35 if (pSPIx == SPI1)
36 SPI1_PCLK_EN();
37 else if (pSPIx == SPI2)
38 SPI2_PCLK_EN();
39 else if (pSPIx == SPI3)
40 SPI3_PCLK_EN();
41 else if (pSPIx == SPI4)
42 SPI4_PCLK_EN();
43 }
44 else
45 {
46 if (pSPIx == SPI1)
47 SPI1_PCLK_DI();
48 else if (pSPIx == SPI2)
49 SPI2_PCLK_DI();
50 else if (pSPIx == SPI3)
51 SPI3_PCLK_DI();
52 else if (pSPIx == SPI4)
53 SPI4_PCLK_DI();
54 }
55} /* End of SPI_PeriClockControl */
56
57/**
58 * SPI_Init()
59 * Brief : Initializes SPI peripheral
60 * Param : @pSPIHandle - pointer to the SPI handle structure
61 * Retval : None
62 * Note : For the serial communication peripherals (e.g., SPI, I2C, ...), there
63 * may be
64 * - one or more control registers where configurable parameters are stored
65 * - one or more data registers where user data is stored
66 * - one or more status registers where various status flags are stored.
67 */
68void SPI_Init(SPI_Handle_TypeDef *pSPIHandle)
69{
70 /* Enable peripheral clock */
71 SPI_PeriClockControl(pSPIHandle->pSPIx, ENABLE);
72
73 /**
74 * Configure SPIx_CR1 register
75 */
76
77 uint32_t temp = 0; /* Temporary register to store SPIx_CR1 configuration information */
78
79 /* Configure device mode (MSTR bit[2] - Master selection) */
80 temp |= pSPIHandle->SPI_Config.SPI_DeviceMode << 2;
81
82 /* Configure bus config
83 *
84 * Full Duplex: BIDIMODE=0, RXONLY=0
85 * Simplex (unidirectional receive-only): BIDIMODE=0, RXONLY=1
86 * Half-Duplex, Tx: BIDIMODE=1, BIDIOE=1
87 * Half-Duplex, Rx: BIDIMODE=1, BIDIOE=0
88 */
89 if (pSPIHandle->SPI_Config.SPI_BusConfig == SPI_BUS_CONFIG_FULL_DUPLEX)
90 {
91 /* Clear BIDIMODE bit[15] - 2-line unidirectional data mode selected */
92 temp &= ~(1 << SPI_CR1_BIDIMODE);
93 }
94 else if (pSPIHandle->SPI_Config.SPI_BusConfig == SPI_BUS_CONFIG_HALF_DUPLEX)
95 {
96 /* Set BIDIMODE bit[15] - 1-line bidirectional data mode selected */
97 temp |= (1 << SPI_CR1_BIDIMODE);
98 }
99 else if (pSPIHandle->SPI_Config.SPI_BusConfig == SPI_BUS_CONFIG_SIMPLEX_RX_ONLY)
100 {
101 /* Clear BIDIMODE bit[15] - 2-line unidirectional data mode selected */
102 temp &= ~(1 << SPI_CR1_BIDIMODE);
103
104 /* Set RXONLY bit[10] - Output disabled (Receive-only mode) */
105 temp |= (1 << SPI_CR1_RXONLY);
106 }
107
108 /* Configure SPI serial clock speed (baud rate) */
109 temp |= pSPIHandle->SPI_Config.SPI_SCLKSpeed << SPI_CR1_BR;
110
111 /* Configure DFF */
112 temp |= pSPIHandle->SPI_Config.SPI_DFF << SPI_CR1_DFF;
113
114 /* Configure CPOL */
115 temp |= pSPIHandle->SPI_Config.SPI_CPOL << SPI_CR1_CPOL;
116
117 /* Configure CPHA */
118 temp |= pSPIHandle->SPI_Config.SPI_CPHA << SPI_CR1_CPHA;
119
120 /* Configure SSM */
121 temp |= pSPIHandle->SPI_Config.SPI_SSM << SPI_CR1_SSM;
122
123 pSPIHandle->pSPIx->CR1 = temp;
124} /* End of SPI_Init */
125
126/**
127 * SPI_DeInit()
128 * Brief : De-initializes SPI peripheral
129 * Param : @pSPIx - base address of SPIx peripheral
130 * Retval : None
131 * Note : N/A
132 */
133void SPI_DeInit(SPI_TypeDef *pSPIx) /* Utilize RCC_AHBxRSTR (AHBx peripheral reset register) */
134{
135 /* Set and clear the corresponding bit of RCC_APBxRSTR to reset */
136 if (pSPIx == SPI1)
137 SPI1_RESET();
138 else if (pSPIx == SPI2)
139 SPI2_RESET();
140 else if (pSPIx == SPI3)
141 SPI3_RESET();
142 else if (pSPIx == SPI4)
143 SPI4_RESET();
144} /* End of SPI_DeInit */
145
146/**
147 * Data send and receive
148 * - Blocking type: Non-interrupt based
149 * - Non-blocking type: interrupt based
150 * - DMA based (Will not be considered in this project)
151 *
152 * Note: Standard practice for choosing the size of 'length' variable is uint32_t or greater
153 */
154
155/**
156 * SPI_TxBlocking()
157 * Brief : Send from @pSPIx the data of length @len stored in @pTxBuffer
158 * Param : @pSPIx - base address of SPIx peripheral
159 * @pTxBuffer - address of the Tx buffer
160 * @len - length of the data to transmit
161 * Retval : None
162 * Note : This is a blocking function. This function will not return until
163 * the data is fully sent out.
164 */
165void SPI_TxBlocking(SPI_TypeDef *pSPIx, uint8_t *pTxBuffer, uint32_t len)
166{
167 while (len > 0)
168 {
169 /* Wait until TXE (Tx buffer empty) bit is set */
170 while (!(pSPIx->SR & (0x1 << SPI_SR_TXE))); /* Blocking (Polling for the TXE flag to set) */
171
172 /* Check DFF (Data frame format) bit in SPIx_CR1 */
173 if (pSPIx->CR1 & (0x1 << SPI_CR1_DFF))
174 {
175 /* 16-bit DFF */
176 /* Load the data into DR */
177 pSPIx->DR = *((uint16_t *)pTxBuffer); /* Make it 16-bit data */
178
179 /* Decrement the length (2 bytes) */
180 len--;
181 len--;
182
183 /* Adjust the buffer pointer */
184 (uint16_t *)pTxBuffer++;
185 }
186 else
187 {
188 /* 8-bit DFF */
189 /* Load the data into DR */
190 pSPIx->DR = *pTxBuffer;
191
192 /* Decrement the length (1 byte) */
193 len--;
194
195 /* Adjust the buffer pointer */
196 pTxBuffer++;
197 }
198 }
199} /* End of SPI_TxBlocking */
200
201/**
202 * SPI_RxBlocking()
203 * Brief : Receive the data of length @len stored in @pRxBuffer
204 * Param : @pSPIx - base address of SPIx peripheral
205 * @pRxBuffer - address of the Rx buffer
206 * @len - length of the data to transmit
207 * Retval : None
208 * Note : This is a blocking function. This function will not return until
209 * the data is fully received.
210 */
211void SPI_RxBlocking(SPI_TypeDef *pSPIx, uint8_t *pRxBuffer, uint32_t len)
212{
213 while (len > 0)
214 {
215 /* Wait until RXNE (Rx buffer not empty) bit is set */
216 while (!(pSPIx->SR & (0x1 << SPI_SR_RXNE))); /* Blocking (Polling for the RXNE flag to set) */
217
218 /* Check DFF (Data frame format) bit in SPIx_CR1 */
219 if (pSPIx->CR1 & (0x1 << SPI_CR1_DFF))
220 {
221 /* 16-bit DFF */
222 /* Read the data from DR into RxBuffer */
223 *((uint16_t *)pRxBuffer) = pSPIx->DR;
224
225 /* Decrement the length (2 bytes) */
226 len--;
227 len--;
228
229 /* Adjust the buffer pointer */
230 (uint16_t *)pRxBuffer++;
231 }
232 else
233 {
234 /* 8-bit DFF */
235 /* Read the data from DR into RxBuffer */
236 *pRxBuffer = pSPIx->DR;
237
238 /* Decrement the length (1 byte) */
239 len--;
240
241 /* Adjust the buffer pointer */
242 pRxBuffer++;
243 }
244 }
245} /* End of SPI_RxBlocking */
246
247/**
248 * SPI_TxInterrupt()
249 * Brief : Fills out the necessary information (@pTxBuffer, @len, SPI state) to
250 * transmit data, set TXEIE bit and returns
251 * Param : @pSPIHandle - pointer to SPI handle structure
252 * @pTxBuffer - address of the Tx buffer
253 * @len - length of the data to transmit
254 * Retval : Tx state of the application
255 * Note : This is a non-blocking function. This function does not write
256 * data into the data register. Writing will be taken care of by
257 * the interrupt handler.
258 */
259uint8_t SPI_TxInterrupt(SPI_Handle_TypeDef *pSPIHandle, uint8_t volatile *pTxBuffer, uint32_t len)
260{
261 uint8_t state = pSPIHandle->TxState;
262
263 if (state != SPI_BUSY_IN_TX)
264 {
265 /* 1. Save the Tx buffer address and length info in some global variables */
266 pSPIHandle->pTxBuffer = pTxBuffer;
267 pSPIHandle->TxLen = len;
268
269 /* 2. Mark the SPI state as busy in transmission so that no other code
270 * can take over the same SPI peripheral until transmission is over.
271 */
272 pSPIHandle->TxState = SPI_BUSY_IN_TX;
273
274 /* 3. Enable the SPI_CR2 TXEIE control bit to get interrupt whenever TXE flag
275 * is set in SR.
276 */
277 pSPIHandle->pSPIx->CR2 |= (0x1 << SPI_CR2_TXEIE);
278 }
279
280 /* 4. Data transmission will be handled by the ISR code. */
281
282 return state;
283}
284
285/**
286 * SPI_RxInterrupt()
287 * Brief : Fills out the necessary information (@pTxBuffer, @len, SPI state) to
288 * receive data, set RXNEIE bit and returns
289 * Param : @pSPIHandle - pointer to SPI handle structure
290 * @pRxBuffer - address of the Rx buffer
291 * @len - length of the data to transmit
292 * Retval : Rx state of the application
293 * Note : This is a non-blocking function. This function does not read
294 * data from the data register. Reading will be taken care of by
295 * the interrupt handler.
296 */
297uint8_t SPI_RxInterrupt(SPI_Handle_TypeDef *pSPIHandle, uint8_t volatile *pRxBuffer, uint32_t len)
298{
299 uint8_t state = pSPIHandle->RxState;
300
301 if (state != SPI_BUSY_IN_RX)
302 {
303 /* 1. Save the Rx buffer address and length info in some global variables */
304 pSPIHandle->pRxBuffer = pRxBuffer;
305 pSPIHandle->RxLen = len;
306
307 /* 2. Mark the SPI state as busy in reception so that no other code
308 * can take over the same SPI peripheral until reception is over.
309 */
310 pSPIHandle->RxState = SPI_BUSY_IN_RX;
311
312 /* 3. Enable the SPI_CR2 RXNEIE control bit to get interrupt whenever RXNE flag
313 * is set in SR.
314 */
315 pSPIHandle->pSPIx->CR2 |= (0x1 << SPI_CR2_RXNEIE);
316 }
317
318 /* 4. Data reception will be handled by the ISR code. */
319
320 return state;
321} /* End of SPI_RxInterrupt */
322
323/**
324 * SPI_PeriControl()
325 * Brief : Enables or disables SPI peripheral @pSPIx
326 * Param : @pSPIx - base address of SPIx peripheral
327 * @state - ENABLE or DISABLE macro
328 * Retval : None
329 * Note : N/A
330 */
331void SPI_PeriControl(SPI_TypeDef *pSPIx, uint8_t state)
332{
333 if (state == ENABLE)
334 pSPIx->CR1 |= (0x1 << SPI_CR1_SPE); /* Enable */
335 else
336 pSPIx->CR1 &= ~(0x1 << SPI_CR1_SPE); /* Disable */
337} /* End of SPI_PeriControl */
338
339/**
340 * SPI_SSIConfig()
341 * Brief : Sets or resets SPI CR1 register's SSI (Internal Slave Select) bit
342 * Param : @pSPIx - base address of SPIx peripheral
343 * @state - ENABLE or DISABLE macro
344 * Retval : None
345 * Note : This bit has an effect only when the SSM bit is set.
346 * The value of this bit is forced onto the NSS pin and
347 * the IO value of the NSS pin is ignored.
348 * This bit is not used in I2S mode and SPI TI mode.
349 */
350void SPI_SSIConfig(SPI_TypeDef *pSPIx, uint8_t state)
351{
352 if (state == ENABLE)
353 pSPIx->CR1 |= (0x1 << SPI_CR1_SSI); /* Enable */
354 else
355 pSPIx->CR1 &= ~(0x1 << SPI_CR1_SSI); /* Disable */
356} /* End of SPI_SSIConfig */
357
358/**
359 * SPI_SSOEConfig()
360 * Brief : Sets or resets SPI CR2 register's SSOE (Slave Select Output Enable) bit
361 * Param : @pSPIx - base address of SPIx peripheral
362 * @state - ENABLE or DISABLE macro
363 * Retval : None
364 * Note : When SSOE = 1, SS output is disabled in master mode and the cell
365 * can work in multimaster configuration
366 * When SSOE = 0, SS output is enabled in master mode and when the cell
367 * is enabled. The cell cannot work in a multimaster environment.
368 */
369void SPI_SSOEConfig(SPI_TypeDef *pSPIx, uint8_t state)
370{
371 if (state == ENABLE)
372 pSPIx->CR2 |= (0x1 << SPI_CR2_SSOE); /* Enable */
373 else
374 pSPIx->CR2 &= ~(0x1 << SPI_CR2_SSOE); /* Disable */
375} /* End of SPI_SSOEConfig */
376
377/**
378 * SPI_IRQInterruptConfig()
379 * Brief : Configures IRQ interrupts (processor; NVIC_ISERx, NVIC_ICERx)
380 * Param : @irqNumber - IRQ number
381 * @state - ENABLE or DISABLE macro
382 * Retval : None
383 * Note : Reference - Cortex-M4 Devices Generic User Guide
384 * Clearing ISERx bit won't disable the interrupt.
385 * To disable interrupt ICERx bit has to be set!
386 */
387void SPI_IRQInterruptConfig(uint8_t irqNumber, uint8_t state)
388{
389 if (state == ENABLE)
390 {
391 /* Configure NVIC_ISERx register */
392 if (irqNumber <= 31)
393 *NVIC_ISER0 |= (0x1 << irqNumber);
394 else if (32 <= irqNumber && irqNumber <= 63)
395 *NVIC_ISER1 |= (0x1 << irqNumber % 32);
396 else if (64 <= irqNumber && irqNumber <= 95)
397 *NVIC_ISER2 |= (0x1 << irqNumber % 32);
398 }
399 else
400 {
401 /* Configure NVIC_ICERx register */
402 if (irqNumber <= 31)
403 *NVIC_ICER0 |= (0x1 << irqNumber);
404 else if (32 <= irqNumber && irqNumber <= 63)
405 *NVIC_ICER1 |= (0x1 << irqNumber % 32);
406 else if (64 <= irqNumber && irqNumber <= 95)
407 *NVIC_ICER2 |= (0x1 << irqNumber % 32);
408 }
409} /* End of SPI_IRQInterruptConfig */
410
411/**
412 * SPI_OIRQPriorityConfig()
413 * Brief : Configures IRQ priority (processor; NVIC_IPRx)
414 * Param : @irqNumber - IRQ number
415 * @irqPriotity - IRQ priority (Make sure this parameter is of
416 * type uint32_t. Due to the number of bits it
417 * needs to be shifted during the calculation,
418 * declaring it as uint8_t did not do its job.)
419 * @state - ENABLE or DISABLE macro
420 * Retval : None
421 * Note : Reference - Cortex-M4 Devices Generic User Guide
422 * STM32F407xx MCUs use only 4 most significant bits within
423 * each 8-bit section of IPRx. Make sure to account for
424 * this offset when calculating the place to write the
425 * priority.
426 */
427void SPI_IRQPriorityConfig(uint8_t irqNumber, uint32_t irqPriority)
428{
429 /* Find out the IPR register */
430 uint8_t iprNumber = irqNumber / 4;
431 uint8_t iprSection = irqNumber % 4;
432 uint8_t bitOffset = (iprSection * 8) + (8 - NUM_PRI_BITS_USED);
433 *(NVIC_IPR_BASE + iprNumber) |= (irqPriority << bitOffset);
434} /* End of SPI_IRQPriorityConfig */
435
436/**
437 * SPI_IRQHandling()
438 * Brief : Handles SPI interrupt
439 * Param : @pSPIHandle - pointer to SPI handle structure
440 * Retval : None
441 * Note : SPI interrupt event flags (TXE, RXNE, MODF, OVR, CRCERR, FRE)
442 */
443void SPI_IRQHandling(SPI_Handle_TypeDef *pSPIHandle)
444{
445 uint8_t temp1, temp2;
446
447 /* Check for TXE event */
448 temp1 = pSPIHandle->pSPIx->SR & (0x1 << SPI_SR_TXE);
449 temp2 = pSPIHandle->pSPIx->CR2 & (0x1 << SPI_CR2_TXEIE);
450
451 if (temp1 && temp2)
452 {
453 /* Handle TXE interrupt */
454 SPI_TXE_InterruptHandle(pSPIHandle); /* Helper function */
455 }
456
457 /* Check for RXNE event */
458 temp1 = pSPIHandle->pSPIx->SR & (0x1 << SPI_SR_RXNE);
459 temp2 = pSPIHandle->pSPIx->CR2 & (0x1 << SPI_CR2_RXNEIE);
460
461 if (temp1 && temp2)
462 {
463 /* Handle RXNE interrupt */
464 SPI_RXNE_InterruptHandle(pSPIHandle); /* Helper function */
465 }
466
467 /* Check for OVR (overrun) event (OVR flag will be set when receiving data
468 * when Rx buffer is still not empty. In this condition, all the subsequently
469 * received data bytes will be discarded. So, the OVR flag must be cleared.
470 */
471 temp1 = pSPIHandle->pSPIx->SR & (0x1 << SPI_SR_OVR);
472 temp2 = pSPIHandle->pSPIx->CR2 & (0x1 << SPI_CR2_ERRIE);
473
474 if (temp1 && temp2)
475 {
476 /* Handle OVR interrupt */
477 SPI_OVR_InterruptHandle(pSPIHandle); /* Helper function */
478 }
479
480 /* Will not consider MODF, CRCERR events here */
481} /* End of SPI_IRQHandling */
482
483/**
484 * Private helper functions
485 */
486
487/**
488 * SPI_TXE_InterruptHandle()
489 * Brief : Handles TXE interrupt
490 * Param : @pSPIHandle - pointer to SPI handle structure
491 * Retval : None
492 * Note : This is a private helper function and it not intended to be
493 * called by the user application. Thus defined as static function.
494 */
495static void SPI_TXE_InterruptHandle(SPI_Handle_TypeDef *pSPIHandle)
496{
497 /* Check DFF (Data frame format) bit in SPIx_CR1 */
498 if (pSPIHandle->pSPIx->CR1 & (0x1 << SPI_CR1_DFF))
499 {
500 /* 16-bit DFF */
501 /* Load the data into DR */
502 pSPIHandle->pSPIx->DR = *((uint16_t *)(pSPIHandle->pTxBuffer)); /* Make it 16-bit data */
503
504 /* Decrement the length (2 bytes) */
505 pSPIHandle->TxLen--;
506 pSPIHandle->TxLen--;
507
508 /* Adjust the buffer pointer */
509 (uint16_t *)pSPIHandle->pTxBuffer++;
510 }
511 else
512 {
513 /* 8-bit DFF */
514 /* Load the data into DR */
515 pSPIHandle->pSPIx->DR = *(pSPIHandle->pTxBuffer);
516
517 /* Decrement the length (1 byte) */
518 pSPIHandle->TxLen--;
519
520 /* Adjust the buffer pointer */
521 (pSPIHandle->pTxBuffer)++;
522 }
523
524 if (!pSPIHandle->TxLen)
525 {
526 /* TxLen is 0, so close the SPI transmission and inform the application
527 * Tx is over.
528 */
529 SPI_CloseTx(pSPIHandle);
530
531 /* Inform the application */
532 SPI_ApplicationEventCallback(pSPIHandle, SPI_EVENT_TX_CMPLT);
533 /* This callback function must be implemented by the application */
534 }
535} /* End of SPI_TXE_InterruptHandle */
536
537/**
538 * SPI_RXNE_InterruptHandle()
539 * Brief : Handles RXNE interrupt
540 * Param : @pSPIHandle - pointer to SPI handle structure
541 * Retval : None
542 * Note : This is a private helper function and it not intended to be
543 * called by the user application. Thus defined as static function.
544 */
545static void SPI_RXNE_InterruptHandle(SPI_Handle_TypeDef *pSPIHandle)
546{
547 /* Check DFF (Data frame format) bit in SPIx_CR1 */
548 if (pSPIHandle->pSPIx->CR1 & (0x1 << SPI_CR1_DFF))
549 {
550 /* 16-bit DFF */
551 /* Copy the contents of DR into Rx buffer */
552 *((uint16_t*)pSPIHandle->pRxBuffer) = (uint16_t)pSPIHandle->pSPIx->DR;
553
554 /* Decrement the length (2 bytes) */
555 pSPIHandle->RxLen -= 2;
556
557 /* Adjust the buffer pointer */
558 (uint16_t *)(pSPIHandle->pRxBuffer)++;
559 }
560 else
561 {
562 /* 8-bit DFF */
563 /* Copy the contents of DR into Rx buffer */
564 *(pSPIHandle->pRxBuffer) = (uint8_t)pSPIHandle->pSPIx->DR;
565
566 /* Decrement the length (1 byte) */
567 pSPIHandle->RxLen--;
568
569 /* Adjust the buffer pointer */
570 (pSPIHandle->pRxBuffer)++;
571 }
572
573 if (!pSPIHandle->RxLen)
574 {
575 /* TxLen is 0, so close the SPI reception and inform the application
576 * Rx is over.
577 */
578 SPI_CloseRx(pSPIHandle);
579
580 /* Inform the application */
581 SPI_ApplicationEventCallback(pSPIHandle, SPI_EVENT_RX_CMPLT);
582 /* This callback function must be implemented by the application */
583 }
584} /* End of SPI_RXNE_InterruptHandle */
585
586/**
587 * SPI_OVR_InterruptHandle()
588 * Brief : Handles OVR interrupt
589 * Param : @pSPIHandle - pointer to SPI handle structure
590 * Retval : None
591 * Note : This is a private helper function and it not intended to be
592 * called by the user application. Thus defined as static function.
593 */
594static void SPI_OVR_InterruptHandle(SPI_Handle_TypeDef *pSPIHandle)
595{
596 uint8_t temp;
597
598 /* Clear the OVR flag */
599 if (pSPIHandle->TxState != SPI_BUSY_IN_TX)
600 {
601 temp = pSPIHandle->pSPIx->DR;
602 temp = pSPIHandle->pSPIx->SR;
603 }
604 (void)temp;
605 /* In case you need to read data from a variable/register without having to store it,
606 * you can typecast it to void. It will suppress compiler 'unused variable 'warnings.
607 */
608
609 /* Inform the application */
610 SPI_ApplicationEventCallback(pSPIHandle, SPI_EVENT_OVR);
611 /* This callback function must be implemented by the application */
612
613} /* End of SPI_OVR_InterruptHandle */
614
615/**
616 * SPI_ClearOVRFlag
617 * Brief : Clears the OVR flag
618 * Param : @pSPIx - base address of SPIx peripheral
619 * Retval : None
620 * Note : N/A
621 */
622void SPI_ClearOVRFlag(SPI_TypeDef *pSPIx)
623{
624 uint8_t temp;
625
626 temp = pSPIx->DR;
627 temp = pSPIx->SR;
628 (void)temp;
629 /* In case you need to read data from a variable/register without having to store it,
630 * you can typecast it to void. It will suppress compiler 'unused variable 'warnings.
631 */
632} /* SPI_ClearOVRFlag */
633
634/**
635 * SPI_CloseTx()
636 * Brief : Closes Tx operation
637 * Param : @pSPIHandle - pointer to SPI handle structure
638 * Retval : None
639 * Note : Application call this function to abruptly close the SPI communication.
640 */
641void SPI_CloseTx(SPI_Handle_TypeDef *pSPIHandle)
642{
643 /* Disable TXE interrupt */
644 pSPIHandle->pSPIx->CR2 &= ~(0x1 << SPI_CR2_TXEIE);
645
646 /* Reset Tx buffer information and state */
647 pSPIHandle->pTxBuffer = NULL;
648 pSPIHandle->TxLen = 0;
649 pSPIHandle->TxState = SPI_READY;
650} /* End of SPI_CloseTx */
651
652/**
653 * SPI_CloseRx()
654 * Brief : Closes Rx operation
655 * Param : @pSPIHandle - pointer to SPI handle structure
656 * Retval : None
657 * Note : Application call this function to abruptly close the SPI communication.
658 */
659void SPI_CloseRx(SPI_Handle_TypeDef *pSPIHandle)
660{
661 /* Disable RXNE interrupt */
662 pSPIHandle->pSPIx->CR2 &= ~(0x1 << SPI_CR2_RXNEIE);
663
664 /* Reset Rx buffer information and state */
665 pSPIHandle->pRxBuffer = NULL;
666 pSPIHandle->RxLen = 0;
667 pSPIHandle->RxState = SPI_READY;
668} /* End of SPI_CloseRx */
669
670/**
671 * SPI_ApplicationEventCallback()
672 * Brief : Notifies the application of the event occurred
673 * Param : @pSPIHandle - pointer to SPI handle structure
674 * @appEvent - SPI event occurred
675 * Retval : None
676 * Note : This function must be implemented by the application. Since the driver
677 * does not know in which application this function will be implemented,
678 * the driver defines it as a weak function. The application may override
679 * this function.
680 * If the application does not implement this function, the following
681 * definition will be executed.
682 */
683__WEAK void SPI_ApplicationEventCallback(SPI_Handle_TypeDef *pSPIHandle, uint8_t appEvent)
684{
685 /* Intentionally left blank (Application will override this function) */
686} /* End of SPI_ApplicationEventCallback */