i.MX RT1052 Mini核心板板载了32MB的NorFlash存储芯片,QSPI接口,走的flexspi总线。本帖子主要测试下通过qspi想 norflash芯片中写入256个数据,在读出来,验证qspi的读写操作,通过串口打印相关信息。
先看下串口打印信息:
原理图如下图所示:
对应1052引脚
其中:
FlexSPI_SS0 ---> GPIO_SD_B1_06 ---> FLEXSPI_A_SS0_B |
FlexSPI_CLK ---> GPIO_SD_B1_07 ---> FLEXSPI_A_SCLK |
FlexSPI_D0_A ---> GPIO_SD_B1_08 ---> FLEXSPI_A_DATA0 |
FlexSPI_D1_A ---> GPIO_SD_B1_09 ---> FLEXSPI_A_DATA1 |
FlexSPI_D2_A ---> GPIO_SD_B1_10 ---> FLEXSPI_A_DATA2 |
FlexSPI_D3_A ---> GPIO_SD_B1_11 ---> FLEXSPI_A_DATA3 |
FlexSPI是一个灵活的SPI(串行外围接口)主机控制器,它支持两个SPI通道和多达4个外部设备。每个通道支持单/双/四/八进制数据传输(1/2/4/8双向数据线)。
时序图:
FlexSPI控制器的iniitialization序列如下: •在系统级启用控制器时钟(AHB时钟/IP总线时钟/串行根时钟)。 •将MCR0[MDIS]设置为0x1(确保控制器配置为模块停止模式) •配置模块控制寄存器:MCR0、MCR1、MCR2。(不改变MCR0(MDIS)) •配置AHB总线控制寄存器(AHBCR)和AHB RX缓冲区控制寄存器(AHBRXBUFxCR)如果使用AHB命令,则可以选择。 •配置Flash控制寄存器(FLSHxCR0、FLSHxCR1、FLSHxCR2)外部设备类型 •根据样本时钟源配置DLL控制寄存器(DLLxCR)选择 •将MCR0[MDIS]设为0x0(退出模块停止模式) •根据需要配置LUT(用于AHB命令或IP命令) •可选重置控制器(通过将MCR0[SWRESET]设置为0x1)外部设备在控制器之后通常需要通过IP命令进行配置初始化。例如,设备配置是通过写入状态完成的大多数串行或Flash的命令。
- void NorFlashInit(void)
- {
- flexspi_config_t config;
- const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
- CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);
- CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 24); /* Set PLL3 PFD0 clock 360MHZ. */
- CLOCK_SetMux(kCLOCK_FlexspiMux, 0x3); /* Choose PLL3 PFD0 clock as flexspi source clock. */
- CLOCK_SetDiv(kCLOCK_FlexspiDiv, 2); /* flexspi clock 120M. */
- SCB_DisableDCache();
- PRINTF("\r\nNorFlash初始化\r\n");
- /*获取 FLEXSPI 默认设置并配置 FLEXSPI */
- FLEXSPI_GetDefaultConfig(&config);
- /*设置通过 AHB 总线读取数据的 AHB 缓冲区大小. */
- config.ahbConfig.enableAHBPrefetch = true;
- FLEXSPI_Init(FLEXSPI, &config);
- /* 根据串行闪存功能配置闪存设置. */
- FLEXSPI_SetFlashConfig(FLEXSPI, &deviceconfig, kFLEXSPI_PortA1);
- /* 更新查找表. */
- FLEXSPI_UpdateLUT(FLEXSPI, 0, customLUT, CUSTOM_LUT_LENGTH);
- }
复制代码
- void FLEXSPI_GetDefaultConfig(flexspi_config_t *config)
- {
- config->rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackInternally;
- config->enableSckFreeRunning = false;
- config->enableCombination = false;
- config->enableDoze = true;
- config->enableHalfSpeedAccess = false;
- config->enableSckBDiffOpt = false;
- config->enableSameConfigForAll = false;
- config->seqTimeoutCycle = 0xFFFFU;
- config->ipGrantTimeoutCycle = 0xFFU;
- config->txWatermark = 8;
- config->rxWatermark = 8;
- config->ahbConfig.enableAHBWriteIpTxFifo = false;
- config->ahbConfig.enableAHBWriteIpRxFifo = false;
- config->ahbConfig.ahbGrantTimeoutCycle = 0xFFU;
- config->ahbConfig.ahbBusTimeoutCycle = 0xFFFFU;
- config->ahbConfig.resumeWaitCycle = 0x20U;
- memset(config->ahbConfig.buffer, 0, sizeof(config->ahbConfig.buffer));
- config->ahbConfig.enableClearAHBBufferOpt = false;
- config->ahbConfig.enableAHBPrefetch = false;
- config->ahbConfig.enableAHBBufferable = false;
- config->ahbConfig.enableAHBCachable = false;
- }
复制代码 根据串行闪存功能配置闪存设置,设置qspi的时序和引脚绑定。
FLEXSPI_SetFlashConfig(FLEXSPI, &deviceconfig, kFLEXSPI_PortA1);(疑问:这里为什么是kFLEXSPI_PortA1 没看明白?)
- /*! @brief FLEXSPI operation port select.*/
- typedef enum _flexspi_port
- {
- kFLEXSPI_PortA1 = 0x0U, /*!< Access flash on A1 port. */
- kFLEXSPI_PortA2 = 0x1U, /*!< Access flash on A2 port. */
- kFLEXSPI_PortB1 = 0x2U, /*!< Access flash on B1 port. */
- kFLEXSPI_PortB2 = 0x3U, /*!< Access flash on B2 port. */
- } flexspi_port_t;
复制代码
时序- flexspi_device_config_t deviceconfig = {
- .flexspiRootClk = 100000000,
- .flashSize = FLASH_SIZE,
- .CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
- .CSInterval = 2,
- .CSHoldTime = 3,
- .CSSetupTime = 3,
- .dataValidTime = 0,
- .columnspace = 0,
- .enableWordAddress = 0,
- .AWRSeqIndex = 0,
- .AWRSeqNumber = 0,
- .ARDSeqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD,
- .ARDSeqNumber = 1,
- .AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
- .AHBWriteWaitInterval = 0,
- };
复制代码
在测试代码中先读取flash的id- /* 获取vendor ID. */
- status = flexspi_nor_get_vendor_id(FLEXSPI, &vendorID);
- if (status != kStatus_Success)
- {
- return status;
- }
- PRINTF("Vendor ID: 0x%x\r\n", vendorID);
复制代码
然后进入quad模式
- /* 进入quad模式. */
- status = flexspi_nor_enable_quad_mode(FLEXSPI);
- if (status != kStatus_Success)
- {
- return status;
- }
复制代码
然后先擦除扇区,flash擦除扇区就是写1操作,所以读出来的数据都是oxff
- status = flexspi_nor_flash_erase_sector(FLEXSPI, EXAMPLE_SECTOR * SECTOR_SIZE);
- if (status != kStatus_Success)
- {
- PRINTF("擦除flash扇区失败 !\r\n");
- return -1;
- }
复制代码
然后写入数据
- status =
- flexspi_nor_flash_page_program(FLEXSPI, EXAMPLE_SECTOR * SECTOR_SIZE, (void *)s_nor_program_buffer);
- if (status != kStatus_Success)
- {
- PRINTF("页写入失败 !\r\n");
- return -1;
- }
复制代码
|