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