cancel
Showing results for 
Search instead for 
Did you mean: 

[STM8] PWM does not stop.

ankhola
Associate III

Hi friends,

Again I have come with a problem. Please see my code. PWM works as usual. But it is made to stop by resetting PC3 bit, PWM does not stop rather, it behaves randomly. Sometimes the PWM channels are driven high, driven low or PWM pulse is there. Many modifications has turned futile. Hence I seek your support.

Regards

ankhola

Main,c

/* MAIN.C file
 * 
 * Copyright (c) 2002-2005 STMicroelectronics
 */


#include "stm8s.h"
#include "ccp.h"


void inv_on(void);
void inv_off(void);
void sw_state(void);

unsigned int pwm_duty1 = 40;
unsigned int pwm_duty2 = 50;
unsigned int i=0;
unsigned int duty;
unsigned char toggle=0;
unsigned char off_state;
unsigned char on_state;

unsigned const int table []= {0, 16, 32, 48, 64, 80, 96, 
112, 127, 143, 159, 174, 190, 205, 220, 235, 250, 264, 279,
293, 307, 321, 335, 349, 362, 375, 388, 400, 413, 425, 437,
448, 460, 471, 481, 492, 502, 511, 521, 530, 539, 547, 555, 
563, 570, 577, 584, 590, 596, 602, 607, 612, 616, 620, 623,
627, 630, 632, 634, 636, 637, 638, 638, 638, 638, 637, 636, 
634, 632, 630, 627, 623, 620, 616, 612, 607, 602, 596, 590, 
584, 577, 570, 563, 555, 547, 539, 530, 521, 511, 502, 492, 
481, 471, 460, 448, 437, 425, 413, 400, 388, 375, 362, 349,
335, 321, 307, 293, 279, 264, 250, 235, 220, 205, 190, 174, 
159, 143, 127, 112, 96, 80, 64, 48, 32, 16};



@far @interrupt void TIM2_UPD_OVF_IRQHandler(void) {
    // 1. Clear the Interrupt Pending Bit
   if (TIM2->SR1 & TIM2_SR1_UIF)
    {
    if (toggle == 0)  { 
   TIM1_SetCompare2 (0);
	 i++;
     if(i == 125) {
		 i = 0;	
     toggle = ~ toggle;  
		 	
								  }
	 TIM1_SetCompare1(table[i]);
		  

										  }
	else             { 
   TIM1_SetCompare1 (0);
	 i++;
     if(i == 125) {
		 i = 0;	
	 toggle = ~ toggle;
	 
		 	                }
	 TIM1_SetCompare2(table[i]);
		  

									  }
                 
        TIM2->SR1 &= ~TIM2_SR1_UIF;
    }
}



void sw_state(void)  {
	if (GPIO_ReadInputPin, (GPIOC, GPIO_PIN_3))
	on_state = 1;
	else
	on_state = 0;
							}
							

void inv_on()  {

	TIM1_ComplementaryPWM_Init();
	TIM2_OC_Init();
	//GPIO_Init(GPIOD,GPIO_PIN_7, GPIO_MODE_OUT_PP_HIGH_FAST); 
	 enableInterrupts();
do  {
	sw_state();      
                             
	}  while (on_state == 1);
			}
						
	void inv_off () {
//TIM1 -> CCER1 &= 0xFA;
TIM1->CCER1 &= ~TIM1_CCER1_CC1E;
TIM1->CCER1 &= ~TIM1_CCER1_CC1NE;
TIM2 -> IER = TIM2_IER_UIE;
GPIOB -> DDR |= 0x03;
GPIOB -> ODR &= 0xFC;
GPIOC -> DDR |= 0x06;
GPIOC -> ODR &= 0xF9;
GPIOB -> CR1 |= 0x03;
GPIOC -> CR1 |= 0x06;
TIM1_CtrlPWMOutputs(DISABLE);
do  {
	sw_state();     
                            
	} while (on_state == 0);
								 }
	  

	
										 
	

void main(void)
{
	Clock_Config();
	gpio_init();
	do  {
 sw_state();   
if (on_state == 1)
inv_on();      
else
inv_off();       
		} while (1);
		    
	
//while(1) {
        // Main loop can be used for other tasks or dynamically changing PWM values
 //   }
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
  while (1)
  {
		
  }
}
#endif

 

ccp.h

#include "stm8s.h"


void gpio_init(void)  {
	GPIO_Init(GPIOC, GPIO_PIN_3, GPIO_MODE_IN_PU_IT);
										}

void Clock_Config(void) {
    CLK->ICKR |= CLK_ICKR_HSIEN; // Enable HSI
    while (!(CLK->ICKR & CLK_ICKR_HSIRDY)); // Wait for stabilization
    CLK->CKDIVR = 0x00; // HSI 16MHz / 1 = 16MHz
    CLK->SWR = 0xE1; // Use HSI as master clock
}

void TIM2_OC_Init(void)
{
	CLK->PCKENR1 = 0xFF;
        TIM2->PSCR = 0x00; 
    TIM2 -> ARRH = 1280 >> 8;
    TIM2 -> ARRL = 1280 & 0xFF;
   //TIM2->CCMR1 = 0x00; 
		//TIM2 -> EGR |= (1 << TIM2_EGR_UG);
    TIM2 -> IER = 0x01;
   TIM2->CR1 |= TIM2_CR1_CEN;
}



void TIM1_ComplementaryPWM_Init(void)
{
    // 1. Enable TIM1 Clock
	CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, ENABLE);

    // 2. Configure GPIOs for TIM1 Channels (PC6-CH1, PC7-CH1N, PC3-CH2, PC4-CH2N)
    // Note: Depends on specific STM8 variant, check datasheet for pinout
    GPIO_Init(GPIOC, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST);
    GPIO_Init(GPIOC, GPIO_PIN_2, GPIO_MODE_OUT_PP_LOW_FAST);
    GPIO_Init(GPIOB, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST);
    GPIO_Init(GPIOB, GPIO_PIN_1, GPIO_MODE_OUT_PP_LOW_FAST);

    // 3. Time Base Configuration: PWM Frequency = 16MHz / (15+1) / (999+1) = 1kHz
    TIM1_TimeBaseInit(1, TIM1_COUNTERMODE_UP, 639, 0);

    // 4. Channel 1 Configuration (PWM1 Mode)
    TIM1_OC1Init(TIM1_OCMODE_PWM1, 
                 TIM1_OUTPUTSTATE_ENABLE, 
                 TIM1_OUTPUTNSTATE_ENABLE, // Enable complementary
                 500, // Duty Cycle (CCR1)
                 TIM1_OCPOLARITY_HIGH, 
                 TIM1_OCNPOLARITY_HIGH, 
                 TIM1_OCIDLESTATE_RESET, 
                 TIM1_OCNIDLESTATE_RESET);

    // 5. Channel 2 Configuration (PWM1 Mode)
    TIM1_OC2Init(TIM1_OCMODE_PWM1, 
                 TIM1_OUTPUTSTATE_ENABLE, 
                 TIM1_OUTPUTNSTATE_ENABLE, // Enable complementary
                 250, // Duty Cycle (CCR2)
                 TIM1_OCPOLARITY_HIGH, 
                 TIM1_OCNPOLARITY_HIGH, 
                 TIM1_OCIDLESTATE_RESET, 
                 TIM1_OCNIDLESTATE_RESET);

    // 6. Dead Time Configuration (e.g., 10 ticks)
    TIM1->DTR = 0x30;

    // 7. Enable Main Output
    TIM1_CtrlPWMOutputs(ENABLE);

    // 8. Enable Timer
    TIM1_Cmd(ENABLE);
}

 

1 ACCEPTED SOLUTION

Accepted Solutions

@Peter BENSCH wrote:

... and while we're at it: if you paste code only after formatting it with a code formatter (e.g. with formatter.org/cpp-formatter, coding style Google, indent 2, column 80), community members can read and understand your code more easily and quickly.

Regards
/Peter


Hi, Peter. It is  humbly expressed that I could not get you as I am not so familiar with this community, 

However, regarding my original problem, I undertook relentless tests for several days. Lastly, I detected the bug. During a test, where GPIOC Pin 3 was not used, but configured.  Only the function inv_on() and inv_off() with delay set after each, within a do-while loop was done to see if those functions are working well. It was observed that those functions were working well. But, unwittingly, I pressed the switch connected to GPIOC Pin 3, and saw that the problem appears. Then I moved  the polling pin to other port. Now there is no issue. No de-bounce effect. Code is working flawlessly. 

 

Thank you Peter.

Regards,

ankhola

View solution in original post

5 REPLIES 5
Peter BENSCH
ST Employee

There are several issues in your code; the main ones explaining the random PWM behaviour are:

  1. TIM2 interrupt is never disabled when you turn the inverter off:
    TIM2->IER = TIM2_IER_UIE; // This actually (re‑)enables the update interrupt instead of disabling it.​

     

  2. TIM1 is not cleanly stopped / re‑initialised. You call TIM1_CtrlPWMOutputs(DISABLE); but the timer is still running and the compare registers are modified in the ISR.
  3. GPIO PC3 used as input is also configured/forced as output:
    GPIOC->DDR |= 0x06;  // sets PC1, PC2 as outputs (ok), but not PC3
    GPIOC->ODR &= 0xF9;  // clears PC1, PC2 bits (mask 0b11111001)​
  4. Both inv_on() and inv_off() contain blocking do…while loops polling PC3. If the switch is noisy, you may enter/exit these functions at arbitrary times while timers and interrupts are active, again causing inconsistent PWM states. Better: use an EXTI on PC3 or handle debouncing and state changes in the main loop, not in blocking loops inside the on/off functions.

Suggested minimal fix to stop PWM cleanly when PC3 goes low:

void inv_off(void)
{
  // Stop using TIM2 to modulate the sine
  TIM2->IER &= ~TIM2_IER_UIE;    // disable update interrupt
  TIM2->CR1 &= ~TIM2_CR1_CEN;    // stop timer 2 (optional but cleaner)

  TIM1_CtrlPWMOutputs(DISABLE);  // Disable all PWM outputs from TIM1
  TIM1->CR1 &= ~TIM1_CR1_CEN;
  TIM1->CCER1 &= ~(TIM1_CCER1_CC1E | TIM1_CCER1_CC1NE |
                   TIM1_CCER1_CC2E | TIM1_CCER1_CC2NE);

  // Force bridge pins to a defined low state
  GPIOB->DDR |= 0x03;
  GPIOB->CR1 |= 0x03;
  GPIOB->ODR &= ~0x03;

  GPIOC->DDR |= 0x06;   // only PC1, PC2 as outputs
  GPIOC->CR1 |= 0x06;
  GPIOC->ODR &= ~0x06;

  // Wait until PC3 becomes high again
  do {
    sw_state();
  } while (on_state == 0);
}

And in TIM2_OC_Init() do not re‑enable the interrupt from elsewhere; only enable it when you really want PWM to run.

Hope this helps?

Regards
/Peter

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
ankhola
Associate III

Thanks Peter for spending your valuable time and patience to support a newbie. The mistake to disable TIM2 interrupt, clearing UIE bit was detected after uploading the post, but the error in configuring GPIOC in inv_off() function has been escaped. I have modified the code inserting your suggested snippet of code, but the problem still persists. It is not clear to me as to how TIM1 counter continues when it is stopped using TIM1->CR1 &=  ~TIM1_CR1_CEN. It is noticed that the problem occurs while switching off PWM, For starting, there is no problem. It is also noticed that sometimes when switched off, continuous PWM pulse is seen with fixed duty, no variation in width of pulse. It shows that TIM2 interrupt is stopped, hence the last retrieved value of the sine table continues. If there is noise in switch on/off, effect will last for some cycles, then it should work as per position of switch. But it appears that control is stuck to a position as the pattern of pulse is not changed. I like to share a video of the pulse train captured in oscilloscope, but due to ignorance of uploading video, I failed.

 

Regards,

ankhola  

Peter BENSCH
ST Employee

From your description the timers themselves seem to behave correctly; what you are seeing is most likely caused by the switch handling / state machine rather than TIM1 ignoring CEN.

Please check:

  1. Confirm the exact code now used in inv_on(), inv_off(), TIM2_UPD_OVF_IRQHandler() and sw_state() - there may still be a place where TIM2 or TIM1 are (re)enabled unintentionally, or where toggle/compare registers are not re‑initialised
  2. Remove the blocking
    do { sw_state(); } while (...)​

    loops and handle PC3 only in the main loop, with proper de‑bouncing. A noisy edge can easily leave the system in an in‑between state.
  3.  After disabling PWM, explicitly write the final safe state to the TIM1 compare registers and to the GPIO ODR bits (e.g. all low), and then verify with a debugger that:
  • TIM1->CR1 & TIM1_CR1_CEN is 0
  • TIM1->BDTR & TIM1_BDTR_MOE is 0
  • TIM1->CCER1 has all CCxE/CCxNE bits cleared
  • TIM2->IER & TIM2_IER_UIE is 0

Maybe someone can make you a suggestion of a minimal start/stop sequence if you can share the updated code and which STM8 part and pins you use for CH1/CH1N/CH2/CH2N and the switch.

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
Peter BENSCH
ST Employee

... and while we're at it: if you paste code only after formatting it with a code formatter (e.g. with formatter.org/cpp-formatter, coding style Google, indent 2, column 80), community members can read and understand your code more easily and quickly.

Regards
/Peter

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

@Peter BENSCH wrote:

... and while we're at it: if you paste code only after formatting it with a code formatter (e.g. with formatter.org/cpp-formatter, coding style Google, indent 2, column 80), community members can read and understand your code more easily and quickly.

Regards
/Peter


Hi, Peter. It is  humbly expressed that I could not get you as I am not so familiar with this community, 

However, regarding my original problem, I undertook relentless tests for several days. Lastly, I detected the bug. During a test, where GPIOC Pin 3 was not used, but configured.  Only the function inv_on() and inv_off() with delay set after each, within a do-while loop was done to see if those functions are working well. It was observed that those functions were working well. But, unwittingly, I pressed the switch connected to GPIOC Pin 3, and saw that the problem appears. Then I moved  the polling pin to other port. Now there is no issue. No de-bounce effect. Code is working flawlessly. 

 

Thank you Peter.

Regards,

ankhola