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)){};
}
}