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
  • Eliot,

    I'm not familiar with the code you posted above or the library that it uses, however I have implemented code to control a piezo buzzer in much the same way that you require, which I'll provide snippets of below. Some of this code may be in the library you use, again I haven't looked at it.

    First, you can configure the pin to the buzzer as an output like below:

    // Audio / PWM Pin Setup
      nrf_gpio_cfg_output(PWM_OUTPUT_PIN_NUMBER);		// Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as output
      nrf_gpiote_task_config(0, PWM_OUTPUT_PIN_NUMBER, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW);
      NRF_PPI->CH[1].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[1];  // Configure PPI channel 1 to toggle PWM_OUTPUT_PIN on every TIMER2 COMPARE[1] match
      NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
      NRF_PPI->CHEN = (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos);  // Enable PPI channels 0-2
    

    Then you can configure the Timer to control the PWM output as below - this code will cause the PWM pin to toggle whenever the number in CC[1] is hit:

    // Configure Timer for Buzzer
    	NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;
      NRF_TIMER2->PRESCALER = 4; //1us resolution
      NRF_TIMER2->TASKS_CLEAR = 1;
      NRF_TIMER2->CC[1] = MAX_SAMPLE_LEVELS;
      NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);
      NVIC_EnableIRQ(TIMER2_IRQn); // Enable interrupt on Timer 2
      __enable_irq();
    

    Next, you can implement a handler for the timer using code like below:

    void TIMER2_IRQHandler(void)						// used for buzzer
    {
      if ((NRF_TIMER2->EVENTS_COMPARE[1] != 0) && ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE1_Msk) != 0))
      {
        // Sets the next CC1 value
        NRF_TIMER2->EVENTS_COMPARE[1] = 0;
        NRF_TIMER2->CC[1] = (NRF_TIMER2->CC[1] + MAX_SAMPLE_LEVELS);
      }
    }
    

    To start the buzzer, simply start the Timer, as below:

    NRF_TIMER2->TASKS_START = 1;

    Try changing the value of MAX_SAMPLE_LEVELS around to achieve different tones.

    I hope this helps!

    Cheers, Steve

Reply
  • Eliot,

    I'm not familiar with the code you posted above or the library that it uses, however I have implemented code to control a piezo buzzer in much the same way that you require, which I'll provide snippets of below. Some of this code may be in the library you use, again I haven't looked at it.

    First, you can configure the pin to the buzzer as an output like below:

    // Audio / PWM Pin Setup
      nrf_gpio_cfg_output(PWM_OUTPUT_PIN_NUMBER);		// Connect GPIO input buffers and configure PWM_OUTPUT_PIN_NUMBER as output
      nrf_gpiote_task_config(0, PWM_OUTPUT_PIN_NUMBER, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW);
      NRF_PPI->CH[1].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[1];  // Configure PPI channel 1 to toggle PWM_OUTPUT_PIN on every TIMER2 COMPARE[1] match
      NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
      NRF_PPI->CHEN = (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos);  // Enable PPI channels 0-2
    

    Then you can configure the Timer to control the PWM output as below - this code will cause the PWM pin to toggle whenever the number in CC[1] is hit:

    // Configure Timer for Buzzer
    	NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;
      NRF_TIMER2->PRESCALER = 4; //1us resolution
      NRF_TIMER2->TASKS_CLEAR = 1;
      NRF_TIMER2->CC[1] = MAX_SAMPLE_LEVELS;
      NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);
      NVIC_EnableIRQ(TIMER2_IRQn); // Enable interrupt on Timer 2
      __enable_irq();
    

    Next, you can implement a handler for the timer using code like below:

    void TIMER2_IRQHandler(void)						// used for buzzer
    {
      if ((NRF_TIMER2->EVENTS_COMPARE[1] != 0) && ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE1_Msk) != 0))
      {
        // Sets the next CC1 value
        NRF_TIMER2->EVENTS_COMPARE[1] = 0;
        NRF_TIMER2->CC[1] = (NRF_TIMER2->CC[1] + MAX_SAMPLE_LEVELS);
      }
    }
    

    To start the buzzer, simply start the Timer, as below:

    NRF_TIMER2->TASKS_START = 1;

    Try changing the value of MAX_SAMPLE_LEVELS around to achieve different tones.

    I hope this helps!

    Cheers, Steve

Children
Related