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
  • Spoke too soon, with Loop = 1 it still doesn't work.

     // 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->LOOP = 1;

  • Ahh, a bit more magic needed... you have to configure both sequences:

      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] =  (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] =  (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] =  (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] =  (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->SEQ[1].PTR  = ((uint32_t) nrf_pwm_duty) << PWM_SEQ_PTR_PTR_Pos;
      NRF_PWM0->SEQ[1].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->LOOP = 1;
     
      NRF_PWM0->ENABLE = PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos;
      NRF_PWM0->TASKS_SEQSTART[0] = 1;	
    	while (1) {
    		for (volatile int i=0; i<1000000; i++) ;
    		nrf_pwm_duty[0] = CFG_PWM_INVERT+198;	
    		for (volatile int i=0; i<1000000; i++) ;
    		nrf_pwm_duty[0] = CFG_PWM_INVERT+2;		
    	}
    

  • You're right, that's got it. Awesome help! I hope they get this into the documentation!

    PS) CFG_PWM_INVERT+2 should be CFG_PWM_INVERT | 2

Reply Children
No Data
Related