Max PWM frequency with 50% duty cycle on nrf52840

Hi,

What is the maximum PWM frequency one can achieve on the nrf52840 with 50% duty cycle? Sample .dts and c-code in NRF Connect SDK would be appreciated!

In practice I just want to achieve the highest possible frequency on a GPIO as possible. Is there another way to achieve a higher frequency than the PWM frequency? For example routing the internal clock to a GPIO?

I appreciate your help.

Parents Reply Children
  • Hi,

    You can find code for using the PWM peripheral with nrfx here,

    regards
    Jared 

  • Is it possible to obtain this with the zephyr API?

    It works for 4 MHz, but not 5,333

    #define PWM_PERIOD_4MHZ PWM_KHZ(4000)
    ret = pwm_set_dt(&pwm_led0, PWM_PERIOD_4MHZ, PWM_PERIOD_4MHZ / 2U);
    I have tried this which doesn't work:
    #define PWM_PERIOD_5333KHZ PWM_KHZ(16000/3);
    ret = 
    pwm_set_dt(&pwm_led0, PWM_PERIOD_5333KHZ, PWM_PERIOD_5333KHZ / 2U);
    But it does not work
  • Hi,

    Which exact frequency are you trying to set the PWM signal to with the Zephyr API? 

    5 MHz?

  • Using the Zephyr API I struggle to get anything stable over 1MHz, but using the PWM peripheral directly I'm able to get about 5.33 MHz with 50% duty cycle easily:

    Code used:

    #define PWM_PIN (13UL)
    
    
    int16_t buf[] = {(1 << 15) | 1}; // Inverse polarity (bit 15), 
    
    int main(void)
    {
      // Start accurate HFCLK (XOSC)
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) ;
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
      
      // Configure PWM_PIN as output, and set it to 0
      NRF_GPIO->DIRSET = (1 << PWM_PIN);
      NRF_GPIO->OUTCLR = (1 << PWM_PIN);
      
      
      NRF_PWM0->PRESCALER   = PWM_PRESCALER_PRESCALER_DIV_1; // 1 us
      NRF_PWM0->PSEL.OUT[0] = PWM_PIN;
      NRF_PWM0->MODE        = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos);
      NRF_PWM0->DECODER     = (PWM_DECODER_LOAD_Common       << PWM_DECODER_LOAD_Pos) | 
                              (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos);
      NRF_PWM0->LOOP        = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos);
      
      NRF_PWM0->COUNTERTOP = 3; // 
      
      
      NRF_PWM0->SEQ[0].CNT = ((sizeof(buf) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos);
      NRF_PWM0->SEQ[0].ENDDELAY = 0;
      NRF_PWM0->SEQ[0].PTR = (uint32_t)&buf[0];
      NRF_PWM0->SEQ[0].REFRESH = 0;
      NRF_PWM0->SHORTS = 0;
      
      NRF_PWM0->ENABLE = 1;
      NRF_PWM0->TASKS_SEQSTART[0] = 1;
      
      while (1) 
      {
      }
    }

    regards

    Jared

Related