Jump to content

    
MPetrovich

STM32F103 не пишет в TIM4->DIER

Recommended Posts

Сегодня провел такой эксперимент: подавал 3,3В поочередно на каждый вход АЦП (РА3...РА5), а на остальные не подавал ничего. На референсный вход РА6 подал 12В. Т.е. обеспечил условия, при которых ZeroCross не происходит. Сделал присвоение x=V_BEMF; после получения в V_BEMF результата конверсии. Выводил в терминал строчки: № шага, № канала АЦП, значение х. В х после окончания шага должно было оставаться последнее значение V_BEMF. Неожиданно для меня получилось вывести результат. На каждом канале АЦП на номере соответствующем тому, куда в этот момент подавалось 3,3В выводились значения равные напряжению после делителей.

Подключил резисторную звезду и надеялся увидеть на всех каналах АЦП значения равные опорному напряжению. Но почему то выводится только на одном канале РА4 значение равное удвоенному опорному напряжению. Т.е. похоже измерение происходит не в момент, когда фаза свободна, а в момент, когда она ШИМится.

Пока взял паузу потому что уже "глаз замылился".

Share this post


Link to post
Share on other sites

После небольшого перерыва вернулся к схеме и кое-что подправил. Прежде всего подрихтовал код. Вот так теперь выглядит процедура оббработки прерывания по обновлению счётчика ШИМ:


void BEMF_Sampling(void)
{
  //wait, while there are interconnection glitch
  volatile uint8_t i=10;  while(i>0)i--; //29*0,167~5uSec
  B12_ON
  ADC_SoftwareStartConvCmd(ADC1, ENABLE); //Start ADC conversion manually
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)==RESET); //Wait while ADC sample complete.
  //After read conersion result from ADC_DR, flag EOC is cleared.
  uint16_t V_BEMF = ADC_GetConversionValue(ADC1);//read ADC Conversion Value in V_BEMF;
 //*************************************************************************
  //Первый результат измерения всегда отбрасывается, т.к. в Commutate() Prev_V_BEMF=0
  if(/*(V_BEMF>(V_ref-300))&&(V_BEMF<(V_ref+300))&&*/(Prev_V_BEMF!=0))
   {
     if(((V_BEMF>V_ref)&&(Prev_V_BEMF<=V_ref))||((V_BEMF<V_ref)&&(Prev_V_BEMF>=V_ref)))
       {
   	     TIM4->DIER = 0;//Disable TIM4 interrupts, stop V_BEMF measuring
         ZeroCross = TRUE;
	     LED_ON
	     if(GPIOB->ODR & GPIO_Pin_13)GPIOB->BRR = GPIO_Pin_13;//if bit 13 SET, RESET bit
	     else GPIOB->BSRR = GPIO_Pin_13;//if bit 13 RESET, SET bit
  //*****************************************************************
//Save time from last commutation to ZeroCross event. It's the FIRST half of intercommutation time.
	    uint16_t Temp = TIM_GetCounter(TIM3);
        //TimeSinceCommutation = TIM_GetCounter(TIM3);
// Filter the  ZC detection with earlier measurements through IIR(recoursive) filter.
   //TimeSinceCommutation = (1*Temp+3*TimeSinceCommutation)/4;
//Write this value in TIM3_CCR1 register. It's the SECOND half of intercommutation period
   //When counter will reach this value, next Commutate() will happen
        //TIM3 -> CNT = 0;
        //TIM3 -> CCR1 = 2*TimeSinceCommutation;
       }
   }
//*****************************************************************/
  Prev_V_BEMF = V_BEMF;//Save V_BEMF in Prev_V_BEMF
  if(ZeroCross != TRUE)  B12_OFF
}

 

 

И самое главное - нашел ошибку в последовательности операций в функции, работающей в основном цикле и определяющей последовательность работы всей программы:


static void PWMControl(void)
{
/* Calculate duty cycle from speed reference value.
 * SPEED_Ref=ADC channel_7 conversion result: 0<SPEED_Ref<4096
 * Duty_Cycle =((100*SPEED_Ref)/ADC_RESOLUTION);
 */
    Set_PWM_Duty_Cycle(SPEED_Ref/41);
  //Wait when counter will reach TIM3_CCR1 value = TimeSinceCommutation.
   //Then Commutate() will happen.
   while(TIM_GetFlagStatus(TIM3, TIM_IT_CC1)==RESET);
   //Commutate();
   TIM3->SR = 0; B12_OFF
   ZeroCross = FALSE;   LED_OFF   Prev_V_BEMF=0;
   TIM4->DIER = 0;//Запрещаем прерывания от PWM, т.к. идут пререходные процессы.
   PWM_Distribution(nextCommutationStep);//Переключаем фазы мотора на следующий шаг комутации.
   TIM3 -> CCR1 = 300;//TimeSinceCommutation-300;//2250-300;//
   TIM3 -> CNT = 0;
   Read_Vref();   Read_SPEED_Ref();
   ADC_Multiplexor(ADMUXTable[nextCommutationStep]);
   nextCommutationStep++;//Commutation step counter. Define the next commutation step number
   if (nextCommutationStep > 5)
          {nextCommutationStep = 0;}
   //*************************************************************************************

   while(TIM_GetFlagStatus(TIM3, TIM_IT_CC1)==RESET);
   TIM3->SR = 0;//Clear allTIM3 flags
   TIM4->SR = 0;  TIM4->DIER |= 0x0001;//Enable TIM4 Update interrupt.
   TIM3->CCR1 = 2*TimeSinceCommutation;//4500;//
}

Раньше операции  Read_Vref();   Read_SPEED_Ref(); были в начале процедуры и это сбивало последовательность работы мотора и переключение каналов АЦП. Сечас вроде всё на месте и картинка на осциллографе выглядит вот так:

 

PHASE_ZeroCrossing.JPG

Жёлтый луч  - это как раз сигнал ZeroCross. Он получается на ноге В13 как результат вот этих действий

if(GPIOB->ODR & GPIO_Pin_13)GPIOB->BRR = GPIO_Pin_13;//if bit 13 SET, RESET bit
	     else GPIOB->BSRR = GPIO_Pin_13;//if bit 13 RESET, SET bit

Пунктирная линия - уровень порогового напряжения ZeroCross.

Получается теперь вроде бы всё работает, однако, если раскомментировать вот эти строчки:


   //TimeSinceCommutation = (1*Temp+3*TimeSinceCommutation)/4;
//Write this value in TIM3_CCR1 register. It's the SECOND half of intercommutation period
   //When counter will reach this value, next Commutate() will happen
        //TIM3 -> CNT = 0;
        //TIM3 -> CCR1 = 2*TimeSinceCommutation;

мотор начинает стопориться. Вот причину этого я пока не понимаю:umnik2:

 

Share this post


Link to post
Share on other sites

Мне с самого начала не понравилась форма сигнала противо-эдс на шагах паузы. У вас трапеции направлены в другую сторону. Как-то неправильно.
Погуглил по картинкам, вот похожие картинки, человеку тоже не нравились: BLDC BEMF not right
Пишет, что починил это, что мотор крутится при таких картинках чуть ли не в противофазе к норме.
Посмотрите, может поможет...

Share this post


Link to post
Share on other sites
On 6/20/2020 at 12:02 AM, Baser said:

Посмотрите, может поможет...

Посмотрел, почитал. Как я понял из всего прочитанного, нужно очень точно попасть в "ворота" (doors, как их называет один из участников обсуждения) коммутации.

Решил последовать его совету. Запустил программу начиная с периода коммутации в 10мСек и с шагом в 20мкСек укорачивал этот интервал, делая по 12 шагов на каждом значении периода коммутации. Процедура занимала довольно много времени и я сидел пялясь в осциллограф и рассчитывая увидеть хоть что то похожее на картинки из апноутов. 

Однако увы, ничего похожего я так и не дождался, хотя раскрутил мотор основательно. Не знаю сколько оборотов он выдал, но уже перешёл с гула на вой, а потом на визг:shok:

Позапускав эдак несколько раз, убедился, что картина не меняется и перестал насиловать несчастный моторчик. Так что снова вышел облом.:swoon:

Share this post


Link to post
Share on other sites

После перерыва вернулся к своей схеме. Подкорректировал код и добился устойчивой работы мотора в диапазоне порядка 70-75% от максимальной скважности. причём регулировка скорости в этом диапазоне происходит без срывов и даже быстрое изменение скважности потенциометром не приводит к потере контроля. При всём при том форма сигнала на фазах осталась такой, как и была - "неконфессиональной", я бы сказал)))

При превышении определённого уровня скважности ШИМ мотор резко меняет режим вращения и на сигналах с фаз видно сильное зашумление. Контроль оборотов потенциометром, тем не менее, сохраняется, но и при уменьшении скважности до минимальной (10%) сигнал всё равно остаётся очень "грязным".

Проанализировав вышеописанную ситуацию, я предположил, что при увеличении скважности не хватает времени на зарядку конденсаторов подкачки в драйверах верхних ключей, т.к. они заряжается через нагрузку - обмотки. Возможно сопротивление обмоток таково, что оно на частоте ШИМ (10кГц) ощутимо увеличивает время зарядки конденсатора подкачки.

Исходя из этих соображений решил попробовать установить зарядовый насос для подкачки заряда в конденсатор, питающий драйвер верхнего ключа в период, когда верхний ключ открыт. Схема зарядового насоса (charge pump) была позаимствована мной из апнота фирмы IR. Прежде, чем реализовывать это схемное решение, хочу узнать мнения участников о схеме и о самом принципе. Вот схема:

 

POWER_STAGE.JPG

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.