This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

pwm dimming led rgb with trouble on third and thourth channel.

i am having trouble with pwm module 2. only two of the channels are working but not the third nor the fourth. i tried pwm module 1 but im having the same problem there. i cant tell what im missing :/

the third channel only works if i declare it on its with "NRF_PWM2->PSEL.OUT" and passing only zeros to other elements in "pwm_seq[4]" even tho i did not activate the other channels/assign them to any physical pin.

please help.

void initRgbPwm(int32_t pwmFreq)  
{                                      			
		rgbCounterTop = 0;	
		uint32_t baseFreq = 500000;
		uint8_t preSc = 5;
		while(rgbCounterTop <= 100 && baseFreq <= 16000000)
		{
			rgbCounterTop = (baseFreq / pwmFreq);
			if(rgbCounterTop <= 100 && baseFreq <= 16000000)
			{
				baseFreq = baseFreq * 2;
				preSc--;
			}	else break;
		}
		
		If(rgbCounterTop > 100)   
		{
				uint16_t pwm_seq[4] = {0, 0, 0, 0};
			
			NRF_PWM2->PSEL.OUT[0] = 0x0000001A;	// red rgb.
			NRF_PWM2->PSEL.OUT[1] = 0x00000006;	// green rgb.
			NRF_PWM2->PSEL.OUT[2] = 0x0000001B;	// blue rgb.
			
			NRF_PWM2->ENABLE = 1;   
			NRF_PWM2->MODE = 0;   
			NRF_PWM2->PRESCALER = preSc;   
			NRF_PWM2->COUNTERTOP = rgbCounterTop;    
			NRF_PWM2->LOOP = 0;   
			NRF_PWM2->DECODER = 0X00000102;    
			NRF_PWM2->SEQ[0].PTR  = ((uint32_t)(pwm_seq) << PWM_SEQ_PTR_PTR_Pos);    
			NRF_PWM2->SEQ[0].CNT  = ((sizeof(pwm_seq) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);   
			NRF_PWM2->TASKS_SEQSTART[0] = 1;    
		}
}

void rgbPwm(uint8_t dutyCycleRed, uint8_t dutyCycleGreen, uint8_t dutyCycleBlue)
{
	uint16_t dutyCycleCh1 = (dutyCycleRed * rgbCounterTop)/100;  
	uint16_t dutyCycleCh2 = (dutyCycleGreen * rgbCounterTop)/100; 
	uint16_t dutyCycleCh3 = (dutyCycleBlue * rgbCounterTop)/100; 
	
	uint16_t pwm_seq[4] = {dutyCycleCh1  | 0x8000, dutyCycleCh2  | 0x8000, dutyCycleCh3  | 0x8000, 0};

	NRF_PWM2->SEQ[0].PTR  = ((uint32_t)(pwm_seq) << PWM_SEQ_PTR_PTR_Pos);
	NRF_PWM2->SEQ[0].CNT  = ((sizeof(pwm_seq) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
	NRF_PWM2->TASKS_SEQSTART[0] = 1;
}
  • A good start will be do declare pwm_seq as static:

    static uint16_t pwm_seq[4] = {dutyCycleCh1  | 0x8000, dutyCycleCh2  | 0x8000, dutyCycleCh3  | 0x8000, 0};
    

    If you don't do this, pwm_seq will be placed in the stack and NRF_PWM2->SEQ[0].PTR will point to a place in stack. After the function ends pwm_seq will not exist anymore, or more specific the place in the stack where it was may be overwritten by another function.

    The static keyword will place the variable some place else in RAM and it will exist throughout the lifetime of the program. See here for more info, or read about static and automatic variables in C.

  • i made the rgb pwm to work on module 0 without actually the static declaration. altho ur making sense, i actually followed nrf52832 v1.2 datasheet with example code without the static. i tried putting the static declaration and got an error that says "initializer element is not a compile-time constant" and thats bcz the value of pwm_seq_rgb is not a constant (dutyCycleCh1 is a variable).

  • Sorry, I gave you code that don't work. It will not work since dutyCycleCh1, 2 and 3 is not compile time constants. You cannot set the value of a static or global variable to a non compile constant (a variable), static uint16_t pwm_seq[4] = ... will only be run once at startup, not when the function is called. This is correct code:

    static uint16_t pwm_seq[4] = {0x8000, 0x8000, 0x8000, 0}; //initialize to 0 duty cycle
    
    uint16_t dutyCycleCh1 = (dutyCycleRed * rgbCounterTop)/100;  
    uint16_t dutyCycleCh2 = (dutyCycleGreen * rgbCounterTop)/100; 
    uint16_t dutyCycleCh3 = (dutyCycleBlue * rgbCounterTop)/100;
    
    pwm_seq[0] = dutyCycleCh1  | 0x8000;
    pwm_seq[1] = dutyCycleCh2  | 0x8000;
    pwm_seq[2] = dutyCycleCh3  | 0x8000;
    
  • i kept working on it. and after a while with no progress i just moved the function down the main(void)/changed its location within the main(void) and it worked for some reason.

Related