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

PWM event generation

I am working with the PWM driver to drive a stepper motor and I have a couple of doubts about when all the events are generated. My doubts are related to events:

  • NRF_PWM_EVENT_SEQEND0 && NRF_PWM_EVENT_SEQEND1
  • NRF_PWM_EVENT_LOOPSDONE
  • NRF_PWM_EVENT_PWMPERIODEND

As I understand it from the documentation, the event:

  • NRF_PWM_EVENT_SEQEND0 && NRF_PWM_EVENT_SEQEND1

    Generated when the correspondence SEQUENCE (0 || 1) is finished. At my understanding this is when the `top_count` has been reached the number of times specified in the `repeats` attribute of the sequence plus one. (Assume `end_delay` is 0 for simplicity).

  • NRF_PWM_EVENT_LOOPSDONE

    Generated when both sequences (0 and 1) have being finished the number specified by playback_count.

  • NRF_PWM_EVENT_PWMPERIODEND

    Generated each time top_count is reached. 

This is at least what I understand from reading the documentation about the PWM Driver events. Is this correct?

I asked, because I have been setting up a test to count and that is not what I have observe. I have setup a timer in counter mode to count the number of the different pwm events generated, and I obtained weird values. The pwm sequence was defined as:

static uint16_t seq_values[] = {PWM_TOP_COUNT / 2};       // 50% Duty cycle
nrf_pwm_sequence_t const seq =
{
    .values.p_common = seq_values,
    .length          = NRF_PWM_VALUES_LENGTH(seq_values),
    .repeats         = 0,
    .end_delay       = 0
};


and the PWM started as: 

(void) nrfx_pwm_simple_playback(
    &m_pwm0, 
    &seq, 
    1,
    NRFX_PWM_FLAG_LOOP | NRFX_PWM_FLAG_SIGNAL_END_SEQ0 | NRFX_PWM_FLAG_SIGNAL_END_SEQ1    
);

with the pwm instance configured in mode NRF_PWM_MODE_UP and in NRF_PWM_LOAD_COMMON. 

The results obtained were weird because the amount of events registered of type NRF_PWM_EVENT_SEQEND0 and NRF_PWM_EVENT_SEQEND1 are the double than the events of type NRF_PWM_EVENT_PWMPERIODEND. The number of events of NRF_PWM_EVENT_LOOPSDONE are the same than NRF_PWM_EVENT_PWMPERIODEND which also confuse me, because I wouldn't expect those to be the same according to my assumption on when the event should be generated. The number of events registered by the timer are in order of:

  • 4000 for NRF_PWM_EVENT_PWMPERIODEND and NRF_PWM_EVENT_LOOPSDONE.
  • 8000 forNRF_PWM_EVENT_SEQEND0 and NRF_PWM_EVENT_SEQEND1.

All the test are made under the same conditions, and the number of pwm pulses generated are the same since the motor moves the gear about the same.  So I am a bit confused for when the events are supposed to be generated. By the way I am using SDK 15.

Regards.

Parents
  • Hi 

    Have you checked figure 6 in the PWM peripheral documentation?

    Essentially the SEQEND events are generated when the last byte is read from the corresponding sequence registers, which happens before the playback is completed. 

    This allows you to safely rewrite the data stored in the sequence buffer, knowing that the PWM peripheral is done reading from it. 

    • NRF_PWM_EVENT_LOOPSDONE

      Generated when both sequences (0 and 1) have being finished the number specified by playback_count.

    • NRF_PWM_EVENT_PWMPERIODEND

      Generated each time top_count is reached. 

    Yes, that sounds correct. 

    Regarding the number of events you see I think I will need to reproduce this myself. I will do some tests tomorrow when I have access to the necessary tools. 

    Best regards
    Torbjørn

  • Yes, I have seen that figure. It's the one I used to assume when the events was supposed to be generated. Thanks for confirming that my assumptions were correct, I was a bit worry to have misunderstood the figure.

    I know the SEQEND events are generated at reading of the last byte, that makes sense. It seemed to me that such detail would not affect to the question, since that should not affect the amount of events generated. 

    Thanks for taking a look to it.

    regards,
    spw

  • Hi 

    I tried running the complex playback function, and the results seem to be as expected:

    nrf_drv_pwm_complex_playback(&m_pwm0, &seq0, &seq1, 4, 0);

    Since I run the loop four times I see the SEQEND0 and SEQEND1 events happening 4 times one after the other, followed by the LOOPSDONE event happening once at the very end. 

    The PWMPERIODEND event happens at a much higher rate, as it follow the PWM frequency. 

    If I run the nrfx_pwm_simple_playback(..) function, more similar to your example, I see that the SEQEND1 and LOOPSDONE events occur repeatedly at the same rate, while the PERIODEND event occurs X times as often, where X is the length of the sequence. 

    So I am a bit unsure how you got the results you listed earlier. In particular it seems odd that the PERIODEND event would happen less frequent than the SEQEND0 and SEQEND1 events. This shouldn't really be possible...

    Best regards
    Torbjørn

  • I am curious about:
    - What is the frequency you used to the PWM?
    I used a 1 MHZ frequency with a top_count of 500. 


    - How did you count the number of events? 
    I used a timer counter with a PPI trigger interaction. Did you use the same or other approach?

    I will review the code on my end, maybe there is something I missed or I can provide further info about it.

    Regards,

    Enrique.

Reply
  • I am curious about:
    - What is the frequency you used to the PWM?
    I used a 1 MHZ frequency with a top_count of 500. 


    - How did you count the number of events? 
    I used a timer counter with a PPI trigger interaction. Did you use the same or other approach?

    I will review the code on my end, maybe there is something I missed or I can provide further info about it.

    Regards,

    Enrique.

Children
  • Hi Enrique

    I use the GPIOTE and PPI peripherals to connect the PWM events to pins, allowing me to track them on an oscilloscope. 

    If you want to do the same you can use the following code to set it up:

        NRF_GPIOTE->CONFIG[0] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                                GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                                (32 + 10) << GPIOTE_CONFIG_PSEL_Pos;
        NRF_GPIOTE->CONFIG[1] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                                GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                                (32 + 11) << GPIOTE_CONFIG_PSEL_Pos;
        NRF_GPIOTE->CONFIG[2] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                                GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                                (32 + 12) << GPIOTE_CONFIG_PSEL_Pos;
        NRF_GPIOTE->CONFIG[3] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                                GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                                (32 + 13) << GPIOTE_CONFIG_PSEL_Pos;
    
        NRF_PPI->CH[0].EEP = (uint32_t)&NRF_PWM0->EVENTS_PWMPERIODEND;
        NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
        NRF_PPI->CH[1].EEP = (uint32_t)&NRF_PWM0->EVENTS_LOOPSDONE;
        NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[1];
        NRF_PPI->CH[2].EEP = (uint32_t)&NRF_PWM0->EVENTS_SEQEND[0];
        NRF_PPI->CH[2].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[2];
        NRF_PPI->CH[3].EEP = (uint32_t)&NRF_PWM0->EVENTS_SEQEND[1];
        NRF_PPI->CH[3].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[3];
        NRF_PPI->CHENSET = 0xF;

    The GPIO's used in this case is P1.10-P1.13, mapped to PWMPERIODEND, LOOPSDONE, SEQEND[0] and SEQEND[1] respectively. 

    Best regards
    Torbjørn

Related