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

PWM with a piezo buzzer

I'm trying to get some sound out of a piezo buzzer using the PWM library here:

github.com/.../nrf51-pwm-library

My buzzer has a resonant frequency of 2,730Hz. The buzzer doesn't have its own driver, I need to generate the wave for it. What changes do I need to make to main_sin.c to get that frequency?

Here's what I've tried so far.

int main(void)
{
    uint32_t counter = 0;
    
    nrf_pwm_config_t pwm_config = PWM_DEFAULT_CONFIG;
    
    pwm_config.mode             = PWM_MODE_BUZZER_64; // Was PWM_MODE_LED_100
    pwm_config.num_channels     = 1; // Was 3

    // One channel only, on pin 14
    pwm_config.gpio_num[0]      = 14; // Was 8
    // pwm_config.gpio_num[1]      = 8;
    // pwm_config.gpio_num[2]      = 10;
    
    // Initialize the PWM library
    nrf_pwm_init(&pwm_config);

    while (true)
    {
        // Update the 3 outputs with out of phase sine waves
        nrf_pwm_set_value(0, sin_table[counter]);
        // nrf_pwm_set_value(1, sin_table[(counter + 33) % 100]);
        // nrf_pwm_set_value(2, sin_table[(counter + 66) % 100]);
        counter = (counter + 1) % 100;
        
        // Add a delay to control the speed of the sine wave
        // 125 kHz is one wave every 0.000008s or 0.008ms or 8us, so why is this 8000us?
        // nrf_delay_us(8000);

        // If 8000us gets us 125kHz, then 366,300 should get us 2730Hz.
        nrf_delay_us(366300);
    }
}

As the comments above show, I'm confused about how this delay relates to the PWM frequency.

I'd also like to be executing other code while the buzzer is sounding and thought that PPI made this possible. So why the while() loop here at all?

Parents
  • Hi Eliot

    Did you figure this out?

    You can modify the nrf51-pwm-library to run at a base frequency of about 2730 Hz quite easily, you just have to change the max value of the PWM using the following formula:

    pwm_max_value = 16.000.000 / (2 * 2^PRESCALER * FREQUENCY)

    With a prescaler of 0 this gives you a max value of 2930, and I implemented a new PWM mode in nrf_pwm.c to test this out:

        case PWM_MODE_BUZZER_2730HZ:
            PWM_TIMER->PRESCALER = 0;
            pwm_max_value = 2930;
            break;
    

    Now you just need to set the channel according to the duty cycle you want on your buzzer signal, for 50% duty cycle use 1465.

    Best regards Torbjørn

  • Sorry, I'm not following entirely. I've modified nrf_pwm_init() to use your extra case, thanks for that. But don't understand what you mean by "for 50% duty cycle use 1465". What should the pwm_config look like?

    nrf_pwm_config_t pwm_config =
    	{.num_channels  = 3,
    	.gpio_num       = {8,9,10},
    	.ppi_channel    = {0,1,2,3,4,5},
    	.gpiote_channel = {2,3,0},
    	.mode           = PWM_MODE_BUZZER_2730HZ};
    

    My buzzer has one pin on the Nordic's pin 14 and the other on ground, effectively.

Reply
  • Sorry, I'm not following entirely. I've modified nrf_pwm_init() to use your extra case, thanks for that. But don't understand what you mean by "for 50% duty cycle use 1465". What should the pwm_config look like?

    nrf_pwm_config_t pwm_config =
    	{.num_channels  = 3,
    	.gpio_num       = {8,9,10},
    	.ppi_channel    = {0,1,2,3,4,5},
    	.gpiote_channel = {2,3,0},
    	.mode           = PWM_MODE_BUZZER_2730HZ};
    

    My buzzer has one pin on the Nordic's pin 14 and the other on ground, effectively.

Children
No Data
Related