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

4x Independent PWM - Code Check Required

Hi,

I had this working, I'm sure of it. Now though I get 100% duty on one channel and 0% on another. Something's not right.

  volatile uint16_t nrf_pwm_duty[4] = {CFG_PWM_INVERT};
  
  NRF_PWM0->COUNTERTOP  = CFG_PWM_COUNT; // 200 = 16MHz/200 = 80KHz, 10mA per step 
  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) &nrf_pwm_duty << PWM_SEQ_PTR_PTR_Pos;
  NRF_PWM0->SEQ[0].CNT  = (sizeof(nrf_pwm_duty) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos;
  NRF_PWM0->SHORTS      = PWM_SHORTS_LOOPSDONE_SEQSTART0_Enabled << PWM_SHORTS_LOOPSDONE_SEQSTART0_Pos;
  NRF_PWM0->PSEL.OUT[CFG_PWM_OUTPUT_USB_NUM] = (CFG_PIN_PWM_USB_NUM << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
  NRF_PWM0->PSEL.OUT[CFG_PWM_OUTPUT_FRONT_NUM] = (CFG_PIN_PWM_FRONT_NUM << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
  NRF_PWM0->PSEL.OUT[CFG_PWM_OUTPUT_REAR_NUM] = (CFG_PIN_PWM_REAR_NUM << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
  NRF_PWM0->PSEL.OUT[CFG_PWM_MPPT_NUM] = (CFG_PIN_PWM_MPPT_NUM << 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->TASKS_SEQSTART[0] = 1;


Pins are correct, my focus is CFG_PWM_OUTPUT_FRONT_NUM which is number/channel 1 in the duty array.

I set the value with a duty of 5,  nrf_pwm_duty[outputChannel] = CFG_PWM_INVERT | value;  // (0x8005)

The pin is at 100%. If I disable PWM it's at floating voltage (correct).

Parents
  • I've been battling this for a few hours and still can't crack it.

    I've tested the pins by using GPIO and driving them high. Currently when PWM is enabled they all sit at 0v.

    The values in nrf_pwm_duty are correct (I set them at 0x8032 elsewhere, so 50/200 duty).

      volatile uint16_t nrf_pwm_duty[4] = {CFG_PWM_INVERT, CFG_PWM_INVERT, CFG_PWM_INVERT, CFG_PWM_INVERT};
    
      // pwm
      NRF_GPIO->PIN_CNF[CFG_PIN_PWM_USB_NUM] = pinDisconnectInputBuffer | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos);
      NRF_GPIO->PIN_CNF[CFG_PIN_PWM_FRONT_NUM] = pinDisconnectInputBuffer | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos);
      NRF_GPIO->PIN_CNF[CFG_PIN_PWM_REAR_NUM] = pinDisconnectInputBuffer | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos);
      NRF_GPIO->PIN_CNF[CFG_PIN_PWM_MPPT_NUM] = pinDisconnectInputBuffer | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos);
      //NRF_GPIO->OUTSET = 1 << CFG_PIN_PWM_FRONT_NUM;
    
      NRF_PWM0->COUNTERTOP  = CFG_PWM_COUNT << PWM_COUNTERTOP_COUNTERTOP_Pos; // 200 = 16MHz/200 = 80KHz, 10mA per step 
      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) nrf_pwm_duty) << PWM_SEQ_PTR_PTR_Pos;
      NRF_PWM0->SEQ[0].CNT  = (sizeof(nrf_pwm_duty) / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos;
      NRF_PWM0->SHORTS      = PWM_SHORTS_LOOPSDONE_SEQSTART0_Enabled << PWM_SHORTS_LOOPSDONE_SEQSTART0_Pos;
      NRF_PWM0->PSEL.OUT[CFG_PWM_OUTPUT_USB_NUM] = (CFG_PIN_PWM_USB_NUM << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
      NRF_PWM0->PSEL.OUT[CFG_PWM_OUTPUT_FRONT_NUM] = (CFG_PIN_PWM_FRONT_NUM << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
      NRF_PWM0->PSEL.OUT[CFG_PWM_OUTPUT_REAR_NUM] = (CFG_PIN_PWM_REAR_NUM << PWM_PSEL_OUT_PIN_Pos) | (PWM_PSEL_OUT_CONNECT_Connected << PWM_PSEL_OUT_CONNECT_Pos);
      NRF_PWM0->PSEL.OUT[CFG_PWM_MPPT_NUM] = (CFG_PIN_PWM_MPPT_NUM << 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->TASKS_SEQSTART[0] = 1;


    I'm unsure if the SHORTS for Looping is required but tried with and without.

    To my eyes this code is identical to the examples givin in the documentation.

    If I GPIO high one of the pins and enable the PWM the pin goes low, so it is enabled.

  • Hi,

    your code works at 52832 (I believe pwm module is identical in 52810). Though you didn't show some defines, if they're correct, it looks like a hardware issue.

  • Damn, I've just swapped the 810 and it's behaving the same as the original.

    Here are the defines, nothing special and pins are 100% correct (tested via GPIO function).

    enum CFG_PWM_NUM {
      CFG_PWM_OUTPUT_USB_NUM,
      CFG_PWM_OUTPUT_FRONT_NUM,
      CFG_PWM_OUTPUT_REAR_NUM,
      CFG_PWM_MPPT_NUM
    };

    #define CFG_PWM_RESOLUTION 8
    #define CFG_PWM_INVERT (1 << 15)
    #define CFG_PWM_COUNT 200 //((1 << CFG_PWM_RESOLUTION)-1)

    #define CFG_PIN_PWM_USB_NUM 27
    #define CFG_PIN_PWM_FRONT_NUM 26
    #define CFG_PIN_PWM_REAR_NUM 25
    #define CFG_PIN_PWM_MPPT_NUM 18

Reply
  • Damn, I've just swapped the 810 and it's behaving the same as the original.

    Here are the defines, nothing special and pins are 100% correct (tested via GPIO function).

    enum CFG_PWM_NUM {
      CFG_PWM_OUTPUT_USB_NUM,
      CFG_PWM_OUTPUT_FRONT_NUM,
      CFG_PWM_OUTPUT_REAR_NUM,
      CFG_PWM_MPPT_NUM
    };

    #define CFG_PWM_RESOLUTION 8
    #define CFG_PWM_INVERT (1 << 15)
    #define CFG_PWM_COUNT 200 //((1 << CFG_PWM_RESOLUTION)-1)

    #define CFG_PIN_PWM_USB_NUM 27
    #define CFG_PIN_PWM_FRONT_NUM 26
    #define CFG_PIN_PWM_REAR_NUM 25
    #define CFG_PIN_PWM_MPPT_NUM 18

Children
Related