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