Driving a Piezo bender / speaker / buzzer for a Car Alarm


I am looking for support driving a Piezo bender for a car Alarm system. These alarms generally make multiple alarm sounds in a periodic changing manner. I am trying to understand how such an audio signal can be generated using the NRF52832 and also, what is the most suitable HW configuration (Possiby H-Bridge) that can be used to generate the necessary signals to drive such a Piezo sounder / bender / buzzer for the car alarm sounds.

The audio tones generated by typical alarms vary from 2.8KHz to 800 Hz depending on the exact audio being generated.

Is it possible to use the PWM module to do such a thing?

Any support is greatly appreciated.



  • Hello Anadi,

    Is it possible to use the PWM module to do such a thing?

    For your answer, yes. It is possible to driver a Piezo speaker/buzzer with PWM. I have not tried with Piezo bender so I cannot give you an exact answer for this. 

    Here is the reference schematic using FET and Piezo buzzer: 

    Also my reference code:

    /* This array cannot be allocated on stack (hence "static") and it must
       be in RAM (hence no "const", though its content is not changed).	*/
    static nrf_pwm_values_common_t /*const*/ buzzer_seq_values[BUZZER_PWM_STEP] = 
        8192, 0, 8192, 0, 8192, 0, 8192, 0,
        8192, 0, 8192, 0, 8192, 0, 8192, 0,
        8192, 0, 8192, 0, 8192, 0, 8192, 0,
        8192, 0, 8192, 0, 8192, 0, 8192, 0
    nrf_pwm_values_common_t *m_buzz_value = (uint16_t *)buzzer_seq_values;
    nrf_pwm_sequence_t const buzzer_seq =
        .values.p_common = buzzer_seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(buzzer_seq_values),
        .repeats         = 16,
        .end_delay       = 0
    void pwm_init(void)
        nrf_drv_pwm_config_t const buzzer_pwm_config =
            .output_pins =
                BUZZER_TRIGGER_PIN,			  // 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_8MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = 200,
            .load_mode    = NRF_PWM_LOAD_COMMON,
            .step_mode    = NRF_PWM_STEP_AUTO
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_buzzer_pwm, &buzzer_pwm_config, NULL));
        m_used |= USED_PWM(0);
    void buzzer_active(uint16_t repeat_time)
        (void)nrf_drv_pwm_simple_playback(&m_buzzer_pwm, &buzzer_seq, repeat_time, NRF_DRV_PWM_FLAG_STOP);
    /* inside main function */
    int main(void)
        /* Do something here */
        /* Do something here */
        forr (;;)
            /* Do something here */

  • Dear Duy,

    Thanks for sharing a quick response and inputs on my query. I will expand on my original post to share further details on the problem at hand. Piezo buzzers have two (external drive) or three electrode (self drive) construction. Most three electrode piezo elemts have a fixed frequency operation and hence can be driven by using the reference circuit shared by you. Please see (https://electronics.stackexchange.com/questions/18212/whats-the-third-wire-on-a-piezo-buzzer, https://www.murata.com/en-global/products/sound/sounder/basic/piezotype).

    For our case, since the frequency needs to changed, we need to use a 2 electrode external drive piezo diaphragm / bender. For capacitive Piezo elements that we are using, it is recommended to use an AC signal. This can be used to increase the VP-P across the diaphragm to double the value of the VDD and hence the loudness. Please see a reference circuit and attached simulation.

    Further, since the alarm sounds need to vary in the band from 800 Hz to 2.7Khz we need to be able to change the frequencey periodically in order to change the sound type. Please see e.g (https://www.johndcook.com/blog/2016/03/10/creating-police-siren-sounds-with-frequency-modulation/, )

    So, here is what we need to achieve:

    1. Drive 2 inverted polarity channels (simultaneously) in order to drive the attached circuit

    2. Generate signal at different frequencies (simulate sound type)

    3. Use a varying sound level to make it distinguishable (Possibly use PWM based on a sine wave or similar funnction)

    I was not aware of the nrf_drv_pwm_simple_playback function. We had use the following reference code with limited success. I think we can try to change the playback method you have shared to see if we can achieve the desired result.

    Further thoughts and inputs are welcome.



        /* 2-channel PWM, 200Hz, output on DK LED pins. */
        app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_2CH(5000L, BSP_LED_0, BSP_LED_1);
        /* Switch the polarity of the second channel. */
        pwm1_cfg.pin_polarity[1] = APP_PWM_POLARITY_ACTIVE_HIGH;
        /* Initialize and enable PWM. */
        err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback);
        uint32_t value;
        while (true)
            for (uint8_t i = 0; i < 40; ++i)
                value = (i < 20) ? (i * 5) : (100 - (i - 20) * 5);
                ready_flag = false;
                /* Set the duty cycle - keep trying until PWM is ready... */
                while (app_pwm_channel_duty_set(&PWM1, 0, value) == NRF_ERROR_BUSY);
                /* ... or wait for callback. */
                while (!ready_flag);
                APP_ERROR_CHECK(app_pwm_channel_duty_set(&PWM1, 1, value));