你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

如何使用SPI的DMA模式读写FLASH

[复制链接]
ldptest 提问时间:2019-12-3 16:13 /
环境:HAL + USB + W25Q64 + Fatfs
硬件:stm32f103c8t6 + MX25L64

我使用普通模式,完成在W25Q64中写入文件,通过USB可以再PC中读取出来。

因为我下一步想做一个监测系统,想提高flash读写效率,使用DMA模式
MCU一直在监测,不断往数组中写入数据,一旦满了,数据通过DMA模式往FLASH传,MCU继续监测。读也一样。

1、为了试验,我先把读的部分置换为DMA操作
HAL_SPI_Receive_DMA(&hspi1,buffer,4096);
在回调函数中
再Flash_cs端设置为高电平
但程序不能正常运行,请问需要增加什么代码?

2、写入,因为FLASH一个扇区4096bytes,但每次只能写入1Page(256bytes)
请问是否可以通过DMA循环传输功能实现不需要MCU介入一次写入扇区内容?

收藏 评论7 发布时间:2019-12-3 16:13

举报

7个回答
maxtch 回答时间:2019-12-4 10:39:44
您的这种场景其实不适合用这种 SPI 闪存,更适合的应该是 microSD 卡或 eMMC:容量更大,也更耐擦写。
ldptest 回答时间:2019-12-4 12:20:58
maxtch 发表于 2019-12-4 10:39
您的这种场景其实不适合用这种 SPI 闪存,更适合的应该是 microSD 卡或 eMMC:容量更大,也更耐擦写。 ...

因为数据量不大,所以想用spi flash
ldptest 回答时间:2019-12-11 21:49:48
我分解步骤测试,擦写扇区后写入数据,再回读检查是否正确。
方法一:正常方法写读
void ExtFlash_PageProg(uint8_t* pBuffer, uint32_t WriteAddr,uint16_t NumberOfBytes)
{
  ExtFlash_WaitForWriteEnd();                           //检查FLASH是否忙
  ExtFlash_WriteEnable();                               //允许写入
  ExtFlash_CS_LOW();
  InstructionSynthesis(W25X_PageProgram,WriteAddr);     //页编程
  SPI_Send(Send32Bits, 4);
  SPI_Send(pBuffer, NumberOfBytes);
  ExtFlash_CS_HIGH();
  ExtFlash_WriteDisable();                              //禁止写入
}
再执行
  if (ExtFlash_ReadBackTest() == HAL_OK)
  {
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
  }

结果,亮灯。

方法一:DMA写,正常读
void ExtFlash_PageProg(uint8_t* pBuffer, uint32_t WriteAddr,uint16_t NumberOfBytes)
{
  ExtFlash_WaitForWriteEnd();                           //检查FLASH是否忙
  ExtFlash_WriteEnable();                               //允许写入
  ExtFlash_CS_LOW();
  InstructionSynthesis(W25X_PageProgram,WriteAddr);     //页编程
  SPI_Send(Send32Bits, 4);
  SPI_Send_DMA(pBuffer, NumberOfBytes);
}
回调函数
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
  if(hspi == &hspi1)
  {
    ExtFlash_CS_HIGH();
    ExtFlash_WriteDisable();                              //禁止写入
    if (ExtFlash_ReadBackTest() == HAL_OK)
    {
      HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
    }
  }
}
结果,不亮灯。
调试,能进入回调函数,能运行读页,但读回的都是0xFF(ReadBuff是清0的)。

出问题可能性:
1、SPI在DMA不能正常传输数据
2、Flash不能正确接收DMA方式传输的数据
3、还没传输,就进入中断(因为第一个数字都没写进flash)

求助:如何解决?


SPI设置:
void MX_SPI1_Init(void)
{

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

}


DMA设置:
    hdma_spi1_tx.Instance = DMA1_Channel3;
    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_tx.Init.Mode = DMA_NORMAL;
    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_HIGH;
    if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi1_tx);
ldptest 回答时间:2019-12-12 23:51:17
唉,又是时钟先后顺序问题
Cubemx生成代码有问题

Step1:适用逻辑分析仪发现DMA根本没发数据
SPI.png


在Main.c

  MX_SPI1_Init();
  MX_DMA_Init();

在MX_SPI1_Init ————》 HAL_SPI_Init —————》 HAL_SPI_MspInit
HAL_SPI_MspInit中
先激活
    __HAL_RCC_SPI1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
然后进行GPIO设置
再进行DMA设置

MX_DMA_Init中
先激活
__HAL_RCC_DMA1_CLK_ENABLE();
然后再进行中断设置

以上代码是CubeMX自动生成。

我突然想起前段时间看到的文章
__HAL_RCC_DMA1_CLK_ENABLE();与SPI、GPIO时钟一起激活。
OK,DMA就能正常发送数据。
butterflyspring 回答时间:2019-12-17 17:14:39
是外设时钟没使能好,然后就初始化外设不成功吧?
ldptest 回答时间:2019-12-18 09:15:00
butterflyspring 发表于 2019-12-17 17:14
是外设时钟没使能好,然后就初始化外设不成功吧?

是时钟先后顺序问题
Cubemx生成代码有问题

在Main.c

  MX_SPI1_Init();
  MX_DMA_Init();

在MX_DMA_Init中才激活DMA时钟
ldptest 回答时间:2019-12-18 09:57:57
目前进展,
1、非DMA模式下,已经调通了。
2、DMA模式下的SPI flash的扇区读写也正常
3、但在USB + Fatfs 在DMA模式下仍不正常。

stm32f103c8t6的RAM只有20K,一个扇区就用4K,是否与这个有关,还是fatfs不支持DMA.
正在找其他RAM比较多的机进行移植测试。

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版