AM6422: ADC reading via SPI

Other Parts Discussed in Thread: AM6422, SYSCONFIG

I'm writing to ask for your expertise on a challenging issue customer is facing with reading data from two ADCs simultaneously on the AM6422. Please see below  email:

We've implemented a solution to communicate with two ADS7038Q ADCs in parallel using two SPI peripherals (MCSPI0 and MCSPI1), but the implementation is proving to be unreliable.

Our Current Approach

The intended logic is to use a master-slave clocking scheme:
  1. MCSPI0 is configured as the clock master, generating the SPI clock for both devices.
  2. MCSPI1 is set up as "data-only" and is intended to use the clock from MCSPI0.
  3. A single GPIO pin acts as a shared Chip Select (CS) for both ADCs.
Here is a view of the hardware connections from our schematic:
Our transaction sequence is as follows:
  1. Pull the shared GPIO CS pin low.
  2. We then initiate the two MCSPI_transfer calls. To manage the timing, we use the Init delay parameter from the SysConfig tool specifically when starting the transfer for the slave peripheral (MCSPI1), right before the master (MCSPI0) begins generating the clock.
  3. We wait for both transfers to complete using semaphores.
  4. Finally, we pull the shared GPIO CS pin high.
The Problem: Inconsistent and Unreliable Data
The core challenge we're trying to solve is reliably controlling this shared-clock and shared-CS architecture from software.
Despite this setup, the communication is not stable. Even when tuning the Init delay and experimenting with different SPI clock frequencies, we are consistently getting different or corrupted values from the ADCs on each read cycle.
It seems that even with the Init delay, we cannot overcome the inherent timing jitter of starting two peripheral operations from software. The slight, unpredictable delay is enough to cause misalignment and unreliable data.
Given these synchronization challenges, I was hoping you might have some suggestions.

An alternative solution was suggested that involves using the PRU to "bit-bang" the SPI protocol directly. This method would provide the deterministic, cycle-accurate timing needed to solve our synchronization problem.
However, this solution is not feasible for our current hardware design. The PRU bit-banging approach requires that the CLK, MOSI, and CS lines be controllable as general-purpose I/O (GPIO). Our board does not use GPIO for these signals; they are wired directly to the dedicated MCSPI peripheral pins on the processor. Because of this hardware constraint, we cannot implement this PRU-based solution without a board revision.
Do you know of a more robust,  method on the AM6422 to trigger two SPI transfers at the exact same time?
For example, could we use an internal event trigger or another peripheral feature to ensure both MCSPI modules start in perfect lockstep?
Any insights or alternative approaches you could recommend would be a great help.
Thank you for your time and consideration.
  • Hi Ricardo, let me re-assign this question to our MCU+RTOS McSPI/SPI expert as I believe this is the SDK customer is using. Please correct me if I am wrong. I will also loop our HW experts for their inputs to your question "Could we use internal event trigger or another peripheral feature to ensure both MCSPI modules start in perfect lockstep?".

    In the meantime, few questions:

    - How is customer triggering MCSPI_transfer() for both SPI peripherals (MCSPI0 and MCSPI1)? 

    - Are they using DMA?

    - How MCSPI_transfer calls() is sync between both peripherals? any SemaphoreP_post() or any other barrier?

    Thank you,

    Paula

  • Hi Riccardo,

    First thing that comes to my mind is - did you try with SPI0 <-> ADC0 communication only? That is, disconnect SPI1 by leaving pin mux to default (gpios). Test with SPI0 such as it is the only SPI + ADC in the system. 

    Also please also make sure D0 is an output and D1 is an input, because I know they are configurable in a SPI register and this could be missed.

    Thanks,

    Stan

  • Hi Stanislav, Paula, 
    please find below their reply:

    I have already tried the communication SPI0 <-> ADC0 and it is working properly.
    Regarding your questions:
    1. How MCSPI_transfer() is triggered for both peripherals
    The dual SPI transfers are triggered like this:
    2. DMA Usage
    No, I am NOT using DMA. The implementation uses callback-based transfers with interrupt mode:
    3. Synchronization Mechanism
    The synchronization uses binary semaphores with callback functions:
    Semaphore Infrastructure:
    Callback Functions Post Semaphores:
    Main Thread Waits for Both:
    Summary
    • Transfer Triggering: Sequential MCSPI_transfer() calls (SPI0 then SPI1)
    • DMA: No - uses interrupt-driven callback mode
    • Synchronization: Binary semaphores with SemaphoreP_post() in callbacks and SemaphoreP_pend() to wait for both completions
    Here you can find the configuration that I am using:

    For SPI0 :
    For SPI1:
    For contoling the shared CS I am using GPIO ADC0_CS:
    And the Clock and CS of the SPI1 are declared as GPIO inputs:
    Thank you so much for your help.
  • Hi Riccardo, thanks for the information, we will take a look at it and come back to you

    Paula

  • Hi Riccardo,

    I can see these discrepancies for SPI1:

    1. SPI1 should be slave but configured as master (controller)

    2. SPI1 should be clock consumer but clock pin is not selected

    2.a) I don't think I understand what means clock is GPIO. SPI in slave mode needs clock on its own clock input. Clock via GPIO is not possible.

    3. SPI1 module is in 4 pin mode but CS is handled via GPIO. 

    and SPI0:

    1. SPI0  module is in 4 pin mode but CS is handled via GPIO. 

    Overall, this SPI0 + SPI1 configuration is very unusual and it's hard to tell it will work flawlessly. My personal opinion is that connecting SPI0 and SPI1 to their respective ADCs with their respective clocks (CS may stay 1x GPIO) will lead to very similar results in terms of timing but will be much more reliable as a setup. As I can see, they are testing with 2MHz but the ADC supports as fast as 60MHz, and at these speeds clock and data signals need special attention when routing PCB traces. Routing the clock to several consumers would be a challenge.

    What I mean is I think it's worth to be tested (SPI0 = SPI1 = masters with their own clocks to ADCs) on another board in parallel with the current tests, if they didn't already.

    Regards,

    Stan

  • Hi,

    Here is my observation based on the description above:

    1. The naive way to achieve parallel communication with 2 ADCs would be to use two MCSPI Controllers and talking to ADC1 and ADC2 at the same time. Then why is MCSPI1 and MCSPI0 used as a controller and slave respectively.
    2. If MCSPI1 is used as a peripheral and is expected to get Clock from Master in your case, MCSPI0, then MCSPI1 should be configured as a Peripheral.
    3. To configure MCSPI in general and MCSPI1 as a peripheral please refer this detailed FAQ:  [FAQ] SK-AM64B: MCSPI Integration Guide 
    4. Moreover, refer the following code(from the e2e response) which demonstrates Peripheral mode: https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1305146/sk-am64b-r5f-spi-dma-in-mcspi_ms_mode_peripheral/5064289#5064289

    Best Regards,

    Vaibhav