我能够确定、在使用 PRU 编译器 2.3.3 时、使用 DRAM2(ICSS 的 32KB 共享存储器)存在限制。 该工程最初使用了以下内容:
链接器片段
内存:
章节:
.shared_struct > PRU_SHAREDMEM、第 2 页
头文件调用
C 文件
Struct_Data R4、||LDI ||
LDI R4、0
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.
我能够确定、在使用 PRU 编译器 2.3.3 时、使用 DRAM2(ICSS 的 32KB 共享存储器)存在限制。 该工程最初使用了以下内容:
链接器片段
内存:
章节:
.shared_struct > PRU_SHAREDMEM、第 2 页
头文件调用
您好、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、并是的链接器引用
我们将二进制映像加载到 PRU、并是的链接器引用
如果您正在加载 C 程序、您能否查看此帖子中的建议: (+) LP-AM261:以编程方式在 PRU 上加载 C 应用程序时出现的问题(卡在_TI_decompress_lzss 中)-基于 Arm 的微控制器论坛 — 基于 Arm 的微控制器 — TI E2E 支持论坛
您好、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 、并在链接帖子中从变通方法到方法修复了此问题
1)--ram_model vs --rom_model 在我们 5 个月前尝试的初始化中没有什么区别。 没有可靠的时间来解决这个问题、因此我们自己解决了这个问题、并且从那时起就一直在继续我们的解决方案。 我愿意根据我们日常的资源使用经验、在我们的项目中调用额外的 TI 功能。
2) 没有任何 TI 解决方案、我们都尝试在启动时修复堆栈指针 (R2) 填充、这与填充 C28 相同。 我们创造了自己的道路来解决这个问题。
--ram_model 与--rom_model 在初始化方面没有任何区别
是的 — 这不会
没有任何 TI 解决方案我们都尝试过在启动时修复堆栈指针 (R2) 填充
没问题。 有很多方法可以解决这个问题、但 libc init 函数会像链接线程中的客户一样设置堆栈指针。
根据我们日常的资源使用经验、我愿意在我们的项目中调用其他 TI 功能。 [/报价]公平、但没有添加新的 API 来解决此问题。