痞子衡嵌入式:其实i.MXRT下改造FlexSPI driver同样支持AHB方式去写入NOR Flash (2)

  但也不要就此放弃,单独 Page Program 子序列还是可以通过 AHB 方式写来替代的,这样也可以让我们过一下 AHB 方式写入 Flash 的瘾,只是需要在 AHB 写入操作前后辅助 IPG 方式下的 Write Enable 和 Read Status 动作,下一节用代码给大家实际演示。

痞子衡嵌入式:其实i.MXRT下改造FlexSPI driver同样支持AHB方式去写入NOR Flash

三、FlexSPI driver用法 例程路径:\SDK_2.10.0_MIMXRT1170-EVK\boards\evkmimxrt1170\driver_examples\flexspi\nor\polling_transfer\cm7\iar 3.1 初始化

  先来看一下 FlexSPI 初始化函数 flexspi_nor_flash_init(),这个函数需要三个配置变量:分别是 flexspi_config_t 型面向 FlexSPI 外设层的配置 flexspiconfig,flexspi_device_config_t 型面向 Flash 器件端的配置 deviceconfig,以及很核心的 customLUT(这里只列出了跟 Flash 写操作相关的时序)。

#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE 2 #define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD 4 #define NOR_CMD_LUT_SEQ_IDX_READSTATUSREG 12 #define CUSTOM_LUT_LENGTH 60 const uint32_t customLUT[CUSTOM_LUT_LENGTH] = { /* Write Enable */ [4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), /* Page Program - quad mode */ [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x32, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), [4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), /* Read status register */ [4 * NOR_CMD_LUT_SEQ_IDX_READSTATUSREG] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x05, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04), }; flexspi_device_config_t deviceconfig = { .flexspiRootClk = 12000000, .flashSize = 0x4000, /* 16Mb/KByte */ .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, }; void flexspi_nor_flash_init(FLEXSPI_Type *base) { CLOCK_SetRootClockDiv(kCLOCK_Root_Flexspi1, 2); CLOCK_SetRootClockMux(kCLOCK_Root_Flexspi1, 0); /*Get FLEXSPI default settings and configure the flexspi. */ flexspi_config_t flexspiconfig; FLEXSPI_GetDefaultConfig(&flexspiconfig); /*Set AHB buffer size for reading data through AHB bus. */ flexspiconfig.ahbConfig.enableAHBPrefetch = true; flexspiconfig.ahbConfig.enableAHBBufferable = true; flexspiconfig.ahbConfig.enableReadAddressOpt = true; flexspiconfig.ahbConfig.enableAHBCachable = true; flexspiconfig.rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackFromDqsPad; FLEXSPI_Init(base, &flexspiconfig); /* Configure flash settings according to serial flash feature. */ FLEXSPI_SetFlashConfig(base, &deviceconfig, kFLEXSPI_PortA1); /* Update LUT table. */ FLEXSPI_UpdateLUT(base, 0, customLUT, CUSTOM_LUT_LENGTH); /* Do software reset. */ FLEXSPI_SoftwareReset(base); } 3.2 一般用法(IPG写)

  先来看 IPG 方式的 Flash 写入函数,其中 Page Program 子时序是通过 FLEXSPI_TransferBlocking() 函数来完成的,这个函数就是往大小为 256 bytes 的 IP TX FIFO 写 src 里的数据(默认 FlexSPI->MCR0[ATDFEN] = 0 情况下),SEQ_CTL 组件处理时会将缓存在 IP TX FIFO 里的数据全部发送到 Flash 端。

void flexspi_nor_flash_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t size) { // Write Enable 子时序 flexspi_nor_write_enable(base, dstAddr); flexspi_transfer_t flashXfer; flashXfer.deviceAddress = dstAddr; flashXfer.port = kFLEXSPI_PortA1; flashXfer.cmdType = kFLEXSPI_Write; flashXfer.SeqNumber = 1; flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD; flashXfer.data = (uint32_t *)(void *)src; flashXfer.dataSize = size; // page program 子时序 FLEXSPI_TransferBlocking(base, &flashXfer); // Read Status 子时序 flexspi_nor_wait_bus_busy(base); FLEXSPI_SoftwareReset(base); } 3.3 特殊用法(AHB写)

  我们现在来改造 IPG 方式的 Flash 写入函数,首先要修改 deviceconfig 变量将 AWRSeqIndex 指向 PAGEPROGRAM_QUAD 在 LUT 中的位置,然后将 FLEXSPI_TransferBlocking() 函数换成 AHB 写入代码(memcpy 或者指针操作赋值),这时候 src 里的数据就会被自动放在大小为 64 bytes 的 AHB TX Buffer 里,SEQ_CTL 组件处理时会将缓存在 AHB TX Buffer 里的数据全部发送到 Flash 端。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwspwp.html