This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

PWM clock on nRF52 does not lock on oscilloscope

I have a very simple program that generates a 50% duty cycle clock using the NRF_PWM0 on the new nRF52 device. Unfortunately, my Tektronix 1GHz oscilloscope doesn't lock to the signal. If I used a Timer and GPIOTE with PPI then the clock was perfect.

I am wondering if the PWM_CLK input to the PWM hardware resource is not correct. The reference manual just uses the PWM_CLK in description but doesn't describe what it is or how do I configure or start/lock it. Any ideas?

Note that I am not using any SoftDevice and this is on a custom board with just the nRF52 part and nothing else.

int main (void)
{
    // Start 16 MHz crystal oscillator .
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_HFCLKSTART    = 1;

    // Wait for the external oscillator to start up.
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
    }

    NRF_PWM0->ENABLE = (PWM_ENABLE_ENABLE_Enabled << PWM_ENABLE_ENABLE_Pos);
    NRF_PWM0->PRESCALER = NRF_PWM_CLK_1MHz;
    NRF_PWM0->MODE = NRF_PWM_MODE_UP;
    NRF_PWM0->COUNTERTOP = 20;
    NRF_PWM0->PSEL.OUT[0] = 6;
    NRF_PWM0->PSEL.OUT[1] = NRF_PWM_PIN_NOT_CONNECTED;
    NRF_PWM0->PSEL.OUT[2] = NRF_PWM_PIN_NOT_CONNECTED;
    NRF_PWM0->PSEL.OUT[3] = NRF_PWM_PIN_NOT_CONNECTED;
    NRF_PWM0->DECODER = ((uint32_t)NRF_PWM_LOAD_INDIVIDUAL << PWM_DECODER_LOAD_Pos) |
                        ((uint32_t)NRF_PWM_STEP_AUTO << PWM_DECODER_MODE_Pos);
    NRF_PWM0->SHORTS = 0;
    NRF_PWM0->INTEN = 0;
    static nrf_pwm_values_individual_t duty = 
    {
        .channel_0 = 10,
        .channel_1 = 10,
        .channel_2 = 10,
        .channel_3 = 10,
    };

    NRF_PWM0->SEQ[0].PTR = (uint32_t)&duty;
    NRF_PWM0->SEQ[0].CNT = NRF_PWM_VALUES_LENGTH(duty);
    NRF_PWM0->SEQ[0].REFRESH = 0;
    NRF_PWM0->SEQ[0].ENDDELAY = 0;
    NRF_PWM0->TASKS_SEQSTART[0] = 1;

    while (1) {
    }
}

Thanks a lot!

Parents
  • Hi,

    Please refer to this answer.

    You can try the following code:

    int main (void)
    {
        // Start 16 MHz crystal oscillator .
        NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
        NRF_CLOCK->TASKS_HFCLKSTART    = 1;
    
        // Wait for the external oscillator to start up.
        while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
        }
    
        uint16_t pwm_seq[4] = {10000, 11000 | 0x8000, 0, 0};
        NRF_PWM0->PSEL.OUT[0] = (2 << 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 (1) {
        }
    }
    

    Make sure that you are not using any pins that conflict with peripherals, for example on the DK you can use pin 0 and 1 as they are used by the HF crystal.

    Best regards,

    Øyvind

  • Thanks Øyvind. I tried exactly your code but the waveform still keeps scrolling. The oscilloscope just doesn't lock. It appears that the frequency period isn't correct or maybe there is a phase shift of some sort?

    If I do stop the trigger or do a single capture then I do see the waveform period as 1 ms. The low-period is about 600 us and On duration is 400 us. This would be based upon the 10,000 value in pwm_seq[0].

    I am using Pin 5 and a few more unconnected pins but they all have scrolling clock. Note that I am using a single channel and not concerned about inverting the signal with Bit 16 (MSB) yet.

Reply
  • Thanks Øyvind. I tried exactly your code but the waveform still keeps scrolling. The oscilloscope just doesn't lock. It appears that the frequency period isn't correct or maybe there is a phase shift of some sort?

    If I do stop the trigger or do a single capture then I do see the waveform period as 1 ms. The low-period is about 600 us and On duration is 400 us. This would be based upon the 10,000 value in pwm_seq[0].

    I am using Pin 5 and a few more unconnected pins but they all have scrolling clock. Note that I am using a single channel and not concerned about inverting the signal with Bit 16 (MSB) yet.

Children
No Data
Related