New PWM audio driver for audio output using a digital pin on a CPU

This commit is contained in:
inmarket 2014-03-30 19:10:31 +10:00
parent c16cb15ce9
commit 04f03ea71d
5 changed files with 206 additions and 0 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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