环境: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介入一次写入扇区内容? |
因为数据量不大,所以想用spi flash
方法一:正常方法写读
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);
Cubemx生成代码有问题
Step1:适用逻辑分析仪发现DMA根本没发数据
在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就能正常发送数据。
是时钟先后顺序问题
Cubemx生成代码有问题
在Main.c
MX_SPI1_Init();
MX_DMA_Init();
在MX_DMA_Init中才激活DMA时钟
1、非DMA模式下,已经调通了。
2、DMA模式下的SPI flash的扇区读写也正常
3、但在USB + Fatfs 在DMA模式下仍不正常。
stm32f103c8t6的RAM只有20K,一个扇区就用4K,是否与这个有关,还是fatfs不支持DMA.
正在找其他RAM比较多的机进行移植测试。