bs_bcu_app/drv/drv_stm32f4xx/drv_spi.c

351 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "drv_clk.h"
#include "drv_spi.h"
#include "drv_dma.h"
#include "drv_gpio.h"
#include "kit_debug.h"
#define SPI_SYNC_TIMEOUT (2550u)
#define CR1_SPI_EN ((uint16_t)0x0040)
#define SPI_NSS_Soft ((uint16_t)0x0200)
#define SPI_Mode_Master ((uint16_t)0x0104)
#define SPI_Direction_1Line_Tx ((uint16_t)0xC000)
#define SPI_I2S_DMAReq_Tx ((uint16_t)0x0002)
#define SPI_I2S_DMAReq_Rx ((uint16_t)0x0001)
#define SPI_I2S_FLAG_TXE ((uint16_t)0x0002)
#define SPI_I2S_FLAG_BSY ((uint16_t)0x0080)
#define SPI_I2S_FLAG_RXNE ((uint16_t)0x0001)
#define GPIO_REMAP_SPI1 ((uint32_t)0x00000001)
#define GPIO_REMAP_SPI3 ((uint32_t)0x10000000)
typedef struct
{
DmaStream rx_dma_stream;
DmaStream tx_dma_stream;
DmaChannel dma_channel;
SPI_TypeDef *reg;
}Stm32SpiProp;
static KitResult drv_spi_set_clock_gpio(SpiDev dev, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx);
static const Stm32SpiProp stm32_spi[kSpiDev_End] =
{
{kDma2Stream_2, kDma2Stream_3, kDmaChannel_3, SPI1},
{kDma1Stream_3, kDma1Stream_4, kDmaChannel_0, SPI2},
{kDma2Stream_0, kDma2Stream_5, kDmaChannel_0, SPI3}
};
/********************************************************************************
Func SPI1_REMAP = 0 SPI1_REMAP = 1 SPI3_REMAP = 0 SPI3_REMAP = 1
SPI_SCK PA5 PB3 PB3 PC10
SPI_MISO PA6 PB4 PB4 PC11
SPI_MOSI PA7 PB5 PB5 PC12
APB1频率 = 168M/4 = 42M
APB2频率 = 168M/2 = 84M
********************************************************************************/
static KitResult drv_spi_set_clock_gpio(SpiDev dev, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx)
{
KitResult res = kKitResult_Ok;
uint32_t sck_io = drv_gpio_get_actual_io(sck_idx);
uint32_t miso_io = drv_gpio_get_actual_io(miso_idx);
uint32_t mosi_io = drv_gpio_get_actual_io(mosi_idx);
switch (dev)
{
case kSpiDev_1:
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
res |= drv_clk_set_status(kBspClk_APB2, RCC_APB2Periph_SPI1);
if((sck_io == GPIO_PORT_PIN(kGpioPort_A, 5)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_A, 7)))
{
drv_gpio_set_af(kGpioPort_A, 5, 5);
drv_gpio_set_af(kGpioPort_A, 7, 5);
if(miso_io == GPIO_PORT_PIN(kGpioPort_A, 6))
{
drv_gpio_set_af(kGpioPort_A, 6, 5);
}
}
else if((sck_io == GPIO_PORT_PIN(kGpioPort_B, 3)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 5)))
{
drv_gpio_set_af(kGpioPort_B, 3, 5);
drv_gpio_set_af(kGpioPort_B, 5, 5);
if(miso_io == GPIO_PORT_PIN(kGpioPort_B, 4))
{
drv_gpio_set_af(kGpioPort_B, 4, 5);
}
}
else if((sck_io == GPIO_PORT_PIN(kGpioPort_A, 5)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 5)))
{
drv_gpio_set_af(kGpioPort_A, 5, 5);
drv_gpio_set_af(kGpioPort_B, 5, 5);
if(miso_io == GPIO_PORT_PIN(kGpioPort_A, 6))
{
drv_gpio_set_af(kGpioPort_A, 6, 5);
}
}
else
{
res |= kKitResult_ParamErr;
}
break;
case kSpiDev_2:
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
if((sck_io == GPIO_PORT_PIN(kGpioPort_B, 13)) || (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 15)))
{
drv_gpio_set_af(kGpioPort_B, 13, 5);
drv_gpio_set_af(kGpioPort_B, 15, 5);
if(miso_io == GPIO_PORT_PIN(kGpioPort_B, 14))
{
drv_gpio_set_af(kGpioPort_B, 14, 5);
}
}
#if defined(STM32F429_439xx)
else if((sck_io == GPIO_PORT_PIN(kGpioPort_D, 3)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_C, 3)))
{
drv_gpio_set_af(kGpioPort_D, 3, 5);
drv_gpio_set_af(kGpioPort_C, 3, 5);
if(miso_io == GPIO_PORT_PIN(kGpioPort_C, 2))
{
drv_gpio_set_af(kGpioPort_C, 2, 5);
}
}
#endif
else
{
res |= kKitResult_ParamErr;
}
break;
case kSpiDev_3:
RCC->APB1ENR |= RCC_APB1ENR_SPI3EN;
if((sck_io == GPIO_PORT_PIN(kGpioPort_B, 3)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_B, 5)))
{
drv_gpio_set_af(kGpioPort_B, 3, 6);
drv_gpio_set_af(kGpioPort_B, 5, 6);
if(miso_io == GPIO_PORT_PIN(kGpioPort_B, 4))
{
drv_gpio_set_af(kGpioPort_B, 4, 6);
}
}
else if((sck_io == GPIO_PORT_PIN(kGpioPort_C, 10)) && (mosi_io == GPIO_PORT_PIN(kGpioPort_C, 12)))
{
drv_gpio_set_af(kGpioPort_C, 10, 6);
drv_gpio_set_af(kGpioPort_C, 12, 6);
if(miso_io == GPIO_PORT_PIN(kGpioPort_C, 11))
{
drv_gpio_set_af(kGpioPort_C, 11, 6);
}
}
else
{
res = kKitResult_ParamErr;
}
break;
default:
res = kKitResult_ParamErr;
break;
}
return res;
}
/*******************重要寄存器默认值*******************
*SPI_CR1-BIDIMODE(15) 默认“双线双向”模式
*SPI_CR1-DFF(11) 默认8位数据帧格式
*SPI_CR1-SSM(9) 默认硬件控制CS
*SPI_CR1-LSBFIRST(7) 默认先发送MSB
*spi1 时钟源位APB2 速度= CLOCK_APB2_FREQ/Divx
*TXE置位表示数据数据从发送缓冲器传输到移位寄存器,并不一定发送完成
*RXNE置位表示移位寄存器中接收到的数据字被传送到接收缓冲器
********************************************************/
#define SPI_CR1_FRF KIT_CREAT_BIT(4)
KitResult drv_spi_init(SpiDev dev, SpiFreq freq, SpiMode mode, SpiFrame spi_frame, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx)
{
uint16_t cr1;
KitResult res;
KIT_ASSERT_PARAM((dev < kSpiDev_End) && (freq < kSpiFreq_End) && (mode < kSpiMode_End) && (spi_frame < SpiFrame_End));
res = drv_spi_set_clock_gpio(dev, sck_idx, miso_idx, mosi_idx);
if(res == kKitResult_Ok)
{
cr1 = stm32_spi[dev].reg->CR1;
cr1 |= freq << 3;
cr1 |= (mode | (spi_frame << 7));
//主机模式 cs软件控制 8位数据
cr1 |= (SPI_NSS_Soft | SPI_Mode_Master | CR1_SPI_EN);
if(miso_idx == NULL)
cr1 |= SPI_Direction_1Line_Tx;
stm32_spi[dev].reg->CR1 = cr1;
}
KIT_ASSERT_RES(dev, res);
return res;
}
KitResult drv_spi_init1(SpiDev dev, SpiFreq freq, uint32_t spi_config, uint16_t sck_idx, uint16_t miso_idx, uint16_t mosi_idx)
{
uint16_t cr1;
KitResult res;
KIT_ASSERT_PARAM((dev < kSpiDev_End) && (freq < kSpiFreq_End));
res = drv_spi_set_clock_gpio(dev, sck_idx, miso_idx, mosi_idx);
if(res == kKitResult_Ok)
{
cr1 = freq << 3;
cr1 |= (uint16_t)spi_config;
stm32_spi[dev].reg->CR1 |= cr1;
stm32_spi[dev].reg->CR2 |= (spi_config >> 16);
}
KIT_ASSERT_RES(dev, res);
return res;
}
KitResult drv_spi_set_dma(SpiDev dev, bool is_rx_en, bool is_tx_en)
{
uint16_t cr2;
KitResult res;
SPI_TypeDef *reg;
KIT_ASSERT_PARAM(dev < kSpiDev_End);
if(dev < kSpiDev_End)
{
reg = stm32_spi[dev].reg;
cr2 = reg->CR2;
if(is_rx_en == true)
{
drv_dma_init(stm32_spi[dev].rx_dma_stream, stm32_spi[dev].dma_channel, DMA_CFG_DATA_DIR_P2M|DMA_CFG_CYCLE_NONE|DMA_CFG_DATA_M_I|DMA_CFG_DATA_P_N|DMA_CFG_DATA_LEN_1B, (uint32_t)&reg->DR);
cr2 |= SPI_I2S_DMAReq_Rx;
}
else
cr2 &= ~SPI_I2S_DMAReq_Rx;
if(is_tx_en == true)
{
drv_dma_init(stm32_spi[dev].tx_dma_stream, stm32_spi[dev].dma_channel, DMA_CFG_DATA_DIR_M2P|DMA_CFG_CYCLE_NONE|DMA_CFG_DATA_M_I|DMA_CFG_DATA_P_N|DMA_CFG_DATA_LEN_1B, (uint32_t)&reg->DR);
cr2 |= SPI_I2S_DMAReq_Tx;
}
else
cr2 &= ~SPI_I2S_DMAReq_Tx;
reg->CR2 = cr2;
res = kKitResult_Ok;
}
else
{
res = kKitResult_OutRange;
}
return res;
}
/********************************************************************
向DR写数据后SPI并不会立即启动发送此时BSY仍然为0TXE为0延迟2个APB时
钟周期后发送启动TXE变为1BSY变为1等到数据发送完成BSY再变为0
**********************************************************************/
//发送一个字节
KitResult drv_spi_sync_send_receive(SpiDev dev, uint8_t *data)
{
KitResult res = kKitResult_Ok;
SPI_TypeDef *reg;
int32_t timeout = 0;
KIT_ASSERT_PARAM((dev < kSpiDev_End) && (data != NULL));
reg = stm32_spi[dev].reg;
//send data
while((reg->SR & SPI_I2S_FLAG_TXE) == 0)
{
if(timeout++ >= SPI_SYNC_TIMEOUT)
{
return kKitResult_TimeOut;
}
}
reg->DR = *data;
timeout = 0;
//recved data
while((reg->SR & (SPI_I2S_FLAG_RXNE | SPI_I2S_FLAG_BSY)) != SPI_I2S_FLAG_RXNE)
{
if(timeout++ >= SPI_SYNC_TIMEOUT)
{
res = kKitResult_TimeOut;
break;
}
}
*data = reg->DR;
return res;
}
//读写多个字节
KitResult drv_spi_series_sync_send_receive(SpiDev dev, uint8_t *tx_buf, uint16_t tx_len, uint8_t *rx_buf, uint16_t rx_len)
{
uint32_t i;
KitResult res = kKitResult_Ok;
KIT_ASSERT_PARAM(dev < kSpiDev_End);
KIT_ASSERT_PARAM(((tx_buf == NULL) && (tx_len == 0)) || ((tx_buf != NULL) && (tx_len > 0)));
KIT_ASSERT_PARAM(((rx_buf == NULL) && (rx_len == 0)) || ((rx_buf != NULL) && (rx_len > 0)));
//send
for(i = 0; i < tx_len; i++)
res |= drv_spi_sync_send_receive(dev, tx_buf + i);
//receive
for(i = 0; i < rx_len; i++)
res |= drv_spi_sync_send_receive(dev, rx_buf + i);
return res;
}
KitResult drv_spi_dma_sync_send(SpiDev dev, uint8_t *tx_buf, uint16_t tx_len)
{
KitResult res;
KIT_ASSERT_PARAM(dev < kSpiDev_End);
KIT_ASSERT_PARAM(((tx_buf == NULL) && (tx_len == 0)) || ((tx_buf != NULL) && (tx_len > 0)));
//接收前读一次SPI2->DR保证接收缓冲区为空
stm32_spi[dev].reg->DR;
res = kit_wait_flag((volatile uint32_t *)&stm32_spi[dev].reg->SR, SPI_I2S_FLAG_TXE, SPI_SYNC_TIMEOUT);
if(res == kKitResult_Ok)
{
res = drv_dma_send(stm32_spi[dev].tx_dma_stream, tx_buf, tx_len);
}
return res;
}
KitResult drv_spi_dma_sync_receive(SpiDev dev, uint8_t *rx_buf, uint16_t rx_len)
{
KitResult res;
KIT_ASSERT_PARAM(dev < kSpiDev_End);
KIT_ASSERT_PARAM(((rx_buf == NULL) && (rx_len == 0)) || ((rx_buf != NULL) && (rx_len > 0)));
//接收前读一次SPI2->DR保证接收缓冲区为空
stm32_spi[dev].reg->DR;
res = kit_wait_flag((volatile uint32_t *)&stm32_spi[dev].reg->SR, SPI_I2S_FLAG_TXE, SPI_SYNC_TIMEOUT);
if(res == kKitResult_Ok)
{
res = drv_dma_receive(stm32_spi[dev].rx_dma_stream, stm32_spi[dev].tx_dma_stream, rx_buf, rx_len);
}
return res;
}