- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我目前正在努力处理一段非常简单的代码,它表明 ARM GCC 的 1 级优化器以某种方式破坏了一个简单的公式。
这使用标准编译器设置 (O1) 在最新的 Atmel 6.2 Studio 上运行。
Atmel 工具链\ARM GCC\Native\4.8.1426\arm-gnu-toolchain
代码非常少:
volatile uint32_t g_timing_tick_ms=0;
void SysTick_Handler(void)
{
g_timing_tick_ms++;
}
inline uint32_t get_millis()
{
return g_timing_tick_ms;
}
uint32_t get_micros()
{
return (g_timing_tick_ms * 1000 + (1000 - SysTick->VAL/84));
}
uint8_t timer_expired(timer_ *t)
{
uint32_t cur_us = get_micros();
uint32_t dt = cur_us - t->last_systick_us;
t->last_systick_us = cur_us;
if (t->elapsed <= dt)
{
// <--------- dt is regularly a huge value (around 0xfffffe00)
// this happens because t->last_systick_us sometimes is bigger than cur_us (overflow)
// however get_micros() is without such an error, cur_us ALWAYS increases and the
// variables are not modified outside this function which is called every 500us.
t->elapsed = t->interval;
return 1;
}
t->elapsed -= dt;
return 0;
};
get_millis
从每毫秒调用一次的 Systick 计时器返回毫秒数。
系统定时器为24位,以84mhz的速率递减计数。get_micros
() 使用此 systick 值并计算自上次重置以来经过的微秒,然后加上毫秒 *1000。
这工作得很好,我找不到更快的方法来获取当前微秒作为时间戳。
第三个函数显示了一个偶发问题,有时存储在 t->last_systick_us 中的值(直接来自 get_micros() )比它应该的大。确切地说,最后三个十进制值总是 986 (20065986,1000986)。
该值大约 1000us 太高,十进制数末尾始终带有 986。
每隔一些电话就会发生这种情况。
解决方法:
1)改变:
uint32_t dt = cur_us - t->last_systick_us; --->
volatile uint32_t dt = cur_us - t->last_systick_us;
将此变量更改为 volatile 解决了这个问题,这导致了编译器以一种糟糕的方式处理它的想法。该变量不是静态的,它是本地变量,没有任何东西可以从外部对其进行修改,volatile 是一种浪费,但可以解决数学问题。2)改变
uint32_t get_micros() ----->内联 uint32_t get_micros()这也解决了这个问题,但是这也不是一个好的解决方法,因为编译器不必将其内联。所以这可能会在未来的某个时候适得其反。
3)在值更改之前将任何调试写入或类似内容添加到计时器函数中也可以修复它,具体取决于代码。
这似乎是 gcc-ARM 核心编译器中的错误,优化器以某种方式破坏了数学。我可以提供 asm,我不知道 ARM ASM,但我注意到它在靠近 get_micro() 公式的部分删除了一个“sub”。
我不认为我这里有代码错误,它太简单了(而且效果很好)。此外,解决方案表明这不是编码错误,在函数中添加或删除内联除了优化之外应该没有任何区别。
也许有人知道该怎么做,经历过/解决了类似的行为。我正处于完全删除优化器的边缘,但这可能会花费相当多的性能。
更新
当我意识到可能的原因并且我认为是这种情况时,我正准备准备 asm 差异(并通读)。
我认为这是一个竞争条件,Systick 的中断还没有触发,但是 systick 定时器溢出了。
结果是大约 1000us 的误差(随着定时器每 84ns 滴答一次,误差会小一些。
这将导致错误,不可预测,并且通过更改代码,循环会发生变化,通过更改循环,它可能会以导致竞争条件稍后出现的方式对齐代码。
我进行了调试,并且可以验证问题在 Systick 重新加载后不久就发生了。
很抱歉在编译器错误中做出过快的猜测。
最佳答案
问题是由于竞争条件引起的,编译器没有错误。我不完全确定,但我认为这是 SAM3x8e ARM 实现(或一般的 Cortex M3)中的弱点,或者他们没有考虑使用 IRQ 和 Systick 值的人。
无论我尝试过什么修复或代码,我总是遇到以下两种情况之一:在 get_micros() 计算期间触发中断Systick 在 get_micros() 期间溢出,但没有触发中断。
get_micros() 读取一个旧的毫秒/Systick 值和一个新的 systick/毫秒变量,导致近 1 毫秒的错误。
有人可能会考虑添加 NVIC_DisableIRQ(SysTick_IRQn);一开始有帮助。它没有,它在 ASF 中没有记录,但 NVIC 不处理 Systick 启用/禁用,IRQn 为负,不会对异常产生任何影响。
有趣的是,NVIC 用于在 Atmels 驱动程序代码中设置优先级,但可能也没有效果。
另一个有趣的方面是 atmel 在它自己的一些源代码示例中使用了这个调用。(在浪费了 6 个小时之后就没那么有趣了)
我尝试用 __disable_irq() 保护代码但没有产生积极影响,同样的竞争条件发生了(定时器被改变但 Systick 值还没有超过)
我试过这个:
if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) micro_us+=1000;
这会读取系统控制寄存器并检查自上次读取后计数器是否溢出。
根据 atmel sam3x8ek 数据表,它应该这样做。
但是,读取此寄存器的两个未记录的副作用:
1) 它启动另一个 Systick 中断!
2) 它将计数标志值重置为 0
数据表中对这两个操作只字未提,2) 没用但不会成为问题 1) 是个阻碍。
禁用 IRQ 的唯一方法是在系统处理程序中,SCB->SHCSR。
但是,如果发生这种情况(硬故障),则会导致崩溃。
可能的解决方案:禁用 systick 的时钟,等待挂起的 IRQ 发生,然后继续。这将确保读取值和读取中断同步,并且会引入一个小的定时错误并在函数本身中花费额外的时间。
经过大约 4-5 小时的调试和与错误或未记录的功能作斗争后,我想出的最佳解决方案是以下代码:
uint32_t get_micros()
{
//__disable_irq(); // does not affect systick
static uint32_t last_value;
volatile uint32_t timestamp = g_timing_tick_ms; // set to volatile to make sure the compiler does not optimize here
volatile uint32_t val = SysTick->VAL;
uint32_t micro_us = (timestamp * 1000 + (1000 - val/84));
if (last_value > micro_us) micro_us+=1000; // Hack: race condition only causes a 1ms delay, this solves it
last_value = micro_us;
//if (SysTick->VAL > val ) micro_us+=1000; // undocmented, causes VAL reset to 0
//if (NVIC_GetPendingIRQ(SysTick_IRQn)) micro_us+=1000; // asf undocumented, does not handle systick (system handler)
//if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) micro_us+=1000; // triggerd undocumented systick interrupt
return micro_us; // hardcoded auf 84mhz
}
我希望这可以节省别人我不得不花费的时间。
它引入了一个新变量并保留了最后一个值的运行副本,如果时间开始倒流,它会将值增加 1 毫秒(误差始终为 1 毫秒)。
如果这看起来不够干净:
我能想到的唯一精益解决方案是停止系统时钟并改用计时器。
定时器有更好的文档记录(至少对于基本使用而言)并且它们工作可靠。SAM3 带有 9 个定时器。
关于c - 更新 : SAM3X problems with systick handler and accessing systick value for microsecond resolution,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24592145/
我很绝望,现在已经两天(!!)天都没有解决方案来解决以下问题。 更新 Lion 后,我想使用最新版本的 rvm 安装额外的 rubies。 这是我之后调用 bundler 时发生的情况: /Users
我的问题: ajax 调用的无限循环会产生问题吗? 假设有这样的代码: ajaxcall(); function ajaxcall(){ jQuery.ajax({ typ
这是一个有趣的小项目,我已经开始尝试并最大限度地提高赢得办公室曲棍球池的机会。我试图找到最好的方法来选择 20 名能够在最高工资帽内给我最多分数的球员。 例如,假设原始数据由 玩家姓名 位置(前锋,后
我有一个总数为540000的数字列表。我想将此列表分为3个列表,每个列表总共180000。最有效的编程方法是这样做,假设数字列表是一个平面文件,每个数字为线? 最佳答案 听起来像Knapsack pr
抱歉,也许因为我不是英语,我不知道,但我找不到解决几个问题的任何资源;也许我用的词不正确.. 我想了解有关 iPhone 4 和 5 不同分辨率的更多信息。 首先:如果我开发针对 iPhone 4 分
在全局配置缓存后,如 docs ,如果我在 app.module 之外使用 CacheInterceptor,它会抛出错误。 app.module.ts const cacheConfig = {
我无法让 g:each 工作。我正在尝试遍历任何内容,但它永远不起作用 = 不生成任何 html。 索引.gsp Item ${i.name} 用户 Controller .g
在我的 XAML 文件中,我有一个这样声明的 ListBox:
想知道你是否可以帮助我: 我有一个名为initializeAll的方法: public final void initializeAll() { //other stuff........ rand
我尝试过使用 XML 和 JAVA 在我的 Android Activity 中创建一个 ImageView。这两次,我都能够获取我一天前创建的所有其他 PNG 资源以显示在 ImageView 中。
我需要你的帮助。这是什么意思? Warning: mysql_query() [function.mysql-query]: Access denied for user 'ODBC'
这是一段代码 function test() { this.value = "foo"; } $(document).ready(function () { test();
这是一些非常基础的东西。渲染期间引发异常:java.util.Locale.toLanguageTag()Ljava/lang/String; XML: 问题似乎出在 Edit
除其他来源外,我还使用 Stackoverflow 上的各种帖子,尝试实现我自己的 PHP 分类器,以将推文分类为正面、中性和负面类别。在编码之前,我需要弄清楚流程。我的思路和例子如下:
在过去的几周里,每当我在 Eclipse 上使用 SVN 插件时,我都会收到以下错误: Certificate Problem There is a problem with the site's s
我被拒绝运行以下功能(位于 /var/www/mysite/public_html/app/Controllers/Script.php) $structure = '/var/www/mysite/
我正在使用 ctags 为我的 Emacs 创建标签以使用 cygwin 从中读取符号。 Emacs 说 “访问标签表缓冲区:文件/home/superman/tags 不是有效的标签表” 这是我查找
我知道作为一种函数式语言,XSL 没有像传统的 for 循环(而是 for-each)那样的东西。 我正在尝试从可变数量的元素开始创建一个具有固定数量 (7) 的表。总之,我有
我正在使用RavenDB进行一些测试,以基于iphone应用程序存储数据。该应用程序将发送一个带有GPS key 的5个GPS坐标的字符串。我在RavenDB中看到每个文档约为664-668字节。这是
我无法理解我的应用程序的行为。我想创建一个简单的窗口 (1000x700px),分为两部分(分别为 250px 和 750px 宽度)。我尝试了以下代码: import java.awt.Color;
我是一名优秀的程序员,十分优秀!