ADSP-SC573
Production
The ADSP-SC57x/ADSP-2157x processors are members of the SHARC® family of products. The ADSP-SC57x processor is based on the SHARC+® dual-core and the arm...
Datasheet
ADSP-SC573 on Analog.com
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?
Moved to CrossCore Embedded Studio and Add-ins Community.
Hi,
From your code, we understand that you are not enabling secure transaction for SPORT devices. While using DMA mode, you have to call adi_spu_EnableMasterSecure() API for enabling peripherals to generate secure transactions.
Hope the code which we shared in the below Ezone thread might be helpful for you.
ez.analog.com/.../i-would-need-example-code-for-loopback-sport
Regards,
Nishanthi.V
Thank you. I have tested the example code and it works better. But it doesn't transfer the whole data (256 byte). There is some data at the end that isn't received. And if I increase it more there still is a few bytes at the end that does not get received. Could you verify it?
It only receives 240 byte.
Can you confirm this?

And if I run the rx in interrupt mode it receives all bytes.
And here I filled the receive buffer with value 99. The image shows that the last bytes of the receive buffer doesn't get over written by new data by the DMA, they still contain the value 99.
The nRxCallbackCounter is 1. This indicates that the DMA is finished.
Something goes wrong with the DMA.

I tested some more. If I increase the nBufferRx0[] by 128 byte it will receives all 256 bytes. Why is that so? It is like the end of the array is forbidden to write to by DMA. So by increasing the array size I can pass this blocking.

I continued to experiment. I added alignment to the nBufferRx0[]. I got it to work if I aligned it with it's own size. But I don't know why. (the #pragma alignments in the example code arenot recognized by the compiler)

I found this in the reference manual:

I don't know if it implies what I have found or if they mean something else.
If I run your example in Core 1 (SHARC) it works. All the problems occur when running it in Core 0 (Arm Cortex). Why is that? How should the example be modified to run in Core 0?
Hi,
The reason of issue is that destination buffer is not aligned on cache line boundaries.
We have previously shared the project for SHARC0 core where buffers are created in SHARC0's internal memory. Cache coherency issue will not occur.
But by default, Buffers are placed are in external memory when we run project in ARM core.
If they are not aligned 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.
Please find the attached working project for ARM core.
Hope this helps you
Regards,
Santhi