|
STM32H7A3VGTA 配置QSPI读书W25Q128储存器 读取 写入数据都正常,使用MDMA模式就出错, 使用CubeMX配置QSPI MDMA ,代码如下: /* Includes ------------------------------------------------------------------*/ #include "octospi.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ OSPI_HandleTypeDef hospi1; MDMA_HandleTypeDef hmdma_octospi1_fifo_th; /* OCTOSPI1 init function */ void MX_OCTOSPI1_Init(uint16_t ClockPrescaler) { /* USER CODE BEGIN OCTOSPI1_Init 0 */ /* USER CODE END OCTOSPI1_Init 0 */ OSPIM_CfgTypeDef sOspiManagerCfg = {0}; /* USER CODE BEGIN OCTOSPI1_Init 1 */ /* USER CODE END OCTOSPI1_Init 1 */ hospi1.Instance = OCTOSPI1; hospi1.Init.FifoThreshold = 16;// FIFO阈值为4个字节 空闲字节数 hospi1.Init.DualQuad = HAL_OSPI_DUALQUAD_DISABLE;//禁止双闪存模式 hospi1.Init.MemoryType = HAL_OSPI_MEMTYPE_MACRONIX;//储存器类型 为标准协议MACRONIX hospi1.Init.DeviceSize = 24;// SPI FLASH大小,W25Q128大小为16M字节,2^24,所以取权值24-1=23 //QSPI_FLASH_SIZE - 1; 需要扩大一倍,否则内存映射方位最后 1 个地址时,会异常 hospi1.Init.ChipSelectHighTime =3;// 范围0-7片选高电平时间为3个时钟(10*6=60ns),即手册里面的参数tSHSL1=10nS tSHSL2=50nS hospi1.Init.FreeRunningClock = HAL_OSPI_FREERUNCLK_DISABLE;//自由运行时钟模式 hospi1.Init.ClockMode = HAL_OSPI_CLOCK_MODE_0; //模式0 片选信号为高的时候时钟为低电平 hospi1.Init.WrapSize = HAL_OSPI_WRAP_NOT_SUPPORTED;//内存不支持卷读取 hospi1.Init.ClockPrescaler =ClockPrescaler; // QPSI分频比=280/(2+1)=93.333MHz,W25Q128最大频率为133M hospi1.Init.SampleShifting = HAL_OSPI_SAMPLE_SHIFTING_HALFCYCLE;// 采样移位半个周期(DDR模式下,必须设置为0) hospi1.Init.DelayHoldQuarterCycle = HAL_OSPI_DHQC_DISABLE;//DDR模式延期周期 无延迟 hospi1.Init.ChipSelectBoundary = 0;//芯片选择边界 单Flash模式(推荐设置为0) hospi1.Init.DelayBlockBypass = HAL_OSPI_DELAY_BLOCK_BYPASSED;//不使用时间延迟模块 hospi1.Init.MaxTran = 0;//最大传输字节数 DCR3 hospi1.Init.Refresh = 0;//禁用刷新率 DCR4 if (HAL_OSPI_Init(&hospi1) != HAL_OK)//函数内部包括引脚初始化void HAL_OSPI_MspInit(OSPI_HandleTypeDef* ospiHandle) { Error_Handler(); } //端口管理 sOspiManagerCfg.ClkPort = 1;//时钟引脚 sOspiManagerCfg.NCSPort = 1;//片选端口 sOspiManagerCfg.IOLowPort = HAL_OSPIM_IOPORT_1_LOW; sOspiManagerCfg.Req2AckTime = 1; if (HAL_OSPIM_Config(&hospi1, &sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN OCTOSPI1_Init 2 */ /* USER CODE END OCTOSPI1_Init 2 */ } void HAL_OSPI_MspInit(OSPI_HandleTypeDef* ospiHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(ospiHandle->Instance==OCTOSPI1) { /* USER CODE BEGIN OCTOSPI1_MspInit 0 */ /* USER CODE END OCTOSPI1_MspInit 0 */ LL_RCC_SetOSPIClockSource(LL_RCC_OSPI_CLKSOURCE_HCLK);//280MHz /* OCTOSPI1 clock enable */ __HAL_RCC_OCTOSPIM_CLK_ENABLE(); __HAL_RCC_OSPI1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); /**OCTOSPI1 GPIO Configuration PA1 ------> OCTOSPIM_P1_IO3 PA3 ------> OCTOSPIM_P1_CLK PA7 ------> OCTOSPIM_P1_IO2 PC9 ------> OCTOSPIM_P1_IO0 PC10 ------> OCTOSPIM_P1_IO1 PC11 ------> OCTOSPIM_P1_NCS */ GPIO_InitStruct.Pin = GPIO_PIN_1; 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_OCTOSPIM_P1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF3_OCTOSPIM_P1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = 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_AF10_OCTOSPIM_P1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11; 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_OCTOSPIM_P1; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* OCTOSPI1 MDMA Init */ /* MDMA controller clock enable */ __HAL_RCC_MDMA_CLK_ENABLE(); // HAL_MDMA_DeInit(&hmdma_octospi1_fifo_th); /* OCTOSPI1 MDMA Init */ // OCTOSPI1_FIFO_TH Init hmdma_octospi1_fifo_th.Instance = MDMA_Channel0; // 使用MDMA的通道0 hmdma_octospi1_fifo_th.Init.Request = MDMA_REQUEST_OCTOSPI1_FIFO_TH; // QSPI的FIFO阀值触发中断 hmdma_octospi1_fifo_th.Init.TransferTriggerMode = MDMA_BUFFER_TRANSFER; // 使用MDMA的buffer传输 hmdma_octospi1_fifo_th.Init.Priority = MDMA_PRIORITY_VERY_HIGH; // 优先级高 hmdma_octospi1_fifo_th.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;// 小端格式 hmdma_octospi1_fifo_th.Init.SourceInc = MDMA_SRC_INC_DISABLE;// BYTE;// // 源地址字节不递增 hmdma_octospi1_fifo_th.Init.DestinationInc = MDMA_DEST_INC_BYTE; // 目的地址自增 hmdma_octospi1_fifo_th.Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE; // 源地址数据宽度字节 hmdma_octospi1_fifo_th.Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE;// 目的地址数据宽度字节 hmdma_octospi1_fifo_th.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE; // 小端,右对齐 hmdma_octospi1_fifo_th.Init.BufferTransferLength = 16; // 每次传输1个字节 hmdma_octospi1_fifo_th.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE; // 源数据单次传输 hmdma_octospi1_fifo_th.Init.DestBurst = MDMA_DEST_BURST_SINGLE; // 目的数据单次传输 hmdma_octospi1_fifo_th.Init.SourceBlockAddressOffset = 0; // 用于block传输,buffer传输用不到 hmdma_octospi1_fifo_th.Init.DestBlockAddressOffset = 0; // 用于block传输,buffer传输用不到 if (HAL_MDMA_Init(&hmdma_octospi1_fifo_th) != HAL_OK)//初始化 { Error_Handler(); } if (HAL_MDMA_ConfigPostRequestMask(&hmdma_octospi1_fifo_th, 0, 0) != HAL_OK)// { Error_Handler(); } __HAL_LINKDMA(ospiHandle,hmdma,hmdma_octospi1_fifo_th); /* OCTOSPI1 interrupt Init */ HAL_NVIC_SetPriority(OCTOSPI1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(OCTOSPI1_IRQn); // /* Clear all interrupt flags */ // __HAL_MDMA_CLEAR_FLAG(&hmdma_octospi1_fifo_th, (MDMA_FLAG_TE | MDMA_FLAG_CTC | MDMA_FLAG_BT | MDMA_FLAG_BRT | MDMA_FLAG_BFTC)); // //// /* Clear the Channel Transfer Complete flag */ //// __HAL_MDMA_CLEAR_FLAG(&hmdma_octospi1_fifo_th, MDMA_FLAG_CTC); // /* Enable the Peripheral */ // __HAL_MDMA_ENABLE(&hmdma_octospi1_fifo_th); } } void HAL_OSPI_MspDeInit(OSPI_HandleTypeDef* ospiHandle) { if(ospiHandle->Instance==OCTOSPI1) { /* USER CODE BEGIN OCTOSPI1_MspDeInit 0 */ /* USER CODE END OCTOSPI1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_OCTOSPIM_CLK_DISABLE(); __HAL_RCC_OSPI1_CLK_DISABLE(); /**OCTOSPI1 GPIO Configuration PA1 ------> OCTOSPIM_P1_IO3 PA3 ------> OCTOSPIM_P1_CLK PA7 ------> OCTOSPIM_P1_IO2 PC9 ------> OCTOSPIM_P1_IO0 PC10 ------> OCTOSPIM_P1_IO1 PC11 ------> OCTOSPIM_P1_NCS */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_3|GPIO_PIN_7); HAL_GPIO_DeInit(GPIOC, GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11); /* OCTOSPI1 MDMA DeInit */ HAL_MDMA_DeInit(ospiHandle->hmdma); /* OCTOSPI1 interrupt Deinit */ HAL_NVIC_DisableIRQ(OCTOSPI1_IRQn); /* USER CODE BEGIN OCTOSPI1_MspDeInit 1 */ /* USER CODE END OCTOSPI1_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /*W25Q128 读取数据*/ #include "w25qxx_OSPI.h" #include "TFT_LCD.h"//LCD显示驱动 extern MDMA_HandleTypeDef hmdma_octospi1_fifo_th; extern OSPI_HandleTypeDef hospi1; /* 本文件使用的全局变量 */ static __IO uint8_t rx_Completed,tx_Completed,cmd_Completed,status_Match;//,timeout; /* USER CODE BEGIN 1 */ /** * @brief 初始化OSPI存储器 * @retval OSPI存储器状态 */ uint8_t W25Qxx_OSPI_Init(uint16_t ClockPrescaler) { OSPI_RegularCmdTypeDef s_command; uint16_t w25qxx_id; uint8_t value = W25QxJV_FSR_QE; /* OSPI存储器复位 */ if (W25Qxx_OSPI_ResetMemory() != OSPI_OK) { return OSPI_NOT_SUPPORTED; } /* 使能写操作 */ if (W25Qxx_OSPI_WriteEnable() != OSPI_OK) { return OSPI_ERROR; } /* 设置四路使能的状态寄存器,使能四通道IO2和IO3引脚 */ /* * @brief QSPI发送命令 * @param cmd : 要发送的指令 * @param addr: 发送到的目的地址 * @param mode: 模式,详细位定义如下: * @arg mode[1:0]: 指令模式; 00,无指令; 01,单线传输指令; 10,双线传输指令; 11,四线传输指令. * @arg mode[3:2]: 地址模式; 00,无地址; 01,单线传输地址; 10,双线传输地址; 11,四线传输地址. * @arg mode[5:4]: 地址长度; 00,8位地址; 01,16位地址; 10,24位地址; 11,32位地址. * @arg mode[7:6]: 数据模式; 00,无数据; 01,单线传输数据; 10,双线传输数据; 11,四线传输数据. * @param dmcycle: 空指令周期数 */ s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;//工作模式配置 s_command.FlashId = HAL_OSPI_FLASH_ID_1;// 第一片flash s_command.Instruction = WRITE_STATUS_REG2_CMD; //指令0x31 W25Q128指令 s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;//指令模式 s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS;//8bit数据 s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;//单通道模式 // s_command.Address = 0x000; s_command.AddressMode = HAL_OSPI_ADDRESS_NONE; // 地址模式 // s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS; s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;//单通道模式 // s_command.AlternateBytes = 0xFFFFFFFF; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;//无交替字节 // s_command.AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_8_BITS; // s_command.AlternateBytesDtrMode=HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; s_command.DataMode = HAL_OSPI_DATA_1_LINE; // 数据模式 s_command.NbData = 1;//1字节数据0-0xFFFFFFFF 0=整个储存器 s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; s_command.DummyCycles = 0; // 设置空指令周期数0-31 s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; // 每次都发送指令 s_command.DQSMode = HAL_OSPI_DQS_DISABLE;//不使用DQS /* 配置命令 */ if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } /* 传输数据 */ if (HAL_OSPI_Transmit(&hospi1, &value, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } /* 自动轮询模式等待存储器就绪 */ if (W25Qxx_OSPI_AutoPollingMemReady(W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK) { return OSPI_ERROR; } w25qxx_id=W25Qxx_OSPI_FLASH_ReadDeviceID(); /* 配置地址模式为 4 字节 , 非W25Q256直接跳过*/ if ( w25qxx_id!= W25Q256) return OSPI_OK; if (W25Qxx_OSPI_Addr_Mode_Init() != OSPI_OK) { return OSPI_ERROR; } return OSPI_OK; } /** * @brief 检查地址模式不是4字节地址,配置为4字节 * @retval OSPI存储器状态 */ uint8_t W25Qxx_OSPI_Addr_Mode_Init(void) { OSPI_RegularCmdTypeDef s_command; uint8_t reg; /* 初始化读取状态寄存器命令 */ s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; s_command.FlashId = HAL_OSPI_FLASH_ID_1; s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_STATUS_REG3_CMD;//WRITE_STATUS_REG3_CMD;//寄存器3 s_command.AddressMode = HAL_OSPI_ADDRESS_NONE; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = HAL_OSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 1; s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; /* 配置命令 */ if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } /* 接收数据 */ if (HAL_OSPI_Receive(&hospi1, ®, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } /* 检查寄存器的值 */ if ((reg & W25Q256FV_FSR_4ByteAddrMode) == 1) // 4字节模式 { return OSPI_OK; } else // 3字节模式 { /* 配置进入 4 字节地址模式命令 */ s_command.Instruction = Enter_4Byte_Addr_Mode_CMD;// s_command.DataMode = HAL_OSPI_DATA_NONE; /* 配置并发送命令 */ if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)//寄存器3 地址模式 != HAL_OK) { return OSPI_ERROR; } /* 自动轮询模式等待存储器就绪 */ if (W25Qxx_OSPI_AutoPollingMemReady( W25QxJV_SUBSECTOR_ERASE_MAX_TIME) != OSPI_OK) { return OSPI_ERROR; } return OSPI_OK; } } /*** @brief 从OSPI存储器中读取大量数据. * @param pData: 指向要读取的数据的指针 * @param ReadAddr: 读取起始地址 * @param Size: 要读取的数据大小 * @retval OSPI存储器状态 */ uint8_t W25Qxx_OSPI_Read(uint8_t *pData, uint32_t ReadAddr, uint32_t Size) { OSPI_RegularCmdTypeDef s_command; if(Size == 0) return OSPI_OK; /* 初始化读命令 */ s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; s_command.FlashId = HAL_OSPI_FLASH_ID_1; s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;//指令1线 s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;//快速读命令 s_command.AddressMode = HAL_OSPI_ADDRESS_4_LINES;//地址4线 #if W25Qxx_ID==W25Q256 s_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS; #else s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;//24位地址 #endif s_command.Address = ReadAddr; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = HAL_OSPI_DATA_4_LINES;//数据4线 s_command.DummyCycles = 6; s_command.NbData = Size; s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; /* 配置命令 */ if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)//发送快速读命令 != HAL_OK) { // Error_Handler(); return OSPI_ERROR; } /* 接收数据 */ if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK) { // Error_Handler(); //return OSPI_ERROR; } return OSPI_OK; } /** * @brief 从OSPI存储器中读取大量数据. * @param pData: 指向要读取的数据的指针 * @param ReadAddr: 读取起始地址 * @param Size: 要读取的数据大小 * @retval OSPI存储器状态 */ uint8_t W25Qxx_OSPI_Read_MDMA(uint8_t *pData, uint32_t ReadAddr, uint32_t Size) { OSPI_RegularCmdTypeDef s_command; if(Size == 0) return OSPI_OK; /* 初始化读命令 */ s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; s_command.FlashId = HAL_OSPI_FLASH_ID_1; s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE;//指令1线 s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;//快速读命令 s_command.AddressMode = HAL_OSPI_ADDRESS_4_LINES;//地址4线 #if W25Qxx_ID==W25Q256 s_command.AddressSize = HAL_OSPI_ADDRESS_32_BITS; #else s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS;//24位地址 #endif s_command.Address = ReadAddr; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = HAL_OSPI_DATA_4_LINES;//数据4线 s_command.DummyCycles = 6; s_command.NbData = Size; s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; /* 配置命令 */ if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)//发送快速读命令 != HAL_OK) { return OSPI_ERROR; } // /* MDMA方式读取 */ if (HAL_OSPI_Receive_DMA(&hospi1, pData) != HAL_OK) { // Error_Handler(); return OSPI_ERROR; } return OSPI_OK; } /** * @brief 复位OSPI存储器。 * @param hOSPI: OSPI句柄 * @retval 无 */ uint8_t W25Qxx_OSPI_ResetMemory(void) { OSPI_RegularCmdTypeDef s_command; /* 初始化复位使能命令 */ s_command.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG; s_command.FlashId = HAL_OSPI_FLASH_ID_1; s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; s_command.Instruction = RESET_ENABLE_CMD; s_command.AddressMode = HAL_OSPI_ADDRESS_NONE; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = HAL_OSPI_DATA_NONE; s_command.DummyCycles = 0; s_command.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; s_command.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; s_command.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; /* 发送命令 */ if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } /* 发送复位存储器命令 */ s_command.Instruction = RESET_MEMORY_CMD; if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } s_command.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES; s_command.Instruction = RESET_ENABLE_CMD; s_command.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; /* 发送命令 */ if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } /* 发送复位存储器命令 */ s_command.Instruction = RESET_MEMORY_CMD; if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { return OSPI_ERROR; } /* 配置自动轮询模式等待存储器就绪 */ if (W25Qxx_OSPI_AutoPollingMemReady(HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != OSPI_OK) { return OSPI_ERROR; } return OSPI_OK; } //以下为主程序 //如果操作异常,减小W25qxx频率 MX_MDMA_Init();//内置MDMA中断 HAL_OSPI_MspInit(&hospi1);//QSPI引脚初始化 MX_OCTOSPI1_Init(2);//W25qxx频率=OSPI频率/(分频+1)280/3=93.333MHz MAX CLOCKS<=133Mhz 内部引用QSPI引脚初始化 W25Qxx_OSPI_Init(2);//W25qxx频率=OSPI频率/(分频+1)280/3=93.333MHz MAX CLOCKS<=133Mhz FlashID =W25Qxx_OSPI_FLASH_ReadDeviceID(); unsigned char TEST_DATA256[256]={0}; /********普通QSPI方式读数据ok*****/ W25Qxx_OSPI_Read(&TEST_DATA256[0], 0x100, 64);//从0x100地址开始读64个数据 验证ok /*****DMA方式读不到数据********/ W25Qxx_OSPI_Read_MDMA(&TEST_DATA256[64], 0x100, 64);//从0x100地址开始读64个数据 读不到数据 Serial_USART10_SendArray(&TEST_DATA256[0], 64);//发送数组8位地址指针,发送数组 64个数 验证ok Serial_USART10_SendByte(0xFF);//串口USART1_发送 Serial_USART10_SendByte(0xFF);//串口USART1_发送 Serial_USART10_SendArray(&TEST_DATA256[64], 64);//发送数组8位地址指针,发送数组64个数 数据没有拷贝全为0 有没有哪位大佬用QSPI+MDMA能正常工作的,请分享一下 谢谢! |
感谢大佬的指点,问题解决
H7demo板下载点灯没反应
//STM32H7A3VGT6 QSPI的DMA方式无法正常工作
IDE下载程序问题
STM32H743VIT6,出给客户,客户用自己台湾产地的库存做X-ray对比,发现供货物料和他们自己的样品引线不一样,请问这是什么原因呢?有没有大神帮忙解答一下,谢谢!
STM32H750VBT6 sdio
cubeIDE编译后如何能把部分代码存放到内部Flash,剩下的存放在外部Flash?
求助:STM32H7B0 + QSPI W25Q128JV无法读取ID
STM32H743内部温度传感器读数错误
配置CubeMX后(STM32H723VGT6),自动生成的代码,编译报错
微信公众号
手机版
问题已解决:
原来是库函数内部有错误
HAL_OSPI_Receive_DMA(&hospi1, pData)//此函数内部调用库函数HAL_MDMA_Start内部源地址与目的地址调转位置了
谢谢反馈~!
我不知你使用的是什么版本的cube库,我看了手头STM32H7系列cube库v1.12.1的相关代码。
HAL_OSPI_Receive_DMA(OSPI_HandleTypeDef hospi, uint8_t pData),做接收的话,这里的pData应该是接收缓冲的地址,即存放读取结果的地址。然后它调用下面函数时:
HAL_MDMA_Start_IT(MDMA_HandleTypeDef *hmdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t BlockDataLength, uint32_t BlockCount)
就应该对应着 目标地址。
基于这个版本的HAL_MDMA_Start_IT()函数定义,我测试过是没有发现问题的,即源端、目的端没有弄反。