This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS570LS1227: ADC FIFO ID Conversion Error

Part Number: TMS570LS1227
Other Parts Discussed in Thread: HALCOGEN

Hi there,

For a motor control software I triggered the ADC mesasuremnt on the PWM (Cntr Zero and PRD; two measurements per period). There are totally 7 channels to be measured at PWM Cntr Zero and Prd (3x Current; 4 x Voltages). The FIFO Size of ADC Group 1 is set to 14, therefore the adc_notifiaction is called once per PWM cycle. (Look at the images below)

With the following code the adc results are read (code snipped in adc_notification):

        static adcData_t bufferRawAdcData[14] = {0};
        static uint32_t AdcCnt = 0;
        AdcCnt = adcGetData(adcREG1, adcGROUP1, bufferRawAdcData);

AdcCnt is always 14 since there are 14 ADC values. Channel ID 8 is in bufferRawAdcData[0]  (when PWM = ZERO) and bufferRawAdcData[8] (when PWM=PRD) This acutally works, but the not reliable! The main problem is, that sometimes on bufferRawAdcData[0] is Channel ID 14, followed by Channel ID 15. After sevral measurements the whole thing recovers and  bufferRawAdcData[0] is again ID 8. This behaviour must no happen! There is an offset! It is not deterministic, when this happens! Sometimes after 5 seconds; sometimes multiple times per seconds etc...

The following modification of the HalCoGen function (file adc.c) solved the problem:

uint32 adcGetData(adcBASE_t *adc, uint32 group, adcData_t * data)
{
    uint32  i;
    uint32  buf;
    uint32  mode;    
    uint32  index = (adc == adcREG1) ? 0U : 1U;

    uint32  intcr_reg = adc->GxINTCR[group];
    uint32  count = (intcr_reg >= 256U) ? s_adcFiFoSize[index][group] : (s_adcFiFoSize[index][group] - (uint32)(intcr_reg & 0xFFU));
    adcData_t *ptr = data;

/* USER CODE BEGIN (16) */
/* USER CODE END */

    mode = (adc->OPMODECR & ADC_12_BIT_MODE);

    if(mode == ADC_12_BIT_MODE)
      {
        /** -  Get conversion data and channel/pin id */
        for (i = 0U; i < count; i++)
        {
          buf        = adc->GxBUF[group].BUF0;
          /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
          ptr->value = (uint16)(buf & 0xFFFU);
          ptr->id    = (uint32)((buf >> 16U) & 0x1FU);
          /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
          ptr++;
        }
      }
      else
      {
        /** -  Get conversion data and channel/pin id */
        for (i = 0U; i < count; i++)
        {
          buf        = adc->GxBUF[group].BUF0;
          /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
          ptr->value = (uint16)(buf & 0x3FFU);
          ptr->id    = (uint32)((buf >> 10U) & 0x1FU);
          /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
          ptr++;
        }
      }


    adc->GxINTFLG[group] = 9U;

    /**   @note The function adcInit has to be called before this function can be used.\n
    *           The user is responsible to initialize the message box.
    */

/* USER CODE BEGIN (17) */

    while(!(adc->GxINTFLG[group] & 0x04))
    {
        index = (adc == adcREG1) ? 0U : 1U;
        adcData_t *ptr = data;

        if(mode == ADC_12_BIT_MODE)
          {
            /** -  Get conversion data and channel/pin id */
            for (i = 0U; i < count; i++)
            {
              buf        = adc->GxBUF[group].BUF0;
              /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
              ptr->value = (uint16)(buf & 0xFFFU);
              ptr->id    = (uint32)((buf >> 16U) & 0x1FU);
              /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
              ptr++;
            }
          }
          else
          {
            /** -  Get conversion data and channel/pin id */
            for (i = 0U; i < count; i++)
            {
              buf        = adc->GxBUF[group].BUF0;
              /*SAFETYMCUSW 45 D MR:21.1 <APPROVED> "Valid non NULL input parameters are only allowed in this driver" */
              ptr->value = (uint16)(buf & 0x3FFU);
              ptr->id    = (uint32)((buf >> 10U) & 0x1FU);
              /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */
              ptr++;
            }
          }


        adc->GxINTFLG[group] = 9U;
    }
/* USER CODE END */

    return count;
}

Is there a better solution? It looks like a timing problem, the while-loop whitin adcGetData empties the buffer. Do I have to reset a flag before starting the next conversion?

Thanks for your help.

Best regards,

Patrick

  • Hi Patrick,

    It does look like a timing issue: how often do you trigger the ADC group1 using the ePWM event? Is there enough time for the conversions to complete and the data to be completely read out between the triggers? If you find that the time is not sufficient, you could choose to use two groups instead of one for the conversions. You have to identify two separate trigger events of course, but then you could manage the timings such that you are reading and processing results from one conversion group while the other group is converting.

    If the number of conversions results read out in each interrupt routine is 14, then all the available results must be getting read out without explicitly checking for the memory empty flag.

    I will try your setup on my bench when I am in the office tomorrow as well. Can you please also include your ePWM configuration?

    Regards,
    Sunil
  • Hi Sunil

    The adc notification is executed with 16kHz, PWM Settings for ETPWM1:

    Settings for ETPWM2/3:

    How can I check that the ADC  is emptied within one pwm period? PWM Period is 62.5us, time for conversion is 6us. There shouldn't be a problem.

    Thank you for your help.

    Best regards,

    Patrick

  • Hi Sunil

    I didn't hear any further response from you. Unfortunately it is still an issue.

    Could you try my setup on your testbench?

    Do you require further documents/settings?

    Thank you and regards,

    Patrick

  • Hi Patrick,

    The ePWM settings show the PWM period to be 31.25 us. This is half of what you stated in your previous post. Which one is the desired setting?

    Regards,
    Sunil
  • Patrick,

    Can you upload your CCS code project?

    Regards,
    Sunil
  • Dear Sunil

    It is a project fropm our company which uses a licened safety RTOS. Is it possible to send you the CCS Project in private?

    I would rather not upload inside the forum.

    Thank you and best regards,

    Patrick

  • Hi Sunil

    Yes, this is due to the fact the PWM counter is set as up-down; therefore its period is twice 31.25 us. (I configured this via software while initialization)

    Regards,
    Patrick