如何制作符合自己设备的FLM下载算法

news/2025/1/17 19:51:49/

FLM_0">如何制作符合自己设备的FLM下载算法

--------以I.MXRT1062 QSPI FLAH为例(串行qspi nor flash)

本文介绍一种基于i.mxrt1062的外挂flah的qspi nor flash下载算法FLM的一种方法,Flash 编程算法是一种用于擦除或下载应用程序到 Flash 设备的软件。设备系列包 (DFP) 通常包含预定义的 Flash 算法,用于对其中支持的设备进行编程。ARM:CMSIS 包中提供了用于创建新算法的模板。以下部分更详细地介绍了该过程。

文章目录

前言

什么是FLMFLM(FLASH Loader Middeware)即闪存加载中间件,一般来说FLM下载算法不需要我们制作,因为使用Keil MDK进行开发,我们需要安装packet软件包,而这软件包就包含了FLM下载算法。当我们在keil mdk中编译好了镜像(hex 、bin、srec、elf)文件需要下载到flash当中时,首先需要选择适合您开发板的FLM下载算法
选择<a class=FLM下载算法" />

从上图可以看到我们可以选择的下载算法有都在列表里面了,但是我们要把程序下载进去需要选择适合自己的FLM文件,像开发STM32则直接选择就可以了,我们在安装软件包时候就已经将下载算法包含到Flash文件夹当中了。我们可以打开keil mdk的安装目录进行查看(路径为**…**/keil/arm/flash)文件夹下。
在这里插入图片描述

1、下载算法原理

我们使用下载工具(J-LinkST-LinkDAP-Link)进行下载,其本质就是将FLMFlash 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

    这个文件是和你的下载息息相关,大家可以去看看里面的函数,不难发现里面的函数是空函数,这部分需要读者自己去实现。

    这些函数分别是

    • init();

      • Init解释为初始化,初始化时钟、外设总线、Flash接口等等。
    • uinit();

      • Uint解释为解除初始化,解除初始化,用在IDE完成对程序的下载之后,解除FLM的操作。
    • EraseChip();

      • EraseChip解释为擦除整个芯片的意思,对于Flash而言,要想将程序下载到Flash里面,就要先擦除,Flash存储器的擦除操作是在块级别上进行的,意味着要擦除数据时,必须擦除整个块,而不能只擦除单个字节或位,擦除操作会将块中的所有位设置为逻辑“1”。
      • 在NOR Flash中,擦除操作会将位设置为高电平;在NAND Flash中,擦除操作会将位设置为低电平。在向Flash存储器写入数据之前,必须先擦除目标块,因为Flash只能将位从“1”改变为“0”,而不能从“0”改变为“1”。
    • EraseSector();

      EraseSector 解释为擦除扇区,在Flash中可以选择擦除的方式,比如:

      • 单元(Cell)Flash存储器的基本存储单元,用于存储一个位(bit)的信息。
      • 块(Block):由多个存储单元组成,是Flash擦除操作的基本单位。一个块通常包含32、64、128或更多个字节。
      • 面(Plane) 或 子系统(Sub-array)Flash设备可能包含多个块,这些块可以组织成面或子系统。
    • ProgramPage();

      ProgramPage(通俗讲就是将程序下载到Flash里面)通常是指在使用Flash存储器编程时,将数据写入Flash的一个操作过程。在嵌入式系统编程中,Flash编程通常涉及以下步骤:

      • 擦除(Erase):在写入数据之前,必须先擦除Flash块。这是因为Flash只能将位从1改变为0,而不能从0改变为1。擦除操作会将整个块设置为全1状态。
      • 编程(Program):编程操作是将数据写入已经被擦除的Flash块中。ProgramPage通常指的是将一页(Page)数据写入Flash存储器。
  • 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、实战

1、基于I.MX RT1062FLM下载算法

[!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]

    要引用正确的头文件路径,不然代码会编译不通过,这里需要重点注意

在这里插入图片描述

2、制作其它单片机FLM下载算法

  • 写好相应的接口
  • 对时钟,flash进行初始化
  • 可以对flash进行操作,如:读、写、擦、等
  • 对接flashprg文件中的接口即可

4、验证

打开keil工程目录,将生成的FLM文件复制到下载算法Flash目录中,然后打开任意工程编译好之后选择生成的FLM算法进行下载,经测试发现可以正常将代码下载到Flash当中。

总结

本文主要介绍了如何制作符合自己设备的FLM下载算法,文中以nxp的 I.MX RT1062 的Qspi flash作为例子,最后成功将代码通过生成的FLM下载到trget(目标单片机中)


http://www.ppmy.cn/news/1563955.html

相关文章

k8s加入集群一直卡在Running pre-flight checks

情况一&#xff1a;token过期问题 如果是token过期问题&#xff0c;重新生成一下token在加入进去就行了 重新生成一个永不过期的token&#xff1a; kubeadm token create --ttl 0把初始化生成命令的token换成这个新生成的即可 重新生成一个永不过期的token并且打印加入命令&a…

AI的崛起:它将如何改变IT行业的职业景象?

随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;许多人开始担忧其对IT行业的影响&#xff0c;担心AI的出现可能会导致大量IT从业者失业。然而&#xff0c;事实并非如此简单&#xff0c;AI的崛起将为IT行业带来深刻的变革&#xff0c;既有挑战&#xff0c;也有机…

C++实现设计模式---享元模式 (Flyweight)

享元模式 (Flyweight) 享元模式 是一种结构型设计模式&#xff0c;它通过共享对象来减少内存使用和对象创建的开销。当系统中有大量相似对象时&#xff0c;享元模式可以避免重复创建相同对象&#xff0c;从而节省内存。 意图 通过共享相同对象来减少内存消耗。用于系统中存在…

排序算法(C语言版)

直接插入排序 #include<stdio.h> #include<stdlib.h> #define MAXSIZE 100 //定义顺序表结构体 typedef struct { int key;//这里可以根据实际需求添加其他数据成员 }RedType; typedef struct { RedType r[MAXSIZE 1];//r[0]闲置或用作哨兵 int length; }…

Swift语言的数据库编程

Swift语言的数据库编程 引言 在现代应用程序的开发中&#xff0c;数据的存储和管理是一个至关重要的环节。无论是移动应用、Web服务还是桌面软件&#xff0c;数据库都扮演着数据存储和检索的核心角色。随着Swift语言在iOS和macOS开发中的普及&#xff0c;越来越多的开发者开始…

mobaxterm内置编辑器中文出现乱码如何解决:直接更换编辑器为本地编辑器

诸神缄默不语-个人CSDN博文目录 使用场景是我需要用mobaxterm通过SSH的方式登录服务器&#xff0c;进入服务器之后我就直接打开代码文件&#xff0c;mobaxterm会直接用内置的编辑器&#xff08;MobaTextEditor&#xff09;打开&#xff0c;但这会导致中文编程乱码。 我一开始是…

【Mysql进阶知识】Mysql 程序的介绍、选项在命令行配置文件的使用、选项在配置文件中的语法

目录 一、程序介绍 二、mysqld--mysql服务器介绍 三、mysql - MySQL 命令行客户端 3.1 客户端介绍 3.2 mysql 客户端选项 指定选项的方式 mysql 客户端命令常用选项 在命令行中使用选项 选项(配置)文件 使用方法 选项文件位置及加载顺序 选项文件语法 使用举例&am…

Conda的一些常用命令

以下是Conda的一些常用命令&#xff1a; pip freeze > requirements.txt pip install -r requirements.txt 基本信息查看类 查看conda版本&#xff1a; conda -V 或 conda --version 可以查看当前安装的conda版本。 查看conda帮助信息&#xff1a; conda -h 或 conda --he…