设计实现QSPI Flash的下载算法

news2024/11/29 1:50:10

mm32-2nd-bootloader技术白皮书(3)——设计实现QSPI Flash的下载算法

mm32-2nd-bootloader技术白皮书(3)——设计实现QSPI Flash的下载算法 | MCU加油站

cathy的头像

cathy 发布于:周一, 03/20/2023 - 15:29 ,关键词:

  • mm32-2nd-bootloader
  • QSPI
  • Flash

相关阅读:

mm32-2nd-bootloader技术白皮书(1)——配置软硬件环境

mm32-2nd-bootloader技术白皮书(2)——QSPI外设简介

简介

前文中了解了微控制器可以使用 QSPI 接口连接 QSPI Flash,来实现扩展微控制器的 Flash 空间,存储较大 code size 的应用程序。

但通过 QSPI 接口连接的 QSPI Flash,无法直接使用已有的片内 Flash 的下载算法下载程序,例如在 MDK 平台上编译的程序,在没有下载算法的情况下,是不能直接点击 MDK 的下载按钮或调试按钮下载调试程序的,这样会对使用 QSPI Flash 存储执行程序带来很大的麻烦。

因此,本文将使用 MDK 平台,以 PLUS-F5270 开发板为例,讲解如何制作适用于 MM32F5270 系列 MCU 的 QSPI Flash 下载算法,让用户在 MDK 平台中下载应用程序就如同在片内 Flash 中那样方便。

生成下载算法文件

在 Keil-MDK 的安装目录下,包含一个下载算法的模板文件,例如:MDK 安装在 C 盘目录下,则工程模板的位置在 "C:\Keil_v5\ARM\Flash" ,模板名称为 "_Template",如图 1 所示。

1.png

图1 下载算法模板的目录与包含文件

复制整个 "_Template"文件到该目录下,并重命名为“MM32F5270_QSPI_FlashLoader”,当然也可以换成其它名字;进入该文件夹,将所有名为 "NewDevice" 的文件重命名,建议同文件夹名保持一致。

重命名文件后,打开 ".uvprojx" 后缀的工程文件,进入 MDK 工程,在 Project 栏中可以看到,除了 "Abstract.txt" 文件外,只有 "FlashPrg.c" 与 "FlashDev.c" 两个文件。

修改MDK工程选项配置

打开 Options for Target,进入 Device 页面,PLUS-F5270 使用的微控制器为 MM32F5277E9PV,在左下角的芯片选择中,选择 MindMotion -> MM32F5270 Series->MM32F5277E -> MM32F5277E9PV"。

由于 MM32F5270 系列芯片使用 STAR-MC1 内核处理器,不能使用 AC5 编译器编译代码,需选择 Target 页面,将 Code Generation 的 ARM Compiler 版本选择为 Use default compiler version 6。

选择 Output 页面,修改 Name of Executable 选项中的内容以表示设备,建议该修改名称与文件夹保持一致。修改页面如图 2 所示。

2.png

图2 MDK的工程选项配置界面

由于下载算法通常是在 Flash 目录下开发,使用下载算法时要将下载算法放到 Flash 目录下,避免调试下载算法时,来回将下载算法文件复制到前一级目录。因此,在工程选项配置中,将输出下载算法的路径配置到前一级目录下。选择 User 页面,修改 After Build/Rebuild 的Run #1为cmd.exe /C copy "Objects\%L" "..\@L.FLM",如图 3 所示。

3.png

图3 Keil-MDK的输出下载算法路径配置界面

Flash 编程算法使用 Read-Only Position Independent 与 Read-Write Position Independent。通过观察 "MM32F5270_QSPI_FlashLoader" 文件夹下的 "Target.lin" 文件可知,不管是代码还是数据,都被放入与地址无关的空间内,因此在编译时,要将代码和数据以“和地址无关”的方式编译。选择 C/C++(AC6) 页面,勾选 Read-Only Position Independent 与 Read-Write Position Independent;选择 Asm 页面,也勾选 Read-Only Position Independent 与  Read-Write Position Independent 选项,如图 4 所示。

4.png

图4 Keil-MDK的工程算法编译方式选项配置界面

此处需注意要将 C/C++(AC6) 页面下的 Warnings: 选项选为AC5-like Warnings,否则会产生路径名不同的 warning。

FlashDev.c(25): warning: non-portable path to file '"..\FlashOS.h"'; specified path differs in case from file name on disk [-Wnonportable-include-path]
#include "..\FlashOS.H"        // FlashOS Structures
         ^~~~~~~~~~~~~~
         "..\FlashOS.h"

查看整个 MM32F5270_QSPI_FlashLoader 工程文件,会发现当前工程中没有启动文件与主函数,默认只有几个功能函数,在这种情况下,编译会爆出下面的警告:

L6305W: Image does not have an entry point. (Not specified or not set due to multiple choices.)

但下载算法本身是不需要启动文件和主函数的,只在下载代码时由调试器调用下载算法,因此,需忽略该 warning。选择 Linker 界面,修改 Misc controls 中的内容为 --diag_suppress L6305 ,如图 5 所示。

5.png

图5 配置 MDK 工程禁用错误 L6305

修改FlashDev.c文件

在 MM32F5270_QSPI_FlashLoader工程文件中,FlashDev.c 文件的内容由实际所使用的 QSPI Flash 芯片决定,该文件中包含一个名为 FlashDevice 的结构体,本文以 W25Q128 芯片为例,作为与 MM32F5270 MCU 相连接的 QSPI Flash 芯片,该芯片容量为 16MB,扇区大小为 4KB,页大小为 256Byte。则结构体FlashDevice 的配置如下:

    struct FlashDevice const FlashDevice  =  {
   FLASH_DRV_VERS,              // Driver Version, do not modify!
   "MM32F5270 QSPI FlashLoader",// Device Name 
   EXTSPI,                      // Device Type
   0x90000000,                  // Device Start Address
   0x01000000,                  // Device Size in Bytes (16MB)
   256,                         // Programming Page Size
   0,                           // Reserved, must be 0
   0xFF,                        // Initial Content of Erased Memory
   100,                         // Program Page Timeout 100 mSec
   3000,                        // Erase Sector Timeout 3000 mSec

// Specify Size and Address of Sectors
   0x001000, 0x000000,          // Sector Size  4kB (1 Sectors)
   SECTOR_END
};

若使用 W25Q64 芯片,其芯片容量 8MB,Device Size in Bytes 行的值需修改为 0x00800000。

修改好后,先进行一次编译,然后在 MM32F5270 的任意工程中查看列表,以MM32F5270中的 hello_world 样例工程为例。

打开 hello_world 样例工程的 Options for Target 选项,到 Debug  页面下,打开调试器的 Settings, 到 Flash Download 页面下,进入 Add 选项,可看见列表中新增了一个名为 MM32F5270 QSPI FlashLoader 的下载算法,列表界面如图 6 所示。

6.png

图6 MDK 的下载算法添加列表

当然,这个下载算法还尚且不能使用,仍需要进行功能填充。若要让下载算法可用,首先,需要添加必要的文件,使用 MindSDK 生成任意一个 MM32F5270 的工程,提取其中的 device 目录到下载算法的目录下。

下载算法需要使用到的文件如图 7 所示:

7.png

图7 在工程中添加下载算法所需文件

添加完所需文件后,需添加头文件地址才能使用对应文件,如图 8 所示。

8.png

图8 在工程中添加头文件地址

为什么没有把所有的驱动文件都包含进去呢?这是由于 FlashLoader 需尽可能的小,如果把所有的驱动都添加进去的话,下载算法就会变得很大很大,要知道,下载算法没有启动文件和主函数,编译器不知道哪些函数没有用到,因此不会进行优化,将没有用到的函数删除。因此仅添加 GPIO,QSPI 和 RCC 三个必须使用到的驱动,如有必要,甚至可以写好下载算法后,将这三个驱动文件中没有用到的函数也进行删除。

QSPI Flash芯片的驱动开发

要想将代码下载到 QSPI Flash 中,就要根据 QSPI Flash 手册中的对应要求来操作 QSPI Flash,为此,需要为 QSPI Flash 芯片设计驱动,当然,为了减少代码量,仅实现必要的功能。

QSPI Flash 支持单线,双线和四线操作,本文为方便编程,仅描述实现单线模式的操作,且认为 QSPI Flash 没有对任何块实施写保护等操作,同时,QSPI Flash 没有进入所谓的 QPI 模式。当然,上述特殊需求也能够在 Flashloader 中实现,但本文不再详细赘述如何实现。

在 FlashPrg.c 文件中设计并添加 QspiFlash_Init()、QspiFlash_IsBusy()、QspiFlash_EnableWrite()、QspiFlash_EraseSector()、QspiFlash_WritePage() 函数作为 QSPI Flash 芯片的驱动函数。

QspiFlash_Init() 函数

设计函数QspiFlash_Init()用于初始化,该函数包括 GPIO 的初始化,QSPI 模块的初始化,QSPI 直接模式读的初始化,由于仅使用单线模式,故无需额外打开 QSPI Flash 的四线模式。以上初始化的需求如下:

  • GPIO 的初始化

    配置 GPIO 使其作为 QSPI 的信号线,供 QSPI 外设与 QSPI Flash 进行通信。

  • QSPI 模块的初始化

    使其能够与 QSPI Flash 进行通信,实现读数据和写数据的功能。

  • QSPI 直接模式读的初始化

    为了使系统能够通过访问地址的形式直接读取到 QSPI Flash 中的数据,调试器下载程序后,会通过访问地址的形式读取 QSPI Flash 中的数据,与下载的数据进行对比,实现校验功能。

需要注意的是,GPIO 要根据 QSPI 实际使用到的引脚进行配置,QSPI Flash 的初始化要根据 QSPI Flash 的数据手册进行调整,可能部分 QSPI Flash 在读写数据之前,会有一些针对 QSPI Flash 的初始化操作。

void QspiFlash_Init(void)
{
    /* enable periph clock. */
    RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOA
                        | RCC_AHB1_PERIPH_GPIOB
                        | RCC_AHB1_PERIPH_GPIOG
                        | RCC_AHB1_PERIPH_QSPI
                        , true);

    /* enable gpio. */
    GPIO_Init_Type gpio_init;
    gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
    gpio_init.Speed   = GPIO_Speed_50MHz;

    gpio_init.Pins    = GPIO_PIN_3; /* QSPI_DA1. */
    GPIO_Init(GPIOA, &gpio_init);
    GPIO_PinAFConf(GPIOA,gpio_init.Pins, GPIO_AF_10);

    gpio_init.Pins    = GPIO_PIN_3 | GPIO_PIN_10; /* QSPI_DA2 & QSPI_CS. */
    GPIO_Init(GPIOB, &gpio_init);
    GPIO_PinAFConf(GPIOB,gpio_init.Pins, GPIO_AF_10);

    gpio_init.Pins    = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8; /* QSPI_DA0, QSPI_SCK & QSPI_DA3. */
    GPIO_Init(GPIOG, &gpio_init);
    GPIO_PinAFConf(GPIOG,gpio_init.Pins, GPIO_AF_10);

    /* enable qspi. */
    QSPI_Init_Type qspi_init;
    qspi_init.SpiMode           = QSPI_SpiMode_3;
    qspi_init.SckDiv            = 8u;
    qspi_init.CsHighLevelCycles = 9u;
    qspi_init.RxSampleDelay     = 1u;

    QSPI_Init(QSPI, &qspi_init);

    /* enable qspi direct xfer mode. */
    QSPI_DirectXferConf_Type qspi_direct_conf;
    qspi_direct_conf.CmdBusWidth  = QSPI_BusWidth_1b;
    qspi_direct_conf.CmdValue     = 0x0B; /* fast read. */
    qspi_direct_conf.AddrBusWidth = QSPI_BusWidth_1b;
    qspi_direct_conf.AddrWordWidth    = QSPI_WordWidth_24b;
    qspi_direct_conf.AltBusWidth  = QSPI_BusWidth_None;
    qspi_direct_conf.DummyCycles  = 8u;
    qspi_direct_conf.DataBusWidth = QSPI_BusWidth_1b;

    QSPI_EnableDirectRead(QSPI, &qspi_direct_conf);
}

QspiFlash_IsBusy() 函数

QspiFlash_IsBusy() 函数通过读取 QSPI Flash 的寄存器值,确定 QSPI Flash 是否处于忙碌状态。在向 QSPI Flash 中写入数据之后,需要使用该函数等待 QSPI Flash 将写进去的数据完全烧写到 Flash 单元中。

判断本文使用的 QSPI Flash 是否忙碌的方法是:读取这个 QSPI Flash 寄存器 2 中的第一个比特位是否为1,若为1 则是忙碌状态。

具体的判断方法,还是需要根据使用的 QSPI Flash 手册来确定判断方法。

bool QspiFlash_IsBusy(void)
{
    QSPI_ClearStatus(QSPI, QSPI_STATUS_XFER_DONE);

    QSPI_IndirectXferConf_Type xfer_conf;
    xfer_conf.CmdBusWidth   = QSPI_BusWidth_1b;
    xfer_conf.CmdValue      = 0x05; /* get reg1 value. */
    xfer_conf.AddrBusWidth  = QSPI_BusWidth_None;
    xfer_conf.AltBusWidth   = QSPI_BusWidth_None;
    xfer_conf.DummyCycles   = 0u;
    xfer_conf.DataBusWidth  = QSPI_BusWidth_1b;
    xfer_conf.DataWordWidth = QSPI_WordWidth_8b;
    xfer_conf.DataLen       = 1;

    QSPI_SetIndirectReadConf(QSPI, &xfer_conf);

    while(0 == (QSPI_GetStatus(QSPI) & QSPI_STATUS_XFER_DONE) )
    {}

    uint32_t reg1 = QSPI_GetIndirectData(QSPI);

    if (0 == (reg1 & 0x01) )
    {
        return false;
    }
    else
    {
        return true;
    }
}

QspiFlash_EnableWrite() 函数

QspiFlash_EnableWrite() 函数主要是为了进行写使能操作,保证数据可写入。

每次进行任何写操作时,都需要执行一次写使能操作。需要注意,每一次写操作完成后,写使能就会关闭(当然,还需视具体芯片而定)。

void QspiFlash_EnableWrite(bool enable)
{
    QSPI_ClearStatus(QSPI, QSPI_STATUS_XFER_DONE);

    QSPI_IndirectXferConf_Type xfer_conf;
    xfer_conf.CmdBusWidth   = QSPI_BusWidth_1b;
    if (true == enable)
    {
        xfer_conf.CmdValue      = 0x06; /* enbale write. */
    }
    else
    {
        xfer_conf.CmdValue      = 0x04; /* disable write. */
    }
    xfer_conf.AddrBusWidth  = QSPI_BusWidth_None;
    xfer_conf.AltBusWidth   = QSPI_BusWidth_None;
    xfer_conf.DummyCycles   = 0u;
    xfer_conf.DataBusWidth  = QSPI_BusWidth_None;

    QSPI_SetIndirectWriteConf(QSPI, &xfer_conf);

    while(0 == (QSPI_GetStatus(QSPI) & QSPI_STATUS_XFER_DONE) )
    {}
}

QspiFlash_EraseSector() 函数

QspiFlash_EraseSector() 函数执行擦除扇区操作。

void QspiFlash_EraseSector(uint32_t addr)
{
    QspiFlash_EnableWrite(true);
    QSPI_ClearStatus(QSPI, QSPI_STATUS_XFER_DONE);

    QSPI_IndirectXferConf_Type xfer_conf;
    xfer_conf.CmdBusWidth   = QSPI_BusWidth_1b;
    xfer_conf.CmdValue      = 0x20; /* sector erase. */
    xfer_conf.AddrBusWidth  = QSPI_BusWidth_1b;
    xfer_conf.AddrWordWidth = QSPI_WordWidth_24b;
    xfer_conf.AddrValue     = addr & 0x00FFFFFF;
    xfer_conf.AltBusWidth   = QSPI_BusWidth_None;
    xfer_conf.DummyCycles   = 0u;
    xfer_conf.DataBusWidth  = QSPI_BusWidth_None;

    QSPI_SetIndirectWriteConf(QSPI, &xfer_conf);

    while(0 == (QSPI_GetStatus(QSPI) & QSPI_STATUS_XFER_DONE) )
    {}

    while(QspiFlash_IsBusy() ) /* wait for erase done. */
    {}

    QspiFlash_EnableWrite(false);
}

QspiFlash_WritePage() 函数

QspiFlash_WritePage() 函数用于执行写数据操作。

注意,擦数据是按块(或者叫做扇区)擦除,写操作是按页进行写,页的大小是小于块的大小的。块大小和页大小已经在前面的 FlashDev.c 中定义好了,调试下载器会按照上面定义的大小进行块擦除和页写入。

void QspiFlash_WritePage(uint32_t addr, uint32_t size, uint8_t * data)
{
    QspiFlash_EnableWrite(true);
    QSPI_ClearStatus(QSPI, QSPI_STATUS_XFER_DONE);

    QSPI_IndirectXferConf_Type xfer_conf;
    xfer_conf.CmdBusWidth   = QSPI_BusWidth_1b;
    xfer_conf.CmdValue      = 0x02; /* sector erase. */
    xfer_conf.AddrBusWidth  = QSPI_BusWidth_1b;
    xfer_conf.AddrWordWidth = QSPI_WordWidth_24b;
    xfer_conf.AddrValue     = addr & 0x00FFFFFF;
    xfer_conf.AltBusWidth   = QSPI_BusWidth_None;
    xfer_conf.DummyCycles   = 0u;
    xfer_conf.DataBusWidth  = QSPI_BusWidth_1b;
    xfer_conf.DataWordWidth = QSPI_WordWidth_8b;
    xfer_conf.DataLen       = size;

    QSPI_SetIndirectWriteConf(QSPI, &xfer_conf);

    while(0 == (QSPI_GetStatus(QSPI) & QSPI_STATUS_XFER_DONE) )
    {
        if (size > 0 && 0 != (QSPI_GetStatus(QSPI) & QSPI_STATUS_FIFO_EMPTY) )
        {
            QSPI_PutIndirectData(QSPI, *data++);
            size--;
        }
    }

    while(QspiFlash_IsBusy() ) /* wait for erase done. */
    {}

    QspiFlash_EnableWrite(false);
}

修改FlashPrg.c文件

在 MM32F5270_QSPI_FlashLoader 工程的 FlashPrg.c 文件中,根据用户手册对于 Flash 描述和 Flash 控制器的特性,适配编程算法。

使用上述QSPI Flash芯片驱动开发函数对FlashPrg.c文件中的模板函数进行填充。

Init()函数

初始化函数除了初始化 QSPI Flash 本身,还需要初始化 MCU 的时钟,使其工作在片内 RC 振荡器提供的 8M 时钟环境下。

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) 
{
    /* Switch to HSI. */
    RCC->CR |= RCC_CR_HSION_MASK; /* Make sure the HSI is enabled. */
    while ( RCC_CR_HSIRDY_MASK != (RCC->CR & RCC_CR_HSIRDY_MASK) )
    {
    }
    RCC->CFGR = RCC_CFGR_SW(0u); /* Reset other clock sources and switch to HSI. */
    while ( RCC_CFGR_SWS(0u) != (RCC->CFGR & RCC_CFGR_SWS_MASK) ) /* Wait while the SYSCLK is switch to the HSI. */
    {
    }

    /* Reset all other clock sources. */
    RCC->CR = RCC_CR_HSION_MASK;

    /* Disable all interrupts and clear pending bits. */
    RCC->CIR = RCC->CIR; /* clear flags. */
    RCC->CIR = 0u; /* disable interrupts. */

    QspiFlash_Init();
    return (0);                                  /* Finished without Errors. */
}

UnInit()函数

无需任何操作。

UnInit() 函数在下载程序的操作完成后被调用,如果 Flashloader 操作的是片内 Flash,可能会在该函数内实现一个对片内 Flash 上锁的操作,保证 Flash 中的数据不会被意外修改,而本文使用的 QSPI Flash 不需要类似的操作,因此这个函数不用做任何改动,当然,也得视具体的 QSPI Flash 而定。

EraseChip()函数

QSPI Flash 本身具有擦除整颗芯片数据的指令,但为了减少代码量,可以使用循环调用擦除扇区的方法来擦除整颗芯片的数据。

int EraseChip (void) 
{
    for (uint32_t i = 0; i < 0x01000000; i+= 0x1000)
    {
        QspiFlash_EraseSector(i);
    }
    return (0);                                  /* Finished without Errors. */
}

EraseSector() 函数

此函数的目的是擦除扇区。

需要注意的是,Flash_EraseSector() 需要传入的参数是 QSPI Flash 芯片内的地址,而不是在 MCU 上映射的地址,因此需要使用 0x00FFFFFF 掩码取有效地址。

int EraseSector (unsigned long adr) 
{
    QspiFlash_EraseSector(adr & 0x00FFFFFF);
    return (0);                                  /* Finished without Errors. */
}

ProgramPage()函数

此函数的目的是将程序写入 Flash 中。

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) 
{
    QspiFlash_WritePage(adr,sz,buf);
    return (0);                                /* Finished without Errors. */
}

总结

完成上述下载算法所需的函数后,下载算法也就制作完成了。使用这个下载算法,就可以实现下载程序到 QSPI Flash 的操作,但本文还没有讲该怎么实现这个可以存储在 QSPI Flash 中的应用程序,也没有讲解该怎么执行这个程序,所以暂时还没有办法验证这个下载算法是否可用,不过后续也将会讲解如何跳转执行存储在 QSPI Flash 中的应用程序,和如何让应用程序能够存储在 QSPI Flash 中。

来源:灵动MM32MCU

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/975641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

变压器智能在线监测

变压器智能在线监测是一种先进的变压器状态监测方式&#xff0c;采用了先进的技术手段&#xff0c;能够对变压器运行状态进行实时、在线、自动的监测和分析。可以在变压器运行过程中&#xff0c;对其电压、电流、温度、局放等参数进行实时监测&#xff0c;及时发现异常情况并进…

为何跨境界如此看重黑色星期五?这一点是关键

黑色星期五通常会利用折扣和独一无二的优惠为电子商务商店带来大量新客户。黑色星期五可能会给您的在线商店带来丰厚的利润&#xff0c;如果无法留住这些客户&#xff0c;您就会损失巨大。通过对电子商务客户服务策略进行一些调整&#xff0c;您可以将这些黑色星期五客户转变为…

2023最新多功能XL软件库APP源码+PHP后端系统源码/功能强大/软件库自带后台管理系统

2023最新多功能XL软件库APP源码PHP后端系统源码/功能强大/软件库自带后台管理系统31xl软件库最新可以正常使用版: https://url11.ctfile.com/d/25976711-57801726-b66bb0?p6724 &#xff08;访问密码&#xff1a;6724&#xff09; 多功能软件库&#xff0c;支持自定义对接易支…

LiveGBS流媒体平台GB/T28181功能-支持数据库切换为高斯数据库信创瀚高数据信创数据库

LiveGBS流媒体平台GB/T28181功能-支持数据库切换为高斯数据库信创瀚高数据信创数据库 1、如何配置切换高斯数据库&#xff1f;2、如何配置切换信创瀚高数据库&#xff1f;3、搭建GB28181视频直播平台 1、如何配置切换高斯数据库&#xff1f; livecms.ini -> [db]下面添加配…

JavaScript - 好玩的打字动画

效果预览&#xff1a; &#x1f680;HTML版本 <!DOCTYPE html> <html> <head><title>打字动画示例</title><style>.typewriter {color: #000;overflow: hidden; /* 隐藏溢出的文本 */white-space: nowrap; /* 不换行 */border-right: .…

macOS通过钥匙串访问找回WiFi密码的详细教程

如果您忘记了Mac电脑上的WiFi密码&#xff0c;可以通过钥匙串访问来找回它。具体步骤如下&#xff1a; 1.打开Mac电脑的“启动台”&#xff0c;然后在其他文件中找到“钥匙串访问”。 2.运行“钥匙串访问”应用程序&#xff0c;点击左侧的“系统”&#xff0c;然后在右侧找到…

FT232RL国产替代芯片GP232RL无需软硬件修改资料

GP232RL是最新加入 ftdi 系列 usb 接口集成电路设备的设备。 GP232RL是一个 usb 到串行 uart 接口&#xff0c;带有可选的时钟发生器输出&#xff0c;以及新的 ftdichip-idTM 安全加密器特性。此外&#xff0c;还提供了异步和同步位崩接口模式。 通过将外部 eeprom、时钟电路和…

Android Studio更新新版本后无法创建flutter项目

最新更新了AndroidStudio版本&#xff0c;发现无法创建flutter项目。 dart和flutter插件确认都已安装&#xff0c;该有的环境配置都已配置。 最后与同事的插件作比较发现是Android APK Support这个插件没勾选。 勾选后&#xff0c;点击右下角的apply&#xff0c;重启AndroidS…

vue+elementUI el-select 自定义搜索逻辑(filter-method)

下拉列表的默认搜索是搜索label显示label,我司要求输入id显示label名称 <el-form-item label"部门&#xff1a;"><el-select v-model"form.region1" placeholder"请选择部门" filterable clearable:filter-method"dataFilter&qu…

手写apply方法

<script>/** 手写apply方法 * */Function.prototype.myApply function (context, args) {console.log(this, sss)//fnconst key Symbol()context[key] thiscontext[key](...args)delete context[key]return context[key]}const obj {name: zs,age: 18}function fn …

保姆级 C++ 学习路线

上周有小伙伴留言求安排一手C/C学习路线&#xff0c;这周一份保姆级的C语言安排上&#xff01; 以前就写过C语言的学习路线&#xff1a;可能是北半球最好的零基础C语言学习路线&#xff0c;这次把C的学习路线也安排上&#xff0c;专门花了一个多月写了这篇学习路线&#xff0c;…

风控引擎如何快速添加模型,并实时了解运行状态?

目录 风控模型的主要类型 风控引擎如何管理模型&#xff1f; 模型就是基于目标群体的大规模采样数据&#xff0c;挖掘出某个实际问题或客观事物的现象本质及运行规律&#xff0c;利用抽象的概念分析存在问题或风险&#xff0c;计算推演出减轻、防范问题或风险的对策过程&…

【MySql】数据库的CRUD(增删查改)

写在最前面的话 哈喽&#xff0c;宝子们&#xff0c;今天给大家带来的是MySql数据库的CRUD&#xff08;增删改查&#xff09;&#xff0c;CRUD是数据库非常基础的部分&#xff0c;也是后端开发日常工作中最主要的一项工作&#xff0c;接下来让我们一起进入学习吧&#xff0c;感…

如何指定this

<script>/*如何指定this的值可以通过2类方法指定1.调用时指定1.1call方法1.2apply方法2.创建时指定2.1bind方法2.2箭头函数*/// ------1.调用时指定------//1.1call方法:挨个传入参数//1.2apply方法:数组形式传入参数function foo (numA, numB) {console.log(this)consol…

10个最强大的AI驱动的3D建模工具【生成式AI】

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 在快速发展的技术世界中&#xff0c;人工智能 (AI) 已经改变了游戏规则&#xff0c;尤其是在 3D 对象生成领域。 AI 驱动的 3D 对象生成器彻底改变了我们创建和可视化 3D 模型的方式&#xff0c;使该过程更加高效、准确且可…

【LarkDay】UE开发者沙龙活动回顾

文章目录 1、相关咨询2、录播链接3、演讲内容 1、相关咨询 「Paraverse平行云」邀您线上参与LarkDay UE 开发者沙龙 UE超硬核实战攻略&#xff5c;LarkDay UE开发者沙龙回顾&#xff08;文末有福利&#xff09; LarkDay UE 开发者沙龙问卷报告与获奖名单 2、录播链接 【Bil…

每日一题 501二叉搜素树中的众数(中序遍历)

题目 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 BST 满足如下定义&a…

固定资产卡片乱怎么管理

固定资产卡片是记录公司固定资产信息的重要工具&#xff0c;如果管理不善&#xff0c;容易造成卡片混乱、数据错误等问题。 为了避免这种情况的发生&#xff0c;可以采取以下措施&#xff1a;  建立完善的资产管理制度&#xff0c;明确固定资产的分类、标准和使用情况&#x…

【vue】vuex持久化插件vuex-persistedstate:

文章目录 一、说明&#xff1a;二、手动利用HTML5的本地存储&#xff1a;三、利用vuex-persistedstate插件【1】安装【2】配置使用【3】存储sessionStorage的情况【4】存储cookie的情况【5】默认持久化所有state&#xff0c;指定需要持久化的state,配置如下【6】vuex引用多个插…

荣耀开发者沙龙 · 北京站 活动精彩回顾

聚梦想&#xff0c;创非凡&#xff0c;荣耀云业务开发者沙龙北京站顺利落幕。来自全国各地的开发者伙伴齐聚北京&#xff0c;共同探讨在应用分发、服务分发、内容分发上的新可能&#xff0c;探索云业务基础能力和荣耀MagicOS的奥秘&#xff0c;解码商业推广平台的增长潜力&…