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.

[参考译文] 关于:AM263P4:如何在 PRU ICSS 共享 RAM 中使用共享存储器区域

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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1589919/re-am263p4-how-to-use-shared-memory-region-in-pru-icss-shared-ram

我能够确定、在使用 PRU 编译器 2.3.3 时、使用 DRAM2(ICSS 的 32KB 共享存储器)存在限制。  该工程最初使用了以下内容:

链接器片段

内存:

第 0 页:
   /* 12KB PRU 指令 RAM */
   PRU_IMEM      :org = 0x00000000 len = 0x00003000

  /* RAM */

  第 1 页:
   /*数据 RAM */
   /* 8KB PRU 数据 RAM 0 */
   PRU0_DMEM_0   :org = 0x00000000 len = 0x00002000 CREGISTER=24
   /* 8KB PRU 数据 RAM 1 */
   PRU0_DMEM_1   :org = 0x00002000 len = 0x00002000 CREGISTER=25

  第 2 页:
   /* C28 需要进行编程以指向 SHAREDMEM、默认值为 0 */
   /*具有 ECC 的 32KB 共享通用存储器 RAM、在 PRU0 和 PRU1 之间共享*/
   PRU_SHAREDMEM  :org = 0x00010000 len = 0x00008000 CREGISTER=28

章节:
.shared_struct > PRU_SHAREDMEM、第 2 页

头文件调用

extern s_shared_structs[NUM_structs] Custom_Struct  __attribute__((section(“.shared_struct")“)) Struct_Data;

C 文件
S_section Custom_Struct(“.shared_struct")“) Struct_Data;


在.asm 文件中这样做的结果为:
Struct_Data R4、||LDI ||
在调试中查看反汇编时、我们看到这一行变为:
LDI R4、0
此后、对 Struct_Data 的任何基准在连接 RAM 时都会使用 R4 和偏移量。  因此、这些变量实际上永远不会使其到达位于 0x00010000 的共享 RAM。
 
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Nathan、

    这是一个有趣的 问题,我还没有尝试自己。 但是、一旦我们确定了情况、我想添加一个演示相关概念的示例。 请告诉我们“工作“代码是什么样子的。

    1) 如果这是多个内核之间的共享存储器区域、我建议定义固定偏移量  

    如果您没有在共享 RAM 中放置任何其他内容、可能没关系、但链接器似乎并不能保证始终以相同的方式对不同的工程放置数据区域。 我建议指定起始地址、类似于以下示例 C linker.cmd 文件中的_c_int00 *强制设置为特定地址的方式: https://github.com/TexasInstruments/open-pru/blob/main/source/linker_cmd/c_code/am263px/AM263px_PRU0.cmd

    (展望未来,我计划在接下来的几周内再对 linker.cmd 文件标签进行一次更改 、使标签更具描述性、然后我将停止修改 OpenPRU 存储库中的所有 linker.cmd 文件)

    2) 如何在 C 代码中定义该段?

    我不确定__ attribute__((section)) 是否是在此使用的正确格式(可能是,这可能是对 https://www.ti.com/lit/spruhv7 中 LOCATION Pragma 的有效使用?) 

    根据对 C 编译器文档的了解、我会首先尝试使用 DATA_SECTION pragma 在 C 中定义数据段:
    https://www.ti.com/lit/spruhv7

    如果您从汇编语言访问、我不确定是否足以定义段、如下所示:
    .sect “.shared_struct"</s>“

    或者、如果您还想使用.cstruct 和.cunion 来确保汇编语言中的结构与 C 中的结构遵循相同的布局。您可以在 PRU 汇编语言工具用户指南 ( https://www.ti.com/lit/ug/spruhv6) 中找到有关这些主题的更多信息 

    此致、

    Nick

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

    确保配置 C28 以进行 SHAREDMEM 访问

    要确认的另一个一点是、您实际上是根据您附加的 linker.cmd 文件中的注释对 C28 进行编程:

    PAGE 2:
          /* C28 needs to be programmed to point to SHAREDMEM, default is 0 */
          /* 32 KB Shared general purpose memory RAM with ECC, shared between PRU0 and PRU1 */

    另一种可能发生的情况是、如果代码 在 SHAREDMEM 内将||0x10000||放置在偏移量 0x0 处(因此 R4 可能是 SHAREDMEM 偏移量)、那么 C 编译器可能会假设已处理共享 Struct_Data 起始地址 0x10000。

    在汇编代码中  

    您可以在 OpenPRU PRU_EMIF 工程中查看一个示例:
    https://github.com/TexasInstruments/open-pru/blob/main/examples/pru_emif/firmware/pru0/main.asm

    ;----------------------------------------------------------------------------
    ;   Constant Table Entries Configuration
    ;   Sample code to configure Constant Table Entries.
    ;----------------------------------------------------------------------------
    ; Configure the Constant Table entry C28 to point to start of shared memory
    ; PRU_ICSSG Shared RAM (local-C28) : 00nn_nn00h, nnnn = c28_pointer[15:0]
    ; By default it is set to 0000_0000h so it will point to DMEM0 address
        ldi     TEMP_REG, 0x0100
        sbco    &TEMP_REG, ICSS_PRU_CTRL_CONST, 0x28, 2

    代码中  

    我想我们没有这方面的例子。 您可以直接写入寄存器 PRU_CTRL_CONSTANT_TABLE_PROG_PTR_0。

    只对直接寄存器写入进行硬编码可能会更容易。 但为了提高透明度、这是我的计划:

    当我为此添加一个示例时、我可能会使用 C 头文件。 我们还没有 AM26x 器件的模块。 我正在与 AM26x 团队核实他们是否计划添加这些元件。 AM26x 和 AM62x 应具有相同的寄存器组、因此您可以将此路径包含在 make 设置中:
    https://github.com/TexasInstruments/open-pru/tree/main/source/include/c_code/am62x 

    然后执行类似的操作(我尚未测试)

    #include <pru_ctrl.h>
    
    ...
    
    /*
     * Configure the Constant Table entry C28 to point to start of shared memory
     * PRU_ICSSG Shared RAM (local-C28) : 00nn_nn00h, nnnn = c28_pointer[15:0]
     * By default it is set to 0000_0000h so it will point to DMEM0 address
     */
    CT_CTRL.CONSTANT_TABLE_PROG_PTR_0_bit.C28_POINTER = 0x100;

    此致、

    Nick

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

    我已经将 C28 的初始化添加到我们开发的自定义代码中。 我们将二进制映像加载到 PRU、并是的链接器引用  

    .text:_c_int00 * >  0x0、PAGE 0  将解析为 .text:_c_int00 _noinit_noargs、这 不会初始化 R2(栈指针)和 C28。 我很想知道、自从您和我上次在 5 个月前的 E2E 帖子 ( e2e.ti.com/.../pru-cgt-c-compiler-for-pru-does-not-initialize-stack-pointer) 中讨论过这个问题以来、这个问题已经得到解决
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引述 userid=“619313" url="“ url="~“~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1587512/am263p4-am263px-icss-ram-mapping-and-access/6123206

    我们将二进制映像加载到 PRU、并是的链接器引用  

    .text:_c_int00 * >  0x0、PAGE 0  将解析为 .text:_c_int00 _noinit_noargs、这 不会初始化 R2(栈指针)
    [/报价]

    如果您正在加载 C 程序、您能否查看此帖子中的建议: (+) LP-AM261:以编程方式在 PRU 上加载 C 应用程序时出现的问题(卡在_TI_decompress_lzss 中)-基于 Arm 的微控制器论坛 — 基于 Arm 的微控制器 — TI E2E 支持论坛

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

    感谢您的答复。 实际上、我们针对 R2 加载问题开发了更好的权变措施、当从 R5 加载 PRU 时、可以在进入 main () 循环之前、将其应用于加载任何寄存器。  

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

    您好、Nathan、

    我不同意 Pratheesh 在链接的回复中的“变通办法“一词。 如果按照 我刚才描述的方式运行(我还没有带宽进行测试)、这不是一种“权变措施“、这将是 TI 支持的标准方法、用于从 MCU+内核初始化 PRU C 代码(除非我们添加可以处理 ELF 二进制文件的 MCU+驱动程序)。

    我仍在研究 PRU Academy 的文档和代码、该文档和代码将正式记录步骤。 这是该页面的当前 AM64x 版本、 因为 AM26x PRU Academy 仍在写入中:

    PRU 入门实验>实验 4:如何初始化 PRU >从 MCU+内核初始化
    https://dev.ti.com/tirex/explore/node?node=A__AWTM5qdKV.bV6igFiAtgFQ__AM64-ACADEMY__WI1KRXP__LATEST

    这是我的 手册、位于“编写 MCU+代码来初始化 PRU 子系统“下方

    工程设置  

    1) 确保_c_int00*像您正在做的那样强制进入 IRAM 的开头(未来的读者,请参阅 AM263Px linker.cmd 文件模板了解 C 代码):
    https://github.com/TexasInstruments/open-pru/blob/main/source/linker_cmd/c_code/am263px/AM263px_PRU0.cmd

    2) 此通用方法应适用于在 PRU 链接器标志中同时传递--ram_model 和--rom_model。 我被告知、如果您加载大量可压缩的数据、rom_model 就有意义、但在我处理过的所有简单项目中、ram_model 都可以更有效地使用内存。

    -- ram_model 表示 DRAM 中的变量是由 R5 内核在加载期间填充的,而不是由 PRU 内核在运行时填充的。

    ram_model 和 rom_model 之间的其他区别:
    *如果使用这些模型进行构建,您可以在 PRU 固件二进制文件的.map 文件中看到数据区域的差异
    *使用--ram_model、DMEM 区域.cinit 将处于未初始化状态、但您将看到 .data 等数据区域已初始化
    *使用--rom_model、DMEM 区域.cinit 将被初始化(如果您实际上有数据要放置在 DRAM 中)、但.data 等数据区域未初始化  

    3) 生成 HEX 数组文件。

    打开 hex 数组文件时、您应该会看到多个数据数组、其中每个数组对应 linker.cmd 文件中定义的每一页。 在我的测试中、看起来它按页面顺序排列。 因此、第一个数组是 PAGE 0 (IMEM)、后面的数组应该用于 PAGE 1(在我们的当前 linker.cmd 示例中为 DMEM0/DMEM1)和 PAGE 2 (PRU_SHAREDMEM)。 如果没有任何数据被 R5 加载到存储器区域中、则不会生成数组。

    假设 PRU0 有数据要加载到 DMEM0 中、且数据数组称为 PRU0Firmware_1(而 IMEM 阵列为 PRU0Firmware_0)。

    4) 使用 PRUICSS_writeMemory 加载数据

    目前、我的 empty_c 示例使用 PRUICSS_loadFirmware、它不加载 DMEM:
    https://github.com/TexasInstruments/open-pru/blob/main/examples/empty_c/mcuplus/empty_example.c

    因此、我们希望用手动步骤替换它、如在 MCU+ SDK 文档中:
    https://software-dl.ti.com/mcu-plus-sdk/esd/AM64X/latest/exports/docs/api_guide_am64x/DRIVERS_PRUICSS_PAGE.html

        /* Reset and disable PRU core */
        PRUICSS_resetCore(gPruicssHandle, PRUICSS_PRU0);
        PRUICSS_disableCore(gPruicssHandle, PRUICSS_PRU0);
     
        /* Register an Interrupt Handler for an event */
        PRUICSS_registerIrqHandler(gPruicssHandle,
                                   pruEvtoutNum,
                                   intrNum,
                                   eventNum,
                                   waitEnable,
                                   irqHandler);
     
     
        /* API to do Interrupt-Channel-host mapping */
        PRUICSS_intcInit(gPruicssHandle, &pruicssIntcInitData);
     
        /* Load the IRAM in PRU */
        PRUICSS_writeMemory(gPruicssHandle,
                            PRUICSS_IRAM_PRU(0),
                            0,
                            (uint32_t *) pruFirmware,
                            pruFirmwareLength);
        /* Enable PRU */
        PRUICSS_enableCore(gPruicssHandle, PRUICSS_PRU0);

    但我们还需要添加第二个 PRUICSS_writeMemory 命令来加载 DMEM。 我们有 PRU 句柄、 由于我们正在加载 DMEM0、我们将传递内存区域 PRUICSS_DataRAM (0)。 但现在您需要知道字偏移量和数据数组的大小。

    数据数组不会用零填充。 因此您需要知道失调电压。  此时、我不确定是否有比检查.map 文件更好的方法来查看此信息。

    以此.map 文件为例。 让我们来看看第 1 页/ array1 中的数据

    SECTION ALLOCATION MAP
    
     output                                  attributes/
    section   page    origin      length       input sections
    --------  ----  ----------  ----------   ----------------
    ...
    .bss       1    00000000    000001f0     UNINITIALIZED
                      00000000    000001f0     (.common:payload)
    
    .stack     1    000001f0    00000100     UNINITIALIZED
                      000001f0    00000004     rtspruv3_le.lib : boot.c.obj (.stack)
                      000001f4    000000fc     --HOLE--
    
    .cinit     1    00000000    00000000     UNINITIALIZED
    
    .rodata    1    00000348    0000000c
                      00000348    0000000c     main.obj (.rodata:.string)
    
    .resource_table
    *          1    000002f0    00000058
                      000002f0    00000058     main.obj (.resource_table:retain)
    
    

    因此 0x0 - 0x2F0 是未初始化的数据 (.bss、.stack)
    初始化的数据从 0x2F0 开始、大小为 0x58 + 0xC (.resource_table &.rodata)

    FYI:不支持的边线外壳

    如果 PRU0 使用 DMEM0、PRU1 使用 DMEM1、则此方法很有效。 但是、如果 PRU 内核同时使用 DMEM0 和 DMEM1、那么我们当前的 linker.cmd 文件示例效果不佳(对于 PRU0、十六进制数组文件大于所需的值、对于 PRU1,我希望它甚至不起作用)。 如果您需要将数据加载到 DMEM0 和 DMEM1 中、我建议将 linker.cmd 文件拆分为 2 个不同的页面、然后对 PRUICSS_writeMemory 进行 2 个单独的调用、以将每个单独的数组加载到每个 DMEM 实例中。

    待解决的问题:

    1)- ram_model 与 — rom_model 在栈指针初始化方面有何不同?

    2) 这些步骤是否真的适用于您的项目,或者您是否看到了问题?

    此致、

    Nick

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

    我完全同意 Nick Saulnier 、并在链接帖子中从变通方法到方法Slight smile修复了此问题

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

    1)--ram_model vs --rom_model 在我们 5 个月前尝试的初始化中没有什么区别。 没有可靠的时间来解决这个问题、因此我们自己解决了这个问题、并且从那时起就一直在继续我们的解决方案。 我愿意根据我们日常的资源使用经验、在我们的项目中调用额外的 TI 功能。  

    2) 没有任何 TI 解决方案、我们都尝试在启动时修复堆栈指针 (R2) 填充、这与填充 C28 相同。 我们创造了自己的道路来解决这个问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    --ram_model 与--rom_model 在初始化方面没有任何区别

    是的 — 这不会

    没有任何 TI 解决方案我们都尝试过在启动时修复堆栈指针 (R2) 填充

    没问题。 有很多方法可以解决这个问题、但 libc init 函数会像链接线程中的客户一样设置堆栈指针。

    根据我们日常的资源使用经验、我愿意在我们的项目中调用其他 TI 功能。  [/报价]

    公平、但没有添加新的 API 来解决此问题。