完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
前言
本文程序运行于STM32L452CEUX系列单片机(适用于L4),使用MDK5.33、STM32CubeMX,实现QSPI通过DMA四线读写W25Q64或128JV。 参考资料:
W25QXX命令 用到的命令如下: /* For W25Q64JV or W25Q128JV */ #define WRITE_STATUS_CFG_REG_CMD (0x01) #define WRITE_ENABLE_CMD (0x06) #define READ_ID_CMD2 (0x9F) #define READ_STATUS_REG_CMD (0x05) #define QUAD_INOUT_FAST_READ_CMD (0xEB) #define QUAD_IN_FAST_PROG_CMD (0x32) #define SUBSECTOR_ERASE_CMD (0x20) 读 W25Q64JV数据手册中的描述如下: 左上角的(1-4-4)表示指令阶段使用 1 个 IO,地址阶段使用 4 个 IO,数据阶段也是使用 4 个 IO void QSPI_ReadBuffer(uint8_t * _pBuf, uint32_t _uiReadAddr, uint32_t _uiSize) { uint8_t cnt = 0; QSPI_CommandTypeDef sCommand = {0}; /* 基本配置 */ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1 线方式发送指令 */ sCommand.AddressSize = QSPI_ADDRESS_24_BITS; /* 24 位地址 */ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q64JV 不支持 DDR */ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR 模式,数据输出延迟 */ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输要发指令 */ /* 读取数据 */ sCommand.Instruction = QUAD_INOUT_FAST_READ_CMD; /* 24bit 地址的 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(&hqspi, &sCommand, 10000) != HAL_OK) { Error_Handler(); } /* 读取 */ qspi_RxCplt = 0; if (HAL_QSPI_Receive_DMA(&hqspi, _pBuf) != HAL_OK) { Error_Handler(); } while (!qspi_RxCplt) { cnt++; if (cnt == 200) { cnt = 0; Debug("Read Timeout"); break; } HAL_Delay(50); } } qspi_RxCplt在接收完成中断置位: __IO uint8_t qspi_RxCplt = 1; void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi) { qspi_RxCplt++; } 擦除 写数据之前需要擦除 W25Q64JV数据手册中关于Sector擦除的描述如下: 左上角的(1-1-1)表示指令阶段使用 1 个 IO,地址阶段使用 1个 IO,数据阶段也是使用 1 个 IO /* ********************************************************************************************************* * 函 数 名: QSPI_EraseSector * 功能说明: 页擦除 * 形 参: _uiSectorAddr : 擦除该地址所在的页 * 返 回 值: None ********************************************************************************************************* */ void QSPI_EraseSector(uint32_t _uiSectorAddr) { QSPI_CommandTypeDef sCommand = {0}; /* 写使能 */ QSPI_WriteEnable(&hqspi); /* 基本配置 */ 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; /* W25Q64JV 不支持 DDR */ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR 模式,数据输出延迟 */ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 仅发送一次命令 */ /* 写序列配置 */ sCommand.Instruction = SUBSECTOR_ERASE_CMD; /* 32bit 地址的扇区擦除命令 */ sCommand.DummyCycles = 0; /* 不需要空周期 */ sCommand.AddressMode = QSPI_ADDRESS_1_LINE; /* 1 线地址 */ sCommand.NbData = QSPI_DATA_NONE; /* 无需发送数据 */ sCommand.Address = _uiSectorAddr; /* 扇区首地址,保证是4KB整数倍 */ if (HAL_QSPI_Command(&hqspi, &sCommand, 10000) != HAL_OK) { //return 0; Error_Handler(); } QSPI_AutoPollingMemReady(&hqspi); } 写使能 写之前需要执行写使能 /* ********************************************************************************************************* * 函 数 名: QSPI_WriteEnable * 功能说明: 写使能 * 形 参: None * 返 回 值: None ********************************************************************************************************* */ static void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef sCommand = {0}; QSPI_AutoPollingTypeDef sConfig; /* 基本配置 */ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1 线方式发送指令 */ sCommand.AddressSize = QSPI_ADDRESS_24_BITS; /* 24 位地址 */ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q64JV 不支持 DDR */ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR 模式,数据输出延迟 */ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输要发指令 */ /* 读取数据 */ sCommand.Instruction = WRITE_ENABLE_CMD; /* 写使能命令 */ sCommand.AddressMode = QSPI_ADDRESS_NONE; /* 无需地址 */ sCommand.DataMode = QSPI_DATA_NONE; /* 无需数据 */ sCommand.DummyCycles = 0; /* 空周期 */ if (HAL_QSPI_Command(hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } /* Configure automatic polling mode to wait for write enabling ---- */ sConfig.Match = 0x02; sConfig.Mask = 0x02; sConfig.MatchMode = QSPI_MATCH_MODE_AND; sConfig.StatusBytesSize = 1; sConfig.Interval = 0x10; sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; sCommand.Instruction = READ_STATUS_REG_CMD; sCommand.DataMode = QSPI_DATA_1_LINE; if (HAL_QSPI_AutoPolling(hqspi, &sCommand, &sConfig, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } } 写 /* ********************************************************************************************************* * 函 数 名: QSPI_WriteBuffer * 功能说明: 页编程,页大小 256 字节,任意页都可以写入 * 形 参: _pBuf : 数据源缓冲区; * _uiWriteAddr :目标区域首地址,即页首地址,比如 0, 256, 512 等。 * _usWriteSize :数据个数,不能超过页面大小,范围 1 - 256。 * 返 回 值: 1:成功, 0:失败 ********************************************************************************************************* */ uint8_t QSPI_WriteBuffer(uint8_t *_pBuf, uint32_t _uiWriteAddr, uint16_t _usWriteSize) { uint8_t cnt = 0; QSPI_CommandTypeDef sCommand = {0}; /* 写使能 */ QSPI_WriteEnable(&hqspi); /* 基本配置 */ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1 线方式发送指令 */ sCommand.AddressSize = QSPI_ADDRESS_24_BITS; /* 24 位地址 */ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q64JV 不支持 DDR */ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR 模式,数据输出延迟 */ sCommand.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD; /* 仅发送一次命令 */ /* 写序列配置 */ sCommand.Instruction = QUAD_IN_FAST_PROG_CMD; /* 24bit 地址的 4 线快速写入命令 */ sCommand.DummyCycles = 0; /* 不需要空周期 */ sCommand.AddressMode = QSPI_ADDRESS_1_LINE; /* 1 线地址 */ sCommand.DataMode = QSPI_DATA_4_LINES; /* 4 线数据 */ sCommand.NbData = _usWriteSize; /* 写数据大小 */ sCommand.Address = _uiWriteAddr; /* 写入地址 */ if (HAL_QSPI_Command(&hqspi, &sCommand, 10000) != HAL_OK) { //return 0; Error_Handler(); } /* 启动传输 */ qspi_TxCplt = 0; if (HAL_QSPI_Transmit_DMA(&hqspi, _pBuf) != HAL_OK) { //return 0; Error_Handler(); } while (!qspi_TxCplt) { cnt++; if (cnt == 200) { cnt = 0; Debug("Write Timeout"); break; } HAL_Delay(50); } QSPI_AutoPollingMemReady(&hqspi); return 1; } qspi_TxCplt在发送完成中断中置位: __IO uint8_t qspi_TxCplt = 1; void HAL_QSPI_TxCpltCallback(QSPI_HandleTypeDef *hqspi) { qspi_TxCplt++; } static void QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef sCommand = {0}; QSPI_AutoPollingTypeDef sConfig = {0}; /* 基本配置 */ sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; /* 1 线方式发送指令 */ sCommand.AddressSize = QSPI_ADDRESS_24_BITS; /* 24 位地址 */ sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; /* 无交替字节 */ sCommand.DdrMode = QSPI_DDR_MODE_DISABLE; /* W25Q64JV 不支持 DDR */ sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; /* DDR 模式,数据输出延迟 */ sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; /* 每次传输要发指令 */ /* 读取数据 */ sCommand.Instruction = READ_STATUS_REG_CMD; /* 读取状态命令 */ sCommand.AddressMode = QSPI_ADDRESS_NONE; /* 无需地址 */ sCommand.DataMode = QSPI_DATA_1_LINE; /* 1线数据 */ sCommand.DummyCycles = 0; /* 空周期 */ sConfig.Mask = 0x01; sConfig.Match = 0x00; sConfig.MatchMode = QSPI_MATCH_MODE_AND; sConfig.StatusBytesSize = 1; sConfig.Interval = 0x10; sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; if (HAL_QSPI_AutoPolling(hqspi, &sCommand, &sConfig, 10000) != HAL_OK) { Error_Handler(); } } 测试 uint8_t read_buf[1024]; void Normal_Test(void) { memset(read_buf, 0x79, 128); memset(read_buf + 128, 0x34, 128); QSPI_EraseSector(1); QSPI_WriteBuffer(read_buf, 0, 256); memset(read_buf, 0x77, 256); QSPI_ReadBuffer((uint8_t *)read_buf, 0, 256); for (size_t i = 0; i < 256; i++) { Debug("0x%2X ", read_buf); } } |
|
|
|
只有小组成员才能发言,加入小组>>
3323 浏览 9 评论
3000 浏览 16 评论
3498 浏览 1 评论
9073 浏览 16 评论
4093 浏览 18 评论
1194浏览 3评论
613浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
603浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2342浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1902浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 08:59 , Processed in 1.169344 second(s), Total 80, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号