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
11
14
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 */48
52/**53 * @SPI_ApplicationEvents54 */55
60/**61 * @SPI_DeviceMode62 * Note: SPI_CR1 MSTR bit[2] - Master selection63 */64
67/**68 * @SPI_BusConfig69 */70//#define SPI_BUS_CONFIG_SIMPLEX_TX_ONLY    2   // Simply removing Rx line = Same config as FD73
75/**76 * @SPI_CLKSpeed77 * Note: SPI_CR1 BR[5:3] - Baud rate control78 */79
88/**89 * @SPI_DFF90 * Note: SPI_CR1 DFF bit[11] - Data frame format/91 */92/* Default */93
95/**96 * @SPI_CPOL97 * Note: SPI_CR1 CPOL bit[1] - Clock polarity98 */99/* Default */100
102/**103 * @SPI_CPHA104 * Note: SPI_CR1 CPHA bit[0] - Clock phase105 */106/* Default */107
109/**110 * @SPI_SSM111 * Note: SPI_CR1 SSM bit[9] - Software slave management112 */113/* Default */114
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
11
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 */