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.

Reply
  • 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.

Children
Related