351 lines
12 KiB
C
351 lines
12 KiB
C
#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)®->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)®->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仍然为0,TXE为0,延迟2个APB时
|
||
钟周期后发送启动TXE变为1,BSY变为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;
|
||
}
|
||
|