小猫爪:i.MX RT1050学习笔记15-FlexSPI-FLASH使用3-KEIL FLASH算法中的使用
小猫爪:i.MX RT1050学习笔记15-FlexSPI-FLASH使用3-KEIL FLASH算法中的使用
- 1 前言
- 2 FLASH算法解析
- 2.1 初始化Init
- 2.2 写操作
- END
1 前言
在前面介绍了RT1050启动时会读取镜像的FCB数据对FlexSPI进行初始化,在下载代码进FLASH时,我们需要使用FLASH算法,那我们怎样在KEIL FLASH算法中对FlexSPI进行初始化呢,或者说怎样针对自己的FLASH设计自己的算法呢?
2 FLASH算法解析
首先去了解一下官方的源码做了什么,打开NXP RT1050的IAR FLASH算法源码(路径:C:\Keil_v5\ARM\Flash\MiMXRT105x_ATXP032)。
2.1 初始化Init
首先我们看看初始化函数,FLASH算法的FlashInit初始化函数源码如下:
int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {// Initialize pinsBOARD_InitPins();// Initialize clockBOARD_BootClockRUN();// Initialize FlexSPI controller for EcoXiPEcoXiP_init();//Unprotect all sectors in anticipation of erase/program operationsEcoXiP_unprotect_all();//Switch to Octal-DDR modeEcoXiP_enter_octal_mode(true);return 0;
}
一览无余,首先对相关引脚和时钟的初始化,这些都跟FlexSPI无关,关于FlexSPI相关的初始化全部都在EcoXiP_init中,废话不多说上源码:
// Initialize FlexSPI controller for EcoXiP
void EcoXiP_init(void)
{uint32_t i;// Set flexspi source clockconst clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};// Reset flash
#if(FLASH_RESET_METHOD == METHOD_PIN_RESET)EcoXiP_reset();
#endif
#if(FLASH_RESET_METHOD == METHOD_JEDEC_RESET)EcoXiP_jreset();
#endif// Give it some time to settle down (using EcoXiP reset recovery time)for(i = 0; i < ECOXIP_RESET_RECOVEY_US; i++)delay();// Assign pins to FlexSPI and configure them EcoXiP_config_flexspi_pins();// Point to FlexSPI baseexip_flexspi = FLEXSPI;// Set up source clockCLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 480000*18/(FLEXSPI_SOURCE_CLOCK/1000)); /* Set PLL3 PFD0 clock */CLOCK_SetMux(kCLOCK_FlexspiMux, 0x3); /* Choose PLL3 PFD0 clock as FlexSPI source clock. */// Set up SCLKflexspi_root_clock = SCLK_FREQ;deviceconfig.flexspiRootClk = flexspi_root_clock;CLOCK_SetDiv(kCLOCK_FlexspiDiv, (FLEXSPI_SOURCE_CLOCK/flexspi_root_clock) - 1); /* Divide source clock the source/root ratio. *//* Get FLEXSPI default settings and configure the FlexSPI. */FLEXSPI_GetDefaultConfig(&flexspi_config);// Enable AHB prefetchingflexspi_config.ahbConfig.enableAHBPrefetch = true;// To achieve high speeds - always use DQSflexspi_config.rxSampleClock = kFLEXSPI_ReadSampleClkExternalInputFromDqsPad;// Need to set the combination-enable option. This options combines 8 data lines// from FlexSPI channel A with 4 data lines from FlexSPI channel B to form an// 8-line bus for octal. On this SoC this is th eonly way to enable octal.flexspi_config.enableCombination = true;/* Init FlexSPI. */FLEXSPI_Init(exip_flexspi, &flexspi_config);/* Configure flash settings according to serial flash feature. */FLEXSPI_SetFlashConfig_Adesto(exip_flexspi, &deviceconfig, kFLEXSPI_PortA1);/* Update LUT table. */FLEXSPI_UpdateLUT_Adesto(exip_flexspi, 0, spi_lut, LUT_SIZE);/* Do software reset. */FLEXSPI_SoftwareReset(exip_flexspi);// Set current operation mode to SPIop_mode = SPI_MODE;// Initialize fields in the structure we will send to the FlexSPI driver.// These fields will always have the same values in our case.flashxfer.port = kFLEXSPI_PortA1;flashxfer.SeqNumber = 1;
}
可以看到其初始化过程非常的露骨,还是那么一览无余,具体过程如下:
①初始化时钟
②初始化引脚
③初始化FlexSPI外设相关的寄存器
④初始化FLASH特性相关的寄存器
⑤初始化LUT表寄存器
⑤复位FlexSPI
非常简单,再看看初始化FlexSPI外设相关的寄存器的结构体:
typedef struct _flexspi_config
{flexspi_read_sample_clock_t rxSampleClock; /*!< Sample Clock source selection for Flash Reading. */bool enableSckFreeRunning; /*!< Enable/disable SCK output free-running. */bool enableCombination; /*!< Enable/disable combining PORT A and B Data Pins(SIOA[3:0] and SIOB[3:0]) to support Flash Octal mode. */bool enableDoze; /*!< Enable/disable doze mode support. */bool enableHalfSpeedAccess; /*!< Enable/disable divide by 2 of the clock for halfspeed commands. */bool enableSckBDiffOpt; /*!< Enable/disable SCKB pad use as SCKA differential clockoutput, when enable, Port B flash access is not available. */bool enableSameConfigForAll; /*!< Enable/disable same configuration for all connected deviceswhen enabled, same configuration in FLASHA1CRx is applied to all. */uint16_t seqTimeoutCycle; /*!< Timeout wait cycle for command sequence execution,timeout after ahbGrantTimeoutCyle*1024 serial root clock cycles. */uint8_t ipGrantTimeoutCycle; /*!< Timeout wait cycle for IP command grant, timeout afteripGrantTimeoutCycle*1024 AHB clock cycles. */uint8_t txWatermark; /*!< FLEXSPI IP transmit watermark value. */uint8_t rxWatermark; /*!< FLEXSPI receive watermark value. */struct{bool enableAHBWriteIpTxFifo; /*!< Enable AHB bus write access to IP TX FIFO. */bool enableAHBWriteIpRxFifo; /*!< Enable AHB bus write access to IP RX FIFO. */uint8_t ahbGrantTimeoutCycle; /*!< Timeout wait cycle for AHB command grant,timeout after ahbGrantTimeoutCyle*1024 AHB clock cycles. */uint16_t ahbBusTimeoutCycle; /*!< Timeout wait cycle for AHB read/write access,timeout after ahbBusTimeoutCycle*1024 AHB clock cycles. */uint8_t resumeWaitCycle; /*!< Wait cycle for idle state before suspended command sequenceresume, timeout after ahbBusTimeoutCycle AHB clock cycles. */flexspi_ahbBuffer_config_t buffer[FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT]; /*!< AHB buffer size. */bool enableClearAHBBufferOpt; /*!< Enable/disable automatically clean AHB RX Buffer and TX Bufferwhen FLEXSPI returns STOP mode ACK. */bool enableAHBPrefetch; /*!< Enable/disable AHB read prefetch feature, when enabled, FLEXSPIwill fetch more data than current AHB burst. */bool enableAHBBufferable; /*!< Enable/disable AHB bufferable write access support, when enabled,FLEXSPI return before waiting for command excution finished. */bool enableAHBCachable; /*!< Enable AHB bus cachable read access support. */} ahbConfig;
} flexspi_config_t;
再看看初始化FLASH特性相关的寄存器的结构体:
typedef struct _flexspi_device_config
{uint32_t flexspiRootClk; /*!< FLEXSPI serial root clock. */bool isSck2Enabled; /*!< FLEXSPI use SCK2. */uint32_t flashSize; /*!< Flash size in KByte. */flexspi_cs_interval_cycle_unit_t CSIntervalUnit; /*!< CS interval unit, 1 or 256 cycle. */uint16_t CSInterval; /*!< CS line assert interval, mutiply CS interval unit toget the CS line assert interval cycles. */uint8_t CSHoldTime; /*!< CS line hold time. */uint8_t CSSetupTime; /*!< CS line setup time. */uint8_t dataValidTime; /*!< Data valid time for external device. */uint8_t columnspace; /*!< Column space size. */bool enableWordAddress; /*!< If enable word address.*/uint8_t AWRSeqIndex; /*!< Sequence ID for AHB write command. */uint8_t AWRSeqNumber; /*!< Sequence number for AHB write command. */uint8_t ARDSeqIndex; /*!< Sequence ID for AHB read command. */uint8_t ARDSeqNumber; /*!< Sequence number for AHB read command. */flexspi_ahb_write_wait_unit_t AHBWriteWaitUnit; /*!< AHB write wait unit. */uint16_t AHBWriteWaitInterval; /*!< AHB write wait interval, mutiply AHB write intervalunit to get the AHB write wait cycles. */bool enableWriteMask; /*!< Enable/Disable FLEXSPI drive DQS pin as write maskwhen writing to external device. */
} flexspi_device_config_t;
细心的小伙伴们可能发现了,这个结构体就是官网SDK包库的,还有这个结构体与FCB信息的结构体不一样,更加细心的小伙伴又发现了这个结构体与那个结构体大多数信息都是一样的,因为FCB是给bootROM用的,所以除了包括FlexSPI初始化的信息之外还包括了其他信息,感兴趣的小伙伴可以对比一下,找找不同。在这里我就不对结构体进行详细解释了(野火教程里对这两个结构体作了一个非常详细的解释)。
2.2 写操作
同样的,我们再来分析一下在KEIL中怎样去实现FLASH的写操作。直接找到写操作:
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {int stat;stat = EcoXiP_page_program(adr - FLASH_BASE_ADDR, sz, buf);return stat;;
}
在找到EcoXiP_page_program:
int32_t EcoXiP_page_program(uint32_t address, uint32_t size, uint8_t * data)
{uint8_t is_busy;int32_t stat;status_t flexspi_status;stat = EcoXiP_write_enable();if(stat != 0)return 1;flashxfer.cmdType = kFLEXSPI_Write;flashxfer.seqIndex = LUT_SEQ_INDEX_PAGE_PROG;flashxfer.deviceAddress = address;flashxfer.data = (uint32_t *) data;flashxfer.dataSize = size;flexspi_status = FLEXSPI_TransferBlocking(exip_flexspi, &flashxfer);if (flexspi_status != kStatus_Success)return 1;do{stat = EcoXiP_read_busy_status(&is_busy);if(stat != 0)return 1;}while(is_busy);return 0;
}
一览无余啊,三个步骤,一个写操作总共调用了三个函数,先发送写使能指令(EcoXiP_write_enable),再开始写数据(FLEXSPI_TransferBlocking),最后发送读指令读取状态确认擦写完成(EcoXiP_read_busy_status),在这里我们就单独拿出读状态EcoXiP_read_busy_status来做个介绍。直接上代码:
// Read EcoXiP status register 1
uint32_t EcoXiP_read_busy_status(uint8_t *busy_status)
{uint32_t status_reg_1;status_t flexspi_status;flashxfer.cmdType = kFLEXSPI_Read;flashxfer.seqIndex = LUT_SEQ_INDEX_READ_STATUS_REG_BYTE1;flashxfer.deviceAddress = 0;flashxfer.data = &status_reg_1;flashxfer.dataSize = 1;flexspi_status = FLEXSPI_TransferBlocking(exip_flexspi, &flashxfer);if (flexspi_status != kStatus_Success)return 1;*busy_status = (status_reg_1 & BUSY_BIT);return 0;
}
非常的简单,使用了SDK库里的发送数据结构体发起了一次IP command流程操作(具体流程可以参考我之前的文章《小猫爪:i.MX RT1050学习笔记12-FlexSPI简介》)。可以看出它调用了LUT表中序列LUT_SEQ_INDEX_READ_STATUS_REG_BYTE1的指令,找到这个序列:
// Read Status (byte 1)[4] = (QINST_CMD << 10) | (PAD_1 << 8) | (EXIP_CMD_READ_STATUS_REG_BYTE1) |(QINST_READ << 26) | (PAD_1 << 24) | (1 << 16),
整理一下就是:
指令序号 | 指令名称 | PAD数量 | OPCODE | 描述 |
---|---|---|---|---|
1 | QINST_CMD | PAD_1 | 0x05 | SDR模式1线模式向FLASH发送0x05(查芯片手册0x05为读状态寄存器第一位) |
2 | QINST_READ | PAD_1 | 1 | SDR模式1线模式读取1个字节 |
说到这里,细心的小伙伴又问了,不是不满8个指令的序列需要在后面加STOP指令吗?因为STOP指令对应的LUT表值就是0,而数组初始值为0,所以每条指令后面默认都会有STOP指令,不加STOP也是可以的。
说到这里,大家可能对LUT表的使用已经非常熟悉了吧(注意:对LUT表其他指令的解析在另外两篇文章中也有)。
对于KEIL的FLASH算法,我们不要忘记了还要对FlashDevice的初始化,直接上源码:
struct FlashDevice const FlashDevice = {FLASH_DRV_VERS, // Driver Version, do not modify!"MIMXRT105x EcoXiP Flash", // Device Name EXTSPI, // Device TypeFLASH_BASE_ADDR, // Device Start AddressFLASH_SIZE, // Device Size in BytesFLASH_PAGE_SIZE, // Programming Page Size0, // Reserved, must be 00xFF, // Initial Content of Erased Memory100, // Program Page Timeout 100 mSec3000, // Erase Sector Timeout 3000 mSec// Specify Size and Address of SectorsFLASH_SECTORE_SIZE, 0x00000000, // Sector size and start offset of this sector groupSECTOR_END
};
FlashDevice的初始化对于KEIL来说是非常重要的,需要根据实际FLASH情况对其进行修改。
根据以上的操作,我们就能针对FLASH编写自己的KEIL FLASH算法啦。FLASH算法编写完了之后,还有两处的设置不要随意篡改:
第一个就是FLASH空间大小,第二个则是FLASH算法下载的RAM位置及大小,如下图:
END
小猫爪:i.MX RT1050学习笔记15-FlexSPI-FLASH使用3-KEIL FLASH算法中的使用相关推荐
- 小猫爪:i.MX RT1050学习笔记6-Low Power
小猫爪:i.MX RT1050学习笔记6-Low Power 1 前言 2 RT1050的电源管理 2.1 PMU(Power Management Unit) 2.2 GPC(General Pow ...
- 小猫爪:i.MX RT1050学习笔记3-CCM
小猫爪:i.MX RT1050学习笔记3-CCM 1 前言 2 RT时钟的管理 3 CCM的结构 4 CCM的时钟树 5 时钟模块的具体功能 5.1 生成时钟 5.1.1 时钟源 5.1.2 7个PL ...
- 小猫爪:i.MX RT1050学习笔记2-下载
小猫爪:i.MX RT1050学习笔记2-下载 1 前言 2 Flashloader和FLASH算法 2.1 FLASH算法 2.2 Flashloader 3 下载方式 END 1 前言 在前面介绍 ...
- 小猫爪:i.MX RT1050学习笔记7-Power Supply
小猫爪:i.MX RT1050学习笔记7-Power Supply电源设计 1 前言 2 与电源相关的引脚 3 上电和掉电序列 4 关于片内DCDC模块 5 特殊引脚的处理 6 RT系列芯片由于电源波 ...
- 小猫爪:i.MX RT1050学习笔记4-IO系统
小猫爪:i.MX RT1050学习笔记4-IO系统 1 前言 2 PAD 2.1 IORING 2.2 IOMUX 2.3 IOMUXC 3 GPIO 4 应用实例 1 前言 在介绍GPIO之前,不得 ...
- 小猫爪:i.MX RT1050学习笔记5-中断NVIC
小猫爪:i.MX RT1050学习笔记5-中断NVIC 1 前言 2 中断号 3 中断优先级分组和中断优先级 4 相关操作函数 5 应用实例 5.1 RT1050 GPIO中断 5.2 中断配置过程 ...
- 小猫爪:i.MX RT1050学习笔记20-安全启动4-实现HAB签名和HAB加密
小猫爪:i.MX RT1050学习笔记20-安全启动4-实现HAB签名和HAB加密 1 前言 2 准备工作 2.1 下载Flashloader 2.2 下载CST 2.3 安装OpenSSL 3 实战 ...
- 小猫爪:i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解
i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解 1 前言 2 FlexCAN简介 2.1 MB(邮箱)系统 2.1.1 正常模式下 2.1.2 激活了CAN FD情况下 2. ...
- 小猫爪:i.MX RT1050学习笔记23-FreeRTOS移植之宇宙最详细
小猫爪:i.MX RT1050学习笔记23-FreeRTOS移植之宇宙最详细 1 前言 2 准备 2.1 下载FreeRTOS源代码 2.2 准备一个RT1050的普通工程 3 移植 3.1 添加文件 ...
最新文章
- 第五周周记(国庆第一天)
- 第一课.图与图神经网络
- 6 种不同情况下写的代码
- python数据分析视频网盘-微专业Python数据分析实战
- 【AI-1000问】为什么现在大家喜欢用3*3小卷积?
- C语言中size_t的陷阱
- 我为什么鼓励工程师写blog
- JavaScript实现按位的isPowerOfTwo算法(附完整源码)
- android定位会出现的问题,Android 定位当前位置可能出现的问题
- pta l2-6(树的遍历)
- Web进程被kill掉后线程还在运行怎么办?
- 【bzoj2730】 HNOI2012—矿场搭建
- 一些mootools的资源
- 《Python算法教程_中文版》pdf
- 利用Drawable生成圆形图片
- linux命令 执行间隙,linux 定时执行任务 at atq atrm命令的使用
- 剑指 Offer 46. 把数字翻译成字符串 【 c++/java详细题解 】
- Unity笔记之动画遮罩
- 逻辑究竟是什么以及逻辑应当是什么?
- 那些常被忽略的 html 标签