stm32 从机SPI DMA接收,从机一开DMA就进完成中断,上代码

2019-12-15 12:12发布

stm32 从机SPI DMA接收,从机一开DMA就进完成中断,   我采用SPI1为主机接到芯片上SPI2从机,进行自测试,  我在主机没有发任何数据情况下, 开启从机SPI2接收DMA, 立即就进入了DMA接收完成中断!收到的数据全是00,  在主机不发送情况, 无论从机单独开发送DMA 还是接收DMA都直接进入完成中断!   

int main()
{
        u8 data1[6]={17,17,17,17,17,17};
        u8 data2[6]={0x00,0xFF,0x01,0x03,0x05,0x09};
        RCC_HSE_Config(25,336,2,7); //将pllp=2修改为4,相当于把168M的系统时钟变为84M了
        SysTick_Init(168);
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组 4个抢占 4个软件

        SPI1_DMA_Master_Init();
        SPI2_DMA_Master_Init();
       
       
       
        while(1)
        {

                SPI2_DMA_Send(data1 ,6);
//                SPI1_DMA_Send(data2 ,6);

                delay_ms(1000);

        }


/*******************************************************************************
**** 文件功能: SPI通信 DMA收发 初始化
**** 备    注:
*******************************************************************************
*******************************************************************************/
#include "spi.h"

SPI_Init_Parm SPI1_Parm;   //SPI1参数
SPI_Init_Parm SPI2_Parm;   //SPI2参数

//以下是SPI模块的初始化代码,配置成主机模式                                                   
//SPI口初始化
//这里针是对SPI1的初始化
void SPI2_Init(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1时钟
       
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3复用为 SPI1
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4复用为 SPI1
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5复用为 SPI1
       
        //GPIOFB3,4,5初始化设置
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5复用功能输出       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
       
        //这里只针对SPI口初始化
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //设置SPI工作模式:设置为主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                //设置SPI的数据大小:SPI发送接收8位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                //串行同步时钟的空闲状态为高电平
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;                //定义波特率预分频的值:波特率预分频值为256
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
        SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

        SPI_Cmd(SPI1, ENABLE); //使能SPI外设
       
        SPI1_ReadWriteByte(0xff);//启动传输       
}

void SPI1_DMA_Master_Init(void)        //初始化SPI1作为主机口采用DMA收发
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;
        DMA_InitTypeDef  DMA_InitStructure;   
        NVIC_InitTypeDef NVIC_InitStructure;
       
        //初始SPI1 Parm
        SPI1_Parm.DMA_TxBuff_Len = sizeof(SPI1_Parm.Send_Buff);  //SPI发送缓冲区大小      
        SPI1_Parm.DMA_RxBuff_Len = sizeof(SPI1_Parm.Recv_Buff);  //SPI接收缓冲区大小   
        SPI1_Parm.Flag_Tx_Busy=0;      //SPI正在发送
        SPI1_Parm.Flag_New_Recv=0;     //是否收到新数据
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOB时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1时钟
       
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_SPI1); //引脚复用为 SPI1
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_SPI1); //
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_SPI1); //
       
        //GPIOFA5,6,7初始化设置
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//复用功能输出       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
       
        //这里只针对SPI口初始化
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //设置SPI工作模式:设置为主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                //设置SPI的数据大小:SPI发送接收8位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                //串行同步时钟的空闲状态为高电平
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;                //定义波特率预分频的值:波特率预分频值为256
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
        SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
        SPI_NSSInternalSoftwareConfig(SPI1,SPI_NSSInternalSoft_Set);

  //设置SPI1 接收DMA Stream    流2为接收 通道3
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
  DMA_DeInit(DMA2_Stream2);
        while (DMA_GetCmdStatus(DMA2_Stream2) != DISABLE){}//等待DMA可配置
        DMA_InitStructure.DMA_Channel = DMA_Channel_3;  //通道选择
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI1->DR;//DMA外设地址
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SPI1_Parm.Recv_Buff;//DMA 存储器0地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//存储器到外设模式
        DMA_InitStructure.DMA_BufferSize = SPI1_Parm.DMA_RxBuff_Len;//数据传输量
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式, 递增模式就是每传输一个地址加1
        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_High;//优先级
        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(DMA2_Stream2, &DMA_InitStructure);//初始化DMA Stream
        DMA_Cmd(DMA2_Stream2, DISABLE);  
          //DMA接收中断优先级配置
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
        DMA_ITConfig(DMA2_Stream2,DMA_IT_TC | DMA_IT_TE,ENABLE); //开启 DMA接收完成中断       
               
        //设置SPI1 发送DMA Stream  ,流3为发送 通道3
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
  DMA_DeInit(DMA2_Stream3);
        while (DMA_GetCmdStatus(DMA2_Stream3) != DISABLE){}//等待DMA可配置
        DMA_InitStructure.DMA_Channel = DMA_Channel_3;  //通道选择
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI1->DR;//DMA外设地址
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SPI1_Parm.Send_Buff;//DMA 存储器0地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式
        DMA_InitStructure.DMA_BufferSize = SPI1_Parm.DMA_TxBuff_Len;//数据传输量
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式, 递增模式就是每传输一个地址加1
        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_High;//优先级
        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(DMA2_Stream3, &DMA_InitStructure);//初始化DMA Stream
        DMA_Cmd(DMA2_Stream3, DISABLE);  

          //DMA发送中断优先级配置
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
        DMA_ITConfig(DMA2_Stream3,DMA_IT_TC | DMA_IT_TE,ENABLE); //开启 DMA接收完成中断       


  //使能相关功能
  SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
  SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
        SPI_Cmd(SPI1, ENABLE); //使能SPI外设
        DMA_Cmd(DMA2_Stream2, DISABLE);  //接收
        DMA_Cmd(DMA2_Stream3, DISABLE); //发送
}
/**************************************************************************************************
* 函 数 名: SPI1_DMA_Send
* 函数功能: 开启SPI1收发DMA 按固定字节数收发SPI
* 输    入: *send_data 发送数据指针, send_len发送数量
* 输    出: 无
**************************************************************************************************/
void SPI1_DMA_Send(u8 *send_data ,u16 send_len)
{
        while (SPI1_Parm.Flag_Tx_Busy!=0){;}//判断是否正在发送中
  SPI1_Parm.Flag_Tx_Busy = 1;  
        SPI1_Parm.DMA_TxBuff_Len=send_len;
        SPI1_Parm.DMA_RxBuff_Len=send_len;
        DMA_Cmd(DMA2_Stream2, DISABLE);   
        DMA_Cmd(DMA2_Stream3, DISABLE);         
        //关闭DMA传输
        while (DMA_GetCmdStatus(DMA2_Stream2) != DISABLE){;}        //确保DMA可以被设置  
        while (DMA_GetCmdStatus(DMA2_Stream3) != DISABLE){;}        //确保DMA可以被设置
               
        my_mem_cpy(SPI1_Parm.Send_Buff,send_data,(u32)send_len);       
        DMA_SetCurrDataCounter(DMA2_Stream2,SPI1_Parm.DMA_RxBuff_Len); //接收数据传输量  
        DMA_SetCurrDataCounter(DMA2_Stream3,SPI1_Parm.DMA_TxBuff_Len); //发送数据传输量
        DMA_Cmd(DMA2_Stream2, ENABLE);  
        DMA_Cmd(DMA2_Stream3, ENABLE);                     
       
}
/**************************************************************************************************
* SPI1 DMA数据流接收完成
*函数功能: DMA 数据流2中断函数  
**************************************************************************************************/
void DMA2_Stream2_IRQHandler()
{
        if(DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_TCIF2)!=0)//SPI1 DMA接收完成中断
        {   
                DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_TCIF2);
                while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY) != RESET){;}                          
                DMA_Cmd(DMA2_Stream2,DISABLE);
                my_mem_cpy(SPI1_Parm.Recv_Data,SPI1_Parm.Recv_Buff,(u32)SPI1_Parm.DMA_RxBuff_Len);       
                SPI1_Parm.Flag_New_Recv=SPI1_Parm.DMA_RxBuff_Len;
        }
        if(DMA_GetFlagStatus(DMA2_Stream2,DMA_FLAG_TEIF2)!=0) //出错
        {
          DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_TEIF2);
                DMA_Cmd(DMA2_Stream2,DISABLE);
        }
}
/**************************************************************************************************
* SPI1 DMA数据流发送完成
*函数功能: DMA 数据流3中断函数  
**************************************************************************************************/
void DMA2_Stream3_IRQHandler()
{
        if(DMA_GetFlagStatus(DMA2_Stream3,DMA_FLAG_TCIF3)!=0)//SPI1 DMA发送完成中断
        {   
                DMA_ClearFlag(DMA2_Stream3,DMA_FLAG_TCIF3);  
                while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_BSY) != RESET){;}
          DMA_Cmd(DMA2_Stream3,DISABLE);
                SPI1_Parm.Flag_Tx_Busy = 0;  //清除发送忙标记
        }
        if(DMA_GetFlagStatus(DMA2_Stream3,DMA_FLAG_TEIF3)!=0) //出错
        {
          DMA_ClearFlag(DMA2_Stream3,DMA_FLAG_TEIF3);  //清除标志位
                DMA_Cmd(DMA2_Stream3,DISABLE);        
    SPI1_Parm.Flag_Tx_Busy = 0;               
        }
}











void SPI2_DMA_Master_Init(void)        //初始化SPI2作为主机口采用DMA收发
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;
        DMA_InitTypeDef  DMA_InitStructure;   
        NVIC_InitTypeDef NVIC_InitStructure;
       
        //初始SPI2 Parm
        SPI2_Parm.DMA_TxBuff_Len = sizeof(SPI2_Parm.Send_Buff);  //SPI发送缓冲区大小      
        SPI2_Parm.DMA_RxBuff_Len = sizeof(SPI2_Parm.Recv_Buff);  //SPI接收缓冲区大小   
        SPI2_Parm.Flag_Tx_Busy=0;      //复位SPI正在发送
        SPI2_Parm.Flag_New_Recv=0;     //复位是否收到新数据
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
        RCC_APB2PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);//使能SPI2时钟
       
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //引脚复用为 SPI2
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource14,GPIO_AF_SPI2); //
        GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //
       
        //GPIOFA5,6,7初始化设置
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;//复用功能输出       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
        //这里只针对SPI口初始化
        RCC_APB2PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE);//复位SPI2
        RCC_APB2PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  
        SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;               
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;               
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;               
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;       
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;               
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;                //预分频值为128 APB1为42M  APB2为84M
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;       
        SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
        SPI_Init(SPI2, &SPI_InitStructure);  
//        SPI_NSSInternalSoftwareConfig(SPI2,SPI_NSSInternalSoft_Set);

  //设置SPI2 接收DMA Stream    流3为接收 通道0
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
  DMA_DeInit(DMA1_Stream3);
        while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE){}
        DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR;
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SPI2_Parm.Recv_Buff;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
        DMA_InitStructure.DMA_BufferSize = SPI2_Parm.DMA_RxBuff_Len;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;//优先级
        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(DMA1_Stream3, &DMA_InitStructure);
        DMA_Cmd(DMA1_Stream3, DISABLE);  
          //DMA接收中断优先级配置
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
        DMA_ITConfig(DMA1_Stream3,DMA_IT_TC | DMA_IT_TE,ENABLE); //开启 DMA接收完成中断       
               
        //设置SPI2 发送DMA Stream  ,流4为发送 通道0
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
  DMA_DeInit(DMA1_Stream4);
        while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE){}//等待DMA可配置
        DMA_InitStructure.DMA_Channel = DMA_Channel_0;  //通道选择
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR;//DMA外设地址
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SPI2_Parm.Send_Buff;//DMA 存储器0地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式
        DMA_InitStructure.DMA_BufferSize = SPI2_Parm.DMA_TxBuff_Len;//数据传输量
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式, 递增模式就是每传输一个地址加1
        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_High;//优先级
        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(DMA1_Stream4, &DMA_InitStructure);//初始化串口接收DMA Stream
        DMA_Cmd(DMA1_Stream4, DISABLE);  

          //DMA发送中断优先级配置
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
        DMA_ITConfig(DMA1_Stream4,DMA_IT_TC | DMA_IT_TE,ENABLE); //开启 DMA接收完成中断       


  //使能相关功能
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
        SPI_Cmd(SPI2, ENABLE); //使能SPI外设
        DMA_Cmd(DMA1_Stream3, ENABLE);  //接收
        DMA_Cmd(DMA1_Stream4, DISABLE); //发送
}
/**************************************************************************************************
* 函 数 名: SPI2_DMA_Send
* 函数功能: 开启SPI2收发DMA 按固定字节数收发SPI
* 输    入: *send_data 发送数据指针, send_len发送数量
* 输    出: 无
**************************************************************************************************/
void SPI2_DMA_Send(u8 *send_data ,u16 send_len)
{
//        while (SPI2_Parm.Flag_Tx_Busy!=0){;}//判断是否正在发送中
//  SPI2_Parm.Flag_Tx_Busy = 1;  
        SPI2_Parm.DMA_TxBuff_Len=send_len;
        SPI2_Parm.DMA_RxBuff_Len=send_len;
        DMA_Cmd(DMA1_Stream3, DISABLE);   
        DMA_Cmd(DMA1_Stream4, DISABLE);         
        //关闭DMA传输
        while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE){;}       
        while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE){;}        //确保DMA可以被设置
               
        my_mem_cpy(SPI2_Parm.Send_Buff,send_data,(u32)send_len);       
        DMA_SetCurrDataCounter(DMA1_Stream3,SPI2_Parm.DMA_RxBuff_Len); //接收数据传输量  
        DMA_SetCurrDataCounter(DMA1_Stream4,SPI2_Parm.DMA_TxBuff_Len); //发送数据传输量
        DMA_Cmd(DMA1_Stream3, ENABLE);  
        //DMA_Cmd(DMA1_Stream4, ENABLE);                     
       
}
/**************************************************************************************************
* SPI2 DMA数据流接收完成
*函数功能: DMA 数据流2中断函数  
**************************************************************************************************/
void DMA1_Stream3_IRQHandler()
{
        if(DMA_GetFlagStatus(DMA1_Stream3,DMA_FLAG_TCIF3)!=0)//SPI2 DMA接收完成中断
        {   
                DMA_ClearFlag(DMA1_Stream3,DMA_FLAG_TCIF3);
                while (SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY) != RESET){;}                          
                DMA_Cmd(DMA1_Stream3,DISABLE);
                my_mem_cpy(SPI2_Parm.Recv_Data,SPI2_Parm.Recv_Buff,(u32)SPI2_Parm.DMA_RxBuff_Len);       
                SPI2_Parm.Flag_New_Recv=SPI2_Parm.DMA_RxBuff_Len;
        }
        if(DMA_GetFlagStatus(DMA1_Stream3,DMA_FLAG_TEIF3)!=0) //出错
        {
          DMA_ClearFlag(DMA1_Stream3,DMA_FLAG_TEIF3);
                DMA_Cmd(DMA1_Stream3,DISABLE);
        }
}
/**************************************************************************************************
* SPI2 DMA数据流发送完成
*函数功能: DMA 数据流3中断函数  
**************************************************************************************************/
void DMA1_Stream4_IRQHandler()
{
        if(DMA_GetFlagStatus(DMA1_Stream4,DMA_FLAG_TCIF4)!=0)//SPI2 DMA发送完成中断
        {   
                DMA_ClearFlag(DMA1_Stream4,DMA_FLAG_TCIF4);  
                while (SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_BSY) != RESET){;}
          DMA_Cmd(DMA1_Stream4,DISABLE);
                SPI2_Parm.Flag_Tx_Busy = 0;  //清除发送忙标记
        }
        if(DMA_GetFlagStatus(DMA1_Stream4,DMA_FLAG_TEIF4)!=0) //出错
        {
          DMA_ClearFlag(DMA1_Stream4,DMA_FLAG_TEIF4);  //清除标志位
                DMA_Cmd(DMA1_Stream4,DISABLE);        
    SPI2_Parm.Flag_Tx_Busy = 0;               
        }
}










//SPI1速度设置函数
//SPI速度=fAPB2/分频系数
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256  
//fAPB2时钟一般为84Mhz:
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{
        SPI1->CR1&=0XFFC7;//位3-5清零,用来设置波特率
        SPI1->CR1|=SPI_BaudRatePrescaler;        //设置SPI1速度
        SPI_Cmd(SPI1,ENABLE); //使能SPI1
}
//SPI1 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{                                          
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空  
        SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个byte  数据
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //等待接收完一个byte  
        return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据                  
}
//**********************使用方法****************************************
//SPI1_Init(); //初始化SPI
//SPI1_SetSpeed(SPI_BaudRatePrescaler_256);设置速度

//*********************//*********************//*********************
0条回答

一周热门 更多>