STM32 SPI工作在主模式时用DMA方式接收数据

平台:STM32F103

功能:SPI工作在主模式时用DMA方式接收数据,在需要从SPI FLASH中读出大量数据时,可以在读数据的同时释放CPU的占用,提高系统利用效率

        DMA不可以自动帮忙发送时钟信号,但是如果让spi发送数据并且使用DMA方式,spi可以帮忙自动发送时钟信号。基于这样的理论, 直接上代码(参考:http://blog.sina.com.cn/s/blog_9d8d362b0101cukb.html)

#if (ON == SPI_DMA_ON)
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址    
void SPI_DMA_Config(u32 MBAr)
{
    DMA_InitTypeDef DMA_InitStructure;
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                    //使能DMA传输

     //接收DMA配置
     DMA_Cmd(SPI_RX_DMA_CH, DISABLE);                                     //DMA关闭后才能配置
    DMA_DeInit(SPI_RX_DMA_CH);                                          //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&SPI_FLASH_NUM->DR);//DMA外设ADC基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = MBAr;                        //DMA内存基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                  //数据传输方向,外设->内存
    DMA_InitStructure.DMA_BufferSize = 0;                               //DMA通道的DMA缓存的大小
    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;               //DMA通道 x拥有中优先级 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                        //DMA通道x没有设置为内存到内存传输

    SPI_I2S_ReceiveData(SPI_FLASH_NUM);                                 //空读一次数据    
    
    /*传输完成中断使能*/
    DMA_ITConfig(SPI_RX_DMA_CH, DMA_IT_TC, ENABLE);    
    DMA_Init(SPI_RX_DMA_CH, &DMA_InitStructure);                        //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器

    //发送DMA配置
    DMA_Cmd(SPI_TX_DMA_CH, DISABLE);                                    //DMA关闭后才能配置
    DMA_DeInit(SPI_TX_DMA_CH);                                          //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                  //数据传输方向,从内存读取发送到外设
    DMA_InitStructure.DMA_BufferSize = 0;                               //DMA通道的DMA缓存的大小
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;            //内存地址寄存器不用递增,因为只是为了发送时钟
    DMA_Init(SPI_TX_DMA_CH, &DMA_InitStructure);                        //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
} 

//开启一次DMA传输
void SPI_DMA_Enable(u16 len)
{
    DMA_Cmd(SPI_RX_DMA_CH, DISABLE );                                         //关闭 指示的通道        
    DMA_SetCurrDataCounter(SPI_RX_DMA_CH,len);                                //DMA通道的DMA缓存的大小
    DMA_Cmd(SPI_RX_DMA_CH, ENABLE);
    
    DMA_Cmd(SPI_TX_DMA_CH, DISABLE );                                         //关闭 指示的通道        
    DMA_SetCurrDataCounter(SPI_TX_DMA_CH,len);                                //DMA通道的DMA缓存的大小
    DMA_Cmd(SPI_TX_DMA_CH, ENABLE);                                           //开启DMA传输
}

void SPI_FLASH_Data_Read_By_DMA(uint8_t *s,const uint32_t Add,const uint16_t Date_Length)
{
    uint32_t    Add_24;
    uint32_t    n;
    uint8_t        Shift_Bit,Temp;

    //重新配置DMA通道
    while(DMA_GetCurrDataCounter(SPI_RX_DMA_CH)!=0);                    //等待上一次通道传输完成 
    SPI_DMA_Config((u32)s);
    
    ErrorFlashStatus = ERROR_OK;        //开始一次新的读操作,错误状态复位
    
    /*SPI_FLASH_NUM的片选有效*/
    SPI_FLASH_Enable;
    /*地址有效位数为24,屏蔽高12位*/
    Add_24 = Add & 0x00FFFFFF;
    /*发送读数据指令*/
    SPI_FLASH_Byte_Send(READ);
    /*24位地址要分三次发送*/
    for(n=3;n>0;n--)
    {
        Shift_Bit = (n-1)*8;
        Temp = (uint8_t)(0xFF & (Add_24 >> Shift_Bit));
        SPI_FLASH_Byte_Send(Temp);
    }
    
    /*开始读数据*/
    SPI_DMA_Enable(Date_Length);
    
    /*结束读操作,SPI_FLASH_NUM片选无效,放在DAM中断中完成*/
}

/*   
 * 函数名:void DMA1_Channel1_IRQHandler(void)  
 * 描述  :DMA1中断服务函数   
 * 输入  :无   
 * 输出  :无   
 */
void DMA1_Channel2_IRQHandler(void)
{
    /*结束读操作,SPI_FLASH_NUM片选无效*/
    SPI_FLASH_Disable;
    /* 清除 DMA1 Channel2 transfer complete 中断标志 */ 
    DMA_ClearITPendingBit(DMA1_IT_TC2);
    DMA_Cmd(SPI_RX_DMA_CH, DISABLE );   
}
#endif


你可能感兴趣的:(SPI,stm32,dma)