Skip to main content
$AK
Associate III
March 10, 2021
Solved

Generate PWM with two duty cycles simultaneously

  • March 10, 2021
  • 5 replies
  • 4609 views

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

    This topic has been closed for replies.
    Best answer by $AK

    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

    5 replies

    Tesla DeLorean
    Guru
    March 10, 2021

    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 VenmoUp vote any posts that you find helpful, it shows what's working..
    $AK
    $AKAuthor
    Associate III
    March 10, 2021

    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

    Tesla DeLorean
    Guru
    March 10, 2021

    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 VenmoUp vote any posts that you find helpful, it shows what's working..
    zambrano.luigi
    ST Employee
    March 10, 2021

    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

    $AK
    $AKAuthor
    Associate III
    March 11, 2021

    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

    $AK
    $AKAuthor
    Associate III
    March 10, 2021

    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

    Erwan YVIN
    ST Employee
    March 26, 2021

    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

    $AK
    $AKAuthorBest answer
    Associate III
    March 27, 2021

    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

    Erwan YVIN
    ST Employee
    April 1, 2021

    good news ,

    i spoke about SPC560B54 - Dis 

    Nice to see that WS2812/13 Addressable LED data is working with SPC560B54

    Good work

    Erwan

    $AK
    $AKAuthor
    Associate III
    April 1, 2021

    Thanks,

    SPC560B54 MCU had DMA, but the actual MCU was SPC560B50 which doesnt support DMA feature.

    Regards,

    AK