More SPI problems? Sending 4 bytes and receives 4 bytes but first byte is wrong in DMA mode. Interrupt mode works fine.

I'm using ADSP-SC573 ez-board.

I have setup SPI0 to send 4 bytes and connected MOSI to MISO so the DSP receives the sent bytes. This is a test so to find out how to send and receive SPI data at the same time (as I must later do when writing a driver for a chip).

But when I use DMA the first byte is wrong/junk and the rest of bytes is shifted on byte. If I use interrupt mode it is OK.

Image from logic analyzer using interrupt (works OK):

Image from logic analyzer using DMA at 100kHz (first byte is junk, rest of data shifted on byte):

Image from logic analyzer using DMA at 10MHz (even more crazy. It even sends data one more time (3 bytes)):

I have aligned the buffers and setup the SPU (hope those are correct):

My code (run on core 0):

#define USE_DMA // Define to use DMA
#define SPI_CLOCK_FREQUENCY 100e3 // Defines the SPI clock frequency

#include <sys/platform.h>
#include <sys/adi_core.h>
#include "adi_initialize.h"
#include "TestDrivers_Core0.h"
#include <drivers/spi/adi_spi.h>
#include <stdio.h>
#include <services/spu/adi_spu.h>
#include <sys/platform.h>
#include <stdint.h>
#include <inttypes.h>

#if !defined(ADI_CACHE_LINE_LENGTH)
/* The ADI_CACHE_* macros were introduced in CCES 2.4.0 in <sys/platform.h>.
 * If using an older toolchain, define them here.
 */
#if defined(__ADSPARM__)
#define ADI_CACHE_LINE_LENGTH (32uL)
#define ADI_CACHE_ALIGN_MIN_4 __attribute__((aligned(ADI_CACHE_LINE_LENGTH)))
#elif defined(__ADSP215xx__)
#define ADI_CACHE_LINE_LENGTH (64uL)
#define ADI_CACHE_ALIGN_MIN_4 _Pragma("align 64")
#else
#error Unknown ADI_CACHE_LINE_LENGTH
#endif
#define ADI_CACHE_ROUND_UP_SIZE(size, type) \
    (((((((size) * sizeof(type)) \
           + (ADI_CACHE_LINE_LENGTH - 1uL)) \
          / ADI_CACHE_LINE_LENGTH) * ADI_CACHE_LINE_LENGTH) \
      + (sizeof(type) - 1uL)) / sizeof(type))
#endif

/*=============  LOCAL DEFINES   =============*/

/* When the processor's L1 and/or L2 cache is enabled the receive data buffers must */
/* be aligned on cache line boundaries. If they are not then any data access by the core may        */
/* pull a buffer into the cache while the DMA is operating on the data buffer. Both the core and    */
/* the DMA are masters on the bus. The core will be performing cache operations. The DMA engine will*/
/* not be. So it is important for the application to both align data that will be operated on by the*/
/* DMA and to separate this data from other application data.                                       */
#if defined(__ICCARM__)
#define SRCALIGN _Pragma("data_alignment=4")
#define DSTALIGN _Pragma("data_alignment=32")
#elif defined(__ADSPGCC__)
#define DSTALIGN ADI_CACHE_ALIGN_MIN_4
#define SRCALIGN __attribute__ ((aligned (4)))
#else
#define DSTALIGN ADI_CACHE_ALIGN_MIN_4
#define SRCALIGN _Pragma("align 4")
#endif

#ifdef USE_DMA
#define SPI_MEMORY_SIZE ADI_SPI_DMA_MEMORY_SIZE
#else
#define SPI_MEMORY_SIZE ADI_SPI_INT_MEMORY_SIZE
#endif

/* SPU handle */
static ADI_SPU_HANDLE hSpu;

/* Memory required for the SPU operation */
static uint8_t SpuMemory[ADI_SPU_MEMORY_SIZE];

ADI_SPI_HANDLE hSpi;
uint8_t SpiMemory[SPI_MEMORY_SIZE];

SRCALIGN uint8_t tx[4] = {1,2,3,4}; // 4 bytes to send
DSTALIGN uint8_t rx[ADI_CACHE_ROUND_UP_SIZE(4, uint8_t)]; // 4 bytes to receive


bool spuInit(void)
{
  while (1)
  {
    // Initialize SPU Service
    if (adi_spu_Init(0u, SpuMemory, nullptr, nullptr, &hSpu)) break;

    // Make SPI0 to generate secure transactions
    if ( adi_spu_EnableMasterSecure(hSpu, 69, true)) break;

    // Make SPI0 TX DMA to generate secure transactions
    if (adi_spu_EnableMasterSecure(hSpu, 62, true)) break;

    // Make SPI0 RX DMA to generate secure transactions
    if (adi_spu_EnableMasterSecure(hSpu, 63, true)) break;
    return true;
  }

  // Failure
  return false;
}

bool test(void)
{
  while (1)
  {
    if (adi_spi_Open(0, &SpiMemory, SPI_MEMORY_SIZE, &hSpi)) break;

    /* device in master of the SPI interface */
    if (adi_spi_SetMaster(hSpi, true)) break;

    if (adi_spi_SetTransceiverMode(hSpi, ADI_SPI_TXRX_MODE)) break;

#ifdef USE_DMA
    /* use DMA */
    if (adi_spi_EnableDmaMode(hSpi, true)) break;
#else
    /* use interrupt */
    if (adi_spi_EnableDmaMode(hSpi, false)) break;
#endif
    /* SPI slave select in controlled by software not hardware */
    //if (adi_spi_SetHwSlaveSelect(hSpi, false)) break;
    if (adi_spi_SetHwSlaveSelect(hSpi, false)) break;

    if (adi_spi_ManualSlaveSelect(hSpi, true)) break;

    /* send zeros if tx SPI underflows*/
    if (adi_spi_SetTransmitUnderflow(hSpi, true)) break;

    /* data transitions on falling edge of clock */
    if (adi_spi_SetClockPhase(hSpi, false)) break;

    if (adi_spi_SetClockPolarity(hSpi, false)) break;

    /* Setup SPI clock */
    uint16_t spiClockRate = (112.5e6 / SPI_CLOCK_FREQUENCY) - 0.5f; // Note it is (112.5e6 / clkFrequency) - 1.0f + 0.5f     0.5f is for rounding before truncating
    if (adi_spi_SetClock(hSpi, spiClockRate)) break;

    /* SPI slave select is on SPI slave select 6 pin */
    if (adi_spi_SetSlaveSelect(hSpi, ADI_SPI_SSEL_ENABLE6)) break;

    /* SPI data transfers are 8 bit */
    if (adi_spi_SetWordSize(hSpi, ADI_SPI_TRANSFER_8BIT)) break;

    /* generate tx data interrupt when watermark level breaches 50% level */
    /* DMA watermark levels are disabled because SPI is in interrupt mode */
    if (adi_spi_SetTxWatermark(hSpi, ADI_SPI_WATERMARK_50, ADI_SPI_WATERMARK_DISABLE, ADI_SPI_WATERMARK_DISABLE)) break;

    /* generate rx data interrupt when watermark level breaches 50% level */
    /* DMA watermark levels are disabled because SPI is in interrupt mode */
    if (adi_spi_SetRxWatermark(hSpi, ADI_SPI_WATERMARK_50, ADI_SPI_WATERMARK_DISABLE, ADI_SPI_WATERMARK_DISABLE)) break;

    if (adi_spi_RegisterCallback(hSpi, NULL, NULL)) break;

    if (adi_spi_SlaveSelect(hSpi, true)) break;

    ADI_SPI_TRANSCEIVER transceiver = { NULL, 0, tx, 4, rx, 4 };
    if (adi_spi_ReadWrite(hSpi, &transceiver)) break;

    if (adi_spi_SlaveSelect(hSpi, false)) break;

    printf("Received: ");
    for (uint8_t i = 0; i < 4; i++)
    {
      printf("%" PRIx8 "\n", rx[i]);
    }

    return true;
  }

  // Failure
  return false;
}



int main()
{
  spuInit();
  /**
   * Initialize managed drivers and/or services that have been added to
   * the project.
   * @return zero on success
   */
  adi_initComponents();

  test();

  return 0;
}

Why is this happening? What am I doing wrong?

Getting tired of these SPI-problems. Takes too much time to setup this DSP.



Added one more image showing behavioral at 10MHz with DMA.
[edited by: masip at 8:26 AM (GMT -4) on 16 Jun 2021]
Parents
  • 0
    •  Analog Employees 
    on Jun 16, 2021 3:23 PM

    Hello,

    We are testing our sample code using manual slave select mode. we will get back to you soon.

    Best Regards,
    Santhakumari.K

  • 0
    •  Analog Employees 
    on Jul 12, 2021 3:29 PM in reply to santha.vijay

    Hello,

    Please refer the attached test code for SC-573 in DMA mode. Here we are transferring 10bytes of data from SPI2 to SPI0. We are supporting SSLDD 3.0 in Griffin and GL processors too.

    The support for SC5xx is also available in sources when the macro SSLDD_3_SPI_SUPPORT_FOR_SC5xx is defined in the project then SSLDD 3.0 drivers are picked in adi_spi.c.

    Please follow the below procedures to include it.
    1. Open system.svc of project.
    2. Add the SPI Driver for SHARC(1.0.1) from "Device Drivers and System Service" list.
    3. Add the SPI Driver Support for SC5xx (1.0.0) from "SSLDD 3.0 support for ADSP-SC5xx" add-in lists.
    4. Click on Finish.

    Hope you can use this as a base for your development.

    TestSPI_Core1.zip

Reply
  • 0
    •  Analog Employees 
    on Jul 12, 2021 3:29 PM in reply to santha.vijay

    Hello,

    Please refer the attached test code for SC-573 in DMA mode. Here we are transferring 10bytes of data from SPI2 to SPI0. We are supporting SSLDD 3.0 in Griffin and GL processors too.

    The support for SC5xx is also available in sources when the macro SSLDD_3_SPI_SUPPORT_FOR_SC5xx is defined in the project then SSLDD 3.0 drivers are picked in adi_spi.c.

    Please follow the below procedures to include it.
    1. Open system.svc of project.
    2. Add the SPI Driver for SHARC(1.0.1) from "Device Drivers and System Service" list.
    3. Add the SPI Driver Support for SC5xx (1.0.0) from "SSLDD 3.0 support for ADSP-SC5xx" add-in lists.
    4. Click on Finish.

    Hope you can use this as a base for your development.

    TestSPI_Core1.zip

Children
No Data