514 lines
13 KiB
C
514 lines
13 KiB
C
/*
|
||
******************************************************************************
|
||
* @file driver_spi_slave.c
|
||
* @author FreqChip Firmware Team
|
||
* @version V1.0.0
|
||
* @date 2021
|
||
* @brief SPI module driver.
|
||
* This file provides firmware functions to manage the
|
||
* Serial Peripheral Interface (SPI) peripheral
|
||
******************************************************************************
|
||
* @attention
|
||
*
|
||
* Copyright (c) 2021 FreqChip.
|
||
* All rights reserved.
|
||
******************************************************************************
|
||
*/
|
||
#include "driver_spi.h"
|
||
|
||
static void spi_slave_tx_u8(SPI_HandleTypeDef *hspi)
|
||
{
|
||
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
|
||
{
|
||
hspi->SPIx->DR = hspi->u_TxData.p_u8[hspi->u32_TxCount++];
|
||
|
||
if (hspi->u32_TxCount >= hspi->u32_TxSize)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void spi_slave_tx_u16(SPI_HandleTypeDef *hspi)
|
||
{
|
||
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
|
||
{
|
||
hspi->SPIx->DR = hspi->u_TxData.p_u16[hspi->u32_TxCount++];
|
||
|
||
if (hspi->u32_TxCount >= hspi->u32_TxSize)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void spi_slave_tx_u32(SPI_HandleTypeDef *hspi)
|
||
{
|
||
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
|
||
{
|
||
hspi->SPIx->DR = hspi->u_TxData.p_u32[hspi->u32_TxCount++];
|
||
|
||
if (hspi->u32_TxCount >= hspi->u32_TxSize)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void spi_slave_rx_u8(SPI_HandleTypeDef *hspi)
|
||
{
|
||
while (!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
|
||
{
|
||
hspi->u_RxData.p_u8[hspi->u32_RxCount++] = hspi->SPIx->DR;
|
||
|
||
if (hspi->u32_RxCount >= hspi->u32_RxSize)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void spi_slave_rx_u16(SPI_HandleTypeDef *hspi)
|
||
{
|
||
while (!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
|
||
{
|
||
hspi->u_RxData.p_u16[hspi->u32_RxCount++] = hspi->SPIx->DR;
|
||
|
||
if (hspi->u32_RxCount >= hspi->u32_RxSize)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void spi_slave_rx_u32(SPI_HandleTypeDef *hspi)
|
||
{
|
||
while (!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
|
||
{
|
||
hspi->u_RxData.p_u32[hspi->u32_RxCount++] = hspi->SPIx->DR;
|
||
|
||
if (hspi->u32_RxCount >= hspi->u32_RxSize)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_IRQHandler
|
||
*
|
||
* @brief Handle SPI interrupt request.
|
||
*
|
||
* @param hspi: SPI handle.
|
||
*/
|
||
void spi_slave_IRQHandler(SPI_HandleTypeDef *hspi)
|
||
{
|
||
uint8_t frame_size;
|
||
/* Tx FIFO Threshold EMPTY */
|
||
if (__SPI_TxFIFO_EMPTY_INT_STATUS(hspi->SPIx))
|
||
{
|
||
frame_size = hspi->Init.Frame_Size;
|
||
|
||
if(frame_size <= SPI_FRAME_SIZE_8BIT)
|
||
{
|
||
spi_slave_tx_u8(hspi);
|
||
}
|
||
else if(frame_size <= SPI_FRAME_SIZE_16BIT)
|
||
{
|
||
spi_slave_tx_u16(hspi);
|
||
}
|
||
else
|
||
{
|
||
spi_slave_tx_u32(hspi);
|
||
}
|
||
|
||
if (hspi->u32_TxCount >= hspi->u32_TxSize)
|
||
{
|
||
__SPI_TxFIFO_EMPTY_INT_DISABLE(hspi->SPIx);
|
||
|
||
hspi->b_TxBusy = false;
|
||
|
||
if (hspi->TxCpltCallback != NULL)
|
||
{
|
||
hspi->TxCpltCallback(hspi);
|
||
}
|
||
}
|
||
}
|
||
/* Rx FIFO Threshold FULL */
|
||
else if (__SPI_RxFIFO_FULL_INT_STATUS(hspi->SPIx))
|
||
{
|
||
frame_size = hspi->Init.Frame_Size;
|
||
|
||
if(frame_size <= SPI_FRAME_SIZE_8BIT)
|
||
{
|
||
spi_slave_rx_u8(hspi);
|
||
}
|
||
else if(frame_size <= SPI_FRAME_SIZE_16BIT)
|
||
{
|
||
spi_slave_rx_u16(hspi);
|
||
}
|
||
else
|
||
{
|
||
spi_slave_rx_u32(hspi);
|
||
}
|
||
|
||
if (hspi->u32_RxCount >= hspi->u32_RxSize)
|
||
{
|
||
__SPI_RxFIFO_FULL_INT_DISABLE(hspi->SPIx);
|
||
|
||
hspi->b_RxBusy = false;
|
||
|
||
if (hspi->RxCpltCallback != NULL)
|
||
{
|
||
hspi->RxCpltCallback(hspi);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_init
|
||
*
|
||
* @brief Initialize the SPI according to the specified parameters in the struct_SPIInit_t
|
||
*
|
||
* @param hspi: SPI handle.
|
||
*/
|
||
void spi_slave_init(SPI_HandleTypeDef *hspi)
|
||
{
|
||
/* Disable SPI, reset FIFO */
|
||
__SPI_DISABLE(hspi->SPIx);
|
||
|
||
/* Work mode */
|
||
hspi->SPIx->CTRL0.SCPOL = hspi->Init.Work_Mode & 0x2 ? 1 : 0;
|
||
hspi->SPIx->CTRL0.SCPH = hspi->Init.Work_Mode & 0x1 ? 1 : 0;
|
||
|
||
/* FIFO Threshold */
|
||
hspi->SPIx->TXFTLR = hspi->Init.TxFIFOEmpty_Threshold;
|
||
hspi->SPIx->RXFTLR = hspi->Init.RxFIFOFull_Threshold;
|
||
|
||
/* Disable all interrupt */
|
||
hspi->SPIx->IMR.MSTIM = 0;
|
||
hspi->SPIx->IMR.TXEIM = 0;
|
||
hspi->SPIx->IMR.TXOIM = 0;
|
||
hspi->SPIx->IMR.RXUIM = 0;
|
||
hspi->SPIx->IMR.RXOIM = 0;
|
||
hspi->SPIx->IMR.RXFIM = 0;
|
||
|
||
__SPI_CS_TOGGLE_DISABLE(hspi->SPIx);
|
||
|
||
/* CS Set */
|
||
hspi->SPIx->SER = 0;
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_transmit
|
||
*
|
||
* @brief Send an amount of data in blocking mode.(Standard<72><64>Dual and Quad mode)
|
||
*
|
||
* @param hspi: SPI handle.
|
||
* fp_Data: pointer to data buffer
|
||
* fu32_Size: amount of data to be sent
|
||
*/
|
||
void spi_slave_transmit(SPI_HandleTypeDef *hspi, void *fp_Data, uint32_t fu32_Size)
|
||
{
|
||
uint8_t frame_size;
|
||
union {
|
||
void *data;
|
||
uint8_t *p_u8;
|
||
uint16_t *p_u16;
|
||
uint32_t *p_u32;
|
||
} p_data;
|
||
|
||
p_data.data = fp_Data;
|
||
|
||
/* config Mult Write Transfer parameters */
|
||
spi_slave_MultWireConfig(hspi,Wire_Write);
|
||
|
||
/* Get current frame size */
|
||
frame_size = hspi->Init.Frame_Size;
|
||
|
||
/* Frame Size <= 8 */
|
||
if (frame_size <= SPI_FRAME_SIZE_8BIT)
|
||
{
|
||
while (fu32_Size--)
|
||
{
|
||
while(__SPI_IS_TxFIFO_FULL(hspi->SPIx));
|
||
/* write data to tx FIFO */
|
||
hspi->SPIx->DR = *p_data.p_u8++;
|
||
}
|
||
}
|
||
else if(frame_size <= SPI_FRAME_SIZE_16BIT)
|
||
{
|
||
while (fu32_Size--)
|
||
{
|
||
while(__SPI_IS_TxFIFO_FULL(hspi->SPIx));
|
||
/* write data to tx FIFO */
|
||
hspi->SPIx->DR = *p_data.p_u16++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
while(fu32_Size--)
|
||
{
|
||
while(__SPI_IS_TxFIFO_FULL(hspi->SPIx));
|
||
/* write data to tx FIFO */
|
||
hspi->SPIx->DR = *p_data.p_u32++;
|
||
}
|
||
}
|
||
|
||
while(__SPI_IS_BUSY(hspi->SPIx));
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_transmit_IT
|
||
*
|
||
* @brief Send an amount of data in interrupt mode.(Standard<72><64>Dual and Quad mode)
|
||
*
|
||
* @param hspi: SPI handle.
|
||
* fp_Data: pointer to data buffer
|
||
* fu32_Size: amount of data to be sent
|
||
*/
|
||
void spi_slave_transmit_IT(SPI_HandleTypeDef *hspi, void*fp_Data, uint32_t fu32_Size)
|
||
{
|
||
if (hspi->b_TxBusy)
|
||
return;
|
||
uint8_t frame_size;
|
||
|
||
/* config Mult Write Transfer parameters */
|
||
spi_slave_MultWireConfig(hspi,Wire_Write);
|
||
|
||
hspi->u32_TxSize = fu32_Size;
|
||
hspi->u32_TxCount = 0;
|
||
hspi->b_TxBusy = true;
|
||
hspi->u_TxData.p_data = fp_Data;
|
||
|
||
/* Get current frame size */
|
||
frame_size = hspi->Init.Frame_Size;
|
||
|
||
if (frame_size <= SPI_FRAME_SIZE_8BIT)
|
||
{
|
||
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
|
||
{
|
||
hspi->SPIx->DR = hspi->u_TxData.p_u8[hspi->u32_TxCount++];
|
||
|
||
if (hspi->u32_TxCount >= fu32_Size)
|
||
{
|
||
hspi->b_TxBusy = false;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
else if (frame_size <= SPI_FRAME_SIZE_16BIT)
|
||
{
|
||
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
|
||
{
|
||
hspi->SPIx->DR = hspi->u_TxData.p_u16[hspi->u32_TxCount++];
|
||
|
||
if (hspi->u32_TxCount >= fu32_Size)
|
||
{
|
||
hspi->b_TxBusy = false;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
while(!__SPI_IS_TxFIFO_FULL(hspi->SPIx))
|
||
{
|
||
hspi->SPIx->DR = hspi->u_TxData.p_u32[hspi->u32_TxCount++];
|
||
|
||
if (hspi->u32_TxCount >= fu32_Size)
|
||
{
|
||
hspi->b_TxBusy = false;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* TxFIFO empty interrupt enable */
|
||
__SPI_TxFIFO_EMPTY_INT_ENABLE(hspi->SPIx);
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_transmit_DMA
|
||
*
|
||
* @brief Send an amount of data in DMA mode.(Standard<72><64>Dual and Quad mode)
|
||
*
|
||
* @param hspi: SPI handle.
|
||
*/
|
||
void spi_slave_transmit_DMA(SPI_HandleTypeDef *hspi)
|
||
{
|
||
/* config Mult Write Transfer parameters */
|
||
spi_slave_MultWireConfig(hspi,Wire_Write);
|
||
|
||
/* DMA Config */
|
||
__SPI_DMA_TX_ENABLE(hspi->SPIx);
|
||
__SPI_DMA_TX_LEVEL(hspi->SPIx, hspi->Init.TxFIFOEmpty_Threshold);
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_receive
|
||
*
|
||
* @brief Receive an amount of data in blocking mode.(Standard<72><64>Dual and Quad mode)
|
||
*
|
||
* @param hspi: SPI handle.
|
||
* fp_Data: pointer to data buffer
|
||
* fu32_Size: amount of data to be Receive
|
||
*/
|
||
void spi_slave_receive(SPI_HandleTypeDef *hspi, void *fp_Data, uint32_t fu32_Size)
|
||
{
|
||
uint8_t frame_size;
|
||
union {
|
||
void *data;
|
||
uint8_t *p_u8;
|
||
uint16_t *p_u16;
|
||
uint32_t *p_u32;
|
||
} p_data;
|
||
|
||
p_data.data = fp_Data;
|
||
|
||
/* config Mult Read Transfer parameters */
|
||
spi_slave_MultWireConfig(hspi,Wire_Read);
|
||
|
||
/* Get current frame size */
|
||
frame_size = hspi->Init.Frame_Size;
|
||
|
||
/* Frame Size <= 8 */
|
||
if (frame_size <= SPI_FRAME_SIZE_8BIT)
|
||
{
|
||
|
||
while (fu32_Size)
|
||
{
|
||
while(!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
|
||
{
|
||
*p_data.p_u8++ = hspi->SPIx->DR;
|
||
|
||
fu32_Size--;
|
||
}
|
||
}
|
||
}
|
||
else if (frame_size <= SPI_FRAME_SIZE_16BIT)
|
||
{
|
||
while (fu32_Size)
|
||
{
|
||
while(!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
|
||
{
|
||
*p_data.p_u16++ = hspi->SPIx->DR;
|
||
|
||
fu32_Size--;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
while (fu32_Size)
|
||
{
|
||
while(!__SPI_IS_RxFIFO_EMPTY(hspi->SPIx))
|
||
{
|
||
*p_data.p_u32++ = hspi->SPIx->DR;
|
||
|
||
fu32_Size--;
|
||
}
|
||
}
|
||
}
|
||
|
||
while(__SPI_IS_BUSY(hspi->SPIx));
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_receive_IT
|
||
*
|
||
* @brief Receive an amount of data in interrupt mode.(Standard<72><64>Dual and Quad mode)
|
||
*
|
||
* @param hspi: SPI handle.
|
||
* fp_Data: pointer to data buffer
|
||
* fu32_Size: amount of data to be Receive
|
||
*/
|
||
void spi_slave_receive_IT(SPI_HandleTypeDef *hspi, void *fp_Data, uint32_t fu32_Size)
|
||
{
|
||
if (hspi->b_RxBusy)
|
||
return;
|
||
|
||
/* config Mult Read Transfer parameters */
|
||
spi_slave_MultWireConfig(hspi,Wire_Read);
|
||
|
||
hspi->u32_RxSize = fu32_Size;
|
||
hspi->u32_RxCount = 0;
|
||
hspi->b_RxBusy = true;
|
||
hspi->u_RxData.p_data = fp_Data;
|
||
|
||
/* RxFIFO full interrupt enable */
|
||
__SPI_RxFIFO_FULL_INT_ENABLE(hspi->SPIx);
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_receive_DMA
|
||
*
|
||
* @brief Receive an amount of data in interrupt mode.(Standard<72><64>Dual and Quad mode)
|
||
*
|
||
* @param hspi: SPI handle.
|
||
* fp_Data: pointer to data buffer
|
||
* fu32_Size: amount of data to be Receive
|
||
*/
|
||
void spi_slave_receive_DMA(SPI_HandleTypeDef *hspi)
|
||
{
|
||
/* config Mult Read Transfer parameters */
|
||
spi_slave_MultWireConfig(hspi,Wire_Read);
|
||
|
||
/* DMA Config */
|
||
__SPI_DMA_RX_ENABLE(hspi->SPIx);
|
||
__SPI_DMA_RX_LEVEL(hspi->SPIx, hspi->Init.RxFIFOFull_Threshold);
|
||
}
|
||
|
||
/************************************************************************************
|
||
* @fn spi_slave_MultWireConfig
|
||
*
|
||
* @brief config Mult Wire Transfer parameters.(DualbQuad mode)
|
||
*
|
||
* @param hspi: SPI handle.
|
||
*/
|
||
void spi_slave_MultWireConfig(SPI_HandleTypeDef *hspi, enum_Wire_Type_t fe_type)
|
||
{
|
||
/* Disable SPI, reset FIFO */
|
||
__SPI_DISABLE(hspi->SPIx);
|
||
|
||
/* slave mode and Frame Size*/
|
||
if (hspi->MultWireParam.Wire_X2X4X8 == Wire_X2)
|
||
{
|
||
__SPI_SLAVE_SET_MODE_X2(hspi->SPIx);
|
||
|
||
hspi->SPIx->CTRL0.DFS_32 = (hspi->Init.Frame_Size + 1) / 2 - 1;
|
||
}
|
||
else if (hspi->MultWireParam.Wire_X2X4X8 == Wire_X4)
|
||
{
|
||
__SPI_SLAVE_SET_MODE_X4(hspi->SPIx);
|
||
|
||
hspi->SPIx->CTRL0.DFS_32 = (hspi->Init.Frame_Size + 1) / 4 - 1;
|
||
}
|
||
else
|
||
{
|
||
__SPI_SLAVE_SET_MODE_X1(hspi->SPIx);
|
||
hspi->SPIx->CTRL0.DFS_32 = hspi->Init.Frame_Size;
|
||
}
|
||
|
||
if (fe_type == Wire_Write)
|
||
{
|
||
/* slave output enable */
|
||
hspi->SPIx->CTRL0.SLV_OE = 0;
|
||
|
||
/* Select Only Tx mode */
|
||
__SPI_TMODE_Tx_ONLY(hspi->SPIx);
|
||
}
|
||
else
|
||
{
|
||
/* slave output disable */
|
||
hspi->SPIx->CTRL0.SLV_OE = 1;
|
||
|
||
/* Select Only Rx mode */
|
||
__SPI_TMODE_Rx_ONLY(hspi->SPIx);
|
||
}
|
||
|
||
/* Enable SPI */
|
||
__SPI_ENABLE(hspi->SPIx);
|
||
}
|