~ruther/qmk_firmware

83e6ddbbb4c8e715bfe419c4d7fc0ae305ea5bd5 — Drashna Jaelre 1 year, 1 month ago 045e5c9
[Audio] Add support for audio shutdown pin (#22731)

Co-authored-by: Ryan <fauxpark@gmail.com>
M data/mappings/info_config.hjson => data/mappings/info_config.hjson +2 -0
@@ 19,6 19,8 @@
    // Audio
    "AUDIO_DEFAULT_ON": {"info_key": "audio.default.on", "value_type": "bool"},
    "AUDIO_DEFAULT_CLICKY_ON": {"info_key": "audio.default.clicky", "value_type": "bool"},
    "AUDIO_POWER_CONTROL_PIN": {"info_key": "audio.power_control.pin"},
    "AUDIO_POWER_CONTROL_PIN_ON_STATE": {"info_key": "audio.power_control.on_state", "value_type": "int" },
    "AUDIO_VOICES": {"info_key": "audio.voices", "value_type": "flag"},
    "SENDSTRING_BELL": {"info_key": "audio.macro_beep", "value_type": "flag"},


M data/schemas/keyboard.jsonschema => data/schemas/keyboard.jsonschema +8 -0
@@ 135,6 135,14 @@
                },
                "macro_beep": {"type": "boolean"},
                "pins": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
                "power_control": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                        "on_state": {"$ref": "qmk.definitions.v1#/bit"},
                        "pin": {"$ref": "qmk.definitions.v1#/mcu_pin"}
                    }
                },
                "voices": {"type": "boolean"}
            }
        },

M docs/feature_audio.md => docs/feature_audio.md +25 -23
@@ 171,29 171,31 @@ The available keycodes for audio are:

## Audio Config

| Settings                        | Default              | Description                                                                   |
|---------------------------------|----------------------|-------------------------------------------------------------------------------|
|`AUDIO_PIN`                      | *Not defined*        |Configures the pin that the speaker is connected to.                           |
|`AUDIO_PIN_ALT`                  | *Not defined*        |Configures the pin for a second speaker or second pin connected to one speaker.|
|`AUDIO_PIN_ALT_AS_NEGATIVE`      | *Not defined*        |Enables support for one speaker connected to two pins.                         |
|`AUDIO_INIT_DELAY`               | *Not defined*        |Enables delay during startup song to accomidate for USB startup issues.        |
|`AUDIO_ENABLE_TONE_MULTIPLEXING` | *Not defined*        |Enables time splicing/multiplexing to create multiple tones simutaneously.     |
|`STARTUP_SONG`                   | `STARTUP_SOUND`      |Plays when the keyboard starts up (audio.c)                                    |
|`GOODBYE_SONG`                   | `GOODBYE_SOUND`      |Plays when you press the QK_BOOT key (quantum.c)                               |
|`AG_NORM_SONG`                   | `AG_NORM_SOUND`      |Plays when you press AG_NORM (process_magic.c)                                 |
|`AG_SWAP_SONG`                   | `AG_SWAP_SOUND`      |Plays when you press AG_SWAP (process_magic.c)                                 |
|`CG_NORM_SONG`                   | `AG_NORM_SOUND`      |Plays when you press CG_NORM (process_magic.c)                                 |
|`CG_SWAP_SONG`                   | `AG_SWAP_SOUND`      |Plays when you press CG_SWAP (process_magic.c)                                 |
|`MUSIC_ON_SONG`                  | `MUSIC_ON_SOUND`     |Plays when music mode is activated (process_music.c)                           |
|`MUSIC_OFF_SONG`                 | `MUSIC_OFF_SOUND`    |Plays when music mode is deactivated (process_music.c)                         |
|`MIDI_ON_SONG`                   | `MUSIC_ON_SOUND`     |Plays when midi mode is activated (process_music.c)                            |
|`MIDI_OFF_SONG`                  | `MUSIC_OFF_SOUND`    |Plays when midi mode is deactivated (process_music.c)                          |
|`CHROMATIC_SONG`                 | `CHROMATIC_SOUND`    |Plays when the chromatic music mode is selected (process_music.c)              |
|`GUITAR_SONG`                    | `GUITAR_SOUND`       |Plays when the guitar music mode is selected (process_music.c)                 |
|`VIOLIN_SONG`                    | `VIOLIN_SOUND`       |Plays when the violin music mode is selected (process_music.c)                 |
|`MAJOR_SONG`                     | `MAJOR_SOUND`        |Plays when the major music mode is selected (process_music.c)                  |
|`DEFAULT_LAYER_SONGS`            | *Not defined*        |Plays song when switched default layers with [`set_single_persistent_default_layer(layer)`](ref_functions.md#setting-the-persistent-default-layer)(quantum.c)       |
|`SENDSTRING_BELL`                | *Not defined*        |Plays chime when the "enter" ("\a") character is sent (send_string.c)          |
| Settings                         | Default              | Description                                                                                 |
|----------------------------------|----------------------|---------------------------------------------------------------------------------------------|
|`AUDIO_PIN`                       | *Not defined*        |Configures the pin that the speaker is connected to.                                         |
|`AUDIO_PIN_ALT`                   | *Not defined*        |Configures the pin for a second speaker or second pin connected to one speaker.              |
|`AUDIO_PIN_ALT_AS_NEGATIVE`       | *Not defined*        |Enables support for one speaker connected to two pins.                                       |
|`AUDIO_INIT_DELAY`                | *Not defined*        |Enables delay during startup song to accomidate for USB startup issues.                      |
|`AUDIO_ENABLE_TONE_MULTIPLEXING`  | *Not defined*        |Enables time splicing/multiplexing to create multiple tones simutaneously.                   |
|`AUDIO_POWER_CONTROL_PIN`         | *Not defined*        |Enables power control code to enable or cut off power to speaker (such as with PAM8302 amp). |
|`AUDIO_POWER_CONTROL_PIN_ON_STATE`| `1`                  |The state of the audio power control pin when audio is "on" - `1` for high, `0` for low.     |
|`STARTUP_SONG`                    | `STARTUP_SOUND`      |Plays when the keyboard starts up (audio.c)                                                  |
|`GOODBYE_SONG`                    | `GOODBYE_SOUND`      |Plays when you press the QK_BOOT key (quantum.c)                                             |
|`AG_NORM_SONG`                    | `AG_NORM_SOUND`      |Plays when you press AG_NORM (process_magic.c)                                               |
|`AG_SWAP_SONG`                    | `AG_SWAP_SOUND`      |Plays when you press AG_SWAP (process_magic.c)                                               |
|`CG_NORM_SONG`                    | `AG_NORM_SOUND`      |Plays when you press CG_NORM (process_magic.c)                                               |
|`CG_SWAP_SONG`                    | `AG_SWAP_SOUND`      |Plays when you press CG_SWAP (process_magic.c)                                               |
|`MUSIC_ON_SONG`                   | `MUSIC_ON_SOUND`     |Plays when music mode is activated (process_music.c)                                         |
|`MUSIC_OFF_SONG`                  | `MUSIC_OFF_SOUND`    |Plays when music mode is deactivated (process_music.c)                                       |
|`MIDI_ON_SONG`                    | `MUSIC_ON_SOUND`     |Plays when midi mode is activated (process_music.c)                                          |
|`MIDI_OFF_SONG`                   | `MUSIC_OFF_SOUND`    |Plays when midi mode is deactivated (process_music.c)                                        |
|`CHROMATIC_SONG`                  | `CHROMATIC_SOUND`    |Plays when the chromatic music mode is selected (process_music.c)                            |
|`GUITAR_SONG`                     | `GUITAR_SOUND`       |Plays when the guitar music mode is selected (process_music.c)                               |
|`VIOLIN_SONG`                     | `VIOLIN_SOUND`       |Plays when the violin music mode is selected (process_music.c)                               |
|`MAJOR_SONG`                      | `MAJOR_SOUND`        |Plays when the major music mode is selected (process_music.c)                                |
|`DEFAULT_LAYER_SONGS`             | *Not defined*        |Plays song when switched default layers with [`set_single_persistent_default_layer(layer)`](ref_functions.md#setting-the-persistent-default-layer)(quantum.c). |
|`SENDSTRING_BELL`                 | *Not defined*        |Plays chime when the "enter" ("\a") character is sent (send_string.c)                        |

## Tempo
the 'speed' at which SONGs are played is dictated by the set Tempo, which is measured in beats-per-minute. Note lengths are defined relative to that.

M docs/reference_info_json.md => docs/reference_info_json.md +7 -0
@@ 123,10 123,17 @@ Configures the [Audio](feature_audio.md) feature.
        * Default: `false`
    * `pins` (Required)
        * The GPIO pin(s) connected to the speaker(s).
    * `power_control`
        * `on_state`
            * The logical GPIO state required to turn the speaker on.
            * Default: `1` (on = high)
        * `pin`
            * The GPIO pin connected to speaker power circuit.
    * `voices`
        * Use multiple audio voices.
        * Default: `false`


## Backlight :id=backlight

Configures the [Backlight](feature_backlight.md) feature.

M keyboards/adafruit/macropad/config.h => keyboards/adafruit/macropad/config.h +0 -2
@@ 48,5 48,3 @@
#define AUDIO_PWM_CHANNEL RP2040_PWM_CHANNEL_A
#define AUDIO_INIT_DELAY
#define AUDIO_CLICKY

#define SPEAKER_SHUTDOWN GP14

M keyboards/adafruit/macropad/info.json => keyboards/adafruit/macropad/info.json +5 -0
@@ 8,6 8,11 @@
        "pid": "0x0108",
        "device_version": "0.0.1"
    },
    "audio": {
        "power_control": {
            "pin": "GP14"
        }
    },
    "encoder": {
        "rotary": [
            {"pin_a": "GP18", "pin_b": "GP17"}

D keyboards/adafruit/macropad/macropad.c => keyboards/adafruit/macropad/macropad.c +0 -42
@@ 1,42 0,0 @@
/* Copyright 2022 Jose Pablo Ramirez <jp.ramangulo@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "quantum.h"

#ifdef AUDIO_ENABLE
void keyboard_pre_init_kb(void) {
    // ensure pin is set and enabled pre-audio init
    setPinOutput(SPEAKER_SHUTDOWN);
    writePinHigh(SPEAKER_SHUTDOWN);
    keyboard_pre_init_user();
}

void keyboard_post_init_kb(void) {
    // set pin based on active status
    writePin(SPEAKER_SHUTDOWN, audio_is_on());
    keyboard_post_init_user();
}

void audio_on_user(void) {
    writePinHigh(SPEAKER_SHUTDOWN);
}

void audio_off_user(void) {
    // needs a delay or it runs right after play note.
    wait_ms(200);
    writePinLow(SPEAKER_SHUTDOWN);
}
#endif

M platforms/avr/drivers/audio_pwm_hardware.c => platforms/avr/drivers/audio_pwm_hardware.c +3 -3
@@ 213,7 213,7 @@ void channel_2_stop(void) {
}
#endif

void audio_driver_initialize(void) {
void audio_driver_initialize_impl(void) {
#ifdef AUDIO1_PIN_SET
    channel_1_stop();
    gpio_set_pin_output(AUDIO1_PIN);


@@ 254,7 254,7 @@ void audio_driver_initialize(void) {
#endif
}

void audio_driver_stop(void) {
void audio_driver_stop_impl(void) {
#ifdef AUDIO1_PIN_SET
    channel_1_stop();
#endif


@@ 264,7 264,7 @@ void audio_driver_stop(void) {
#endif
}

void audio_driver_start(void) {
void audio_driver_start_impl(void) {
#ifdef AUDIO1_PIN_SET
    channel_1_start();
    if (playing_note) {

M platforms/chibios/drivers/audio_dac_additive.c => platforms/chibios/drivers/audio_dac_additive.c +3 -3
@@ 303,7 303,7 @@ static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_
 */
static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};

void audio_driver_initialize(void) {
void audio_driver_initialize_impl(void) {
    if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
        palSetLineMode(A4, PAL_MODE_INPUT_ANALOG);
        dacStart(&DACD1, &dac_conf);


@@ 350,11 350,11 @@ void audio_driver_initialize(void) {
    gptStart(&GPTD6, &gpt6cfg1);
}

void audio_driver_stop(void) {
void audio_driver_stop_impl(void) {
    state = OUTPUT_SHOULD_STOP;
}

void audio_driver_start(void) {
void audio_driver_start_impl(void) {
    gptStartContinuous(&GPTD6, 2U);

    for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) {

M platforms/chibios/drivers/audio_dac_basic.c => platforms/chibios/drivers/audio_dac_basic.c +3 -3
@@ 190,7 190,7 @@ static void gpt_audio_state_cb(GPTDriver *gptp) {
    }
}

void audio_driver_initialize(void) {
void audio_driver_initialize_impl(void) {
    if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
        palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
        dacStart(&DACD1, &dac_conf_ch1);


@@ 223,7 223,7 @@ void audio_driver_initialize(void) {
    gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg);
}

void audio_driver_stop(void) {
void audio_driver_stop_impl(void) {
    if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
        gptStopTimer(&GPTD6);



@@ 241,7 241,7 @@ void audio_driver_stop(void) {
    gptStopTimer(&AUDIO_STATE_TIMER);
}

void audio_driver_start(void) {
void audio_driver_start_impl(void) {
    if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
        dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE);
    }

M platforms/chibios/drivers/audio_pwm_hardware.c => platforms/chibios/drivers/audio_pwm_hardware.c +3 -3
@@ 87,7 87,7 @@ static void audio_callback(virtual_timer_t *vtp, void *p) {
    chSysUnlockFromISR();
}

void audio_driver_initialize(void) {
void audio_driver_initialize_impl(void) {
    pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);

    // connect the AUDIO_PIN to the PWM hardware


@@ 100,7 100,7 @@ void audio_driver_initialize(void) {
    chVTObjectInit(&audio_vt);
}

void audio_driver_start(void) {
void audio_driver_start_impl(void) {
    channel_1_stop();
    channel_1_start();



@@ 115,7 115,7 @@ void audio_driver_start(void) {
    }
}

void audio_driver_stop(void) {
void audio_driver_stop_impl(void) {
    channel_1_stop();
    chVTReset(&audio_vt);
}

M platforms/chibios/drivers/audio_pwm_software.c => platforms/chibios/drivers/audio_pwm_software.c +3 -3
@@ 121,7 121,7 @@ GPTConfig   gptCFG = {
    .callback  = gpt_callback,
};

void audio_driver_initialize(void) {
void audio_driver_initialize_impl(void) {
    pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);

    palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL);


@@ 138,7 138,7 @@ void audio_driver_initialize(void) {
    gptStart(&AUDIO_STATE_TIMER, &gptCFG);
}

void audio_driver_start(void) {
void audio_driver_start_impl(void) {
    channel_1_stop();
    channel_1_start();



@@ 147,7 147,7 @@ void audio_driver_start(void) {
    }
}

void audio_driver_stop(void) {
void audio_driver_stop_impl(void) {
    channel_1_stop();
    gptStopTimer(&AUDIO_STATE_TIMER);
}

M platforms/test/drivers/audio_pwm_hardware.c => platforms/test/drivers/audio_pwm_hardware.c +3 -3
@@ 15,6 15,6 @@

#include "audio.h"

void audio_driver_initialize(void) {}
void audio_driver_start() {}
void audio_driver_stop() {}
void audio_driver_initialize_impl(void) {}
void audio_driver_start_impl() {}
void audio_driver_stop_impl() {}

M quantum/audio/audio.c => quantum/audio/audio.c +27 -0
@@ 20,6 20,7 @@
#include "debug.h"
#include "wait.h"
#include "util.h"
#include "gpio.h"

/* audio system:
 *


@@ 121,6 122,32 @@ static bool    audio_initialized    = false;
static bool    audio_driver_stopped = true;
audio_config_t audio_config;

#ifndef AUDIO_POWER_CONTROL_PIN_ON_STATE
#    define AUDIO_POWER_CONTROL_PIN_ON_STATE 1
#endif

void audio_driver_initialize(void) {
#ifdef AUDIO_POWER_CONTROL_PIN
    gpio_set_pin_output_push_pull(AUDIO_POWER_CONTROL_PIN);
    gpio_write_pin(AUDIO_POWER_CONTROL_PIN, !AUDIO_POWER_CONTROL_PIN_ON_STATE);
#endif
    audio_driver_initialize_impl();
}

void audio_driver_stop(void) {
    audio_driver_stop_impl();
#ifdef AUDIO_POWER_CONTROL_PIN
    gpio_write_pin(AUDIO_POWER_CONTROL_PIN, !AUDIO_POWER_CONTROL_PIN_ON_STATE);
#endif
}

void audio_driver_start(void) {
#ifdef AUDIO_POWER_CONTROL_PIN
    gpio_write_pin(AUDIO_POWER_CONTROL_PIN, AUDIO_POWER_CONTROL_PIN_ON_STATE);
#endif
    audio_driver_start_impl();
}

void eeconfig_update_audio_current(void) {
    eeconfig_update_audio(audio_config.raw);
}

M quantum/audio/audio.h => quantum/audio/audio.h +3 -3
@@ 215,9 215,9 @@ void audio_startup(void);
// hardware interface

// implementation in the driver_avr/arm_* respective parts
void audio_driver_initialize(void);
void audio_driver_start(void);
void audio_driver_stop(void);
void audio_driver_initialize_impl(void);
void audio_driver_start_impl(void);
void audio_driver_stop_impl(void);

/**
 * @brief get the number of currently active tones

Do not follow this link