NRF52840 nrf nrfx PWM glitching complex waveform

I need to create some complex waveforms and my strategy is to use nrfx_pwm_complex_playback to play one waveform then the other as a seamless loop; and I'll manipulate the sequence that's not currently being played and it should then switch in at the end of the current sequence.

I've set up the most simple case with two sequences. It's looping but the waveform is not good - single pulses popping up. This isn't finished code but should be complete.

What am I missing? Thanks!

static nrf_pwm_values_common_t sequence_data[ 2 ][ 100 ];

static nrf_pwm_sequence_t sequences[ 2 ];


static nrfx_pwm_config_t const config_motor =
{
.output_pins =
{
IO_PIN_MOTOR_PWM, // channel 0
NRFX_PWM_PIN_NOT_USED, // channel 1
NRFX_PWM_PIN_NOT_USED, // channel 2
NRFX_PWM_PIN_NOT_USED // channel 3
},
.irq_priority = 5,
.base_clock = NRF_PWM_CLK_8MHz, // Originally 8MHz
//.base_clock = NRF_PWM_CLK_1MHz, // Originally 8MHz
//.base_clock = NRF_PWM_CLK_125kHz,
.count_mode = NRF_PWM_MODE_UP,
//.top_value = 2500,
.top_value = 255,
.load_mode = NRF_PWM_LOAD_COMMON,
.step_mode = NRF_PWM_STEP_AUTO
};

  nrfx_pwm_init(&pwm_motor, &config_motor, NULL, NULL);

void io_spwm_motor_complex_flat( uint8_t seqIndex , uint32_t duty , uint16_t periods ) {
duty = 255 - duty;

sequence_data[ seqIndex ][ 0 ] = (duty <= 255 ) ? duty : 255 ;

sequences[ seqIndex ] = ( nrf_pwm_sequence_t )
{
.values.p_common = sequence_data[ seqIndex ],
.length = 1,
.repeats = periods,
.end_delay = 0
};
nrfx_pwm_sequence_update( &pwm_motor , seqIndex , &sequences[ seqIndex ] );
}

void io_spwm_complex_restart(uint32_t duty )
{
io_spwm_motor_complex_flat( 0 , 64 , 4 );
io_spwm_motor_complex_flat( 1 , 250 , 4 );

(void)nrfx_pwm_complex_playback(&pwm_motor, &sequences[ 0 ] , &sequences[ 1 ] , 2 , NRFX_PWM_FLAG_LOOP );

//(void)nrfx_pwm_simple_playback(&pwm_motor, &sequences[ 1 ] , 1, NRFX_PWM_FLAG_LOOP);

}

io_spwm_complex_restart( 1 );

  • Hi Nick

    I don't quite understand which pulses you are talking about by looking at the figure. 

    If I understand your code correctly the PWM switches between 64/255, which are the short pulses, and 250/255, which is the other state where it is mostly high but will drop down shortly for each PWM period. 

    To me the diagram looks OK, but maybe it is something I am missing?

    If you can share your code as a C file I can also try to reproduce the issue here. 

    Best regards
    Torbjørn

  • Thank you. My intention with this code is that each sequence is 5 periods long (1+4). From the trace picture, you see that solo pulses appear which should not be there. The code above I think it enough to replicate the problem, there is no other code manipulating this device.

    You see at nrfx_pwm_complex_playback, I have set loop to 2. If I set it to 1 this does not appear to play back the sequences properly even once; I get 5 x 64/255 pulses and one 250/255, looping. From the docs I think 1 is the correct value. It is as though the .repeats attribute is ignored and the value played only once.

  • After some more thinking. The loop mechanism uses the short circuit task to restart sequence 0; this appears to ignore the .repeats value in sequence 1. Is the task being triggered once the PWM value is loaded, i.e. before it is repeated? So maybe it's playing only the first value from sequence 1, then the task triggers to start sequence 0?

    Thinking on this, I set end_delay on sequence 1 to the number of periods required and this still did not extend sequence 1. I I think sequence 0 is being triggered as soon as the final value in sequence 1 is loaded so .repeats and .end_delay are ignored. How do I get around this?

  • From the SDK

    "The repeats and end_delay values (which are written to the SEQ[n].REFRESH and SEQ[n].ENDDELAY registers in the peripheral, respectively) are ignored at the end of a complex sequence playback, indicated by the LOOPSDONE event. See the Product Specification for more information."

    So how do I continuously loop two sequences, where the last uses .repeats? I have to create a data stream of that length? Very inefficient to fill an array with values.

  • Hi Nick

    Now I understand the issue, I didn't spot this in the diagram earlier...

    Yes, this is a limitation in the hardware unfortunately. 

    If you give me a bit more information about what the PWM pulse should be used for maybe we can come up with a different approach to implementing this. 

    For instance, how big of a repeat counter are you planning to use in the actual application, and what is the length of the buffers?

    Could it be an alternative to step through the buffer manually using the NextStep decoder mode?
    In this mode you will be in more direct control of when the PWM moves to the next value in the DMA buffer, which means you can indirectly set the number of repeats based on how often you trigger the NEXTSTEP task. 

    Best regards
    Torbjørn

Related