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

How to use PWM Waveform mode? Having issue with last sequence completing.

Despite all the questions on this forum for how to change PWM frequency on the fly, I found no mention of anyone using "WaveForm" mode. Perhaps it's new? There are also no examples available so I'm trying to figure it out myself.

https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/pwm.html?cp=2_1_0_46#concept_pzc_1pw_nr

The code below works, but for some reason, the last duty-cycle and top_value will only play one cycle even though I have 'repeat' to more than zero. If I put {0,0,0,0} in addition to the sequence, the waveform will complete, but cause some unwanted behavior on my output.

TODO: Add oscilloscope screenshot.

I'm an amateur programmer, so is there an example on how to use WaveForm Mode? I plan to have multiple sequences, so an example on how to update the sequence after the initial seq_values array would be nice

The code below is heavily stripped down so it may not actually compile.

SDK Version: v15.0.0

Thanks!

#include <stdint.h>
#include <string.h>
#include "nordic_common.h"
#include "nrf.h"
#include "app_error.h"
#include "boards.h"
#include "app_timer.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_delay.h"
#include "nrf_drv_pwm.h"

#include "pcb_config.h"
#include "music_tones.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);

void play_tone(uint16_t tone);


void pwm_init()
{

  nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            SPEAKER_OUT | NRF_DRV_PWM_PIN_INVERTED, // channel 0
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_4MHz, // =250ns clock
        .count_mode   = NRF_PWM_MODE_UP,
        // "top_value" is essentially the frequency of the PWM output
        .top_value    = 1000,
        .load_mode    = NRF_PWM_LOAD_WAVE_FORM,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, pwm_handler));

}

void play_tone(uint16_t tone)
{

  uint16_t sequence_step_repeats = 200; // 200x250nsx2= 25ms

  static nrf_pwm_values_wave_form_t const seq_values[] =
	{
		{ NOTE_A7/2 , 0 , 0 , NOTE_A7 },
		{ NOTE_A7/2 , 0 , 0 , NOTE_A7 },
		{ NOTE_A7/2 , 0 , 0 , NOTE_A7 },
		{ NOTE_A7/2 , 0 , 0 , NOTE_A7 },
		{ NOTE_A5/2 , 0 , 0 , NOTE_A5 },
		{ NOTE_A5/2 , 0 , 0 , NOTE_A5 },
		{ 0 , 0 , 0 , 0 }
	};
  nrf_pwm_sequence_t const seq =
  {
      .values.p_wave_form = seq_values,
      .length          = NRF_PWM_VALUES_LENGTH(seq_values),
      .repeats         = sequence_step_repeats,
      .end_delay       = 0 //Additional time (in PWM periods) that the last duty cycle is to be kept after the sequence is played.
  };

  (void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_STOP);
}

int main(void)
{
  // Initialize generic
  log_init();
  timers_init();
  pwm_init();
  power_management_init();

  // Enter main loop.
  for (;;)
  {
  
    play_tone(1);
    nrf_delay_ms(1000);
    while(!nrf_drv_pwm_is_stopped(&m_pwm0)){};

  }
}

Related