cancel
Showing results for 
Search instead for 
Did you mean: 

Is a safe way to convert others ADC channels using the same interrupt mechanism employed by a FOC 4.0 library?

Muscle Man
Associate III

Hi,

I'm here to ask if someone knows a safe way to convert other analog sources using the ADC macrocells

of a STM32F407ZE MCU used to spin a BLDC motor by means of a FOC 4.0 library.

I mean, is there a way to correctly hook my code to the ADC IRQ Handler employed by FOC to manage

its tasks? Unfortunately we haven't the code of FOC library, so I do not know how to accomplish this task.

I have to convert the analog signals coming from 4 NTC resistors, and other two signals. They are attached

to ADC channels belonging to ADC2 and ADC3 (someone told me that FOC uses ADC module 1 and ADC

module 2).

At the moment the only way to accomplish this task is to run this code (after FOC initialization):

 /* Enable ADC2 and GPIO clocks ****************************************/
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
 
 /* Configure ADC2 Channel3 pin as analog input ******************************/
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 /* ADC Common Init **********************************************************/
 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;
 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
 ADC_CommonInit(&ADC_CommonInitStructure);
 
 /* ADC2 Init ****************************************************************/
 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
 ADC_InitStructure.ADC_ScanConvMode = DISABLE;
 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_CC1;
 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
 ADC_InitStructure.ADC_NbrOfConversion = 1;
 ADC_Init(ADC2, &ADC_InitStructure);
 
 /* ADC2 regular channel 3 configuration **************************************/
 ADC_RegularChannelConfig(ADC2, ADC_Channel_3, 1, ADC_SampleTime_56Cycles);
 
 /* Enable ADC2 */
 ADC_Cmd(ADC2, ENABLE);
 
 
 /* Enable ADC3 and GPIO clocks ****************************************/
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
 
 /* Configure pins as analog input ******************************/
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_10;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 GPIO_Init(GPIOF, &GPIO_InitStructure);
 
 /* ADC Common Init **********************************************************/
 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div8;
 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
 ADC_CommonInit(&ADC_CommonInitStructure);
 
 /* ADC3 Init ****************************************************************/
 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
 ADC_InitStructure.ADC_ScanConvMode = DISABLE;
 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_CC1;
 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
 ADC_InitStructure.ADC_NbrOfConversion = 1;
 ADC_Init(ADC3, &ADC_InitStructure);
 
 /* ADC3 regular channels configuration **************************************/
 ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 1, ADC_SampleTime_56Cycles);
 ADC_RegularChannelConfig(ADC3, ADC_Channel_9, 1, ADC_SampleTime_56Cycles);
 ADC_RegularChannelConfig(ADC3, ADC_Channel_14, 1, ADC_SampleTime_56Cycles);
 ADC_RegularChannelConfig(ADC3, ADC_Channel_15, 1, ADC_SampleTime_56Cycles);
 
 /* Enable ADC3 */
 ADC_Cmd(ADC3, ENABLE);
 
 

Basically I program every ADC channel in the same way: ADC1,2,3 modules in Indipendent Mode, every ADC module to act for a singular conversion (no scan mode).

Then in the main loop I execute the following code:

 uint16_t usCurrent1;
 uint16_t usCurrent2;
 uint16_t usNTC1;
 uint16_t usNTC2;
 uint16_t usNTC3;
 
 /* Single conversion */
 ADC_RegularChannelConfig(ADC2, ADC_Channel_3, 1, ADC_SampleTime_56Cycles);
 ADC_SoftwareStartConv(ADC2);
 while (ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == RESET) {}
 usCurrent1 = ADC_GetConversionValue(ADC2) >> 4;
 
 ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 1, ADC_SampleTime_56Cycles);
 ADC_SoftwareStartConv(ADC3);
 while (ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET) {}
 usCurrent2 = ADC_GetConversionValue(ADC3) >> 4;
 
 ADC_RegularChannelConfig(ADC3, ADC_Channel_9, 1, ADC_SampleTime_56Cycles);
 ADC_SoftwareStartConv(ADC3);
 while (ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET) {}
 usNTC1 = ADC_GetConversionValue(ADC3) >> 4;
 
 ADC_RegularChannelConfig(ADC3, ADC_Channel_14, 1, ADC_SampleTime_56Cycles);
 ADC_SoftwareStartConv(ADC3);
 while (ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET) {}
 usNTC2 = ADC_GetConversionValue(ADC3) >> 4;
 
 ADC_RegularChannelConfig(ADC3, ADC_Channel_15, 1, ADC_SampleTime_56Cycles);
 ADC_SoftwareStartConv(ADC3);
 while (ADC_GetFlagStatus(ADC3, ADC_FLAG_EOC) == RESET) {}
 usNTC3 = ADC_GetConversionValue(ADC3) >> 4;

Practically, not knowing how to hook-up to the ADC interrupt handler code implemented in the FOC 4.0, I used

a "polling" approach configuring the ADC macrocell to make a singular conversion of the selected channel and

waiting for the End Of Conversion of that channel.

What I can see is that usCurrent1, usCurrent3, usNTC1, usNTC3 and usNTC3 takes three kinds of strange values

(near 0, near 511 and near 1023). I think this behavior is due to the fact that the FOC and my pieces of code interact

in the wrong way.

Someone can tell me if I made the wrong approach and/or if there is another way to solve this problem?

Thank in advance everyone can help me..

1 ACCEPTED SOLUTION

Accepted Solutions
Saurabh SONA
Associate II

Using ADCs in independent mode especially the ones used for current sensing can interfere with MC operations or vice-versa. There is a dedicated method of using the ADCs for additional application analog inputs. Basically it involves requesting the MC library to perform a conversion whenever the ADC peripheral is free and checking if the conversion is complete. It is quite similar to what you are doing but the actual instance for performing the conversion is controlled by the MC library.

Just initialize the ADC channels that you need and use the following APIs to perform the conversions in the main while(1) loop or the SysTick interrupt handler:

 if(MC_RegularConvState() == UDRC_STATE_IDLE) //Ensure that no other user conversion is ongoing

 {

   MC_RequestRegularConv(ADC_Channel_0, ADC_SampleTime_28_5Cycles); //ADC_Channel_0, Sample Duration of 28.5 Cycles

 }

 else if(MC_RegularConvState() == UDRC_STATE_EOC) //Check if requested user conversion is complete

 {

   ADC_UsrVal = MC_GetRegularConv(); // Fetch the converted ADC value

}

I have used this method with FOC Firmware v4.1.0 so should work in your case too. Hope it helps.

View solution in original post

1 REPLY 1
Saurabh SONA
Associate II

Using ADCs in independent mode especially the ones used for current sensing can interfere with MC operations or vice-versa. There is a dedicated method of using the ADCs for additional application analog inputs. Basically it involves requesting the MC library to perform a conversion whenever the ADC peripheral is free and checking if the conversion is complete. It is quite similar to what you are doing but the actual instance for performing the conversion is controlled by the MC library.

Just initialize the ADC channels that you need and use the following APIs to perform the conversions in the main while(1) loop or the SysTick interrupt handler:

 if(MC_RegularConvState() == UDRC_STATE_IDLE) //Ensure that no other user conversion is ongoing

 {

   MC_RequestRegularConv(ADC_Channel_0, ADC_SampleTime_28_5Cycles); //ADC_Channel_0, Sample Duration of 28.5 Cycles

 }

 else if(MC_RegularConvState() == UDRC_STATE_EOC) //Check if requested user conversion is complete

 {

   ADC_UsrVal = MC_GetRegularConv(); // Fetch the converted ADC value

}

I have used this method with FOC Firmware v4.1.0 so should work in your case too. Hope it helps.