As per #nrf52840 datasheet
NRF_P0->DIR |= 0x0001E000; NRF_P0->OUT |= 0x0001E000; uint16_t pwm_seq[4]= {160 , 3200}; NRF_PWM0->PSEL.OUT[0] = 0; NRF_PWM0->PSEL.OUT[0] = 13 ;
NRF_P0->DIR |= 0x0001E000;
NRF_P0->OUT |= 0x0001E000;
uint16_t pwm_seq[4]= {160 , 3200};
NRF_PWM0->PSEL.OUT[0] = 0;
NRF_PWM0->PSEL.OUT[0] = 13 ;
NRF_PWM0->PSEL.OUT[1] = 0 ; NRF_PWM0->PSEL.OUT[1] = 14 ;
NRF_PWM0->ENABLE = 0x00000001; NRF_PWM0->MODE = 0x00000000; NRF_PWM0->PRESCALER = 0x00000000; //16Mhz NRF_PWM0->COUNTERTOP = 16000; // PWM_Freq = 1000 Hz //NRF_PWM0->LOOP = 0x00000000; //NRF_PWM0->DECODER = 0x00000002; NRF_PWM0->SEQ[0].PTR = (uint32_t)(pwm_seq); NRF_PWM0->SEQ[0].CNT = 2; NRF_PWM0->SEQ[0].REFRESH = 0; NRF_PWM0->SEQ[0].ENDDELAY = 0; NRF_PWM0->TASKS_SEQSTART[0] = 1;
NRF_PWM0->ENABLE = 0x00000001;
NRF_PWM0->MODE = 0x00000000;
NRF_PWM0->PRESCALER = 0x00000000; //16Mhz
NRF_PWM0->COUNTERTOP = 16000; // PWM_Freq = 1000 Hz
//NRF_PWM0->LOOP = 0x00000000;
//NRF_PWM0->DECODER = 0x00000002;
NRF_PWM0->SEQ[0].PTR = (uint32_t)(pwm_seq);
NRF_PWM0->SEQ[0].CNT = 2;
NRF_PWM0->SEQ[0].REFRESH = 0;
NRF_PWM0->SEQ[0].ENDDELAY = 0;
NRF_PWM0->TASKS_SEQSTART[0] = 1;
I've configured PWM0 registers as mentioned above. But with this setting both LED1 & LED2 are showing same intensity that means both channels set to common pulse width.
How to edit this configuration so that both channels will set to different pulse width ?
If I set NRF_PWM0->DECODER = 0x00000002; I didn't observe anything on two channels.
How to update pulse width dynamically after these initial configuration ?
Thank You !!
Hello,
I am not quite sure where you found this piece of code, but it can be a bit confusing, since all of our PWM examples are set up in different ways, using different modules.
The "best" way is to use the timer and PPI, do manage the PWM signals directly. However, it does not use the PWM module. Only a timer and GPIO control.
In the Product Specification, on page 559 is an example on one way to use the PWM module, which looks similar to the way that you set it up.
Below, I modified this to match your pins.
int main(void) { uint16_t pwm_seq[4] = { 1600, 3200}; NRF_PWM0->PSEL.OUT[0] = (13 << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos); NRF_PWM0->PSEL.OUT[1] = (14 << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos); NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos); NRF_PWM0->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos); NRF_PWM0->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); NRF_PWM0->COUNTERTOP = (16000 << PWM_COUNTERTOP_COUNTERTOP_Pos); //1 msec NRF_PWM0->LOOP = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos); NRF_PWM0->DECODER = (PWM_DECODER_LOAD_Individual << PWM_DECODER_LOAD_Pos) | (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos); NRF_PWM0->SEQ[0].PTR = ((uint32_t)(pwm_seq) << PWM_SEQ_PTR_PTR_Pos); NRF_PWM0->SEQ[0].CNT = ((sizeof(pwm_seq) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos); NRF_PWM0->SEQ[0].REFRESH = 0; NRF_PWM0->SEQ[0].ENDDELAY = 0; NRF_PWM0->TASKS_SEQSTART[0] = 1; while (true) { // Do nothing. nrf_delay_ms(1000); // Wait for one second if (pwm_seq[0] == 3200) // Toggle between two duty cycles on channel 0 pwm_seq[0] = 1600; else pwm_seq[0] = 3200; NRF_PWM0->TASKS_SEQSTART[0] = 1; // Update the PWM module } }
Note that the nrf_delay_ms() is a very little power efficient function. I used it because it is easy to set up to show how to update the PWM' duty cycle.
If you paste this code into e.g. the example found in SDK\examples\peripheral\template_project, you will see that LED1 and LED2 is controlled by the PWM, and the intensity of LED1 is toggling between two values.
Best Regards,
Edvin
I referred #nrf52840 Datasheet. It is same as your suggestion but with my style. And it is very simple compare to using combo of PPI & Timer.
And it works & that's it !!