Skip to content

am243x: add pru-eqep example - #149

Closed
a1248924 wants to merge 0 commit into
mainfrom
a1248924_EQEP
Closed

am243x: add pru-eqep example#149
a1248924 wants to merge 0 commit into
mainfrom
a1248924_EQEP

Conversation

@a1248924

@a1248924 a1248924 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Signed-off-by: Ayushman a-ayushman@ti.com

@qodo-code-review

qodo-code-review Bot commented Jul 3, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (7) 📘 Rule violations (4) 📜 Skill insights (0)

Grey Divider


Action required

1. sbbo before buffer bounds 📘 Rule violation ⛨ Security
Description
sbbo &time_stamp, DMEM0, buffer_addr, 4 stores to DMEM using buffer_addr before verifying that
buffer_addr + 4 stays within buffer_size, and the wrap check only triggers on `buffer_addr >
buffer_size (allowing buffer_addr == buffer_size`). This can write past the intended buffer end
and corrupt adjacent PRU memory.
Code

examples/pru_eqep/firmware/main.asm[R122-129]

+    sbbo    &time_stamp, DMEM0, buffer_addr, 4
+    sbco    &buffer_addr, DMEM1, WRITE_PTR_OFFSET, 2
+    sbco    &QPOS, DMEM1, CH_POS_OFFSET, 4
+
+    ; Handle buffer wrap-around
+    qbgt    no_buffer_wrap, buffer_addr, buffer_size
+    ldi     buffer_addr, 0
+    ldi     READ_POS_BUFF, 0
Evidence
PR Compliance ID 1 requires bounds checks before memory accesses and specifically calls out
offset+size validation. In main.asm, a 4-byte store uses buffer_addr before the wrap/bounds
logic, and the wrap condition (qbgt) does not prevent buffer_addr == buffer_size, enabling an
out-of-bounds write.

examples/pru_eqep/firmware/main.asm[122-129]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PRU firmware writes a 4-byte timestamp to `DMEM0 + buffer_addr` before ensuring `buffer_addr` is within the valid buffer range, and the wrap condition allows `buffer_addr == buffer_size`.

## Issue Context
Compliance requires bounds checks for memory accesses, including validating `offset + size` against named limits.

## Fix Focus Areas
- examples/pru_eqep/firmware/main.asm[122-129]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Direct .asg register aliases 📘 Rule violation ⚙ Maintainability
Description
The new PRU assembly include uses extensive direct register aliasing via .asg instead of
.struct/.sassign. This increases risk of register overlap/corruption and makes calling/register
conventions harder to audit.
Code

examples/pru_eqep/firmware/include/memory.inc[R33-49]

+    .asg   r0,     scratch
+    .asg   r1,     scratch2
+    .asg   r17.b0, curr_gpi_sample  ; Current GPI state after masking
+    .asg   r17.b1, A_B_Z_edge       ; Edge detection for A,B,Z signals
+    .asg   r18,    curr_ts          ; Timestamp counter
+    .asg   r19.b0, edge             ; Edge detection
+    .asg   r20.b0, prev_sample      ; Previous state of A,B,Z signals
+    .asg   r21,    time_stamp       ; Time stamp counter
+    .asg   r22.w0, buffer_addr      ; Buffer address pointer
+    .asg   r22.w2, buffer_size      ; Buffer size
+    .asg   r23,    wr_ptr           ; Write pointer
+    .asg   r24.w0, READ_POS_BUFF    ; Read position buffer
+    .asg   r24.w2, read_pos_speed_intr ; Read position speed interrupt
+    .asg   r26.b0, a_b_transition   ; A/B transition state
+    .asg   r26.b1, qpos_update      ; 2-> QPOS--, 1-> QPOS++, 0-> no change
+    .asg   r27,    QPOS             ; Position counter
+    .asg   r28,    DMEM0            ; Data memory pointer
Evidence
PR Compliance ID 6 requires new/updated PRU assembly to prefer .struct/.sassign over direct
aliasing. The added memory.inc defines most register usage using .asg (e.g., scratch,
buffer_addr, QPOS), meeting the failure criteria for direct register aliasing.

examples/pru_eqep/firmware/include/memory.inc[33-49]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PRU assembly register map is implemented with many `.asg` aliases, contrary to the preferred `.struct`/`.sassign` pattern.

## Issue Context
The compliance rule requires structured register allocation to reduce overlap/corruption risk and improve maintainability.

## Fix Focus Areas
- examples/pru_eqep/firmware/include/memory.inc[33-49]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. readme.md wrong empty path 📘 Rule violation ≡ Correctness
Description
The README references <open-pru/examples/empty/firmware/device/>, which does not match this
example’s actual location and can mislead users. The same section also contains extremely long
markdown lines, reducing portability/readability in rendered views and diffs.
Code

examples/pru_eqep/readme.md[R20-23]

+- **When using CCS projects to build**, import the CCS project from the above mentioned Example folder path for R5F and PRU, After this `main.asm`, `linker.cmd` files gets copied to ccs workspace of PRU project. The `main.asm` contains sample code to halt PRU program
+
+     - Build the PRU project using the CCS project menu (see [for AM64x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM64X/latest/exports/docs/api_guide_am64x/CCS_PROJECTS_PAGE.html), [for AM243x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM243X/latest/exports/docs/api_guide_am243x/CCS_PROJECTS_PAGE.html), [for AM261x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM261X/latest/exports/docs/api_guide_am261x/CCS_PROJECTS_PAGE.html), [for AM263x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM263X/latest/exports/docs/api_guide_am263x/CCS_PROJECTS_PAGE.html), [for AM263Px](https://software-dl.ti.com/mcu-plus-sdk/esd/AM263PX/latest/exports/docs/api_guide_am263px/CCS_PROJECTS_PAGE.html)).
+          - Build Flow: Once you click on build in PRU project, firmware header file which is generated in release or debug folder of ccs workspace, is moved to  `<open-pru/examples/empty/firmware/device/>`
Evidence
PR Compliance ID 13 requires repository path references in docs to match the on-disk layout; the
README points to examples/empty despite this being the pru_eqep example. PR Compliance ID 15
requires respecting markdown line-length limits; the same section contains very long single-line
link text and prose.

examples/pru_eqep/readme.md[20-23]
Best Practice: Learned patterns
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new README contains an incorrect repository path reference (points to `examples/empty` instead of `examples/pru_eqep`) and includes very long single-line markdown content.

## Issue Context
Incorrect path references break portability/usability of docs, and overly long markdown lines violate documentation formatting expectations.

## Fix Focus Areas
- examples/pru_eqep/readme.md[20-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (6)
4. Asm file included by make 🐞 Bug ≡ Correctness
Description
The PRU0 firmware makefile uses GNU make include to include memory.inc, but that file contains
assembly syntax (e.g., ; comments and .asg) and will be parsed as make syntax, causing the build
to fail.
Code

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile[R31-34]

+# pru_rules.mak has shared settings for all PRU/RTU/TX_PRU core makefiles
+include $(OPEN_PRU_PATH)/pru_rules.mak
+include $(OPEN_PRU_PATH)/examples/pru_eqep/firmware/include/memory.inc
+# Optional:
Evidence
The makefile explicitly includes memory.inc, and memory.inc begins with ; and assembly
directives which are not valid makefile syntax, so make will error when trying to parse it.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile[31-38]
examples/pru_eqep/firmware/include/memory.inc[1-8]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile` includes an assembly `.inc` file via make's `include`, which will break parsing and stop the build.

### Issue Context
`memory.inc` is meant to be included by the PRU assembler (via `.include` in `main.asm` or via compiler include paths), not by `make`.

### Fix Focus Areas
- Remove the `include $(OPEN_PRU_PATH)/examples/pru_eqep/firmware/include/memory.inc` line.
- Ensure the assembler can still find `memory.inc` via `INCLUDE += --include_path=...`.

### Fix Focus Areas (code references)
- examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile[31-38]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Wrong GPI byte sampled 🐞 Bug ≡ Correctness
Description
memory.inc defines cur_sample as r31.b0 for PRU0/PRU1 and TX_PRU cores, but those cores should
sample GPIs from r31.b1 and r31.b2 respectively; the firmware will read incorrect A/B/Z inputs
and compute wrong position/speed.
Code

examples/pru_eqep/firmware/include/memory.inc[R51-58]

+; Define cur_sample based on core type
+    .if $isdefed("RTU_PRU0") | $isdefed("RTU_PRU1")
+        .asg   r31.b0, cur_sample   ; Use byte0 for GPIs 0-7
+    .elseif $isdefed("PRU0") | $isdefed("PRU1")
+        .asg   r31.b0, cur_sample   ; Use byte1 for GPIs 8-15
+    .elseif $isdefed("TX_PRU0") | $isdefed("TX_PRU1")
+        .asg   r31.b0, cur_sample   ; Use byte2 for GPIs 16-19
+    .endif
Evidence
The implementation maps PRU0/PRU1 and TX_PRU cores to r31.b0, while the file’s own guide states
PRU cores must use r31.b1 and TX_PRU cores must use r31.b2.

examples/pru_eqep/firmware/include/memory.inc[51-58]
examples/pru_eqep/firmware/include/memory.inc[154-167]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`cur_sample` is aliased to the wrong r31 byte for PRU and TX_PRU cores, so the firmware polls the wrong GPI bits.

### Issue Context
The same file documents the intended mapping (b0 for GPIs 0-7, b1 for 8-15, b2 for 16-19), but the implementation always uses `r31.b0`.

### Fix Focus Areas
- Use `r31.b1` for `PRU0`/`PRU1`.
- Use `r31.b2` for `TX_PRU0`/`TX_PRU1`.

### Fix Focus Areas (code references)
- examples/pru_eqep/firmware/include/memory.inc[51-58]
- examples/pru_eqep/firmware/include/memory.inc[154-167]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Buffer wrap condition reversed 🐞 Bug ≡ Correctness
Description
In main.asm, the wrap check qbgt no_buffer_wrap, buffer_addr, buffer_size causes the code to
take the wrap-around path whenever buffer_addr <= buffer_size, so buffer_addr is repeatedly
reset and the normal increment path is skipped.
Code

examples/pru_eqep/firmware/main.asm[R126-129]

+    ; Handle buffer wrap-around
+    qbgt    no_buffer_wrap, buffer_addr, buffer_size
+    ldi     buffer_addr, 0
+    ldi     READ_POS_BUFF, 0
Evidence
The branch guards the wrap reset, while the increment occurs only in the no_buffer_wrap block;
with buffer_addr starting at 0, the current condition falls through to the wrap reset and never
reaches the increment path.

examples/pru_eqep/firmware/main.asm[120-130]
examples/pru_eqep/firmware/main.asm[156-159]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The PRU ring-buffer wrap logic branches incorrectly, so the firmware resets the buffer pointers at the wrong time.

### Issue Context
The increment of `buffer_addr` happens in `no_buffer_wrap`, but the current branch condition makes it unreachable for normal values (e.g., `buffer_addr` starts at 0).

### Fix Focus Areas
- Change the comparison so that `no_buffer_wrap` is taken when `buffer_addr < buffer_size` (or when `buffer_addr` is within bounds).
- Ensure wrap occurs only when the next write would exceed the buffer (>= size).

### Fix Focus Areas (code references)
- examples/pru_eqep/firmware/main.asm[126-130]
- examples/pru_eqep/firmware/main.asm[156-159]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Mask used as register offset 🐞 Bug ≡ Correctness
Description
ABZ_enable_load_share_mode() adds *_MASK constants to the PRU CFG base pointer when reading the
EDPRU TX CFG register, but those constants are bitmasks (e.g., 0x10) rather than register offsets
(e.g., 0xE4/0x104), so it reads the wrong address and may misconfigure load-share mode.
Code

examples/pru_eqep/mcuplus/pru_eqep_example.c[R569-583]

+void ABZ_enable_load_share_mode(void *pruCfg, uint32_t pruSlice)
+{
+    uint32_t regVal;
+    if(pruSlice == 1)
+    {
+        regVal = HW_RD_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU1TXCFGREGISTER_PRU1_ED_TX_CLK_SEL_MASK);
+        regVal |= CSL_ICSSCFG_EDPRU1TXCFGREGISTER_PRU1_ENDAT_SHARE_EN_MASK;
+        HW_WR_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU1TXCFGREGISTER, regVal);
+    }
+    else
+    {
+        regVal = HW_RD_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU0TXCFGREGISTER_PRU0_ED_TX_CLK_SEL_MASK);
+        regVal |= CSL_ICSSCFG_EDPRU0TXCFGREGISTER_PRU0_ENDAT_SHARE_EN_MASK;
+        HW_WR_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU0TXCFGREGISTER, regVal);
+    }
Evidence
The host code uses *_MASK macros as pointer offsets, but the CSL header shows those macros are bit
masks while the register offsets are separate macros (0xE4/0x104).

examples/pru_eqep/mcuplus/pru_eqep_example.c[569-583]
source/include/am243x/cslr_icss_g.h[13069-13071]
source/include/am243x/cslr_icss_g.h[14785-14789]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The code reads a PRU CFG register using a bitmask macro as if it were a register offset, so the value read is from the wrong location.

### Issue Context
`CSL_ICSSCFG_EDPRU1TXCFGREGISTER_PRU1_ED_TX_CLK_SEL_MASK` is 0x10 (mask), while `CSL_ICSSCFG_EDPRU1TXCFGREGISTER` is 0x104 (offset). The same pattern exists for PRU0.

### Fix Focus Areas
- Replace the `HW_RD_REG32(base + *_MASK)` reads with `HW_RD_REG32(base + CSL_ICSSCFG_EDPRU{0,1}TXCFGREGISTER)`.
- Keep using the `*_ENDAT_SHARE_EN_MASK` bitmask when setting/clearing bits in the read value.

### Fix Focus Areas (code references)
- examples/pru_eqep/mcuplus/pru_eqep_example.c[569-583]
- source/include/am243x/cslr_icss_g.h[13069-13071]
- source/include/am243x/cslr_icss_g.h[14785-14789]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Position base uses CH0 offset 🐞 Bug ≡ Correctness
Description
All six channels set position_base using CH0_POSITION_OFFSET, ignoring the distinct offsets
defined for channels 1-5, so channels 1-5 will read the wrong position value and report incorrect
direction/position.
Code

examples/pru_eqep/mcuplus/pru_eqep_example.c[R317-322]

+    ABZHandle[0]->position_base = (void *)((uint32_t)(ABZHandle[0]->baseMemAddr1) + CH0_POSITION_OFFSET);
+    ABZHandle[1]->position_base = (void *)((uint32_t)(ABZHandle[1]->baseMemAddr1) + CH0_POSITION_OFFSET);
+    ABZHandle[2]->position_base = (void *)((uint32_t)(ABZHandle[2]->baseMemAddr1) + CH0_POSITION_OFFSET);
+    ABZHandle[3]->position_base = (void *)((uint32_t)(ABZHandle[3]->baseMemAddr1) + CH0_POSITION_OFFSET);
+    ABZHandle[4]->position_base = (void *)((uint32_t)(ABZHandle[4]->baseMemAddr1) + CH0_POSITION_OFFSET);
+    ABZHandle[5]->position_base = (void *)((uint32_t)(ABZHandle[5]->baseMemAddr1) + CH0_POSITION_OFFSET);
Evidence
The code assigns CH0_POSITION_OFFSET for all channels, while the file defines unique offsets per
channel; this guarantees that channels 1–5 read the wrong address.

examples/pru_eqep/mcuplus/pru_eqep_example.c[67-73]
examples/pru_eqep/mcuplus/pru_eqep_example.c[317-322]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`position_base` is initialized with the same offset for every channel, even though each channel has a different position offset.

### Issue Context
The file defines `CH1_POSITION_OFFSET` ... `CH5_POSITION_OFFSET`, but they are not used when setting `ABZHandle[i]->position_base`.

### Fix Focus Areas
- Set `position_base` for each channel using the matching `CHx_POSITION_OFFSET`.
- Optionally use a small lookup array to avoid repetitive code.

### Fix Focus Areas (code references)
- examples/pru_eqep/mcuplus/pru_eqep_example.c[67-73]
- examples/pru_eqep/mcuplus/pru_eqep_example.c[317-322]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. mem_limit scaled by channel 🐞 Bug ≡ Correctness
Description
mem_limit is computed as DMEM_CHANNEL_SIZE*i + DMEM_CHANNEL_SIZE, but the PRU firmware write
pointer (buffer_addr) is a per-channel offset that wraps to 0; for channels >0 this inflates
wrap-around edge counts and produces incorrect speed.
Code

examples/pru_eqep/mcuplus/pru_eqep_example.c[R309-314]

+        ABZHandle[i]->QPOSCOUNT = 0;
+        ABZHandle[i]->read_ptr = ABZHandle[i]->baseMemAddr0;
+        ABZHandle[i]->write_ptr = ABZHandle[i]->baseMemAddr1;
+        ABZHandle[i]->mem_limit=(DMEM_CHANNEL_SIZE)*(i) + DMEM_CHANNEL_SIZE;
+        if(i<3) ABZHandle[i]->pru_slice=0;
+        else ABZHandle[i]->pru_slice=1;
Evidence
The host’s wrap calculation uses mem_limit as the end of the ring buffer, but firmware resets the
write pointer to 0 on wrap; scaling mem_limit by channel index therefore over-counts edges for
channels >0.

examples/pru_eqep/mcuplus/pru_eqep_example.c[294-316]
examples/pru_eqep/mcuplus/pru_eqep_example.c[485-510]
examples/pru_eqep/firmware/main.asm[126-130]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Speed calculation uses `mem_limit` as the buffer end when the write pointer wraps, but `mem_limit` is incorrectly made larger for higher channel indices.

### Issue Context
`EQEP_Get_Speed_ABZ()` uses `mem_limit` only as an upper bound for `(mem_limit - read_ptr_offset + write_ptr_offset)` when `read_ptr_offset > write_ptr_offset` (wrap case). Since firmware resets `buffer_addr` back to 0 on wrap, `mem_limit` must be the fixed per-channel buffer size.

### Fix Focus Areas
- Change `ABZHandle[i]->mem_limit` to `DMEM_CHANNEL_SIZE` (or the correct per-channel buffer size constant), not scaled by `i`.
- Ensure the host-side buffer size constant matches the firmware’s `MAX_BUFFER`/wrap behavior.

### Fix Focus Areas (code references)
- examples/pru_eqep/mcuplus/pru_eqep_example.c[294-316]
- examples/pru_eqep/mcuplus/pru_eqep_example.c[485-510]
- examples/pru_eqep/firmware/main.asm[126-130]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

10. Long postBuildStep command line 📘 Rule violation ⚙ Maintainability
Description
New .projectspec files embed long command strings in a single line (for example,
postBuildStep=...), which harms readability and violates the repository’s configuration
line-length expectations. This makes future edits and reviews error-prone.
Code

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/example.projectspec[R55-57]

+        postBuildStep="
+            $(CG_TOOL_ROOT)/bin/hexpru --diag_wrap=off --array --array:name_prefix=PRU0Firmware -o ../pru0_load_bin.h ${BuildArtifactFileBaseName}.out;
+        "
Evidence
PR Compliance ID 17 requires long command-like attributes in config files to be wrapped/reflowed
where feasible. The added postBuildStep entries are long single lines in multiple new
.projectspec files, matching the failure criteria.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/example.projectspec[55-57]
examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec[70-70]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Project configuration includes very long single-line command attributes (notably `postBuildStep`), reducing maintainability and violating line-length guidance.

## Issue Context
The compliance rule requests wrapping/reflowing long command-like attributes where feasible.

## Fix Focus Areas
- examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/example.projectspec[55-57]
- examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec[70-70]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. Spin loop inside ISR 🐞 Bug ☼ Reliability
Description
Each PRU host interrupt ISR busy-waits in a tight while (...) ; loop until the PRU updates the
write pointer; if the PRU stalls or the pointer never changes, the ISR can run indefinitely and
block other interrupts/tasks.
Code

examples/pru_eqep/mcuplus/pru_eqep_example.c[R394-401]

+    if (!(ABZHandle[0]->write_ptr_offset == (HW_RD_REG32(ABZHandle[0]->baseMemAddr1) & WRITE_PTR_OFFSET_MASK)))
+    {
+        EQEP_Get_Speed_ABZ(0);
+    }
+    else
+    {
+        while (ABZHandle[0]->write_ptr_offset == (HW_RD_REG32(ABZHandle[0]->baseMemAddr1) & WRITE_PTR_OFFSET_MASK));
+        EQEP_Get_Speed_ABZ(0);
Evidence
The ISR code contains a tight polling loop with no timeout, which is unsafe in Hwi context and can
prevent forward progress under fault conditions.

examples/pru_eqep/mcuplus/pru_eqep_example.c[389-420]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The interrupt handlers contain an unbounded spin-wait, which can lock the CPU in interrupt context.

### Issue Context
The ISR currently retries until `write_ptr_offset` changes. In failure modes (PRU halted, missed update, misconfigured mapping) this never terminates.

### Fix Focus Areas
- Avoid waiting inside the ISR; instead, read once and compute if data progressed, or defer work to a task.
- If waiting is necessary, add a bounded retry/timeout and record an error condition.

### Fix Focus Areas (code references)
- examples/pru_eqep/mcuplus/pru_eqep_example.c[389-420]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Jul 3, 2026

Copy link
Copy Markdown

PR Summary by Qodo

am243x: add PRU-based eQEP (ABZ) example

✨ Enhancement ⚙️ Configuration changes 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Add pru_eqep example emulating eQEP (ABZ) via PRU-ICSS on AM243x LaunchPad.
• Provide PRU/RTU/TX firmware projects plus R5F FreeRTOS host app to load and read data.
• Integrate example into examples build and document CCS/makefile build-and-run flow.
Diagram

graph TD
  A["examples/makefile"] --> B["examples/pru_eqep/makefile"] --> C["PRU firmware (ASM)"]
  C --> D["FW headers (.h)"] --> E["R5F FreeRTOS app"] --> F["PRUICSS + INTC"]
  G{{"ABZ signals"}} --> C --> H[("PRU DMEM/shared")]
  H --> E
  F -. "PRU events 16-21" .-> E

  subgraph Legend
    direction LR
    _proc["Build/Code"] ~~~ _ext{{"External"}} ~~~ _mem[("Memory")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Single parameterized PRU firmware project
  • ➕ Reduces duplication across 6 nearly-identical ti-pru-cgt projectspec/makefile/linker sets
  • ➕ Simplifies maintenance when memory maps or build flags change
  • ➕ Easier to add more boards/ICSS instances
  • ➖ Harder to represent cleanly in CCS import flow (separate cores/projects are straightforward)
  • ➖ May complicate postBuildStep header generation (different name_prefix/output paths per core)
2. Use PRU C firmware instead of assembly
  • ➕ Improves readability and onboarding for users extending the example
  • ➕ Potentially easier unit-level testing and reuse across devices
  • ➖ Harder to guarantee cycle-accurate polling/latency at high edge rates
  • ➖ May increase code size and risk of compiler-induced timing variability

Recommendation: The PR’s approach (separate PRU/RTU/TX projects + host loader) is appropriate for a reference example because it mirrors how users import/build per-core firmware in CCS and keeps core-specific memory maps explicit. Consider a follow-up refactor to template/parameterize the repeated PRU project scaffolding if this example will be expanded to more devices/boards.

Files changed (38) +3460 / -1

Enhancement (5) +1183 / -0
memory.incShared PRU register/constants mapping for ABZ capture +167/-0

Shared PRU register/constants mapping for ABZ capture

• Defines register assignments, per-core GPI selection/masks, DMEM offsets, and interrupt masks shared by the PRU firmware across PRU/RTU/TX cores.

examples/pru_eqep/firmware/include/memory.inc

main.asmPRU assembly firmware implementing high-speed ABZ edge capture +188/-0

PRU assembly firmware implementing high-speed ABZ edge capture

• Implements a polling loop that detects A/B/Z transitions, timestamps edges using the PRU cycle counter, updates a QPOS counter via a LUT, and signals host interrupts when buffers reach thresholds.

examples/pru_eqep/firmware/main.asm

main.cFreeRTOS entrypoint wiring to pru_eqep example +84/-0

FreeRTOS entrypoint wiring to pru_eqep example

• Adds a standard MCU+ FreeRTOS main that initializes the system/board and runs pru_eqep_example_main in a high-priority task.

examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/main.c

eqep_diagnostic.hABZ diagnostic data structures and state definitions +139/-0

ABZ diagnostic data structures and state definitions

• Defines ABZ handle/config structures and state enums used by the host diagnostic/control logic.

examples/pru_eqep/mcuplus/eqep_diagnostic.h

pru_eqep_example.cHost-side PRU firmware loader + ISR-driven speed/position reporting +605/-0

Host-side PRU firmware loader + ISR-driven speed/position reporting

• Implements PRUICSS initialization, load-share enablement, firmware loading for PRU/RTU/TX cores, INTC ISR registration for six channels, and routines to compute speed/direction/position from PRU DMEM buffers.

examples/pru_eqep/mcuplus/pru_eqep_example.c

Documentation (1) +39 / -0
readme.mdDocumentation for building and running the PRU eQEP example +39/-0

Documentation for building and running the PRU eQEP example

• Documents supported combinations and step-by-step instructions for building via CCS projects or makefiles, including PRU-CGT prerequisites and firmware header usage.

examples/pru_eqep/readme.md

Other (32) +2238 / -1
makefileRegister pru_eqep as a buildable example +1/-1

Register pru_eqep as a buildable example

• Adds the new pru_eqep subdirectory to the examples build list so it is built with the existing examples workflow.

examples/makefile

example.projectspecCCS projectspec for ICSSG0 PRU0 firmware +82/-0

CCS projectspec for ICSSG0 PRU0 firmware

• Introduces a CCS project specification for building PRU0 assembly firmware and emitting a hexpru-generated header image.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/example.projectspec

linker.cmdLinker memory map for AM243x ICSSG0 PRU0 +52/-0

Linker memory map for AM243x ICSSG0 PRU0

• Defines the PRU0 instruction/data memory layout and section placement for the assembly firmware build.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/linker.cmd

makefileMakefile for PRU0 firmware build and header export +48/-0

Makefile for PRU0 firmware build and header export

• Adds a ti-pru-cgt build makefile that uses shared pru_rules.mak and exports the generated pru0_load_bin.h to the example firmware folder.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile

makefile_projectspecCCS Eclipse build/export wrapper for PRU0 project +16/-0

CCS Eclipse build/export wrapper for PRU0 project

• Provides targets to build/clean/export the PRU0 CCS project via CCS headless eclipse tooling.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile_projectspec

example.projectspecCCS projectspec for ICSSG0 PRU1 firmware +82/-0

CCS projectspec for ICSSG0 PRU1 firmware

• Adds PRU1 CCS project configuration for assembly firmware and post-build header generation.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru1_fw/ti-pru-cgt/example.projectspec

linker.cmdLinker memory map for AM243x ICSSG0 PRU1 +52/-0

Linker memory map for AM243x ICSSG0 PRU1

• Defines PRU1 instruction/data memory regions and section placements aligned with slice1 usage.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru1_fw/ti-pru-cgt/linker.cmd

makefileMakefile for PRU1 firmware build and header export +49/-0

Makefile for PRU1 firmware build and header export

• Adds build rules for PRU1 firmware and exports the generated pru1_load_bin.h into the example firmware directory.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru1_fw/ti-pru-cgt/makefile

makefile_projectspecCCS Eclipse build/export wrapper for PRU1 project +16/-0

CCS Eclipse build/export wrapper for PRU1 project

• Adds headless CCS build/clean/export targets for the PRU1 CCS project.

examples/pru_eqep/firmware/am243x-lp/icss_g0_pru1_fw/ti-pru-cgt/makefile_projectspec

example.projectspecCCS projectspec for ICSSG0 RTU PRU0 firmware +82/-0

CCS projectspec for ICSSG0 RTU PRU0 firmware

• Adds RTU0 CCS project configuration to build assembly firmware and generate rtupru0_load_bin.h.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru0_fw/ti-pru-cgt/example.projectspec

linker.cmdLinker memory map for AM243x ICSSG0 RTU0 +52/-0

Linker memory map for AM243x ICSSG0 RTU0

• Defines RTU instruction RAM and data RAM section placement for the RTU PRU0 firmware build.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru0_fw/ti-pru-cgt/linker.cmd

makefileMakefile for RTU PRU0 firmware build and header export +49/-0

Makefile for RTU PRU0 firmware build and header export

• Adds ti-pru-cgt build rules for RTU0 firmware and exports rtupru0_load_bin.h to the example firmware path.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru0_fw/ti-pru-cgt/makefile

makefile_projectspecCCS Eclipse build/export wrapper for RTU0 project +16/-0

CCS Eclipse build/export wrapper for RTU0 project

• Adds CCS headless build/clean/export targets for the RTU PRU0 project.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru0_fw/ti-pru-cgt/makefile_projectspec

example.projectspecCCS projectspec for ICSSG0 RTU PRU1 firmware +82/-0

CCS projectspec for ICSSG0 RTU PRU1 firmware

• Adds RTU1 CCS project configuration to build assembly firmware and generate rtupru1_load_bin.h.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru1_fw/ti-pru-cgt/example.projectspec

linker.cmdLinker memory map for AM243x ICSSG0 RTU1 +52/-0

Linker memory map for AM243x ICSSG0 RTU1

• Defines RTU1 instruction RAM and data RAM section placement for slice1 RTU firmware.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru1_fw/ti-pru-cgt/linker.cmd

makefileMakefile for RTU PRU1 firmware build and header export +49/-0

Makefile for RTU PRU1 firmware build and header export

• Adds ti-pru-cgt build rules for RTU1 firmware and exports rtupru1_load_bin.h into the example firmware directory.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru1_fw/ti-pru-cgt/makefile

makefile_projectspecCCS Eclipse build/export wrapper for RTU1 project +16/-0

CCS Eclipse build/export wrapper for RTU1 project

• Adds CCS headless build/clean/export targets for the RTU PRU1 project.

examples/pru_eqep/firmware/am243x-lp/icss_g0_rtu_pru1_fw/ti-pru-cgt/makefile_projectspec

example.projectspecCCS projectspec for ICSSG0 TX PRU0 firmware +82/-0

CCS projectspec for ICSSG0 TX PRU0 firmware

• Adds TX_PRU0 CCS project configuration to build assembly firmware and generate txpru0_load_bin.h.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru0_fw/ti-pru-cgt/example.projectspec

linker.cmdLinker memory map for AM243x ICSSG0 TX_PRU0 +52/-0

Linker memory map for AM243x ICSSG0 TX_PRU0

• Defines TX PRU instruction RAM size and maps sections to the appropriate TX_PRU0 DMEM partition.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru0_fw/ti-pru-cgt/linker.cmd

makefileMakefile for TX PRU0 firmware build and header export +49/-0

Makefile for TX PRU0 firmware build and header export

• Adds ti-pru-cgt build rules for TX_PRU0 firmware and exports txpru0_load_bin.h to the example firmware directory.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru0_fw/ti-pru-cgt/makefile

makefile_projectspecCCS Eclipse build/export wrapper for TX_PRU0 project +16/-0

CCS Eclipse build/export wrapper for TX_PRU0 project

• Adds CCS headless build/clean/export targets for the TX PRU0 project.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru0_fw/ti-pru-cgt/makefile_projectspec

example.projectspecCCS projectspec for ICSSG0 TX PRU1 firmware +82/-0

CCS projectspec for ICSSG0 TX PRU1 firmware

• Adds TX_PRU1 CCS project configuration to build assembly firmware and generate txpru1_load_bin.h.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru1_fw/ti-pru-cgt/example.projectspec

linker.cmdLinker memory map for AM243x ICSSG0 TX_PRU1 +52/-0

Linker memory map for AM243x ICSSG0 TX_PRU1

• Defines TX PRU instruction RAM size and maps sections to the appropriate TX_PRU1 DMEM partition.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru1_fw/ti-pru-cgt/linker.cmd

makefileMakefile for TX PRU1 firmware build and header export +49/-0

Makefile for TX PRU1 firmware build and header export

• Adds ti-pru-cgt build rules for TX_PRU1 firmware and exports txpru1_load_bin.h into the example firmware directory.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru1_fw/ti-pru-cgt/makefile

makefile_projectspecCCS Eclipse build/export wrapper for TX_PRU1 project +16/-0

CCS Eclipse build/export wrapper for TX_PRU1 project

• Adds CCS headless build/clean/export targets for the TX PRU1 project.

examples/pru_eqep/firmware/am243x-lp/icss_g0_tx_pru1_fw/ti-pru-cgt/makefile_projectspec

makefileTop-level pru_eqep build orchestrator (PRU + MCU+) +110/-0

Top-level pru_eqep build orchestrator (PRU + MCU+)

• Adds the example makefile that gates builds by device, builds all required PRU/RTU/TX firmware targets first, then builds the AM243x MCU+ FreeRTOS host project when enabled.

examples/pru_eqep/makefile

example.syscfgSysConfig for PRUICSS GPIO and interrupt mapping (AM243x R5F) +315/-0

SysConfig for PRUICSS GPIO and interrupt mapping (AM243x R5F)

• Configures PRU-ICSS instance, GPIO pin usage, and INTC event/channel mappings required for six ABZ channels and host interrupt delivery.

examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/example.syscfg

example.projectspecCCS projectspec for R5F FreeRTOS host app (ti-arm-clang) +123/-0

CCS projectspec for R5F FreeRTOS host app (ti-arm-clang)

• Adds a CCS project definition for the R5F host application, including SysConfig enablement and include paths to generated PRU firmware headers.

examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec

makefileMCU+ auto-generated makefile for R5F FreeRTOS build and appimage +355/-0

MCU+ auto-generated makefile for R5F FreeRTOS build and appimage

• Provides the ti-arm-clang build pipeline, SysConfig generation, and boot image (appimage/rprc/xip) generation rules for the host example.

examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/makefile

makefile_ccs_bootimage_genCCS post-build boot image generation makefile +113/-0

CCS post-build boot image generation makefile

• Adds a CCS-oriented post-build makefile to convert the built ELF into rprc/appimage (and sign when applicable).

examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen

makefile_projectspecCCS Eclipse build/export wrapper for R5F host project +16/-0

CCS Eclipse build/export wrapper for R5F host project

• Provides CCS headless build/clean/export targets for the R5F FreeRTOS host project.

examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec

syscfg_c.rov.xsROV metadata for SysConfig/FreeRTOS project +12/-0

ROV metadata for SysConfig/FreeRTOS project

• Adds the ROV configuration file to enable FreeRTOS runtime object viewing in CCS.

examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs

Comment thread examples/pru_eqep/firmware/main.asm Outdated
Comment on lines +122 to +129
sbbo &time_stamp, DMEM0, buffer_addr, 4
sbco &buffer_addr, DMEM1, WRITE_PTR_OFFSET, 2
sbco &QPOS, DMEM1, CH_POS_OFFSET, 4

; Handle buffer wrap-around
qbgt no_buffer_wrap, buffer_addr, buffer_size
ldi buffer_addr, 0
ldi READ_POS_BUFF, 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. sbbo before buffer bounds 📘 Rule violation ⛨ Security

sbbo &time_stamp, DMEM0, buffer_addr, 4 stores to DMEM using buffer_addr before verifying that
buffer_addr + 4 stays within buffer_size, and the wrap check only triggers on `buffer_addr >
buffer_size (allowing buffer_addr == buffer_size`). This can write past the intended buffer end
and corrupt adjacent PRU memory.
Agent Prompt
## Issue description
The PRU firmware writes a 4-byte timestamp to `DMEM0 + buffer_addr` before ensuring `buffer_addr` is within the valid buffer range, and the wrap condition allows `buffer_addr == buffer_size`.

## Issue Context
Compliance requires bounds checks for memory accesses, including validating `offset + size` against named limits.

## Fix Focus Areas
- examples/pru_eqep/firmware/main.asm[122-129]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +33 to +49
.asg r0, scratch
.asg r1, scratch2
.asg r17.b0, curr_gpi_sample ; Current GPI state after masking
.asg r17.b1, A_B_Z_edge ; Edge detection for A,B,Z signals
.asg r18, curr_ts ; Timestamp counter
.asg r19.b0, edge ; Edge detection
.asg r20.b0, prev_sample ; Previous state of A,B,Z signals
.asg r21, time_stamp ; Time stamp counter
.asg r22.w0, buffer_addr ; Buffer address pointer
.asg r22.w2, buffer_size ; Buffer size
.asg r23, wr_ptr ; Write pointer
.asg r24.w0, READ_POS_BUFF ; Read position buffer
.asg r24.w2, read_pos_speed_intr ; Read position speed interrupt
.asg r26.b0, a_b_transition ; A/B transition state
.asg r26.b1, qpos_update ; 2-> QPOS--, 1-> QPOS++, 0-> no change
.asg r27, QPOS ; Position counter
.asg r28, DMEM0 ; Data memory pointer

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Direct .asg register aliases 📘 Rule violation ⚙ Maintainability

The new PRU assembly include uses extensive direct register aliasing via .asg instead of
.struct/.sassign. This increases risk of register overlap/corruption and makes calling/register
conventions harder to audit.
Agent Prompt
## Issue description
The PRU assembly register map is implemented with many `.asg` aliases, contrary to the preferred `.struct`/`.sassign` pattern.

## Issue Context
The compliance rule requires structured register allocation to reduce overlap/corruption risk and improve maintainability.

## Fix Focus Areas
- examples/pru_eqep/firmware/include/memory.inc[33-49]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +55 to +57
postBuildStep="
$(CG_TOOL_ROOT)/bin/hexpru --diag_wrap=off --array --array:name_prefix=PRU0Firmware -o ../pru0_load_bin.h ${BuildArtifactFileBaseName}.out;
"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Long postbuildstep command line 📘 Rule violation ⚙ Maintainability

New .projectspec files embed long command strings in a single line (for example,
postBuildStep=...), which harms readability and violates the repository’s configuration
line-length expectations. This makes future edits and reviews error-prone.
Agent Prompt
## Issue description
Project configuration includes very long single-line command attributes (notably `postBuildStep`), reducing maintainability and violating line-length guidance.

## Issue Context
The compliance rule requests wrapping/reflowing long command-like attributes where feasible.

## Fix Focus Areas
- examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/example.projectspec[55-57]
- examples/pru_eqep/mcuplus/am243x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec[70-70]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread examples/pru_eqep/readme.md Outdated
Comment on lines +20 to +23
- **When using CCS projects to build**, import the CCS project from the above mentioned Example folder path for R5F and PRU, After this `main.asm`, `linker.cmd` files gets copied to ccs workspace of PRU project. The `main.asm` contains sample code to halt PRU program

- Build the PRU project using the CCS project menu (see [for AM64x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM64X/latest/exports/docs/api_guide_am64x/CCS_PROJECTS_PAGE.html), [for AM243x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM243X/latest/exports/docs/api_guide_am243x/CCS_PROJECTS_PAGE.html), [for AM261x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM261X/latest/exports/docs/api_guide_am261x/CCS_PROJECTS_PAGE.html), [for AM263x](https://software-dl.ti.com/mcu-plus-sdk/esd/AM263X/latest/exports/docs/api_guide_am263x/CCS_PROJECTS_PAGE.html), [for AM263Px](https://software-dl.ti.com/mcu-plus-sdk/esd/AM263PX/latest/exports/docs/api_guide_am263px/CCS_PROJECTS_PAGE.html)).
- Build Flow: Once you click on build in PRU project, firmware header file which is generated in release or debug folder of ccs workspace, is moved to `<open-pru/examples/empty/firmware/device/>`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. readme.md wrong empty path 📘 Rule violation ≡ Correctness

The README references <open-pru/examples/empty/firmware/device/>, which does not match this
example’s actual location and can mislead users. The same section also contains extremely long
markdown lines, reducing portability/readability in rendered views and diffs.
Agent Prompt
## Issue description
The new README contains an incorrect repository path reference (points to `examples/empty` instead of `examples/pru_eqep`) and includes very long single-line markdown content.

## Issue Context
Incorrect path references break portability/usability of docs, and overly long markdown lines violate documentation formatting expectations.

## Fix Focus Areas
- examples/pru_eqep/readme.md[20-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +31 to +34
# pru_rules.mak has shared settings for all PRU/RTU/TX_PRU core makefiles
include $(OPEN_PRU_PATH)/pru_rules.mak
include $(OPEN_PRU_PATH)/examples/pru_eqep/firmware/include/memory.inc
# Optional:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

5. Asm file included by make 🐞 Bug ≡ Correctness

The PRU0 firmware makefile uses GNU make include to include memory.inc, but that file contains
assembly syntax (e.g., ; comments and .asg) and will be parsed as make syntax, causing the build
to fail.
Agent Prompt
### Issue description
`examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile` includes an assembly `.inc` file via make's `include`, which will break parsing and stop the build.

### Issue Context
`memory.inc` is meant to be included by the PRU assembler (via `.include` in `main.asm` or via compiler include paths), not by `make`.

### Fix Focus Areas
- Remove the `include $(OPEN_PRU_PATH)/examples/pru_eqep/firmware/include/memory.inc` line.
- Ensure the assembler can still find `memory.inc` via `INCLUDE += --include_path=...`.

### Fix Focus Areas (code references)
- examples/pru_eqep/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile[31-38]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread examples/pru_eqep/firmware/main.asm Outdated
Comment on lines +569 to +583
void ABZ_enable_load_share_mode(void *pruCfg, uint32_t pruSlice)
{
uint32_t regVal;
if(pruSlice == 1)
{
regVal = HW_RD_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU1TXCFGREGISTER_PRU1_ED_TX_CLK_SEL_MASK);
regVal |= CSL_ICSSCFG_EDPRU1TXCFGREGISTER_PRU1_ENDAT_SHARE_EN_MASK;
HW_WR_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU1TXCFGREGISTER, regVal);
}
else
{
regVal = HW_RD_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU0TXCFGREGISTER_PRU0_ED_TX_CLK_SEL_MASK);
regVal |= CSL_ICSSCFG_EDPRU0TXCFGREGISTER_PRU0_ENDAT_SHARE_EN_MASK;
HW_WR_REG32((uint8_t *)pruCfg + CSL_ICSSCFG_EDPRU0TXCFGREGISTER, regVal);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

8. Mask used as register offset 🐞 Bug ≡ Correctness

ABZ_enable_load_share_mode() adds *_MASK constants to the PRU CFG base pointer when reading the
EDPRU TX CFG register, but those constants are bitmasks (e.g., 0x10) rather than register offsets
(e.g., 0xE4/0x104), so it reads the wrong address and may misconfigure load-share mode.
Agent Prompt
### Issue description
The code reads a PRU CFG register using a bitmask macro as if it were a register offset, so the value read is from the wrong location.

### Issue Context
`CSL_ICSSCFG_EDPRU1TXCFGREGISTER_PRU1_ED_TX_CLK_SEL_MASK` is 0x10 (mask), while `CSL_ICSSCFG_EDPRU1TXCFGREGISTER` is 0x104 (offset). The same pattern exists for PRU0.

### Fix Focus Areas
- Replace the `HW_RD_REG32(base + *_MASK)` reads with `HW_RD_REG32(base + CSL_ICSSCFG_EDPRU{0,1}TXCFGREGISTER)`.
- Keep using the `*_ENDAT_SHARE_EN_MASK` bitmask when setting/clearing bits in the read value.

### Fix Focus Areas (code references)
- examples/pru_eqep/mcuplus/pru_eqep_example.c[569-583]
- source/include/am243x/cslr_icss_g.h[13069-13071]
- source/include/am243x/cslr_icss_g.h[14785-14789]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread examples/pru_eqep/mcuplus/pru_eqep_example.c Outdated
Comment on lines +309 to +314
ABZHandle[i]->QPOSCOUNT = 0;
ABZHandle[i]->read_ptr = ABZHandle[i]->baseMemAddr0;
ABZHandle[i]->write_ptr = ABZHandle[i]->baseMemAddr1;
ABZHandle[i]->mem_limit=(DMEM_CHANNEL_SIZE)*(i) + DMEM_CHANNEL_SIZE;
if(i<3) ABZHandle[i]->pru_slice=0;
else ABZHandle[i]->pru_slice=1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

10. Mem_limit scaled by channel 🐞 Bug ≡ Correctness

mem_limit is computed as DMEM_CHANNEL_SIZE*i + DMEM_CHANNEL_SIZE, but the PRU firmware write
pointer (buffer_addr) is a per-channel offset that wraps to 0; for channels >0 this inflates
wrap-around edge counts and produces incorrect speed.
Agent Prompt
### Issue description
Speed calculation uses `mem_limit` as the buffer end when the write pointer wraps, but `mem_limit` is incorrectly made larger for higher channel indices.

### Issue Context
`EQEP_Get_Speed_ABZ()` uses `mem_limit` only as an upper bound for `(mem_limit - read_ptr_offset + write_ptr_offset)` when `read_ptr_offset > write_ptr_offset` (wrap case). Since firmware resets `buffer_addr` back to 0 on wrap, `mem_limit` must be the fixed per-channel buffer size.

### Fix Focus Areas
- Change `ABZHandle[i]->mem_limit` to `DMEM_CHANNEL_SIZE` (or the correct per-channel buffer size constant), not scaled by `i`.
- Ensure the host-side buffer size constant matches the firmware’s `MAX_BUFFER`/wrap behavior.

### Fix Focus Areas (code references)
- examples/pru_eqep/mcuplus/pru_eqep_example.c[294-316]
- examples/pru_eqep/mcuplus/pru_eqep_example.c[485-510]
- examples/pru_eqep/firmware/main.asm[126-130]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +394 to +401
if (!(ABZHandle[0]->write_ptr_offset == (HW_RD_REG32(ABZHandle[0]->baseMemAddr1) & WRITE_PTR_OFFSET_MASK)))
{
EQEP_Get_Speed_ABZ(0);
}
else
{
while (ABZHandle[0]->write_ptr_offset == (HW_RD_REG32(ABZHandle[0]->baseMemAddr1) & WRITE_PTR_OFFSET_MASK));
EQEP_Get_Speed_ABZ(0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

11. Spin loop inside isr 🐞 Bug ☼ Reliability

Each PRU host interrupt ISR busy-waits in a tight while (...) ; loop until the PRU updates the
write pointer; if the PRU stalls or the pointer never changes, the ISR can run indefinitely and
block other interrupts/tasks.
Agent Prompt
### Issue description
The interrupt handlers contain an unbounded spin-wait, which can lock the CPU in interrupt context.

### Issue Context
The ISR currently retries until `write_ptr_offset` changes. In failure modes (PRU halted, missed update, misconfigured mapping) this never terminates.

### Fix Focus Areas
- Avoid waiting inside the ISR; instead, read once and compute if data progressed, or defer work to a task.
- If waiting is necessary, add a bounded retry/timeout and record an error condition.

### Fix Focus Areas (code references)
- examples/pru_eqep/mcuplus/pru_eqep_example.c[389-420]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@pratheesh

Copy link
Copy Markdown
Contributor

Took a detailed pass through this PR, verifying each item against the code, the CSL headers, and CI. Grouping the Qodo findings by whether they hold up, plus a couple of independent items.

Confirmed — worth fixing (+1)

  • am243x: pru io: Add pru emif example & firmware #5 (make include memory.inc) — this is what makes Build (am243x) red. firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile:33 does include $(OPEN_PRU_PATH)/examples/pru_eqep/firmware/include/memory.inc, but memory.inc is PRU assembly (.asg, ;-comments, .if $isdefed). GNU make tries to parse it and errors out. The assembler already gets it via the include path added on line 38 (INCLUDE += --include_path=.../include), so line 33 is both redundant and build-breaking — just remove it. (The other SoCs pass only because pru_eqep is am243x-only.)

  • Am263x: PRU-I2S #8 (mask used as register offset) — real read-modify-write bug. In ABZ_enable_load_share_mode(), the read uses the mask as the address offset while the write uses the register offset:

    • CSL_ICSSCFG_EDPRU1TXCFGREGISTER = 0x104, but ..._PRU1_ED_TX_CLK_SEL_MASK = 0x10
    • CSL_ICSSCFG_EDPRU0TXCFGREGISTER = 0xE4, but ..._PRU0_ED_TX_CLK_SEL_MASK = 0x10
      So it reads from the wrong register (base+0x10), ORs in the enable bit, and writes the result to the correct register. The read offset should be the ...REGISTER, not the ...MASK.
  • A0503545 add sdk infra to am243x am64x #1 (write past buffer end) — real off-by-one. sbbo &time_stamp, DMEM0, buffer_addr, 4 writes before the wrap check, and buffer_addr is incremented all the way up to buffer_size (MAX_BUFFER = 0x400) before it is reset — so one store lands at offset 0x400, i.e. 4 bytes into the next channel's region (channels are 0x400 apart per DMEM_CHx_OFFSET). Wrap should trigger at buffer_addr >= buffer_size - 4, or bounds-check before the store.

  • Added AM26x support for Open PRU #9 (position_base) — CH1–CH5 offsets are dead code. Lines 317–322 set position_base with CH0_POSITION_OFFSET for all six channels; CH1_POSITION_OFFSET … CH5_POSITION_OFFSET are defined but never used. Either wire each channel to its own offset or drop the unused defines.

  • A0503595 spi loopback example #6 (cur_sample byte) — the per-core .if/.elseif is currently a no-op. All three branches assign r31.b0, while the comments (and the "GPI Byte Selection Guide") say b0 / b1 / b2 for RTU / PRU / TX_PRU. As written the conditional does nothing. If the PRU/TX_PRU cores really sample GPIs 8–15 / 16–19 this is a functional bug; if not, the branches and the guide are misleading and should be trimmed.

Disagree — please do not apply this one

  • am64x/am243x : infra : add scripts to install node modules #7 (buffer wrap reversed) — false positive; the current code is correct. In TI PRU assembly QBGT label, a, b branches when b > a (cf. this repo's own qbgt END_FOR_LOOP, N, I0 ; loop till I0>N). So qbgt no_buffer_wrap, buffer_addr, buffer_size takes the increment path while buffer_addr < buffer_size and falls through to the reset otherwise — which is the intended behaviour. Reversing it as the bot suggests would break a working loop. The only real issue in this block is the off-by-one already covered in A0503545 add sdk infra to am243x am64x #1.

Low priority / subjective

Independent items (not flagged by the bot)

  • Firmware↔C position offset mismatch. The firmware writes the position at DMEM1 + CH_POS_OFFSET (0x30), but the C side reads it at baseMemAddr1 + CH0_POSITION_OFFSET (0x1C). Even after Added AM26x support for Open PRU #9, 0x1C != 0x30, so the R5F would read position from the wrong location — please reconcile the shared-memory layout between main.asm and pru_eqep_example.c.
  • MAX_BUFFER .set 0x400 ; Buffer size = 8 kB0x400 is 1 KB, not 8 KB. Fix the comment (and confirm the intended size).

Happy to re-verify once these are addressed — particularly a green Build (am243x) after #5.

@a1248924

a1248924 commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator Author

thanks @pratheesh for grouping the comments, will review it carefully

@a1248924
a1248924 force-pushed the a1248924_EQEP branch 3 times, most recently from 82a3d5f to 6eb4e38 Compare July 5, 2026 20:16
if (ABZHandle[channel]->prev_ts > ABZHandle[channel]->cur_ts)
ABZHandle[channel]->delta_t = TIMESTAMP_MASK - ABZHandle[channel]->prev_ts + ABZHandle[channel]->cur_ts;
else
ABZHandle[channel]->delta_t = ABZHandle[channel]->cur_ts - ABZHandle[channel]->prev_ts;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

construct a case where delta_t becomes zero leading to division by zero, for timing calculations, only 24 bits are being considered currently

@TexasInstruments TexasInstruments deleted a comment from qodo-code-review Bot Jul 11, 2026
@TexasInstruments TexasInstruments deleted a comment from qodo-code-review Bot Jul 11, 2026
@TexasInstruments TexasInstruments deleted a comment from qodo-code-review Bot Jul 11, 2026
@pratheesh-ti

Copy link
Copy Markdown
Collaborator

/agentic_describe

DebugP_log("EQEP Position Speed Test Started ...\r\n");

// Main loop
uint64_t last_print_us = ClockP_getTimeUsec();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain this by adding comment ?


/* Print status every 1 second */
uint64_t now_us = ClockP_getTimeUsec();
if ((now_us - last_print_us) >= 1000000U)

@rajul-bhambay rajul-bhambay Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use #defines for hardcoded values 1000000

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also explain the flow in each branch what exactly is happening

ABZHandle[ch]->prev_QPOS = ABZHandle[ch]->QPOSCOUNT;
ABZHandle[ch]->QPOSCOUNT = HW_RD_REG32((uint32_t)ABZHandle[ch]->position_base);
if (ABZHandle[ch]->QPOSCOUNT > ABZHandle[ch]->prev_QPOS) ABZHandle[ch]->direction = 1;
else if (ABZHandle[ch]->QPOSCOUNT < ABZHandle[ch]->prev_QPOS) ABZHandle[ch]->direction = -1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if there are no transitions, aren't we supposed to bring direction to 0?

ABZHandle[ch]->write_ptr_offset = curr_write_ptr_offset;
EQEP_Get_Speed_ABZ(ch);

PRUICSS_clearEvent(gPruIcssXHandle, 16U + ch);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use macros for hardcoded values 16U

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants