i.MX6裸机开发(9):CCM时钟控制模块

news2024/11/16 3:38:13

本章参考资料:《IMX6ULRM》(参考手册)。

学习本章时,配合《IMX6ULRM》第18章Clock Controller Module (CCM),效果会更佳,特别是涉及到寄存器说明的部分。

本章我们主要讲解时钟部分,芯片内部的各个设备都在时钟的驱动下运行,了解整个芯片的时钟树、时钟配置,那么对i.MX 6U的一切时钟的来龙去脉都会了如指掌。

1. 时钟控制模块(CCM)的主要作用

i.MX 6U的时钟系统由时钟控制模块CCM进行控制,其主要功能如下:

  • 使用PLL锁相环电路将参考时钟倍频,得到频率更高的时钟。为芯片内核和外设提供可选的时钟源。i.MX 6U共有7个PLL锁相环电路,分别为:

    ARM PLL(PLL 1)、System PLL(PLL 2)、USB1 PLL(PLL 3)、Audio PLL(PLL 4)、Video PLL(PLL5)ENET PLL(PLL 6)、USB2 PLL(PLL 7)。

  • 提供PLL控制寄存器、时钟选择寄存器、时钟分频寄存器。灵活控制输出到外设和内核的时钟频率。

  • 控制低功耗机构。

时钟控制模块

CCM_CLK_IGNITION模块

管理从外部晶振时钟到稳定的根时钟输出的整个过程。CCM完成重置之后CCM_CLK_IGNITION模块立即启动。 GPC是General Power Controller的缩写,即总电源管理模块,它不属于CCM,系统电压与时钟关系密切, 简单来说,系统电压影响系统最高的时钟频率,CCM又可以控制总电源管理模块(GPC)进入待机或低功耗状态。 相关内容将会在GPC章节详细介绍。

PLL时钟产生

CCM_ANALOG为CCM的模拟部分,作用是将频率较低的参考时钟(例如24MHz的XTALOSC时钟)使用PLL锁相环电路倍频到更高的时钟。 CCM_CLK_SWITCHER模块接收来自CCM_ANALOG模块的锁相环时钟输输出,以及锁相环的旁路时钟, 并为CCM_CLK_ROOT_GEN子模块生成切换时钟输出(pll3_sw_clk)。i.MX 6U共有7个PLL锁相环电路,可以独立配置。 其中PLL2与PLL3结合PFD能够输出多个频率可调的时钟。

根时钟生成

CCM_CLK_ROOT_GEN接收来自CCM_CLK_SWITCHER模块的PLL或PFD时钟,经过时钟的选择、分频等操作之后产生并输出根时钟。根时钟将会作内核或外设的时钟源。

时钟同步

当更改某些时钟的时钟源时需要进行时钟的同步CCM_HND_SK模块用于管理时钟握手,即时钟的同步。

低功耗管理与时钟启用模块

CCM_LPM用于管理低功耗模式,管理时钟的开启与关闭。CCM_CLK_LOGIC,根据来自CCM_LPM模块和CCM_IP的信号产生时钟启用或关闭信号。

低功耗时钟门控模块(LPCG)

低功耗时钟门控模块(LPCG)根据CCM_CLK_LOGIC模块输出信号控制时钟输出。时钟越多、频率越高功耗也就越高。关闭没有使用的时钟或降低时钟频率能够有效的降低功耗。

2. 时钟树简介

i.MX 6U芯片时钟的结构以时钟树的方式进行描述。当我们设置外设时钟时大多会参考时钟树进行设置, 本章配套程序将以ARM_CLK_ROOT(CPU根时钟)为例讲解时钟的配置方法。

时钟树

时钟树

2.1. PLL与PFD时钟产生

i.MX 6U外部连接了两个晶振,分别用于提供32.768KHz和24MHz时钟。其中32.768KHz晶振称为外部低速时钟(CKIL), 当芯片上电后要保持该时钟一直处于运行状态,为需要的外设提供时钟。24Mhz晶振产生的时钟称为外部高速时钟(CKIH)。芯片利用内部振荡器产生基准时钟(OSC),内部振荡器产生基准时钟(OSC)基于外部高速时钟(CKIH),产生24MHz的参考时钟, 24MHz参考时钟常用作PLL锁相环电路的输入时钟。

下面以ARM PLL(PLL 1)为例讲解从24MHz参考时钟到ARM PLL(PLL 1)时钟的过程,如下所示。

24MHz参考时钟到ARM PLL(PLL 1)时钟

ARM PLL(PLL 1)只有一个控制寄存器CCM_ANALOG_PLL_ARMn,CCM_ANALOG_PLL_ARMn[BYPASS_CLK_SRC]用于选择输入钟源(Fin), 一般我们使用24MHz参考时钟,当然也可以选择外部引脚输入引脚(CLK1_N /CLK1_P)输入的外部时钟。CCM_ANALOG_PLL_ARMn[DIV_SELECT]位选择锁相环分频值(DIV_SELECT)。 取值范围为54到108。输出频率计算公式为 ARM_PLL = Fin * DIV_SELECT/2.0。如果选择24MHz参考时钟作为时钟输入,DIV_SELECT选择88则ARM PLL的输出频率为1056MHz。 CCM_ANALOG_PLL_ARMn[ENABLE]用于配置是否使能ARM PLL输出,如果要使用ARM PLL就需要将该位设置为1。

从上图中可以看出,PLL2与PLL3下方各有一组PFD。PFD是Phase Fractional Dividers的缩写,我们这里翻译为分数分频。 PFD的频率由PLL2或PLL3输出频率分频产生。我们以PLL2产生PFD0~PFD3讲解PFD的产生过程,如下所示。

PFD产生过程

寄存器CCM_ANALOG_PFD_528n用于控制PFD0~PFD3的输出频率。以PFD0为例,CCM_ANALOG_PFD_528n[PFD0_FRAC]用于设置分频值, 取值范围为12到35,PFD0的输出频率计算公式为:PFD0_out =528*18/ PFD0_FRAC如果PFD0_FRAC = 27,PFD0的输出频率为352MHz。 CCM_ANALOG_PFD_528n[PFD0_CLKGATE]门控寄存器,用于设置是否使能PFD0的输出。PLL输出时钟和PFD输出时钟经选择和分频后将作为内核或外设的根时钟。

2.2. 根时钟生成模块CLOCK ROOT GEN

根时钟生成模块主要完成两个工作,第一选择时钟,第二设置时钟分频。

时钟选择器(CLOCK SWITCHER)输出了多个频率不同的PLL时钟和PFD时钟。每个外设时钟通过MUX模块连接到多个PLL时钟输出, 每个MUX实际是一个寄存器,用于选择时钟源。时钟分频也是一个寄存器位。总之就是通过配置对应的寄存器为外设选择时钟源并设置时钟频率。 具体是那些寄存器?在图中标记的很清楚,根据图中标注可以很容易、灵活的配置时钟。

下面以“ARM_CLK_ROOT”时钟为例讲解,时钟配置步骤。“ARM_CLK_ROOT”时钟是CPU时钟,也就是我们常说的主频。 修改该时钟之前首先要将CPU时钟切换到另外一个可用的时钟,修改完成后再切换回来。 具体下所示。(图片太大,图片中的字看不清楚,请查阅《IMX6ULRM》18.5.1 Clock Generation P631页)

CPU时钟切换

上图中,标号①与标号②处是CCSR时钟选择寄存器的两个配置位,用于设置时钟源。这里假设要将CPU时钟修改为792MHz。 步骤如下:(具体代码在讲解代码时会介绍)

  1. 配置CCSR寄存器,将 “ARM_CLK_ROOT”时钟切换到osc_clk(24MHz)

CCSR寄存器如下所示:

CCSR寄存器

这里共用到了CCSR寄存器的两个控制位,

第一处CCSR[STEP_SEL] 对应图标号①处,设置CCSR[STEP_SEL] = 0,表示选择24MHz的osc_clk时钟,osc_clk时钟是固定的,默认我们选择这个时钟。CCSR[STEP_SEL] =1,表示选择secondary_clk时钟,这个时钟暂时用不到,不用关心。 第二处CCSR[PLL1_SW_CLK_SEL]对应图标号②处,设置CCSR[PLL1_SW_CLK_SEL] = 0,表示选择pll1_main_clk时钟。CCSR[PLL1_SW_CLK_SEL] =1,表示选择step_clk时钟。

我们设置CCSR[STEP_SEL] = 0、CCSR[PLL1_SW_CLK_SEL] = 1,这样CPU时钟源被切换到了24MHz的osc_clk时钟,下一步就可以修改PLL1的输出时钟。

  1. 修改PLL1输出时钟。PLL1输出时钟设置方法已经在55.3 时钟树简介,第一小节介绍,这里不再赘述。

  2. 设置CCSR[PLL1_SW_CLK_SEL] = 1,将CPU时钟切换到pll1_main_clk即PLL1输出时钟。

  3. 修改时钟分频。如下所示。

修改时钟分频。如下所示。

从上8可以看出,从PLL1到“ARM_CLK_ROOT”还要经过CACRR[ARM_PODF] 时钟分频寄存器。 进过上一步PLL1的输出时钟被设置为792MHz,所以这里设置CACRR[ARM_PODF] = 0,不分频。

3. 设置系统时钟实验

系统时钟设置实验代码由“interrupt_init”代码修改得到,本章也只讲解新增部分代码,完整请参考本章配套源码。

本章的示例代码目录为:bare_metal/clock_init

野火裸机下载工具download_tool路径为:bare_metal/download-tool/download-tool.tar.bz2

3.1. 实验说明

3.1.1. 硬件介绍

本实验只用RGB灯显示大致显示CPU运行速度,没有用到其他外部电路。

3.1.2. 原理图分析
  • RGB灯原理图请参考 第四章节汇编点亮LED灯 章节。

3.2. 实验代码讲解

3.2.1. 编程思路

拷贝“bare_metal/interrupt_init”程序,并重命名为“bare_metal/clock_init”。 分别在“bare_metal/clock_init/device”、“bare_metal/clock_init/include”文件夹下添加clock.c、clock.h。 添加了新的源文件,当然要将其添加到makefile 中。

打开“bare_metal/clock_init/device”目录下的“makefile”文件,将clock.o添加到最终目标的依赖中,代码如下所示。

all : button.o  led.o system_MCIMX6Y2.o clock.o
   arm-none-eabi-ld -r $^  -o device.o

 

3.2.2. 代码分析
3.2.2.1. 添加时钟初始化代码

时钟初始化代码主要实现更改CPU时钟、设置PLL2、PLL3的输出时钟以及对应的PFD时钟。如下所示。

/********************第一部分***********************/
/* 外部 XTAL (OSC) 时钟频率 */
uint32_t g_xtalFreq = 24000000;
/*外部 RTC XTAL 时钟频率 */
uint32_t g_rtcXtalFreq = 32768;

void system_clock_init(void)
{
   /********************第二部分***********************/
   /******************* PLL 输出时钟设置************************/
   if ((CCM->CCSR & (0x01 << 2)) == 0) //CPU 使用的是 ARM PLL
   {
      /*将CPU时钟切换到XTAL (OSC) 时钟*/
      CCM->CCSR &= ~(0x01 << 8); //控制CCSR: step_sel ,选择 osc_clk 作为时钟源
      CCM->CCSR |= (0x01 << 2); //设置GLITCHLESS MUX 选择 step_clk 作为时钟源
   }

   /********************第三部分***********************/
   /*设置PLL1输出时钟为792MHz,它将作为CPU时钟*/
   CCM_ANALOG->PLL_ARM |= (0x42 << 0);

   /*将CPU 时钟重新切换到 ARM PLL*/
   CCM->CCSR &= ~(0x01 << 2);
   /*设置时钟分频系数为0,即不分频*/
   CCM->CACRR &= ~(0x07 << 0); //清零分频寄存器   30秒大约闪烁45次
   // CCM->CACRR |= (0x07 << 0); //清零分频寄存器 30秒大约闪烁20次

   /********************第四部分***********************/
   /*设置PLL2(System PLL) 输出时钟*/
   /* Configure SYS PLL to 528M */
   CCM_ANALOG->PLL_SYS_SS &= ~(0x8000);     //使能PLL2 PFD输出
   CCM_ANALOG->PLL_SYS_NUM &= ~(0x3FFFFFFF);//设置分频系数为0,即不分频。
   CCM_ANALOG->PLL_SYS |= (0x2000); //使能PLL2 输出
   CCM_ANALOG->PLL_SYS |= (1 << 0); //设置输出频率为528M
   while ((CCM_ANALOG->PLL_SYS & (0x80000000)) == 0) //等待设置生效
   {
   }

   /*设置PLL3(System PLL) 输出时钟*/
   /* Configure USB PLL to 480M */
   CCM_ANALOG->PLL_USB1 |= (0x2000);    //使能 PLL3时钟输出
   CCM_ANALOG->PLL_USB1 |= (0x1000);    //PLL3上电使能
   CCM_ANALOG->PLL_USB1 |= (0x40);      // 使能USBPHYn
   CCM_ANALOG->PLL_USB1 &= ~(0x01 << 0);//设置输出频率为480MHz
   while ((CCM_ANALOG->PLL_SYS & (0x80000000)) == 0)//等待设置生效
   {
   }

   /*关闭暂时不使用的 PLL4 、PLL5  、PLL6 、PLL7*/
   CCM_ANALOG->PLL_AUDIO = (0x1000);    //关闭PLL4
   CCM_ANALOG->PLL_VIDEO = (0x1000);    //关闭PLL5
   CCM_ANALOG->PLL_ENET =  (0x1000);    //关闭PLL6
   CCM_ANALOG->PLL_USB2 =  (0x00);           //关闭PLL7

   /********************第五部分***********************/
   /******************PFD 输出时钟设置*******************/
   /*禁用PLL2 的所有PFD输出*/
   CCM_ANALOG->PFD_528 |=(0x80U) ;      //关闭PLL2 PFD0
   CCM_ANALOG->PFD_528 |=(0x8000U) ;    //关闭PLL2 PFD1
   // CCM_ANALOG->PFD_528 |=(0x800000U) ;  //关闭PLL2 PFD2 ,
                           DDR使用的是该时钟源,关闭后程序不能运行。暂时不关闭
   CCM_ANALOG->PFD_528 |=(0x80000000U); //关闭PLL2 PFD3

   /*设置PLL2 的PFD输出频率*/
   CCM_ANALOG->PFD_528 &= ~(0x3FU); //清零PLL2 PFD0 时钟分频
   CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD1 时钟分频
   CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD2 时钟分频
   CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD3 时钟分频

   CCM_ANALOG->PFD_528 |= (0x1B << 0); //设置PLL2 PFD0 输出频率为 352M
   CCM_ANALOG->PFD_528 |= (0x10 << 8); //设置PLL2 PFD0 输出频率为 594M
   CCM_ANALOG->PFD_528 |= (0x18 << 16); //设置PLL2 PFD0 输出频率为 396M
   CCM_ANALOG->PFD_528 |= (0x30 << 24); //设置PLL2 PFD0 输出频率为 198M

   /*启用PLL2 的所有PFD输出*/
   CCM_ANALOG->PFD_528 &= ~(0x80U) ;      //开启PLL2 PFD0
   CCM_ANALOG->PFD_528 &= ~(0x8000U) ;    //开启PLL2 PFD1
   CCM_ANALOG->PFD_528 &= ~(0x800000U) ;  //开启PLL2 PFD2
   CCM_ANALOG->PFD_528 &= ~(0x80000000U); //开启PLL2 PFD3

   /********************第六部分***********************/
   /*禁用PLL3 的所有PFD输出*/
   CCM_ANALOG->PFD_480 |=(0x80U) ;      //关闭PLL3 PFD0
   CCM_ANALOG->PFD_480 |=(0x8000U) ;    //关闭PLL3 PFD1
   CCM_ANALOG->PFD_480 |=(0x800000U) ;  //关闭PLL3 PFD2
   CCM_ANALOG->PFD_480 |=(0x80000000U); //关闭PLL3 PFD3

   /*设置PLL3 的PFD输出频率*/
   CCM_ANALOG->PFD_480 &= ~(0x3FU);   //清零PLL3 PFD0 时钟分频
   CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD1 时钟分频
   CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD2 时钟分频
   CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD3 时钟分频

   CCM_ANALOG->PFD_480 |= (0xC << 0); //设置PLL3 PFD0 输出频率为 720M
   CCM_ANALOG->PFD_480 |= (0x10 << 8); //设置PLL3 PFD0 输出频率为 540M
   CCM_ANALOG->PFD_480 |= (0x11 << 16); //设置PLL3 PFD0 输出频率为 508.2M
   CCM_ANALOG->PFD_480 |= (0x13 << 24); //设置PLL3 PFD0 输出频率为 454.7M

   /*启用PLL3 的所有PFD输出*/
   CCM_ANALOG->PFD_480 &= ~(0x80U) ;      //开启PLL3 PFD0
   CCM_ANALOG->PFD_480 &= ~(0x8000U) ;    //开启PLL3 PFD1
   CCM_ANALOG->PFD_480 &= ~(0x800000U) ;  //开启PLL3 PFD2
   CCM_ANALOG->PFD_480 &= ~(0x80000000U); //开启PLL3 PFD3

   /********************第七部分***********************/
   /******************常用外设根时钟设置****************/
   CCM->CSCDR1 &= ~(0x01 << 6); //设置UART选择 PLL3 / 6 = 80MHz
   CCM->CSCDR1 &= ~(0x3F);     //清零
   /*设置串口根时钟分频值为1,UART根时钟频率为:80M / (dev + 1) = 40MHz*/
   CCM->CSCDR1 |= (0x01 << 0); //
}

代码很长,但很简单,只修改了几个时钟配置寄存。结合代码各部分讲解如下。

  • 第一部分,定义变量g_xtalFreq 、g_rtcXtalFreq分别保存XTAL (OSC)时钟 、RTC XTAL时钟。这两个时钟频率后面章节会用到。

  • 第二部分和第三部分。设置CPU时钟频率。这部分内容对应时钟树简介章节第二部分。简单说明如下:第二部分代码首先判断当CPU时钟是否使用pll1_main_clk,如果是,则将其切换到osc_clk时钟。第三部分,修改PLL1输出频率,并将CPU时钟源切换到pll1_main_clk。

  • 第四部分,设置PLL2~PLL7的输出频率。其中PLL2的时钟被设置为528M并开启了PFD输出功能。PLL3的时钟被设置为480M并开启了PFD输出功能。PLL4~PLL7我们暂时用不到,直接关闭时钟输出。关闭不使用的时钟能够有效的减少功耗。

  • 第五部分,设置PLL2的PFD输出。PLL2共有4个PFD输出(PFD0~PFD3),PLL2的PFD设置通过CCM_ANALOG_PFD_528n寄存器实现,如下所示。

CCM_ANALOG_PFD_528n寄存器实现

这里不再介绍CCM_ANALOG_PFD_528寄存器的各个位的作用,结合代码或者参考《IMX6ULRM》手册Chapter 18 Clock Controller Module (CCM)寄存器介 绍部分很容易知道各个位的作用。初学者不必纠结每个控制位的作用,只需要知道这个寄存器有设置PLL2的FPD输出功能即可。具体使用到时查手册即可。

PLL2的PFD输出大致分为三部分,第一,禁用PLL2的PFD输出。第二,设置PFD的输出频率。第三 ,启用PFD输出。特别注意的是这里没有禁用PFD2,因为这 是DDR的时钟源。关闭后程序无法运行。

  • 第六部分,设置PLL3的PFD输出,设置方法与设置PLL2的PFD输出完全相同,只是这里设置的是CCM_ANALOG_PFD_480时钟。

  • 第七部分,设置串口的根时钟。这里只设置了串口,其他外设的时钟频率呢?在BOOT ROM中已经初始化了部分外设的时钟,为减少难度,那些没有使用到的外设或者对频率没有严格要求的外设我们暂时保持默认的时钟频率。这里设置UART根时钟的目的是以UART为例讲解如何设置外设时钟。UART时钟源产生路径如下所示。

UART时钟源产生路径

从图中可以看出,从PLL时钟到UART时钟共用用到了两个时钟选择寄存器(标号①和③),两个时钟分频寄存器(标号②和标号④)。 我们最终目的是将PLL3时钟作为UART根时钟(UART_CLK_ROOT)的根时钟。按照标号顺序讲解如下:

(1) 标号①选择PLL3时钟还是CCM_PLL3_BYP。我们选择PLL3输出时钟,寄存器CCSR[PLL3_SW_CLK_SEL] = 0, 则表示选择PLL3时钟。默认情况下是这样设置的。所以我们代码中并没有设置该寄存器。

(2) 标号②设置时钟分频,根据之前的设置,PLL3的输出频率为480MHz ,这里的时钟分频是固定的6分频, 经过分频后的时钟为 480MHz / 6 = 80MHz。

(3) 标号③ 再次选择时钟源。一个是PLL3分频得到的80MH时钟,另外一个是OSC时钟即24MHz的系统参考时钟。 设置 CSCDR1[UART_CLK_SEL] = 0,选择第一个(80MHz)时钟。

(4) 标号④再次进行时钟分频。这是一个6位的时钟分频寄存器。分频值为CSCDR1[UART_CLK_PODF]寄存器值加一。 程序中将其设置为1,则分频系数为2,UART_CLK_ROOT时钟频率实际为80MHz / 2 = 40MHz 。

3.2.2.2. 添加简易测试代码

由于程序中只有按键和RGB灯,所以我们暂时使用RGB灯闪烁频率大致判断程序运行速度。测试代码如下所示。

/*简单延时函数*/
void delay(uint32_t count)
{
   volatile uint32_t i = 0;
   for (i = 0; i < count; ++i)
   {
      __asm("NOP"); /* 调用nop空指令 */
   }
}


int main()
{
   system_clock_init();  //初始化系统时钟
   rgb_led_init();       //初始化 RGB 灯,初始化后 默认所有灯都不亮。

   while (1)
   {
      red_led_off;
      green_led_on;
      delay(0xFFFFF);

      green_led_off;
      red_led_on;
      delay(0xFFFFF);
   }
   return 0;
}

测试代码很简单,编写一个简易延时函数。在while(1)中控制RGB闪烁。我们可以修改CPU时钟分频,如下所示。

void system_clock_init(void)
{
   /******************* PLL 输出时钟设置************************/
   if ((CCM->CCSR & (0x01 << 2)) == 0) //CPU 使用的是 ARM PLL
   {
      /*将CPU时钟切换到XTAL (OSC) 时钟*/
      CCM->CCSR &= ~(0x01 << 8); //控制CCSR: step_sel ,选择 osc_clk 作为时钟源
      CCM->CCSR |= (0x01 << 2);  //设置GLITCHLESS MUX 选择 step_clk 作为时钟源
   }

   /*设置PLL1输出时钟为792MHz,它将作为CPU时钟*/
   CCM_ANALOG->PLL_ARM |= (0x42 << 0);

   /*将CPU 时钟重新切换到 ARM PLL*/
   CCM->CCSR &= ~(0x01 << 2);

   /*设置时钟分频系数为0,即不分频*/
   CCM->CACRR &= ~(0x07 << 0); //清零分频寄存器   不分频
   //CCM->CACRR |= (0x07 << 0);     // 8分频

   ...
}

通过修改时钟分频寄存器修改CPU时钟频率。我们可以对比不分频和8分频的实验效果。

3.3. 实验准备

3.3.1. 编译程序

程序编写完成后,在“clock_init” 文件夹下执行make命令,makefile工具便会自动完成程序的编译、链接、格式转换等工作。 正常情况下我们可以在当前目录看到生成的一些中间文件以及我们期待的.bin文件。

3.3.2. 烧录程序

在编译下载官方SDK程序到开发板章节我们详细讲解了如何将二进制文件烧写到SD卡(烧写工具自动实现为二进制文件添加头)。这里再次说明下载步骤。

  • 将一张空SD卡(烧写一定会破坏SD卡中原有数据!!!烧写前请保存好SD卡中的数据),接入电脑后在虚拟机的右下角状态栏找到对应的SD卡。将其链接到虚拟机。

  • 进入烧写工具目录,执行 ./mkimage.sh <烧写文件路径> 命令,例如要 烧写的led.bin位于home目录下,则烧写命令为 ./mkimage.sh /home/led.bin 。

  • 执行上一步后会列出linux下可烧写的磁盘,选择你插入的SD卡即可。这一步非常危险!!!一定要确定选择的是你插入的SD卡!!,如果选错很可能破坏你电脑 磁盘内容,造成数据损坏!!!。确定磁盘后SD卡以”sd”开头,选择”sd”后面的字符即可。例如要烧写的sd卡是”sdb”则输入”b”即可。

3.4. 程序运行结果

烧写完成,首先将开发板启动方式设置为SD卡启动,将SD卡插入开发板卡槽。 接通电源正常可以看到RGB灯闪烁,修改CPU时钟再次下载可以看到RGB灯闪烁频率加快。

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

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

相关文章

TensorFlow实现Softmax回归

原理 模型 相比线性回归&#xff0c;Softmax只多一个分类的操作&#xff0c;即预测结果由连续值变为离散值&#xff0c;为了实现这样的结果&#xff0c;我们可以使最后一层具有多个神经元&#xff0c;而输入不变&#xff0c;其结构如图所示&#xff1a; 为了实现分类&#xf…

AI编程简介

文章目录 AI 编程的特点常见编程工具copilot的工作原理AI编程常用技巧 AI 编程的特点 AI 编程是指利用人工智能技术来辅助开发过程的一种编程方式。包括但不限于&#xff1a;代码生成、优化、调试、审查&#xff0c;文档生成、测试自动化。 编程能力是大模型各项能力的天花板&…

可用于便携音箱的18V同步升压变换器TPS61288

在音频市场中,便携式音箱因其自带电源、方便携带深受消费者喜爱。便携式音箱通常配备2节可充电锂离子电池,当输出功率要求高于10W时,电池电压不足以为音频功放提供足够的功率,一般需要升压电路将电池电压升压至12V~18V以满足功率要求。 TPS61288是德州仪器公司推出的一款最…

力扣2025.分割数组的最多方案数

力扣2025.分割数组的最多方案数 哈希表 前缀和 用两个哈希表分别存元素(之后会遍历)左侧和右侧的前缀和 typedef long long LL;class Solution {public:int waysToPartition(vector<int>& nums, int k) {int n nums.size(),ans 0;vector<LL> sum(n);unor…

【Redis】Redis编程技巧

Redis编程技巧 一、StringVeiw是什么&#xff1f;二、OptionalString是什么&#xff1f;三、怎么看keys *1、vector配合back_inserter2、set配合inserter 四、chrono_literals技巧 一、StringVeiw是什么&#xff1f; 是一种轻量级的字符串视图类型&#xff0c;通常提供的是一种…

Mora:多智能体框架实现通用视频生成

人工智能咨询培训老师叶梓 转载标明出处 尽管已有一些模型能够生成视频&#xff0c;但大多数模型在生成超过10秒的长视频方面存在局限。Sora模型的出现标志着视频生成能力的一个新时代&#xff0c;它不仅能够根据文本提示生成长达一分钟的详细视频&#xff0c;而且在编辑、连接…

026集—CAD中多段线批量增加折点(相交点)——vba代码实现

当需要批量在多段线中加入顶点&#xff08;与多段线相交的点&#xff09;时&#xff0c;如下图所示&#xff1a;若干条线相交&#xff1a; 我们想在相交处增加折点&#xff0c;可通过vba插件一键完成。 &#xff08;使用方法命令行输入&#xff1a;vbaman,加载插件&#xff0c…

一本读懂数据库发展史的书

数据库及其存储技术&#xff0c;一直以来都是基础软件的主力。数据库系统的操作接口标准&#xff0c;也是应用型软件的重要接口&#xff0c;关系重大。 作为最“有感”的系统软件&#xff0c;数据库的历史悠久、品类繁多、创新活跃。 对数据库历史发展的介绍&#xff0c;有利…

JavaEE(1):web后端开发环境搭建和创建一个Servlet项目

web后端(javaEE)程序需要运行在服务器的&#xff0c;这样前端才可以访问得到 web后端开发&#xff1a; 服务器&#xff1f; 解释1&#xff1a;服务器就是一款软件&#xff0c;可以向其发送请求&#xff0c;服务器会作出一个响应。可以在服务器中部署文件&#xff0c;让他人访问…

MySQL必会知识精华2(了解基础篇)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以完成数据库增删改查的实际操作。轻松应对面试或者笔试题中MySQL相关题目 上篇文章我们先做一下MySQL学习的准备工作&#xff0c;如安装MySQL 服务&#xff0c;配置MySQL&#xff0c;连接MySQL。本篇文章注重…

大模型学习笔记 - LLM 之RAG

RAG RAG RAG SuveryRAG 简介RAG 范式的演变 1. 初级 RAG2. 高级 RAG3. 模块化的 RAG 介绍 RAG框架简述 检索技术文本生成增强技术简介 RAG 与 微调的区别RAG 模型评估解析RAG 研究的挑战与前景构建 RAG 系统的工具 在学习RAG中, 发现这个网站的内容特别好&#xff0c;也比较…

决策树算法:ID3与C4.5的对比分析

决策树是一种非常直观且易于理解的机器学习方法&#xff0c;被广泛应用于分类和回归任务中。在这篇文章中&#xff0c;我们将探讨两种经典的决策树算法&#xff1a;ID3与C4.5&#xff0c;并分析它们之间的区别。 一 算法概述 我们每天都做着各种形形色色的决策——周末怎么嗨…

普元EOS-微前端的base基座介绍

1 前言 微前端开发的时候要使用base基座。 这个base基座到底是什么&#xff1f; base基座能提供哪些功能&#xff1f; 本文将进行简单的介绍。 2 高开前端引用base基座 在高开页面引入base基座的语法如下&#xff1a; <script>import { BaseVue, AjaxUtil } from …

五、Centos7-安装Jenkins

目录 一、基础环境准备 1.安装JDK 2.安装Tomcat 二、安装Jenkins 1.配置Jenkins插件镜像源 2.问题&#xff1a;进入manager jenkins页面报错 3.配置Git 4.配置jdk 三、重新安装Jenkins 四、另一种Centos安装jenkins的方式--最终可用版 克隆了一个base的虚拟机&#x…

深度学习入门:循环神经网络------RNN概述,词嵌入层,循环网络层及案例实践!(万字详解!)

目录 &#x1f354; RNN 概述 1.1 循环神经网络 1.2 自然语言处理 &#x1f354; 词嵌入层 2.1 词嵌入层的使用 2.2 关于词嵌入层的思考 2.3 小节 &#x1f354; 循环网络层 3.1 RNN 网络原理 3.1.1 RNN计算过程 3.1.2 如何计算神经元内部 3.2 PyTorch RNN 层的使用…

机器学习(前六关大总结)生动讲解+代码实例

老粉都知道&#xff08;还不点关注&#xff09;我这机器学习已经有几天没更了&#xff0c;主要是最近忙碌比赛&#xff0c;所以时间紧张 那么我为大家总结一下&#xff0c;之前的机器学习知识点&#xff0c;让大家更好了解机器学习领域。 在此阅读前&#xff0c;感谢大家的关…

HTMl标签;知识回忆;笔记分享;

HTML标签是用于定义和组织网页内容的基础构建块。每个标签都有特定的作用。 一&#xff0c;标准结构标签&#xff1a; HTML文档标准结构&#xff1a; <html><head></head><body>this is my second html... </body> </html> 【1】htm…

代码随想录 | day 15 | 二叉树part03

完全二叉树的节点个数 方法一&#xff1a;可以用递归法遍历一遍左子树和右子树的个数之和再加1等于全部节点个数 class Solution { public:int getcount(TreeNode* cur){if(curNULL) return 0;int leftcount getcount(cur->left);int rightcount getcount(cur->right…

Python3.11二进制AI项目程序打包为苹果Mac App(DMG)-应用程序pyinstaller制作流程(AppleSilicon)

众所周知&#xff0c;苹果MacOs系统虽然贵为Unix内核系统&#xff0c;但由于系统不支持N卡&#xff0c;所以如果想在本地跑AI项目&#xff0c;还需要对相关的AI模块进行定制化操作&#xff0c;本次我们演示一下如何将基于Python3.11的AI项目程序打包为MacOS可以直接运行的DMG安…

90. UE5 RPG 实现技能的装配

在上一篇里&#xff0c;我们实现了在技能面板&#xff0c;点击技能能够显示出技能的相关描述以及下一级的技能的对应描述。 在这一篇里&#xff0c;我们实现一下技能的装配。 在之前&#xff0c;我们实现了点击按钮时&#xff0c;在技能面板控制器里存储了当前选中的技能的相关…