#include "spi.h"

uint8_t spi1_rec_buf[SPI1_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
uint8_t spi1_tx_buf[SPI1_TX_LEN];   // 发送缓冲区
uint8_t spi1_rec_cnt;
uint8_t spi1_rec_flag = 0; // spi1接收标志位

void SPI1DMA_Enable(DMA_Stream_TypeDef *DMA_Streamx, uint16_t count)
{
    DMA_Cmd(DMA_Streamx, DISABLE); //关闭DMA传输
    while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE)
    {
    } //确保DMA可以被设置

    DMA_SetCurrDataCounter(DMA_Streamx, count); //数据传输量
    DMA_Cmd(DMA_Streamx, ENABLE);               //开启DMA传输
}

void spi1_config(void)
{
    /* 硬件SPI */
    SPI_InitTypeDef SPI_InitStructure;

    /* 配置SPI硬件参数*/
    SPI_InitStructure.SPI_Direction         = SPI_Direction_2Lines_FullDuplex; // 2线全双工
    SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;                 //主机模式
    SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;                 // 8位
    SPI_InitStructure.SPI_CPOL              = SPI_CPOL_High;                   //	时钟上升沿采样数据
    SPI_InitStructure.SPI_CPHA              = SPI_CPHA_2Edge;                  //	时钟的第2个边沿采样数据
    SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;                    // 片选控制方式 软件控制
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;        // 设置波特率预分频系数  实测SCK周期800ns  12.5MHz
    SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;                // 数据位传输次序 高位先传
    SPI_InitStructure.SPI_CRCPolynomial     = 7;                               // CRC多项式寄存器 本例不用
    SPI_Init(SPI1, &SPI_InitStructure);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
}

void spi1_dma_config(void)
{
    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // DMA2时钟使能

    DMA_DeInit(SPI1_DMA_TXCH);

    while (DMA_GetCmdStatus(SPI1_DMA_TXCH) != DISABLE)
        ; //等待DMA可配置

    /* 配置 DMA Stream */
    DMA_InitStructure.DMA_Channel            = SPI1_DMA;                   //通道选择
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;        // DMA外设地址
    DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)spi1_tx_buf;      // DMA 存储器0地址
    DMA_InitStructure.DMA_DIR                = DMA_DIR_MemoryToPeripheral; //存储器到外设模式

    DMA_InitStructure.DMA_BufferSize         = SPI1_TX_LEN;                 //数据传输量
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;   //外设非增量模式
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;        //存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;     //存储器数据长度:8位
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;             // 使用普通模式

    DMA_InitStructure.DMA_Priority        = DMA_Priority_Medium; //中等优先级6
    DMA_InitStructure.DMA_FIFOMode        = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold   = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst     = DMA_MemoryBurst_Single;     //存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
    DMA_Init(SPI1_DMA_TXCH, &DMA_InitStructure);                        //初始化DMA Stream

    DMA_DeInit(SPI1_DMA_RXCH);

    while (DMA_GetCmdStatus(SPI1_DMA_RXCH) != DISABLE)
        ; //等待DMA可配置
    /* 配置 DMA Stream */
    DMA_InitStructure.DMA_Channel            = SPI1_DMA;                   //通道选择
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;        // DMA外设地址
    DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)spi1_rec_buf;     // DMA 存储器0地址
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralToMemory; //外设到存储器模式

    DMA_InitStructure.DMA_BufferSize         = SPI1_REC_LEN;                //数据传输量
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;   //外设非增量模式
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;        //存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;     //存储器数据长度:8位
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;           // 使用循环模式

    DMA_InitStructure.DMA_Priority        = DMA_Priority_Medium; //中等优先级
    DMA_InitStructure.DMA_FIFOMode        = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold   = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst     = DMA_MemoryBurst_Single;     //存储器突发单次传输
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
    DMA_Init(SPI1_DMA_RXCH, &DMA_InitStructure);                        //初始化DMA Stream
}

void spi1_init(void)
{

    spi1_config();

    spi1_dma_config();

    SPI_Cmd(SPI1, ENABLE); //  使能SPI

    SPI_I2S_ClearITPendingBit(SPI1, SPI_I2S_IT_RXNE);
}

void SPI1DMA_Trans(const uint8_t *data, uint16_t count)
{
    DMA_Cmd(SPI1_DMA_RXCH, DISABLE);
    DMA_Cmd(SPI1_DMA_TXCH, DISABLE);
    DMA_SetCurrDataCounter(SPI1_DMA_RXCH, count);
    DMA_SetCurrDataCounter(SPI1_DMA_TXCH, count);
    SPI1->DR;
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
        ;
    DMA_Cmd(SPI1_DMA_RXCH, ENABLE);
    DMA_Cmd(SPI1_DMA_TXCH, ENABLE);
    while (DMA_GetFlagStatus(SPI1_DMA_RXCH, DMA_FLAG_TCIF2) != RESET)
        ;
    while (DMA_GetFlagStatus(SPI1_DMA_TXCH, DMA_FLAG_TCIF3) != RESET)
        ;
    DMA_Cmd(SPI1_DMA_RXCH, DISABLE);
    DMA_Cmd(SPI1_DMA_TXCH, DISABLE);
    DMA_ClearFlag(SPI1_DMA_RXCH, DMA_FLAG_TCIF2);
    DMA_ClearFlag(SPI1_DMA_TXCH, DMA_FLAG_TCIF3);
}
