您尚未登录。

楼主 # 2024-08-09 14:59:53

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 646
积分: 779
个人网站

52位的GTC计时器数值为什么要特意转成格雷码?根本没法用!

想用GTC实现1us精度的时基计时,搞完才发现这玩意是格雷码的!格雷码转自然码要耗费几十上百个指令周期,即根本实现不了微秒级精度。

格雷码用途何在?!

离线

楼主 #3 2024-08-11 10:31:59

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 646
积分: 779
个人网站

Re: 52位的GTC计时器数值为什么要特意转成格雷码?根本没法用!

@xdlkliang
感谢解答。我上面的需求说法有误,我要的是分辨率为1us,精度是us级(10us左右)的时基计时。
我测试了第二种方式,发现读取timeh寄存器时会再现cpu异常。寄存器读取函数如下:

static inline uint32_t _read_csr_time_lo(void)
{
    uint32_t value;

    __asm__ __volatile__ ("csrr %0, time\n\t"
            : "=r" (value) :
            : "memory");

    return value;
}

static inline uint32_t _read_csr_time_hi(void)
{
    uint32_t value;

    __asm__ __volatile__ ("csrr %0, timeh\n\t"
            : "=r" (value) :
            : "memory");

    return value;
}

RTOS SDK 1.0.5下经测试读寄存器time没有问题,读寄存器timeh时出现cpu异常:

CPU Exception: NO.2                                                                                                                                                                                               
x1(ra)   : 00000000400338b8     x2(sp)   : 000000004022d2c8     x3(gp)   : 00000000401ba318     x4(tp)   : 00000000deadbeef                                                                                       
x5(t0)   : 00000000401bbef8     x6(t1)   : 0000000000000001     x7(t2)   : 00000000deadbeef     x8(s0/fp): 0000000000000006                                                                                       
x9(s1)   : 00000000400bb7e0     x10(a0)  : 0000000000000001     x11(a1)  : 000000004022d2e8     x12(a2)  : ffffffff00000000                                                                                       
x13(a3)  : 0000000040223228     x14(a4)  : 0000000000000000     x15(a5)  : 0000000000000000     x16(a7)  : 0000000000000009                                                                                       
x17(a7)  : 0000000040223228     x18(s2)  : 0000000040223222     x19(s3)  : 0000000040150570     x20(s4)  : 00000000401829f8                                                                                       
x21(s5)  : 0000000040150900     x22(s6)  : 000000004015bd28     x23(s7)  : 00000000401c2400     x24(s8)  : 000000000000000d                                                                                       
x25(s9)  : 0000000040223222     x26(s10) : 0000000040222dd0     x27(s11) : 00000000deadbeef     x28(t3)  : 0000000000000022                                                                                       
x29(t4)  : 000000000000005c     x30(t5)  : 000000000000000a     x31(t6)  : 00000000deadbeef                                                                                                                       
mcause   : 0000000000000002                                                                                                                                                                                       
mtval    : 00000000c8102773                                                                                                                                                                                       
mepc     : 00000000400bb7f0                                                                                                                                                                                       
mstatus  : 8000000a00007880

什么问题?

离线

楼主 #4 2024-08-11 15:37:40

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 646
积分: 779
个人网站

Re: 52位的GTC计时器数值为什么要特意转成格雷码?根本没法用!

发现RTOS SDK里有这个API:aic_get_time_us,其实现就是读time寄存器,于是找到上面问题的原因了。

我用的芯片是D21x,其CSR寄存器time是64位的,所以此芯片应该没有timeh寄存器,只需读time寄存器即可。
那么,基本上只需两条指令就能获取分辨率为1us的时基,不错!

最后D21x上读取内核时基的函数如下,D13x等32位MCU就没那么便利了:要读取寄存器2次且需处理读取过程中的进位情况

static inline uint64_t _read_csr_time(void)
{
    uint64_t value;

    __asm__ __volatile__ ("csrr %0, time\n\t"
            : "=r" (value) :
            : "memory");

    return value;
}

PS:RTOS SDK里d13x、d12x等读取系统时基的函数 aic_get_ticks,没有处理读取过程中可能出现的进位情况(读取时低32位寄存器发生32位进位),是否是一个BUG?!

u64 aic_get_ticks(void)
{
    return (((u64)csi_coret_get_valueh() << 32U) | csi_coret_get_value());
}

最近编辑记录 海石生风 (2024-08-11 15:48:30)

离线

楼主 #6 2024-08-13 12:05:51

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 646
积分: 779
个人网站

Re: 52位的GTC计时器数值为什么要特意转成格雷码?根本没法用!

"把左移操作放到运算符右边"还不行吧,参照Linux SDK那边(linux-5.10/arch/riscv/include/asm/timex.h)应该改成如下才行吧:

u64 aic_get_ticks(void)
{
	u32 hi, lo;

	do {
		hi = csi_coret_get_valueh();
		lo = csi_coret_get_value();
	} while (hi != csi_coret_get_valueh());

	return ((u64)hi << 32) | lo;
}

最近编辑记录 海石生风 (2024-08-13 12:07:26)

离线

楼主 #9 2024-08-13 14:36:47

海石生风
会员
所在地: 深圳
注册时间: 2019-07-02
已发帖子: 646
积分: 779
个人网站

Re: 52位的GTC计时器数值为什么要特意转成格雷码?根本没法用!

@xdlkliang
不行呀,在读取过程中产生进位,即是高低两个寄存器都已经变化了呀,那么两个寄存器都要重新读取。

所以要用do while流程来或以下的if流程来处理:

	hi = csi_coret_get_valueh();
	lo = csi_coret_get_value();

	// 产生进位的时间间隔是很长的,不可能在短时间内产生两次进位
	if(hi != csi_coret_get_valueh()) {
		hi = csi_coret_get_valueh();
		lo = csi_coret_get_value();
	}

最近编辑记录 海石生风 (2024-08-13 14:37:40)

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn