你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32H7A3VGTA QSPI读W25Q128J DMA模式不能工作

[复制链接]
onlap 提问时间:2025-10-29 23:14 / 已解决
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能正常工作的,请分享一下 谢谢!

收藏 评论5 发布时间:2025-10-29 23:14

举报

5个回答
onlap 回答时间:2025-11-5 21:47:28

问题已解决:

原来是库函数内部有错误

HAL_OSPI_Receive_DMA(&hospi1, pData)//此函数内部调用库函数HAL_MDMA_Start内部源地址与目的地址调转位置了

xmshao 回答时间:2025-11-6 16:33:32

谢谢反馈~!

我不知你使用的是什么版本的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()函数定义,我测试过是没有发现问题的,即源端、目的端没有弄反。

onlap 回答时间:2025-11-11 08:43:48

/ Enable the transmit MDMA Channel / if (HAL_MDMA_Start_IT(hospi->hmdma, (uint32_t)pData, (uint32_t)&hospi->Instance->DR, hospi->XferSize, 1) == HAL_OK)

这个位置弄反了

onlap 回答时间:2025-11-11 14:02:30

xmshao 发表于 2025-11-6 16:33
谢谢反馈~!</p>
<p>我不知你使用的是什么版本的cube库,我看了手头STM32H7系列cube库<strong>v1.12.1</strong>的相关代码 ...

[md]/ Enable the transmit MDMA Channel / if (HAL_MDMA_Start_IT(hospi->hmdma, (uint32_t)pData, (uint32_t)&hospi->Instance->DR, hospi->XferSize, 1) == HAL_OK)

这个位置错了

xmshao 回答时间:2025-11-11 18:00:26

onlap 发表于 2025-11-11 14:02
/<em> Enable the transmit MDMA Channel </em>/
if (HAL_MDMA_Start_IT(hospi-&gt;hmdma, (uint32_t)pData, (u ...

[md]现在的版本是正确的:

image.png

HAL_OSPI_Receive_DMA(OSPI_HandleTypeDef hospi, uint8_t pData)

image.png

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版