|
|
大佬,我使用MDMA读取写入W25Q256的时候,数据完全不对,不用的话没问题,而且使用了MDMA后 直接读取和写入也不正常了,不知道为什么
这是我的配置
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "quadspi.h"
QSPI_HandleTypeDef hqspi;
MDMA_HandleTypeDef hmdma_quadspi_fifo_th;
/* QUADSPI init function */
void MX_QUADSPI_Init(void)
{
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 1;
hqspi.Init.FifoThreshold = 32;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 24;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_3;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN QUADSPI_Init 2 */
// __HAL_MDMA_ENABLE_IT(&hmdma_quadspi_fifo_th,MDMA_IT_CTC);
/* USER CODE END QUADSPI_Init 2 */
}
void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(qspiHandle->Instance==QUADSPI)
{
/* USER CODE BEGIN QUADSPI_MspInit 0 */
/* USER CODE END QUADSPI_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* QUADSPI clock enable */
__HAL_RCC_QSPI_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**QUADSPI GPIO Configuration
PF6 ------> QUADSPI_BK1_IO3
PF7 ------> QUADSPI_BK1_IO2
PF8 ------> QUADSPI_BK1_IO0
PF9 ------> QUADSPI_BK1_IO1
PB2 ------> QUADSPI_CLK
PB6 ------> QUADSPI_BK1_NCS
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* QUADSPI MDMA Init */
/* QUADSPI_FIFO_TH Init */
hmdma_quadspi_fifo_th.Instance = MDMA_Channel0;
hmdma_quadspi_fifo_th.Init.Request = MDMA_REQUEST_QUADSPI_FIFO_TH;
hmdma_quadspi_fifo_th.Init.TransferTriggerMode = MDMA_BUFFER_TRANSFER;
hmdma_quadspi_fifo_th.Init.Priority = MDMA_PRIORITY_LOW;
hmdma_quadspi_fifo_th.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
hmdma_quadspi_fifo_th.Init.SourceInc = MDMA_SRC_INC_BYTE;
hmdma_quadspi_fifo_th.Init.DestinationInc = MDMA_DEST_INC_DISABLE;
hmdma_quadspi_fifo_th.Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE;
hmdma_quadspi_fifo_th.Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE;
hmdma_quadspi_fifo_th.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE;
hmdma_quadspi_fifo_th.Init.BufferTransferLength = 128;
hmdma_quadspi_fifo_th.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE;
hmdma_quadspi_fifo_th.Init.DestBurst = MDMA_DEST_BURST_SINGLE;
hmdma_quadspi_fifo_th.Init.SourceBlockAddressOffset = 0;
hmdma_quadspi_fifo_th.Init.DestBlockAddressOffset = 0;
if (HAL_MDMA_Init(&hmdma_quadspi_fifo_th) != HAL_OK)
{
Error_Handler();
}
if (HAL_MDMA_ConfigPostRequestMask(&hmdma_quadspi_fifo_th, 0, 0) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(qspiHandle,hmdma,hmdma_quadspi_fifo_th);
}
}
这是我的读写函数:
static bool qspi_receive(uint8_t *buf, uint32_t datalen)
{
hqspi.Instance->DLR = datalen - 1; /* 配置数据长度 */
if (HAL_QSPI_Receive(&hqspi, buf, 5000) == HAL_OK)
{
return 0;
}
else
{
return 1;
}
}
static bool qspi_transmit(uint8_t *buf, uint32_t datalen)
{
hqspi.Instance->DLR = datalen - 1; /* 配置数据长度 */
if (HAL_QSPI_Transmit(&hqspi, buf, 5000) == HAL_OK)
{
return 0;
}
else
{
return 1;
}
}
static bool qspi_receive_dma(uint8_t *buf, uint32_t datalen)
{
hqspi.Instance->DLR = datalen - 1; /* 配置数据长度 */
SCB_CleanInvalidateDCache();
if (HAL_QSPI_Receive_DMA(&hqspi, buf) == HAL_OK)
{
uint32_t tickstart = HAL_GetTick();
while (HAL_QSPI_GetState(&hqspi) != HAL_QSPI_STATE_READY)
{
if ((HAL_GetTick() - tickstart) > 5000) // 1秒超时
{
return false;
}
}
SCB_CleanInvalidateDCache();
return true;
}
else
{
return false;
}
}
static bool qspi_transmit_dma(uint8_t *buf, uint32_t datalen)
{
hqspi.Instance->DLR = datalen - 1; /* 配置数据长度 */
SCB_CleanInvalidateDCache();
if (HAL_QSPI_Transmit_DMA(&hqspi, buf) == HAL_OK)
{
// 或者使用超时等待
uint32_t tickstart = HAL_GetTick();
while (HAL_QSPI_GetState(&hqspi) != HAL_QSPI_STATE_READY)
{
if ((HAL_GetTick() - tickstart) > 5000) // 1秒超时
{
return false;
}
}
SCB_CleanInvalidateDCache();
return true;
}
else
{
return false;
}
}
这里是 读写W25Q256函数
static void norflash_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
/* QPI,快速读数据,地址为ReadAddr,4线传输数据_32位地址_4线传输地址_4线传输指令,8空周期,NumByteToRead个数据 */
QSPI_Handle.Send_Cmd(FLASH_FastReadData, addr, (3 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 8);
QSPI_Handle.Read(pbuf, datalen);
}
static void norflash_read_dma(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
/* QPI,快速读数据,地址为ReadAddr,4线传输数据_32位地址_4线传输地址_4线传输指令,8空周期,NumByteToRead个数据 */
QSPI_Handle.Send_Cmd(FLASH_FastReadData, addr, (3 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 8);
QSPI_Handle.Read_DMA(pbuf, datalen);
}
static void norflash_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
norflash_write_enable(); /* 写使能 */
/* QPI,页写指令,地址为WriteAddr,4线传输数据_32位地址_4线传输地址_4线传输指令,无空周期,NumByteToWrite个数据 */
QSPI_Handle.Send_Cmd(FLASH_PageProgram, addr, (3 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 0);
QSPI_Handle.Write(pbuf, datalen);
norflash_wait_busy(); /* 等待写入结束 */
}
static void norflash_write_page_dma(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
norflash_write_enable(); /* 写使能 */
/* QPI,页写指令,地址为WriteAddr,4线传输数据_32位地址_4线传输地址_4线传输指令,无空周期,NumByteToWrite个数据 */
QSPI_Handle.Send_Cmd(FLASH_PageProgram, addr, (3 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 0);
QSPI_Handle.Write_DMA(pbuf, datalen);
norflash_wait_busy(); /* 等待写入结束 */
}
static void norflash_write_nocheck(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint16_t pageremain;
pageremain = 256 - addr % 256; /* 单页剩余的字节数 */
if (datalen <= pageremain)
{
pageremain = datalen; /* 不大于256个字节 */
}
while (1)
{
norflash_write_page(pbuf, addr, pageremain);
if (datalen == pageremain)
{
break; /* 写入结束了 */
}
else
{
pbuf += pageremain;
addr += pageremain;
datalen -= pageremain; /* 减去已经写入了的字节数 */
if (datalen > 256)
{
pageremain = 256; /* 一次可以写入256个字节 */
}
else
{
pageremain = datalen; /* 不够256个字节了 */
}
}
}
}
static void norflash_write_nocheck_dma(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint16_t pageremain;
pageremain = 256 - addr % 256; /* 单页剩余的字节数 */
if (datalen <= pageremain)
{
pageremain = datalen; /* 不大于256个字节 */
}
while (1)
{
norflash_write_page_dma(pbuf, addr, pageremain);
if (datalen == pageremain)
{
break; /* 写入结束了 */
}
else
{
pbuf += pageremain;
addr += pageremain;
datalen -= pageremain; /* 减去已经写入了的字节数 */
if (datalen > 256)
{
pageremain = 256; /* 一次可以写入256个字节 */
}
else
{
pageremain = datalen; /* 不够256个字节了 */
}
}
}
}
/**
* @brief 写SPI FLASH
* @note 在指定地址开始写入指定长度的数据 , 该函数带擦除操作!
* SPI FLASH 一般是: 256个字节为一个Page, 4Kbytes为一个Sector, 16个扇区为1个Block
* 擦除的最小单位为Sector.
*
* @param pbuf : 数据存储区
* @param addr : 开始写入的地址(最大32bit)
* @param datalen : 要写入的字节数(最大65535)
* @retval 无
*/
uint8_t g_norflash_buf[4096];
static void norflash_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t *norflash_buf;
norflash_buf = g_norflash_buf;
secpos = addr / 4096; /* 扇区地址 */
secoff = addr % 4096; /* 在扇区内的偏移 */
secremain = 4096 - secoff; /* 扇区剩余空间大小 */
//printf("ad:%X,nb:%X\r\n",addr, datalen); /* 测试用 */
if (datalen <= secremain)secremain = datalen; /* 不大于4096个字节 */
while (1)
{
norflash_read(norflash_buf, secpos * 4096, 4096); /* 读出整个扇区的内容 */
for (i = 0; i < secremain; i++) /* 校验数据 */
{
if (norflash_buf[secoff + i] != 0XFF)
{
break; /* 需要擦除 */
}
}
if (i < secremain) /* 需要擦除 */
{
norflash_erase_sector(secpos); /* 擦除这个扇区 */
for (i = 0; i < secremain; i++) /* 复制 */
{
norflash_buf[i + secoff] = pbuf;
}
norflash_write_nocheck(norflash_buf, secpos * 4096, 4096); /* 写入整个扇区 */
}
else
{
norflash_write_nocheck(pbuf, addr, secremain); /* 写已经擦除了的,直接写入扇区剩余区间. */
}
if (datalen == secremain)
{
break; /* 写入结束了 */
}
else /* 写入未结束 */
{
secpos++; /* 扇区地址增1 */
secoff = 0; /* 偏移位置为0 */
pbuf += secremain; /* 指针偏移 */
addr += secremain; /* 写地址偏移 */
datalen -= secremain; /* 字节数递减 */
if (datalen > 4096)
{
secremain = 4096; /* 下一个扇区还是写不完 */
}
else
{
secremain = datalen; /* 下一个扇区可以写完了 */
}
}
}
}
static void norflash_write_dma(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t *norflash_buf;
norflash_buf = g_norflash_buf;
secpos = addr / 4096; /* 扇区地址 */
secoff = addr % 4096; /* 在扇区内的偏移 */
secremain = 4096 - secoff; /* 扇区剩余空间大小 */
if (datalen <= secremain)secremain = datalen; /* 不大于4096个字节 */
while (1)
{
norflash_read_dma(norflash_buf, secpos * 4096, 4096); /* 读出整个扇区的内容 */
for (i = 0; i < secremain; i++) /* 校验数据 */
{
if (norflash_buf[secoff + i] != 0XFF)
{
break; /* 需要擦除 */
}
}
if (i < secremain) /* 需要擦除 */
{
norflash_erase_sector(secpos); /* 擦除这个扇区 */
for (i = 0; i < secremain; i++) /* 复制 */
{
norflash_buf[i + secoff] = pbuf;
}
norflash_write_nocheck_dma(norflash_buf, secpos * 4096, 4096); /* 写入整个扇区 */
}
else
{
norflash_write_nocheck_dma(pbuf, addr, secremain); /* 写已经擦除了的,直接写入扇区剩余区间. */
}
if (datalen == secremain)
{
break; /* 写入结束了 */
}
else /* 写入未结束 */
{
secpos++; /* 扇区地址增1 */
secoff = 0; /* 偏移位置为0 */
pbuf += secremain; /* 指针偏移 */
addr += secremain; /* 写地址偏移 */
datalen -= secremain; /* 字节数递减 */
if (datalen > 4096)
{
secremain = 4096; /* 下一个扇区还是写不完 */
}
else
{
secremain = datalen; /* 下一个扇区可以写完了 */
}
}
}
}
static void norflash_erase_chip(void)
{
norflash_write_enable(); /* SET WEL */
norflash_wait_busy();
/* QPI,写全片擦除指令,地址为0,无数据_8位地址_无地址_4线传输指令,无空周期,0个字节数据 */
QSPI_Handle.Send_Cmd(FLASH_ChipErase, 0, (0 << 6) | (0 << 4) | (0 << 2) | (3 << 0), 0);
norflash_wait_busy(); /* 等待芯片擦除结束 */
}
static void norflash_erase_sector(uint32_t saddr)
{
//printf("fe:%x\r\n",Dst_Addr); /* 监视falsh擦除情况,测试用 */
saddr *= 4096;
norflash_write_enable(); /* SET WEL */
norflash_wait_busy();
/* QPI,写扇区擦除指令,地址为0,无数据_32位地址_4线传输地址_4线传输指令,无空周期,0个字节数据 */
QSPI_Handle.Send_Cmd(FLASH_SectorErase, saddr, (0 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 0);
norflash_wait_busy(); /* 等待擦除完成 */
}
static void norflash_wait_busy(void)
{
while ((norflash_read_sr(1) & 0x01) == 0x01); /* 等待BUSY位清空 */
}
可能是什么情况呀?
|
|