diff --git a/drivers/gaudio/pwm/driver.mk b/drivers/gaudio/pwm/driver.mk new file mode 100644 index 00000000..52f752aa --- /dev/null +++ b/drivers/gaudio/pwm/driver.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudio/pwm/gaudio_play_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gaudio/pwm diff --git a/drivers/gaudio/pwm/gaudio_play_board_template.h b/drivers/gaudio/pwm/gaudio_play_board_template.h new file mode 100644 index 00000000..24039d17 --- /dev/null +++ b/drivers/gaudio/pwm/gaudio_play_board_template.h @@ -0,0 +1,38 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef GAUDIO_PLAY_BOARD_H +#define GAUDIO_PLAY_BOARD_H + +/* + * This routine is defined in the driver - the timer interrupt should call this routine. + * + * static void gaudio_play_pwm_timer_callbackI(void); + * + */ + +static bool gaudio_play_pwm_setup(uint32_t frequency, ArrayDataFormat format) { + /* Initialise the PWM - use a midpoint value for the initial PWM value */ + /* Initialise the timer interrupt @ frequency */ + /* Return FALSE if any parameter invalid */ +} + +static void gaudio_play_pwm_start(void) { + /* Start the PWM */ + /* Start the timer interrupt */ +} + +static void gaudio_play_pwm_stop(void) { + /* Stop the timer interrupt */ + /* Stop the PWM */ +} + +static void gaudio_play_pwm_setI(uint16_t value) { + /* Set the PWM value */ +} + +#endif /* GAUDIO_PLAY_BOARD_H */ diff --git a/drivers/gaudio/pwm/gaudio_play_config.h b/drivers/gaudio/pwm/gaudio_play_config.h new file mode 100644 index 00000000..9c65cd11 --- /dev/null +++ b/drivers/gaudio/pwm/gaudio_play_config.h @@ -0,0 +1,34 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef GAUDIO_PLAY_CONFIG_H +#define GAUDIO_PLAY_CONFIG_H + +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +/* These may need to change for your hardware. If so copy this file to your + * project directory and then alter it. + * The maximum sample frequency should be less than + * Max PWM Clock / (2 ^ Bits per sample) + * eg. For the AT91SAM7 max PWM clock = 48MHz / 2 + * For 10 bit PWM accuracy that means GAUDIO_PLAY_MAX_SAMPLE_FREQUENCY = 23,437 Hz + */ +#define GAUDIO_PLAY_MAX_SAMPLE_FREQUENCY 22000 +#define GAUDIO_PLAY_NUM_FORMATS 2 +#define GAUDIO_PLAY_FORMAT1 ARRAY_DATA_10BITUNSIGNED +#define GAUDIO_PLAY_FORMAT2 ARRAY_DATA_8BITUNSIGNED +#define GAUDIO_PLAY_NUM_CHANNELS 1 +#define GAUDIO_PLAY_CHANNEL0_IS_STEREO FALSE +#define GAUDIO_PLAY_MONO 0 + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ + +#endif /* GAUDIO_PLAY_CONFIG_H */ diff --git a/drivers/gaudio/pwm/gaudio_play_lld.c b/drivers/gaudio/pwm/gaudio_play_lld.c new file mode 100644 index 00000000..07fd14b2 --- /dev/null +++ b/drivers/gaudio/pwm/gaudio_play_lld.c @@ -0,0 +1,117 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY + +/* Include the driver defines */ +#include "src/gaudio/driver_play.h" + +/* Forward definition */ +static void gaudio_play_pwm_timer_callbackI(void); + +/* Include the board interface */ +#include "gaudio_play_board.h" + +static GDataBuffer *pplay; +static ArrayDataFormat playfmt; +static size_t playlen; +static uint8_t *pdata; + +static void gaudio_play_pwm_timer_callbackI(void) { + if (pplay) { + + // Get the next value from the current data buffer + if (gfxSampleFormatBits(playfmt) > 8) { + gaudio_play_pwm_setI(*(uint16_t *)pdata); + pdata += 2; + } else { + gaudio_play_pwm_setI(*pdata); + pdata++; + } + + // Are we done yet + if (--playlen) + return; + gaudioPlayReleaseDataBlockI(pplay); + + // Get a new data buffer + if (!(pplay = gaudioPlayGetDataBlockI())) { + // All is done + gaudioPlayDoneI(); + return; + } + + } else { + // Get a new data buffer + if (!(pplay = gaudioPlayGetDataBlockI())) + return; + } + + // Set up ready for the new buffer + playlen = pplay->len; + if (gfxSampleFormatBits(playfmt) > 8) + playlen >>= 1; + pdata = (uint8_t *)(pplay+1); +} + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) { + (void) channel; + + if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_10BITUNSIGNED) + return FALSE; + + playfmt = format; + return gaudio_play_pwm_setup(frequency, format); +} + +bool_t gaudio_play_lld_set_volume(uint8_t vol) { + (void) vol; + return FALSE; +} + +void gaudio_play_lld_start(void) { + + gfxSystemLock(); + // Get a new data buffer + if (pplay || !(pplay = gaudioPlayGetDataBlockI())) { + gfxSystemUnlock(); // Nothing to do + return; + } + + // Set up ready for the new buffer + playlen = pplay->len; + if (gfxSampleFormatBits(playfmt) > 8) + playlen >>= 1; + pdata = (uint8_t *)(pplay+1); + gfxSystemUnlock(); + + // Start the playing + gaudio_play_pwm_start(); +} + +void gaudio_play_lld_stop(void) { + // Stop everything + gaudio_play_pwm_stop(); + + // We may need to clean up the remaining buffer. + gfxSystemLock(); + if (pplay) { + gaudioPlayReleaseDataBlockI(pplay); + pplay = 0; + gaudioPlayDoneI(); + } + gfxSystemUnlock(); +} + +#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */ diff --git a/drivers/gaudio/pwm/readme.txt b/drivers/gaudio/pwm/readme.txt new file mode 100644 index 00000000..1dd3ed9a --- /dev/null +++ b/drivers/gaudio/pwm/readme.txt @@ -0,0 +1,12 @@ +This driver uses a PWM output and a timer to implement an audio play channel. + +Whilst the default config settings will probably work for your hardware, you may need to change them. +If so copy gaudio_play_config.h to your project directory and then alter it. + +The maximum sample frequency is governed primarily by the number of bits of resolution and the +maximum PWM clock rate. The maximum sample frequency should be less than... + + Max PWM Clock / (2 ^ Bits per sample) + +eg. For the AT91SAM7 max PWM clock = 48MHz / 2 + For 10 bit PWM accuracy that means GAUDIO_PLAY_MAX_SAMPLE_FREQUENCY = 23,437 Hz