STM32上SPI+DMA实现大批量读取flash数据

最近做项目需要使用SPI+DMA,为了做实验感受DMA传输数据块,本人以SPI+DMA来读取flash中的数据。网上有很多例程是spi直接读取flash,无法提高性能。因为只是简单的实验SPI的DMA功能,所以在写数据时并没有考虑页写一些制约,只是简单的将1k大小的数据写入flash,然后用DMA读出这1K大小的数据,相信SPI和DMA的配置大家都很熟悉了,本人在此不在强调,只是说几点注意点的:

(1)DMA关于SPI通道的选择,在stm32中,SPI1_RX读请求是DMA通道2,SPI1_TX发送请求是DMA通道3。刚开始我在配置通道的时候没仔细看,看的是SPI/I2S2_RX这个请求,把通道配置成了通道四和通道五,结果一直无法出来结果。所以这个是第一个要注意的。

 

(2)设置发送和接收缓冲区,并且对发送缓冲区初始化,本例中我设定发送和接收缓冲区大小是1K,可以根据自己需要设定,本帖子起抛砖引玉作用。

uint32_t Tx_Buffer[256];
uint32_t Rx_Buffer[256];

对发送缓冲区初始化:

for(i = 0; i< 256; i++)
{
Tx_Buffer[i] = i;
}

下面是对DMA的初始化,本例中没有用到中断。

void DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;

/*开启时钟*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


DMA_DeInit(DMA1_Channel2);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Rx_Buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 256;
    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_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel2, &DMA_InitStructure);

   
    DMA_DeInit(DMA1_Channel3);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Tx_Buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 256;
    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_Medium;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel3, &DMA_InitStructure);

DMA_Cmd (DMA1_Channel2,ENABLE);
DMA_Cmd (DMA1_Channel3,ENABLE);

}

在初始化函数中先不给使能SPI的DMA读请求或者写请求,下面是在main函数中的程序,写之前先擦除,在这里再说明下,我只有在对flash里的数据进行读写操作是才使用DMA,而一些命令的发送接收不用DMA,因为DMA是对数据块进行操作的,小量的数据没必要使用DMA.

 

下面具体介绍main函数中的函数

void SPI_DMA_PageWrite(u32 WriteAddr)
{
  /* Enable the write access to the FLASH */
  SPI_FLASH_WriteEnable();


  /* Select the FLASH: Chip Select low */
  SPI_FLASH_CS_LOW();
  /* Send "Write to Memory " instruction */
  SPI_FLASH_SendByte(W25X_PageProgram);
  /* Send WriteAddr high nibble address byte to write to */
  SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
  /* Send WriteAddr medium nibble address byte to write to */
  SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
  /* Send WriteAddr low nibble address byte to write to */
  SPI_FLASH_SendByte(WriteAddr & 0xFF);


SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

while(DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET);

  /* Deselect the FLASH: Chip Select high */
  SPI_FLASH_CS_HIGH();

}
先发送写数据命令,然后发送写数据地址,命令和地址发送完后,我们就要写入数据了,此时我们要是使能SPI的DMA发送请求,即函数SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE); 就会启动DMA,为了防止DMA没有发送完数据就释放总线,我加入了函数while(DMA_GetFlagStatus(DMA1_FLAG_TC3) == RESET);,来保证DMA传输完成。最后拉高片选线。

 

void SPI_DMA_BufferRead(u32 ReadAddr)
{
  /* Select the FLASH: Chip Select low */
  SPI_FLASH_CS_LOW();


  /* Send "Read from Memory " instruction */
  SPI_FLASH_SendByte(W25X_ReadData);


  /* Send ReadAddr high nibble address byte to read from */
  SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
  /* Send ReadAddr medium nibble address byte to read from */
  SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
  /* Send ReadAddr low nibble address byte to read from */
  SPI_FLASH_SendByte(ReadAddr & 0xFF);


SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
SPI_Init(SPI1, &SPI_InitStructure);


//SPI_FLASH_SendByte(0xff);
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);

while(DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);

  /* Deselect the FLASH: Chip Select high */
  SPI_FLASH_CS_HIGH();
}

首先发送地址和读命令,在这里重要说明一下,刚开始我把SPI配置成全双工模式,因为牵扯到要获取flash地址的操作,但是我们在用SPI以DMA读flash数据的时候,就不能使用全双工模式了,在全双工模式下,我们读取flash的时候需要一直发送一个无效数据0xff,来使电平发生变化,这样就限制了DMA的性能。所以在用DMA读flash数据的时候,我们把SPI模式配置成只读模式,如上面程序中的样子,这个时候就可以直接读取数据,而不需要在发送无效数据0xff,大大提高了性能。SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly;
SPI_Init(SPI1, &SPI_InitStructure);配置为只读模式,SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);使能SPI_DMA读请求。同理为了防止DMA未传输完片选线就拉高,用while(DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET);来保证。

uint32_t Tx_Buffer[256];
uint32_t Rx_Buffer[256];

整个程序思路就是我将发送缓冲区Tx_Buffer中的数据用DMA方式写入flash,用DMA方式读出数据保存到接收缓冲区Rx_Buffer。

因为程序比较简单,并没有考虑到flash写入时的页面大小限制等,但是读写操作已经掌握了,剩下的就是完善了。希望本帖子能够帮助大家,有问题的地方还望指出来,大家共同进步哈!!!!

  • 7
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值