The finer points of PWM on nRF52 using two chained buffers

I'm looking into a rare issue on the BBC micro:bit V2 which uses the nRF52833 as its (application) microcontroller. I used to be familiar with some CPUs from the 80s but my low-level microcontroller knowledge is very minimal.

There's a two buffer PWM example in https://docs.nordicsemi.com/bundle/ps_nrf52833/page/pwm.html shown in Figure 6. Example using two sequences and described below it.

My first question is what are the options for stopping this once started? Can it be stopped after the current buffer (which could be either SEQ[0] or SEQ[1]) is complete? Can it be stopped after the current sample has been processed? How should it be stopped, is the assignment PWM.TASKS_STOP = 1 enough to stop it and when exactly does this stop it? The code I'm looking at waits for PWM.EVENTS_STOPPED to be non zero to indicate the stop has taken effect.

I see this in the docs.

In this case, an automated playback takes place, consisting of SEQ[0], delay 0, SEQ[1], delay 1, then again SEQ[0], etc. The user can choose to start a complex playback with SEQ[0] or SEQ[1] through sending the SEQSTART[0] or SEQSTART[1] task. The complex playback always ends with delay 1.

Does the sentence I have underlined imply it can only be stopped / will only stop once SEQ[1] is fully processed/complete?


In the nRF52833 errata I'm seeing [183] PWM: False SEQEND[0] and SEQEND[1] events. Under Conditions this says:

Any of the LOOPSDONE_SEQSTARTn shortcuts are enabled. LOOP register is non-zero and sequence 1 is one value long.

Is that saying this definitely only occurs for SEQ[1].CNT = 1? I am far from certain but I think this could explain some issues I'm seeing if it could occur for sequences of length 128 or 8.


Does anyone have any recommendations on detailed tutorials for writing interrupt hanlders in C/C++ for ARMv7 / Cortex M4 / nRF52 / nRF52833? In particular ones that cover what you can do and what you musn't for variables read/written to inside interrupt handler and shared with the rest of the code, i.e. atomicity issues.

Parents
  • Hello,

    The PWM can be stopped at any time, also in the middle of a sequence. From the same PWM chapter you linked to:

    The code I'm looking at waits for PWM.EVENTS_STOPPED to be non zero to indicate the stop has taken effect.

    Are you able to confirm if the program always exits this loop? What is the symptom of the problem you are seeing?

    Is that saying this definitely only occurs for SEQ[1].CNT = 1? I am far from certain but I think this could explain some issues I'm seeing if it could occur for sequences of length 128 or 8.

    Yes, that is correct, SEQ[1].CNT must be equal to 1 for the conditions of this errata to be met so it does not appear to be relevant to your case.

    Best regards,

    Vidar

  • I've been working my way through a few things. A brief bit of testing of PWM.ENABLE = 0 after the stop code seems to do the job but the answer to this mystery may be in the SDK library code. I see the implementation of nrfx_pwm_stop() includes a very relevant comment and additional hw register setting.

        // Deactivate shortcuts before triggering the STOP task, otherwise the PWM
        // could be immediately started again if the LOOPSDONE event occurred in
        // the same peripheral clock cycle as the STOP task was triggered.
        nrfy_pwm_shorts_set(p_instance->p_reg, 0);

    I had already tried setting SHORTS to 0 but I was doing it after the STOP setting. That improved things but wasn't perfect. I'll re-order them and do some more testing.

    The library code also does an ENABLE = 0 if waiting for completition is requested.

Reply
  • I've been working my way through a few things. A brief bit of testing of PWM.ENABLE = 0 after the stop code seems to do the job but the answer to this mystery may be in the SDK library code. I see the implementation of nrfx_pwm_stop() includes a very relevant comment and additional hw register setting.

        // Deactivate shortcuts before triggering the STOP task, otherwise the PWM
        // could be immediately started again if the LOOPSDONE event occurred in
        // the same peripheral clock cycle as the STOP task was triggered.
        nrfy_pwm_shorts_set(p_instance->p_reg, 0);

    I had already tried setting SHORTS to 0 but I was doing it after the STOP setting. That improved things but wasn't perfect. I'll re-order them and do some more testing.

    The library code also does an ENABLE = 0 if waiting for completition is requested.

Children
Related