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.hPath: Project/Drivers/Inc/
xxxxxxxxxx1721/*******************************************************************************2 * File : stm32f407xx_spi_driver.h3 * Brief : STM32F407xx MCU specific SPI driver header file4 * Author ; Kyungjae Lee5 * Date : May 21, 20236 *7 * Note : This code includes only the features that are necessary for my8 * personal projects.9 * ****************************************************************************/10
111213
1415
16/*******************************************************************************17 * SPIx peripheral structures18 ******************************************************************************/19
20/* SPIx peripheral configuration structure */21typedef struct22{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 struct34{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_ApplicationStatus47 */48495051
52/**53 * @SPI_ApplicationEvents54 */5556575859
60/**61 * @SPI_DeviceMode62 * Note: SPI_CR1 MSTR bit[2] - Master selection63 */646566
67/**68 * @SPI_BusConfig69 */707172//#define SPI_BUS_CONFIG_SIMPLEX_TX_ONLY 2 // Simply removing Rx line = Same config as FD7374
75/**76 * @SPI_CLKSpeed77 * Note: SPI_CR1 BR[5:3] - Baud rate control78 */798081828384858687
88/**89 * @SPI_DFF90 * Note: SPI_CR1 DFF bit[11] - Data frame format/91 */92/* Default */9394
95/**96 * @SPI_CPOL97 * Note: SPI_CR1 CPOL bit[1] - Clock polarity98 */99/* Default */100101
102/**103 * @SPI_CPHA104 * Note: SPI_CR1 CPHA bit[0] - Clock phase105 */106/* Default */107108
109/**110 * @SPI_SSM111 * Note: SPI_CR1 SSM bit[9] - Software slave management112 */113/* Default */114115
116
117/*******************************************************************************118 * APIs supported by the SPI driver119 * (See function definitions for more information)120 ******************************************************************************/121
122/**123 * Peripheral clock setup124 */125void SPI_PeriClockControl(SPI_TypeDef *pSPIx, uint8_t state);126
127/**128 * Init and De-init129 */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 receive135 * - Blocking type: Non-interrupt based136 * - Non-blocking type: interrupt based137 * - 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 greater140 */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 handling149 */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 APIs156 */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 be167 * 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.cPath: Project/Drivers/Src/
xxxxxxxxxx6861/*******************************************************************************2 * File : stm32f407xx_spi_driver.c3 * Brief : STM32F407xx MCU specific SPI driver source file4 * Author ; Kyungjae Lee5 * Date : May 21, 20236 *7 * Note : This code includes only the features that are necessary for my8 * personal projects.9 * ****************************************************************************/10
1112
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 driver20 * (See function definitions for more information)21 ******************************************************************************/22
23/**24 * SPI_PeriClockControl()25 * Brief : Enables or disables peripheral clock for SPIx26 * Param : @pSPIx - base address of SPIx peripheral27 * @state - ENABLE or DISABLE macro28 * Retval : None29 * Note : N/A30 */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 else45 {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 peripheral60 * Param : @pSPIHandle - pointer to the SPI handle structure61 * Retval : None62 * Note : For the serial communication peripherals (e.g., SPI, I2C, ...), there63 * may be64 * - one or more control registers where configurable parameters are stored65 * - one or more data registers where user data is stored66 * - 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 register75 */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 config83 *84 * Full Duplex: BIDIMODE=0, RXONLY=085 * Simplex (unidirectional receive-only): BIDIMODE=0, RXONLY=186 * Half-Duplex, Tx: BIDIMODE=1, BIDIOE=187 * Half-Duplex, Rx: BIDIMODE=1, BIDIOE=088 */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 peripheral129 * Param : @pSPIx - base address of SPIx peripheral130 * Retval : None131 * Note : N/A132 */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 receive148 * - Blocking type: Non-interrupt based149 * - Non-blocking type: interrupt based150 * - 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 greater153 */154
155/**156 * SPI_TxBlocking()157 * Brief : Send from @pSPIx the data of length @len stored in @pTxBuffer158 * Param : @pSPIx - base address of SPIx peripheral159 * @pTxBuffer - address of the Tx buffer160 * @len - length of the data to transmit161 * Retval : None162 * Note : This is a blocking function. This function will not return until163 * 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 else187 {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 @pRxBuffer204 * Param : @pSPIx - base address of SPIx peripheral205 * @pRxBuffer - address of the Rx buffer206 * @len - length of the data to transmit207 * Retval : None208 * Note : This is a blocking function. This function will not return until209 * 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 else233 {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) to250 * transmit data, set TXEIE bit and returns251 * Param : @pSPIHandle - pointer to SPI handle structure252 * @pTxBuffer - address of the Tx buffer253 * @len - length of the data to transmit254 * Retval : Tx state of the application255 * Note : This is a non-blocking function. This function does not write256 * data into the data register. Writing will be taken care of by257 * 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 code270 * 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 flag275 * 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) to288 * receive data, set RXNEIE bit and returns289 * Param : @pSPIHandle - pointer to SPI handle structure290 * @pRxBuffer - address of the Rx buffer291 * @len - length of the data to transmit292 * Retval : Rx state of the application293 * Note : This is a non-blocking function. This function does not read294 * data from the data register. Reading will be taken care of by295 * 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 code308 * 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 flag313 * 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 @pSPIx326 * Param : @pSPIx - base address of SPIx peripheral327 * @state - ENABLE or DISABLE macro328 * Retval : None329 * Note : N/A330 */331void SPI_PeriControl(SPI_TypeDef *pSPIx, uint8_t state)332{333 if (state == ENABLE)334 pSPIx->CR1 |= (0x1 << SPI_CR1_SPE); /* Enable */335 else336 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) bit342 * Param : @pSPIx - base address of SPIx peripheral343 * @state - ENABLE or DISABLE macro344 * Retval : None345 * 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 and347 * 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 else355 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) bit361 * Param : @pSPIx - base address of SPIx peripheral362 * @state - ENABLE or DISABLE macro363 * Retval : None364 * Note : When SSOE = 1, SS output is disabled in master mode and the cell365 * can work in multimaster configuration366 * When SSOE = 0, SS output is enabled in master mode and when the cell367 * 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 else374 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 number381 * @state - ENABLE or DISABLE macro382 * Retval : None383 * Note : Reference - Cortex-M4 Devices Generic User Guide384 * 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 else400 {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 number415 * @irqPriotity - IRQ priority (Make sure this parameter is of416 * type uint32_t. Due to the number of bits it417 * needs to be shifted during the calculation,418 * declaring it as uint8_t did not do its job.)419 * @state - ENABLE or DISABLE macro420 * Retval : None421 * Note : Reference - Cortex-M4 Devices Generic User Guide422 * STM32F407xx MCUs use only 4 most significant bits within423 * each 8-bit section of IPRx. Make sure to account for424 * this offset when calculating the place to write the425 * 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 interrupt439 * Param : @pSPIHandle - pointer to SPI handle structure440 * Retval : None441 * 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 data468 * when Rx buffer is still not empty. In this condition, all the subsequently469 * 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 functions485 */486
487/**488 * SPI_TXE_InterruptHandle()489 * Brief : Handles TXE interrupt490 * Param : @pSPIHandle - pointer to SPI handle structure491 * Retval : None492 * Note : This is a private helper function and it not intended to be493 * 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 else512 {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 application527 * 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 interrupt540 * Param : @pSPIHandle - pointer to SPI handle structure541 * Retval : None542 * Note : This is a private helper function and it not intended to be543 * 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 else561 {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 application576 * 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 interrupt589 * Param : @pSPIHandle - pointer to SPI handle structure590 * Retval : None591 * Note : This is a private helper function and it not intended to be592 * 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_ClearOVRFlag617 * Brief : Clears the OVR flag618 * Param : @pSPIx - base address of SPIx peripheral619 * Retval : None620 * Note : N/A621 */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 operation637 * Param : @pSPIHandle - pointer to SPI handle structure638 * Retval : None639 * 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 operation655 * Param : @pSPIHandle - pointer to SPI handle structure656 * Retval : None657 * 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 occurred673 * Param : @pSPIHandle - pointer to SPI handle structure674 * @appEvent - SPI event occurred675 * Retval : None676 * Note : This function must be implemented by the application. Since the driver677 * does not know in which application this function will be implemented,678 * the driver defines it as a weak function. The application may override679 * this function.680 * If the application does not implement this function, the following681 * 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 */