Skip to content

Spi driver demo - #161

Open
a1248924 wants to merge 1 commit into
mainfrom
SPI_driver_demo
Open

a1248924 wants to merge 1 commit into
mainfrom
SPI_driver_demo

Conversation

@a1248924

Copy link
Copy Markdown
Collaborator

No description provided.

@qodo-code-review

qodo-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Add AM261x PRU SPI driver demonstration

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

Grey Divider

AI Description

• Adds a persistent PRU bit-banged SPI master and fixed-response slave.
• Demonstrates five-word full-duplex bursts controlled through PRU DMEM from FreeRTOS.
• Adds AM261x build, pinmux, CCS, boot-image, and hardware setup documentation.
Diagram

sequenceDiagram
    actor User
    participant R5F as R5F Demo
    participant DMEM as PRU DMEM
    participant PRU0 as PRU0 Master
    participant PRU1 as PRU1 Slave
    User->>R5F: Enter five commands
    R5F->>DMEM: Write startup config
    R5F->>PRU1: Load slave firmware
    R5F->>PRU0: Load master firmware
    loop Triggered transaction
        R5F->>DMEM: Write commands and trigger
        PRU0->>DMEM: Read five commands
        PRU0->>PRU1: Send 5x16-bit SPI burst
        PRU1-->>PRU0: Return fixed responses
        PRU0->>DMEM: Store responses and clear trigger
        R5F->>DMEM: Poll and read responses
    end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use the hardware SPI peripheral
  • ➕ Reduces firmware size and duplicated mode-specific assembly
  • ➕ Provides production-oriented buffering, interrupts, and protocol handling
  • ➕ Avoids cycle-sensitive bit-banging and manual clock compensation
  • ➖ Does not demonstrate deterministic PRU-driven SPI
  • ➖ May not satisfy custom timing or continuous-burst requirements
  • ➖ Requires an available and suitably routed SPI peripheral
2. Use interrupt-based R5F completion
  • ➕ Eliminates periodic trigger polling and sleep latency
  • ➕ Allows the R5F task to block efficiently between transfers
  • ➖ Adds PRU-to-R5F interrupt routing and lifecycle complexity
  • ➖ Is unnecessary for this interactive prototype's low transaction rate
3. Share one firmware path per SPI mode
  • ➕ Could reduce repeated trigger, load, and completion code
  • ➕ Would make transaction bookkeeping easier to maintain
  • ➖ Assembler macros require compile-time mode and bit-order strings
  • ➖ Still requires specialized transfer bodies or lower-level runtime edge logic
  • ➖ Refactoring could affect precisely validated SPI timing

Recommendation: Keep the PRU bit-banged implementation for this demonstration because deterministic GPIO-driven SPI is its primary purpose, and preassembling eight transfer variants is a reasonable response to compile-time macro parameters. For production reuse, prefer hardware SPI where its timing is sufficient; otherwise, first consolidate common PRU transaction bookkeeping and consider interrupt-based completion.

Files changed (24) +3781 / -1

Enhancement (7) +2101 / -0
main.asmImplement persistent PRU0 SPI master firmware +442/-0

Implement persistent PRU0 SPI master firmware

• Implements a runtime-selected SPI master covering four modes and both bit orders. Each trigger performs five back-to-back 16-bit full-duplex transfers under one chip-select assertion, stores responses in DMEM0, and clears the trigger.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm

main.asmImplement the PRU1 SPI slave responder +158/-0

Implement the PRU1 SPI slave responder

• Adds a persistent MODE3/MSB slave that waits for chip select and exchanges five 16-bit words per burst. It returns fixed encoder-style responses and records received commands in DMEM1.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm

spi_master_macros.incAdd PRU SPI master transfer macros +569/-0

Add PRU SPI master transfer macros

• Introduces timed master read, write, and full-duplex transfer macros supporting SPI modes 0-3, MSB/LSB ordering, and packet-size validation.

examples/spi_driver/firmware/am261x-lp/spi_master_macros.inc

spi_slave_macros.incAdd PRU SPI slave transfer macros +511/-0

Add PRU SPI slave transfer macros

• Introduces slave read, write, and full-duplex macros that wait on mode-specific clock edges and support MSB/LSB packet transfers.

examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc

time_macros.incAdd cycle and nanosecond delay macros +87/-0

Add cycle and nanosecond delay macros

• Provides reusable PRU delay macros used to control chip-select setup and SPI clock timing.

examples/spi_driver/firmware/am261x-lp/time_macros.inc

main.cAdd the FreeRTOS application entry point +84/-0

Add the FreeRTOS application entry point

• Initializes the system and board, creates the static high-priority demo task, and starts the FreeRTOS scheduler.

examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/main.c

empty_example.cImplement the R5F SPI demonstration controller +250/-0

Implement the R5F SPI demonstration controller

• Initializes PRU memory, writes startup configuration, loads slave then master firmware, and repeatedly submits five commands through DMEM. It polls for completion with a timeout and prints the five returned words.

examples/spi_driver/mcuplus/empty_example.c

Documentation (1) +253 / -0
readme.mdDocument the PRU SPI driver demonstration +253/-0

Document the PRU SPI driver demonstration

• Documents architecture, DMEM contracts, runtime configuration, timing constraints, supported combinations, fixed slave responses, build behavior, and AM261x LaunchPad wiring.

examples/spi_driver/readme.md

Other (16) +1427 / -1
makefileRegister the SPI driver example +1/-1

Register the SPI driver example

• Adds 'spi_driver' to the top-level examples build traversal.

examples/makefile

example.projectspecDefine the PRU0 CCS project +84/-0

Define the PRU0 CCS project

• Configures the AM261x PRU0 assembly project, compiler and linker options, source inputs, and firmware-header generation.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/example.projectspec

linker.cmdMap PRU0 firmware memory sections +43/-0

Map PRU0 firmware memory sections

• Defines AM261x PRU instruction, local data, peer data, and shared-memory regions and places firmware sections in PRU0 memory.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/linker.cmd

makefileAdd the PRU0 command-line build +49/-0

Add the PRU0 command-line build

• Builds the PRU0 firmware with shared PRU rules and exports its generated firmware array for the MCU+ application.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile

makefile_projectspecAdd PRU0 CCS project automation +16/-0

Add PRU0 CCS project automation

• Provides targets to export, build, and clean the PRU0 CCS project.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile_projectspec

example.projectspecDefine the PRU1 CCS project +84/-0

Define the PRU1 CCS project

• Configures the AM261x PRU1 assembly project and generates a PRU1 firmware header for the host application.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/example.projectspec

linker.cmdMap PRU1 firmware memory sections +43/-0

Map PRU1 firmware memory sections

• Defines the AM261x PRU1 instruction and data-memory layout and assigns firmware sections to local PRU1 memory.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/linker.cmd

makefileAdd the PRU1 command-line build +49/-0

Add the PRU1 command-line build

• Builds PRU1 firmware and publishes its generated firmware array to the AM261x example directory.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile

makefile_projectspecAdd PRU1 CCS project automation +16/-0

Add PRU1 CCS project automation

• Provides targets to export, build, and clean the PRU1 CCS project.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile_projectspec

makefileOrchestrate SPI firmware and host builds +106/-0

Orchestrate SPI firmware and host builds

• Adds AM261x project gating and build targets that compile both PRU firmware images before the MCU+ FreeRTOS host.

examples/spi_driver/makefile

example.syscfgConfigure AM261x peripherals and PRU pinmux +327/-0

Configure AM261x peripherals and PRU pinmux

• Configures ICSS_M1, PRU GPIO routing, board I/O expansion, UART logging, FreeRTOS support, MPU regions, and linker memory sections for the demo.

examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/example.syscfg

example.projectspecDefine the R5F CCS project +117/-0

Define the R5F CCS project

• Configures the R5F FreeRTOS CCS project, SDK dependencies, PRU firmware include paths, SysConfig generation, libraries, and boot-image post-processing.

examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec

makefileAdd the R5F command-line and boot-image build +352/-0

Add the R5F command-line and boot-image build

• Adds compilation, SysConfig generation, linking, cleanup, coverage, multicore ELF generation, and secure-device signing targets for the host application.

examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile

makefile_ccs_bootimage_genGenerate CCS multicore boot images +112/-0

Generate CCS multicore boot images

• Adds CCS post-build generation of multicore ELF images, including optional signing and encryption for secure devices.

examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen

makefile_projectspecAdd R5F CCS project automation +16/-0

Add R5F CCS project automation

• Provides targets to export, build, and clean the R5F CCS project.

examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec

syscfg_c.rov.xsEnable FreeRTOS runtime object views +12/-0

Enable FreeRTOS runtime object views

• Registers FreeRTOS ROV definitions for CCS and Theia debugging.

examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs

@qodo-code-review

qodo-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (10) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Firmware builds fail from make ✓ Resolved 🐞 Bug ≡ Correctness
Description
Both PRU ti-pru-cgt/makefile files include pru_rules.mak without appending the local ../../
include directory, even though their main.asm files include macro files stored there. As a result,
standalone builds cannot resolve spi_master_macros.inc or spi_slave_macros.inc, while the
existing SPI loopback firmware explicitly adds that include path.
Code

examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile[R31-32]

+# pru_rules.mak has shared settings for all PRU/RTU/TX_PRU core makefiles
+include $(OPEN_PRU_PATH)/pru_rules.mak
Evidence
The shared rules pass only their INCLUDE variable to clpru and do not include this project's
firmware directory. The new firmware's first-level includes are in firmware/am261x-lp, two levels
above each PRU build directory; the established SPI loopback makefile adds precisely that path.

pru_rules.mak[49-55]
pru_rules.mak[125-130]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[39-39]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[26-26]
examples/spi_driver/firmware/am261x-lp/spi_master_macros.inc[43-44]
examples/spi_loopback/firmware/am243x-lp/icss_g0_pru0_fw/ti-pru-cgt/makefile[31-38]

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 standalone PRU firmware builds do not add the directory containing the SPI and timing macro includes to `clpru`'s include search path.

### Fix Focus Areas
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/ti-pru-cgt/makefile[31-32]
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/ti-pru-cgt/makefile[31-32]

### Recommended Fix
After including `pru_rules.mak`, append `INCLUDE += --include_path=../../` in both PRU makefiles, matching the SPI loopback firmware convention. This makes `spi_master_macros.inc`/`spi_slave_macros.inc` and their local `time_macros.inc` dependency resolvable during standalone builds.

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


2. Project skipped by root builds ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The new spi_driver project is not registered in examples/makefile, so repository-wide make,
make pru, make host, and make clean silently skip it. This also prevents normal aggregate
builds from detecting regressions in the new firmware and host application.
Code

examples/spi_driver/makefile[R7-8]

+PROJECT_NAME := spi_driver
+SUPPORTED_PROCESSORS := am261x
Evidence
The SPI makefile declares a standalone AM261x project and defines its firmware and MCU+ targets, but
the parent makefile's exhaustive SUBDIRS list omits spi_driver; all parent targets recurse
exclusively through that list.

examples/spi_driver/makefile[7-12]
examples/spi_driver/makefile[60-80]
examples/spi_driver/makefile[94-103]
examples/makefile[3-7]
examples/makefile[9-24]

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 newly added `spi_driver` project has its own build targets but is absent from the parent examples directory list, so aggregate repository builds never invoke it.

## Issue Context
The root build delegates to `examples/makefile`, whose recursive targets process only entries in `SUBDIRS`. Add `spi_driver` to that list and ensure aggregate clean, PRU, and host targets reach the project.

## Fix Focus Areas
- examples/makefile[3-7]
- examples/spi_driver/makefile[7-12]
- examples/spi_driver/makefile[60-80]

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


3. Wrong DMEM base channels 🐞 Bug ≡ Correctness
Description
In pru_eqep_example_main(), ABZHandle[i]->baseMemAddr0 is computed from pru0DramBase for all 6
channels, but the PRU1-side firmware channels (RTU_PRU1/PRU1/TX_PRU1) place their buffers in the
PRU1 DRAM bank. This causes channels 3–5 to read stale/incorrect ring-buffer data and report wrong
speed/position/phase-error results.
Code

examples/pru_eqep/mcuplus/pru_eqep_example.c[R243-246]

+        ABZHandle[i]->baseMemAddr0 = (uint32_t *)(
+            ((PRUICSS_HwAttrs *)(gPruIcssXHandle->hwAttrs))->pru0DramBase +
+            DMEM_OFFSETS[i]
+        );
Evidence
The host code always uses hwAttrs->pru0DramBase for baseMemAddr0, even though it labels channels 3–5
as PRU1-bank channels; the firmware explicitly places PRU1-core DMEM bases at 0x2C00/0x3000/0x3400
(i.e., PRU1-bank region). Existing code in the repo treats pru0DramBase and pru1DramBase as distinct
banks selected per core, so using pru0DramBase for PRU1 channels is inconsistent with the expected
memory map.

examples/pru_eqep/mcuplus/pru_eqep_example.c[238-258]
examples/pru_eqep/firmware/include/memory.inc[120-161]
examples/pru_emif/pru_emif_app/pruemif16.c[241-245]

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

## Issue description
`pru_eqep_example_main()` initializes each channel’s `baseMemAddr0` using `hwAttrs->pru0DramBase` unconditionally. However, the PRU firmware assigns distinct DMEM base offsets for PRU1-side cores (RTU_PRU1/PRU1/TX_PRU1), which correspond to the PRU1 DRAM bank. As a result, channels 3–5 (PRU1-side) will read from the PRU0 DRAM bank instead of PRU1, producing incorrect diagnostics.

## Issue Context
- Channels 0–2 correspond to PRU0-side cores; channels 3–5 correspond to PRU1-side cores.
- Firmware memory layout shows PRU1-side cores use DMEM offsets in the PRU1 region (e.g., 0x2C00/0x3000/0x3400), which conceptually is `PRU1_DRAM_BASE + {0x0C00,0x1000,0x1400}`.

## Fix
- Compute `baseMemAddr0` with `pru0DramBase` for channels 0–2 and `pru1DramBase` for channels 3–5.
- Keep `DMEM_OFFSETS[i]` as-is (since offsets 3–5 are already the per-bank offsets), but switch the base pointer depending on `i`.

## Fix Focus Areas
- examples/pru_eqep/mcuplus/pru_eqep_example.c[238-259]

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



Remediation recommended

4. Slave low-bit-first reads fail to build 🐞 Bug ≡ Correctness ⭐ New
Description
m_read_packet_spi_slave_lsb_gpo_sclk is defined with gpo even though its own heading and the
sibling MSB read macro expose the slave input-clock API as gpi. Any firmware that calls the
documented LSB-only slave read name fails assembly with an undefined macro, while the other bit
order builds.
Code

examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[147]

+m_read_packet_spi_slave_lsb_gpo_sclk   .macro  dataReg, PACKETSIZE, bitId, SCLK_PIN, SDI_PIN, MODE
Evidence
The file names the low-bit-first read macro as m_read_packet_spi_slave_lsb_gpi_sclk in its API
heading, but the actual definition uses m_read_packet_spi_slave_lsb_gpo_sclk; the corresponding
MSB slave read is also defined with gpi_sclk. This proves the low-bit-first definition breaks the
documented naming contract.

examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[88-88]
examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[115-147]

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 low-bit-first slave read macro is documented with a `gpi_sclk` name but defined with `gpo_sclk`, so callers using the documented and convention-consistent name cannot assemble.

## Fix Focus Areas
- examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[115-147]

## Recommended Fix
Rename `m_read_packet_spi_slave_lsb_gpo_sclk` to `m_read_packet_spi_slave_lsb_gpi_sclk`, matching the macro heading, the input-clock implementation, and the corresponding MSB macro.

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


5. Firmware customization breaks the demo 🐞 Bug ≡ Correctness
Description
The fixed-configuration section directs users to edit only PRU0 firmware even though packet size and
pin assignments are independently defined by PRU1 and the pin routing is generated from SysConfig.
Changing either advertised setting by following these instructions leaves the two endpoints or
physical routing inconsistent, preventing the customized round trip from operating correctly.
Code

examples/spi_driver/readme.md[R138-141]

+### Fixed at firmware build time (edit `firmware/am261x-lp/icss_m1_pru0_fw/main.asm` and rebuild)
+
+- **Packet size** — fixed at 16 bits (`PACKET_SIZE`). The underlying macros
+  (`spi_master_macros.inc`/`spi_slave_macros.inc`) enforce **1-32 bits** at
Evidence
The README's single-file instruction conflicts with separate PACKET_SIZE and pin constants in both
firmware images, while SysConfig independently selects and routes the corresponding PRU signals.
Editing only the named PRU0 file therefore cannot produce a consistent packet-size or pin
reassignment.

examples/spi_driver/readme.md[131-150]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[50-59]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[38-44]
examples/spi_driver/mcuplus/am261x-lp/r5fss0-0_freertos/example.syscfg[70-97]

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 customization instructions name only PRU0 firmware, but packet-size and pin changes also require corresponding PRU1 firmware and SysConfig updates.

## Fix Focus Areas
- examples/spi_driver/readme.md[138-150]

## Recommended Fix
Split the build-time settings by component. State that packet-size changes must be applied consistently to both PRU firmware files, pin changes must update the relevant PRU constants and SysConfig routing before regeneration, and only the master timing compensation values are confined to PRU0.

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


6. Aborted bursts desynchronize the slave 🐞 Bug ☼ Reliability
Description
DO_5X_TRANSFER invokes transfer macros that wait only for clock transitions and cannot abort when
chip select becomes inactive. If chip select is deasserted before all 80 clocks arrive, later bursts
finish the interrupted transfer at the wrong boundary and the slave remains offset until its core is
restarted.
Code

examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[R153-156]

+    m_transfer_packet_spi_slave_gpi_sclk rx0, tx0, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"
+    m_transfer_packet_spi_slave_gpi_sclk rx1, tx1, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"
+    m_transfer_packet_spi_slave_gpi_sclk rx2, tx2, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"
+    m_transfer_packet_spi_slave_gpi_sclk rx3, tx3, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"
Evidence
PRU1 checks chip select only before entering DO_5X_TRANSFER, while all five transfer calls must
complete before control returns to the outer polling loop. The invoked macro waits for sampling and
shifting edges through helpers that poll only SCLK, so an early chip-select rise cannot reset its
word or burst position.

examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[116-132]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[147-158]
examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[375-410]
examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[470-503]

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

## Issue description
PRU1 cannot abandon a partial five-word transfer when chip select becomes inactive, so subsequent bursts remain aligned to the interrupted transaction rather than their own boundaries.

## Fix Focus Areas
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[116-157]
- examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[362-410]

## Recommended Fix
Make the slave transfer path monitor the chip-select input while waiting for each clock edge and return an aborted status when it rises. On abort, discard partial receive data, wait for a fresh high-to-low chip-select transition, reinitialize all five transfer registers, and begin the next burst at word zero.

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


View medium (5)
7. Single-word transfers return stale data 🐞 Bug ≡ Correctness
Description
PRU_SPI_runTransaction writes the obsolete command slot at 0x0C and reads the obsolete response
slot at 0x08. Every PRU0 branch now consumes five commands from 0x14–0x24 and produces responses
at 0x28–0x38, so invoking this retained helper triggers a burst from unrelated slots and returns a
value PRU0 never updates.
Code

examples/spi_driver/mcuplus/empty_example.c[R124-125]

+    dmem_write32(PRU0_DMEM_BASE, DMEM_CFG_COMMAND, commandWord);
+    dmem_write32(PRU0_DMEM_BASE, DMEM_CFG_TRIGGER, 1U);
Evidence
The host helper accesses offsets 0x0C and 0x08, while PRU0 defines and exclusively loads/stores
the five-word regions beginning at 0x14 and 0x28; none of its eight transaction paths updates
the helper's response slot.

examples/spi_driver/mcuplus/empty_example.c[47-64]
examples/spi_driver/mcuplus/empty_example.c[120-139]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[66-76]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[133-142]

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

## Issue description
`PRU_SPI_runTransaction` still accesses the legacy single-word DMEM slots, but the new PRU0 firmware only implements five-word bursts using different slots. Calling the helper therefore sends unrelated data and reads a stale response.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[120-140]
- examples/spi_driver/mcuplus/empty_example.c[47-64]

## Recommended Fix
Remove `PRU_SPI_runTransaction` and the unused legacy single-word constants and comments. If single-word operation must remain supported, implement an explicit adapter that populates all required burst slots and returns the corresponding active response, or restore a matching firmware protocol.

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


8. Decimal input parsed hexadecimal 🐞 Bug ≡ Correctness
Description
The prompt requests decimal command words, but DebugP_scanf("%x", &input) parses them as
hexadecimal. For example, entering decimal 10 sends 0x10 (16), causing the SPI transaction to
use a different command than the user requested.
Code

examples/spi_driver/mcuplus/empty_example.c[220]

+            DebugP_scanf("%x", &input);
Evidence
The application tells users to enter decimal values at line 215, then reads each value with the
hexadecimal %x conversion at line 220. The parsed value is assigned directly to commandWords[i]
at line 228 and subsequently transmitted.

examples/spi_driver/mcuplus/empty_example.c[215-228]

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 console requests decimal command words but parses input using the hexadecimal `%x` conversion, so digit-only values can be transmitted with the wrong numeric value.

## Issue Context
Either parse decimal input with `%u`, or explicitly change the prompt and validation messages to request hexadecimal input.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[215-224]

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


9. Timeout desynchronizes transactions 🐞 Bug ☼ Reliability
Description
PRU_SPI_runTransaction5 returns on timeout while leaving the outstanding trigger active, and the
caller immediately permits another transaction. If the timed-out PRU operation later clears that
shared trigger after the retry sets it, the retry reports success and reads responses from the
previous transaction.
Code

examples/spi_driver/mcuplus/empty_example.c[R161-164]

+        if (elapsed >= TRIGGER_POLL_TIMEOUT_US)
+        {
+            return 0;
+        }
Evidence
The host returns immediately when its 5 ms poll expires without cancelling or resetting the
outstanding request, then the caller continues the main loop. PRU0 independently publishes responses
and clears DMEM_CFG_TRIGGER at the end of a burst, so a delayed clear can be mistaken for completion
of a later request using that same one-bit trigger.

examples/spi_driver/mcuplus/empty_example.c[154-172]
examples/spi_driver/mcuplus/empty_example.c[232-243]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[365-375]

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

## Issue description
A timed-out SPI transaction remains active because the shared trigger is left set. A late PRU completion can clear the trigger belonging to a subsequent retry, causing stale responses to be accepted as current.

## Issue Context
The PRU clears the same trigger only after publishing its responses, while the application continues its input loop after a timeout. Recovery must not simply clear the trigger while the PRU may still be processing; either stop/reinitialize the PRU transaction state or terminate further transactions, or introduce a sequence-based handshake that distinguishes completions.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[156-172]
- examples/spi_driver/mcuplus/empty_example.c[232-235]
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[365-375]

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


10. Failed input reuses command 🐞 Bug ≡ Correctness
Description
empty_example_main ignores whether DebugP_scanf successfully parsed a value and then validates
and dispatches the uninitialized or previously retained input. Malformed or unavailable console
input can therefore trigger an unintended SPI transaction, and an unconsumed invalid token can
repeat this behavior.
Code

examples/spi_driver/mcuplus/empty_example.c[R169-170]

+        DebugP_log("\r\nEnter command (0-3): ");
+        DebugP_scanf("%d", &input);
Evidence
input is declared without initialization, the scan result is discarded, and the following code
reads that value to select and execute one of four command words regardless of whether parsing
succeeded.

examples/spi_driver/mcuplus/empty_example.c[129-133]
examples/spi_driver/mcuplus/empty_example.c[167-180]
examples/spi_driver/mcuplus/empty_example.c[182-189]

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 command loop uses `input` even when console parsing fails, allowing an indeterminate or stale command to be sent.

## Issue Context
Initialize the input variable, check the `DebugP_scanf` result before range validation, and consume or otherwise handle invalid input so the same malformed token does not repeatedly fail.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[131-133]
- examples/spi_driver/mcuplus/empty_example.c[167-180]
- examples/spi_driver/mcuplus/empty_example.c[182-189]

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


11. Header missing guards 🐞 Bug ⚙ Maintainability
Description
eqep_diagnostic.h has no include guard and does not include the headers that define types it uses
(e.g., uint8_t/uint32_t, PRUICSS_Handle), making it dependent on include order and susceptible to
redefinition errors if included multiple times. This can cause brittle build failures as the example
evolves or headers are reorganized.
Code

examples/pru_eqep/mcuplus/eqep_diagnostic.h[R33-34]

+// Typedef for ABZ handle
+typedef struct ABZ_Config_s *ABZ_Handle;
Evidence
The header begins immediately with comments and then type declarations (no guard macros visible at
the start), and it uses fixed-width integer types and PRUICSS_Handle without including their
definitions, meaning it relies on other headers being included first.

examples/pru_eqep/mcuplus/eqep_diagnostic.h[1-20]
examples/pru_eqep/mcuplus/eqep_diagnostic.h[33-72]

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

## Issue description
`eqep_diagnostic.h` declares public types using `uint8_t`, `uint32_t`, and `PRUICSS_Handle` but does not include headers that define these types, and it lacks an include guard. This makes compilation depend on transitive includes and include order, and can cause redefinition errors if the header is included more than once.

## Issue Context
This header is intended to define shared types (`ABZ_Config`, `ABZ_Handle`) used by the PRU EQEP MCU+ example.

## Fix
- Add an include guard (`#ifndef / #define / #endif`) or `#pragma once`.
- Include required headers directly (at minimum `<stdint.h>`; and whichever project header provides `PRUICSS_Handle`, typically `<drivers/pruicss.h>` in this repo’s examples).

## Fix Focus Areas
- examples/pru_eqep/mcuplus/eqep_diagnostic.h[1-20]
- examples/pru_eqep/mcuplus/eqep_diagnostic.h[33-75]

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



Informational

12. Source guidance names the wrong bit order 🐞 Bug ⚙ Maintainability
Description
The application header describes the demo and bundled slave as MODE3/LSB even though initialization
and the slave transfer routine both select MODE3/MSB. A maintainer following those source notes
while changing or debugging configuration can pair the peers with opposite bit ordering, despite the
project README documenting MSB correctly.
Code

examples/spi_driver/mcuplus/empty_example.c[6]

+ * PRU-SPI encoder-emulation demo - R5F side (phase 3, MODE3/LSB only)
Evidence
The stale application comments repeatedly say MODE3/LSB, while the same file configures MSB, PRU1
assembles every transfer with the MSB argument, and the README also identifies MODE3/MSB as the
supported paired configuration.

examples/spi_driver/mcuplus/empty_example.c[6-17]
examples/spi_driver/mcuplus/empty_example.c[25-32]
examples/spi_driver/mcuplus/empty_example.c[192-195]
examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[152-158]
examples/spi_driver/readme.md[184-189]

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

## Issue description
Several source comments describe the active demo as MODE3/LSB and claim only that path uses five-word bursts, while the executable configuration and slave firmware use MODE3/MSB and PRU0 implements five-word bursts for all eight combinations.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[6-32]
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[120-123]
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[84-94]

## Recommended Fix
Update the comments to identify MODE3/MSB as the bundled master/slave configuration and state that all PRU0 mode and bit-order branches use the five-word protocol. Remove references to unchanged legacy single-transfer branches.

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


Grey Divider

Context sources
Review mode: ⚖️ Balanced: Comparison failure: full PR diff.

Grey Divider

Tip of the day
💡 Did you know, you can start a comment with 'qodo' or '@qodo' to chat about any finding

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread examples/pru_eqep/mcuplus/pru_eqep_example.c
Comment thread examples/pru_eqep/mcuplus/eqep_diagnostic.h
Comment thread examples/spi_driver/makefile
Comment on lines +169 to +170
DebugP_log("\r\nEnter command (0-3): ");
DebugP_scanf("%d", &input);

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

2. Failed input reuses command 🐞 Bug ≡ Correctness

empty_example_main ignores whether DebugP_scanf successfully parsed a value and then validates
and dispatches the uninitialized or previously retained input. Malformed or unavailable console
input can therefore trigger an unintended SPI transaction, and an unconsumed invalid token can
repeat this behavior.
Agent Prompt
## Issue description
The command loop uses `input` even when console parsing fails, allowing an indeterminate or stale command to be sent.

## Issue Context
Initialize the input variable, check the `DebugP_scanf` result before range validation, and consume or otherwise handle invalid input so the same malformed token does not repeatedly fail.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[131-133]
- examples/spi_driver/mcuplus/empty_example.c[167-180]
- examples/spi_driver/mcuplus/empty_example.c[182-189]

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

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit c7b425c

Comment on lines +161 to +164
if (elapsed >= TRIGGER_POLL_TIMEOUT_US)
{
return 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

1. Timeout desynchronizes transactions 🐞 Bug ☼ Reliability

PRU_SPI_runTransaction5 returns on timeout while leaving the outstanding trigger active, and the
caller immediately permits another transaction. If the timed-out PRU operation later clears that
shared trigger after the retry sets it, the retry reports success and reads responses from the
previous transaction.
Agent Prompt
## Issue description
A timed-out SPI transaction remains active because the shared trigger is left set. A late PRU completion can clear the trigger belonging to a subsequent retry, causing stale responses to be accepted as current.

## Issue Context
The PRU clears the same trigger only after publishing its responses, while the application continues its input loop after a timeout. Recovery must not simply clear the trigger while the PRU may still be processing; either stop/reinitialize the PRU transaction state or terminate further transactions, or introduce a sequence-based handshake that distinguishes completions.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[156-172]
- examples/spi_driver/mcuplus/empty_example.c[232-235]
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[365-375]

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

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit a278e17

while (i < 5U)
{
DebugP_log(" cmd[%u]: ", i);
DebugP_scanf("%x", &input);

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

1. Decimal input parsed hexadecimal 🐞 Bug ≡ Correctness

The prompt requests decimal command words, but DebugP_scanf("%x", &input) parses them as
hexadecimal. For example, entering decimal 10 sends 0x10 (16), causing the SPI transaction to
use a different command than the user requested.
Agent Prompt
## Issue description
The console requests decimal command words but parses input using the hexadecimal `%x` conversion, so digit-only values can be transmitted with the wrong numeric value.

## Issue Context
Either parse decimal input with `%u`, or explicitly change the prompt and validation messages to request hexadecimal input.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[215-224]

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

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit dc18a4d

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 41a382f

Comment on lines +124 to +125
dmem_write32(PRU0_DMEM_BASE, DMEM_CFG_COMMAND, commandWord);
dmem_write32(PRU0_DMEM_BASE, DMEM_CFG_TRIGGER, 1U);

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

4. Single-word transfers return stale data 🐞 Bug ≡ Correctness

PRU_SPI_runTransaction writes the obsolete command slot at 0x0C and reads the obsolete response
slot at 0x08. Every PRU0 branch now consumes five commands from 0x14–0x24 and produces responses
at 0x28–0x38, so invoking this retained helper triggers a burst from unrelated slots and returns a
value PRU0 never updates.
Agent Prompt
## Issue description
`PRU_SPI_runTransaction` still accesses the legacy single-word DMEM slots, but the new PRU0 firmware only implements five-word bursts using different slots. Calling the helper therefore sends unrelated data and reads a stale response.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[120-140]
- examples/spi_driver/mcuplus/empty_example.c[47-64]

## Recommended Fix
Remove `PRU_SPI_runTransaction` and the unused legacy single-word constants and comments. If single-word operation must remain supported, implement an explicit adapter that populates all required burst slots and returns the corresponding active response, or restore a matching firmware protocol.

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

*
* SPDX-License-Identifier: BSD-3-Clause
*
* PRU-SPI encoder-emulation demo - R5F side (phase 3, MODE3/LSB only)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Informational

9. Source guidance names the wrong bit order 🐞 Bug ⚙ Maintainability

The application header describes the demo and bundled slave as MODE3/LSB even though initialization
and the slave transfer routine both select MODE3/MSB. A maintainer following those source notes
while changing or debugging configuration can pair the peers with opposite bit ordering, despite the
project README documenting MSB correctly.
Agent Prompt
## Issue description
Several source comments describe the active demo as MODE3/LSB and claim only that path uses five-word bursts, while the executable configuration and slave firmware use MODE3/MSB and PRU0 implements five-word bursts for all eight combinations.

## Fix Focus Areas
- examples/spi_driver/mcuplus/empty_example.c[6-32]
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[120-123]
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru0_fw/main.asm[84-94]

## Recommended Fix
Update the comments to identify MODE3/MSB as the bundled master/slave configuration and state that all PRU0 mode and bit-order branches use the five-word protocol. Remove references to unchanged legacy single-transfer branches.

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

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 394ef65

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit cbef2f2

Comment on lines +153 to +156
m_transfer_packet_spi_slave_gpi_sclk rx0, tx0, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"
m_transfer_packet_spi_slave_gpi_sclk rx1, tx1, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"
m_transfer_packet_spi_slave_gpi_sclk rx2, tx2, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"
m_transfer_packet_spi_slave_gpi_sclk rx3, tx3, PACKET_SIZE, bitId, SCLK_PIN, SDI_PIN, SDO_PIN, "MODE3", "MSB"

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

4. Aborted bursts desynchronize the slave 🐞 Bug ☼ Reliability

DO_5X_TRANSFER invokes transfer macros that wait only for clock transitions and cannot abort when
chip select becomes inactive. If chip select is deasserted before all 80 clocks arrive, later bursts
finish the interrupted transfer at the wrong boundary and the slave remains offset until its core is
restarted.
Agent Prompt
## Issue description
PRU1 cannot abandon a partial five-word transfer when chip select becomes inactive, so subsequent bursts remain aligned to the interrupted transaction rather than their own boundaries.

## Fix Focus Areas
- examples/spi_driver/firmware/am261x-lp/icss_m1_pru1_fw/main.asm[116-157]
- examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[362-410]

## Recommended Fix
Make the slave transfer path monitor the chip-select input while waiting for each clock edge and return an aborted status when it rises. On abort, discard partial receive data, wait for a fresh high-to-low chip-select transition, reinitialize all five transfer registers, and begin the next burst at word zero.

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

Comment on lines +138 to +141
### Fixed at firmware build time (edit `firmware/am261x-lp/icss_m1_pru0_fw/main.asm` and rebuild)

- **Packet size** — fixed at 16 bits (`PACKET_SIZE`). The underlying macros
(`spi_master_macros.inc`/`spi_slave_macros.inc`) enforce **1-32 bits** at

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

5. Firmware customization breaks the demo 🐞 Bug ≡ Correctness

The fixed-configuration section directs users to edit only PRU0 firmware even though packet size and
pin assignments are independently defined by PRU1 and the pin routing is generated from SysConfig.
Changing either advertised setting by following these instructions leaves the two endpoints or
physical routing inconsistent, preventing the customized round trip from operating correctly.
Agent Prompt
## Issue description
The customization instructions name only PRU0 firmware, but packet-size and pin changes also require corresponding PRU1 firmware and SysConfig updates.

## Fix Focus Areas
- examples/spi_driver/readme.md[138-150]

## Recommended Fix
Split the build-time settings by component. State that packet-size changes must be applied consistently to both PRU firmware files, pin changes must update the relevant PRU constants and SysConfig routing before regeneration, and only the master timing compensation values are confined to PRU0.

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

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit ff049dd

signed-off by Ayushman <a-ayushman@ti.com>
; Returns:
; - The received data packet is stored in the `dataReg` register.
;************************************************************************************
m_read_packet_spi_slave_lsb_gpo_sclk .macro dataReg, PACKETSIZE, bitId, SCLK_PIN, SDI_PIN, MODE

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

4. Slave low-bit-first reads fail to build 🐞 Bug ≡ Correctness

m_read_packet_spi_slave_lsb_gpo_sclk is defined with gpo even though its own heading and the
sibling MSB read macro expose the slave input-clock API as gpi. Any firmware that calls the
documented LSB-only slave read name fails assembly with an undefined macro, while the other bit
order builds.
Agent Prompt
## Issue description
The low-bit-first slave read macro is documented with a `gpi_sclk` name but defined with `gpo_sclk`, so callers using the documented and convention-consistent name cannot assemble.

## Fix Focus Areas
- examples/spi_driver/firmware/am261x-lp/spi_slave_macros.inc[115-147]

## Recommended Fix
Rename `m_read_packet_spi_slave_lsb_gpo_sclk` to `m_read_packet_spi_slave_lsb_gpi_sclk`, matching the macro heading, the input-clock implementation, and the corresponding MSB macro.

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

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 3f78d69

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.

1 participant