aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gaudio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gaudio')
-rw-r--r--drivers/gaudio/Win32/gaudio_play_config.h34
-rw-r--r--drivers/gaudio/Win32/gaudio_play_lld.c9
-rw-r--r--drivers/gaudio/Win32/gaudio_record_config.h34
-rw-r--r--drivers/gaudio/Win32/gaudio_record_lld.c11
-rw-r--r--drivers/gaudio/gadc/driver.mk4
-rw-r--r--drivers/gaudio/gadc/gaudio_record_board_template.h29
-rw-r--r--drivers/gaudio/gadc/gaudio_record_config.h39
-rw-r--r--drivers/gaudio/gadc/gaudio_record_lld.c43
-rw-r--r--drivers/gaudio/pwm/driver.mk5
-rw-r--r--drivers/gaudio/pwm/gaudio_play_board_template.h38
-rw-r--r--drivers/gaudio/pwm/gaudio_play_config.h34
-rw-r--r--drivers/gaudio/pwm/gaudio_play_lld.c117
-rw-r--r--drivers/gaudio/pwm/readme.txt12
-rw-r--r--drivers/gaudio/vs1053/driver.mk7
-rw-r--r--drivers/gaudio/vs1053/gaudio_play_board_template.h71
-rw-r--r--drivers/gaudio/vs1053/gaudio_play_config.h29
-rw-r--r--drivers/gaudio/vs1053/gaudio_play_lld.c348
-rw-r--r--drivers/gaudio/vs1053/readme.txt4
-rw-r--r--drivers/gaudio/vs1053/vs1053.h101
19 files changed, 799 insertions, 170 deletions
diff --git a/drivers/gaudio/Win32/gaudio_play_config.h b/drivers/gaudio/Win32/gaudio_play_config.h
index 4013e91f..c4830010 100644
--- a/drivers/gaudio/Win32/gaudio_play_config.h
+++ b/drivers/gaudio/Win32/gaudio_play_config.h
@@ -5,14 +5,6 @@
* http://ugfx.org/license.html
*/
-/**
- * @file drivers/gaudio/Win32/gaudio_play_config.h
- * @brief GAUDIO Play Driver config file.
- *
- * @addtogroup GAUDIO
- * @{
- */
-
#ifndef GAUDIO_PLAY_CONFIG_H
#define GAUDIO_PLAY_CONFIG_H
@@ -22,42 +14,16 @@
/* Driver hardware support. */
/*===========================================================================*/
-/**
- * @brief The maximum sample frequency supported by this audio device
- */
#define GAUDIO_PLAY_MAX_SAMPLE_FREQUENCY 44100
-
-/**
- * @brief The number of audio formats supported by this driver
- */
#define GAUDIO_PLAY_NUM_FORMATS 2
-
-/**
- * @brief The available audio sample formats in order of preference
- */
#define GAUDIO_PLAY_FORMAT1 ARRAY_DATA_16BITSIGNED
#define GAUDIO_PLAY_FORMAT2 ARRAY_DATA_8BITUNSIGNED
-
-/**
- * @brief The number of audio channels supported by this driver
- */
#define GAUDIO_PLAY_NUM_CHANNELS 2
-
-/**
- * @brief Whether each channel is mono or stereo
- */
#define GAUDIO_PLAY_CHANNEL0_IS_STEREO FALSE
#define GAUDIO_PLAY_CHANNEL1_IS_STEREO TRUE
-
-/**
- * @brief The list of audio channel names and their uses
- * @{
- */
#define GAUDIO_PLAY_MONO 0
#define GAUDIO_PLAY_STEREO 1
-/** @} */
#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */
#endif /* GAUDIO_PLAY_CONFIG_H */
-/** @} */
diff --git a/drivers/gaudio/Win32/gaudio_play_lld.c b/drivers/gaudio/Win32/gaudio_play_lld.c
index 6b4f2dab..c0adf03e 100644
--- a/drivers/gaudio/Win32/gaudio_play_lld.c
+++ b/drivers/gaudio/Win32/gaudio_play_lld.c
@@ -5,11 +5,6 @@
* http://ugfx.org/license.html
*/
-/**
- * @file drivers/gaudio/Win32/gaudio_play_lld.c
- * @brief GAUDIO - Play Driver file for Win32.
- */
-
#include "gfx.h"
#if GFX_USE_GAUDIO && GAUDIO_NEED_PLAY
@@ -47,7 +42,7 @@ static DWORD threadID;
*************************************************************************/
static bool_t senddata(WAVEHDR *pwh) {
- GAudioData *paud;
+ GDataBuffer *paud;
// Get the next data block to send
gfxSystemLock();
@@ -94,7 +89,7 @@ static DWORD WINAPI waveProc(LPVOID arg) {
// Give the buffer back to the Audio Free List
gfxSystemLock();
- gaudioPlayReleaseDataBlockI((GAudioData *)pwh->dwUser);
+ gaudioPlayReleaseDataBlockI((GDataBuffer *)pwh->dwUser);
gfxSystemUnlock();
pwh->lpData = 0;
nQueuedBuffers--;
diff --git a/drivers/gaudio/Win32/gaudio_record_config.h b/drivers/gaudio/Win32/gaudio_record_config.h
index 4d952e1d..5897212b 100644
--- a/drivers/gaudio/Win32/gaudio_record_config.h
+++ b/drivers/gaudio/Win32/gaudio_record_config.h
@@ -5,14 +5,6 @@
* http://ugfx.org/license.html
*/
-/**
- * @file drivers/gaudio/Win32/gaudio_record_config.h
- * @brief GAUDIO Record Driver config file.
- *
- * @addtogroup GAUDIO
- * @{
- */
-
#ifndef GAUDIO_RECORD_CONFIG_H
#define GAUDIO_RECORD_CONFIG_H
@@ -22,42 +14,16 @@
/* Driver hardware support. */
/*===========================================================================*/
-/**
- * @brief The maximum sample frequency supported by this audio device
- */
#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY 44100
-
-/**
- * @brief The number of audio formats supported by this driver
- */
#define GAUDIO_RECORD_NUM_FORMATS 2
-
-/**
- * @brief The available audio sample formats in order of preference
- */
#define GAUDIO_RECORD_FORMAT1 ARRAY_DATA_16BITSIGNED
#define GAUDIO_RECORD_FORMAT2 ARRAY_DATA_8BITUNSIGNED
-
-/**
- * @brief The number of audio channels supported by this driver
- */
#define GAUDIO_RECORD_NUM_CHANNELS 2
-
-/**
- * @brief Whether each channel is mono or stereo
- */
#define GAUDIO_RECORD_CHANNEL0_IS_STEREO FALSE
#define GAUDIO_RECORD_CHANNEL1_IS_STEREO TRUE
-
-/**
- * @brief The list of audio channels and their uses
- * @{
- */
#define GAUDIO_RECORD_MONO 0
#define GAUDIO_RECORD_STEREO 1
-/** @} */
#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */
#endif /* GAUDIO_RECORD_CONFIG_H */
-/** @} */
diff --git a/drivers/gaudio/Win32/gaudio_record_lld.c b/drivers/gaudio/Win32/gaudio_record_lld.c
index 259707e3..c9ac8187 100644
--- a/drivers/gaudio/Win32/gaudio_record_lld.c
+++ b/drivers/gaudio/Win32/gaudio_record_lld.c
@@ -5,11 +5,6 @@
* http://ugfx.org/license.html
*/
-/**
- * @file drivers/gaudio/Win32/gaudio_record_lld.c
- * @brief GAUDIO - Record Driver file for Win32.
- */
-
#include "gfx.h"
#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD
@@ -47,7 +42,7 @@ static DWORD threadID;
*************************************************************************/
static bool_t getbuffer(WAVEHDR *pwh) {
- GAudioData *paud;
+ GDataBuffer *paud;
// Get the next data block to send
gfxSystemLock();
@@ -81,7 +76,7 @@ static bool_t getbuffer(WAVEHDR *pwh) {
static DWORD WINAPI waveProc(LPVOID arg) {
MSG msg;
WAVEHDR *pwh;
- GAudioData *paud;
+ GDataBuffer *paud;
(void) arg;
while (GetMessage(&msg, 0, 0, 0)) {
@@ -93,7 +88,7 @@ static DWORD WINAPI waveProc(LPVOID arg) {
waveInUnprepareHeader(ah, pwh, sizeof(WAVEHDR));
// Save the buffer in the audio record list
- paud = (GAudioData *)pwh->dwUser;
+ paud = (GDataBuffer *)pwh->dwUser;
paud->len = pwh->dwBytesRecorded;
gfxSystemLock();
gaudioRecordSaveDataBlockI(paud);
diff --git a/drivers/gaudio/gadc/driver.mk b/drivers/gaudio/gadc/driver.mk
index 4d79da25..b5a2768a 100644
--- a/drivers/gaudio/gadc/driver.mk
+++ b/drivers/gaudio/gadc/driver.mk
@@ -3,3 +3,7 @@ GFXSRC += $(GFXLIB)/drivers/gaudio/gadc/gaudio_record_lld.c
# Required include directories
GFXINC += $(GFXLIB)/drivers/gaudio/gadc
+
+# Make sure the GADC sub-system is turned on
+GFXDEFS += -DGFX_USE_GADC=GAUDIO_NEED_RECORD
+
diff --git a/drivers/gaudio/gadc/gaudio_record_board_template.h b/drivers/gaudio/gadc/gaudio_record_board_template.h
index 26e87d88..42c15205 100644
--- a/drivers/gaudio/gadc/gaudio_record_board_template.h
+++ b/drivers/gaudio/gadc/gaudio_record_board_template.h
@@ -5,14 +5,6 @@
* http://ugfx.org/license.html
*/
-/**
- * @file drivers/gaudio/gadc/gaudio_record_board_template.h
- * @brief GAUDIO Record Driver board config board file
- *
- * @addtogroup GAUDIO
- * @{
- */
-
#ifndef _GAUDIO_RECORD_BOARD_H
#define _GAUDIO_RECORD_BOARD_H
@@ -20,31 +12,16 @@
/* Audio inputs on this board */
/*===========================================================================*/
-/**
- * @brief The number of audio channels supported by this driver
- * @note This is an example
- */
#define GAUDIO_RECORD_NUM_CHANNELS 1
-/**
- * @brief The list of audio channels and their uses
- * @note This is an example
- * @{
- */
+#define GAUDIO_RECORD_CHANNEL0_IS_STEREO FALSE
+
#define GAUDIO_RECORD_MICROPHONE 0
-/** @} */
-/**
- * @brief The audio channel to GADC physical device assignment
- * @note This is an example
- * @{
- */
#ifdef GAUDIO_RECORD_LLD_IMPLEMENTATION
- static uint32_t gaudin_lld_physdevs[GAUDIO_RECORD_NUM_CHANNELS] = {
+ static uint32_t gaudio_gadc_physdevs[GAUDIO_RECORD_NUM_CHANNELS] = {
GADC_PHYSDEV_MICROPHONE,
};
#endif
-/** @} */
#endif /* _GAUDIO_RECORD_BOARD_H */
-/** @} */
diff --git a/drivers/gaudio/gadc/gaudio_record_config.h b/drivers/gaudio/gadc/gaudio_record_config.h
index 22d8750f..345625ff 100644
--- a/drivers/gaudio/gadc/gaudio_record_config.h
+++ b/drivers/gaudio/gadc/gaudio_record_config.h
@@ -5,14 +5,6 @@
* http://ugfx.org/license.html
*/
-/**
- * @file drivers/gaudio/gadc/gaudio_record_config.h
- * @brief GAUDIN Record Driver config file.
- *
- * @addtogroup GAUDIO
- * @{
- */
-
#ifndef GAUDIO_RECORD_CONFIG_H
#define GAUDIO_RECORD_CONFIG_H
@@ -22,38 +14,13 @@
/* Driver hardware support. */
/*===========================================================================*/
-/**
- * @brief The audio record sample type
- * @details For this driver it matches the cpu sample type
- */
-typedef adcsample_t audio_record_sample_t;
-
-/**
- * @brief The maximum sample frequency supported by this audio device
- * @details For this driver it matches the GADC maximum high speed sample rate
- */
-#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY GADC_MAX_HIGH_SPEED_SAMPLERATE
+#define GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY GADC_MAX_HIGH_SPEED_SAMPLERATE
+#define GAUDIO_RECORD_NUM_FORMATS 1
+#define GAUDIO_RECORD_FORMAT1 GADC_SAMPLE_FORMAT
-/**
- * @brief The number of bits in a sample
- * @details For this driver it matches the cpu sample bits
- */
-#define GAUDIO_RECORD_BITS_PER_SAMPLE GADC_BITS_PER_SAMPLE
-
-/**
- * @brief The format of an audio sample
- * @details For this driver it matches the cpu sample format
- */
-#define GAUDIO_RECORD_SAMPLE_FORMAT GADC_SAMPLE_FORMAT
-
-/**
- * For the GAUDIO driver that uses GADC - all the remaining config definitions are specific
- * to the board.
- */
/* Include the user supplied board definitions */
#include "gaudio_record_board.h"
#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */
#endif /* GAUDIO_RECORD_CONFIG_H */
-/** @} */
diff --git a/drivers/gaudio/gadc/gaudio_record_lld.c b/drivers/gaudio/gadc/gaudio_record_lld.c
index ee994dc1..1d70a259 100644
--- a/drivers/gaudio/gadc/gaudio_record_lld.c
+++ b/drivers/gaudio/gadc/gaudio_record_lld.c
@@ -5,22 +5,7 @@
* http://ugfx.org/license.html
*/
-/**
- * @file drivers/gaudio/gadc/gaudio_record_lld.c
- * @brief GAUDIO - Record Driver file for using the cpu ADC (via GADC).
- *
- * @addtogroup GAUDIO
- *
- * @{
- */
-
-/**
- * We are now implementing the driver - pull in our channel table
- * from the board definitions.
- */
#define GAUDIO_RECORD_IMPLEMENTATION
-
-
#include "gfx.h"
#if GFX_USE_GAUDIO && GAUDIO_NEED_RECORD
@@ -33,30 +18,38 @@
/* Include the driver defines */
#include "src/gaudio/driver_record.h"
+static void gadcCallbackI(void) {
+ GDataBuffer *pd;
+
+ pd = gadcHighSpeedGetDataI();
+ if (pd)
+ gaudioRecordSaveDataBlockI(pd);
+}
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
-void gaudin_lld_init(const gaudin_params *paud) {
+bool_t gaudio_record_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
+ /* Check the parameters */
+ if (channel >= GAUDIO_RECORD_NUM_CHANNELS || frequency > GAUDIO_RECORD_MAX_SAMPLE_FREQUENCY || format != GAUDIO_RECORD_FORMAT1)
+ return FALSE;
+
/* Setup the high speed GADC */
- gadcHighSpeedInit(gaudin_lld_physdevs[paud->channel], paud->frequency, paud->buffer, paud->bufcount, paud->samplesPerEvent);
+ gadcHighSpeedInit(gaudio_gadc_physdevs[channel], frequency);
/* Register ourselves for ISR callbacks */
- gadcHighSpeedSetISRCallback(GAUDIN_ISR_CompleteI);
+ gadcHighSpeedSetISRCallback(gadcCallbackI);
- /**
- * The gadc driver handles any errors for us by restarting the transaction so there is
- * no need for us to setup anything for GAUDIN_ISR_ErrorI()
- */
+ return TRUE;
}
-void gaudin_lld_start(void) {
+void gaudio_record_lld_start(void) {
gadcHighSpeedStart();
}
-void gaudin_lld_stop(void) {
+void gaudio_record_lld_stop(void) {
gadcHighSpeedStop();
}
#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_RECORD */
-/** @} */
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
diff --git a/drivers/gaudio/vs1053/driver.mk b/drivers/gaudio/vs1053/driver.mk
new file mode 100644
index 00000000..d0419c80
--- /dev/null
+++ b/drivers/gaudio/vs1053/driver.mk
@@ -0,0 +1,7 @@
+# List the required driver.
+GFXSRC += $(GFXLIB)/drivers/gaudio/vs1053/gaudio_play_lld.c
+
+# Required include directories
+GFXINC += $(GFXLIB)/drivers/gaudio/vs1053
+
+GFXDEFS += -DGFX_USE_GTIMER=TRUE
diff --git a/drivers/gaudio/vs1053/gaudio_play_board_template.h b/drivers/gaudio/vs1053/gaudio_play_board_template.h
new file mode 100644
index 00000000..d6125bbc
--- /dev/null
+++ b/drivers/gaudio/vs1053/gaudio_play_board_template.h
@@ -0,0 +1,71 @@
+/*
+ * 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
+
+// Initialise the board
+static void board_init(void) {
+
+}
+
+// Chip is initialised enough so we can talk fast to it
+static void board_init_end(void) {
+
+}
+
+// Reset the board
+static void board_reset(void) {
+
+}
+
+// Returns the state of the dreq pin
+static bool board_dreq(void) {
+
+}
+
+// Start a command write
+static void board_startcmdwrite(void) {
+
+}
+
+// End a command write
+static void board_endcmdwrite(void) {
+
+}
+
+// Start a command read
+static void board_startcmdread(void) {
+
+}
+
+// End a command read
+static void board_endcmdread(void) {
+
+}
+
+// Start a data write
+static void board_startdatawrite(void) {
+
+}
+
+// End a data write
+static void board_enddatawrite(void) {
+
+}
+
+// Write data to the SPI port
+static void board_spiwrite(const uint8_t *buf, unsigned len) {
+
+}
+
+// Read data from the SPI port
+static void board_spiread(uint8_t *buf, unsigned len) {
+
+}
+
+#endif /* GAUDIO_PLAY_BOARD_H */
diff --git a/drivers/gaudio/vs1053/gaudio_play_config.h b/drivers/gaudio/vs1053/gaudio_play_config.h
new file mode 100644
index 00000000..bd2af503
--- /dev/null
+++ b/drivers/gaudio/vs1053/gaudio_play_config.h
@@ -0,0 +1,29 @@
+/*
+ * 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. */
+/*===========================================================================*/
+
+#define GAUDIO_PLAY_MAX_SAMPLE_FREQUENCY 48000
+#define GAUDIO_PLAY_NUM_FORMATS 2
+#define GAUDIO_PLAY_FORMAT1 ARRAY_DATA_16BITSIGNED
+#define GAUDIO_PLAY_FORMAT2 ARRAY_DATA_8BITUNSIGNED
+#define GAUDIO_PLAY_NUM_CHANNELS 2
+#define GAUDIO_PLAY_CHANNEL0_IS_STEREO FALSE
+#define GAUDIO_PLAY_CHANNEL1_IS_STEREO TRUE
+#define GAUDIO_PLAY_MONO 0
+#define GAUDIO_PLAY_STEREO 1
+
+#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */
+
+#endif /* GAUDIO_PLAY_CONFIG_H */
diff --git a/drivers/gaudio/vs1053/gaudio_play_lld.c b/drivers/gaudio/vs1053/gaudio_play_lld.c
new file mode 100644
index 00000000..9e77e383
--- /dev/null
+++ b/drivers/gaudio/vs1053/gaudio_play_lld.c
@@ -0,0 +1,348 @@
+/*
+ * 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"
+
+/* Include the vs1053 registers */
+#include "drivers/gaudio/vs1053/vs1053.h"
+
+/* Include the board interface */
+#include "gaudio_play_board.h"
+
+// Override-able parameters
+#ifndef VS1053_CLK
+ #define VS1053_CLK 12288000
+#endif
+#ifndef VS1053_FIRMWARE_PATCH
+ #define VS1053_FIRMWARE_PATCH FALSE
+#endif
+
+// Load the patch file if desired. New format patches only.
+#if VS1053_FIRMWARE_PATCH
+ #define SKIP_PLUGIN_VARNAME
+ static const uint16_t plugin[] = { /* Compressed plugin */
+ #include "vs1053_patch.plg"
+ };
+#endif
+
+// Set various stuff based on the clock
+#if VS1053_CLK >= 16192000
+ #define SCI_MODE_STARTUP (SCI_MODE_DEFAULTS|SM_CLK_RANGE)
+ #define VS1053_CLKI (VS1053_CLK/2)
+#else
+ #define SCI_MODE_STARTUP (SCI_MODE_DEFAULTS)
+ #define VS1053_CLKI (VS1053_CLK)
+#endif
+#if VS1053_CLKI > 13000000 || VS1053_CLKI < 12000000
+ #error "GAUDIO(vs1053): VS1053_CLK is out of range"
+#endif
+#if VS1053_CLKI == 12288000
+ #define SC_FREQ_ADJUST 0x0000
+#else
+ #define SC_FREQ_ADJUST ((VS1053_CLKI-8000000)/4000)
+#endif
+#define VS1053_MAX_SAMPLE_RATE (VS1053_CLKI/256)
+#if VS1053_CLKI > 1228800
+ #define SC_CLOCK_MODE (SC_MULT_3|SC_ADD_1|SC_FREQ_ADJUST)
+#else
+ #define SC_CLOCK_MODE (SC_MULT_3_5|SC_ADD_1|SC_FREQ_ADJUST)
+#endif
+
+// Our static variables
+static bool_t vs1053_isinit;
+static GTimer playTimer;
+
+// Some common macro's
+#define waitforready() while(!board_dreq()) gfxSleepMilliseconds(5)
+
+static void cmd_write(uint16_t addr, uint16_t data) {
+ char buf[4];
+ buf[0] = 2;
+ buf[1] = (char)addr;
+ buf[2] = (char)(data >> 8);
+ buf[3] = (char)data;
+
+ waitforready();
+ board_startcmdwrite();
+ board_spiwrite(buf, 4);
+ board_endcmdwrite();
+}
+
+#if VS1053_CLK > 12288000
+ static inline void cmd_writenodreq(uint16_t addr, uint16_t data) {
+ uint8_t buf[4];
+
+ // This is the same as cmd_write() except for it doesn't wait for dreq first
+ buf[0] = 2;
+ buf[1] = (uint8_t)addr;
+ buf[2] = (uint8_t)(data >> 8);
+ buf[3] = (uint8_t)data;
+
+ board_startcmdwrite();
+ board_spiwrite(buf, 4);
+ board_endcmdwrite();
+ }
+#endif
+
+static uint16_t cmd_read(uint16_t addr) {
+ uint8_t buf[2];
+
+ buf[0] = 3;
+ buf[1] = (char)addr;
+
+ board_startcmdread();
+ board_spiwrite(buf, 2);
+ board_spiread(buf, 2);
+ board_endcmdread();
+ return (((uint16_t)buf[0])<<8)|buf[1];
+}
+
+static void data_write(const uint8_t *data, unsigned len) {
+ board_startdatawrite();
+ board_spiwrite(data, len);
+ board_enddatawrite();
+}
+
+#if VS1053_FIRMWARE_PATCH
+ static void LoadUserCode(void) {
+ int i;
+ uint16_t addr, n, val;
+
+ for(i=0; i<sizeof(plugin)/sizeof(plugin[0]);) {
+ addr = plugin[i++];
+ n = plugin[i++];
+ if (n & 0x8000U) { /* RLE run, replicate n samples */
+ n &= 0x7FFF;
+ val = plugin[i++];
+ while (n--)
+ cmd_write(addr, val);
+ } else { /* Copy run, copy n samples */
+ while (n--)
+ cmd_write(addr, plugin[i++]);
+ }
+ }
+ }
+#endif
+
+static void vs1053_hard_reset(void) {
+ gtimerInit(&playTimer);
+
+ board_init();
+ board_reset();
+
+ #if VS1053_CLK > 12288000
+ cmd_writenodreq(SCI_MODE, SCI_MODE_STARTUP); // Set super-clock before dreq
+ #endif
+
+ // Set up registers
+ cmd_write(SCI_MODE, SCI_MODE_STARTUP); // Set mode
+ cmd_write(SCI_CLOCKF, SC_CLOCK_MODE); // Set clocks
+ board_init_end(); // Clocks are now set up
+ cmd_write(SCI_BASS, 0x0000); // No treble or bass boost
+ cmd_write(SCI_VOL, VOL_MAX); // Maximum volume
+
+ // Load any firmware
+ #if VS1053_FIRMWARE_PATCH
+ LoadUserCode();
+
+ // Reset mode just in case
+ cmd_write(SCI_MODE, SCI_MODE_STARTUP);
+ #endif
+}
+
+static void vs1053_soft_reset(void) {
+ cmd_write(SCI_MODE, cmd_read(SCI_MODE)|SM_RESET);
+ gfxSleepMilliseconds(1); // Wait for at least 2uS
+ waitforready();
+
+ // Reload any firmware
+ #if VS1053_FIRMWARE_PATCH
+ LoadUserCode();
+
+ // Reset mode just in case
+ cmd_write(SCI_MODE, SCI_MODE_STARTUP);
+ #endif
+}
+
+static uint16_t vs1053_getendbyte(void) {
+ cmd_write(SCI_WRAMADDR, WRAMADDR_EXTRAPARAMS+4);
+ return cmd_read(SCI_WRAM);
+}
+
+static GTimer playTimer;
+static GDataBuffer *pplay;
+static size_t playlen;
+static uint8_t *pdata;
+
+static void FeedData(void *param) {
+ unsigned len;
+ (void) param;
+
+ // While there is data space
+ while (!board_dreq()) {
+
+ // Send up to 32 bytes
+ len = playlen;
+ if (len > 32) len = 32;
+ data_write(pdata, len);
+ pdata += len;
+ playlen -= len;
+
+ // Have we finished the buffer
+ while (!playlen) {
+ gfxSystemLock();
+ gaudioPlayReleaseDataBlockI(pplay);
+
+ // Get a new data buffer
+ if (!(pplay = gaudioPlayGetDataBlockI())) {
+ // We should really only do the play-done when the audio
+ // has really finished playing. Unfortunately there seems
+ // to be no documented way of determining this.
+ gaudioPlayDoneI();
+ gfxSystemUnlock();
+ gtimerStop(&playTimer);
+ return;
+ }
+
+ // Set up ready for the new buffer
+ playlen = pplay->len;
+ pdata = (uint8_t *)(pplay+1);
+ gfxSystemUnlock();
+ }
+ }
+}
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+bool_t gaudio_play_lld_init(uint16_t channel, uint32_t frequency, ArrayDataFormat format) {
+ uint32_t brate;
+ uint32_t bps;
+ uint8_t buf[4];
+ static const uint8_t hdr1[] = {
+ 'R', 'I', 'F', 'F',
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 'W', 'A', 'V', 'E',
+ 'f', 'm', 't', ' ',
+ 16, 0, 0, 0,
+ 0x01, 0x00,
+ };
+ static const uint8_t hdr2[] = {
+ 'd', 'a', 't', 'a',
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ };
+
+ if (format != ARRAY_DATA_8BITUNSIGNED && format != ARRAY_DATA_16BITSIGNED)
+ return FALSE;
+ if (frequency > VS1053_MAX_SAMPLE_RATE)
+ return FALSE;
+
+ // Reset the chip if needed
+ if (!vs1053_isinit) {
+ vs1053_hard_reset();
+ vs1053_isinit = TRUE;
+ }
+
+ // Setup
+ bps = (gfxSampleFormatBits(format)+7)/8;
+ if (channel == GAUDIO_PLAY_STEREO)
+ bps *= 2;
+ brate = frequency * bps;
+
+ // Write the RIFF header
+ waitforready();
+ data_write(hdr1, sizeof(hdr1));
+ buf[0] = channel == GAUDIO_PLAY_STEREO ? 2 : 1; buf[1] = 0; data_write(buf, 2);
+ buf[0] = frequency; buf[1] = frequency>>8; buf[2] = frequency>>16; buf[3] = frequency>>24; data_write(buf, 4);
+ buf[0] = brate; buf[1] = brate>>8; buf[2] = brate>>16; buf[3] = brate>>24; data_write(buf, 4);
+ waitforready(); // 32 bytes max before checking
+ buf[0] = bps; buf[1] = 0; data_write(buf, 2);
+ buf[0] = gfxSampleFormatBits(format); buf[1] = 0; data_write(buf, 2);
+ data_write(hdr2, sizeof(hdr2));
+ return TRUE;
+}
+
+bool_t gaudio_play_lld_set_volume(uint8_t vol) {
+ // Volume is 0xFE -> 0x00. Adjust vol to match
+ vol = ~vol;
+ if (vol == 0xFF) vol = 0xFE;
+
+ cmd_write(SCI_VOL, ((uint16_t)vol) << 8 | vol);
+ return TRUE;
+}
+
+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;
+ pdata = (uint8_t *)(pplay+1);
+ gfxSystemUnlock();
+
+ // Start the playing by starting the timer and executing FeedData immediately just to get things started
+ // We really should set the timer to be equivalent to half the available data but that is just too hard to calculate.
+ gtimerStart(&playTimer, FeedData, 0, TRUE, 5);
+ FeedData(0);
+}
+
+void gaudio_play_lld_stop(void) {
+ uint8_t ch;
+ unsigned i;
+
+ // Stop the timer interrupt
+ gtimerStop(&playTimer);
+
+ // We may need to clean up the remaining buffer.
+ gfxSystemLock();
+ if (pplay) {
+ gaudioPlayReleaseDataBlockI(pplay);
+ pplay = 0;
+ gaudioPlayDoneI();
+ }
+ gfxSystemUnlock();
+
+ // Set CANCEL
+ cmd_write(SCI_MODE, cmd_read(SCI_MODE)|SM_CANCEL);
+
+ // Write up to 2048 bytes of data
+ ch = 0;
+ for(i = 0; i < 2048; i++) {
+ if (!(i & 0x1F)) {
+ waitforready();
+ if (!(cmd_read(SCI_MODE) & SM_CANCEL))
+ break;
+ }
+ data_write(&ch, 1);
+ }
+
+ // Make sure the cancel worked
+ waitforready();
+ if ((cmd_read(SCI_MODE) & SM_CANCEL))
+ vs1053_soft_reset();
+
+ // Send the terminating data
+ ch = vs1053_getendbyte();
+ for(i = 0; i < 2052; i++) {
+ if (!(i & 0x1F))
+ waitforready();
+ data_write(&ch, 1);
+ }
+}
+
+#endif /* GFX_USE_GAUDIO && GAUDIO_NEED_PLAY */
diff --git a/drivers/gaudio/vs1053/readme.txt b/drivers/gaudio/vs1053/readme.txt
new file mode 100644
index 00000000..6e99e56f
--- /dev/null
+++ b/drivers/gaudio/vs1053/readme.txt
@@ -0,0 +1,4 @@
+This chip supports playing in many formats including MP3 etc.
+For this driver however we only support PCM in 8 bit unisgned and 16 bit signed formats.
+
+Requires GFX_USE_GTIMER \ No newline at end of file
diff --git a/drivers/gaudio/vs1053/vs1053.h b/drivers/gaudio/vs1053/vs1053.h
new file mode 100644
index 00000000..1ae613be
--- /dev/null
+++ b/drivers/gaudio/vs1053/vs1053.h
@@ -0,0 +1,101 @@
+/*
+ * 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 _VS1053_H
+#define _VS1053_H
+
+// Registers
+#define SCI_MODE 0x00
+ #define SM_DIFF 0x0001
+ #define SM_LAYER12 0x0002
+ #define SM_RESET 0x0004
+ #define SM_CANCEL 0x0008
+ #define SM_EARSPEAKER_LO 0x0010
+ #define SM_TESTS 0x0020
+ #define SM_STREAM 0x0040
+ #define SM_EARSPEAKER_HI 0x0080
+ #define SM_DACT 0x0100
+ #define SM_SDIORD 0x0200
+ #define SM_SDISHARE 0x0400
+ #define SM_SDINEW 0x0800
+ #define SM_ADPCM 0x1000
+ #define SM_LINE1 0x4000
+ #define SM_CLK_RANGE 0x8000
+ #define SCI_MODE_DEFAULTS (SM_LINE1|SM_SDINEW)
+#define SCI_STATUS 0x01
+ #define SS_DO_NOT_JUMP 0x8000
+ #define SS_SWING_MASK 0x7000
+ #define SS_SWING_SHIFT 12
+ #define SS_VCM_OVERLOAD 0x0800
+ #define SS_VCM_DISABLE 0x0400
+ #define SS_VER_MASK 0x00F0
+ #define SS_VER_SHIFT 4
+ #define SS_APDOWN2 0x0008
+ #define SS_APDOWN1 0x0004
+ #define SS_SS_AD_CLOCK 0x0002
+ #define SS_REFERENCE_SEL 0x0001
+#define SCI_BASS 0x02
+ #define ST_AMPLITUDE_MASK 0xF000
+ #define ST_AMPLITUDE_SHIFT 12
+ #define ST_FREQLIMIT_MASK 0x0F00
+ #define ST_FREQLIMIT_SHIFT 8
+ #define SB_AMPLITUDE_MASK 0x00F0
+ #define SB_AMPLITUDE_SHIFT 4
+ #define SB_FREQLIMIT_MASK 0x000F
+ #define SB_FREQLIMIT_SHIFT 0
+#define SCI_CLOCKF 0x03
+ #define SC_MULT_1 0x0000
+ #define SC_MULT_2 0x2000
+ #define SC_MULT_2_5 0x4000
+ #define SC_MULT_3 0x6000
+ #define SC_MULT_3_5 0x8000
+ #define SC_MULT_4 0xa000
+ #define SC_MULT_4_5 0xc000
+ #define SC_MULT_5 0xe000
+ #define SC_ADD_NONE 0x0000
+ #define SC_ADD_1 0x0800
+ #define SC_ADD_1_5 0x1000
+ #define SC_ADD_2 0x1800
+ #define SC_FREQ_MASK 0x07FF
+#define SCI_DECODE_TIME 0x04
+#define SCI_AUDATA 0x05
+ #define SR_RATE_MASK 0xFFFE
+ #define SR_IS_STEREO 0x0001
+#define SCI_WRAM 0x06
+#define SCI_WRAMADDR 0x07
+ #define WRAMADDR_XDATA 0x1800
+ #define WRAMADDR_YDATA 0x5800
+ #define WRAMADDR_INSTR 0x8040
+ #define WRAMADDR_IO 0xC000
+ #define WRAMADDR_EXTRAPARAMS 0x1E02
+#define SCI_HDAT0 0x08
+#define SCI_HDAT1 0x09
+ #define HD_FMT_NONE 0x0000
+ #define HD_FMT_WAV 0x7665
+ #define HD_FMT_AAC_ADTS 0x4154
+ #define HD_FMT_AAC_ADIF 0x4144
+ #define HD_FMT_AAC_M4A 0x4D34
+ #define HD_FMT_WMA 0x574D
+ #define HD_FMT_MIDI 0x4D54
+ #define HD_FMT_OGG 0x4F67
+ #define HD_FMT_MP3_MIN 0xFFE0
+ #define HD_FMT_MP3_MAX 0xFFFF
+#define SCI_AIADDR 0x0A
+#define SCI_VOL 0x0B
+ #define VOL_LEFT_MASK 0xFF00
+ #define VOL_LEFT_SHIFT 8
+ #define VOL_RIGHT_MASK 0x00FF
+ #define VOL_RIGHT_SHIFT 0
+ #define VOL_POWERDOWN 0xFFFF
+ #define VOL_MAX 0x0000
+ #define VOL_MIN 0xFEFE
+#define SCI_AICTRL0 0x0C
+#define SCI_AICTRL1 0x0D
+#define SCI_AICTRL2 0x0E
+#define SCI_AICTRL3 0x0F
+
+#endif /* _VS1053_H */