cancel
Showing results for 
Search instead for 
Did you mean: 

Trigering ADC in the Middle of PWM ON Duty Cycle

bluewaters213
Associate III
Posted on February 07, 2013 at 19:23

Hello,

My intention is using TIM1 Complementary PWM Channel 1-3 for Brushless Motor Control. I want to sample the Phase Voltage at the middle of PWM ON Duty Cycle. I have configure TIM1 to output 6 Channel PWM but there seems to be a problem in triggering an event at the middle on the High Duty Cycle.I configure TIM1 CH1-3 & CH1-3N as 20Khz PWM output while CH4 is configure in Timing Output Compare  with interrupt enable.I toggle PB8-PB9 on CH4 Output Compare match Interrupt.

The Problem is I get multiple toggle in one PWM period. I was hoping to see one  PA8-9 Toggle per PWM Period.I plan on triggering the ADC in the CC4 Interrupt which should happen at the middle of the PWM ON duty cycle with little delay.I have change CCR4 Value but it still stay thesame.

I am Microchip Fan and new to STM32F.In Microchip dsPIC30F Microcontroller, it is pretty easy and straight forward.I have attached logic analyzer screen shot of PWM Channels and PA8-9 .

Logic Analyzer Channel Identification.

Channel0 =>CH1

Channel1=>CH1N

Channel2 =>CH2

Channel3=>CH2N

Channel4 =>CH3

Channel5=>CH3N

Channel6=>PA8

Channel7=>PA9

My Source Code

#include ''stm32f10x.h''

void Init_6CHPWM();

void TIM1_CC_IRQHandler(void);

int main(void)

{

  RCC-> CFGR |= RCC_CFGR_ADCPRE_DIV4;     //ADC divided by 4

  /*Enable all GPIO Clock & Alternate Function Clock*/

  RCC->APB2ENR = RCC_APB2ENR_AFIOEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN;

  /*Enable ADC1 & ADC2 Clock*/

  RCC->APB2ENR |= RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN;

  /*Enable TIMER1 & USART1 Clock*/

  RCC->APB2ENR |= RCC_APB2ENR_TIM1EN | RCC_APB2ENR_USART1EN;

  /*Enable TIMER2, TIMER3 & I2C1 Clock*/

  RCC->APB1ENR = RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN |RCC_APB1ENR_I2C1EN | RCC_APB1ENR_TIM4EN;

  RCC->AHBENR = RCC_AHBENR_DMA1EN ;   //DMA1 clock enable

  GPIOB->CRL = 0x444444AA;    //Configure PB0 & PB1 as Alternate Function Push Pull Output

  GPIOB->CRH = 0x44444222;    //Configure PB8 & PB9 as Output (Push Pull)

  GPIOA->CRL = 0xA4444444;   //PA7 Alternate Function Push Pull Output

  GPIOA->CRH = 0x44444AAA;  //PA8 - PA10 Alternate Function Push Pull Output

  /*Partial remap TIM1: CH1/PA8,CH2/PA9,CH3/PA10,CH4/PA11,CH1N/PA7,CH2N/PB0,CH3N/PB1

   * Remap USART1: TX/PB6, RXPB7   */

  AFIO->MAPR |= AFIO_MAPR_TIM1_REMAP_PARTIALREMAP | AFIO_MAPR_USART1_REMAP;

  Init_6CHPWM();                       //Initialize 20KHz PWM on CH 1-3

    while(1)

    {

    }

}

void Init_6CHPWM()

{

    TIM1->CCMR1 |= 0x00006878; //CH1 & CH2 Output Compare, Preload, PWM1 Enable

    //CH3 Output Compare, Preload, PWM1 Enable | CH4 Output Compare, Timing Enable

    TIM1->CCMR2 |= 0x00008878;

    /*CH1, CH2, CH3 and their Corresponding  Complement Output Enable*/

    TIM1->CCER  |= 0x00000555;

    TIM1->CR1 |= 0x00000080;   // Centre Align Mode 1 & Auto-reload Preload enable

    TIM1->PSC = 0;

    TIM1->ARR = (2800 - 1);    // Auto reload value 1400 (Period = 50us)

    TIM1->CCR1 = 1400;         // Start PWM duty for channel 1

    TIM1->CCR2 = 1000;        // Start PWM duty for channel 2

    TIM1->CCR3 = 600;         // Start PWM duty for channel 3

    TIM1->CCR4 = 1700;         //CH4 Compare Value

    TIM1->BDTR |= 0x00008800;  // Enable Main O/P & Enable OSSR

    TIM1->CR1 |= 0x00000001;   //Counter Enable

    TIM1->DIER |= 0x00000010;  //Capture/Compare 4 interrupt enable

    NVIC_EnableIRQ(TIM1_CC_IRQn); // Enable interrupt from TIM1 Compare (NVIC level)

}

void TIM1_CC_IRQHandler(void)

{

  if(TIM1->SR & TIM_SR_CC4IF)          // if CC4IF flag is set

    {

      TIM3->SR &= ~TIM_SR_CC4IF;     //Clear CC4IF Flag

      GPIOB->ODR ^= (1 << 8);       // toggle LED state

      GPIOB->ODR ^= (1 << 9);

    }

}

I will like to know if it is possible?. if if Yes How?.

Regards

SLim

Please forgive my english

6 REPLIES 6
jj2
Associate II
Posted on February 07, 2013 at 22:29

Other ARMs (and perhaps this STM32) have a means for the PWM Generator to ''auto-trigger'' an ADC conversion - precisely at the transition from PWM ''count up to count down.''  Believe this method is usually called ''center-based PWM'' as opposed to, ''edge-based.'' 

This yields the correctly ''time-slotted'' current measurement you seek.  It is most important during lower duty cycles - less so in higher ones.

Suggest a deep/thorough review of the PWM Section of the datasheet - searching for the PWM's native ability to generate such trigger.  Any other method is less efficient - and may add errors which are hard to resolve and may be inconsistent...

Update: Again - after quick scan of your code - we see you've selected ''center align'' - which should be proper.  Check further to see if some trigger attaches to this mode.  Again - other ARM MCUs can auto-trigger an ADC conversion directly from this up/down PWM count transition...
bluewaters213
Associate III
Posted on February 07, 2013 at 23:15

Hello,

Thanks for your reply. I have gone through the TIM1 section of the datasheet but there is no way thence I turn my attention to the ADC section. I think the ADC can be External Trigger by TIM1_CC4 event (Page 217 (RM0008-Reference manual).Is this what I am looking?.

Slim

jj2
Associate II
Posted on February 08, 2013 at 03:33

Rm0008 suggests that you have an early 32MF103 device, iirc.  Is this the case?  My belief is that there is more capability w/in newer F3 and F4 family devices.  And - it may be that these newer devices are better explained - and can lead you to a better solution.

It should be possible for you to generate a fixed ~20% duty cycle from a PWM Generator - and to monitor both it and the top instruction w/in the ''hoped for'' ADC interrupt service - which that PWM Generator has triggered.  The top instruction w/in the ADC interrupt should generate a marker pulse - so that you can see how close it is to the center of the PWM signal.

A simplification exists which allows you to make your actual motor current measurements only upon the transition of your Hall signal inputs.  You achieve this by enabling the ADC conversion only if a ''new'' Hall transition is detected.   In our case - we only make that ADC based phase current measurement when a new ''low side'' phase driver becomes active.

One last suggestion - we use the ARM's analog comparator to constantly monitor all 3 phase currents.  Should an over-current be detected - we ''kill'' that particular PWM cycle - and only activate the subsequent ones when the comparator signals that they are, ''in range.''

bluewaters213
Associate III
Posted on February 08, 2013 at 06:52

Hello,

I am sorry that I did not mention the MCU I am using.It is STM32F103RB.Are you suggesting that there is no Hardware Means of trigeering ADC in the middle of the  PWM Duty ON period?.Do I have to find a work around means or implement your idea?.

Regards

jj2
Associate II
Posted on February 08, 2013 at 16:23

''Are you suggesting that there is no Hardware Means of trigeering ADC in the middle of the  PWM Duty ON period?.''

No - I simply have not used STM32 recently enough - in this mode - to know for sure.  What I've attempted to do is give you (hoped for) key insights - which enable you and other readers to explore this issue. 

As stated - other ARM MCU makers do provide an ADC trigger from their ''center aligned'' PWM Generators - when so ordered.  The hope here is that this is an ARM provided capability - and has not been ''shut-down'' by the vendor's PWM implementation.

MCU datasheet chapters which you should seriously review are: PWM, ADC - and Timers as a last resort.  You should search specifically for, ''Interrupt Triggers'' especially any/all which impact the ADC. 

If such a serious search does not answer - perhaps a review of datasheets for newer, more capable F3 and F4 parts will yield some benefit.  (and I suppose - this may be a poorly or even undocumented feature - w/in the aging STM103)

If you have the time - you may perform a comprehensive review of each/every Register - which bear upon PWM, ADC and (last) Timer - trying to learn if and where such ADC trigger bit is located.  Again - multiple, other ARM MCUs have such feature - it may just require bit more ''digging'' on your part to find it.  Good luck...

Konami
Senior

Did you find an answer to this?