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

//STM32H7A3VGT6 QSPI的DMA方式无法正常工作

[复制链接]
onlap 提问时间:2025-10-31 21:03 / 未解决
//STM32H7A3VGT6  QSPI的DMA方式无法正常工作
/* USER CODE END Header */
/* 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 = 4;//     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; // 每次传输16个字节
    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);
               
  }
}

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 */

extern MDMA_HandleTypeDef hmdma_octospi1_fifo_th;
extern OSPI_HandleTypeDef hospi1;


/* USER CODE BEGIN 1 */
/*
HAL_QSPI_Init
HAL_QSPI_DeInit
HAL_QSPI_Command
HAL_QSPI_Command_IT
HAL_QSPI_AutoPolling
HAL_QSPI_AutoPolling_IT
HAL_QSPI_Transmit
HAL_QSPI_Receive
HAL_QSPI_Transmit_DMA
HAL_QSPI_Receive_DMA
HAL_QSPI_MemoryMapped
*/
/**
* @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, &reg, 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)
        {
                return OSPI_ERROR;
        }

        /* 接收数据 */
        if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK)
        {
                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)
        {                //OCTOSPI1->DR=0x52005050
                   //MDMABASE=0x52000000
                //        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;
}


/**
* @brief  发送写入使能,等待它有效.
* @param  hOSPI: OSPI句柄
* @retval 无
*/
uint8_t W25Qxx_OSPI_WriteEnable(void)
{
        OSPI_RegularCmdTypeDef s_command;
        OSPI_AutoPollingTypeDef s_config;
        /* 启用写操作 */
        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        = WRITE_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       = READ_STATUS_REG1_CMD;
        s_command.DataMode          = HAL_OSPI_DATA_1_LINE;
        s_command.NbData            = 1;
       
        if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK)//读寄存器1状态
        {
                return OSPI_ERROR;
        }
        /* 配置自动轮询模式等待写启用 */
        s_config.Match = W25QxJV_FSR_WREN;;//匹配写使能数据
        s_config.Mask = W25QxJV_FSR_WREN;;//寄存器第2位
        s_config.MatchMode = HAL_OSPI_MATCH_MODE_AND;//逻辑与判断 完全匹配
        s_config.Interval = 0x10;//查询间隔时间0-0xFFFF CLK周期
        s_config.AutomaticStop = HAL_OSPI_AUTOMATIC_STOP_ENABLE;//匹配后自动停止检测

        if (HAL_OSPI_AutoPolling(&hospi1, &s_config, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_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(12);//W25qxx频率=OSPI频率/(分频+1)280/3=93.333MHz MAX CLOCKS<=133Mhz
       
        FlashID =W25Qxx_OSPI_FLASH_ReadDeviceID();
        unsigned char TEST_DATA256[256]={0};       
              //以下直接读取数据正常
        W25Qxx_OSPI_Read(&TEST_DATA256[0], 0x100, 64);//从0x100地址开始读64个数据

            //以下DMA方式无法读取数据
        W25Qxx_OSPI_Read_MDMA(&TEST_DATA256[64], 0x100, 64);//从0x100地址开始读64个数据

        Serial_USART10_SendArray(&TEST_DATA256[0], 64);//发送数组8位地址指针,发送数组 64位数 查看QSPI接收数据正常
        Serial_USART10_SendByte(0xFF);//串口USART1_发送
        Serial_USART10_SendByte(0xFF);//串口USART1_发送                       
        Serial_USART10_SendArray(&TEST_DATA256[64], 64);//发送数组8位地址指针,发送数组 64位数         查看MDMA方式接收数据为0,无变化




收藏 评论0 发布时间:2025-10-31 21:03

举报

0个回答

所属标签

相似问题

官网相关资源

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