|
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个时钟(106=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));
// // / 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 / /**
uint8_t W25Qxx_OSPI_Init(uint16_t ClockPrescaler) { OSPI_RegularCmdTypeDef s_command; uint16_t w25qxx_id; uint8_t value = W25QxJV_FSR_QE;
if (W25Qxx_OSPI_ResetMemory() != OSPI_OK) { return OSPI_NOT_SUPPORTED; } / 使能写操作 / if (W25Qxx_OSPI_WriteEnable() != OSPI_OK) { return OSPI_ERROR; } / 设置四路使能的状态寄存器,使能四通道IO2和IO3引脚 / /*
/**
//从W25Q128中指定地址读取图片数据进行显示 void TFT_LCD_showimage_QSPI_MDMA(unsigned short Line_start,unsigned short Column_start,unsigned short Column_Size,unsigned short Line_Size,unsigned int Addr_offset) //显示图片 { unsigned char IMAGE_DATA[Column_Size*2]; uint8_t temp; unsigned int ii,jj; unsigned short picH,picL;
TFT_LCD_DC_1 ; //写入数据 SPI1->CR1 &=0xFFFFFFFE;//停止SPI1 SPI1->CFG1 |=0x000F000F;//16位模式 |=0x000F000F SPI1->CR1 |=0x01;//使能SPI1(SPE)
SPI1->CR1|=1<<9;//主传输开始 CSCART while((SPI1->SR&1<<1)==0); //等待发送区空 ((__IO uint16_t )&SPI1->TXDR) = (picH<<8|picL); //发送一个HalfWord SPI1->IFCR|=3<<3;//传输结束标志清零 (End Of Transfer flag clear),向该位写入 1 可将 SPI2S_SR 寄存器的 EOT 标志清零 } } SPI1->CR1 &=0xFFFFFFFE;//停止spi SPI1->CFG1 &=0xFFE7FFE7;//8位模式&=0xFFE7FFE7 SPI1->CR1 |=0x01;//打开spi } //以下为主程序 //如果操作异常,减小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 = SPI_FLASH_ReadID(); FlashID2 =W25Qxx_OSPI_FLASH_ReadDeviceID(); TFT_LCD_showimage_QSPI_MDMA(0,0,240,320,gImage_240_320_01FLASH_ADD); //显示图片 delay_with_IWDG(20);//100mS*TIMES 以上如果使用以下命令工作正常 / 接收数据 / if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK) { // Error_Handler(); return OSPI_ERROR; } 如果改成以下命令就死机 // / MDMA方式读取 / if (HAL_OSPI_Receive_DMA(&hospi1, pData) != HAL_OK) { Error_Handler(); // return OSPI_ERROR; } 有没有哪位大佬用QSPI+MDMA能正常工作的,请分享一下 谢谢! |
【2025.10.29】每日签到:STM32 Bootloader使用情况调查问卷最后一天!
【2025.10.28】每日签到:广州/南京 | STM32GUI图形界面应用开发实训(基于STM32H7R7/S7 + TouchGFX开发平台)
【2025.10.09】每日签到:假期结束都有收获吗?
【2025.10.27】每日签到:STM32 Bootloader使用情况调查问卷记得来填写!
【2025.10.24】每日签到:立即在GitHub上抢先体验面向STM32U5的最新STM32Cube HAL更新
【2025.10.23】每日签到:下午STM32MP135直播,记得预约全球峰会直播!
1024休息一下
【2025.10.22】每日签到:STM32全球线上峰会已上线, 速来报名>>
【2025.10.21】每日签到:下午2点直播ST在通用伺服与机器人电机控制应用中的解决方案与产品介绍
【2025.10.20】每日签到:明天ST在通用伺服与机器人电机控制应用中的解决方案与产品介绍直播,记得来预约!
微信公众号
手机版