This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
[引用用户="Ming Zhong10"]
器件型号: TDA4VM
尊敬的专家:
我们的客户发现从 A72读取 GTC 将会出现以下问题:
LO 过流时、HI 应增加1。 但他们发现、LO 溢出、但 HI 不会增加。
您是否有任何建议的最佳做法来读取这2个32位寄存器?
谢谢、致以最诚挚的问候!
ZM
[/报价]
大家好、 专家也很好
我们发现、在特定时刻、HI 增加1、 但 LO 未清除、因此当我们读取 GTC 时间时、它比实时时间大约增加21秒。
我们如何解决这个问题? 如果无法解决此问题、该时间(HI 增加1、 但 LO 未清零)将持续多长时间?
在我看来、ZM 和 Subin Li 描述了两个不同的问题。 我不知道这个问题。 您能否提供寄存器转储、以便我尝试重新创建问题?
Subin、
您能否提供一段代码和日志来解释此问题?
我认为如果您可以打印寄存器、将有助于我们的专家了解。
谢谢、致以最诚挚的问候!
ZM
我们的示例代码如下所示:
#define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) #define GTC_BASE_寄存 器0x00A90000 OFF_t GTC_TARGET = GTC_BASE_REGTER; FD = OPEN ("/dev/mem、O_RDWR | O_SYNC)); GTC_MAP_BASE = mMAP (0、MAP_SIZE、 PROT_READ | PROT_WRITE、MAP_SHARED、FD、GTC_TARGET 和~MAP_MASK); GTC_virt_addr = GTC_MAP_BASE +(GTC_TARGET 和 MAP_MASK); uint64_t READ_RESULT =*((unsigned long *) GTC_virt_addr + 1);
在特定时刻、READ_RESULT 为0x01FFFFFFFD、然后我们快速得到 READ_RESULT agian、即0x02FFFFFFFD、应为0x0200000000。
我们认为此时 HI (0x00A9000C)增加1、但 LO (0x00A90008)不会被清除。
我们如何解决这个问题? 如果无法解决此问题、该时间(HI 增加1、 但 LO 未清零)将持续多长时间?
谢谢!
ZM 误解了我们的问题、请帮助解决我的问题。 谢谢你。
我们的示例代码如下所示:
#define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) #define GTC_BASE_寄存 器0x00A90000 OFF_t GTC_TARGET = GTC_BASE_REGTER; FD = OPEN ("/dev/mem、O_RDWR | O_SYNC)); GTC_MAP_BASE = mMAP (0、MAP_SIZE、 PROT_READ | PROT_WRITE、MAP_SHARED、FD、GTC_TARGET 和~MAP_MASK); GTC_virt_addr = GTC_MAP_BASE +(GTC_TARGET 和 MAP_MASK); uint64_t READ_RESULT =*((unsigned long *) GTC_virt_addr + 1);
在特定时刻、READ_RESULT 为0x01FFFFFFFD、然后我们再次快速获取 READ_RESULT、即0x02FFFFFFFD、应为0x0200000000。
我们认为此时 HI (0x00A9000C) 增加1、但 LO (0x00A90008)不会被清除。
我们如何解决这个问题? 如果无法解决此问题、该时间(HI 增加1、 但 LO 未清零)将持续多长时间?
谢谢!
到目前为止、我无法复制您的错误。 GTC 源时钟的频率是多少? 此外、 GTC_CNTFID0寄存器中的值是多少? 在读取0x02FFFFFFFD 之后、如果您从寄存器中读取足够多的时间、最终是否会读取0x200000000?
您可以尝试以不同方式执行的操作之一是从 GTC_CNTVS 读取、该寄存器在只读寄存器中包含相同的信息。 由于我无法重新创建您的问题、我不确定这是否可以解决。
-Zack
您好、Zack
关于 GTC 源时钟,我们没有更改 CTRLMMR_GTC_CLKSEL 的值(位0~3)、所以它的值默认为0、我们使用 MAIN_PLL3_HSDIV1_CLKOUT 作为源时钟、它是200MHz。
GTC_CNTFID0寄存器中的值为0。
在我读取0x02FFFFFFFD 后、如果我从寄存器中读取足够多的时间、我最终会读取0x200000000 (或0x200000XXX)。 我们想知道、当 我们得到错误的值(0x02FFFFFFFD)时、我们必须等待多长时间才能获得正确的值((0x200000XXX)?
您所说的 GTC_CNTVS 寄存器是 GTC_CNTCMS_HI 和 GTC_CNTCMS_LO、我发现这些值与 0x00A90008和 0x00A9000C 相同。
也许您可以使用下面显示的测试代码来复制错误:
uint64_t LAST_RESULT = 0; uint64_t READ_RESULT = 0; while (1){ Read_Result =*((unsigned long *) GTC_virt_addr + 1); if (abs(read_result-last_result)> 200000000){ printf ("出错!\n"); } LAST_RESULT = READ_RESULT; usleep(1); }
当我离开它运行几个小时时、我遇到了这个问题。 为了捕捉故障、我必须在正确的时刻查询计数器、让计数器运行一段时间、从而找出故障。
我将继续研究这个问题以找到解决方案。
谢谢、期待收到您的好消息。
Subin、
无法在 GTC 上同步 HI 和 LO 的存储器映射寄存器。 由于 GTC 计数器的接口宽度仅为32位、因此对计数器的任何读取都必须是两次32位读取。 如果通过翻转 LO 寄存器来分隔这两次读取、则会遇到错误。
我建议使用以下权变措施:以尽可能短的延迟对计时器计数器执行第二次读取、以检测是否存在错误读取。 第二次读取应始终大于第一次读取。 如果不是、则第一次读取无效。 有几个警告:
1) 1)读取 GTC 计数器时、应始终先读取 LO、然后读取 HI。 示例中的 C 代码将计数器视为单个64位数、但根据您提供的值序列、汇编代码首先读取 LO、然后读取 HI。
2) 2)第二次读取必须在 LO 的翻转时间内发生。 换句话说、读取之间的时间必须小于(2^32)/(GTC_CLK 频率)。
3) 3)读取 GTC 计数器两次后、丢弃第二次读取、并使用第一次读取作为返回值。
请告诉我、这是否是您可以接受的解决方法、如果您还有任何疑问、请告知我。
您好、Zack
您是否在该问题上取得了进展?
如果目前没有好的解决方案、您能否先向我们确认 这一时刻 (HI 增加1、但 LO 未清除)的持续时间?
谢谢!
Subin、
我不确定你是否错过了这个机会,但我在9月4日作了答复。 请查看该回复、并告诉我该解决方案是否适合您。
谢谢、
Zack
您好、Zack
我认为您的解决方案存在一些问题。
1、第一次读取后多久开始第二次读取?如果两次读取之间的时间太短、则两次读取的值始终相同或非常接近。 因此 、两个读数的值可能都是错误的。
2、我们认为存在以下情况:
①first 读取:0x1FFFFFF00(真)
usleep(XXX)
第二个读取:0x1FFFFFFFE(真)
返回:0x1FFFFFFFE
②first 读取:0x1FFFFFFFE(真)
usleep(XXX)
第二个读取:0x2FFFFFFFF(false)
usleep(XXX)
第三次读取:0x20000000E(true)
返回 :0x20000000E
③first 读取:0x2FFFFFFFE(错误)
usleep(XXX)
第二个读取: 0x20000000E(true)
usleep(XXX)
第三次读取: 0x20000001E(true)
返回: 0x20000001E
现在、我们想知道最短的使用时间 XXX。
但我们不能在这里使用 usleep、因为调用时会导致上下文切换。 如果经常调用它、则会导致效率低下。
因此、我们将使用忙等待函数、因为它不会导致上下文切换。
因此 、我们需要知道最短的使用时间 XXX。
Subin、
您在上一篇帖子中说过:
"如果两次读取之间的时间太短、两次读取的值始终相同或非常接近。"
您是否观察到连续多次读取错误值? 我在测试中没有观察到这一点、如果您发现这一点、那么它的运行方式与我对根本问题的理解背道而驰。
如果是这种情况、那么我同意读取之间必须有一定的最短等待时间、我将努力弄清楚延迟必须是什么。
您好、Zack
我的意思是、如果我读出这样的时间:
首先读取:0x2FFFFFF0E
第二个读取:0x2FFFFFF0E
如果在两个读数之间不等待一段时间、则第二次读数将与第一次读数相同或非常接近。
如果第一次读取为 true、第二次读取也为 true。 如果第一次读取为 false、第二次读取也为 false。
因此、我们必须知道 读取之间的最短等待时间。
上述两个错误读取的情形是假设的还是观察到的? 我认为不可能在类似的一行中获得两个错误的读数。 误差的来源是 LO 在读取 LO 和 HI 之间发生翻转。 事件按以下顺序发生:
1) 1)您读取 LO
2) 2) LO 翻转、HI 递增。
3) 3)您读为 HI。
现在、您已读取了一个递增的 HI 值、但在翻转之前读取了一个 LO 值。 您的代码会将它们作为一个64位值粘在一起。 这是导致错误读数的原因。 但是、通过这种机制、只要两次连续读取之间的时间远小于 LO 的翻转周期、两次连续读取就不能同时为 false。
-Zack
您好、Zack
我认为您的想法是错误的。
下面是我的测试日志:
读取 GTC:(最后一个:2796023698067) 0x28AFFFFD293
读取 GTC:(第一个: 2796023698067) 0x28AFFFFD293
usleep (1)
读取 GTC:(第二个:2800318676976) 0x28BFFFFFFF0
读取 GTC:(第三个: 2800318676976) 0x28BFFFFFFF0
因此、如果我在没有睡眠的情况下读取寄存器、这些值将是相同的。
因此、我们需要知道读取寄存器的间隔时间、该间隔应 至少保证 一次读取正确。
您从哪个内核访问该寄存器、该内核的运行速度是多少?
-Zack
我们从 A72访问该寄存器、它以2GHz 的频率运行。
Subin、
我联系了设计师、他给出了以下评论:
至少从 CPU 内核的角度来看,这实际上不是 GTC 的预期用途。 GTC 部分用于实现 ARMv8通用定时器架构的系统计数器功能。 因此、它通过一个灰色的编码系统定时器总线将时间计数分配给 ARM 处理器 每个 ARM 内核都包含处理器元件计时器、这些计时器通过系统计时器总线从 GTC 获取其计数器值 因此、我希望 A72内核能够通过 使用系统控制寄存器读取其本地 CNTPCT 而不是尝试从 GTC 计数器寄存器读取来获得时间。
这是可行的解决方案吗?
您好、Zack
我们不仅需要从 A72获取时间、还需要从其他内核(R5、C66和 C7X)获取时间。 我们发现只有 RTC 寄存器可以用作公共时间源。 您说过、我们可以读取 其本地 CNTPCT 以在 A72中获得时间、但我们无法在其他内核中以相同的方式获得时间。 如果我们使用其他方法来获取其他内核中的时间、我们得到的时间将会有所不同。
另一方面、无论 GTC 的用途如何、我们之前描述的问题都存在。 现在我们无法解决这个问题。
现在、我们只想知道 GTC 寄存器错误将持续多长时间。
Subin、
读取 GTC:(最后一个:2796023698067) 0x28AFFFFD293
读取 GTC:(第一个: 2796023698067) 0x28AFFFFD293
usleep (1)
读取 GTC:(第二个:2800318676976) 0x28BFFFFFFF0
读取 GTC:(第三个: 2800318676976) 0x28BFFFFFFF0
我不是很了解上面的测试日志。 您是否按顺序读取了最后、第一、第二、第三次?
因此、如果我在没有睡眠的情况下读取寄存器、这些值将是相同的。
因此、我们需要知道读取寄存器的间隔时间、该间隔应 至少保证 一次读取正确。
您能否使用计数器值填充大型数组、而不在 READ_GTC 之间调用 usleep? 在跳转之前、跳转会破坏 READ_GTC 值、在跳转之后、至少有足够大的数组来查看 GTC 中的一些转换。 这样、我们就可以更好地了解 GTC 寄存器的访问速度、这将有助于回答您的问题。
-Zack
您好、Zack
1、是的、我 按顺序阅读最后、第一、第二、第三。
测试日志告诉我们、我读取了两次、它们的值为0x28AFFFFD293、它们是对的。
但是在使用睡眠之后(1),我读取了两次, 它们的值是0x28BFFFFFFF0, 它们是错误的(与0x28AFFFFD293比较时大跳) 。
2、我想我们已经清楚地描述了这个问题。
从理论分析的角度来看、我们需要知道该误差时间将持续多长时间。
我们的测试不完全可靠、具体取决于实际环境。
此问题已延迟很长时间、请尽快帮助我们解决、谢谢。
预期持续时间为1 GTC 时钟周期。