AnsweredAssumed Answered

Blackfin BF514F SPORT-DMA-AD73360 Chained with Loopback

Question asked by Quintinvw on May 19, 2016
Latest reply on Jun 16, 2016 by Jithul_Janardhanan

Hi,

I need help with the SPORT setup on our custom board. We are using a BF514F and a AD73360 ADC. I have the setup working perfectly with normal chained buffers. But, we have UART RX problem. Every now and again a few bytes will get corrupted (Not lost at all, I don't even get line status error interrupts and have made sure it is enabled). Our thinking is that maybe the UART RX interrupt does not get service quick enough, that the SPORT DMA interrupt (because it is a higher priority) is interrupting (nesting) the UART RX interrupt and data gets lost. Could this be?

 

So I thought that maybe not having to resubmit the buffers (used for the ADC connected via SPORT) every time I get the DMA callback from the (SPORT-DMA-ADC) would help the interrupt time to be shorter. As far as I understand, a way around this is to setup the SPORT data flow method to be chained with loopback. This means one does not need to resubmit the buffer in the DMA callback from the SPORT.

 

I just want to describe the flow quickly. Hope I can do it in a non confusing way. We have a AD76630 ADC connected to the BF514F DSP via SPORT. The SPORT is setup to use two 2-D buffers in a ping-pong way via DMA to service the ADC. The ADC samples signals at 8 kHz and the DMA generates a callback every 10ms to tell me that the data is ready. First half en then second half (ping then pong, ) This runs continually. Currently I use the SPORT in CHAINED with no loopback. SO everytime a DMA callback is generated, I resubmit the next buffer within the callback. The ADC requires the buffers a.s.a.p.

 

The ADC needs a setup to be written to it a startup that I do. So the above method has worked fine. But one always want to optimize it and I thought that doing the CHAINED with LOOPBACK would not be hard. But I am running into problems. I did read that I have to disable the DATA FLOW before I submit the new buffers but I seem to get stuck in some interrupt after enabling the dataflow again. I have more questions at the bottom of the following code extract.

 

Here is the code extract:

InboundBuffer1.Data = &InboundDataStruct.AllDataStruct.InboundData1D4Ch1[0];      // Address location of actual data buffer
  //InboundBuffer1.ElementCount       = (4 * 6 * 80); // 4 ADC's, 6 Channels Each, 80 samples per 10ms
  InboundBuffer1.ElementWidth = 2;                                                  // Bytes per element
  InboundBuffer1.CallbackParameter = (void*) 0x12345678;                            // see SPORT CallbackRoutine

  InboundBuffer1.ProcessedFlag = FALSE;

  InboundBuffer1.pNext = &InboundBuffer2;

  InboundBuffer1.XCount = X;

  InboundBuffer1.XModify = 2 * Y;

  InboundBuffer1.YCount = Y;

  InboundBuffer1.YModify = -2 * (Y * (X - 1) - 1);

 

  // Setup main buffer 2

  InboundBuffer2.Data = &InboundDataStruct.AllDataStruct.InboundData2D4Ch1[0];      // Address location of actual data buffer
  //InboundBuffer2.ElementCount       = (4 * 6 * 80); // 4 ADC's, 6 Channels Each, 80 samples per 10ms
  InboundBuffer2.ElementWidth = 2;                                                  // Bytes per element
  InboundBuffer2.CallbackParameter = (void*) 0x12345679;                            // see CallbackRoutine

  InboundBuffer2.ProcessedFlag = FALSE;

  InboundBuffer2.pNext = NULL;

  InboundBuffer2.XCount = X;

  InboundBuffer2.XModify = 2 * Y;

  InboundBuffer2.YCount = Y;

  InboundBuffer2.YModify = -2 * (Y * (X - 1) - 1);

 

  // Setup dummy buffer

  InboundDummy.Data = &InboundDummyData[0]; // Address location of actual data buffer

  InboundDummy.ElementCount = 32;

  InboundDummy.ElementWidth = 2;                        // Bytes per element

  InboundDummy.CallbackParameter = (void*) 0x22222223; // see CallbackRoutine

  InboundDummy.ProcessedFlag = FALSE;

  InboundDummy.pNext = NULL;

 

  // Setup out-bound buffer.

  OutboundBuffer.Data = &OutboundData[0];   // Address location of actual data buffer

  OutboundBuffer.ElementCount = 32;

  OutboundBuffer.ElementWidth = 2;                      // Bytes per element

  OutboundBuffer.CallbackParameter = (void*) 0x22222222;

  OutboundBuffer.ProcessedFlag = FALSE;

  OutboundBuffer.pNext = NULL;

 

// Submit SPORT out-bound buffer, write configuration data to ADC

  Result = adi_dev_Write(SPORTDriverHandle, ADI_DEV_1D, (ADI_DEV_BUFFER *) &OutboundBuffer);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  // Submit SPORT dummy in-bound buffer, required to catch junk data coming in from configuration settings write

  Result = adi_dev_Read(SPORTDriverHandle, ADI_DEV_1D, (ADI_DEV_BUFFER *) &InboundDummy);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  // Enable SPORT dataflow, enabling it essentially starts the transmit of the data to the ADC

  Result = adi_dev_Control(SPORTDriverHandle, ADI_DEV_CMD_SET_DATAFLOW, (void *) TRUE);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  //while((BSPSPORTTXDone() == FALSE));

  // todo: Need to put and exit counter here and log the error (Error, ADC not initialized), this is also here to make sure ADC   is setup before continuing to run the next part of the code where samples are received. A RX_done flag is checked in the SPORT callback to make sure all the dummy bytes are received. Thus the ADC was successfully programmed.

  while((BSPSPORTRXDone() == FALSE));

 

  // Disable SPORT dataflow, required to disable before submitting new buffers

  Result = adi_dev_Control(SPORTDriverHandle, ADI_DEV_CMD_SET_DATAFLOW, (void *) FALSE);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  // Submit SPORT running in-bound buffer

  Result = adi_dev_Read(SPORTDriverHandle, ADI_DEV_2D, (ADI_DEV_BUFFER *) &InboundBuffer1);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  // Enable SPORT dataflow

  Result = adi_dev_Control(SPORTDriverHandle, ADI_DEV_CMD_SET_DATAFLOW, (void *) TRUE);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

After the last time I enable the dataflow the code seems to get stuck in a interrupt. I've tried everything but cant get the chained with loopback to work as expected. Please help, maybe I'm following the wrong program flow. Please let me know if more information is required.

 

The SPORT setup itself is as follows:

GENERIC_STATUS_t BSPSPORTInit(U32 dataFlowMethod)

{

  U32 Result = ADI_DEV_RESULT_SUCCESS;

 

  U16  temp;            // USed to copy configuration register values into

  void *pTemp;

 

  ADI_SPORT_TX_CONFIG1_REG txConfig1;

  ADI_SPORT_TX_CONFIG2_REG txConfig2;

  ADI_SPORT_RX_CONFIG1_REG rxConfig1;

  ADI_SPORT_RX_CONFIG2_REG rxConfig2;

 

  // Setup SPORT configuration registers. All values are as recommended by the AD73360 Datasheet

  // • Configure for external SCLK.

  // • Serial Word Length = 16 bits.

  // • Transmit and Receive Frame Sync's required with every word.

  // • Receive Frame Sync is an input to the DSP.

  // • Transmit Frame Sync is an:

  //   - Input—in Frame Sync Loop-Back Mode

  //   - Output—in Non-frame Sync Loop-Back Mode.

  // • Frame Sync's occur one SCLK cycle before the MSB of the serial word.

  // • Frame Sync's are active high

 

  txConfig1.tspen = 0;

  txConfig1.itclk = 0;

  txConfig1.tdtype = 0;

  txConfig1.tlsbit = 0;

  txConfig1.itfs = 0;

  txConfig1.tfsr = 1;          // Transmit Frame Sync Enabled

  txConfig1.ditfs = 0;

  txConfig1.ltfs = 0;          // Frame Syncs are active high

  txConfig1.latfs = 0;

  txConfig1.tckfe = 0;

 

  txConfig2.slen = 15;         // Serial Word Length 15 = 16 bits

  txConfig2.txse = 0;

  txConfig2.tsfse = 0;

  txConfig2.trfst = 0;

 

  rxConfig1.rspen = 0;

  rxConfig1.irclk = 0;

  rxConfig1.rdtype = 0;

  rxConfig1.rlsbit = 0;

  rxConfig1.irfs = 0;

  rxConfig1.rfsr = 1;          // Receive Frame Sync Enabled

  rxConfig1.lrfs = 0;          // Frame Syncs are active high

  rxConfig1.larfs = 0;

  rxConfig1.rckfe = 0;

 

  rxConfig2.slen = 15;         // Serial Word Length 15 = 16 bits

  rxConfig2.rxse = 0;

  rxConfig2.rsfse = 0;

  rxConfig2.rrfst = 0;

 

  // SPORT Open Device

  Result = adi_dev_Open(DevMgrHandle, &ADISPORTEntryPoint, SPORT_DEVICE_NUMBER, (void *) 0x12345678, &SPORTDriverHandle, ADI_DEV_DIRECTION_BIDIRECTIONAL, DmaMgrHandle, NULL, SPORTCallback);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  /* enable SPORT0 primary transmit and receive signals */

  *pPORTG_MUX &= 0x0400; /* DR0PRI, RFS0, RSCLK0, DT0PRI, TFS0, TCLK0, UART0 TX, UART0 RX */

  ssync();

 

  /* enable peripheral function */

  *pPORTG_FER |= PG3 | PG4 | PG5 | PG6 | PG7 | PG8 | PG9 | PG10; /* DR0PRI, RSCLK0, RFS0, TFS0 , DT0PRI, TSCLK0, UART0 TX, UART0 RX */

  ssync();

 

  *pPORTG_HYSTERESIS = 0x5555;       // Turn Hysteresis on

  ssync();

 

  if(dataFlowMethod == ADI_DEV_MODE_CHAINED)

  {

    // SPORT Set device data flow method

    Result = adi_dev_Control(SPORTDriverHandle, ADI_DEV_CMD_SET_DATAFLOW_METHOD, (void *) ADI_DEV_MODE_CHAINED);

    if(Result != ADI_DEV_RESULT_SUCCESS)

    {

      return (FAIL);

    }

    ssync();

  }

 

  if(dataFlowMethod == ADI_DEV_MODE_CHAINED_LOOPBACK)

  {

    // SPORT Set device data flow method

    Result = adi_dev_Control(SPORTDriverHandle, ADI_DEV_CMD_SET_DATAFLOW_METHOD, (void *) ADI_DEV_MODE_CHAINED_LOOPBACK);

    if(Result != ADI_DEV_RESULT_SUCCESS)

    {

      return (FAIL);

    }

    ssync();

  }

 

 

  // SPORT Write TXC1 Configuration Registers

  pTemp = &txConfig1;

  temp = *((U16 *) pTemp);

  Result = adi_dev_Control(SPORTDriverHandle, ADI_SPORT_CMD_SET_TCR1, (void *) temp);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  // SPORT Write TXC2 Configuration Registers

  pTemp = &txConfig2;

  temp = *((U16 *) pTemp);

  Result = adi_dev_Control(SPORTDriverHandle, ADI_SPORT_CMD_SET_TCR2, (void *) temp);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  // SPORT Write RXC1 Configuration Registers

  pTemp = &rxConfig1;

  temp = *((U16 *) pTemp);

  Result = adi_dev_Control(SPORTDriverHandle, ADI_SPORT_CMD_SET_RCR1, (void *) temp);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  // SPORT Write RXC2 Configuration Registers

  pTemp = &rxConfig2;

  temp = *((U16 *) pTemp);

  Result = adi_dev_Control(SPORTDriverHandle, ADI_SPORT_CMD_SET_RCR2, (void *) temp);

  if(Result != ADI_DEV_RESULT_SUCCESS)

  {

    return(FAIL);

  }

  ssync();

 

  return (PASS);

}

 

Kind regards,

Quintin.

 

Andreas

Prashant

Outcomes