cancel
Showing results for 
Search instead for 
Did you mean: 

Generate PWM with two duty cycles simultaneously

$AK
Associate III

Hello All,

I'm working on PWM on SPC560B54 - Dis by importing and using example source code "SPC560Bxx_RLA PWM-ICU Test Application for Discovery"

I can generate PWM signal with 800kHz and 400kHz frequency but could not change the Pulse width of every pulse I'm generating.

In order to control ws2812 addressable LED, PWM needs to be generated with 60% and 30% duty cycle simultaneously. I tried to generate PWM with two width simultaneously but sometimes one pulse is missed or generated extra. From datasheet ws2812 needs data in 800kHz and 400kHz with 24bits of "1"code(60%) and "0"code(30%) for one led.

  

/*************************************************************************************************/
#define LED_CNT 1
#define RED 1
#define GREEN 0
#define BLUE 2
 
uint8_t led_buffer[LED_CNT][3],i;
 
 
void glow_led(void)
{
	uint16_t led_no;
	uint8_t led_color,one=1;
	uint8_t bit;
	for(led_no = 0; led_no<LED_CNT; led_no++)
	{
		for(led_color=0; led_color<3; led_color++)
		{
			for(bit = 8; bit>0;bit--)
			{
				if((led_buffer[led_no][led_color]&(one<<(bit-1)))!=0)  /*1 Code*/
				{
					pwm_lld_enable_channel(&PWMD5, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD5, 6000), 0);
				}
				else				   								 /*0 Code*/
				{
					pwm_lld_enable_channel(&PWMD5, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD5, 3000), 0);
				}
			}
		}
	}
	 pwm_lld_enable_channel(&PWMD5, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD5, 0), 0); /*Reset code*/
	 microsec_delay(50);
	pwm_lld_disable_channel(&PWMD5, 0);
}
 
void led(uint8_t led_num, uint8_t R, uint8_t G, uint8_t B)
{
	led_buffer[led_num][RED] = R;
	led_buffer[led_num][GREEN] = G;
	led_buffer[led_num][BLUE] = B;
	glow_led();
}
 
 
int main(void) 
{
	/* Initialization of all the imported components in the order specified in
	 the application wizard. The function is generated automatically.*/
	componentsInit();
 
	/* Enable Interrupts */
	irqIsrEnable();
 
	/*
	* Initializes the PWM driver 1.
	*/
	pwm_lld_start(&PWMD5, &pwm_config_emios1);
 
	while(1)
		{
		for(i=0;i<LED_CNT;i++)
			{
				led(i,0,255,255);
				osalThreadDelayMilliseconds(1000);
			}
			for(i=0;i<LED_CNT;i++)
			{
				led(i,0,0,0);
				osalThreadDelayMilliseconds(1000);
			}
		}
}
 
/*************************************************************************************************/

system clock - 64MHz, Peripheral Clock - 32MHz, PWM Frequency - 400kHz/800kHz.

Please guide me with above issue or Is there any other possible way to generate different pulses or to control ws2812.

Regards,

AK

1 ACCEPTED SOLUTION

Accepted Solutions

Hello @Erwan YVIN​,

Thanks for your suggestion, but the MCU I'm using doesn't support DMA.

I just solved the above stated issue by using SPI interface by converting a single bit to a byte of data in SPI in 6.4MHz clock.

I 'am running SPI data with 6.4MHz speed, where the time for sending 8bits of data is 1.25us.

To send data for WS2812/13 Addressable LED data should be passed in 400/800kbps (2.5us/1.25us).

0693W000008y4t8QAA.jpg 

Regards,

AK

View solution in original post

12 REPLIES 12

Likely to need to modulate via DMA out of a pattern buffer.

If you are losing cycles it could be because you're saturating the processor or changing the duty midcycle.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
zambrano.luigi
Senior III

HI,

as shown in the example SPC560Bxx_RLA PWM-ICU Test Application for Discovery integrated in SPC5Studio, in order to appreciate the change of the duty cycle, it is necessary to add a wait cycle (osalThreadDelayMilliseconds) before change again the duty cycle.

  /*
   * Starts the PWM channel 0 using 75% duty cycle and 0% dead time.
   */
  pwm_lld_enable_channel(&PWMD5, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD5, 7500), 0);
  osalThreadDelayMilliseconds(2000);
 
  /*
   * Changes the PWM channel 0 to 50% duty cycle.
   */
  pwm_lld_enable_channel(&PWMD5, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD5, 5000), 0);
  osalThreadDelayMilliseconds(2000);
 
  /*
   * Changes the PWM channel 0 to 25% duty cycle.
   */
  pwm_lld_enable_channel(&PWMD5, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD5, 2500), 0);
  osalThreadDelayMilliseconds(2000);

In this way the duty cycle modification will be active for the duration of the wait cycle.

Regards,

Luigi

Hi @Community member​ ,

Thanks for your response,

There is no DMA in the MCU I'm using. so that i tried the above method.

Is there any other way to change the duty cycle simultaneously in 400kHz frequency to remove below issue.

"If you are losing cycles it could be because you're saturating the processor or changing the duty midcycle.​"

Regards,

AK

$AK
Associate III

Hi @zambrano.luigi​ ,

I couldn't give delay between the duty cycle modification, as I'm running PWM in 400kHz frequency, with 2.5us period.

Could you suggest any other possibilities with microsecond modification in dutycycle.

Regards,

AK

The SPC5 isn't my platform, but generally 800 KHz is considered quite high bandwidth for interrupts, if you have to modify the duty of each cycle you're going to want to optimize that path. ie prepare data in a loop (pattern) buffer which you present rapidly under interrupt. In other ST MCU architectures the TIM CCR register controls the duty and has a shadow register so the hardware latches the new content at the update (zero) roll-over.

It could be the part is suboptimal for this, ie might do it, but burns all available resources to the point the MCU can do no other actual work.

Perhaps it makes sense to have a small slave MCU (say STM32L0) which does have TIM and DMA resources to drive strings of LEDs, animate, sequence, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
$AK
Associate III

I tried with storing the data of 24 bit in buffer as suggested, but the generated pulse is sometimes 23 or 24 or 25. One of the bit is missed or generated again, before next condition check.

I captured 3 images with 24bits and 23 bits, but 25 bits of data also received.

Regards,

AK

0693W000008wbA6QAI.bmp0693W000008wbA1QAI.bmp0693W000008wb9wQAA.bmp

$AK
Associate III

d

Hi @zambrano.luigi (ST Employee)​ ,

I couldn't give delay between the duty cycle modification, as I'm running PWM in 400kHz frequency, with 2.5us period.

Could you suggest any other possibilities with microsecond modification in dutycycle.

Regards,

AK

Erwan YVIN
ST Employee

Hello AK ,

Interesting project ,

in some projects STM32 + WS2812B ,

http://stm32f4-discovery.net/2018/06/tutorial-control-ws2812b-leds-stm32/

it is nice article. (DMA with PWM could fit with your requirement)

Best regards

Erwan