Post Go back to editing

SPORT0 A does not receive data from SPORT0 B.

Thread Summary

The user is experiencing issues with SPORT0 A not receiving data from SPORT0 B via DMA on an ADSP-SC573 EZ-Board. The problem is resolved by ensuring the destination buffer is aligned on cache line boundaries, which is necessary when using external memory with the ARM core. The example code provided for the ARM core demonstrates proper alignment and secure transaction enabling, which helps in resolving the issue.
AI Generated Content

I'm using an ADSP-SC573 on an ADSP-SC573 EZ-Board.

I have trouble getting SPORT0 A to receive data that is transmitted from SPORT0 B.

The connections are as following:

This is how it looks using a logic analyzer (measured on the SPORT0 A pins).

Note: PC11 is set high by the Tx callback function and PC15 is set high by the Rx callback function.

This is my code:

/*****************************************************************************
 * TestDrivers_Core0.cpp
 *****************************************************************************/

#include <sys/platform.h>
#include <sys/adi_core.h>
#include "adi_initialize.h"
#include "TestDrivers_Core0.h"
#include <services/gpio/adi_gpio.h>
#include <drivers/sport/adi_sport.h>
#include <stdio.h>

/// Allocate memory for the GPIO service
static uint8_t gpioMemory[ADI_GPIO_CALLBACK_MEM_SIZE];

/* Handle for Tx channel */
ADI_SPORT_HANDLE hDeviceTx;

/* Handle for Rx channel */
ADI_SPORT_HANDLE hDeviceRx;

/* Memory required by the device for Rx operation */
uint8_t DeviceRxMemory[ADI_SPORT_DMA_MEMORY_SIZE];

/* Memory required by the device for Tx operation */
uint8_t DeviceTxMemory[ADI_SPORT_DMA_MEMORY_SIZE];

/* flag indicating if Tx is ready */
volatile bool txReady = false;

/* flag indicating if Rx is ready */
volatile bool rxReady = false;

/* data to be sent */
uint8_t txData[4] = { 0x81, 0x00, 0xF0, 0x0F };

/* received data */
uint8_t rxData[4] = {0, 0, 0, 0};

/*********************************************************************
    Function:       sportCallbackTx
    Description:    This is a callback function registered with the driver.
                    This function will be called when the TX completes the data transfer.
*********************************************************************/
void sportCallbackTx(void* pHandle, uint32_t u32Arg, void* pArg)
{
  ADI_SPORT_EVENT event = (ADI_SPORT_EVENT) u32Arg;

  switch (event)
  {
  case ADI_SPORT_EVENT_TX_BUFFER_PROCESSED:
    txReady = true;
    adi_gpio_Set(ADI_GPIO_PORT_C, ADI_GPIO_PIN_11);
    break;
  default:
    break;
  }
}

/*********************************************************************
    Function:       sportCallbackRx
    Description:    This is a callback function registered with the driver.
                    This function will be called when the RX completes the data transfer.
*********************************************************************/
void sportCallbackRx(void* pHandle, uint32_t u32Arg, void* pArg)
{
  ADI_SPORT_EVENT event = (ADI_SPORT_EVENT) u32Arg;

  switch (event)
  {
  case ADI_SPORT_EVENT_RX_BUFFER_PROCESSED:
    rxReady = true;
    adi_gpio_Set(ADI_GPIO_PORT_C, ADI_GPIO_PIN_15);
    break;
  default:
    break;
  }
}


/*********************************************************************
    Function:       configureTx
    Description:    Setup SPORT0 B as Tx channel
*********************************************************************/
ADI_SPORT_RESULT configureTx(void)
{
  /* open the SPORT driver */
  ADI_SPORT_RESULT eResult = adi_sport_Open(0, ADI_HALF_SPORT_B, ADI_SPORT_DIR_TX, ADI_SPORT_SERIAL_MODE, DeviceTxMemory, ADI_SPORT_DMA_MEMORY_SIZE, &hDeviceTx);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* configure the sport for data length, LSB first etc */
  eResult = adi_sport_ConfigData(hDeviceTx, // hDevice
      ADI_SPORT_DTYPE_ZERO_FILL, // eDataType
      7, // nWordLength (7 = 8 bits)
      false, // bLSBFirst (false : MSB first (Big endian) )
      false, // bEnablePack (false : Disable DMA packing)
      false); // bRightJustifiedMode (only for I2S mode)
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /*configure the clock for the SPORT. This API set the whether use the internal clock, SPORT clock etc */
  eResult = adi_sport_ConfigClock(hDeviceTx, // hDevice
      99, // nClockRatio (divide processor system clock ( SCLK) by 100)
      true, // bUseIntlClock (true : Device configured to use internal clock)
      true, // bFallingEdge (true : Use falling edge of the clock)
      false); //bGatedClk (false : Disable gated clock mode)
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* Configure the frame sync. This API configure the SPORT whether to use frame sync or not , external or internal framesync etc */
  eResult = adi_sport_ConfigFrameSync(hDeviceTx, // hDevice
      8, // nFsDivisor  Number of serial clocks between frame syncs = 7 + 1 (7 clk slots where FS is not active)
      true, // bFSRequired (true : Device requires a frame sync for its operation)
      true, // bInternalFS (true : Use internal frame sync)
      false, // bDataFS (false : Use data-dependent frame sync)    false = slutar skicka clock, true, skickar clock hela tiden och verkar hitta på data
      false, // bActiveHighFS (false : Use active high frame sync)
      false, // bLateFS (false : Use Early frame sync)
      false); // bEdgeSensitiveFS
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* Enable the DMA mode */
  eResult = adi_sport_EnableDMAMode(hDeviceTx, true);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* Register a callback for the DMA */
  eResult = adi_sport_RegisterCallback(hDeviceTx, sportCallbackTx, NULL);
  return eResult;
}

/*********************************************************************
    Function:       configureRx
    Description:    Setup SPORT0 A as Rx channel
*********************************************************************/
ADI_SPORT_RESULT configureRx(void)
{
  /* open the SPORT driver */
  ADI_SPORT_RESULT eResult = adi_sport_Open(0, ADI_HALF_SPORT_A, ADI_SPORT_DIR_RX, ADI_SPORT_SERIAL_MODE, DeviceRxMemory, ADI_SPORT_DMA_MEMORY_SIZE, &hDeviceRx);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* configure the sport for data length, LSB first etc */
  eResult = adi_sport_ConfigData(hDeviceRx, // hDevice
      ADI_SPORT_DTYPE_ZERO_FILL, // eDataType
      7, // nWordLength (7 = 8 bits)
      false, // bLSBFirst (false : MSB first (Big endian) )
      false, // bEnablePack (false : Disable DMA packing)
      false); // bRightJustifiedMode (only for I2S mode)
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /*configure the clock for the SPORT. This API set the whether use the internal clock, SPORT clock etc */
  eResult = adi_sport_ConfigClock(hDeviceRx, // hDevice
      99, // nClockRatio (divide processor system clock ( SCLK) by 100)
      false, // bUseIntlClock (false : Device configured to use external clock)
      true, // bFallingEdge (true : Use falling edge of the clock)
      false); //bGatedClk (false : Disable gated clock mode)
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* Configure the frame sync. This API configure the SPORT whether to use frame sync or not , external or internal framesync etc */
  eResult = adi_sport_ConfigFrameSync(hDeviceRx, // hDevice
      8, // nFsDivisor  Number of serial clocks between frame syncs = 7 + 1 (7 clk slots where FS is not active)
      true, // bFSRequired (true : Device requires a frame sync for its operation)
      false, // bInternalFS (false : Use external frame sync)
      false, // bDataFS (false : Use data-dependent frame sync)
      false, // bActiveHighFS (false : Use active high frame sync)
      false, // bLateFS (false : Use Early frame sync)
      false); // bEdgeSensitiveFS
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* Enable the DMA mode */
  eResult = adi_sport_EnableDMAMode(hDeviceRx, true);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  /* Register a callback for the DMA */
  eResult = adi_sport_RegisterCallback(hDeviceRx, sportCallbackRx, NULL);
  return eResult;
}


ADI_SPORT_RESULT testSport(void)
{
  ADI_SPORT_RESULT eResult;
  eResult = configureTx();
  if (eResult != ADI_SPORT_SUCCESS) return eResult;
  eResult = configureRx();
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  eResult = adi_sport_SubmitBuffer(hDeviceRx, (void *) rxData, sizeof(rxData));
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  eResult = adi_sport_SubmitBuffer(hDeviceTx, (void *) txData, sizeof(txData));
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  eResult = adi_sport_Enable(hDeviceRx, true);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  eResult = adi_sport_Enable(hDeviceTx, true);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  // Wait until Tx and Rx is ready
  while (!txReady || !rxReady)
  {
    ;
  }

  // Shut down SPORT

  eResult = adi_sport_Enable(hDeviceRx, false);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  eResult = adi_sport_Enable(hDeviceTx, false);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  eResult = adi_sport_Close(hDeviceTx);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  eResult = adi_sport_Close(hDeviceRx);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

  return eResult;
}

int main()
{
  adi_initComponents();

  adi_core_enable(ADI_CORE_SHARC0);
  adi_core_enable(ADI_CORE_SHARC1);

  uint32_t gpioMaxCallbacks;
  ADI_GPIO_RESULT result = adi_gpio_Init((void*) gpioMemory, sizeof(gpioMemory), &gpioMaxCallbacks);

  // Set PC11 as output and low
  // PC11 will go high when sportCallbackTx() is called
  result = adi_gpio_SetDirection(ADI_GPIO_PORT_C, ADI_GPIO_PIN_11, ADI_GPIO_DIRECTION_OUTPUT);
  result = adi_gpio_Clear(ADI_GPIO_PORT_C, ADI_GPIO_PIN_11);

  // Set PC15 as output and low
  // PC15 will go high when sportCallbackRx() is called
  result = adi_gpio_SetDirection(ADI_GPIO_PORT_C, ADI_GPIO_PIN_15, ADI_GPIO_DIRECTION_OUTPUT);
  result = adi_gpio_Clear(ADI_GPIO_PORT_C, ADI_GPIO_PIN_15);

  if (testSport() != ADI_SPORT_SUCCESS)
  {
    printf("SPORT fail\n");
  }
  else
  {
    printf("SPORT OK\n");

    // Compare received data
    bool success = true;
    for (uint32_t i = 0; i < sizeof(rxData); i++)
    {
      if (rxData[i] != txData[i])
      {
        success = false;
      }
    }

    if (success)
    {
      printf("Rx data OK\n");
    }
    else
    {
      printf("Rx data fail\n");
    }
  }

  while (1)
    ;

  return 0;

}

SPORT0 B is setup to transmit data. This looks fine. I can see that the sportCallbackTx() activates (PC11 goes high).

SPORT0 A is setup to receive data. It calls sportCallbackRx() and sets PC15 high. But when checking the rxData[] the DMA has not received any data. rxData[] still contains the original data.

Program output:

SPORT OK
0xaa
0xaa
0xaa
0xaa
Rx data fail

sportCallbackRx() is called when SPORT0 B has clocked out 4 bytes. So I think this would indicate that SPORT 0 A has received 4 bytes. But the buffer ( rxData[]) has not been updated.

Please advice. What am I doing wrong here?

Checking the DMA0 registers

I also looked at the DMA0 register in the debugger. This is how it looks just after calling adi_sport_Enable(hDeviceRx, true):

DMA0_ADDRSTART = 2004F604 DMA0 Start Address of Current Buffer Register (the address of my array where it is going to store the data)

DMA0_ADDR_CUR 2004F604 DMA0 Current Address Register (current address points to the beginning of my array)

DMA0_XCNT 00000004 DMA0 Inner Loop Count Start Value Register (transfer 4 byte)

This is how DMA0 looks when sportCallbackRx() is called:

Notice that DMA0_ADDR_CUR has been incremented 4 bytes to 0x200f608.

And this is my array (it has not changed):

Update

I tried instead to disable DMA mode for the Rx:

  /* Disable the DMA mode */
  eResult = adi_sport_EnableDMAMode(hDeviceRx, false);
  if (eResult != ADI_SPORT_SUCCESS) return eResult;

This seems to work:

SPORT OK
0x81
0x0
0xf0
0xf
Rx data OK

So why does the DMA mode not work?

Edit Notes

Added DMA0 register info
[edited by: masip at 8:04 AM (GMT -4) on 28 May 2021]