RAM选用 ISSI的IS66系列,参照V7 QSPI读写W25Q更改配置,可读可写,但发现单次读写数据长度只能小于2048字节,超过长度就从原点开始重复读写。IS66的burstlength默认1024。求解为什么不能配置起始地址后连续读取。
[C] 纯文本查看 复制代码 void bsp_InitQSPI(void)
{
/* 复位QSPI */
QSPIHandle.Instance = QUADSPI;
if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 设置时钟速度,QSPI clock = 200MHz / (ClockPrescaler+1) = 100MHz */
QSPIHandle.Init.ClockPrescaler = 2;//0:200MHz 1:100MHz 2:66MHz
/* 设置FIFO阀值,范围1 - 32 */
QSPIHandle.Init.FifoThreshold = 32;
/*
QUADSPI在FLASH驱动信号后过半个CLK周期才对FLASH驱动的数据采样。
在外部信号延迟时,这有利于推迟数据采样。
*/
QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
/*Flash大小是2^(FlashSize + 1) = 2^23 = 8MB */
QSPIHandle.Init.FlashSize = QSPI_FLASH_SIZE - 1;
/* 命令之间的CS片选至少保持1个时钟周期的高电平 */
QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
/*
MODE0: 表示片选信号空闲期间,CLK时钟信号是低电平
MODE3: 表示片选信号空闲期间,CLK时钟信号是高电平
*/
QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;
/* QSPI有两个BANK,这里使用的BANK1 */
QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1;
/* V7开发板仅使用了BANK1,这里是禁止双BANK */
QSPIHandle.Init.DualFlash =QSPI_DUALFLASH_ENABLE; //QSPI_DUALFLASH_DISABLE;//
/* 初始化配置QSPI */
if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
[C] 纯文本查看 复制代码 void HAL_QSPI_MspInit(QSPI_HandleTypeDef *hqspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 使能QPSI时钟 */
QSPI_CLK_ENABLE();
/* 复位时钟接口 */
QSPI_FORCE_RESET();
QSPI_RELEASE_RESET();
/* 使能GPIO时钟 */
QSPI_CS_GPIO_CLK_ENABLE();
// QSPI_CS2_GPIO_CLK_ENABLE();
QSPI_CLK_GPIO_CLK_ENABLE();
QSPI_BK1_D0_GPIO_CLK_ENABLE();
QSPI_BK1_D1_GPIO_CLK_ENABLE();
QSPI_BK1_D2_GPIO_CLK_ENABLE();
QSPI_BK1_D3_GPIO_CLK_ENABLE();
QSPI_BK2_D0_GPIO_CLK_ENABLE();// __HAL_RCC_GPIOE_CLK_ENABLE()
QSPI_BK2_D1_GPIO_CLK_ENABLE();// __HAL_RCC_GPIOE_CLK_ENABLE()
QSPI_BK2_D2_GPIO_CLK_ENABLE();// __HAL_RCC_GPIOE_CLK_ENABLE()
QSPI_BK2_D3_GPIO_CLK_ENABLE();// __HAL_RCC_GPIOE_CLK_ENABLE()
/* QSPI CS GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = QSPI_CS_AF;
HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &GPIO_InitStruct);
// /* QSPI CS GPIO 引脚配置 */
// GPIO_InitStruct.Pin = QSPI_CS2_PIN;
// GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
// GPIO_InitStruct.Pull = GPIO_PULLUP;
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
// GPIO_InitStruct.Alternate = QSPI_CS2_AF;
// HAL_GPIO_Init(QSPI_CS2_GPIO_PORT, &GPIO_InitStruct);
/* QSPI CLK GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_CLK_PIN;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = QSPI_CLK_AF;
HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D0 GPIO pin 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D0_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D0_AF;
HAL_GPIO_Init(QSPI_BK1_D0_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D1 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D1_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D1_AF;
HAL_GPIO_Init(QSPI_BK1_D1_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D2 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D2_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D2_AF;
HAL_GPIO_Init(QSPI_BK1_D2_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D3 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK1_D3_PIN;
GPIO_InitStruct.Alternate = QSPI_BK1_D3_AF;
HAL_GPIO_Init(QSPI_BK1_D3_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D0 GPIO pin 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK2_D0_PIN;
GPIO_InitStruct.Alternate = QSPI_BK2_D0_AF;
HAL_GPIO_Init(QSPI_BK2_D0_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D1 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK2_D1_PIN;
GPIO_InitStruct.Alternate = QSPI_BK2_D1_AF;
HAL_GPIO_Init(QSPI_BK2_D1_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D2 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK2_D2_PIN;
GPIO_InitStruct.Alternate = QSPI_BK2_D2_AF;
HAL_GPIO_Init(QSPI_BK2_D2_GPIO_PORT, &GPIO_InitStruct);
/* QSPI D3 GPIO 引脚配置 */
GPIO_InitStruct.Pin = QSPI_BK2_D3_PIN;
GPIO_InitStruct.Alternate = QSPI_BK2_D3_AF;
HAL_GPIO_Init(QSPI_BK2_D3_GPIO_PORT, &GPIO_InitStruct);
/* 使能QSPI中断 */
HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x02, 0);
HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
/* 配置MDMA时钟 */
QSPI_MDMA_CLK_ENABLE();
hmdma.Instance = MDMA_Channel1; /* 使用MDMA的通道1 */
hmdma.Init.Request = MDMA_REQUEST_QUADSPI_FIFO_TH; /* QSPI的FIFO阀值触发中断 */
hmdma.Init.TransferTriggerMode = MDMA_BUFFER_TRANSFER; /* 使用MDMA的buffer传输 */
hmdma.Init.Priority = MDMA_PRIORITY_HIGH; /* 优先级高 */
hmdma.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;/* 小端格式 */
hmdma.Init.SourceInc = MDMA_SRC_INC_BYTE; /* 源地址字节递增 */
hmdma.Init.DestinationInc = MDMA_DEST_INC_DISABLE; /* 目的地址无效自增 */
hmdma.Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE; /* 源地址数据宽度字节 */
hmdma.Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE; /* 目的地址数据宽度字节 */
hmdma.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE; /* 小端,右对齐 */
hmdma.Init.BufferTransferLength = 128; /* 每次传输128个字节 */
hmdma.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE; /* 源数据单次传输 */
hmdma.Init.DestBurst = MDMA_DEST_BURST_SINGLE; /* 目的数据单次传输 */
hmdma.Init.SourceBlockAddressOffset = 0; /* 用于block传输,buffer传输用不到 */
hmdma.Init.DestBlockAddressOffset = 0; /* 用于block传输,buffer传输用不到 */
/* 关联MDMA句柄到QSPI句柄里面 */
__HAL_LINKDMA(hqspi, hmdma, hmdma);
/* 先复位,然后配置MDMA */
HAL_MDMA_DeInit(&hmdma);
HAL_MDMA_Init(&hmdma);
/* 使能MDMA中断,并配置优先级 */
HAL_NVIC_SetPriority(MDMA_IRQn, 0x02, 0);
HAL_NVIC_EnableIRQ(MDMA_IRQn);
}
[C] 纯文本查看 复制代码 void SS67_enter_qpi_mode(void)
{
QSPI_CommandTypeDef sCommand = {0};
/* 基本配置 */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1线方式发送指令 */
sCommand.AddressSize = QSPI_ADDRESS_24_BITS; /* 32位地址 */
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q256JV不支持DDR */
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR模式,数据输出延迟 */
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输都发指令 */
/* 写使能 */
sCommand.Instruction = SS67_ENTER_QPI_MODE; /* 写使能指令 */
sCommand.AddressMode = QSPI_ADDRESS_NONE; /* 无需地址 */
sCommand.DataMode = QSPI_DATA_NONE; /* 无需数据 */
sCommand.DummyCycles = 0; /* 空周期 */
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
}
[C] 纯文本查看 复制代码 uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize)
{
QSPI_CommandTypeDef sCommand={0};
//LED3_0();
/* 用于等待发送完成标志 */
TxCplt = 0;
/* 基本配置 */
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; /* 4线方式发送指令 */
sCommand.AddressSize = QSPI_ADDRESS_24_BITS; /* 32位地址 */
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q256JV不支持DDR */
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR模式,数据输出延迟 */
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 仅发送一次命令 */
/* 写序列配置 */
sCommand.Instruction = SS67_QPI_WRITE; /* 32bit地址的4线快速写入命令 */
sCommand.DummyCycles = 0; /* 不需要空周期 */
sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址方式 */
sCommand.DataMode = QSPI_DATA_4_LINES; /* 4线数据方式 */
sCommand.NbData = _usWriteSize; /* 写数据大小 */
sCommand.Address = _uiWriteAddr; /* 写入地址 */
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 启动MDMA传输 */
if (HAL_QSPI_Transmit_DMA(&QSPIHandle, _pBuf) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
/* 等待数据发送完毕 */
// while(TxCplt == 0);
// TxCplt = 0;
// /* 等待Flash页编程完毕 */
// StatusMatch = 0;
// QSPI_AutoPollingMemReady(&QSPIHandle);
// while(StatusMatch == 0);
// StatusMatch = 0;
return 1;
}
[C] 纯文本查看 复制代码 /*
*********************************************************************************************************
* 函 数 名: QSPI_ReadBuffer
* 功能说明: 连续读取若干字节,字节个数不能超出芯片容量。
* 形 参: _pBuf : 数据源缓冲区。
* _uiReadAddr :起始地址。
* _usSize :数据个数, 可以大于PAGE_SIZE, 但是不能超出芯片总容量。
* 返 回 值: 无
*********************************************************************************************************
*/
void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize)
{
QSPI_CommandTypeDef sCommand = {0};
/* 用于等待接收完成标志 */
RxCplt = 0;
/* 基本配置 */
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES; /* 1线方式发送指令 */
sCommand.AddressSize = QSPI_ADDRESS_24_BITS; /* 32位地址 */
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q256JV不支持DDR */
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR模式,数据输出延迟 */
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输要发指令 */
/* 读取数据 */
sCommand.Instruction = SS67_QPI_READ; /* 32bit地址的4线快速读取命令 */
sCommand.DummyCycles = 6; /* 空周期 */
sCommand.AddressMode = QSPI_ADDRESS_4_LINES; /* 4线地址 */
sCommand.DataMode = QSPI_DATA_4_LINES; /* 4线数据 */
sCommand.NbData = _uiSize; /* 读取的数据大小 */
sCommand.Address = _uiReadAddr; /* 读取数据的起始地址 */
if (HAL_QSPI_Command(&QSPIHandle, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
//if (HAL_QSPI_Receive(&QSPIHandle, _pBuf, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
// {
// ERROR_HANDLER();
// }
/* MDMA方式读取 */
if (HAL_QSPI_Receive_DMA(&QSPIHandle, _pBuf) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
// /* 等接受完毕 */
// while(RxCplt == 0);
// RxCplt = 0;
}
|