FLM_0">如何制作符合自己设备的FLM下载算法
--------以I.MXRT1062 QSPI FLAH为例(串行qspi nor flash)
本文介绍一种基于i.mxrt1062的外挂flah的qspi nor flash下载算法FLM的一种方法,Flash 编程算法是一种用于擦除或下载应用程序到 Flash 设备的软件。设备系列包 (DFP) 通常包含预定义的 Flash 算法,用于对其中支持的设备进行编程。ARM:CMSIS 包中提供了用于创建新算法的模板。以下部分更详细地介绍了该过程。
前言
什么是FLM?FLM(FLASH Loader Middeware)即闪存加载中间件,一般来说FLM下载算法不需要我们制作,因为使用Keil MDK进行开发,我们需要安装packet软件包,而这软件包就包含了FLM下载算法。当我们在keil mdk中编译好了镜像(hex 、bin、srec、elf)文件需要下载到flash当中时,首先需要选择适合您开发板的FLM下载算法。
FLM下载算法" />
从上图可以看到我们可以选择的下载算法有都在列表里面了,但是我们要把程序下载进去需要选择适合自己的FLM文件,像开发STM32则直接选择就可以了,我们在安装软件包时候就已经将下载算法包含到Flash文件夹当中了。我们可以打开keil mdk的安装目录进行查看(路径为**…**/keil/arm/flash)文件夹下。
1、下载算法原理
我们使用下载工具(J-Link、ST-Link、DAP-Link)进行下载,其本质就是将FLM(Flash Loader Middeware)加载到RAM当中(可以理解为将一段操作FLASH的代码下载到RAM中然后通过这段程序将code下载到FLASH中),然后通过FLM作为媒介将程序下载到Flash当中。
注: 截自 <Programming External Flash used with STM32 Devices MDK Tutorial AN333, Autumn 2020, v1.0>
2、工程模板
笔者认为想要去快速入门某一样事情,最快的方式是先找历程demo,先把demo跑通然后再去深究其实现原理。这是尤为重要。回到本文的核心,怎么做?怎么找到模板?答案肯定是有的,除了在安装软件包附带的FLM下载算法之外还有keil 给我们留下的工程模板,这个模板的位置在keil5安录/ARM/Flash/_Template这个文件夹里面有给模板工程,我们对工程进行编译会发现会得到一个.FLM文件。
打开工程会发现工程目录只有简单的几个文件。
那么这两个文件有什么奥妙呢?接下来笔者为大家一一解密,解其全貌。
-
Abstract.txt
这个文件里面写了笔记以及参考的网站。http://arm-software.github.io/CMSIS_5/Pack/html/flashAlgorithm.html
-
FlashPrag.c
这个文件是和你的下载息息相关,大家可以去看看里面的函数,不难发现里面的函数是空函数,这部分需要读者自己去实现。
这些函数分别是
-
FlashDev.c
这个文件是我们注册的设备结构体,和您的设备相关。
/***************************************************************************** @file FlashDev.c* @brief Flash Device Description for New Device Flash* @version V1.0.0* @date 10. January 2018******************************************************************************/ /** Copyright (c) 2010-2018 Arm Limited. All rights reserved.** SPDX-License-Identifier: Apache-2.0** Licensed under the Apache License, Version 2.0 (the License); you may* not use this file except in compliance with the License.* You may obtain a copy of the License at** www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include "FlashOS.H" // FlashOS Structures/* ZLG-MIMxRT1062 */ struct FlashDevice const FlashDevice = {FLASH_DRV_VERS, /* 设备版本 不能更改! */"MIMxRT1062_W25Q256", /* 设备名称 */ EXTSPI, /* 设备类型 可以跳转到FlashOS.H去查看 相关的定义 */ 0x60000000, /* Flash设备shou地址 会将这个地址挂载到AHB总线上 */ 0x00800000, /* Flash设备的空间大小 这里是0x010000000 也就是16MB*/ 256, /* 编程页的大小 根据Flash的型号数据手册可以选择256 但是为了速度快一些可以选择 4096 */ 0, /* 保留位,但是这里不能修改必须默认为0 */ 0xFF, /* 擦除内存的初始内容 */ 100, /* 程序页面超时 100 毫秒 根据手册可以修改相应的时间 */ 3000, /* 擦除扇区超时 3000 毫秒 根据手册可以修改相应的时间*/ 0x001000, 0x000000, /* 扇区大小 4KB*/ SECTOR_END };
3、实战
[!NOTE]
将模板工程复制到卓面(路径为:安装目录\Keil_v5\ARM\Flash_Template),取名为MIMxRT1062_xxxx(工程名称随意取)。除此之外我们还需要将从nxp官网的sdk下载到卓面。
1、将keil提供的模板复制到卓面中
2、从nxp官网下载官方evk的sdk
👍参考连接为:https://mcuxpresso.nxp.com/zh
进去之后选择开发板,选项,如在过程中提示需要登陆则先注册登录。
进去之后选择电路板/处理器,然后电机右下角的构建SDK,后面勾选全部工具链,最后点击下载即可。
点击构建sdk,最后点击下载即可。
下载完成之之后将SDK进行解压缩操作。
同步打开复制到卓面的工程模板
图上勾选的是从SDK中复制过来的文件夹,CMSIS、devices,里面有芯片的一些相关信息,复制进行主要是为了对芯片进行init的时候起到作用。其中的flexspi文件夹是因为板子使用flexspi操作flash,所以进行了分类。flash_ops文件夹是操作flash的具体函数。
做完这些之后我们开始点击工程,进到keil中进行代码的编写。
[!IMPORTANT]
接下来就是在keil中进行代码的编写了,这段内容比较重要,在文章的结尾会给示例demo连接
打开keil工程
接下来就是对以上的文件进行代码的编写和接口的编了,先进行编译确保工程可以编译通过。
-
对FlashDev.c进行编写
/**************************************************************************//*** @file FlashDev.c* @brief Flash Device Description for New Device Flash* @version V1.0.0* @date 10. January 2018******************************************************************************/ /** Copyright (c) 2010-2018 Arm Limited. All rights reserved.** SPDX-License-Identifier: Apache-2.0** Licensed under the Apache License, Version 2.0 (the License); you may* not use this file except in compliance with the License.* You may obtain a copy of the License at** www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#include "FlashOS.H" // FlashOS Structures#if 0 /* 模板可以作为参考的一个示例 */ struct FlashDevice const FlashDevice = {FLASH_DRV_VERS, // Driver Version, do not modify!"New Device 256kB Flash", // Device Name ONCHIP, // Device Type0x00000000, // Device Start Address0x00040000, // Device Size in Bytes (256kB)1024, // 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 Sectors0x002000, 0x000000, // Sector Size 8kB (8 Sectors)0x010000, 0x010000, // Sector Size 64kB (2 Sectors) 0x002000, 0x030000, // Sector Size 8kB (8 Sectors)SECTOR_END }; #else /* ZLG-MIMxRT1062 */ struct FlashDevice const FlashDevice = {FLASH_DRV_VERS, /* 设备版本 不能更改! */"MIMxRT1062_W25Q256", /* 设备名称 */ EXTSPI, /* 设备类型 可以跳转到FlashOS.H去查看 相关的定义 */ 0x60000000, /* Flash设备shou地址 会将这个地址挂载到AHB总线上 */ 0x00800000, /* Flash设备的空间大小 这里是0x010000000 也就是16MB*/ 256, /* 编程页的大小 根据Flash的型号数据手册可以选择256 但是为了速度快一些可以选择 4096 */ 0, /* 保留位,但是这里不能修改必须默认为0 */ 0xFF, /* 擦除内存的初始内容 */ 100, /* 程序页面超时 100 毫秒 根据手册可以修改相应的时间 */ 3000, /* 擦除扇区超时 3000 毫秒 根据手册可以修改相应的时间*/ 0x001000, 0x000000, /* 扇区大小 4KB*/ SECTOR_END };#endif
这里可以理解为是对设备进行注册,这些包含了flash信息,具体需要去看下载的Flash的数据手册和应用手册
-
FlashPrag.c
/**************************************************************************//*** @file FlashPrg.c* @brief Flash Programming Functions adapted for New Device Flash* @version V1.0.0* @date 10. January 2018******************************************************************************/ /** Copyright (c) 2010-2018 Arm Limited. All rights reserved.** SPDX-License-Identifier: Apache-2.0** Licensed under the Apache License, Version 2.0 (the License); you may* not use this file except in compliance with the License.* You may obtain a copy of the License at** www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an AS IS BASIS, WITHOUT* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*///CPU_MIMXRT1052DVL6B, MCUXPRESSO_SDK #include "FlashOS.H" // FlashOS Structures #include "fsl_flexspi.h" #include "app.h" extern status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address); extern status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src); extern status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId); extern status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base); extern status_t flexspi_nor_erase_chip(FLEXSPI_Type *base); extern void flexspi_nor_flash_init(FLEXSPI_Type *base); #define FLASH_BASE_ADR (0x60000000)#if 1 /* 初始化Flash */ int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {(void)adr;(void)clk;(void)fnc;flexspi_nor_flash_init(FLEXSPI);return (0); } /* 解除初始化 */ int UnInit (unsigned long fnc) {return (0); } /* 擦除芯片 */ int EraseChip (void) {return (flexspi_nor_erase_chip(FLEXSPI)); } /* 扇区擦除 */ int EraseSector (unsigned long adr) {return (flexspi_nor_flash_erase_sector(FLEXSPI, adr - FLASH_BASE_ADR)); } /* 下载 */ int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {return ( flexspi_nor_flash_page_program( FLEXSPI, adr - FLASH_BASE_ADR, (uint32_t*)buf)); }#endif
这个文件实际上就是对Flash的接口进行配置
-
flexspi.c
/** Copyright (c) 2016, Freescale Semiconductor, Inc.* Copyright 2016-2022, 2023 NXP* All rights reserved.** SPDX-License-Identifier: BSD-3-Clause*/#include "fsl_flexspi.h"/* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.flexspi" #endif/******************************************************************************** Definitions******************************************************************************/#define FREQ_1MHz (1000000UL) #define FLEXSPI_DLLCR_DEFAULT (0x100UL) #define FLEXSPI_LUT_KEY_VAL (0x5AF05AF0UL)enum {kFLEXSPI_DelayCellUnitMin = 75, /* 75ps. */kFLEXSPI_DelayCellUnitMax = 225, /* 225ps. */ };enum {kFLEXSPI_FlashASampleClockSlaveDelayLocked =FLEXSPI_STS2_ASLVLOCK_MASK, /* Flash A sample clock slave delay line locked. */kFLEXSPI_FlashASampleClockRefDelayLocked =FLEXSPI_STS2_AREFLOCK_MASK, /* Flash A sample clock reference delay line locked. */ #if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK)) && (FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK))kFLEXSPI_FlashBSampleClockSlaveDelayLocked =FLEXSPI_STS2_BSLVLOCK_MASK, /* Flash B sample clock slave delay line locked. */ #endif #if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BREFLOCK)) && (FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BREFLOCK))kFLEXSPI_FlashBSampleClockRefDelayLocked =FLEXSPI_STS2_BREFLOCK_MASK, /* Flash B sample clock reference delay line locked. */ #endif };/*! @brief Common sets of flags used by the driver, _flexspi_flag_constants. */ enum {/*! IRQ sources enabled by the non-blocking transactional API. */kIrqFlags = kFLEXSPI_IpTxFifoWatermarkEmptyFlag | kFLEXSPI_IpRxFifoWatermarkAvailableFlag |kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag |kFLEXSPI_IpCommandGrantTimeoutFlag | kFLEXSPI_IpCommandExecutionDoneFlag,/*! Errors to check for. */kErrorFlags = kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag |kFLEXSPI_IpCommandGrantTimeoutFlag, };/* FLEXSPI transfer state, _flexspi_transfer_state. */ enum {kFLEXSPI_Idle = 0x0U, /*!< Transfer is done. */kFLEXSPI_BusyWrite = 0x1U, /*!< FLEXSPI is busy write transfer. */kFLEXSPI_BusyRead = 0x2U, /*!< FLEXSPI is busy write transfer. */ };/*! @brief Typedef for interrupt handler. */ typedef void (*flexspi_isr_t)(FLEXSPI_Type *base, flexspi_handle_t *handle);/******************************************************************************** Prototypes******************************************************************************/ static void FLEXSPI_Memset(void *src, uint8_t value, size_t length);/*!* @brief Calculate flash A/B sample clock DLL.** @param base FLEXSPI base pointer.* @param config Flash configuration parameters.*/ static uint32_t FLEXSPI_CalculateDll(FLEXSPI_Type *base, flexspi_device_config_t *config);/******************************************************************************** Variables******************************************************************************/ /*! @brief Pointers to flexspi bases for each instance. */ static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;/*! @brief Pointers to flexspi IRQ number for each instance. */ static const IRQn_Type s_flexspiIrqs[] = FLEXSPI_IRQS;#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Clock name array */ static const clock_ip_name_t s_flexspiClock[] = FLEXSPI_CLOCKS; #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ /*! @brief Pointers to flexspi handles for each instance. */ static flexspi_handle_t *s_flexspiHandle[ARRAY_SIZE(s_flexspiBases)]; #endif#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET /*! @brief Pointers to FLEXSPI resets for each instance. */ static const reset_ip_name_t s_flexspiResets[] = FLEXSPI_RSTS; #endif#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ /*! @brief Pointer to flexspi IRQ handler. */ static flexspi_isr_t s_flexspiIsr; #endif /******************************************************************************** Code******************************************************************************/ /* To avoid compiler opitimizing this API into memset() in library. */ #if defined(__ICCARM__) #pragma optimize = none #endif /* defined(__ICCARM__) */ static void FLEXSPI_Memset(void *src, uint8_t value, size_t length) {assert(src != NULL);uint8_t *p = (uint8_t *)src;for (uint32_t i = 0U; i < length; i++){*p = value;p++;} }uint32_t FLEXSPI_GetInstance(FLEXSPI_Type *base) {uint32_t instance;/* Find the instance index from base address mappings. */for (instance = 0; instance < ARRAY_SIZE(s_flexspiBases); instance++){if (s_flexspiBases[instance] == base){break;}}assert(instance < ARRAY_SIZE(s_flexspiBases));return instance; }static uint32_t FLEXSPI_CalculateDll(FLEXSPI_Type *base, flexspi_device_config_t *config) {bool isUnifiedConfig = true;uint32_t flexspiDllValue;uint32_t dllValue;uint32_t temp; #if defined(FSL_FEATURE_FLEXSPI_DQS_DELAY_PS) && FSL_FEATURE_FLEXSPI_DQS_DELAY_PSuint32_t internalDqsDelayPs = FSL_FEATURE_FLEXSPI_DQS_DELAY_PS; #endifuint32_t rxSampleClock = (base->MCR0 & FLEXSPI_MCR0_RXCLKSRC_MASK) >> FLEXSPI_MCR0_RXCLKSRC_SHIFT;switch (rxSampleClock){case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackInternally:case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackFromDqsPad:case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackFromSckPad:isUnifiedConfig = true;break;case (uint32_t)kFLEXSPI_ReadSampleClkExternalInputFromDqsPad:if (config->isSck2Enabled){isUnifiedConfig = true;}else{isUnifiedConfig = false;}break;default:assert(false);break;}if (isUnifiedConfig){flexspiDllValue = FLEXSPI_DLLCR_DEFAULT; /* 1 fixed delay cells in DLL delay chain) */}else{if (config->flexspiRootClk >= 100U * FREQ_1MHz){ #if defined(FSL_FEATURE_FLEXSPI_DQS_DELAY_MIN) && FSL_FEATURE_FLEXSPI_DQS_DELAY_MIN/* DLLEN = 1, SLVDLYTARGET = 0x0, */flexspiDllValue = FLEXSPI_DLLCR_DLLEN(1) | FLEXSPI_DLLCR_SLVDLYTARGET(0x00); #else/* DLLEN = 1, SLVDLYTARGET = 0xF, */flexspiDllValue = FLEXSPI_DLLCR_DLLEN(1) | FLEXSPI_DLLCR_SLVDLYTARGET(0x0F); #endif #if (defined(FSL_FEATURE_FLEXSPI_HAS_REFPHASEGAP) && FSL_FEATURE_FLEXSPI_HAS_REFPHASEGAP)flexspiDllValue |= FLEXSPI_DLLCR_REFPHASEGAP(2U); #endif /* FSL_FEATURE_FLEXSPI_HAS_REFPHASEGAP */}else{temp = (uint32_t)config->dataValidTime * 1000U; /* Convert data valid time in ns to ps. */dllValue = temp / (uint32_t)kFLEXSPI_DelayCellUnitMin;if (dllValue * (uint32_t)kFLEXSPI_DelayCellUnitMin < temp){dllValue++;}flexspiDllValue = FLEXSPI_DLLCR_OVRDEN(1) | FLEXSPI_DLLCR_OVRDVAL(dllValue);}}return flexspiDllValue; }status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status) {status_t result = kStatus_Success;/* Check for error. */status &= (uint32_t)kErrorFlags;if (0U != status){/* Select the correct error code.. */if (0U != (status & (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag)){result = kStatus_FLEXSPI_SequenceExecutionTimeout;}else if (0U != (status & (uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag)){result = kStatus_FLEXSPI_IpCommandSequenceError;}else if (0U != (status & (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag)){result = kStatus_FLEXSPI_IpCommandGrantTimeout;}else{assert(false);}/* Clear the flags. */FLEXSPI_ClearInterruptStatusFlags(base, status);}return result; }/*!* brief Initializes the FLEXSPI module and internal state.** This function enables the clock for FLEXSPI and also configures the FLEXSPI with the* input configure parameters. Users should call this function before any FLEXSPI operations.** param base FLEXSPI peripheral base address.* param config FLEXSPI configure structure.*/ void FLEXSPI_Init(FLEXSPI_Type *base, const flexspi_config_t *config) {uint32_t configValue = 0;uint8_t i = 0;#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)/* Enable the flexspi clock */(void)CLOCK_EnableClock(s_flexspiClock[FLEXSPI_GetInstance(base)]); #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET/* Reset the FLEXSPI module */RESET_PeripheralReset(s_flexspiResets[FLEXSPI_GetInstance(base)]); #endif/* Reset peripheral before configuring it. */base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;FLEXSPI_SoftwareReset(base);/* Configure MCR0 configuration items. */configValue = FLEXSPI_MCR0_RXCLKSRC(config->rxSampleClock) | FLEXSPI_MCR0_DOZEEN(config->enableDoze) |FLEXSPI_MCR0_IPGRANTWAIT(config->ipGrantTimeoutCycle) |FLEXSPI_MCR0_AHBGRANTWAIT(config->ahbConfig.ahbGrantTimeoutCycle) |FLEXSPI_MCR0_SCKFREERUNEN(config->enableSckFreeRunning) |FLEXSPI_MCR0_HSEN(config->enableHalfSpeedAccess) | #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)FLEXSPI_MCR0_COMBINATIONEN(config->enableCombination) | #endif #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN)FLEXSPI_MCR0_ATDFEN(config->ahbConfig.enableAHBWriteIpTxFifo) | #endif #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN)FLEXSPI_MCR0_ARDFEN(config->ahbConfig.enableAHBWriteIpRxFifo) | #endifFLEXSPI_MCR0_MDIS_MASK;base->MCR0 = configValue;/* Configure MCR1 configurations. */configValue =FLEXSPI_MCR1_SEQWAIT(config->seqTimeoutCycle) | FLEXSPI_MCR1_AHBBUSWAIT(config->ahbConfig.ahbBusTimeoutCycle);base->MCR1 = configValue;/* Configure MCR2 configurations. */configValue = base->MCR2;configValue &= ~(FLEXSPI_MCR2_RESUMEWAIT_MASK | #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)FLEXSPI_MCR2_SCKBDIFFOPT_MASK | #endifFLEXSPI_MCR2_SAMEDEVICEEN_MASK | FLEXSPI_MCR2_CLRAHBBUFOPT_MASK);configValue |= FLEXSPI_MCR2_RESUMEWAIT(config->ahbConfig.resumeWaitCycle) | #if defined(FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTB) && FSL_FEATURE_FLEXSPI_SUPPORT_SEPERATE_RXCLKSRC_PORTBFLEXSPI_MCR2_RXCLKSRC_B(config->rxSampleClockPortB) | #endif #if defined(FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFF) && FSL_FEATURE_FLEXSPI_SUPPORT_RXCLKSRC_DIFFFLEXSPI_MCR2_RX_CLK_SRC_DIFF(config->rxSampleClockDiff) | #endif #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)FLEXSPI_MCR2_SCKBDIFFOPT(config->enableSckBDiffOpt) | #endifFLEXSPI_MCR2_SAMEDEVICEEN(config->enableSameConfigForAll) |FLEXSPI_MCR2_CLRAHBBUFOPT(config->ahbConfig.enableClearAHBBufferOpt);base->MCR2 = configValue;/* Configure AHB control items. */configValue = base->AHBCR;configValue &= ~(FLEXSPI_AHBCR_READADDROPT_MASK | FLEXSPI_AHBCR_PREFETCHEN_MASK | FLEXSPI_AHBCR_BUFFERABLEEN_MASK |FLEXSPI_AHBCR_CACHABLEEN_MASK);configValue |= FLEXSPI_AHBCR_READADDROPT(config->ahbConfig.enableReadAddressOpt) |FLEXSPI_AHBCR_PREFETCHEN(config->ahbConfig.enableAHBPrefetch) |FLEXSPI_AHBCR_BUFFERABLEEN(config->ahbConfig.enableAHBBufferable) |FLEXSPI_AHBCR_CACHABLEEN(config->ahbConfig.enableAHBCachable);base->AHBCR = configValue;/* Configure AHB rx buffers. */for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++){configValue = base->AHBRXBUFCR0[i];configValue &= ~(FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK |FLEXSPI_AHBRXBUFCR0_MSTRID_MASK | FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK);configValue |= FLEXSPI_AHBRXBUFCR0_PREFETCHEN(config->ahbConfig.buffer[i].enablePrefetch) |FLEXSPI_AHBRXBUFCR0_PRIORITY(config->ahbConfig.buffer[i].priority) |FLEXSPI_AHBRXBUFCR0_MSTRID(config->ahbConfig.buffer[i].masterIndex) |FLEXSPI_AHBRXBUFCR0_BUFSZ((uint32_t)config->ahbConfig.buffer[i].bufferSize / 8U);base->AHBRXBUFCR0[i] = configValue;}/* Configure IP Fifo watermarks. */base->IPRXFCR &= ~FLEXSPI_IPRXFCR_RXWMRK_MASK;base->IPRXFCR |= FLEXSPI_IPRXFCR_RXWMRK((uint32_t)config->rxWatermark / 8U - 1U);base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXWMRK_MASK;base->IPTXFCR |= FLEXSPI_IPTXFCR_TXWMRK((uint32_t)config->txWatermark / 8U - 1U);/* Reset flash size on all ports */for (i = 0; i < (uint32_t)kFLEXSPI_PortCount; i++){base->FLSHCR0[i] = 0;} }/*!* brief Gets default settings for FLEXSPI.** param config FLEXSPI configuration structure.*/ void FLEXSPI_GetDefaultConfig(flexspi_config_t *config) {/* Initializes the configure structure to zero. */FLEXSPI_Memset(config, 0, sizeof(*config));config->rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackInternally;config->enableSckFreeRunning = false; #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)config->enableCombination = false; #endifconfig->enableDoze = true;config->enableHalfSpeedAccess = false; #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)config->enableSckBDiffOpt = false; #endifconfig->enableSameConfigForAll = false;config->seqTimeoutCycle = 0xFFFFU;config->ipGrantTimeoutCycle = 0xFFU;config->txWatermark = 8;config->rxWatermark = 8; #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN)config->ahbConfig.enableAHBWriteIpTxFifo = false; #endif #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN)config->ahbConfig.enableAHBWriteIpRxFifo = false; #endifconfig->ahbConfig.ahbGrantTimeoutCycle = 0xFFU;config->ahbConfig.ahbBusTimeoutCycle = 0xFFFFU;config->ahbConfig.resumeWaitCycle = 0x20U;FLEXSPI_Memset(config->ahbConfig.buffer, 0, sizeof(config->ahbConfig.buffer));/* Use invalid master ID 0xF and buffer size 0 for the first several buffers. */for (uint8_t i = 0; i < ((uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 2U); i++){config->ahbConfig.buffer[i].enablePrefetch = true; /* Default enable AHB prefetch. */config->ahbConfig.buffer[i].masterIndex = 0xFU; /* Invalid master index which is not used, so will never hit. */config->ahbConfig.buffer[i].bufferSize =0; /* Default buffer size 0 for buffer0 to buffer(FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 3U)*/}for (uint8_t i = ((uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 2U);i < (uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++){config->ahbConfig.buffer[i].enablePrefetch = true; /* Default enable AHB prefetch. */config->ahbConfig.buffer[i].bufferSize = 256U; /* Default buffer size 256 bytes. */}config->ahbConfig.enableClearAHBBufferOpt = false;config->ahbConfig.enableReadAddressOpt = false;config->ahbConfig.enableAHBPrefetch = false;config->ahbConfig.enableAHBBufferable = false;config->ahbConfig.enableAHBCachable = false; }/*!* brief Deinitializes the FLEXSPI module.** Clears the FLEXSPI state and FLEXSPI module registers.* param base FLEXSPI peripheral base address.*/ void FLEXSPI_Deinit(FLEXSPI_Type *base) {/* Reset peripheral. */FLEXSPI_SoftwareReset(base); }/*!* brief Update FLEXSPI DLL value depending on currently flexspi root clock.** param base FLEXSPI peripheral base address.* param config Flash configuration parameters.* param port FLEXSPI Operation port.*/ void FLEXSPI_UpdateDllValue(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port) {uint32_t configValue = 0;uint32_t statusValue = 0;uint8_t index = (uint8_t)port >> 1U; /* PortA with index 0, PortB with index 1. *//* Wait for bus to be idle before changing flash configuration. */while (!FLEXSPI_GetBusIdleStatus(base)){}/* Configure DLL. */configValue = FLEXSPI_CalculateDll(base, config);base->DLLCR[index] = configValue;/* Exit stop mode. */base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;/* According to ERR011377, need to delay at least 100 NOPs to ensure the DLL is locked. */if (index == 0U){statusValue =((uint32_t)kFLEXSPI_FlashASampleClockSlaveDelayLocked | (uint32_t)kFLEXSPI_FlashASampleClockRefDelayLocked);} #if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK)) && (FSL_FEATURE_FLEXSPI_HAS_NO_STS2_BSLVLOCK))else{statusValue =((uint32_t)kFLEXSPI_FlashBSampleClockSlaveDelayLocked | (uint32_t)kFLEXSPI_FlashBSampleClockRefDelayLocked);} #endifif (0U != (configValue & FLEXSPI_DLLCR_DLLEN_MASK)){ #if defined(FSL_FEATURE_FLEXSPI_HAS_ERRATA_051426) && (FSL_FEATURE_FLEXSPI_HAS_ERRATA_051426)if (config->isFroClockSource == false) #endif{/* Wait slave delay line locked and slave reference delay line locked. */while ((base->STS2 & statusValue) != statusValue){}}/* Wait at least 100 NOPs*/for (uint8_t delay = 100U; delay > 0U; delay--){__NOP();}} }/*!* brief Configures the connected device parameter.** This function configures the connected device relevant parameters, such as the size, command, and so on.* The flash configuration value cannot have a default value. The user needs to configure it according to the* connected device.** param base FLEXSPI peripheral base address.* param config Flash configuration parameters.* param port FLEXSPI Operation port.*/ void FLEXSPI_SetFlashConfig(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port) {uint32_t configValue = 0;uint8_t index = (uint8_t)port >> 1U; /* PortA with index 0, PortB with index 1. *//* Wait for bus to be idle before changing flash configuration. */while (!FLEXSPI_GetBusIdleStatus(base)){}/* Configure flash size and address shift. */ #if defined(FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT) && (FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT)base->FLSHCR0[port] = config->flashSize | FLEXSPI_FLSHCR0_ADDRSHIFT(config->addressShift); #elsebase->FLSHCR0[port] = config->flashSize; #endif /* FSL_FEATURE_FLEXSPI_SUPPORT_ADDRESS_SHIFT *//* Configure flash parameters. */base->FLSHCR1[port] = FLEXSPI_FLSHCR1_CSINTERVAL(config->CSInterval) |FLEXSPI_FLSHCR1_CSINTERVALUNIT(config->CSIntervalUnit) |FLEXSPI_FLSHCR1_TCSH(config->CSHoldTime) | FLEXSPI_FLSHCR1_TCSS(config->CSSetupTime) |FLEXSPI_FLSHCR1_CAS(config->columnspace) | FLEXSPI_FLSHCR1_WA(config->enableWordAddress);/* Configure AHB operation items. */configValue = base->FLSHCR2[port];configValue &= ~(FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK | FLEXSPI_FLSHCR2_AWRWAIT_MASK | FLEXSPI_FLSHCR2_AWRSEQNUM_MASK |FLEXSPI_FLSHCR2_AWRSEQID_MASK | FLEXSPI_FLSHCR2_ARDSEQNUM_MASK | FLEXSPI_FLSHCR2_ARDSEQID_MASK);configValue |=FLEXSPI_FLSHCR2_AWRWAITUNIT(config->AHBWriteWaitUnit) | FLEXSPI_FLSHCR2_AWRWAIT(config->AHBWriteWaitInterval);if (config->AWRSeqNumber > 0U){configValue |= FLEXSPI_FLSHCR2_AWRSEQID((uint32_t)config->AWRSeqIndex) |FLEXSPI_FLSHCR2_AWRSEQNUM((uint32_t)config->AWRSeqNumber - 1U);}if (config->ARDSeqNumber > 0U){configValue |= FLEXSPI_FLSHCR2_ARDSEQID((uint32_t)config->ARDSeqIndex) |FLEXSPI_FLSHCR2_ARDSEQNUM((uint32_t)config->ARDSeqNumber - 1U);}base->FLSHCR2[port] = configValue;/* Configure DLL. */FLEXSPI_UpdateDllValue(base, config, port);/* Step into stop mode. */base->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;/* Configure write mask. */if (config->enableWriteMask){base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMOPT1_MASK;}else{base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMOPT1_MASK;}if (index == 0U) /*PortA*/{base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENA_MASK;base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENA(config->enableWriteMask);} #if !((defined(FSL_FEATURE_FLEXSPI_HAS_NO_FLSHCR4_WMENB)) && (FSL_FEATURE_FLEXSPI_HAS_NO_FLSHCR4_WMENB))else{base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENB_MASK;base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENB(config->enableWriteMask);} #endif/* Exit stop mode. */base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;/* Wait for bus to be idle before use it access to external flash. */while (!FLEXSPI_GetBusIdleStatus(base)){} }/*! brief Updates the LUT table.** param base FLEXSPI peripheral base address.* param index From which index start to update. It could be any index of the LUT table, which* also allows user to update command content inside a command. Each command consists of up to* 8 instructions and occupy 4*32-bit memory.* param cmd Command sequence array.* param count Number of sequences.*/ void FLEXSPI_UpdateLUT(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count) {assert(index < 64U);uint32_t i = 0;volatile uint32_t *lutBase;/* Wait for bus to be idle before changing flash configuration. */while (!FLEXSPI_GetBusIdleStatus(base)){}/* Unlock LUT for update. */ #if !((defined(FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO)) && (FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO))base->LUTKEY = FLEXSPI_LUT_KEY_VAL; #endifbase->LUTCR = 0x02;lutBase = &base->LUT[index];for (i = 0; i < count; i++){*lutBase++ = *cmd++;}/* Lock LUT. */ #if !((defined(FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO)) && (FSL_FEATURE_FLEXSPI_LUTKEY_IS_RO))base->LUTKEY = FLEXSPI_LUT_KEY_VAL; #endifbase->LUTCR = 0x01; }/*! brief Update read sample clock source** param base FLEXSPI peripheral base address.* param clockSource clockSource of type #flexspi_read_sample_clock_t*/ void FLEXSPI_UpdateRxSampleClock(FLEXSPI_Type *base, flexspi_read_sample_clock_t clockSource) {uint32_t mcr0Val;/* Wait for bus to be idle before changing flash configuration. */while (!FLEXSPI_GetBusIdleStatus(base)){}mcr0Val = base->MCR0;mcr0Val &= ~FLEXSPI_MCR0_RXCLKSRC_MASK;mcr0Val |= FLEXSPI_MCR0_RXCLKSRC(clockSource);base->MCR0 = mcr0Val;/* Reset peripheral. */FLEXSPI_SoftwareReset(base); }/*!* brief Sends a buffer of data bytes using blocking method.* note This function blocks via polling until all bytes have been sent.* param base FLEXSPI peripheral base address* param buffer The data bytes to send* param size The number of data bytes to send* retval kStatus_Success write success without error* retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout* retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected* retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected*/ status_t FLEXSPI_WriteBlocking(FLEXSPI_Type *base, uint8_t *buffer, size_t size) {uint32_t txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;uint32_t status;status_t result = kStatus_Success;uint32_t i = 0;/* Send data buffer */while (0U != size){/* Wait until there is room in the fifo. This also checks for errors. */while (0U == ((status = base->INTR) & (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag)){}result = FLEXSPI_CheckAndClearError(base, status);if (kStatus_Success != result){return result;}/* Write watermark level data into tx fifo . */if (size >= 8U * txWatermark){for (i = 0U; i < 2U * txWatermark; i++){base->TFDR[i] = *(uint32_t *)(void *)buffer;buffer += 4U;}size = size - 8U * txWatermark;}else{/* Write word aligned data into tx fifo. */for (i = 0U; i < (size / 4U); i++){base->TFDR[i] = *(uint32_t *)(void *)buffer;buffer += 4U;}/* Adjust size by the amount processed. */size -= 4U * i;/* Write word un-aligned data into tx fifo. */if (0x00U != size){uint32_t tempVal = 0x00U;for (uint32_t j = 0U; j < size; j++){tempVal |= ((uint32_t)*buffer++ << (8U * j));}base->TFDR[i] = tempVal;}size = 0U;}/* Push a watermark level data into IP TX FIFO. */base->INTR = (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag;}return result; }/*!* brief Receives a buffer of data bytes using a blocking method.* note This function blocks via polling until all bytes have been sent.* param base FLEXSPI peripheral base address* param buffer The data bytes to send* param size The number of data bytes to receive* retval kStatus_Success read success without error* retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout* retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected* retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected*/ status_t FLEXSPI_ReadBlocking(FLEXSPI_Type *base, uint8_t *buffer, size_t size) {uint32_t rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;uint32_t status;status_t result = kStatus_Success;uint32_t i = 0;bool isReturn = false;/* Send data buffer */while (0U != size){if (size >= 8U * rxWatermark){/* Wait until there is room in the fifo. This also checks for errors. */while (0U == ((status = base->INTR) & (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag)){result = FLEXSPI_CheckAndClearError(base, status);if (kStatus_Success != result){isReturn = true;break;}}}else{/* Wait fill level. This also checks for errors. */while (size > ((((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8U)){result = FLEXSPI_CheckAndClearError(base, base->INTR);if (kStatus_Success != result){isReturn = true;break;}}}if (isReturn){break;}result = FLEXSPI_CheckAndClearError(base, base->INTR);if (kStatus_Success != result){break;}/* Read watermark level data from rx fifo. */if (size >= 8U * rxWatermark){for (i = 0U; i < 2U * rxWatermark; i++){*(uint32_t *)(void *)buffer = base->RFDR[i];buffer += 4U;}size = size - 8U * rxWatermark;}else{/* Read word aligned data from rx fifo. */for (i = 0U; i < (size / 4U); i++){*(uint32_t *)(void *)buffer = base->RFDR[i];buffer += 4U;}/* Adjust size by the amount processed. */size -= 4U * i;/* Read word un-aligned data from rx fifo. */if (0x00U != size){uint32_t tempVal = base->RFDR[i];for (i = 0U; i < size; i++){*buffer++ = ((uint8_t)(tempVal >> (8U * i)) & 0xFFU);}}size = 0;}/* Pop out a watermark level datas from IP RX FIFO. */base->INTR = (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag;}return result; }/*!* brief Execute command to transfer a buffer data bytes using a blocking method.* param base FLEXSPI peripheral base address* param xfer pointer to the transfer structure.* retval kStatus_Success command transfer success without error* retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout* retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected* retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected*/ status_t FLEXSPI_TransferBlocking(FLEXSPI_Type *base, flexspi_transfer_t *xfer) {uint32_t configValue = 0;status_t result = kStatus_Success;/* Clear sequence pointer before sending data to external devices. */base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;/* Clear former pending status before start this transfer. */base->INTR = FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |FLEXSPI_INTR_IPCMDGE_MASK | FLEXSPI_INTR_IPCMDDONE_MASK;/* Configure base address. */base->IPCR0 = xfer->deviceAddress;/* Reset fifos. */base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;/* Configure data size. */if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config)){configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);}/* Configure sequence ID. */configValue |=FLEXSPI_IPCR1_ISEQID((uint32_t)xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);base->IPCR1 = configValue;/* Start Transfer. */base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config)){result = FLEXSPI_WriteBlocking(base, (uint8_t *)xfer->data, xfer->dataSize);}else if (xfer->cmdType == kFLEXSPI_Read){result = FLEXSPI_ReadBlocking(base, (uint8_t *)xfer->data, xfer->dataSize);}else{/* Empty else. */}/* Wait until the IP command execution finishes */while (0UL == (base->INTR & FLEXSPI_INTR_IPCMDDONE_MASK)){}/* Unless there is an error status already set, capture the latest one */if (result == kStatus_Success){result = FLEXSPI_CheckAndClearError(base, base->INTR);}return result; }/*!* brief Initializes the FLEXSPI handle which is used in transactional functions.** param base FLEXSPI peripheral base address.* param handle pointer to flexspi_handle_t structure to store the transfer state.* param callback pointer to user callback function.* param userData user parameter passed to the callback function.*/ void FLEXSPI_TransferCreateHandle(FLEXSPI_Type *base,flexspi_handle_t *handle,flexspi_transfer_callback_t callback,void *userData) {assert(NULL != handle);uint32_t instance = FLEXSPI_GetInstance(base);/* Zero handle. */(void)memset(handle, 0, sizeof(*handle));/* Set callback and userData. */handle->completionCallback = callback;handle->userData = userData;#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ/* Save the context in global variables to support the double weak mechanism. */s_flexspiHandle[instance] = handle;s_flexspiIsr = FLEXSPI_TransferHandleIRQ; #endif/* Enable NVIC interrupt. */(void)EnableIRQ(s_flexspiIrqs[instance]); }/*!* brief Performs a interrupt non-blocking transfer on the FLEXSPI bus.** note Calling the API returns immediately after transfer initiates. The user needs* to call FLEXSPI_GetTransferCount to poll the transfer status to check whether* the transfer is finished. If the return status is not kStatus_FLEXSPI_Busy, the transfer* is finished. For FLEXSPI_Read, the dataSize should be multiple of rx watermark level, or* FLEXSPI could not read data properly.** param base FLEXSPI peripheral base address.* param handle pointer to flexspi_handle_t structure which stores the transfer state.* param xfer pointer to flexspi_transfer_t structure.* retval kStatus_Success Successfully start the data transmission.* retval kStatus_FLEXSPI_Busy Previous transmission still not finished.*/ status_t FLEXSPI_TransferNonBlocking(FLEXSPI_Type *base, flexspi_handle_t *handle, flexspi_transfer_t *xfer) {uint32_t configValue = 0;status_t result = kStatus_Success;assert(NULL != handle);assert(NULL != xfer);/* Check if the I2C bus is idle - if not return busy status. */if (handle->state != (uint32_t)kFLEXSPI_Idle){result = kStatus_FLEXSPI_Busy;}else{handle->data = (uint8_t *)xfer->data;handle->dataSize = xfer->dataSize;handle->transferTotalSize = xfer->dataSize;handle->state = (xfer->cmdType == kFLEXSPI_Read) ? (uint32_t)kFLEXSPI_BusyRead : (uint32_t)kFLEXSPI_BusyWrite;/* Clear sequence pointer before sending data to external devices. */base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;/* Clear former pending status before start this transfer. */base->INTR = FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |FLEXSPI_INTR_IPCMDGE_MASK | FLEXSPI_INTR_IPCMDDONE_MASK;/* Configure base address. */base->IPCR0 = xfer->deviceAddress;/* Reset fifos. */base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;/* Configure data size. */if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write)){configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);}/* Configure sequence ID. */configValue |=FLEXSPI_IPCR1_ISEQID((uint32_t)xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);base->IPCR1 = configValue;/* Start Transfer. */base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;if (handle->state == (uint32_t)kFLEXSPI_BusyRead){FLEXSPI_EnableInterrupts(base, (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag |(uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag |(uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag |(uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag |(uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag);}else{FLEXSPI_EnableInterrupts(base, (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag | (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag |(uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag | (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag |(uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag);}}return result; }/*!* brief Gets the master transfer status during a interrupt non-blocking transfer.** param base FLEXSPI peripheral base address.* param handle pointer to flexspi_handle_t structure which stores the transfer state.* param count Number of bytes transferred so far by the non-blocking transaction.* retval kStatus_InvalidArgument count is Invalid.* retval kStatus_Success Successfully return the count.*/ status_t FLEXSPI_TransferGetCount(FLEXSPI_Type *base, flexspi_handle_t *handle, size_t *count) {assert(NULL != handle);status_t result = kStatus_Success;if (handle->state == (uint32_t)kFLEXSPI_Idle){result = kStatus_NoTransferInProgress;}else{*count = handle->transferTotalSize - handle->dataSize;}return result; }/*!* brief Aborts an interrupt non-blocking transfer early.** note This API can be called at any time when an interrupt non-blocking transfer initiates* to abort the transfer early.** param base FLEXSPI peripheral base address.* param handle pointer to flexspi_handle_t structure which stores the transfer state*/ void FLEXSPI_TransferAbort(FLEXSPI_Type *base, flexspi_handle_t *handle) {assert(NULL != handle);FLEXSPI_DisableInterrupts(base, (uint32_t)kIrqFlags);handle->state = (uint32_t)kFLEXSPI_Idle; }/*!* brief Master interrupt handler.** param base FLEXSPI peripheral base address.* param handle pointer to flexspi_handle_t structure.*/ void FLEXSPI_TransferHandleIRQ(FLEXSPI_Type *base, flexspi_handle_t *handle) {uint32_t status;status_t result;uint32_t intEnableStatus;uint32_t txWatermark;uint32_t rxWatermark;uint32_t i = 0;status = base->INTR;intEnableStatus = base->INTEN;/* Check if interrupt is enabled and status is alerted. */if ((status & intEnableStatus) != 0U){result = FLEXSPI_CheckAndClearError(base, status);if ((result != kStatus_Success) && (handle->completionCallback != NULL)){FLEXSPI_TransferAbort(base, handle);if (NULL != handle->completionCallback){handle->completionCallback(base, handle, result, handle->userData);}}else{if ((0U != (status & (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag)) &&(handle->state == (uint32_t)kFLEXSPI_BusyRead)){rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;/* Read watermark level data from rx fifo . */if (handle->dataSize >= 8U * rxWatermark){/* Read watermark level data from rx fifo . */for (i = 0U; i < 2U * rxWatermark; i++){*(uint32_t *)(void *)handle->data = base->RFDR[i];handle->data += 4U;}handle->dataSize = handle->dataSize - 8U * rxWatermark;}else{/* Read word aligned data from rx fifo. */for (i = 0U; i < (handle->dataSize / 4U); i++){*(uint32_t *)(void *)handle->data = base->RFDR[i];handle->data += 4U;}/* Adjust size by the amount processed. */handle->dataSize -= (size_t)4U * i;/* Read word un-aligned data from rx fifo. */if (0x00U != handle->dataSize){uint32_t tempVal = base->RFDR[i];for (i = 0U; i < handle->dataSize; i++){*handle->data++ = ((uint8_t)(tempVal >> (8U * i)) & 0xFFU);}}handle->dataSize = 0;}/* Pop out a watermark level data from IP RX FIFO. */base->INTR = (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag;}if (0U != (status & (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag)){base->INTR = (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag;FLEXSPI_TransferAbort(base, handle);if (NULL != handle->completionCallback){handle->completionCallback(base, handle, kStatus_Success, handle->userData);}}/* TX FIFO empty interrupt, push watermark level data into tx FIFO. */if ((0U != (status & (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag)) &&(handle->state == (uint32_t)kFLEXSPI_BusyWrite)){if (0U != handle->dataSize){txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;/* Write watermark level data into tx fifo . */if (handle->dataSize >= 8U * txWatermark){for (i = 0; i < 2U * txWatermark; i++){base->TFDR[i] = *(uint32_t *)(void *)handle->data;handle->data += 4U;}handle->dataSize = handle->dataSize - 8U * txWatermark;}else{/* Write word aligned data into tx fifo. */for (i = 0U; i < (handle->dataSize / 4U); i++){base->TFDR[i] = *(uint32_t *)(void *)handle->data;handle->data += 4U;}/* Adjust size by the amount processed. */handle->dataSize -= (size_t)4U * i;/* Write word un-aligned data into tx fifo. */if (0x00U != handle->dataSize){uint32_t tempVal = 0x00U;for (uint32_t j = 0U; j < handle->dataSize; j++){tempVal |= ((uint32_t)*handle->data++ << (8U * j));}base->TFDR[i] = tempVal;}handle->dataSize = 0;}/* Push a watermark level data into IP TX FIFO. */base->INTR = (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag;}}else{/* Empty else */}}}else{/* Empty else */} }#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ #if defined(FLEXSPI) void FLEXSPI_DriverIRQHandler(void); void FLEXSPI_DriverIRQHandler(void) {s_flexspiIsr(FLEXSPI, s_flexspiHandle[0]);SDK_ISR_EXIT_BARRIER; } #endif#if defined(FLEXSPI0) void FLEXSPI0_DriverIRQHandler(void); void FLEXSPI0_DriverIRQHandler(void) {s_flexspiIsr(FLEXSPI0, s_flexspiHandle[0]);SDK_ISR_EXIT_BARRIER; } #endif #if defined(FLEXSPI1) void FLEXSPI1_DriverIRQHandler(void); void FLEXSPI1_DriverIRQHandler(void) {s_flexspiIsr(FLEXSPI1, s_flexspiHandle[1]);SDK_ISR_EXIT_BARRIER; } #endif #if defined(FLEXSPI2) void FLEXSPI2_DriverIRQHandler(void); void FLEXSPI2_DriverIRQHandler(void) {s_flexspiIsr(FLEXSPI2, s_flexspiHandle[2]);SDK_ISR_EXIT_BARRIER; } #endif#if defined(LSIO__FLEXSPI0) void LSIO_OCTASPI0_INT_DriverIRQHandler(void); void LSIO_OCTASPI0_INT_DriverIRQHandler(void) {s_flexspiIsr(LSIO__FLEXSPI0, s_flexspiHandle[0]);SDK_ISR_EXIT_BARRIER; } #endif #if defined(LSIO__FLEXSPI1) void LSIO_OCTASPI1_INT_DriverIRQHandler(void); void LSIO_OCTASPI1_INT_DriverIRQHandler(void) {s_flexspiIsr(LSIO__FLEXSPI1, s_flexspiHandle[1]);SDK_ISR_EXIT_BARRIER; } #endif#if defined(FSL_FEATURE_FLEXSPI_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_FLEXSPI_HAS_SHARED_IRQ0_IRQ1void FLEXSPI0_FLEXSPI1_DriverIRQHandler(void); void FLEXSPI0_FLEXSPI1_DriverIRQHandler(void) {/* If handle is registered, treat the transfer function is enabled. */if (NULL != s_flexspiHandle[0]){s_flexspiIsr(FLEXSPI0, s_flexspiHandle[0]);}if (NULL != s_flexspiHandle[1]){s_flexspiIsr(FLEXSPI1, s_flexspiHandle[1]);} } #endif#endif
这个文件是芯片驱动flexspi的驱动。
-
flexspi_flash_nor_ops.c
/** Copyright (c) 2016, Freescale Semiconductor, Inc.* Copyright 2016-2022 NXP* All rights reserved.*** SPDX-License-Identifier: BSD-3-Clause*/#include "fsl_flexspi.h" #include "app.h" #include "fsl_iomuxc.h" #if (defined CACHE_MAINTAIN) && (CACHE_MAINTAIN == 1) #include "fsl_cache.h" #endif//#ifdef 0 #if 0 flexspi_device_config_t deviceconfig = {.flexspiRootClk = 133000000,.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, };const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {/* Normal read mode -SDR */[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),/* Fast read mode - SDR */[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x0B, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_1PAD, 0x08, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),/* Fast read quad mode - SDR */[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),/* Write Enable */[4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),/* Erase Sector */[4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),/* Page Program - single mode */[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, 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 ID */[4 * NOR_CMD_LUT_SEQ_IDX_READID] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),/* Enable Quad mode */[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x31, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x02),/* 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),/* Erase whole chip */[4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC7, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), }; #endif /******************************************************************************/ #if 1 flexspi_device_config_t deviceconfig = {.flexspiRootClk = 120000000,.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, };const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {/* Normal read mode -SDR */[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),/* Fast read quad mode - SDR */[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),/* Read extend parameters */[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),/* Write Enable */[4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),/* Erase Sector */[4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),/* Page Program - single mode */[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, 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 ID */[4 * NOR_CMD_LUT_SEQ_IDX_READID] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),/* Enable Quad mode */[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x31, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),/* Erase Block */ // [4 * NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK] =// FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xD8, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),/* 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),/* Erase whole chip */[4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC7, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), };#endif /* FLM */ /******************************************************************************** Definitions******************************************************************************//******************************************************************************** Prototypes******************************************************************************//******************************************************************************** Variables*****************************************************************************/ extern flexspi_device_config_t deviceconfig; extern const uint32_t customLUT[CUSTOM_LUT_LENGTH];/******************************************************************************** Code******************************************************************************/ #if (defined CACHE_MAINTAIN) && (CACHE_MAINTAIN == 1) void flexspi_nor_disable_cache(flexspi_cache_status_t *cacheStatus) { #if (defined __CORTEX_M) && (__CORTEX_M == 7U) #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)/* Disable D cache. */if (SCB_CCR_DC_Msk == (SCB_CCR_DC_Msk & SCB->CCR)){SCB_DisableDCache();cacheStatus->DCacheEnableFlag = true;} #endif /* __DCACHE_PRESENT */#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)/* Disable I cache. */if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)){SCB_DisableICache();cacheStatus->ICacheEnableFlag = true;} #endif /* __ICACHE_PRESENT */#elif (defined FSL_FEATURE_SOC_LMEM_COUNT) && (FSL_FEATURE_SOC_LMEM_COUNT != 0U)/* Disable code bus cache and system bus cache */if (LMEM_PCCCR_ENCACHE_MASK == (LMEM_PCCCR_ENCACHE_MASK & LMEM->PCCCR)){L1CACHE_DisableCodeCache();cacheStatus->codeCacheEnableFlag = true;}if (LMEM_PSCCR_ENCACHE_MASK == (LMEM_PSCCR_ENCACHE_MASK & LMEM->PSCCR)){L1CACHE_DisableSystemCache();cacheStatus->systemCacheEnableFlag = true;}#elif (defined FSL_FEATURE_SOC_CACHE64_CTRL_COUNT) && (FSL_FEATURE_SOC_CACHE64_CTRL_COUNT != 0U)/* Disable cache */CACHE64_DisableCache(EXAMPLE_CACHE);cacheStatus->CacheEnableFlag = true; #endif }void flexspi_nor_enable_cache(flexspi_cache_status_t cacheStatus) { #if (defined __CORTEX_M) && (__CORTEX_M == 7U) #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)if (cacheStatus.DCacheEnableFlag){/* Enable D cache. */SCB_EnableDCache();} #endif /* __DCACHE_PRESENT */#if defined(__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)if (cacheStatus.ICacheEnableFlag){/* Enable I cache. */SCB_EnableICache();} #endif /* __ICACHE_PRESENT */#elif (defined FSL_FEATURE_SOC_LMEM_COUNT) && (FSL_FEATURE_SOC_LMEM_COUNT != 0U)if (cacheStatus.codeCacheEnableFlag){/* Enable code cache. */L1CACHE_EnableCodeCache();}if (cacheStatus.systemCacheEnableFlag){/* Enable system cache. */L1CACHE_EnableSystemCache();}#elif (defined FSL_FEATURE_SOC_CACHE64_CTRL_COUNT) && (FSL_FEATURE_SOC_CACHE64_CTRL_COUNT != 0U)if (cacheStatus.CacheEnableFlag){/* Enable cache. */CACHE64_EnableCache(EXAMPLE_CACHE);} #endif } #endifstatus_t flexspi_nor_write_enable(FLEXSPI_Type *base, uint32_t baseAddr) {flexspi_transfer_t flashXfer;status_t status;/* Write enable */flashXfer.deviceAddress = baseAddr;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Command;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;status = FLEXSPI_TransferBlocking(base, &flashXfer);return status; }status_t flexspi_nor_wait_bus_busy(FLEXSPI_Type *base) {/* Wait status ready. */bool isBusy;uint32_t readValue;status_t status;flexspi_transfer_t flashXfer;flashXfer.deviceAddress = 0;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Read;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READSTATUSREG;flashXfer.data = &readValue;flashXfer.dataSize = 1;do{status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}if (FLASH_BUSY_STATUS_POL){if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET)){isBusy = true;}else{isBusy = false;}}else{if (readValue & (1U << FLASH_BUSY_STATUS_OFFSET)){isBusy = false;}else{isBusy = true;}}} while (isBusy);return status; }status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base) {flexspi_transfer_t flashXfer;status_t status; #if defined(FLASH_QUAD_ENABLE) && FLASH_QUAD_ENABLEuint32_t writeValue = FLASH_QUAD_ENABLE; #endif#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* Write enable */status = flexspi_nor_write_enable(base, 0);if (status != kStatus_Success){return status;}/* Enable quad mode. */flashXfer.deviceAddress = 0;flashXfer.port = FLASH_PORT; #if defined(FLASH_QUAD_ENABLE) && FLASH_QUAD_ENABLEflashXfer.cmdType = kFLEXSPI_Write;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG;flashXfer.data = &writeValue;flashXfer.dataSize = writeValue <= 0xFFU ? 1 : 2; #endif #if defined(MT25Q_FLASH_QUAD_ENABLE) && MT25Q_FLASH_QUAD_ENABLEflashXfer.cmdType = kFLEXSPI_Command;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ENABLEQUAD; #endifstatus = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}status = flexspi_nor_wait_bus_busy(base);/* Do software reset. */FLEXSPI_SoftwareReset(base);#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endifreturn status; }#if defined(NOR_CMD_LUT_SEQ_IDX_SETREADPARAMETER) && NOR_CMD_LUT_SEQ_IDX_SETREADPARAMETER status_t flexspi_nor_set_read_parameter(FLEXSPI_Type *base, uint8_t burstLength, bool enableWrap, uint8_t dummyCycle, bool resetPinSelected) {flexspi_transfer_t flashXfer;status_t status;uint32_t readParameterRegVal = ((uint32_t)resetPinSelected << RESET_PIN_SELECTED_REG_SHIFT) |((uint32_t)dummyCycle << DUMMY_CYCLES_REG_SHIFT) |((uint32_t)enableWrap << WRAP_ENABLE_REG_SHIFT) |((uint32_t)burstLength << BURST_LEGNTH_REG_SHIFT);#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* Write enable */status = flexspi_nor_write_enable(base, 0);if (status != kStatus_Success){return status;}flashXfer.deviceAddress = 0;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Write;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_SETREADPARAMETER;flashXfer.data = &readParameterRegVal;flashXfer.dataSize = 1;status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}status = flexspi_nor_wait_bus_busy(base);/* Do software reset. */FLEXSPI_SoftwareReset(base);#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endifreturn status; } #endifstatus_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address) {status_t status;flexspi_transfer_t flashXfer;#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* Write enable */flashXfer.deviceAddress = address;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Command;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_WRITEENABLE;status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}flashXfer.deviceAddress = address;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Command;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASESECTOR;status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}status = flexspi_nor_wait_bus_busy(base);/* Do software reset. */FLEXSPI_SoftwareReset(base);#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endifreturn status; }status_t flexspi_nor_flash_read(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t length) {status_t status;flexspi_transfer_t flashXfer;#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* Write enable */status = flexspi_nor_write_enable(base, dstAddr);if (status != kStatus_Success){return status;}/* Prepare page program command */flashXfer.deviceAddress = dstAddr;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Read;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD;flashXfer.data = (uint32_t *)src;flashXfer.dataSize = length;status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}status = flexspi_nor_wait_bus_busy(base);/* Do software reset or clear AHB buffer directly. */ #if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK) && \defined(FLEXSPI_AHBCR_CLRAHBTXBUF_MASK)base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK); #elseFLEXSPI_SoftwareReset(base); #endif#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endifreturn status; }status_t flexspi_nor_flash_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src, uint32_t length) {status_t status;flexspi_transfer_t flashXfer;#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* Write enable */status = flexspi_nor_write_enable(base, dstAddr);if (status != kStatus_Success){return status;}/* Prepare page program command */flashXfer.deviceAddress = dstAddr;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Write;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;flashXfer.data = (uint32_t *)src;flashXfer.dataSize = length;status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}status = flexspi_nor_wait_bus_busy(base);/* Do software reset or clear AHB buffer directly. */ #if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK) && \defined(FLEXSPI_AHBCR_CLRAHBTXBUF_MASK)base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK); #elseFLEXSPI_SoftwareReset(base); #endif#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endifreturn status; }status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src) {status_t status;flexspi_transfer_t flashXfer;#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* To make sure external flash be in idle status, added wait for busy before program data foran external flash without RWW(read while write) attribute.*/status = flexspi_nor_wait_bus_busy(base);if (kStatus_Success != status){return status;}/* Write enable. */status = flexspi_nor_write_enable(base, dstAddr);if (status != kStatus_Success){return status;}/* Prepare page program command */flashXfer.deviceAddress = dstAddr;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Write;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_QUAD;flashXfer.data = (uint32_t *)src;flashXfer.dataSize = FLASH_PAGE_SIZE;status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}status = flexspi_nor_wait_bus_busy(base);/* Do software reset or clear AHB buffer directly. */ #if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK) && \defined(FLEXSPI_AHBCR_CLRAHBTXBUF_MASK)base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK); #elseFLEXSPI_SoftwareReset(base); #endif#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endifreturn status; }status_t flexspi_nor_get_vendor_id(FLEXSPI_Type *base, uint8_t *vendorId) {uint32_t temp;flexspi_transfer_t flashXfer;flashXfer.deviceAddress = 0;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Read;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_READID;flashXfer.data = &temp;flashXfer.dataSize = 1;status_t status = FLEXSPI_TransferBlocking(base, &flashXfer);*vendorId = temp;/* Do software reset or clear AHB buffer directly. */ #if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK) && \defined(FLEXSPI_AHBCR_CLRAHBTXBUF_MASK)base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK); #elseFLEXSPI_SoftwareReset(base); #endifreturn status; }status_t flexspi_nor_erase_chip(FLEXSPI_Type *base) {status_t status;flexspi_transfer_t flashXfer;#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* Write enable */status = flexspi_nor_write_enable(base, 0);if (status != kStatus_Success){return status;}flashXfer.deviceAddress = 0;flashXfer.port = FLASH_PORT;flashXfer.cmdType = kFLEXSPI_Command;flashXfer.SeqNumber = 1;flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_ERASECHIP;status = FLEXSPI_TransferBlocking(base, &flashXfer);if (status != kStatus_Success){return status;}status = flexspi_nor_wait_bus_busy(base);#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endifreturn status; } /* 配置flexspi的引脚 */ void flexspi_config() { #ifdef FLMIOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, 1U); IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, 1U); IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, 1U); IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, 1U); IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, 1U); IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, 1U); IOMUXC_SetPinMux(IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, 1U); IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, 0x10F1U); IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, 0x10F1U); IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, 0x10F1U); IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, 0x10F1U); IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, 0x10F1U); IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, 0x10F1U); IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, 0x10F1U); #endif }void flexspi_nor_flash_init(FLEXSPI_Type *base) {flexspi_config(); /* config flexspi */flexspi_config_t config;/* To store custom's LUT table in local. */uint32_t tempLUT[CUSTOM_LUT_LENGTH] = {0x00U};#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_cache_status_t cacheStatus;flexspi_nor_disable_cache(&cacheStatus); #endif/* Copy LUT information from flash region into RAM region, because LUT update maybe corrupt read sequence(LUT[0])* and load wrong LUT table from FLASH region. */memcpy(tempLUT, customLUT, sizeof(tempLUT));flexspi_clock_init();/*Get FLEXSPI default settings and configure the flexspi. */FLEXSPI_GetDefaultConfig(&config);/*Set AHB buffer size for reading data through AHB bus. */config.ahbConfig.enableAHBPrefetch = true;config.ahbConfig.enableAHBBufferable = true;config.ahbConfig.enableReadAddressOpt = true;config.ahbConfig.enableAHBCachable = true;config.rxSampleClock = EXAMPLE_FLEXSPI_RX_SAMPLE_CLOCK;FLEXSPI_Init(base, &config);/* Configure flash settings according to serial flash feature. */FLEXSPI_SetFlashConfig(base, &deviceconfig, FLASH_PORT);/* Update LUT table. */FLEXSPI_UpdateLUT(base, 0, tempLUT, CUSTOM_LUT_LENGTH);/* Do software reset. */FLEXSPI_SoftwareReset(base);#if defined(CACHE_MAINTAIN) && CACHE_MAINTAINflexspi_nor_enable_cache(cacheStatus); #endif }
这个文件很重要因为它是操作Flash的接口文件,上面的LUT表有相应的Flash命令:如写、擦除、复位,写使能、写使能等操作(对应命令需要去看相应的的flash数据手册)。
const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {/* Normal read mode -SDR */[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x03, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_READ_NORMAL + 1] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),/* Fast read quad mode - SDR */[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_READ_FAST_QUAD + 1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04),/* Read extend parameters */[4 * NOR_CMD_LUT_SEQ_IDX_READSTATUS] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x81, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),/* Write Enable */[4 * NOR_CMD_LUT_SEQ_IDX_WRITEENABLE] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),/* Erase Sector */[4 * NOR_CMD_LUT_SEQ_IDX_ERASESECTOR] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x20, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),/* Page Program - single mode */[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x02, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),[4 * NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM_SINGLE + 1] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, 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 ID */[4 * NOR_CMD_LUT_SEQ_IDX_READID] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x04),/* Enable Quad mode */[4 * NOR_CMD_LUT_SEQ_IDX_WRITESTATUSREG] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x31, kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04),/* Erase Block */ // [4 * NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK] =// FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xD8, kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18),/* 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),/* Erase whole chip */[4 * NOR_CMD_LUT_SEQ_IDX_ERASECHIP] =FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xC7, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), };
-
Fsl_colck.c
/** Copyright 2018 - 2021, 2024 NXP* All rights reserved.** SPDX-License-Identifier: BSD-3-Clause*/#include "fsl_clock.h" /* Component ID definition, used by tools. */ #ifndef FSL_COMPONENT_ID #define FSL_COMPONENT_ID "platform.drivers.clock" #endif/******************************************************************************** Definitions******************************************************************************/ /* To make full use of CM7 hardware FPU, use double instead of uint64_t in clock driver to achieve better performance, it is depend on the IDE Floating point settings, if double precision is selected in IDE, clock_64b_t will switch to double type automatically. only support IAR and MDK here */ #if __FPU_USED#if (defined(__ICCARM__))#if (__ARMVFP__ >= __ARMFPV5__) && \(__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/ typedef double clock_64b_t; #else typedef uint64_t clock_64b_t; #endif#elif (defined(__GNUC__))#if (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/ typedef double clock_64b_t; #else typedef uint64_t clock_64b_t; #endif#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)#if defined __TARGET_FPU_FPV5_D16 typedef double clock_64b_t; #else typedef uint64_t clock_64b_t; #endif#else typedef uint64_t clock_64b_t; #endif#else typedef uint64_t clock_64b_t; #endif/******************************************************************************** Variables******************************************************************************//* External XTAL (OSC) clock frequency. */ volatile uint32_t g_xtalFreq; /* External RTC XTAL clock frequency. */ volatile uint32_t g_rtcXtalFreq;/******************************************************************************** Prototypes******************************************************************************//*!* @brief Get the periph clock frequency.** @return Periph clock frequency in Hz.*/ static uint32_t CLOCK_GetPeriphClkFreq(void);/*!* @brief Get the frequency of PLL USB1 software clock.** @return The frequency of PLL USB1 software clock.*/ static uint32_t CLOCK_GetPllUsb1SWFreq(void);/******************************************************************************** Code******************************************************************************/static uint32_t CLOCK_GetPeriphClkFreq(void) {uint32_t freq;/* Periph_clk2_clk ---> Periph_clk */if ((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK_SEL_MASK) != 0U){switch (CCM->CBCMR & CCM_CBCMR_PERIPH_CLK2_SEL_MASK){/* Pll3_sw_clk ---> Periph_clk2_clk ---> Periph_clk */case CCM_CBCMR_PERIPH_CLK2_SEL(0U):freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);break;/* Osc_clk ---> Periph_clk2_clk ---> Periph_clk */case CCM_CBCMR_PERIPH_CLK2_SEL(1U):freq = CLOCK_GetOscFreq();break;case CCM_CBCMR_PERIPH_CLK2_SEL(2U):freq = CLOCK_GetPllFreq(kCLOCK_PllSys);break;case CCM_CBCMR_PERIPH_CLK2_SEL(3U):default:freq = 0U;break;}freq /= (((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >> CCM_CBCDR_PERIPH_CLK2_PODF_SHIFT) + 1U);}/* Pre_Periph_clk ---> Periph_clk */else{switch (CCM->CBCMR & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK){/* PLL2 ---> Pre_Periph_clk ---> Periph_clk */case CCM_CBCMR_PRE_PERIPH_CLK_SEL(0U):freq = CLOCK_GetPllFreq(kCLOCK_PllSys);break;/* PLL2 PFD2 ---> Pre_Periph_clk ---> Periph_clk */case CCM_CBCMR_PRE_PERIPH_CLK_SEL(1U):freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);break;/* PLL2 PFD0 ---> Pre_Periph_clk ---> Periph_clk */case CCM_CBCMR_PRE_PERIPH_CLK_SEL(2U):freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);break;/* PLL1 divided(/2) ---> Pre_Periph_clk ---> Periph_clk */case CCM_CBCMR_PRE_PERIPH_CLK_SEL(3U):freq = CLOCK_GetPllFreq(kCLOCK_PllArm) /(((CCM->CACRR & CCM_CACRR_ARM_PODF_MASK) >> CCM_CACRR_ARM_PODF_SHIFT) + 1U);break;default:freq = 0U;break;}}return freq; }static uint32_t CLOCK_GetPllUsb1SWFreq(void) {uint32_t freq;switch ((CCM->CCSR & CCM_CCSR_PLL3_SW_CLK_SEL_MASK) >> CCM_CCSR_PLL3_SW_CLK_SEL_SHIFT){case 0:{freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);break;}case 1:{freq = 24000000UL;break;}default:freq = 0UL;break;}return freq; }/*!* brief Initialize the external 24MHz clock.** This function supports two modes:* 1. Use external crystal oscillator.* 2. Bypass the external crystal oscillator, using input source clock directly.** After this function, please call ref CLOCK_SetXtal0Freq to inform clock driver* the external clock frequency.** param bypassXtalOsc Pass in true to bypass the external crystal oscillator.* note This device does not support bypass external crystal oscillator, so* the input parameter should always be false.*/ void CLOCK_InitExternalClk(bool bypassXtalOsc) {/* This device does not support bypass XTAL OSC. */assert(!bypassXtalOsc);CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power up */while ((XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_MASK) == 0U){}CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* detect freq */while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_OSC_XTALOK_MASK) == 0UL){}CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; }/*!* brief Deinitialize the external 24MHz clock.** This function disables the external 24MHz clock.** After this function, please call ref CLOCK_SetXtal0Freq to set external clock* frequency to 0.*/ void CLOCK_DeinitExternalClk(void) {CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power down */ }/*!* brief Switch the OSC.** This function switches the OSC source for SoC.** param osc OSC source to switch to.*/ void CLOCK_SwitchOsc(clock_osc_t osc) {if (osc == kCLOCK_RcOsc){XTALOSC24M->LOWPWR_CTRL_SET = XTALOSC24M_LOWPWR_CTRL_SET_OSC_SEL_MASK;}else{XTALOSC24M->LOWPWR_CTRL_CLR = XTALOSC24M_LOWPWR_CTRL_CLR_OSC_SEL_MASK;} }/*!* brief Initialize the RC oscillator 24MHz clock.*/ void CLOCK_InitRcOsc24M(void) {XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK; }/*!* brief Power down the RCOSC 24M clock.*/ void CLOCK_DeinitRcOsc24M(void) {XTALOSC24M->LOWPWR_CTRL &= ~XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK; }/*!* brief Gets the AHB clock frequency.** return The AHB clock frequency value in hertz.*/ uint32_t CLOCK_GetAhbFreq(void) {return CLOCK_GetPeriphClkFreq() / (((CCM->CBCDR & CCM_CBCDR_AHB_PODF_MASK) >> CCM_CBCDR_AHB_PODF_SHIFT) + 1U); }/*!* brief Gets the SEMC clock frequency.** return The SEMC clock frequency value in hertz.*/ uint32_t CLOCK_GetSemcFreq(void) {uint32_t freq;/* SEMC alternative clock ---> SEMC Clock */if ((CCM->CBCDR & CCM_CBCDR_SEMC_CLK_SEL_MASK) != 0U){/* PLL3 PFD1 ---> SEMC alternative clock ---> SEMC Clock */if ((CCM->CBCDR & CCM_CBCDR_SEMC_ALT_CLK_SEL_MASK) != 0U){freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);}/* PLL2 PFD2 ---> SEMC alternative clock ---> SEMC Clock */else{freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);}}/* Periph_clk ---> SEMC Clock */else{freq = CLOCK_GetPeriphClkFreq();}freq /= (((CCM->CBCDR & CCM_CBCDR_SEMC_PODF_MASK) >> CCM_CBCDR_SEMC_PODF_SHIFT) + 1U);return freq; }/*!* brief Gets the IPG clock frequency.** return The IPG clock frequency value in hertz.*/ uint32_t CLOCK_GetIpgFreq(void) {return CLOCK_GetAhbFreq() / (((CCM->CBCDR & CCM_CBCDR_IPG_PODF_MASK) >> CCM_CBCDR_IPG_PODF_SHIFT) + 1U); }/*!* brief Gets the PER clock frequency.** return The PER clock frequency value in hertz.*/ uint32_t CLOCK_GetPerClkFreq(void) {uint32_t freq;/* Osc_clk ---> PER Clock*/if ((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) != 0U){freq = CLOCK_GetOscFreq();}/* Periph_clk ---> AHB Clock ---> IPG Clock ---> PER Clock */else{freq = CLOCK_GetIpgFreq();}freq /= (((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_PODF_MASK) >> CCM_CSCMR1_PERCLK_PODF_SHIFT) + 1U);return freq; }/*!* brief Gets the clock frequency for a specific clock name.** This function checks the current clock configurations and then calculates* the clock frequency for a specific clock name defined in clock_name_t.** param clockName Clock names defined in clock_name_t* return Clock frequency value in hertz*/ uint32_t CLOCK_GetFreq(clock_name_t name) {uint32_t freq;switch (name){case kCLOCK_CpuClk:case kCLOCK_AhbClk:freq = CLOCK_GetAhbFreq();break;case kCLOCK_SemcClk:freq = CLOCK_GetSemcFreq();break;case kCLOCK_IpgClk:freq = CLOCK_GetIpgFreq();break;case kCLOCK_PerClk:freq = CLOCK_GetPerClkFreq();break;case kCLOCK_OscClk:freq = CLOCK_GetOscFreq();break;case kCLOCK_RtcClk:freq = CLOCK_GetRtcFreq();break;case kCLOCK_ArmPllClk:freq = CLOCK_GetPllFreq(kCLOCK_PllArm);break;case kCLOCK_Usb1PllClk:freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);break;case kCLOCK_Usb1PllPfd0Clk:freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd0);break;case kCLOCK_Usb1PllPfd1Clk:freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);break;case kCLOCK_Usb1PllPfd2Clk:freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);break;case kCLOCK_Usb1PllPfd3Clk:freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3);break;case kCLOCK_Usb1SwClk:freq = CLOCK_GetPllUsb1SWFreq();break;case kCLOCK_Usb1Sw120MClk:freq = CLOCK_GetPllUsb1SWFreq() / 4UL;break;case kCLOCK_Usb1Sw60MClk:freq = CLOCK_GetPllUsb1SWFreq() / 8UL;break;case kCLOCK_Usb1Sw80MClk:freq = CLOCK_GetPllUsb1SWFreq() / 6UL;break;case kCLOCK_Usb2PllClk:freq = CLOCK_GetPllFreq(kCLOCK_PllUsb2);break;case kCLOCK_SysPllClk:freq = CLOCK_GetPllFreq(kCLOCK_PllSys);break;case kCLOCK_SysPllPfd0Clk:freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);break;case kCLOCK_SysPllPfd1Clk:freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1);break;case kCLOCK_SysPllPfd2Clk:freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);break;case kCLOCK_SysPllPfd3Clk:freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3);break;case kCLOCK_EnetPll0Clk:freq = CLOCK_GetPllFreq(kCLOCK_PllEnet);break;case kCLOCK_EnetPll1Clk:freq = CLOCK_GetPllFreq(kCLOCK_PllEnet2);break;case kCLOCK_EnetPll2Clk:freq = CLOCK_GetPllFreq(kCLOCK_PllEnet25M);break;case kCLOCK_AudioPllClk:freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);break;case kCLOCK_VideoPllClk:freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);break;default:freq = 0U;break;}return freq; }/*!* brief Gets the frequency of selected clock root.** param clockRoot The clock root used to get the frequency, please refer to @ref clock_root_t.* return The frequency of selected clock root.*/ uint32_t CLOCK_GetClockRootFreq(clock_root_t clockRoot) {static const clock_name_t clockRootSourceArray[][6] = CLOCK_ROOT_SOUCE;static const clock_mux_t clockRootMuxTupleArray[] = CLOCK_ROOT_MUX_TUPLE;static const clock_div_t clockRootDivTupleArray[][2] = CLOCK_ROOT_DIV_TUPLE;uint32_t freq = 0UL;clock_mux_t clockRootMuxTuple = clockRootMuxTupleArray[(uint8_t)clockRoot];clock_div_t clockRootPreDivTuple = clockRootDivTupleArray[(uint8_t)clockRoot][0];clock_div_t clockRootPostDivTuple = clockRootDivTupleArray[(uint8_t)clockRoot][1];uint32_t clockRootMuxValue = (CCM_TUPLE_REG(CCM, clockRootMuxTuple) & CCM_TUPLE_MASK(clockRootMuxTuple)) >>CCM_TUPLE_SHIFT(clockRootMuxTuple);clock_name_t clockSourceName;clockSourceName = clockRootSourceArray[(uint8_t)clockRoot][clockRootMuxValue];assert(clockSourceName != kCLOCK_NoneName);freq = CLOCK_GetFreq(clockSourceName);if (clockRootPreDivTuple != kCLOCK_NonePreDiv){freq /= ((CCM_TUPLE_REG(CCM, clockRootPreDivTuple) & CCM_TUPLE_MASK(clockRootPreDivTuple)) >>CCM_TUPLE_SHIFT(clockRootPreDivTuple)) +1UL;}freq /= ((CCM_TUPLE_REG(CCM, clockRootPostDivTuple) & CCM_TUPLE_MASK(clockRootPostDivTuple)) >>CCM_TUPLE_SHIFT(clockRootPostDivTuple)) +1UL;return freq; }/*! brief Enable USB HS clock.** This function only enables the access to USB HS prepheral, upper layer* should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY* clock to use USB HS.** param src USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.* param freq USB HS does not care about the clock source, so this parameter is ignored.* retval true The clock is set successfully.* retval false The clock source is invalid to get proper USB HS clock.*/ bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq) {uint32_t i;CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;USB1->USBCMD |= USBHS_USBCMD_RST_MASK;/* Add a delay between RST and RS so make sure there is a DP pullup sequence*/for (i = 0; i < 400000U; i++){__ASM("nop");}PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |(PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);return true; }/*! brief Enable USB HS clock.** This function only enables the access to USB HS prepheral, upper layer* should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY* clock to use USB HS.** param src USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.* param freq USB HS does not care about the clock source, so this parameter is ignored.* retval true The clock is set successfully.* retval false The clock source is invalid to get proper USB HS clock.*/ bool CLOCK_EnableUsbhs1Clock(clock_usb_src_t src, uint32_t freq) {uint32_t i = 0;CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;USB2->USBCMD |= USBHS_USBCMD_RST_MASK;/* Add a delay between RST and RS so make sure there is a DP pullup sequence*/for (i = 0; i < 400000U; i++){__ASM("nop");}PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |(PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);return true; }/*! brief Enable USB HS PHY PLL clock.** This function enables the internal 480MHz USB PHY PLL clock.** param src USB HS PHY PLL clock source.* param freq The frequency specified by src.* retval true The clock is set successfully.* retval false The clock source is invalid to get proper USB HS clock.*/ bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq) {static const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};if ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_ENABLE_MASK) != 0U){CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;}else{CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);}USBPHY1->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */USBPHY1->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;USBPHY1->PWD = 0;USBPHY1->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;return true; }/*! brief Disable USB HS PHY PLL clock.** This function disables USB HS PHY PLL clock.*/ void CLOCK_DisableUsbhs0PhyPllClock(void) {CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;USBPHY1->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */ }/*!* brief Initialize the ARM PLL.** This function initialize the ARM PLL with specific settings** param config configuration to set to PLL.*/ void CLOCK_InitArmPll(const clock_arm_pll_config_t *config) {/* Bypass PLL first */CCM_ANALOG->PLL_ARM = (CCM_ANALOG->PLL_ARM & (~CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK)) |CCM_ANALOG_PLL_ARM_BYPASS_MASK | CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC(config->src);CCM_ANALOG->PLL_ARM =(CCM_ANALOG->PLL_ARM & (~(CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK | CCM_ANALOG_PLL_ARM_POWERDOWN_MASK))) |CCM_ANALOG_PLL_ARM_ENABLE_MASK | CCM_ANALOG_PLL_ARM_DIV_SELECT(config->loopDivider);while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0UL){}/* Disable Bypass */CCM_ANALOG->PLL_ARM &= ~CCM_ANALOG_PLL_ARM_BYPASS_MASK; }/*!* brief De-initialize the ARM PLL.*/ void CLOCK_DeinitArmPll(void) {CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_MASK; }/*!* brief Initialize the System PLL.** This function initializes the System PLL with specific settings** param config Configuration to set to PLL.*/ void CLOCK_InitSysPll(const clock_sys_pll_config_t *config) {/* Bypass PLL first */CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & (~CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK)) |CCM_ANALOG_PLL_SYS_BYPASS_MASK | CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC(config->src);CCM_ANALOG->PLL_SYS =(CCM_ANALOG->PLL_SYS & (~(CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK | CCM_ANALOG_PLL_SYS_POWERDOWN_MASK))) |CCM_ANALOG_PLL_SYS_ENABLE_MASK | CCM_ANALOG_PLL_SYS_DIV_SELECT(config->loopDivider);/* Initialize the fractional mode */CCM_ANALOG->PLL_SYS_NUM = CCM_ANALOG_PLL_SYS_NUM_A(config->numerator);CCM_ANALOG->PLL_SYS_DENOM = CCM_ANALOG_PLL_SYS_DENOM_B(config->denominator);/* Initialize the spread spectrum mode */CCM_ANALOG->PLL_SYS_SS = CCM_ANALOG_PLL_SYS_SS_STEP(config->ss_step) |CCM_ANALOG_PLL_SYS_SS_ENABLE(config->ss_enable) |CCM_ANALOG_PLL_SYS_SS_STOP(config->ss_stop);while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0UL){}/* Disable Bypass */CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK; }/*!* brief De-initialize the System PLL.*/ void CLOCK_DeinitSysPll(void) {CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_POWERDOWN_MASK; }/*!* brief Initialize the USB1 PLL.** This function initializes the USB1 PLL with specific settings** param config Configuration to set to PLL.*/ void CLOCK_InitUsb1Pll(const clock_usb_pll_config_t *config) {/* Bypass PLL first */CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) |CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src);CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) |CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK |CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL){}/* Disable Bypass */CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK; }/*!* brief Deinitialize the USB1 PLL.*/ void CLOCK_DeinitUsb1Pll(void) {CCM_ANALOG->PLL_USB1 = 0U; }/*!* brief Initialize the USB2 PLL.** This function initializes the USB2 PLL with specific settings** param config Configuration to set to PLL.*/ void CLOCK_InitUsb2Pll(const clock_usb_pll_config_t *config) {/* Bypass PLL first */CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_MASK)) |CCM_ANALOG_PLL_USB2_BYPASS_MASK | CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC(config->src);CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK)) |CCM_ANALOG_PLL_USB2_ENABLE_MASK | CCM_ANALOG_PLL_USB2_POWER_MASK |CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB2_DIV_SELECT(config->loopDivider);while ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_LOCK_MASK) == 0UL){}/* Disable Bypass */CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_BYPASS_MASK; }/*!* brief Deinitialize the USB2 PLL.*/ void CLOCK_DeinitUsb2Pll(void) {CCM_ANALOG->PLL_USB2 = 0U; }/*!* brief Initializes the Audio PLL.** This function initializes the Audio PLL with specific settings** param config Configuration to set to PLL.*/ void CLOCK_InitAudioPll(const clock_audio_pll_config_t *config) {uint32_t pllAudio;uint32_t misc2 = 0;/* Bypass PLL first */CCM_ANALOG->PLL_AUDIO = (CCM_ANALOG->PLL_AUDIO & (~CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC_MASK)) |CCM_ANALOG_PLL_AUDIO_BYPASS_MASK | CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC(config->src);CCM_ANALOG->PLL_AUDIO_NUM = CCM_ANALOG_PLL_AUDIO_NUM_A(config->numerator);CCM_ANALOG->PLL_AUDIO_DENOM = CCM_ANALOG_PLL_AUDIO_DENOM_B(config->denominator);/** Set post divider:** ------------------------------------------------------------------------* | config->postDivider | PLL_AUDIO[POST_DIV_SELECT] | MISC2[AUDIO_DIV] |* ------------------------------------------------------------------------* | 1 | 2 | 0 |* ------------------------------------------------------------------------* | 2 | 1 | 0 |* ------------------------------------------------------------------------* | 4 | 2 | 3 |* ------------------------------------------------------------------------* | 8 | 1 | 3 |* ------------------------------------------------------------------------* | 16 | 0 | 3 |* ------------------------------------------------------------------------*/pllAudio =(CCM_ANALOG->PLL_AUDIO & (~(CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK | CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK))) |CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(config->loopDivider);switch (config->postDivider){case 16:pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0);misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;break;case 8:pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;break;case 4:pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;break;case 2:pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);break;default:pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);break;}CCM_ANALOG->MISC2 =(CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK)) | misc2;CCM_ANALOG->PLL_AUDIO = pllAudio;while ((CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK_MASK) == 0UL){}/* Disable Bypass */CCM_ANALOG->PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS_MASK; }/*!* brief De-initialize the Audio PLL.*/ void CLOCK_DeinitAudioPll(void) {CCM_ANALOG->PLL_AUDIO = (uint32_t)CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK; }/*!* brief Initialize the video PLL.** This function configures the Video PLL with specific settings** param config configuration to set to PLL.*/ void CLOCK_InitVideoPll(const clock_video_pll_config_t *config) {uint32_t pllVideo;uint32_t misc2 = 0;/* Bypass PLL first */CCM_ANALOG->PLL_VIDEO = (CCM_ANALOG->PLL_VIDEO & (~CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK)) |CCM_ANALOG_PLL_VIDEO_BYPASS_MASK | CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC(config->src);CCM_ANALOG->PLL_VIDEO_NUM = CCM_ANALOG_PLL_VIDEO_NUM_A(config->numerator);CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(config->denominator);/** Set post divider:** ------------------------------------------------------------------------* | config->postDivider | PLL_VIDEO[POST_DIV_SELECT] | MISC2[VIDEO_DIV] |* ------------------------------------------------------------------------* | 1 | 2 | 0 |* ------------------------------------------------------------------------* | 2 | 1 | 0 |* ------------------------------------------------------------------------* | 4 | 2 | 3 |* ------------------------------------------------------------------------* | 8 | 1 | 3 |* ------------------------------------------------------------------------* | 16 | 0 | 3 |* ------------------------------------------------------------------------*/pllVideo =(CCM_ANALOG->PLL_VIDEO & (~(CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK | CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK))) |CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(config->loopDivider);switch (config->postDivider){case 16:pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0);misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);break;case 8:pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);break;case 4:pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);break;case 2:pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);break;default:pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);break;}CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~CCM_ANALOG_MISC2_VIDEO_DIV_MASK) | misc2;CCM_ANALOG->PLL_VIDEO = pllVideo;while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0UL){}/* Disable Bypass */CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS_MASK; }/*!* brief De-initialize the Video PLL.*/ void CLOCK_DeinitVideoPll(void) {CCM_ANALOG->PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK; }/*!* brief Initialize the ENET PLL.** This function initializes the ENET PLL with specific settings.** param config Configuration to set to PLL.*/ void CLOCK_InitEnetPll(const clock_enet_pll_config_t *config) {uint32_t enet_pll = CCM_ANALOG_PLL_ENET_DIV_SELECT(config->loopDivider) |CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT(config->loopDivider1);CCM_ANALOG->PLL_ENET = (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK)) |CCM_ANALOG_PLL_ENET_BYPASS_MASK | CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(config->src);if (config->enableClkOutput){enet_pll |= CCM_ANALOG_PLL_ENET_ENABLE_MASK;}if (config->enableClkOutput1){enet_pll |= CCM_ANALOG_PLL_ENET_ENET2_REF_EN_MASK;}if (config->enableClkOutput25M){enet_pll |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK;}CCM_ANALOG->PLL_ENET =(CCM_ANALOG->PLL_ENET & (~(CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_MASK |CCM_ANALOG_PLL_ENET_POWERDOWN_MASK))) |enet_pll;/* Wait for stable */while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0UL){}/* Disable Bypass */CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_BYPASS_MASK; }/*!* brief Deinitialize the ENET PLL.** This function disables the ENET PLL.*/ void CLOCK_DeinitEnetPll(void) {CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK; }/*!* brief Get current PLL output frequency.** This function get current output frequency of specific PLL** param pll pll name to get frequency.* return The PLL output frequency in hertz.*/ uint32_t CLOCK_GetPllFreq(clock_pll_t pll) {uint32_t freq;uint32_t divSelect;clock_64b_t freqTmp;static const uint32_t enetRefClkFreq[] = {25000000U, /* 25M */50000000U, /* 50M */100000000U, /* 100M */125000000U /* 125M */};/* check if PLL is enabled */if (!CLOCK_IsPllEnabled(CCM_ANALOG, pll)){return 0U;}/* get pll reference clock */freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, pll);/* check if pll is bypassed */if (CLOCK_IsPllBypassed(CCM_ANALOG, pll)){return freq;}switch (pll){case kCLOCK_PllArm:freq = ((freq * ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >>CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT)) >>1U);break;case kCLOCK_PllSys:/* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_SYS_NUM)));freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_SYS_DENOM));if ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) != 0U){freq *= 22U;}else{freq *= 20U;}freq += (uint32_t)freqTmp;break;case kCLOCK_PllUsb1:freq = (freq * (((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0UL) ? 22U : 20U));break;case kCLOCK_PllAudio:/* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */divSelect =(CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_AUDIO_DIV_SELECT_SHIFT;freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_NUM)));freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_DENOM));freq = freq * divSelect + (uint32_t)freqTmp;/* AUDIO PLL output = PLL output frequency / POSTDIV. *//** Post divider:** PLL_AUDIO[POST_DIV_SELECT]:* 0x00: 4* 0x01: 2* 0x02: 1** MISC2[AUDO_DIV]:* 0x00: 1* 0x01: 2* 0x02: 1* 0x03: 4*/switch (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_MASK){case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0U):freq = freq >> 2U;break;case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1U):freq = freq >> 1U;break;case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2U):freq = freq >> 0U;break;default:assert(false);break;}switch (CCM_ANALOG->MISC2 & (CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK)){case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):freq >>= 2U;break;case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):freq >>= 1U;break;case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):freq >>= 0U;break;default:assert(false);break;}break;case kCLOCK_PllVideo:/* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */divSelect =(CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT;freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_NUM)));freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_DENOM));freq = freq * divSelect + (uint32_t)freqTmp;/* VIDEO PLL output = PLL output frequency / POSTDIV. *//** Post divider:** PLL_VIDEO[POST_DIV_SELECT]:* 0x00: 4* 0x01: 2* 0x02: 1** MISC2[VIDEO_DIV]:* 0x00: 1* 0x01: 2* 0x02: 1* 0x03: 4*/switch (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK){case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0U):freq = freq >> 2U;break;case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1U):freq = freq >> 1U;break;case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2U):freq = freq >> 0U;break;default:assert(false);break;}switch (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV_MASK){case CCM_ANALOG_MISC2_VIDEO_DIV(3U):freq >>= 2U;break;case CCM_ANALOG_MISC2_VIDEO_DIV(1U):freq >>= 1U;break;case CCM_ANALOG_MISC2_VIDEO_DIV(0U):case CCM_ANALOG_MISC2_VIDEO_DIV(2U):freq >>= 0U;break;default:assert(false);break;}break;case kCLOCK_PllEnet:divSelect =(CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT;freq = enetRefClkFreq[divSelect];break;case kCLOCK_PllEnet2:divSelect = (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_MASK) >>CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_SHIFT;freq = enetRefClkFreq[divSelect];break;case kCLOCK_PllEnet25M:/* ref_enetpll1 if fixed at 25MHz. */freq = 25000000UL;break;case kCLOCK_PllUsb2:freq = (freq * (((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK) != 0U) ? 22U : 20U));break;default:freq = 0U;break;}return freq; }/*!* brief Initialize the System PLL PFD.** This function initializes the System PLL PFD. During new value setting,* the clock output is disabled to prevent glitch.** param pfd Which PFD clock to enable.* param pfdFrac The PFD FRAC value.* note It is recommended that PFD settings are kept between 12-35.*/ void CLOCK_InitSysPfd(clock_pfd_t pfd, uint8_t pfdFrac) {uint32_t pfdIndex = (uint32_t)pfd;uint32_t pfd528;pfd528 = CCM_ANALOG->PFD_528 &~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)<< (8UL * pfdIndex)));/* Disable the clock output first. */CCM_ANALOG->PFD_528 = pfd528 | ((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * pfdIndex));/* Set the new value and enable output. */CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex)); }/*!* brief De-initialize the System PLL PFD.** This function disables the System PLL PFD.** param pfd Which PFD clock to disable.*/ void CLOCK_DeinitSysPfd(clock_pfd_t pfd) {CCM_ANALOG->PFD_528 |= (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8U * (uint8_t)pfd); }/*!* brief Check if Sys PFD is enabled** param pfd PFD control name* return PFD bypass status.* - true: power on.* - false: power off.*/ bool CLOCK_IsSysPfdEnabled(clock_pfd_t pfd) {return ((CCM_ANALOG->PFD_528 & (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd)) == 0U); }/*!* brief Initialize the USB1 PLL PFD.** This function initializes the USB1 PLL PFD. During new value setting,* the clock output is disabled to prevent glitch.** param pfd Which PFD clock to enable.* param pfdFrac The PFD FRAC value.* note It is recommended that PFD settings are kept between 12-35.*/ void CLOCK_InitUsb1Pfd(clock_pfd_t pfd, uint8_t pfdFrac) {uint32_t pfdIndex = (uint32_t)pfd;uint32_t pfd480;pfd480 = CCM_ANALOG->PFD_480 &~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD0_FRAC_MASK)<< (8UL * pfdIndex)));/* Disable the clock output first. */CCM_ANALOG->PFD_480 = pfd480 | ((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * pfdIndex));/* Set the new value and enable output. */CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex)); }/*!* brief De-initialize the USB1 PLL PFD.** This function disables the USB1 PLL PFD.** param pfd Which PFD clock to disable.*/ void CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd) {CCM_ANALOG->PFD_480 |= (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd); }/*!* brief Check if Usb1 PFD is enabled** param pfd PFD control name.* return PFD bypass status.* - true: power on.* - false: power off.*/ bool CLOCK_IsUsb1PfdEnabled(clock_pfd_t pfd) {return ((CCM_ANALOG->PFD_480 & (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd)) == 0U); }/*!* brief Get current System PLL PFD output frequency.** This function get current output frequency of specific System PLL PFD** param pfd pfd name to get frequency.* return The PFD output frequency in hertz.*/ uint32_t CLOCK_GetSysPfdFreq(clock_pfd_t pfd) {uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllSys);uint64_t tmp64 = (uint64_t)freq * 18UL;switch (pfd){case kCLOCK_Pfd0:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD0_FRAC_SHIFT));break;case kCLOCK_Pfd1:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD1_FRAC_SHIFT));break;case kCLOCK_Pfd2:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD2_FRAC_SHIFT));break;case kCLOCK_Pfd3:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD3_FRAC_SHIFT));break;default:freq = 0U;break;}return freq; }/*!* brief Get current USB1 PLL PFD output frequency.** This function get current output frequency of specific USB1 PLL PFD** param pfd pfd name to get frequency.* return The PFD output frequency in hertz.*/ uint32_t CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd) {uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);uint64_t tmp64 = (uint64_t)freq * 18UL;switch (pfd){case kCLOCK_Pfd0:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT));break;case kCLOCK_Pfd1:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD1_FRAC_SHIFT));break;case kCLOCK_Pfd2:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD2_FRAC_SHIFT));break;case kCLOCK_Pfd3:freq = (uint32_t)(tmp64 / (uint64_t)((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT));break;default:freq = 0U;break;}return freq; }/*! brief Enable USB HS PHY PLL clock.** This function enables the internal 480MHz USB PHY PLL clock.** param src USB HS PHY PLL clock source.* param freq The frequency specified by src.* retval true The clock is set successfully.* retval false The clock source is invalid to get proper USB HS clock.*/ bool CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src, uint32_t freq) {static const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};CLOCK_InitUsb2Pll(&g_ccmConfigUsbPll);USBPHY2->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */USBPHY2->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;USBPHY2->PWD = 0;USBPHY2->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;return true; }/*! brief Disable USB HS PHY PLL clock.** This function disables USB HS PHY PLL clock.*/ void CLOCK_DisableUsbhs1PhyPllClock(void) {CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK;USBPHY2->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */ }/*!* brief Set the clock source and the divider of the clock output1.** param selection The clock source to be output, please refer to clock_output1_selection_t.* param divider The divider of the output clock signal, please refer to clock_output_divider_t.*/ void CLOCK_SetClockOutput1(clock_output1_selection_t selection, clock_output_divider_t divider) {uint32_t tmp32;tmp32 = CCM->CCOSR;if (selection == kCLOCK_DisableClockOutput1){tmp32 &= ~CCM_CCOSR_CLKO1_EN_MASK;}else{tmp32 |= CCM_CCOSR_CLKO1_EN_MASK;tmp32 &= ~(CCM_CCOSR_CLKO1_SEL_MASK | CCM_CCOSR_CLKO1_DIV_MASK);tmp32 |= CCM_CCOSR_CLKO1_SEL(selection) | CCM_CCOSR_CLKO1_DIV(divider);}CCM->CCOSR = tmp32; }/*!* brief Set the clock source and the divider of the clock output2.** param selection The clock source to be output, please refer to clock_output2_selection_t.* param divider The divider of the output clock signal, please refer to clock_output_divider_t.*/ void CLOCK_SetClockOutput2(clock_output2_selection_t selection, clock_output_divider_t divider) {uint32_t tmp32;tmp32 = CCM->CCOSR;if (selection == kCLOCK_DisableClockOutput2){tmp32 &= CCM_CCOSR_CLKO2_EN_MASK;}else{tmp32 |= CCM_CCOSR_CLKO2_EN_MASK;tmp32 &= ~(CCM_CCOSR_CLKO2_SEL_MASK | CCM_CCOSR_CLKO2_DIV_MASK);tmp32 |= CCM_CCOSR_CLKO2_SEL(selection) | CCM_CCOSR_CLKO2_DIV(divider);}CCM->CCOSR = tmp32; }/*!* brief Get the frequency of clock output1 clock signal.** return The frequency of clock output1 clock signal.*/ uint32_t CLOCK_GetClockOutCLKO1Freq(void) {uint32_t freq = 0U;uint32_t tmp32;tmp32 = CCM->CCOSR;if ((tmp32 & CCM_CCOSR_CLKO1_EN_MASK) != 0UL){switch ((tmp32 & CCM_CCOSR_CLKO1_SEL_MASK) >> CCM_CCOSR_CLKO1_SEL_SHIFT){case (uint32_t)kCLOCK_OutputPllUsb1:freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 2U;break;case (uint32_t)kCLOCK_OutputPllSys:freq = CLOCK_GetPllFreq(kCLOCK_PllSys) / 2U;break;case (uint32_t)kCLOCK_OutputPllVideo:freq = CLOCK_GetPllFreq(kCLOCK_PllVideo) / 2U;break;case (uint32_t)kCLOCK_OutputSemcClk:freq = CLOCK_GetSemcFreq();break;case (uint32_t)kCLOCK_OutputLcdifPixClk:freq = CLOCK_GetClockRootFreq(kCLOCK_LcdifClkRoot);break;case (uint32_t)kCLOCK_OutputAhbClk:freq = CLOCK_GetAhbFreq();break;case (uint32_t)kCLOCK_OutputIpgClk:freq = CLOCK_GetIpgFreq();break;case (uint32_t)kCLOCK_OutputPerClk:freq = CLOCK_GetPerClkFreq();break;case (uint32_t)kCLOCK_OutputCkilSyncClk:freq = CLOCK_GetRtcFreq();break;case (uint32_t)kCLOCK_OutputPll4MainClk:freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);break;default:/* This branch should never be hit. */break;}freq /= (((tmp32 & CCM_CCOSR_CLKO1_DIV_MASK) >> CCM_CCOSR_CLKO1_DIV_SHIFT) + 1U);}else{freq = 0UL;}return freq; }/*!* brief Get the frequency of clock output2 clock signal.** return The frequency of clock output2 clock signal.*/ uint32_t CLOCK_GetClockOutClkO2Freq(void) {uint32_t freq = 0U;uint32_t tmp32;tmp32 = CCM->CCOSR;if ((tmp32 & CCM_CCOSR_CLKO2_EN_MASK) != 0UL){switch ((tmp32 & CCM_CCOSR_CLKO2_SEL_MASK) >> CCM_CCOSR_CLKO2_SEL_SHIFT){case (uint32_t)kCLOCK_OutputUsdhc1Clk:freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc1ClkRoot);break;case (uint32_t)kCLOCK_OutputLpi2cClk:freq = CLOCK_GetClockRootFreq(kCLOCK_Lpi2cClkRoot);break;case (uint32_t)kCLOCK_OutputCsiClk:freq = CLOCK_GetClockRootFreq(kCLOCK_CsiClkRoot);break;case (uint32_t)kCLOCK_OutputOscClk:freq = CLOCK_GetOscFreq();break;case (uint32_t)kCLOCK_OutputUsdhc2Clk:freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc2ClkRoot);break;case (uint32_t)kCLOCK_OutputSai1Clk:freq = CLOCK_GetClockRootFreq(kCLOCK_Sai1ClkRoot);break;case (uint32_t)kCLOCK_OutputSai2Clk:freq = CLOCK_GetClockRootFreq(kCLOCK_Sai2ClkRoot);break;case (uint32_t)kCLOCK_OutputSai3Clk:freq = CLOCK_GetClockRootFreq(kCLOCK_Sai3ClkRoot);break;case (uint32_t)kCLOCK_OutputCanClk:freq = CLOCK_GetClockRootFreq(kCLOCK_CanClkRoot);break;case (uint32_t)kCLOCK_OutputFlexspiClk:freq = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot);break;case (uint32_t)kCLOCK_OutputUartClk:freq = CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot);break;case (uint32_t)kCLOCK_OutputSpdif0Clk:freq = CLOCK_GetClockRootFreq(kCLOCK_SpdifClkRoot);break;default:/* This branch should never be hit. */break;}freq /= (((tmp32 & CCM_CCOSR_CLKO2_DIV_MASK) >> CCM_CCOSR_CLKO2_DIV_SHIFT) + 1U);}else{freq = 0UL;}return freq; }
这个文件是这个芯片的时钟驱动,这里需要配置同样的时钟驱动,以确保可以让单片机正常运行。
[!CAUTION]
要引用正确的头文件路径,不然代码会编译不通过,这里需要重点注意
- 写好相应的接口
- 对时钟,flash进行初始化
- 可以对flash进行操作,如:读、写、擦、等
- 对接flashprg文件中的接口即可
4、验证
打开keil工程目录,将生成的FLM文件复制到下载算法的Flash目录中,然后打开任意工程编译好之后选择生成的FLM算法进行下载,经测试发现可以正常将代码下载到Flash当中。
总结
本文主要介绍了如何制作符合自己设备的FLM下载算法,文中以nxp的 I.MX RT1062 的Qspi flash作为例子,最后成功将代码通过生成的FLM下载到trget(目标单片机中)