
SysTick高精度延时实验 前面章节的实验我们使用的是HAL库里自带的API函数HAL_Delay来实现毫秒级别延时的,如果使用到更高精度的延时,例如us级别的延时,我们可以使用定时器来实现,也可以使用SysTick的时钟摘取法来实现。本节,我们介绍如何使用SysTick来实现us级别的延时。 23.1 SysTick简介 23.1.1 SysTick初识 1.什么是SysTick SysTick即系统滴答定时器(system tick timer),它被捆绑在NVIC中,属于Cortex-M内核的一部分。SysTick是一个24位的递减定时器,它是可编程的,软件上可通过对其对应的LOAD寄存器中写入一个数值(最大为224-1)来配置定时器的定时初值。当SysTick以一定的频率工作的时,每来一个脉冲,SysTick从定时初值逐1递减,当递减到0时,SysTick产生一次中断,同时从RELOAD 寄存器(值等于LOAD)中自动重装载定时初值,并重新开始新一轮的递减计数,如此反复。此过程就和我们前面学习的通用定时器以及高级定时器的递减计数功能类似,通过递减计数产生周期性的中断、延时,从而达到计时的效果。 ![]() 图23.1.1. 1 SysTick是递减计数 SysTick属于Cortex-M内核的一个部分,并不是MCU片上外设,所以找遍了参考手册以及数据手册的犄角旮旯,你也看不到更多有关SysTick的详细介绍,如果想了解SysTick,应该查阅内核有关的文档,例如《ARM Cortex-M3与Cortex-M4处理器权威指南》、《Cortex-M3权威指南(中文)》以及《STM32F3与F4系列Cortex M4内核编程手册》等内核相关文件,这些资料存放在 STM32MP157开发板\开发板光盘A-基础资料\4、参考资料 下。 2. 为什么要有SysTick SysTick设计的目的就是给操作系统(OS)提供时基,用于周期性地产生中断来定时触发OS内核,如用于任务管理和上下文切换,处理器也可以在不同时间片内处理不同的任务。若应用中存在嵌入式OS,例如TinyOS、UCOS、RTOS和FreeRTOS等操作系统,SysTick会被OS使。如果不使用OS ,SysTick可当做简单的定时器来用。 对于简单的应用程序,例如我们编写的裸机程序,都是在一个while循环里依次调用各单任务来实现的,如果要处理更多任务或者更复杂的应用,再使用裸机程序就力不从心了,而且会出现更多的问题,例如,在while循环的单任务引用中,如果某一个任务出现问题,后续的任务就被牵连,从而导致系统崩溃。为解决这个问题,操作系统就可以登场了,我们以实时操作系统(RTOS)为例子来说明。当RTOS以并行的架构处理多个任务时,SysTick的任务就是给系统的任务调度提供时钟节拍。根据这个节拍,系统的整个时间段被分成很多很多很小的时间片,而这个时间片则是RTOS实现多任务切换的最小时间单位,每个任务每次只能运行一个时间片的时长就得退出给别的任务运行,这样就可以确保任何一个任务都不会霸占整个系统。如果其中某个任务挂掉了,挂掉的任务并不一定会牵连到整个系统,系统依然可以运行,其它任务依然可以正常调度。 只要是Cortex-M内核都有SysTick,由于和MCU外设无关,这样就方便了程序在不同厂家的Coetex-M内核的MCU之间的移植,例如将RTOS移植到别的硬件平台上,由于SysTick的存在,这样就大大降低了移植的难度。 3. SysTick的时钟 SysTick是MCU内核的一个设备,其时钟来自MCU系统时钟,然后经过分频后得到其工作的时钟,分频值可以是1或者8,所以SysTick的时钟频率最大值为209MHz,可以说其时钟精度还是比较高的,我们从时钟树中就可以看出来: ![]() 图23.1.1. 2 SysTick的时钟频率最大为209MHz 4. SysTick和其它定时器的差别 SysTick属于Cortex-M内核外设,定时器和RTC属于片上外设。 SysTick一般由ARM设计,每个Cortex-M内核里的SysTick都一样,而定时器和RTC属于片上外设,每个芯片厂家设计的芯片可能不一样,所以定时器以及RTC的资源也会不一样。 SysTick的存在主要是用于操作系统中的,如果应用中不使用操作系统,那么SysTick就当做简单的递减定时器来用;RTC可以分配给MPU使用,不能给MCU使用;定时器既可以给MPU使用,也可以给MCU使用,不过在同一个时刻只能单选。 SysTick的时钟源来自Cortex-M内核时钟,RTC时钟源可以是HSE、LSE和LSI,定时器时钟源来自APB1和APB2。默认情况下,STM32CubeMX使用Systick作为时基给其它程序提供计时,例如HAL_Delay延时函数,以及串口程序中的Timeout 超时机制等等,当然也可以选择其它定时器作为时基: ![]() 图23.1.1. 3 Systick作为时基 23.1.2 SysTick 寄存器 固件包的STM32Cube_FW_MP1_V1.2.0\Drivers\CMSIS\Core\Include文件夹下是符合CMSIS标准的内核头文件和CMSIS编译器相关的文件,core开头的是和 Cortex-M 内核相关的文件, MPU开头的是和MPU相关的文件。其中Cortex-M4内核使用core_cm4.h头文件,该文件中有很多关于NVIC中断相关的函数定义和类型定义以及内核的外设相关定义,SysTick相关的寄存器就定义在该文件中: ![]() 表23.1.2. 1 SysTick寄存器列表 下面我们来介绍以上4个寄存器: 1.STK_CTRL(SysTick 控制及状态寄存器) STK_CTRL各位如下: 图23.1.2. 1 STK_CTRL寄存器 ENABLE ENABLE是计数器使能位,用于启用计数器(也就是启用SysTick定时器)。改为置1则使能计数器,清0则关闭计数器。 当ENABLE设置为1时,SysTick定时器被使能,计数器从LOAD寄存器加载RELOAD值,然后递减计数,当递减到0时,COUNTFLAG位变为1,并根据TICKINT的值选择置位SysTick, 然后它将再次加载RELOAD值,并开始计数。 TICKINT TICKINT是SysTick异常请求使能位,该位为0时,当计数器递减到0的时候,SysTick不产生异常请求;该位为1时,当计数器递减到0时产生异常请求。 注:软件可以使用COUNTFLAG来确定SysTick是否曾经计数为零。 CLKSOURCE CLKSOURCE用于配置SysTick的时钟源选择,我们前面说了,SysTick的时钟来自MCU系统时钟,分频值可以是1或者8,当该位为0时为1分频,为1时为8分频。 COUNTFLAG COUNTFLAG是标志计数器是否已经为0,当计数器递减为0时,该位为1。如果读取寄存器或者清除计数器当前值时,该位会被清0. 2. STK_LOAD(SysTick 重装载数值寄存器) STK_LOAD的各位如下图所示: ![]() 图23.1.2. 2 STK_LOAD寄存器 RELOAD[23:0]位是计数器为0时的重装载值,值可以是0x00000001-0x00FFFFFF范围内的任何值。 3. STK_VAL(SysTick当前值寄存器) ![]() 图23.1.2. 3 STK_VAL寄存器 CURRENT[23:0]位是当前计数器的值,读取此位即可获得当前计数器的当前值。写入该位任何值均会清空此位为0,同时STK_CTRL寄存器中的COUNTFLAG位也会被清0。 4. STK_CALIB(SysTick校准寄存器) ![]() 图23.1.2. 4 STK_CALIB寄存器 TENMS[23:0] TENMS[23:0]位是10ms校准值,该值应由芯片设计者提供,若读取该值为0,表示校准值不可用。 SKEW SKEW位用于指示校准值(TENMS值)是否精确,读取此位: 为0,表示校准值正确; 为1,表示校准值不精确,或者校准值未知,这可能会影响SysTick作为软件实时时钟的适用性。 NOREF NOREF用于指示是否有参考时钟提供给处理器。读取此位: 为0,表示有外部参考时钟可供使用; 为1,表示没有外部参考时钟。 23.1.3 SysTick的HAL库驱动 SysTick的HAL库驱动我们在第七章7.4.2小节 滴答定时器相关函数 部分就已经详细分析过了,大家可以参考前面章节的分析,这里就列举出一些HAL库的API函数。 1.HAL_InitTick函数 HAL_InitTick用于配置SysTick的重装载数值寄存器的值,其通过层层调用HAL_SYSTICK_Config函数和SysTick_Config函数完成SysTick的配置,此函数声明如下: __weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) 函数描述: 用于初始化SysTick,配置SysTick的重装载数值寄存器的值。 函数形参: 形参TickPriority是SysTick的中断优先级。 函数返回值: 无。 注意事项: 1、此函数是弱(weak)定义函数,如果用户在别的地方重新定义了同名函数,该函数将被覆盖,编译器会编译用户定义的那个函数; 2、系统复位后,HAL_Init最先被执行时,或者程序由HAL_RCC_ClockConfig重新配置时钟的时候,该函数都会被调用来初始化SysTick; 3、默认情况下,SysTick是计时的时基,SysTick通过周期性的中断来计时的,如果在别的中断中调用HAL_Delay就要小心了,SysTick中断的优先级必须调用它的中断具有更高的优先级(中断优先级数字上更低),否则程序会卡死。 2.HAL_GetTickPrio HAL_GetTickPrio用于获取SysTick的中断优先级,返回值uwTickPrio是SysTick的中断优先级,函数声明如下: uint32_t HAL_GetTickPrio(void) 3. HAL_SetTickFreq和HAL_GetTickFreq函数 HAL_SetTickFreq 函数用于重新配置SysTick的中断频率,HAL_GetTickFreq函数用于获取SysTick的中断频率。函数声明如下: HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq) HAL_TickFreqTypeDef HAL_GetTickFreq(void) 23.2 HAL_Delay函数 23.2.1 SysTick的分频值为1 1.未执行SystemClock_Config函数之前 在前面我们有简单分析过HAL_Delay怎么实现的毫秒延时的,这里我们再次分析实现的过程。 (1)HAL_Init函数 程序进入main.c文件以后,最先执行的是HAL_Init函数,该函数用于初始化HAL库,并配置SysTick每隔1ms生成一次中断。注意的是,此时还没有配置系统时钟(未执行SystemClock_Config函数),系统还是默认使用内部高速时钟HSI,HAL库里SysTick默认采用1分频,所以SysTick时钟频率也为64MHz。
(2)HAL_InitTick函数 HAL_Init函数调用了HAL_InitTick函数完成SysTick的初始化,我们来看看此函数:
经过分析,最后HAL_SYSTICK_Config(SystemCoreClock /(1000U / uwTickFreq))里的参数传递给了LOAD,SysTick就是以此值逐渐递减1来达到计时的。这里,uwTickFreq为1,则参数为SystemCoreClock/1000。 经过前面的分析,在系统复位后,进入主函数前先执行的是HAL_Init函数,而此时系统时钟默认为64MHz,即SystemCoreClock为64MHz。而SysTick的分频值是1,所以SysTick的工作频率为64MHz,那么就可以计算出SysTick多少时间产生一次中断了:SysTick的一个节拍用的时间 * 总的节拍数。一个节拍用时,总的节拍数是,所以计算得SysTick的中断周期:*。 也就是说,系统复位后或者如果时钟树中采用默认的配置,即系统时钟和SysTick的时钟为64MHz,SysTick的分频值为1,SysTick会以每1ms产生一次中断。 (5)SysTick_Handler函数 下面我们看看SysTick的中断服务函数。在前面的实验中,在STM32CubeMX配置好以后,都会在stm32mp1xx_it.c文件中生成一个SysTick的中断服务函数:
(6)HAL_IncTick函数 此中断服务函数调用HAL_IncTick函数,该函数的作用就是使全局变量uwTick每次进入中断后加1,经过前面的分析,系统复位后在未配置系统时钟之前,或者说时钟树采用默认配置时,SysTick每1ms进入中断,也就是每1ms变量 uwTick就自加1:
(7)HAL_Delay函数 当调用HAL_Delay时,HAL_Delay怎么实现的毫秒延时的呢,我们查看HAL_Delay的代码:
第9行,进入HAL_Delay函数以后,先获取当前uwTick的值,并记录在tickstart中,我们称tickstart的值就是原始uwTick的值; 第10行,将用户设置的延时毫秒数Delay赋值给变量wait; 第12~15行,如果没有改动过uwTickFreq 的值,默认uwTickFreq的值为1,这里wait加1后等于(Delay+1)。这里加1为了用于第16~18行的计算。注意,因为SysTick是24位的,所以wait的最大值只能是2^24-1。 第16~18行,通过HAL_GetTick函数获取当前最新的uwTick值,并与之前获取的uwTick值取差运算,当两者差值小于wait时,则一直执行空循环,当差值等于或者大于wait值时,则退出空循环。 假设Delay为10,wait加1后为11,tickstart为15,如果HAL_GetTick()-15<11,那么HAL_GetTick()应该为25,当HAL_GetTick()为26以后就退出空循环了,此时经过了SysTick的10个中断周期,即为10ms。 2. 执行SystemClock_Config函数之后 在没有执行SystemClock_Config函数之前,SysTick的工作频率是64MHz,分频值默认为1,SysTick以1ms产生一次中断。如果我们手动配置了时钟树,例如配置系统时钟为209MHz,SysTick还是1分频,那么SysTick还是1ms的中断周期吗?我们通过代码来分析: 在system_stm32mp1xx.c文件中有SystemCoreClockUpdate函数,SystemCoreClockUpdate函数的作用就是根据时钟寄存器的值来更新SystemCoreClock变量,用户应用程序可以使用它来设置SysTick定时器或配置其他参数。在程序执行期间,每次内核时钟改变时,都会调用SystemCoreClockUpdate函数来更新SystemCoreClock变量的值,这么做也就是为了保证SystemCoreClock的准确性。
所以当我们配置好系统的时钟为209MHz时,SystemCoreClock的值也是209M,当SysTick还是1分频时,SysTick的频率也为209MHz。结合前面的分析,SysTick的一个节拍用的时间为,SysTick的总节拍数为HAL_SYSTICK_Config(SystemCoreClock /(1000U / uwTickFreq))=,那么SysTick产生中断的周期是:=1ms。 通过这里可以验证,不管配置系统时钟(MCU的时钟)为多少,只要SysTick为1分频,SysTick的中断周期都是1ms,使用HAL_Delay可以实现以1ms为单位来计时。 23.2.1 SysTick的分频值为8 当SysTick的分频值为8时,SysTick的中断周期是8ms,我们以系统时钟为209MHz为例子来计算一下。SystemCoreClock的值为209MHz,SysTick分频值为8,SysTick的频率为,SysTick的一个节拍用的时间为,SysTick的总节拍数还是不变为,那么SysTick产生中断的周期是:8ms 。 所以,当修改了SysTick的分频值为8时,执行HAL_Delay(10)函数以后不再是延时10ms,而是80ms。 23.3 SysTick高精度延时实验 本实验配置好的实验工程已经放到了开发板光盘中,路径为:开发板光盘A-基础资料\1、程序源码\11、M4 CubeIDE裸机驱动例程\CubeIDE_project\ 16-1 SysTick。 经过前面的分析,使用HAL库自带的HAL_Delay延时函数可以实现的是毫秒级别的延时,如果需要更精确的延时,例如微妙级别的延时,使用HAL_Delay就不能够实现了。下面,我们使用SysTick来实现微妙级别的延时。 我们将编写delay_us函数实现微妙延时,基于delay_us的基础上编写delay_ms函数实现毫秒延时。编程的思路采用时钟摘取法,以delay_us为例,在进入函数的时候先计算需要延时一段时间所需要的等待的SysTick的计数节拍数,然后我们就一直统计SysTick的计数变化,当计数器的变化节拍数达到我们计算出的节拍数时,说明延时时间到了。比如delay_us(50)表示需要延时50us,假设系统时钟为209MHz,所以要延时50us的话则需要SysTick计数50*209,所以我们的程序就是通过判断是否达到了所需的节拍数来判断所需的延时时间是否已经达到了。 通过时钟摘取法只是抓取SysTick计数器的变化,不需要去修改SysTick的任何配置状态,所以完全不影响SysTick作为UCOS时钟节拍的功能,这就是实现delay和操作系统共用SysTick定时器的原理。下面我们开始介绍这几个函数。 23.3.1 无操作系统 本实验自行编写程序实现SysTick以us计时,然后使用LED0闪烁观察效果,实验中,我们配置系统时钟为209MHz,SysTick为1分频,所以SysTick的时钟频率也为209MHz。 1.新建和配置工程 本节实验可以在前面使用LED的工程中直接添加代码,为了方便,这里新建了一个工程SysTick,并按照前面实验的配置步骤使用HSE作为PLL3的时钟源,同时配置MCU的时钟频率为209MHz,SysTick为1分频: ![]() 图23.3.1. 1 SysTick时钟配置 生成工程后,因为本节实验用到LED0相关的驱动,在Src下新建BSP文件夹,然后把LED0的驱动文件拷贝过来,或者直接拷贝前面实验的BSP文件夹。在BSP文件夹下新建delay.c文件,在BSB/Include文件夹下新建delay.h文件,最后生成的工程如下: ![]() 图23.3.1. 2生成工程 2. 添加用户驱动 (1)添加delay.c文件代码 delay.c文件内容如下:
以上就是时钟摘取法,此时的delay_us,可以实现最长224/209MHz,延时,大概是80274微秒。我们分析一下以上代码: 第7~10行,配置g_fac_us为系统时钟的值,调用该函数时参数需要我们设置。 第21~48行代码是重点部分,这部分代码实现用户设置的微妙延时的时间,我们来分析这段代码: 第23~27行,先定义几个变量,其中:ticks表示实现一定的延时时间SysTick需要计数多少个节拍。told是进入该函数时此时SysTick的计数器的值,我们称为旧的节拍值。tnow是进入while循环后新的节拍值。tcnt是从told值到tnow值,计数器经过了多少个节拍。 第30行,进入while循环后,先获取此时计时器的值tnow; 第31行,如果前后两次得到的计数器的值不相等,说明计数器已经计数了一段时间,可以通过计算在这段时间里计数器计数了多少个节拍来反推出这段时间多长(因为计数器的频率固定,每计数一个节拍用时也固定)。 第33~40,分情况计算出在这段时间里计数器计数了多少个节拍,注意的是SysTick是从224-1递减计数的,当从224-1递减到0时,然后返回继续从2^24-1递减开始递减。 第一种情况,当tnow<told时:tcnt=told-tnow; 第二种情况,当tnow>told时,因为计数器是向下递减计数的,所以计数器已经重新开始计数了,要不然tnow不会小于told。此时tcnt=LOAD-tnow+told。 我们以图来说明: ![]() 图23.3.1. 3 计数器计数示意图 第41行,完成一次判断后,更新told的值,然后再返回到第30行重新进行判断。 第42~45行,当tcnt的值大于或等于需要的节拍数ticks时,说明计时达到或者超过指定的时间,break出循环。 第54~61行,使用delay_us函数实验毫秒延时。 (2)delay.h文件内容
以上代码,第18行,设置Sysclk使用内核时钟源209MHz。 第23和24,配置LED0每隔50ms翻转一次。 23.3.2 有操作系统 这里我们将介绍的是正点原子提供的最新版本的延时函数,该版本的延时函数支持在任意操作系统(OS)下面使用,它可以和操作系统共用SysTick定时器。这里,我们以UCOSII为例,介绍如何实现操作系统和我们的delay函数共用SysTick定时器。首先,我们简单介绍下UCOSII的时钟:ucos运行需要一个系统时钟节拍(类似 “心跳”),而这个节拍是固定的(由OS_TICKS_PER_SEC宏定义设置),比如要求5ms一次(即可设置:OS_TICKS_PER_SEC=200),在STM32上面,一般是由SysTick来提供这个节拍,也就是SysTick要设置为5ms中断一次,为ucos提供时钟节拍,而且这个时钟一般是不能被打断的(否则就不准了)。 1.delay.h文件 如果要支持操作系统,在delay.h中需要添加如下内容:
2.delay_init函数 该函数用来初始化2个重要参数:g_fac_us以及g_fac_ms,同时把SysTick的时钟源选择为外部时钟,如果需要支持操作系统(OS),只需要在delay.h里面,设置SYS_SUPPORT_OS宏的值为1即可,然后,该函数会根据delay_ostickspersec宏的设置,来配置SysTick的中断时间,并开启SysTick中断。具体代码如下:
可以看到,delay_init函数使用了条件编译,来选择不同的初始化过程,如果不使用OS的时候,只是设置一下SysTick的时钟源以及确定fac_us值。而如果使用OS的时候,则会进行一些不同的配置,这里的条件编译是根据SYS_SUPPORT_OS这个宏来确定的,该宏在delay.h里面定义。 在不使用OS的时候:g_fac_us,为us延时的基数,也就是延时1us,SysTick定时器需要走过的时钟周期数。当使用OS的时候,g_fac_us,还是us延时的基数,不过这个值不会被写到SysTick->LOAD寄存器来实现延时,而是通过时钟摘取的办法实现的(前面已经介绍了)。而g_fac_ms则代表ucos自带的延时函数所能实现的最小延时时间。 3. OS相关的宏定义和函数 当需要delay_ms和delay_us支持操作系统(OS)的时候,我们需要用到3个宏定义和4个函数,宏定义及函数代码如下: /* 当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持 首先是3个宏定义:
以上代码,仅支持UCOSII和UCOSIII,不过,对于其他OS的支持,也只需要对以上代码进行简单修改即可实现。 支持OS需要用到的三个宏定义(以UCOSII为例)即: #define delay_osrunning OSRunning /* OS是否运行标记,0,不运行;1,在运行 / #define delay_ostickspersec OS_TICKS_PER_SEC / OS时钟节拍,即每秒调度次数 / #define delay_osintnesting OSIntNesting / 中断嵌套级别,即中断嵌套次数 */ 宏定义:delay_osrunning,用于标记OS是否正在运行,当OS已经开始运行时,该宏定义值为1,当OS还未运行时,该宏定义值为0。 宏定义:delay_ ostickspersec,用于表示OS的时钟节拍,即OS每秒钟任务调度次数。 宏定义:delay_ osintnesting,用于表示OS中断嵌套级别,即中断嵌套次数,每进入一个中断,该值加1,每退出一个中断,该值减1。 支持OS需要用到的4个函数,即: 1)函数:delay_osschedlock,用于delay_us延时,作用是禁止OS进行调度,以防打断us级延时,导致延时时间不准。 2)函数:delay_osschedunlock,同样用于delay_us延时,作用是在延时结束后恢复OS的调度,继续正常的OS任务调度。 3)函数:delay_ostimedly,则是调用OS自带的延时函数,实现延时。该函数的参数为时钟节拍数。 4)函数:SysTick_Handler,则是systick的中断服务函数,该函数为OS提供时钟节拍,同时可以引起任务调度。 以上就是delay_ms和delay_us支持操作系统时,需要实现的3个宏定义和4个函数。下面 我们来看看支持操作系统时delay_us函数编写:。 4. delay_us函数 使用OS的时候,delay_us函数和前面我们不使用操作系统的类似,不同的是多加了delay_osschedlock和delay_osschedunlock是OS提供的两个函数,用于调度上锁和解锁,这里为了防止OS在delay_us的时候打断延时,可能导致的延时不准,所以我们利用这两个函数来实现免打断,从而保证延时精度!
不同的是多加了delay_osschedlock和delay_osschedunlock是OS提供的两个函数,用于调度上锁和解锁,这里为了防止OS在delay_us的时候打断延时,可能导致的延时不准,所以我们利用这两个函数来实现免打断,从而保证延时精度 5. delay_ms函数 使用OS的时候,delay_ms的实现函数如下:
该函数中,delay_osrunning是OS正在运行的标志,delay_osintnesting则是OS中断嵌套次数,必须delay_osrunning为真,且delay_osintnesting为0的时候,才可以调用OS自带的延时函数进行延时(可以进行任务调度),delay_ostimedly函数就是利用OS自带的延时函数,实现任务级延时的,其参数代表延时的时钟节拍数(假设delay_ostickspersec=200,那么delay_ostimedly (1),就代表延时5ms)。 当OS还未运行的时候,我们的delay_ms就是直接由delay_us实现的,不过由于delay_us的时候,任务调度被上锁了,所以还是建议不要用delay_us来延时很长的时间,否则影响整个系统的性能。当OS运行的时候,我们的delay_ms函数将先判断延时时长是否大于等于1个OS时钟节拍(fac_ms),当大于这个值的时候,我们就通过调用OS的延时函数来实现(此时任务可以调度),不足1个时钟节拍的时候,直接调用delay_us函数实现(此时任务无法调度)。 23.3.3 编译和测试 本实验我们的工程是无操作系统的,我们以无操作系统情况下的工程代码为例进行编译测试,编译后,测试PI0引脚的波形。PI0引脚在JP1排针处有引出: ![]() 图23.3.3. 1开发板的PI0引脚 所测试的波形如下,高电平脉冲为500ms,和我们实验的结果一致: ![]() 图23.3.3. 2测试结果 ———————————————— 版权声明:正点原子 |
基于STM32MP1和STM32MP2在嵌入式Linux平台上部署有效的安全保护机制
利用STM32MP1和STM32MP2为嵌入式Linux提供有效的安全措施:供当今决策者参考的3条宝贵经验
STM32MP1 WiFi连接
【STM32MP157】从ST官方例程中分析RPMsg-TTY/SDB核间通信的使用方法
【STM32MPU 安全启动】 TF-A BL2 TrustedBoot原理学习
《STM32MPU安全启动》学**结
《STM32MPU安全启动》学习笔记之optee 如何加载CORTEX-M核和使能校验
《STM32MPU安全启动》学习笔记之TF-A BL2校验optee和uboot的流程以及如何使能
《STM32MPU 安全启动》课程学习心得+开启一扇通往嵌入式系统安全领域深处的大门。
《STM32MPU安全启动》 课程学习心得