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.

[参考译文] AM5728:需要对 IPU 上运行的专用代码进行精确的 GPIO 时序(在1微秒内)

Guru**** 2824385 points

Other Parts Discussed in Thread: SYSBIOS

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/896960/am5728-need-precise-gpio-timing-within-1-microsecond-on-dedicated-code-running-on-the-ipu

器件型号:AM5728
Thread 中讨论的其他器件:SYSBIOS

您好!

我们要求切换具有精确时序的 GPIO 线路。 例如、将 GPIO 设置为高电平、等待至少9微秒但小于11微秒、然后将 GPIO 设置为低电平。

我们在 ipu1上运行代码、在该 IPU 上没有其他运行的代码。 (DSP 和主 CPU 上都运行代码)

我将使用分辨率为10纳秒的示波器来观察输出。

我看到输出低电平的时间短至6.12微秒、长至8.72微秒。 这超出了要求。


我们使用的代码基于 IPC_3_47_02_00/examples/DRA7XX_Linux_elf/ex02_MessageQ/ipu1/Server.c

我已将 GPIO 切换代码剥离至基础知识(见下文)

我将 ECAP 自由运行计时器(PWMSS_ECAP_TSCNT)用于延迟环路。 系统上没有其他代码正在使用或访问该寄存器。


该代码的性能取决于主 CPU 上的负载、即使在禁用中断的情况下也是如此。 我希望时间基本上独立于系统的其余部分。

此代码是否有问题?
我可以检查/更改哪些内容来实现可靠的波形时序? (特定协议不是标准协议、芯片中不可用)


谢谢、
Scott





注意:寄存器地址以"0x6"开头、而不是通常的"0x4"开头、因为代码在 IPU 上运行。

   volatile U32 * const PWMSS_ECAP_TSCNT =(U32 *) 0x68442100;
   volatile U16 * const PWMSS_ECAP_ECCTL2 =(U16 *) 0x6844212A;

   volatile U32 * const CTRL_CORE_PAD_GPMC_A5 =(U32 *) 0x6A003454;
   volatile U32 * const CTRL_CORE_PAD_GPMC_A6 =(U32 *) 0x6A003458;

   易失性 U32 * const gpio1OE =(U32 *) 0x6AE10134;
   易失性 U32 * const gpio1Set =(U32 *) 0x6AE10194;
   易失性 U32 * const gpio1Clr =(U32 *) 0x6AE10190;

   const U32 countusec = 128;
   const int delay1 = 3 * countusec;
   const int delay2 = 6 * countusec;


   *PWMS_ECAP_ECCTL2 =(1<<4);   //设置 TSCNTSTP FREE 运行 TSCNT


   asm (" CPSID FI\n");

   无符号循环;
   for (loop = 0;loop < 16;++loop)
   {
       *gpio1Clr =(1<<27);   //清除 GPIO1_27

       *PWMSS_ECAP_TSCNT = 0;
       while (* PWMSS_ECAP_TSCNT < delay1)
       {}


       *gpio1Set =(1<<27);   //设置 GPIO1_27

       *PWMSS_ECAP_TSCNT = 0;
       while (* PWMSS_ECAP_TSCNT < delay2)
       {}
   }

   asm (" CPSIE FI\n");

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当访问寄存器和从 DDR 获取指令/数据时、M4不提供精确的时序。

    如果您可以每9微秒使用一次中断到 M4、而不是 CPU 读取寄存器、则延迟可能更一致。

    GP 定时器在20Mhz 时钟上运行、因此您可以使用 GP 定时器以9us 的间隔生成中断、而 M4将在 ISR 中切换 GPIO 线路。  

    但是、如果这仍然不符合所需的精度、则必须研究 PRU 的用法。

    您可以参阅以下应用手册、了解如何对 PRU 进行编程。

    https://www.ti.com/lit/pdf/sprach5

    https://www.ti.com/lit/pdf/sprace9

    此致、
    斯坦利

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Stanley、

    我们需要具有不同宽度的脉冲、包括8、9、17、28、 30和43微秒。

    您指的是哪种 GP 定时器? 它是否具有上述持续时间的单次触发计时器所需的分辨率?

    PRU 能否访问任何 GPIO 引脚?

    谢谢、

    Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    请参阅 TRM 中的第22章计时器和第30章 PRU-ICSS。

    https://www.ti.com/lit/ug/spruhz6l/spruhz6l.pdf

    您可以重新编程 GP 计时器、以触发具有不同持续时间的中断。 PRU-ICSS 具有专用 GPIO 引脚。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Stanley、

    使用 GP 定时器时、预期的中断延迟是多少? 如果在 IPU 上运行的代码有时被延迟5微秒以上、我希望中断延迟可能具有相同的延迟。

    谢谢、

    Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Scott、

    我没有中断延迟的基准编号。

    但是、重点是一致性。

    如果将 ISR 代码放入 IPU 内部存储器中、则中断延迟+ ISR 执行应保持一致。

    唯一的变体是 CPU 更新 GPIO 寄存器以切换线路的时间。

    然后、您可以使用此方法测量时间变化、并查看其是否在所需的精度范围内。

    此致、
    斯坦利

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Stanley、

    我尝试使用提供的 Timer_* API。 (我使用的代码如下所示。 docs/cdocc/ti/sysbios/timers/gptimer/Timer.html 中的文档。) 我希望 API 最终使用与直接寄存器访问代码完全相同的寄存器、但可能 API 具有其他导致问题的限制。

     在示波器上,我捕获了两个不同的照射行程。 在系统上运行的唯一内容是基本/最小代码。 (内核、控制台上的 ssh、基本网络等) 我们的主应用程序未运行。

     使用此代码、我预计将有8个周期、每个周期基本为16微秒、占空比基本为50%。 我偶尔会看到这种情况、但结果通常会有明显的问题、只需查看示波器即可。

     第一次捕获的时序足够糟糕、但第二次捕获的时间要差得多。 大多数间隔为6-10微秒。 有些是10-23微秒。 2个长间隔为877和918毫秒(是的、每秒几乎为一整秒)

    谢谢、

    Scott

    ===========================================
    
    #define GPIO_base 0x68050000 // IPU 0x68050000是 MPU 0x48050000
    #define BIT7   (1<<7)
    #define BIT24 (1<<24)
    #define BIT26 (1<<26)
    #define BIT29 (1<<29)
    #define GPIO2 0x5000 #define GPIO6 0xD000 #define GPIO_CLEARDATAOUT 0x0190 #define GPIO_SETDAAOUT 0x0194 静态 Timer_handle gTimerHandle = NULL; 静态易失性无符号 gTestTimerCount = 0; 空 TimerTestHandler (UARg 未使用) { volatile U32 * const GPIO2SET =(U32 *)(GPIO_base + GPIO2 + GPIO_SETDATAOUT); // IPU 0x68055194 MPU 0x48055194 volatile U32 * const GPIO2CLR =(U32 *)(GPIO_base + GPIO2 + GPIO_CLEARDATAOUT);// 0x68055190 0x48055190 volatile U32 * const GPIO6SET =(U32 *)(GPIO_base + GPIO6 + GPIO_SETATAOUT);// 0x6805D194 0x4805D194 volatile U32 * const GPIO6CLR =(U32 *)(GPIO_base + GPIO6 + GPIO_CLEARDATAOUT);// 0x6805D190 0x4805D190 if (++gTestTimerCount >= 32) Timer_stop (gTimerHandle); if (gTestTimerCount & 1) { * GPIO6SET = BIT7;// GPIO6_7 * GPIO2SET = BIT29 | BIT26 | BIT24;// GPIO2_29、GPIO2_26和 GPIO2_24 } else { *GPIO6CLR = BIT7; *GPIO2CLR = BIT29 | BIT26 | BIT24; } void TimerTest (void) { Timer_Params.init( &timerParams.); timerParams.arg = 1; timerParams.period = 250; timerParams.Type = Timer_Period_microperiodType; timerParams.runMode = Timer_RunMode_Continuous; timerParams.startMode = Timer_StartMode_user; if (!gTimerHandle) { gTimerHandle = Timer_create (Timer_any、&TimerTestHandler、&timerParams、NULL); } if (gTimerHandle) { timer_stop (gTimerHandle); Timer_setPeriodMicroSecs (gTimerHandle,8); gTestTimerCount = 0; timer_start( gTimerHandle ); } }========================================

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Stanley、

    我终于让原始中断处理程序工作了。 (基于代码示例程序包\ti\cSL\examples\timer\timer_app\main_m4.c)

    全局变量:
      静态易失性 uint32_t gCntValue;
    在定时器启动前初始化为16、因此应该有8个完整周期。

    我知道中断处理程序正在工作、因为 gCntValue 只在处理程序中递减、而 GPIO 线只在处理程序中被操作。 中断向量直接指向此例程-无中间代码。 该例程足够小、因此不会出现高速缓存问题。 此外、没有常规调用。 所有寄存器访问都是内联的。

    我尝试将周期设置为100微秒(TLDR 0xFFFFFF82F 或-2001)和10微秒(TLDR 0xFFFFFF37或-201)。 两者都不接近于请求的间隔时间。 然而,即使是正确的时间,实际的期间和工作周期仍然非常不稳定

    定时器仅在溢出中断时被初始化。 我尝试使用 timer4 (如示例)和 timer10。 结果是一样的。 对于这两个计时器、CM_L4PER_TIMER4_CLKCTRL 和 CM_L4PER_TIMER10_CLKCTRL 为0x00030000、这表示计时器未启用、没有其他任何内容访问计时器。

    请参阅中断处理程序代码(如下所示)和示波器捕获。

    你有什么建议吗?

    通用计时器是否应具有可靠的周期性中断? (即使间隔为1毫秒、实际周期也不稳定。)

    谢谢、
    Scott

    ===========================

    void TimerIsr (void * handle)
    {
    volatile U32 * const irqStatus =(U32 *)(my_timer_base + timer_IRQSTATUS);
    * irqStatus = timer_INT_OVF it_flag;
    
    if (gCntValue)
    --gCntValue;
    
    if ( gCntValue & 1)
    {
    volatile U32 * const GPIO2SET =(U32 *)(GPIO_base + GPIO2 + GPIO_SETDATAOUT);
    
    * GPIO2SET = BIT29 | BIT26 | BIT24;// GPIO2_29、GPIO2_26和 GPIO2_24
    }
    else
    {
    易失性 U32 * const GPIO2CLR =(U32 *)(GPIO_base + GPIO2 + GPIO_CLEARDATAOUT);
    
    *GPIO2CLR = BIT29 | BIT26 | BIT24;
    }
    

    ===========================

    计时器4、请求了100微秒间隔

    计时器4请求10微秒间隔

    计时器10、100微秒

    计时器10、10微秒

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    计时器时钟源是什么? 它由 CM_L4PER_TIMER4_CLKCTRL.CLKSEL 设置。

    默认情况下、它被设置为 SYS_CLK1。 如果是这种情况、您的设计中 SYS_CLK1的时钟频率是多少?

    您是否确定系统中没有其他任何东西可能使计时器功能时钟处于空闲状态、例如、在 A15上运行的 Linux 电源管理?

    另一种可能是 IPU 电源管理... 如果 M4空闲、则必须启用唤醒才能为中断提供服务。

    您是否对 IPU WUGEN_MEVTx 寄存器进行了编程、以启用与计时器中断相关联的 IRQnum 的唤醒功能?

    此致、

    斯坦利

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Stanley、

     

    我检查了计时器时钟源。 CM_L4PER_TIMER4_CLKCTRL 为0x00030000、因此它是 SYS_CLK1、为20MHz。 (XI_osc0连接到20MHz 时钟输入)问题不在于时序。 问题是通用定时器的中断不稳定且不可靠。

     

    系统上不应有任何东西使定时器功能时钟空闲。 A15本身很忙。 我在主应用程序运行时尝试了相同的 IPU 代码。 GPIO 输出无差异。

     

    M4不空闲。 该任务启动计时器、并处于 CPU 循环中、等待全局变量达到零。 (即“while (variable);”)

     

    代码当前未更改 IPU WUGEN_MEVTx。 从 IPU 代码访问0x5508100C 或0x55081010会导致 IPU 崩溃。 这似乎是有意的。 文件\IPC_3_47_02_00\examples\DRA7XX_Linux_elf\ex02_MessageQ\ipu1\IpuAmmu.cfg 使用 MMU 将16K 从0x55080000开始映射到0x40000000。

    这通过命令行进行确认:

    devmem2 0x58880924返回0x40000000

    devmem2 0x588809A4返回0x55080000

    devmem2 0x58880A24返回0x00000003

     

    我尝试访问 IPU_WUGEN 寄存器。 (通常为0x5508??? 但映射到0x4000???) 读取0x40001000、0x40001004、0x40001008、0x4000100C 和0x40001010会得到预期值。 但是、写入这些位置无效。 它们显然是只读的。

     

     

    是否有任何用于初始化通用计时器中断的示例 IPU 代码? (来自 packages/ti\cSL\examples\timer\timer_app\main_m4.c 的代码在 IPU 上崩溃)

    使用看起来是 IPU 专用计时器的示例代码是什么? (IPUx_UNICACHE_SCTM)

     

     

    谢谢、

    Scott

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果 IPU 时钟从未进入空闲状态、则不必担心 WUGEN 寄存器来唤醒 IPU 时钟。

    WUGEN 寄存器通过0x5508xxxx 地址进行访问、因为它是内部 IPU 总线。

    我们通常不会在 Ammu 中重新映射此内容。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    客户对此问题的快速更新。

    客户能够在非 BIOS 上下文中使用来自 IPU 计时器 IPUx_UNCAHE_SCTM 的中断来获得一致的时序。

    该应用程序是使用 SYSBIOS 编写和编译的,但对于时序关键代码,调用 Task_disable()来停止调度程序,以启用 IPU 的确定性操作。

    之后、针对具有主 A15内核的标准 IPC 启用 BIOS。 因为这似乎是一个可行的解决方案、客户可以关闭此主题。

    谢谢!

    Munan