AnsweredAssumed Answered

ADC and interrupt in motor control

Question asked by motor on Feb 7, 2015
Latest reply on Mar 20, 2015 by Gigi
I am a newbie to STM32, and trying to use stm32f0308 discovery board to implement current feedback motor control.

I have successfully spin a 3-phase motor in open-loop control with space vector PWM. However, I got difficulties in interrupt and ADC. Basically, I am unable to start a ADC according to the desired timing in center-aligned mode as below.
             |--------------------|--------------------|     counter up and down
            0                      period                     0
             |          |
           ISR   ADC
The example code in "STM32Cube_FW_F0_V1.1.0" doesn't show how to generate this ISR to run FOC code. However, it is only in infinite loop while(1). My open-loop control is based on this infinite loop as well. In my code, I am going to implement FOC code under TIM1_CC_IRQHandler. Unfortunately, it reports that TIM1_CC_IRQHandler is never been used by doing so, although it is defined in startup_stm32f030x8.s

Moreover, the ADC samplings are incorrect, although it is able to take feedback readings from shunt resistor. Most readings are 0V/offset value; and some of them show a potion of sinusoidal envelop.

I have got stuck on this for two weeks. Appreciate for any advice! If possible, where can I find a copy of FOC source code based on general STM32?  I don't need anything else, but do need reference to configure ADC and interrupt. 
 

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f0xx_adc.h"
//#include "stm32f0xx_rcc.h"

/* Private typedef -----------------------------------------------------------*/
#define  PERIOD_VALUE       (1200 - 1)  /* Period Value  */

TIM_HandleTypeDef    TimHandle;

/* Timer Output Compare Configuration Structure declaration */
TIM_OC_InitTypeDef              sPWMConfig;
/* Timer Break Configuration Structure declaration */
TIM_BreakDeadTimeConfigTypeDef sBreakConfig;

/* Counter Prescaler value */
uint32_t uwPrescalerValue = 0;

__IO uint16_t  ADC1ConvertedValue = 0, ADC1ConvertedVoltage = 0;
__IO uint32_t ADCmvoltp = 0 ;

/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
static void svpwm(void);
static void TIM_init(void);
static void ADC_Config(void);

static void TIM1_CC_IRQHandler(void)
{
   /* Enable the ADC peripheral */
//  ADC_Cmd(ADC1, ENABLE); 
   
  /* ADC1 regular Software Start Conv */
//  ADC_StartOfConversion(ADC1);
  
    /* Test EOC flag */
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

  ADC1ConvertedValue =ADC_GetConversionValue(ADC1);
   
  /* Compute the voltage */
  ADC1ConvertedVoltage = (ADC1ConvertedValue *3300)/0xFFF;
  
  svpwm();

  __HAL_TIM_SetCompare(&TimHandle,TIM_CHANNEL_1,Ta);
  __HAL_TIM_SetCompare(&TimHandle,TIM_CHANNEL_2,Tb);
  __HAL_TIM_SetCompare(&TimHandle,TIM_CHANNEL_3,Tc);
}

int main(void)
{

  HAL_Init();

  /* Configure LED4 */
  BSP_LED_Init(LED4);

     /* ADC1 Configuration */
  ADC_Config();                         //conflict with systemclock_config()

  /* Configure the system clock to 48 MHz */
  SystemClock_Config();

  /* Compute the prescaler value to have TIM1 counter clock equal to 12MHz */
  uwPrescalerValue = (uint32_t) ((SystemCoreClock  / 48000000) - 1);
 

  TIM_init();
 

  while(1)
  {
  }
}

 

static void SystemClock_Config(void)
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_OscInitTypeDef RCC_OscInitStruct;
 
  /* Select HSE Oscillator as PLL source */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct)!= HAL_OK)
  {
    Error_Handler();
  }

  /* Select PLL as system clock source and configure the HCLK and PCLK1 clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1)!= HAL_OK)
  {
    Error_Handler();
  }
}

static void TIM_init(void)
{
  /* Select the Timer instance */
  TimHandle.Instance = TIM1;
 
  TimHandle.Init.Prescaler         = uwPrescalerValue;
  TimHandle.Init.Period            = PERIOD_VALUE;
  TimHandle.Init.ClockDivision     = 0;
  TimHandle.Init.CounterMode       = TIM_COUNTERMODE_CENTERALIGNED1;
  TimHandle.Init.RepetitionCounter = 0;

  if(HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  /*##-2- Configure the PWM channels #########################################*/
  /* Common configuration for all channels */
  sPWMConfig.OCMode       = TIM_OCMODE_PWM1;
  sPWMConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
  sPWMConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
  sPWMConfig.OCIdleState  = TIM_OCIDLESTATE_SET;
  sPWMConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET; 
  sPWMConfig.OCFastMode   = TIM_OCFAST_DISABLE; 

  /* Set the Break feature & Dead time */
  sBreakConfig.BreakState       = TIM_BREAK_ENABLE;
  sBreakConfig.DeadTime         = 10;
  sBreakConfig.OffStateRunMode  = TIM_OSSR_ENABLE;
  sBreakConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
  sBreakConfig.LockLevel        = TIM_LOCKLEVEL_1; 
  sBreakConfig.BreakPolarity    = TIM_BREAKPOLARITY_HIGH;
  sBreakConfig.AutomaticOutput  = TIM_AUTOMATICOUTPUT_ENABLE;
 
  /* GPIOC Periph clock enable */
  RCC->AHBENR |= (1 << 19);
  //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
 
  /* ADC1 and TIM1 Periph clock enable */
  RCC->APB2ENR |= (1 << 9);

    TIM1->CCER |=(1<<13);
  TIM1->CR1 = 1;                      //control register counter enable
  TIM1->BDTR |= (1<<15);              //break and deadtime register main output enable

  if(HAL_TIMEx_ConfigBreakDeadTime(&TimHandle, &sBreakConfig) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }
 
    /* Set the pulse value for channel 1 */
  sPWMConfig.Pulse = Ta; 
  if(HAL_TIM_PWM_ConfigChannel(&TimHandle, &sPWMConfig, TIM_CHANNEL_1) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }
 
    /* Set the pulse value for channel 2 */
  sPWMConfig.Pulse = Tb;
  if(HAL_TIM_PWM_ConfigChannel(&TimHandle, &sPWMConfig, TIM_CHANNEL_2) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }
 
  /* Set the pulse value for channel 3 */
  sPWMConfig.Pulse = Tc;
  if(HAL_TIM_PWM_ConfigChannel(&TimHandle, &sPWMConfig, TIM_CHANNEL_3) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }
 
  /* Set the pulse value for channel 4 */
  sPWMConfig.Pulse = trigger_value;
  if(HAL_TIM_PWM_ConfigChannel(&TimHandle, &sPWMConfig, TIM_CHANNEL_4) != HAL_OK)
  {
    /* Configuration Error */
    Error_Handler();
  }
  /*##-3- Start PWM signals generation #######################################*/
  /* Start channel 1 */
  if(HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
  {
    /* Starting Error */
    Error_Handler();
  }
  /* Start channel 1N */
  if(HAL_TIMEx_PWMN_Start(&TimHandle, TIM_CHANNEL_1) != HAL_OK)
  {
    /* Starting Error */
    Error_Handler();
  }
 
  /* Start channel 2 */
  if(HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
  {
    /* Starting Error */
    Error_Handler();
  }
  /* Start channel 2N */
  if(HAL_TIMEx_PWMN_Start(&TimHandle, TIM_CHANNEL_2) != HAL_OK)
  {
    /* Starting Error */
    Error_Handler();
  }
 
  /* Start channel 3 */
  if(HAL_TIM_PWM_Start(&TimHandle, TIM_CHANNEL_3) != HAL_OK)
  {
    /* Starting Error */
    Error_Handler();
  }
  /* Start channel 3N */
  if(HAL_TIMEx_PWMN_Start(&TimHandle, TIM_CHANNEL_3) != HAL_OK)
  {
    /* Starting Error */
    Error_Handler();
  }

}

static void ADC_Config(void)
{
  ADC_InitTypeDef          ADC_InitStructure;
  GPIO_InitTypeDef         GPIO_InitStructure;
 
  HAL_RCC_DeInit();
 

  /* GPIOC Periph clock enable */
  RCC->AHBENR |= (1 << 19);
 
  /* ADC1 and TIM1 Periph clock enable */
  RCC->APB2ENR |= (1 << 9);
 
  /* Configure ADC Channel11 as analog input */
  GPIO_InitStructure.Pin = GPIO_PIN_1 ;
  GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
  GPIO_InitStructure.Pull = GPIO_NOPULL ;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
 
    /* ADCs DeInit */ 
  ADC_DeInit(ADC1);
 
  /* Initialize ADC structure */
  ADC_StructInit(&ADC_InitStructure);
 
  /* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits  */
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_CFGR1_EXTEN_0;   
  ADC_InitStructure.ADC_ExternalTrigConv =  ADC_ExternalTrigConv_T1_CC4;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
  ADC_Init(ADC1, &ADC_InitStructure);
 

  /* Convert the ADC1 Channel 11 with 1.5 Cycles as sampling time */
  ADC_ChannelConfig(ADC1, ADC_Channel_11 , ADC_SampleTime_1_5Cycles);
 
  /* ADC Calibration */
  ADC_GetCalibrationFactor(ADC1);
 
  /* Enable the ADC peripheral */
  ADC_Cmd(ADC1, ENABLE);    
 
  /* Wait the ADRDY falg */                          
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
 
  /* ADC1 regular Software Start Conv */
  ADC_StartOfConversion(ADC1);
}

 


Outcomes