【ST NUCLEO-U575ZI-Q 测评 】HAL/LL库使用之systick时基使用与测试
<h1><b>前言</b></h1><p >Systick是CORTEX-M系列单片机的标准内核外设。</p>
<p >一般用于时间基准,时间戳,或者rtos的滴答定时中断。</p>
<p >我们基于上一篇的GPIO可以测试systick的时间是否正确,在systick中断中翻转IO,用示波器/逻辑分析仪测量IO的波形周期即可测试时间是否准确。</p>
<h1 ><b>过程</b></h1>
<p >systick可以参考CORTEX-M3的内核架构文档这里不再赘述。直接看代码。</p>
<p >HAL库也使用了systick作为定时器,延时等操作都依赖于systick。</p>
<h2 ><b>初始化</b></h2>
<p >代码位于stm32u5xx_hal.c中的HAL_Init。</p>
<div class="parsedown-markdown">
<p>HAL_StatusTypeDef HAL_Init(void)</p>
<p >{</p>
<p > /* Configure Flash prefetch */</p>
<p >#if (PREFETCH_ENABLE != 0U)</p>
<p > __HAL_FLASH_PREFETCH_BUFFER_ENABLE();</p>
<p >#endif /* PREFETCH_ENABLE */</p>
<p > </p>
<p > /* Set Interrupt Group Priority */</p>
<p > HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);</p>
<p > </p>
<p > /* Update the SystemCoreClock global variable */</p>
<p > SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR2 & RCC_CFGR2_HPRE) >> RCC_CFGR2_HPRE_Pos];</p>
<p > </p>
<p > /* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */</p>
<p > if (HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)</p>
<p > {</p>
<p > return HAL_ERROR;</p>
<p > }</p>
<p > </p>
<p > /* Init the low level hardware */</p>
<p > HAL_MspInit();</p>
<p > </p>
<p > /* Return function status */</p>
<p > return HAL_OK;</p>
<p >}</p>
</div>
<p > </p>
<p >调用HAL_InitTick进行初始化</p>
<div class="parsedown-markdown">
<p>__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)</p>
<p >{</p>
<p > /* Check uwTickFreq for MisraC 2012 (even if uwTickFreq is a enum type that don't take the value zero)*/</p>
<p > if ((uint32_t)uwTickFreq == 0UL)</p>
<p > {</p>
<p > return HAL_ERROR;</p>
<p > }</p>
<p > </p>
<p > /* Configure the SysTick to have interrupt in 1ms time basis*/</p>
<p > if (HAL_SYSTICK_Config(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq)) > 0U)</p>
<p > {</p>
<p > return HAL_ERROR;</p>
<p > }</p>
<p > </p>
<p > /* Configure the SysTick IRQ priority */</p>
<p > if (TickPriority < (1UL << __NVIC_PRIO_BITS))</p>
<p > {</p>
<p > HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);</p>
<p > uwTickPrio = TickPriority;</p>
<p > }</p>
<p > else</p>
<p > {</p>
<p > return HAL_ERROR;</p>
<p > }</p>
<p > </p>
<p > /* Return function status */</p>
<p > return HAL_OK;</p>
<p >}</p>
</div>
<p > </p>
<p >其中定时周期由HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; /* 1KHz */定义</p>
<p >默认是</p>
<div class="parsedown-markdown">
<p>typedef enum</p>
<p >{</p>
<p > HAL_TICK_FREQ_10HZ = 100U,</p>
<p > HAL_TICK_FREQ_100HZ = 10U,</p>
<p > HAL_TICK_FREQ_1KHZ = 1U,</p>
<p > HAL_TICK_FREQ_DEFAULT = HAL_TICK_FREQ_1KHZ</p>
<p >} HAL_TickFreqTypeDef;</p>
</div>
<p > </p>
<p > </p>
<h2 ><b>中断处理</b></h2>
<p >SysTick_Handler调用HAL_IncTick更新计数器。</p>
<div class="parsedown-markdown">
<p>void SysTick_Handler(void)</p>
<p>{</p>
<p>static volatile uint32_t num = 0;</p>
<p>if(num++ >= 1000)</p>
<p>{</p>
<p>LL_GPIO_TogglePin(GPIOB, 1u<<7);</p>
<p>num=0;</p>
<p>}</p>
<p>HAL_IncTick();</p>
<p>}</p>
</div>
<p > </p>
<h2 ><b>测量时间</b></h2>
<p >总的代码</p>
<div class="parsedown-markdown">
<h1>include "stm32u575xx.h"</h1>
<h1>include "stm32u5xx_ll_gpio.h"</h1>
<h1>include "stm32u5xx_ll_bus.h"</h1>
<p>void SysTick_Handler(void)</p>
<p>{</p>
<p>static volatile uint32_t num = 0;</p>
<p>if(num++ >= 1000)</p>
<p>{</p>
<p>LL_GPIO_TogglePin(GPIOB, 1u<<7);</p>
<p>num=0;</p>
<p>}</p>
<p>HAL_IncTick();</p>
<p>}</p>
<p>void delay(uint32_t t)</p>
<p>{</p>
<p>volatile uint32_t timeout = t;</p>
<p>while(t--);</p>
<p>}</p>
<p>int main(void)</p>
<p>{</p>
<p>LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);</p>
<p>LL_GPIO_InitTypeDef GPIO_InitStruct;</p>
<p>//LL_GPIO_StructInit(&GPIO_InitStruct);</p>
<p>GPIO_InitStruct.Pin = LL_GPIO_PIN_7;</p>
<p>GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;</p>
<p>GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;</p>
<p>GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;</p>
<p>GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;</p>
<p>GPIO_InitStruct.Alternate = LL_GPIO_AF_0;</p>
<p>LL_GPIO_Init(GPIOB, &GPIO_InitStruct);</p>
<p>HAL_Init();</p>
<p>while(1)</p>
<p>{</p>
<p>///delay(1000000ul);</p>
<p>///LL_GPIO_TogglePin(GPIOB, 1u<<7);</p>
<p>}</p>
<p>}</p>
</div>
<p > </p>
<p >使用逻辑分析仪测量,IO翻转时间为1.982917488/2=0.991458744S.</p>
<p >由于中断响应,执行处理代码要一定时间所以有一些误差。</p>
<p > </p>
<p > </p>
<h1 ><b>总结</b></h1>
<p >本篇介绍了systick的使用,测试了其准确度,后面会经常用到时间基准,延时等等。得益于官方的库,几行代码就可以搞定很高效。</p>
<p>systick是个好东西。</p>
<p>学习了</p>
<p>不是太明白有了HAL库,为啥还要搞个LL库</p>
<p>移植FreeRTOS时,要屏蔽PendSV,SVHC和Systick 3个中断</p>
starcat123 发表于 2022-12-17 00:18
学习了
不是太明白有了HAL库,为啥还要搞个LL库
移植FreeRTOS时,要屏蔽PendSV,SVHC和Systick 3个中 ...
<p>LL大部分是使用内联函数对寄存器操作进行封装,也就是相当于直接操作寄存器,</p>
<p>比HAL执行更高效,HAL和LL可以混合使用。</p>
qinyunti 发表于 2022-12-17 09:27
LL大部分是使用内联函数对寄存器操作进行封装,也就是相当于直接操作寄存器,
比HAL执行更高效,HAL和LL ...
<p> </p>
<p>哦,听大佬这么一解释,好像豁然开朗</p>
<p>inline我还是知道是怎么回事儿的,学C51的时候就有,为了更进一步优化代码速度</p>
<p> </p>
<p>测评汇总:免费申请|ST NUCLEO-U575ZI-Q https://bbs.eeworld.com.cn/thread-1228653-1-1.html</p>
页:
[1]