[Core] Adjust PWM hardware audio driver for RP2040 (#17723)
This commit is contained in:
		
							parent
							
								
									efe520645e
								
							
						
					
					
						commit
						19145704e4
					
				
					 22 changed files with 94 additions and 145 deletions
				
			
		| 
						 | 
				
			
			@ -159,7 +159,6 @@ A configuration example for the STM32F103C8 would be:
 | 
			
		|||
//halconf.h:
 | 
			
		||||
#define HAL_USE_PWM                 TRUE
 | 
			
		||||
#define HAL_USE_PAL                 TRUE
 | 
			
		||||
#define HAL_USE_GPT                 TRUE
 | 
			
		||||
#include_next <halconf.h>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -168,8 +167,6 @@ A configuration example for the STM32F103C8 would be:
 | 
			
		|||
#include_next <mcuconf.h>
 | 
			
		||||
#undef STM32_PWM_USE_TIM1
 | 
			
		||||
#define STM32_PWM_USE_TIM1                  TRUE
 | 
			
		||||
#undef STM32_GPT_USE_TIM4
 | 
			
		||||
#define STM32_GPT_USE_TIM4                  TRUE
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If we now target pin A8, looking through the data-sheet of the STM32F103C8, for the timers and alternate functions
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +181,6 @@ with all this information, the configuration would contain these lines:
 | 
			
		|||
#define AUDIO_PIN A8
 | 
			
		||||
#define AUDIO_PWM_DRIVER PWMD1
 | 
			
		||||
#define AUDIO_PWM_CHANNEL 1
 | 
			
		||||
#define AUDIO_STATE_TIMER GPTD4
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
ChibiOS uses GPIOv1 for the F103, which only knows of one alternate function.
 | 
			
		||||
| 
						 | 
				
			
			@ -207,15 +203,15 @@ You can also change the timer used for software PWM by defining the driver.  For
 | 
			
		|||
 | 
			
		||||
While not an exhaustive list, the following table provides the scenarios that have been partially validated:
 | 
			
		||||
 | 
			
		||||
|                          | DAC basic          | DAC additive       | PWM hardware       | PWM software       |
 | 
			
		||||
|--------------------------|--------------------|--------------------|--------------------|--------------------|
 | 
			
		||||
|                          |     DAC basic      |    DAC additive    |    PWM hardware    |    PWM software    |
 | 
			
		||||
| ------------------------ | ------------------ | ------------------ | ------------------ | ------------------ |
 | 
			
		||||
| Atmega32U4               | :o:                | :o:                | :heavy_check_mark: | :o:                |
 | 
			
		||||
| RP2040                   | :x:                | :x:                | :heavy_check_mark: | ?                  |
 | 
			
		||||
| STM32F103C8 (bluepill)   | :x:                | :x:                | :heavy_check_mark: | :heavy_check_mark: |
 | 
			
		||||
| STM32F303CCT6 (proton-c) | :heavy_check_mark: | :heavy_check_mark: | ?                  | :heavy_check_mark: |
 | 
			
		||||
| STM32F405VG              | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
 | 
			
		||||
| L0xx                     | :x: (no Tim8)      | ?                  | ?                  | ?                  |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
:heavy_check_mark: : works and was tested  
 | 
			
		||||
:o: : does not apply  
 | 
			
		||||
:x: : not supported by MCU
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,10 +2,10 @@
 | 
			
		|||
 | 
			
		||||
The following table shows the current driver status for peripherals on RP2040 MCUs:
 | 
			
		||||
 | 
			
		||||
| System                                                           | Support                                        |
 | 
			
		||||
|                              System                              |                    Support                     |
 | 
			
		||||
| ---------------------------------------------------------------- | ---------------------------------------------- |
 | 
			
		||||
| [ADC driver](adc_driver.md)                                      | Support planned (no ETA)                       |
 | 
			
		||||
| [Audio](audio_driver.md)                                         | Support planned (no ETA)                       |
 | 
			
		||||
| [Audio](audio_driver.md#pwm-hardware)                            | :heavy_check_mark:                             |
 | 
			
		||||
| [Backlight](feature_backlight.md)                                | :heavy_check_mark:                             |
 | 
			
		||||
| [I2C driver](i2c_driver.md)                                      | :heavy_check_mark:                             |
 | 
			
		||||
| [SPI driver](spi_driver.md)                                      | :heavy_check_mark:                             |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,7 +60,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		|||
#define AUDIO_PWM_DRIVER   PWMD3
 | 
			
		||||
#define AUDIO_PWM_CHANNEL  4
 | 
			
		||||
#define AUDIO_PWM_PAL_MODE 2
 | 
			
		||||
#define AUDIO_STATE_TIMER  GPTD4
 | 
			
		||||
 | 
			
		||||
/* serial.c configuration for split keyboard */
 | 
			
		||||
#undef SOFT_SERIAL_PIN
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,5 @@
 | 
			
		|||
#define HAL_USE_SPI     TRUE
 | 
			
		||||
#define SPI_USE_WAIT    TRUE
 | 
			
		||||
#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
 | 
			
		||||
#define HAL_USE_GPT     TRUE
 | 
			
		||||
 | 
			
		||||
#include_next <halconf.h>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,8 +38,5 @@
 | 
			
		|||
#undef STM32_SERIAL_USE_USART2
 | 
			
		||||
#define STM32_SERIAL_USE_USART2 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_GPT_USE_TIM4
 | 
			
		||||
#define STM32_GPT_USE_TIM4 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_ST_USE_TIMER
 | 
			
		||||
#define STM32_ST_USE_TIMER 5
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,6 @@
 | 
			
		|||
#define AUDIO_PWM_DRIVER   PWMD4
 | 
			
		||||
#define AUDIO_PWM_CHANNEL  2
 | 
			
		||||
#define AUDIO_PWM_PAL_MODE 2
 | 
			
		||||
#define AUDIO_STATE_TIMER  GPTD3
 | 
			
		||||
#define AUDIO_INIT_DELAY
 | 
			
		||||
#define AUDIO_ENABLE_TONE_MULTIPLEXING
 | 
			
		||||
#define AUDIO_TONE_MULTIPLEXING_RATE_DEFAULT 10
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,6 @@
 | 
			
		|||
 | 
			
		||||
#define HAL_USE_PWM     TRUE
 | 
			
		||||
#define HAL_USE_PAL     TRUE
 | 
			
		||||
#define HAL_USE_GPT     TRUE
 | 
			
		||||
#define HAL_USE_SERIAL  TRUE
 | 
			
		||||
// #define HAL_USE_I2C     TRUE
 | 
			
		||||
#define HAL_USE_SPI     TRUE
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,8 +36,5 @@
 | 
			
		|||
#undef STM32_SERIAL_USE_USART1
 | 
			
		||||
#define STM32_SERIAL_USE_USART1 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_GPT_USE_TIM3
 | 
			
		||||
#define STM32_GPT_USE_TIM3 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_ST_USE_TIMER
 | 
			
		||||
#define STM32_ST_USE_TIMER 5
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		|||
#define AUDIO_PWM_DRIVER PWMD2
 | 
			
		||||
#define AUDIO_PWM_CHANNEL 3
 | 
			
		||||
#define AUDIO_PWM_PAL_MODE 1
 | 
			
		||||
#define AUDIO_STATE_TIMER  GPTD1
 | 
			
		||||
 | 
			
		||||
#define AUDIO_CLICKY
 | 
			
		||||
#define AUDIO_CLICKY_FREQ_RANDOMNESS 1.5f
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,5 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define HAL_USE_PWM TRUE
 | 
			
		||||
#define HAL_USE_GPT TRUE
 | 
			
		||||
 | 
			
		||||
#include_next <halconf.h>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,8 +23,5 @@
 | 
			
		|||
#undef STM32_PWM_USE_TIM4
 | 
			
		||||
#define STM32_PWM_USE_TIM4 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_GPT_USE_TIM1
 | 
			
		||||
#define STM32_GPT_USE_TIM1 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_ST_USE_TIMER
 | 
			
		||||
#define STM32_ST_USE_TIMER 5
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,3 +16,7 @@
 | 
			
		|||
 | 
			
		||||
#define BACKLIGHT_PWM_DRIVER PWMD4
 | 
			
		||||
#define BACKLIGHT_PWM_CHANNEL RP2040_PWM_CHANNEL_B
 | 
			
		||||
 | 
			
		||||
#define AUDIO_PIN GP16
 | 
			
		||||
#define AUDIO_PWM_DRIVER PWMD0
 | 
			
		||||
#define AUDIO_PWM_CHANNEL RP2040_PWM_CHANNEL_A
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,5 +5,8 @@
 | 
			
		|||
 | 
			
		||||
#include_next "mcuconf.h"
 | 
			
		||||
 | 
			
		||||
#undef RP_PWM_USE_PWM0
 | 
			
		||||
#define RP_PWM_USE_PWM0 TRUE
 | 
			
		||||
 | 
			
		||||
#undef RP_PWM_USE_PWM4
 | 
			
		||||
#define RP_PWM_USE_PWM4 TRUE
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		|||
#define AUDIO_PWM_DRIVER   PWMD3
 | 
			
		||||
#define AUDIO_PWM_CHANNEL  4
 | 
			
		||||
#define AUDIO_PWM_PAL_MODE 2
 | 
			
		||||
#define AUDIO_STATE_TIMER  GPTD4
 | 
			
		||||
 | 
			
		||||
/* serial.c configuration for split keyboard */
 | 
			
		||||
#define SERIAL_USART_FULL_DUPLEX  // Enable full duplex operation mode.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,5 @@
 | 
			
		|||
#define HAL_USE_SPI     TRUE
 | 
			
		||||
#define SPI_USE_WAIT    TRUE
 | 
			
		||||
#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
 | 
			
		||||
#define HAL_USE_GPT     TRUE
 | 
			
		||||
 | 
			
		||||
#include_next <halconf.h>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,8 +38,5 @@
 | 
			
		|||
#undef STM32_SERIAL_USE_USART2
 | 
			
		||||
#define STM32_SERIAL_USE_USART2 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_GPT_USE_TIM4
 | 
			
		||||
#define STM32_GPT_USE_TIM4 TRUE
 | 
			
		||||
 | 
			
		||||
#undef STM32_ST_USE_TIMER
 | 
			
		||||
#define STM32_ST_USE_TIMER 5
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,6 @@
 | 
			
		|||
#define AUDIO_PWM_PAL_MODE 1
 | 
			
		||||
#define AUDIO_PWM_DRIVER PWMD1
 | 
			
		||||
#define AUDIO_PWM_CHANNEL 1
 | 
			
		||||
#define AUDIO_STATE_TIMER GPTD4
 | 
			
		||||
 | 
			
		||||
/* RGB LED */
 | 
			
		||||
#define RGB_DI_PIN B1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,9 +18,6 @@
 | 
			
		|||
 | 
			
		||||
/* PWM for AUDIO and RGB LED */
 | 
			
		||||
#define HAL_USE_PWM TRUE
 | 
			
		||||
/* GPT and PAL for Audio */
 | 
			
		||||
#define HAL_USE_GPT TRUE
 | 
			
		||||
#define HAL_USE_PAL TRUE
 | 
			
		||||
/* I2C for OLED display */
 | 
			
		||||
#define HAL_USE_I2C TRUE
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,9 +21,6 @@
 | 
			
		|||
/* TIM1 PWM used for audio driver */
 | 
			
		||||
#undef STM32_PWM_USE_TIM1
 | 
			
		||||
#define STM32_PWM_USE_TIM1 TRUE
 | 
			
		||||
/* TIM5 GPT used for audio driver */
 | 
			
		||||
#undef STM32_GPT_USE_TIM4
 | 
			
		||||
#define STM32_GPT_USE_TIM4 TRUE
 | 
			
		||||
 | 
			
		||||
/* TIM3 used for WS2812 driver */
 | 
			
		||||
#undef STM32_PWM_USE_TIM3
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,10 +28,18 @@
 | 
			
		|||
#    define USE_GPIOV1
 | 
			
		||||
#    define PAL_OUTPUT_TYPE_OPENDRAIN _Static_assert(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible");
 | 
			
		||||
 | 
			
		||||
/* Aliases for GPIO PWM channels - every pin has at least one PWM channel
 | 
			
		||||
 * assigned */
 | 
			
		||||
#    define RP2040_PWM_CHANNEL_A 1U
 | 
			
		||||
#    define RP2040_PWM_CHANNEL_B 2U
 | 
			
		||||
 | 
			
		||||
#    define BACKLIGHT_PAL_MODE (PAL_MODE_ALTERNATE_PWM | PAL_RP_PAD_DRIVE12 | PAL_RP_GPIO_OE)
 | 
			
		||||
#    define BACKLIGHT_PWM_COUNTER_FREQUENCY 1000000
 | 
			
		||||
#    define BACKLIGHT_PWM_PERIOD BACKLIGHT_PWM_COUNTER_FREQUENCY / 2048
 | 
			
		||||
 | 
			
		||||
#    define AUDIO_PWM_PAL_MODE (PAL_MODE_ALTERNATE_PWM | PAL_RP_PAD_DRIVE12 | PAL_RP_GPIO_OE)
 | 
			
		||||
#    define AUDIO_PWM_COUNTER_FREQUENCY 500000
 | 
			
		||||
 | 
			
		||||
#    define usb_lld_endpoint_fields
 | 
			
		||||
 | 
			
		||||
#    define I2C1_SCL_PAL_MODE (PAL_MODE_ALTERNATE_I2C | PAL_RP_PAD_SLEWFAST | PAL_RP_PAD_PUE | PAL_RP_PAD_DRIVE4)
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +63,7 @@
 | 
			
		|||
#        define USE_GPIOV1
 | 
			
		||||
#        define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_STM32_ALTERNATE_OPENDRAIN
 | 
			
		||||
#        define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_STM32_ALTERNATE_PUSHPULL
 | 
			
		||||
#        define AUDIO_PWM_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
 | 
			
		||||
#    else
 | 
			
		||||
#        define PAL_OUTPUT_TYPE_OPENDRAIN PAL_STM32_OTYPE_OPENDRAIN
 | 
			
		||||
#        define PAL_OUTPUT_TYPE_PUSHPULL PAL_STM32_OTYPE_PUSHPULL
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +85,7 @@
 | 
			
		|||
#        define USE_I2CV1
 | 
			
		||||
#        define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_GD32_ALTERNATE_OPENDRAIN
 | 
			
		||||
#        define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_GD32_ALTERNATE_PUSHPULL
 | 
			
		||||
#        define AUDIO_PWM_PAL_MODE PAL_MODE_GD32_ALTERNATE_PUSHPULL
 | 
			
		||||
#    endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,29 +1,15 @@
 | 
			
		|||
/* Copyright 2020 Jack Humbert
 | 
			
		||||
 * Copyright 2020 JohSchneider
 | 
			
		||||
 *
 | 
			
		||||
 * 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/>.
 | 
			
		||||
 */
 | 
			
		||||
// Copyright 2022 Stefan Kerkmann
 | 
			
		||||
// Copyright 2020 Jack Humbert
 | 
			
		||||
// Copyright 2020 JohSchneider
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Audio Driver: PWM
 | 
			
		||||
 | 
			
		||||
the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
 | 
			
		||||
 | 
			
		||||
this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware.
 | 
			
		||||
The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function.
 | 
			
		||||
 | 
			
		||||
 */
 | 
			
		||||
// Audio Driver: PWM the duty-cycle is always kept at 50%, and the pwm-period is
 | 
			
		||||
// adjusted to match the frequency of a note to be played back. This driver uses
 | 
			
		||||
// the chibios-PWM system to produce a square-wave on specific output pins that
 | 
			
		||||
// are connected to the PWM hardware. The hardware directly toggles the pin via
 | 
			
		||||
// its alternate function. see your MCUs data-sheet for which pin can be driven
 | 
			
		||||
// by what timer - looking for TIMx_CHy and the corresponding alternate
 | 
			
		||||
// function.
 | 
			
		||||
 | 
			
		||||
#include "audio.h"
 | 
			
		||||
#include "ch.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -33,53 +19,36 @@ The hardware directly toggles the pin via its alternate function. see your MCUs
 | 
			
		|||
#    error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(AUDIO_PWM_COUNTER_FREQUENCY)
 | 
			
		||||
#    define AUDIO_PWM_COUNTER_FREQUENCY 100000
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern bool    playing_note;
 | 
			
		||||
extern bool    playing_melody;
 | 
			
		||||
extern uint8_t note_timbre;
 | 
			
		||||
 | 
			
		||||
static PWMConfig pwmCFG = {
 | 
			
		||||
    .frequency = 100000, /* PWM clock frequency  */
 | 
			
		||||
    // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
 | 
			
		||||
    .period   = 2,    /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
 | 
			
		||||
    .callback = NULL, /* no callback, the hardware directly toggles the pin */
 | 
			
		||||
    .channels =
 | 
			
		||||
        {
 | 
			
		||||
#if AUDIO_PWM_CHANNEL == 4
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},   /* channel 0 -> TIMx_CH1 */
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},   /* channel 1 -> TIMx_CH2 */
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},   /* channel 2 -> TIMx_CH3 */
 | 
			
		||||
            {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */
 | 
			
		||||
#elif AUDIO_PWM_CHANNEL == 3
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},
 | 
			
		||||
            {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL}
 | 
			
		||||
#elif AUDIO_PWM_CHANNEL == 2
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},
 | 
			
		||||
            {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL}
 | 
			
		||||
#else /*fallback to CH1 */
 | 
			
		||||
            {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL},
 | 
			
		||||
            {PWM_OUTPUT_DISABLED, NULL}
 | 
			
		||||
#endif
 | 
			
		||||
        },
 | 
			
		||||
};
 | 
			
		||||
static PWMConfig pwmCFG = {.frequency = AUDIO_PWM_COUNTER_FREQUENCY, /* PWM clock frequency  */
 | 
			
		||||
                           .period    = 2,
 | 
			
		||||
                           .callback  = NULL,
 | 
			
		||||
                           .channels  = {[(AUDIO_PWM_CHANNEL - 1)] = {.mode = PWM_OUTPUT_ACTIVE_HIGH, .callback = NULL}}};
 | 
			
		||||
 | 
			
		||||
static float channel_1_frequency = 0.0f;
 | 
			
		||||
void         channel_1_set_frequency(float freq) {
 | 
			
		||||
 | 
			
		||||
void channel_1_set_frequency(float freq) {
 | 
			
		||||
    channel_1_frequency = freq;
 | 
			
		||||
 | 
			
		||||
    if (freq <= 0.0) // a pause/rest has freq=0
 | 
			
		||||
    if (freq <= 0.0) {
 | 
			
		||||
        // a pause/rest has freq=0
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pwmcnt_t period = (pwmCFG.frequency / freq);
 | 
			
		||||
    pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
 | 
			
		||||
    pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
 | 
			
		||||
                     // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
 | 
			
		||||
                     PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
 | 
			
		||||
    chSysLockFromISR();
 | 
			
		||||
    pwmChangePeriodI(&AUDIO_PWM_DRIVER, period);
 | 
			
		||||
    pwmEnableChannelI(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
 | 
			
		||||
                      // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
 | 
			
		||||
                      PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
 | 
			
		||||
    chSysUnlockFromISR();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float channel_1_get_frequency(void) {
 | 
			
		||||
| 
						 | 
				
			
			@ -95,54 +64,53 @@ void channel_1_stop(void) {
 | 
			
		|||
    pwmStop(&AUDIO_PWM_DRIVER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gpt_callback(GPTDriver *gptp);
 | 
			
		||||
GPTConfig   gptCFG = {
 | 
			
		||||
    /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
 | 
			
		||||
       the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
 | 
			
		||||
       the tempo (which might vary!) is in bpm (beats per minute)
 | 
			
		||||
       therefore: if the timer ticks away at .frequency = (60*64)Hz,
 | 
			
		||||
       and the .interval counts from 64 downwards - audio_update_state is
 | 
			
		||||
       called just often enough to not miss any notes
 | 
			
		||||
    */
 | 
			
		||||
    .frequency = 60 * 64,
 | 
			
		||||
    .callback  = gpt_callback,
 | 
			
		||||
};
 | 
			
		||||
static virtual_timer_t audio_vt;
 | 
			
		||||
static void            audio_callback(virtual_timer_t *vtp, void *p);
 | 
			
		||||
 | 
			
		||||
void audio_driver_initialize(void) {
 | 
			
		||||
    pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
 | 
			
		||||
 | 
			
		||||
    // connect the AUDIO_PIN to the PWM hardware
 | 
			
		||||
#if defined(USE_GPIOV1) // STM32F103C8
 | 
			
		||||
    palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE_PUSHPULL);
 | 
			
		||||
#else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
 | 
			
		||||
    palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE(AUDIO_PWM_PAL_MODE));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    gptStart(&AUDIO_STATE_TIMER, &gptCFG);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_driver_start(void) {
 | 
			
		||||
    channel_1_stop();
 | 
			
		||||
    channel_1_start();
 | 
			
		||||
 | 
			
		||||
    if (playing_note || playing_melody) {
 | 
			
		||||
        gptStartContinuous(&AUDIO_STATE_TIMER, 64);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_driver_stop(void) {
 | 
			
		||||
    channel_1_stop();
 | 
			
		||||
    gptStopTimer(&AUDIO_STATE_TIMER);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* a regular timer task, that checks the note to be currently played
 | 
			
		||||
 * and updates the pwm to output that frequency
 | 
			
		||||
 */
 | 
			
		||||
static void gpt_callback(GPTDriver *gptp) {
 | 
			
		||||
// a regular timer task, that checks the note to be currently played and updates
 | 
			
		||||
// the pwm to output that frequency.
 | 
			
		||||
static void audio_callback(virtual_timer_t *vtp, void *p) {
 | 
			
		||||
    float freq; // TODO: freq_alt
 | 
			
		||||
 | 
			
		||||
    if (audio_update_state()) {
 | 
			
		||||
        freq = audio_get_processed_frequency(0); // freq_alt would be index=1
 | 
			
		||||
        channel_1_set_frequency(freq);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    chSysLockFromISR();
 | 
			
		||||
    chVTSetI(&audio_vt, TIME_MS2I(16), audio_callback, NULL);
 | 
			
		||||
    chSysUnlockFromISR();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_driver_initialize(void) {
 | 
			
		||||
    pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
 | 
			
		||||
 | 
			
		||||
    // connect the AUDIO_PIN to the PWM hardware
 | 
			
		||||
#if defined(USE_GPIOV1) // STM32F103C8, RP2040
 | 
			
		||||
    palSetLineMode(AUDIO_PIN, AUDIO_PWM_PAL_MODE);
 | 
			
		||||
#else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
 | 
			
		||||
    palSetLineMode(AUDIO_PIN, PAL_MODE_ALTERNATE(AUDIO_PWM_PAL_MODE));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    chVTObjectInit(&audio_vt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_driver_start(void) {
 | 
			
		||||
    channel_1_stop();
 | 
			
		||||
    channel_1_start();
 | 
			
		||||
 | 
			
		||||
    if ((playing_note || playing_melody) && !chVTIsArmed(&audio_vt)) {
 | 
			
		||||
        // a whole note is one beat, which is - per definition in
 | 
			
		||||
        // musical_notes.h - set to 64 the longest note is
 | 
			
		||||
        // BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4 the tempo (which
 | 
			
		||||
        // might vary!) is in bpm (beats per minute) therefore: if the timer
 | 
			
		||||
        // ticks away at 64Hz (~16.6ms) audio_update_state is called just often
 | 
			
		||||
        // enough to not miss any notes
 | 
			
		||||
        chVTSet(&audio_vt, TIME_MS2I(16), audio_callback, NULL);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void audio_driver_stop(void) {
 | 
			
		||||
    channel_1_stop();
 | 
			
		||||
    chVTReset(&audio_vt);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								platforms/chibios/vendors/RP/_pin_defs.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								platforms/chibios/vendors/RP/_pin_defs.h
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -35,8 +35,3 @@
 | 
			
		|||
#define GP28 28U
 | 
			
		||||
#define GP29 29U
 | 
			
		||||
#define GP30 30U
 | 
			
		||||
 | 
			
		||||
/* Aliases for GPIO PWM channels - every pin has at least one PWM channel
 | 
			
		||||
 * assigned */
 | 
			
		||||
#define RP2040_PWM_CHANNEL_A 1U
 | 
			
		||||
#define RP2040_PWM_CHANNEL_B 2U
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue