STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]( 三 )


STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

文章插图
查询法实现片选CS信号(蓝色)和SPI硬件产生的时序
对于这样的实时性,我实在是不明白意法半导体的STM32设计师的初衷是什么 。当然,也有可能是笔者才疏学浅,如果有大神知道,烦请转告,多谢!
二、STM32做SPI从机(Slave)时的DMA传输
当然用DMA读写SPI,更合理的方式是让STM32的SPI工作在从机模式,只要主机给出合理的片选CS、时钟SCK和数据MOSI/MISO信号,作为从机的STM32就能在DMA的支持下 , 实现高效、实时的数据接收 。下面的代码中,我将SPI1配置为从机模式,用DMA1CH2接收数据 。
STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

文章插图
STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

文章插图
1/////// DMA CH2配置代码///////// 2 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA传输 3 DMA_DeInit(DMA1_Channel2);//将DMA的通道1寄存器重设为缺省值 4 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR);//DMA外设基地址 5 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)spi_rx_buff;//DMA内存基地址 6 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//数据传输方向,从外设读取数据到内存 7 DMA_InitStructure.DMA_BufferSize = num;//DMA通道的DMA缓存的大小 8 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变 9 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址寄存器递增10 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度为16位11 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位12 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//工作在正常模式13 DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 x拥有中优先级14 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//DMA通道x没有设置为内存到内存传输15 DMA_Init(DMA1_Channel2, &DMA_InitStructure);//根据DMA_InitStruct中指定的参数初始化DMA的通道16/////// SPI1配置代码/////////17 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE );18 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;//PA4 PA5 6 7是SPI1的CS SCK MIOS MOSI19 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出20 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;21 GPIO_Init(GPIOA, &GPIO_InitStructure);22 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工23 SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;//设置SPI工作模式:设置为SPI从机24 SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;//设置SPI的数据大小:SPI发送接收8位帧结构25 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//空闲时时钟为低电平26 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//数据捕获于第1个时钟沿27 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//SPI_NSS_Hard;////NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制28 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//定义波特率预分频的值29 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始30 SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC值计算的多项式31 SPI_Init(SPI1, &SPI_InitStructure);//根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI从机DMA使用流程
主程序中,控制DMA和读取缓冲中的程序如下所示 。这里为了代码的简单易懂,同样没有使用DMA中断,在实际使用时,建议读者使用中断以提高数据读写效率 。
STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

文章插图
STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

文章插图
1 SPI_Cmd(SPI1, ENABLE); //使能SPI1外设 2 DMA_SetCurrDataCounter(DMA1_Channel2,256);//这部必须在每次启动DMA之前设置,3 DMA_Cmd(DMA1_Channel2, ENABLE);//使能DMA所指示的通道 4 while(DMA_GetFlagStatus(DMA1_FLAG_TC2)==RESET);//判断通道2传输完成 5 DMA_ClearFlag(DMA1_FLAG_TC2);//清除通道2传输完成标志 6 DMA_Cmd(DMA1_Channel2, DISABLE);//禁止DMA 7 SPI_Cmd(SPI1, DISABLE); //禁止SPI,只在开启SPI时接收数据,防止主机不断发送 8 //////////以下可以把数据传输走////////// 9 for(i=0;i<256;i++)10 data_repo_short[i] = spi_rx_buff[i]; SPI从机配置代码
下图是我用FPGA作为SPI主机产生的读写时序,可以看到此时SPI可以达到很高的通信效率 。提高SCK的主频后 , 通信速度上限10Mbytes/S左右(主要受限于STM32的接收SCK频率) 。

推荐阅读