- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们有一个基于 STM32G483 MCU (Cortex M4) 的定制板。我们使用 SysTick 作为软件定时器的引用。 SysTick 重载寄存器设置为 0x00FFFFFF 以便产生最少的中断。 SysTick 以 128MHz 的 CPU 时钟计时,这意味着每 131ms 左右就有一个 SysTick 中断。中断使滴答计数器增加加载值 + 1。
#define SYSTICK_LOAD_VALUE 0x00FFFFFFU
static volatile uint64_t _ticks;
void
systick_interrupt(void)
{
_ticks += SYSTICK_LOAD_VALUE + 1;
}
然后我们使用当前值寄存器获取当前计数周期中经过的时钟周期数来计算当前时间。
uint64_t
systick_get_ticks(void)
{
return _ticks - SysTick->VAL;
}
然后我们可以将这个值用于不同的软件定时器,理论上这些定时器可以在几个时钟周期的数量级内计数。
void
timer_start(struct timer *timer)
{
timer->_start_tick = systick_get_ticks();
}
bool
timer_check_ticks(const struct timer timer, uint64_t duration)
{
uint64_t difference = systick_get_ticks() - timer._start_tick;
return (difference >= duration);
}
由于函数调用的开销,不可能精确到滴答,但在更长的时间段内仍然应该是准确的,例如 1us(128 个滴答)或 1ms(128 000)。当然,软件定时器可能会过冲一些时钟周期,具体取决于主循环频率,但它不应该下冲。
我们看到这些计时器有一些奇怪的行为,因此我们决定通过最简单的主循环来切换我们可以探测的 GPIO 来测试它们。
int
main(void)
{
// Clock, NVIC, SysTick and GPIO initialisation
struct pin test_gpio;
struct timer test_timer;
timer_start(&test_timer);
while (TRUE) {
if (timer_check_ticks(test_timer, 128000U)) { // 128000 ticks @ 128MHz ==> 1ms
gpio_toggle(test_gpio);
timer_start(&test_timer);
}
}
}
有了这个,我们期待一个具有 50% 占空比和 2 毫秒周期 (500Hz) 的方波,这是我大部分时间得到的。然而,有些脉冲有时会更短,例如 185us。在寻找问题根源的过程中,我们也注意到,任何修改后的编译都会改变较短脉冲的长度,但在代码执行时,这个持续时间似乎没有改变。
我们检查了核心时钟确实以 128MHz 运行,SysTick 被配置为我们想要的,我们编写了一个片段来检查 SysTick 中断是否以正确的频率触发,并且 systick_get_ticks()
函数返回一个可靠的数字。这使我们认为问题出在计时器代码本身,但我们似乎无法找到问题所在。
代码是用 clang (--target=arm-none-eabi
) 编译的,不使用 STM32 HAL 库
最佳答案
考虑:
#define SYSTICK_LOAD_VALUE 0x00FFFFFFU
static volatile uint32_t systick_reload_count = 0 ;
void systick_interrupt(void)
{
systick_reload_count++ ;
}
uint64_t systick_get_ticks(void)
{
uint32_t reload_count = 0 ;
uint64_t ticks = 0 ;
do
{
reload_count = systick_reload_count ;
ticks = (reload_count * (SYSTICK_LOAD_VALUE + 1)) +
(SYSTICK_LOAD_VALUE - SysTick->VAL + 1) ;
} while( systick_reload_count != reload_count ) ;
}
这里的 ISR 更简单(更快)并且访问 systick_reload_count
是此 32 位设备上的原子操作(即不能被中断)。
systick_get_ticks
中的 while 循环确保如果在非原子 ticks
计算期间发生重新加载,则获取新的 systick_reload_count
并且 ticks
重新计算。循环通常不应迭代超过两次(您必须被中断 131 毫秒,在这种情况下您还有其他问题!),因此保持确定性。
此解决方案的一个重要方面是计算是在重新加载计数的本地副本中执行的,而不是在 volatile 计数本身上执行的。
关于c - stm32g483 基于 SysTick 的计时器的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68298474/
我目前正在旁听有关嵌入式系统的在线 edX 类(class),并学习如何使用 SysTick 计时器计算耗时。 Picture of logic I'm referring to Code of lo
我目前正在努力处理一段非常简单的代码,它表明 ARM GCC 的 1 级优化器以某种方式破坏了一个简单的公式。 这使用标准编译器设置 (O1) 在最新的 Atmel 6.2 Studio 上运行。 A
我的 STM32F7 需要高精度中断。任务是在每次滴答时增加一个计数器。 CPU 的频率高达 216 MHz(来自数据表),这意味着可以实现大约 5 ns 的滴答持续时间,对吗? 经过一些互联网研究,
SysTick使用说明 系统节拍 我们有一个基于 STM32G483 MCU (Cortex M4) 的定制板。我们使用 SysTick 作为软件定时器的引用。 SysTick 重载寄存器设置为 0x
我有一个 SysTick 异常处理程序,它计算滴答并调用其他函数(f1、f2、f3),其执行时间可以长于 SysTick 周期。这些函数设置和清除它们的事件状态(全局变量),因此如果发生 SysTic
我目前正在移植我的 DCF77 library (您可能会发现 source code at GitHub )从 Arduino(基于 AVR)到 Arduino Due(ARM Cortex M3)
我有一个用于半托管的 ATSAMD21E18A 微型。为了使半托管工作,GDB 需要在第一条 bkpt 指令之前“附加”。另一方面,我莫名其妙地发现,如果在我配置 GDB 时已经附加了 GDB,则 S
我在获取在运行 uC/OS-III 的 NXP LPC1857 上平稳运行的 LED 的 PWM 信号时遇到问题。仅当我禁用以 1ms 运行的操作系统 systick 时,定期发生的闪烁才会停止。 我
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 4 年前。 Improve this qu
我是一名优秀的程序员,十分优秀!