From 6ee8b005ae3ee2bc48ea6ac972b0d3b2a2949608 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Fri, 1 Mar 2013 09:04:52 +1000 Subject: [PATCH] GAUDIN implemented with GADC driver --- demos/modules/gaudin/gfxconf.h | 105 ++++++ demos/modules/gaudin/gwinosc.c | 190 ++++++++++ demos/modules/gaudin/gwinosc.h | 95 +++++ demos/modules/gaudin/main.c | 67 ++++ demos/modules/gaudin/results_264x264.jpg | Bin 0 -> 19614 bytes drivers/gadc/AT91SAM7/gadc_lld_config.h | 7 +- drivers/gaudin/gadc/gaudin_lld.c | 76 ++++ drivers/gaudin/gadc/gaudin_lld.mk | 5 + .../gadc/gaudin_lld_board_olimexsam7ex256.h | 60 +++ drivers/gaudin/gadc/gaudin_lld_config.h | 79 ++++ include/gadc/gadc.h | 34 +- include/gaudin/gaudin.h | 350 +++++++++--------- include/gaudin/lld/gaudin_lld.h | 105 ++++++ include/gfx.h | 340 ++++++++--------- include/gfx_rules.h | 11 +- include/gmisc/gmisc.h | 214 +++++------ src/gadc/gadc.c | 11 + src/gaudin/gaudin.c | 196 ++++++++-- 18 files changed, 1449 insertions(+), 496 deletions(-) create mode 100644 demos/modules/gaudin/gfxconf.h create mode 100644 demos/modules/gaudin/gwinosc.c create mode 100644 demos/modules/gaudin/gwinosc.h create mode 100644 demos/modules/gaudin/main.c create mode 100644 demos/modules/gaudin/results_264x264.jpg create mode 100644 drivers/gaudin/gadc/gaudin_lld.c create mode 100644 drivers/gaudin/gadc/gaudin_lld.mk create mode 100644 drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h create mode 100644 drivers/gaudin/gadc/gaudin_lld_config.h create mode 100644 include/gaudin/lld/gaudin_lld.h diff --git a/demos/modules/gaudin/gfxconf.h b/demos/modules/gaudin/gfxconf.h new file mode 100644 index 00000000..4222acb4 --- /dev/null +++ b/demos/modules/gaudin/gfxconf.h @@ -0,0 +1,105 @@ +/** + * This file has a different license to the rest of the GFX system. + * You can copy, modify and distribute this file as you see fit. + * You do not need to publish your source modifications to this file. + * The only thing you are not permitted to do is to relicense it + * under a different license. + */ + +/** + * Copy this file into your project directory and rename it as gfxconf.h + * Edit your copy to turn on the GFX features you want to use. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* GFX sub-systems to turn on */ +#define GFX_USE_GDISP TRUE +#define GFX_USE_TDISP FALSE +#define GFX_USE_GWIN TRUE +#define GFX_USE_GEVENT FALSE +#define GFX_USE_GTIMER TRUE +#define GFX_USE_GINPUT FALSE +#define GFX_USE_GADC TRUE +#define GFX_USE_GAUDIN TRUE +#define GFX_USE_GAUDOUT FALSE +#define GFX_USE_GMISC FALSE + +/* Features for the GDISP sub-system. */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT FALSE +#define GDISP_NEED_CIRCLE FALSE +#define GDISP_NEED_ELLIPSE FALSE +#define GDISP_NEED_ARC FALSE +#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_PIXELREAD FALSE +#define GDISP_NEED_CONTROL FALSE +#define GDISP_NEED_MULTITHREAD TRUE +#define GDISP_NEED_ASYNC FALSE +#define GDISP_NEED_MSGAPI FALSE + +/* GDISP - builtin fonts */ +#define GDISP_OLD_FONT_DEFINITIONS FALSE +#define GDISP_INCLUDE_FONT_SMALL FALSE +#define GDISP_INCLUDE_FONT_LARGER FALSE +#define GDISP_INCLUDE_FONT_UI1 FALSE +#define GDISP_INCLUDE_FONT_UI2 FALSE +#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE + +/* Features for the TDISP subsystem. */ +#define TDISP_NEED_MULTITHREAD FALSE + +/* Features for the GWIN sub-system. */ +#define GWIN_NEED_BUTTON FALSE +#define GWIN_NEED_CONSOLE FALSE +#define GWIN_NEED_GRAPH FALSE + +/* Features for the GEVENT sub-system. */ +#define GEVENT_ASSERT_NO_RESOURCE FALSE + +/* Features for the GTIMER sub-system. */ +/* NONE */ + +/* Features for the GINPUT sub-system. */ +#define GINPUT_NEED_MOUSE FALSE +#define GINPUT_NEED_KEYBOARD FALSE +#define GINPUT_NEED_TOGGLE FALSE +#define GINPUT_NEED_DIAL FALSE + +/* Features for the GADC sub-system. */ +/* NONE */ + +/* Features for the GAUDIN sub-system. */ +/* NONE */ + +/* Features for the GAUDOUT sub-system. */ +/* NONE */ + +/* Features for the GMISC sub-system. */ +#define GMISC_NEED_ARRAYOPS FALSE + +/* Optional Parameters for various sub-systems */ +/* + #define GDISP_MAX_FONT_HEIGHT 16 + #define GEVENT_MAXIMUM_SIZE 32 + #define GEVENT_MAX_SOURCE_LISTENERS 32 + #define GTIMER_THREAD_WORKAREA_SIZE 512 + #define GADC_MAX_LOWSPEED_DEVICES 4 +*/ + +/* Optional Low Level Driver Definitions */ +/* + #define GDISP_USE_CUSTOM_BOARD FALSE + #define GDISP_SCREEN_WIDTH 320 + #define GDISP_SCREEN_HEIGHT 240 + #define GDISP_USE_FSMC + #define GDISP_USE_GPIO + #define GDISP_VMT_NAME1(x) x##YourDriver1 + #define GDISP_VMT_NAME2(x) x##YourDriver2 + #define TDISP_COLUMNS 16 + #define TDISP_ROWS 2 +*/ + +#endif /* _GFXCONF_H */ diff --git a/demos/modules/gaudin/gwinosc.c b/demos/modules/gaudin/gwinosc.c new file mode 100644 index 00000000..a5de7e38 --- /dev/null +++ b/demos/modules/gaudin/gwinosc.c @@ -0,0 +1,190 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ + +/** + * --------------------------- Our Custom GWIN Oscilloscope --------------- + * + * This GWIN superset implements a simple audio oscilloscope using the GAUDIN module. + * + * It makes many assumptions, the most fundamental of which is that the audio device + * produces unsigned integer samples. + * + * The GMISC module with GMISC_NEED_ARRAYOPS could be used to process the samples more + * correctly if we were really building something generic. + */ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#include "gwinosc.h" + +/* Include internal GWIN routines so we can build our own superset class */ +#include "gwin/internal.h" + +/* Our GWIN identifier */ +#define GW_SCOPE (GW_FIRST_USER_WINDOW+0) + +/* The size of our dynamically allocated audio buffer */ +#define AUDIOBUFSZ 64*2 + +/* How many flat-line sample before we trigger */ +#define FLATLINE_SAMPLES 8 + +GHandle gwinCreateScope(GScopeObject *gs, coord_t x, coord_t y, coord_t cx, coord_t cy, uint16_t channel, uint32_t frequency) { + /* Initialise the base class GWIN */ + if (!(gs = (GScopeObject *)_gwinInit((GWindowObject *)gs, x, y, cx, cy, sizeof(GScopeObject)))) + return 0; + + /* Initialise the scope object members and allocate memory for buffers */ + gs->gwin.type = GW_SCOPE; + chBSemInit(&gs->bsem, TRUE); + gs->nextx = 0; + if (!(gs->lastscopetrace = (coord_t *)chHeapAlloc(NULL, gs->gwin.width * sizeof(coord_t)))) + return 0; + if (!(gs->audiobuf = (adcsample_t *)chHeapAlloc(NULL, AUDIOBUFSZ * sizeof(adcsample_t)))) + return 0; +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + gs->lasty = gs->gwin.height/2; +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + gs->lasty = gs->gwin.height/2; + gs->scopemin = 0; +#endif + + /* Start the GADC high speed converter */ + gaudinInit(channel, frequency, gs->audiobuf, AUDIOBUFSZ, AUDIOBUFSZ/2); + gaudinSetBSem(&gs->bsem, &gs->myEvent); + gaudinStart(); + + return (GHandle)gs; +} + +void gwinWaitForScopeTrace(GHandle gh) { + #define gs ((GScopeObject *)(gh)) + int i; + coord_t x, y; + coord_t yoffset; + audin_sample_t *pa; + coord_t *pc; +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + bool_t rdytrigger; + int flsamples; +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + bool_t rdytrigger; + int flsamples; + coord_t scopemin; +#endif + + /* Wait for a set of audio conversions */ + chBSemWait(&gs->bsem); + + /* Ensure we are drawing in the right area */ + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + + yoffset = gh->height/2 + (1<nextx; + pc = gs->lastscopetrace+x; + pa = gs->myEvent.buffer; +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + rdytrigger = FALSE; + flsamples = 0; +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + rdytrigger = FALSE; + flsamples = 0; + scopemin = 0; +#endif + + for(i = gs->myEvent.count; i; i--) { + + /* Calculate the new scope value - re-scale using simple shifts for efficiency, re-center and y-invert */ + #if GAUDIN_BITS_PER_SAMPLE > SCOPE_Y_BITS + y = yoffset - (*pa++ >> (GAUDIN_BITS_PER_SAMPLE - SCOPE_Y_BITS)); + #else + y = yoffset - (*pa++ << (SCOPE_Y_BITS - GAUDIN_BITS_PER_SAMPLE)); + #endif + +#if TRIGGER_METHOD == TRIGGER_MINVALUE + /* Calculate the scopemin ready for the next trace */ + if (y > scopemin) + scopemin = y; +#endif + + /* Have we reached the end of a scope trace? */ + if (x >= gh->width) { + +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP || TRIGGER_METHOD == TRIGGER_MINVALUE + /* Handle triggering - we trigger on the next sample minimum (y value maximum) or a flat-line */ + + #if TRIGGER_METHOD == TRIGGER_MINVALUE + /* Arm when we reach the sample minimum (y value maximum) of the previous trace */ + if (!rdytrigger && y >= gs->scopemin) + rdytrigger = TRUE; + #endif + + if (y == gs->lasty) { + /* Trigger if we get too many flat-line samples regardless of the armed state */ + if (++flsamples < FLATLINE_SAMPLES) + continue; + flsamples = 0; + } else if (y > gs->lasty) { + gs->lasty = y; + flsamples = 0; + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + /* Arm the trigger when samples fall (y increases) ie. negative slope */ + rdytrigger = TRUE; + #endif + continue; + } else { + /* If the trigger is armed, Trigger when samples increases (y decreases) ie. positive slope */ + gs->lasty = y; + flsamples = 0; + if (!rdytrigger) + continue; + } + + /* Ready for a the next trigger cycle */ + rdytrigger = FALSE; +#endif + + /* Prepare for a scope trace */ + x = 0; + pc = gs->lastscopetrace; + } + + /* Clear the old scope pixel and then draw the new scope value */ + gdispDrawPixel(gh->x+x, gh->y+pc[0], gh->bgcolor); + gdispDrawPixel(gh->x+x, gh->y+y, gh->color); + + /* Save the value */ + *pc++ = y; + x++; + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP || TRIGGER_METHOD == TRIGGER_MINVALUE + gs->lasty = y; + #endif + } + gs->nextx = x; +#if TRIGGER_METHOD == TRIGGER_MINVALUE + gs->scopemin = scopemin; +#endif + + #undef gs +} diff --git a/demos/modules/gaudin/gwinosc.h b/demos/modules/gaudin/gwinosc.h new file mode 100644 index 00000000..08244717 --- /dev/null +++ b/demos/modules/gaudin/gwinosc.h @@ -0,0 +1,95 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ + +#ifndef _GWINOSC_H +#define _GWINOSC_H + +/** + * --------------------------- Our Custom GWIN Oscilloscope --------------- + * + * This GWIN superset implements a simple audio oscilloscope using the GADC high speed device. + * + * It makes many assumptions, the most fundamental of which is that the audio device + * produces unsigned integer samples. + * + * The GMISC module with GMISC_NEED_ARRAYOPS could be used to process the samples more + * correctly if we were really building something generic. + */ + +/* The extent of scaling for our audio data - fixed scale at the moment */ +#ifndef SCOPE_Y_BITS + #define SCOPE_Y_BITS 8 // 8 bits = 0..255 +#endif + +/* Trigger methods */ +#define TRIGGER_NONE 0 /* No triggering */ +#define TRIGGER_POSITIVERAMP 1 /* Trigger on a positive going signal */ +#define TRIGGER_MINVALUE 2 /* Trigger on reaching the minimum value from the last scope */ + +/** + * Which trigger we want to use. + * Experiments suggests that TRIGGER_MINVALUE gives the best result + */ +#ifndef TRIGGER_METHOD + #define TRIGGER_METHOD TRIGGER_MINVALUE +#endif + +/* A scope window object. Treat it as a black box */ +typedef struct GScopeObject_t { + GWindowObject gwin; // Base Class + + coord_t *lastscopetrace; // To store last scope trace + BinarySemaphore bsem; // We get signalled on this + audin_sample_t *audiobuf; // To store audio samples + GEventAudioIn myEvent; // Information on received samples + coord_t nextx; // Where we are up to +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + coord_t lasty; // The last y value - used for trigger slope detection +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + coord_t lasty; // The last y value - used for trigger slope detection + coord_t scopemin; // The last scopes minimum value +#endif + } GScopeObject; + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Create a scope window. + */ + GHandle gwinCreateScope(GScopeObject *gs, coord_t x, coord_t y, coord_t cx, coord_t cy, uint16_t channel, uint32_t frequency); + + /** + * Wait for a scope trace to be ready and then draw it. + */ + void gwinWaitForScopeTrace(GHandle gh); + + /** + * We should also have a special destroy routine here as we have dynamically + * allocated some memory. There is no point implementing this however as, for + * this demo, we never destroy the window. + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GWINOSC_H */ diff --git a/demos/modules/gaudin/main.c b/demos/modules/gaudin/main.c new file mode 100644 index 00000000..7ca8d228 --- /dev/null +++ b/demos/modules/gaudin/main.c @@ -0,0 +1,67 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ + +/** + * This demo demonstrates the use of the GAUDIN module to read audio channel 0. + * The audio channel gets read to display a very simple oscilloscope. + * + * It also demonstrates how to write your own custom GWIN window type. + */ +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +/* Include our custom gwin audio oscilloscope */ +#include "gwinosc.h" + +/* Specify our timing parameters */ +#define MY_AUDIO_FREQUENCY 4000 /* 4khz */ +#define MY_AUDIO_CHANNEL 0 /* Use channel 0 */ + +/* Data */ +static GScopeObject gScopeWindow; + +/* + * Application entry point. + */ +int main(void) { + GHandle ghScope; + coord_t swidth, sheight; + + halInit(); + chSysInit(); + gdispInit(); + gdispClear(Black); + + /* Get the screen dimensions */ + swidth = gdispGetWidth(); + sheight = gdispGetHeight(); + + /* Set up the scope window to fill the screen */ + ghScope = gwinCreateScope(&gScopeWindow, 0, 0, swidth, sheight, MY_AUDIO_CHANNEL, MY_AUDIO_FREQUENCY); + gwinSetBgColor(ghScope, White); + gwinSetColor(ghScope, Red); + gwinClear(ghScope); + + /* Just keep displaying the scope traces */ + while (TRUE) { + gwinWaitForScopeTrace(ghScope); + } +} diff --git a/demos/modules/gaudin/results_264x264.jpg b/demos/modules/gaudin/results_264x264.jpg new file mode 100644 index 0000000000000000000000000000000000000000..461d963b9ff6a203ac4aa0464681f96f23341e19 GIT binary patch literal 19614 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 Q1FzHGro_}<>-0bW*>-)|=>Px# literal 0 HcmV?d00001 diff --git a/drivers/gadc/AT91SAM7/gadc_lld_config.h b/drivers/gadc/AT91SAM7/gadc_lld_config.h index 882573c8..8ba71f20 100644 --- a/drivers/gadc/AT91SAM7/gadc_lld_config.h +++ b/drivers/gadc/AT91SAM7/gadc_lld_config.h @@ -60,6 +60,11 @@ */ #define GADC_BITS_PER_SAMPLE AT91_ADC1_RESOLUTION +/** + * @brief The sample format + */ +#define GADC_SAMPLE_FORMAT ARRAY_DATA_10BITUNSIGNED + /* Pull in board specific defines */ #if defined(GADC_USE_CUSTOM_BOARD) && GADC_USE_CUSTOM_BOARD /* Include the user supplied board definitions */ @@ -73,6 +78,6 @@ #endif /* GFX_USE_GADC */ -#endif /* _GDISP_LLD_CONFIG_H */ +#endif /* GADC_LLD_CONFIG_H */ /** @} */ diff --git a/drivers/gaudin/gadc/gaudin_lld.c b/drivers/gaudin/gadc/gaudin_lld.c new file mode 100644 index 00000000..12e6aced --- /dev/null +++ b/drivers/gaudin/gadc/gaudin_lld.c @@ -0,0 +1,76 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ +/** + * @file drivers/gaudin/gadc/gaudin.c + * @brief GAUDIN - Driver file for using the cpu ADC (via GADC). + * + * @addtogroup GAUDIN + * + * @{ + */ +#include "ch.h" +#include "hal.h" + +/** + * We are now implementing the driver - pull in our channel table + * from the board definitions. + */ +#define GAUDIN_LLD_IMPLEMENTATION + + +#include "gfx.h" + +#if GFX_USE_GAUDIN + +/* Double check the GADC system is turned on */ +#if !GFX_USE_GADC + #error "GAUDIN - The GADC driver for GAUDIN requires GFX_USE_GADC to be TRUE" +#endif + +/* Include the driver defines */ +#include "gaudin/lld/gaudin_lld.h" + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +void gaudin_lld_init(const gaudin_params *paud) { + /* Setup the high speed GADC */ + gadcHighSpeedInit(gaudin_lld_physdevs[paud->channel], paud->frequency, paud->buffer, paud->bufcount, paud->samplesPerEvent); + + /* Register ourselves for ISR callbacks */ + gadcHighSpeedSetISRCallback(GAUDIN_ISR_CompleteI); + + /** + * 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() + */ +} + +void gadc_lld_start(void) { + gadcHighSpeedStart(); +} + +void gadc_lld_stop(void) { + gadcHighSpeedStop(); +} + +#endif /* GFX_USE_GAUDIN */ +/** @} */ diff --git a/drivers/gaudin/gadc/gaudin_lld.mk b/drivers/gaudin/gadc/gaudin_lld.mk new file mode 100644 index 00000000..c969e80b --- /dev/null +++ b/drivers/gaudin/gadc/gaudin_lld.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gaudin/gadc diff --git a/drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h b/drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h new file mode 100644 index 00000000..283a2914 --- /dev/null +++ b/drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h @@ -0,0 +1,60 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ + +/** + * @file drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h + * @brief GAUDIN Driver board config file for the Olimex SAM7EX256 board + * + * @addtogroup GAUDIN + * @{ + */ + +#ifndef _GAUDIN_LLD_BOARD_OLIMEXSAM7EX256_H +#define _GAUDIN_LLD_BOARD_OLIMEXSAM7EX256_H + +/*===========================================================================*/ +/* Audio inputs on this board */ +/*===========================================================================*/ + +/** + * @brief The number of audio channels supported by this driver + */ +#define GAUDIN_NUM_CHANNELS 1 + +/** + * @brief The list of audio channels and their uses + * @{ + */ +#define GAUDIN_MICROPHONE 0 +/** @} */ + +/** + * @brief The following defines are for the low level driver use only + * @{ + */ +#ifdef GAUDIN_LLD_IMPLEMENTATION + static uint32_t gaudin_lld_physdevs[GAUDIN_NUM_CHANNELS] = { + GADC_PHYSDEV_MICROPHONE, + }; +#endif +/** @} */ + +#endif /* _GAUDIN_LLD_BOARD_OLIMEXSAM7EX256_H */ +/** @} */ diff --git a/drivers/gaudin/gadc/gaudin_lld_config.h b/drivers/gaudin/gadc/gaudin_lld_config.h new file mode 100644 index 00000000..402e4180 --- /dev/null +++ b/drivers/gaudin/gadc/gaudin_lld_config.h @@ -0,0 +1,79 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ + +/** + * @file drivers/gaudin/gadc/gaudin_lld_config.h + * @brief GAUDIN Driver config file. + * + * @addtogroup GAUDIN + * @{ + */ + +#ifndef GAUDIN_LLD_CONFIG_H +#define GAUDIN_LLD_CONFIG_H + +#if GFX_USE_GAUDIN + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +/** + * @brief The audio input sample type + * @details For this driver it matches the cpu sample type + */ +typedef adcsample_t audin_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 GAUDIN_MAX_SAMPLE_FREQUENCY GADC_MAX_HIGH_SPEED_SAMPLERATE + +/** + * @brief The number of bits in a sample + * @details For this driver it matches the cpu sample bits + */ +#define GAUDIN_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 GAUDIN_SAMPLE_FORMAT GADC_SAMPLE_FORMAT + +/** + * For the GAUDIN driver that uses GADC - all the remaining config definitions are specific + * to the board. + */ +#if defined(GADC_USE_CUSTOM_BOARD) && GADC_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "gaudin_lld_board.h" +#elif defined(BOARD_OLIMEX_SAM7_EX256) + #include "gaudin_lld_board_olimexsam7ex256.h" +#else + /* Include the user supplied board definitions */ + #include "gaudin_lld_board.h" +#endif + +#endif /* GFX_USE_GAUDIN */ + +#endif /* GAUDIN_LLD_CONFIG_H */ +/** @} */ diff --git a/include/gadc/gadc.h b/include/gadc/gadc.h index be7af516..bd35b30c 100644 --- a/include/gadc/gadc.h +++ b/include/gadc/gadc.h @@ -96,10 +96,15 @@ typedef struct GEventADC_t { } GEventADC; /** - * @brief A callback function (executed in a thread context) + * @brief A callback function (executed in a thread context) for a low speed conversion */ typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param); +/** + * @brief A callback function (executed in an ISR context) for a high speed conversion + */ +typedef void (*GADCISRCallbackFunction)(adcsample_t *buffer, size_t size); + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ @@ -121,9 +126,9 @@ extern "C" { * @note If the high speed ADC is running it will be stopped. The Event subsystem is * disconnected from the high speed ADC and any binary semaphore event is forgotten. * @note bufcount must be greater than countPerEvent (usually 2 or more times) otherwise - * the buffer will be overwitten with new data while the application is still trying + * the buffer will be overwritten with new data while the application is still trying * to process the old data. - * @note Due to a bug in Chibi-OS countPerEvent must be even. If bufcount is not + * @note Due to a bug/feature in Chibi-OS countPerEvent must be even. If bufcount is not * evenly divisable by countPerEvent, the remainder must also be even. * @note The physdev parameter may be used to turn on more than one ADC channel. * Each channel is then interleaved into the provided buffer. Note 'bufcount' @@ -143,8 +148,7 @@ extern "C" { * @note While the high speed ADC is running, low speed conversions can only occur at * the frequency of the high speed events. Thus if high speed events are * being created at 50Hz (eg countPerEvent = 100, frequency = 5kHz) then the maximum - * frequency for low speed conversions is likely to be 50Hz (although it might be - * 100Hz on some hardware). + * frequency for low speed conversions will be 50Hz. * * @api */ @@ -159,14 +163,28 @@ void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer * called first. This saves processing time if the application does * not want to use the GEVENT sub-system for the high speed ADC. * Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again. - * @note The high speed ADC is capable of signalling via this method and a binary semaphore - * at the same time. + * @note The high speed ADC is capable of signalling via this method, an ISR callback and a + * binary semaphore at the same time. * * @api */ GSourceHandle gadcHighSpeedGetSource(void); #endif +/** + * @brief Allow retrieving of results from the high speed ADC using an ISR callback. + * + * @param[in] isrfn The callback function (called in an ISR context). + * + * @note Passing a NULL for isrfn will turn off signalling via this method as will calling + * @p gadcHighSpeedInit(). + * @note The high speed ADC is capable of signalling via this method, a binary semaphore and the GEVENT + * sub-system at the same time. + * + * @api + */ +void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn); + /** * @brief Allow retrieving of results from the high speed ADC using a Binary Semaphore and a static event buffer. * @@ -175,7 +193,7 @@ void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer * * @note Passing a NULL for pbsem or pEvent will turn off signalling via this method as will calling * @p gadcHighSpeedInit(). - * @note The high speed ADC is capable of signalling via this method and the GEVENT + * @note The high speed ADC is capable of signalling via this method, an ISR callback and the GEVENT * sub-system at the same time. * * @api diff --git a/include/gaudin/gaudin.h b/include/gaudin/gaudin.h index 6f35ba19..8c5d658a 100644 --- a/include/gaudin/gaudin.h +++ b/include/gaudin/gaudin.h @@ -1,170 +1,180 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - This file is part of ChibiOS/GFX. - - ChibiOS/GFX 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 3 of the License, or - (at your option) any later version. - - ChibiOS/GFX 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 . -*/ -/** - * @file include/gaudin/gaudin.h - * @brief GAUDIN - Audio Input subsystem header file. - * - * @addtogroup GAUDIN - * - * @{ - */ - -#ifndef _GAUDIN_H -#define _GAUDIN_H - -#include "gfx.h" - -#if GFX_USE_GAUDIN || defined(__DOXYGEN__) - -/* Include the driver defines */ -#include "gaudin_lld_config.h" -//audio_in_sample_t -//GAUDIN_SAMPLE_FORMAT ARRAY_DATA_10BITUNSIGNED -//GAUDIN_STEREO_DEVICE FALSE - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -// Event types for GAUDIN -#define GEVENT_AUDIO_IN (GEVENT_GAUDIN_FIRST+0) - -/** - * @brief The Audio Input event structure. - * @{ - */ -typedef struct GEventAudioIn_t { - /** - * @brief The type of this event (GEVENT_AUDIO_IN) - */ - GEventType type; - /** - * @brief The event flags - */ - uint16_t flags; - /** - * @brief The event flag values. - * @{ - */ - #define GADC_AUDIO_IN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */ - /** @} */ - /** - * @brief The number of audio samples in the buffer - */ - size_t count; - /** - * @brief The buffer containing the audio samples - */ - audio_in_sample_t *buffer; - } GEventAudioIn; - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Initialise the Audio Input Subsystem. - * @details Initialises but does not start the audio in. - * - * @param[in] frequency The sample frequency - * @param[in] buffer The static buffer to put the samples into. - * @param[in] bufcount The total number of conversions that will fit in the buffer. - * @param[in] countPerEvent The number of conversions to do before returning an event. - * - * @note If the audio input is running it will be stopped. - * @note Due to a bug in Chibi-OS countPerEvent must be even for the GADC audio driver. - * If bufcount is not evenly divisable by countPerEvent, the remainder must also be even. - * This requirement may not apply to other GAUDIN drivers. - * @note The number of samples for stereo devices will be double the number of conversions. - * Make sure you allocate your buffers large enough. Each channel is then interleaved - * into the provided buffer. Note 'bufcount' and 'countPerEvent' parameters describe the - * number of conversions not the number of samples. - * @note The buffer is circular. When the end of the buffer is reached it will start - * putting data into the beginning of the buffer again. - * @note The event listener must process the event (and the data in it) before the - * next event occurs. If not, the following event will be lost. - * @note If bufcount is evenly divisable by countPerEvent, then every event will return - * countPerEvent conversions. If bufcount is not evenly divisable, it will return - * a block of samples containing less than countPerEvent samples when it reaches the - * end of the buffer. - * - * @api - */ -void gaudinInit(uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent); - -#if GFX_USE_GEVENT || defined(__DOXYGEN__) - /** - * @brief Turn on sending results to the GEVENT sub-system. - * @details Returns a GSourceHandle to listen for GEVENT_AUDIO_IN events. - * - * @note The audio input will not use the GEVENT system unless this is - * called first. This saves processing time if the application does - * not want to use the GEVENT sub-system for audio input. - * Once turned on it cannot be turned off. - * @note The audio input is capable of signalling via this method and a binary semaphore - * at the same time. - * - * @api - */ - GSourceHandle gaudinGetSource(void); -#endif - -/** - * @brief Allow retrieving of results from the audio input using a Binary Semaphore and a static event buffer. - * - * @param[in] pbsem The binary semaphore is signaled when data is available. - * @param[in] pEvent The static event buffer to place the result information. - * - * @note Passing a NULL for pbsem or pEvent will turn off signalling via this method. - * @note The audio input is capable of signalling via this method and the GEVENT - * sub-system at the same time. - * - * @api - */ -void gaudinSetBSem(BinarySemaphore *pbsem, GEventAudioIn *pEvent); - -/** - * @brief Start the audio input conversions. - * @pre It must have been initialised first with @p gaudinInit() - * - * @api - */ -GSourceHandle gaudinStart(void); - -/** - * @brief Stop the audio input conversions. - * - * @api - */ -void gaudinStop(void); - -#ifdef __cplusplus -} -#endif - -#endif /* GFX_USE_GAUDIN */ - -#endif /* _GAUDIN_H */ -/** @} */ - +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ +/** + * @file include/gaudin/gaudin.h + * @brief GAUDIN - Audio Input subsystem header file. + * + * @addtogroup GAUDIN + * + * @{ + */ + +#ifndef _GAUDIN_H +#define _GAUDIN_H + +#include "gfx.h" + +#if GFX_USE_GAUDIN || defined(__DOXYGEN__) + +/* Include the driver defines */ +#include "gaudin_lld_config.h" + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +// Event types for GAUDIN +#define GEVENT_AUDIO_IN (GEVENT_GAUDIN_FIRST+0) + +/** + * @brief The Audio Input event structure. + * @{ + */ +typedef struct GEventAudioIn_t { + #if GFX_USE_GEVENT || defined(__DOXYGEN__) + /** + * @brief The type of this event (GEVENT_AUDIO_IN) + */ + GEventType type; + #endif + /** + * @brief The current channel + */ + uint16_t channel; + /** + * @brief The event flags + */ + uint16_t flags; + /** + * @brief The event flag values. + * @{ + */ + #define GADC_AUDIO_IN_LOSTEVENT 0x0001 /**< @brief The last GEVENT_AUDIO_IN event was lost */ + /** @} */ + /** + * @brief The number of audio samples in the buffer + */ + size_t count; + /** + * @brief The buffer containing the audio samples + */ + audin_sample_t *buffer; + } GEventAudioIn; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialise (but not start) the Audio Input Subsystem. + * @details Returns FALSE for an invalid channel or other invalid parameter. + * + * @param[in] channel The channel to convert. Can be set from 0 to GAUDIN_NUM_CHANNELS - 1. + * @param[in] frequency The sample frequency + * @param[in] buffer The static buffer to put the samples into. + * @param[in] bufcount The total number of conversions that will fit in the buffer. + * @param[in] countPerEvent The number of conversions to do before returning an event. + * + * @note Only one channel is active at a time. If an audio input is running it will be stopped. + * The Event subsystem is disconnected from the audio subsystem and any binary semaphore + * event is forgotten. + * @note Some channels may be stereo channels which return twice as much sample data with + * the left and right channel data interleaved. Other channels may be mono channels. + * Where stereo channels exist it would be common for the low level driver to also + * offer the left and right channels separately. + * @note Due to a bug in Chibi-OS countPerEvent must be even if using the GADC low level audio driver. + * If bufcount is not evenly divisable by countPerEvent, the remainder must also be even. + * This requirement may not apply to other GAUDIN drivers. + * @note The number of samples for stereo devices will be double the number of conversions. + * Make sure you allocate your buffers large enough. Each channel is then interleaved + * into the provided buffer. Note 'bufcount' and 'countPerEvent' parameters describe the + * number of conversions not the number of samples. + * @note The buffer is circular. When the end of the buffer is reached it will start + * putting data into the beginning of the buffer again. + * @note The event listener must process the event (and the data in it) before the + * next event occurs. If not, the following event will be lost. + * @note If bufcount is evenly divisable by countPerEvent, then every event will return + * countPerEvent conversions. If bufcount is not evenly divisable, it will return + * a block of samples containing less than countPerEvent samples when it reaches the + * end of the buffer. + * + * @api + */ +bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, size_t bufcount, size_t samplesPerEvent); + +#if GFX_USE_GEVENT || defined(__DOXYGEN__) + /** + * @brief Turn on sending results to the GEVENT sub-system. + * @details Returns a GSourceHandle to listen for GEVENT_AUDIO_IN events. + * + * @note The audio input will not use the GEVENT system unless this is + * called first. This saves processing time if the application does + * not want to use the GEVENT sub-system for audio input. + * Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again. + * @note The audio input is capable of signalling via this method and a binary semaphore + * at the same time. + * + * @api + */ + GSourceHandle gaudinGetSource(void); +#endif + +/** + * @brief Allow retrieving of results from the audio input using a Binary Semaphore and a static event buffer. + * + * @param[in] pbsem The binary semaphore is signaled when data is available. + * @param[in] pEvent The static event buffer to place the result information. + * + * @note Passing a NULL for pbsem or pEvent will turn off signalling via this method. + * @note The audio input is capable of signalling via this method and the GEVENT + * sub-system at the same time. + * + * @api + */ +void gaudinSetBSem(BinarySemaphore *pbsem, GEventAudioIn *pEvent); + +/** + * @brief Start the audio input conversions. + * @pre It must have been initialised first with @p gaudinInit() + * + * @api + */ +void gaudinStart(void); + +/** + * @brief Stop the audio input conversions. + * + * @api + */ +void gaudinStop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GAUDIN */ + +#endif /* _GAUDIN_H */ +/** @} */ + diff --git a/include/gaudin/lld/gaudin_lld.h b/include/gaudin/lld/gaudin_lld.h new file mode 100644 index 00000000..2b2db86e --- /dev/null +++ b/include/gaudin/lld/gaudin_lld.h @@ -0,0 +1,105 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ +/** + * @file include/gaudin/lld/gaudin_lld.h + * @brief GAUDIN - Audio Input driver header file. + * + * @defgroup Driver Driver + * @ingroup GAUDIN + * @{ + */ + +#ifndef _GAUDIN_LLD_H +#define _GAUDIN_LLD_H + +#include "gfx.h" + +#if GFX_USE_GADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +/** + * @brief The structure passed to start a audio conversion + * @note We use the structure instead of parameters purely to save + * interrupt stack space which is very limited in some platforms. + * @{ + */ +typedef struct gaudin_params_t { + uint16_t channel; + uint32_t frequency; + audin_sample_t *buffer; + size_t bufcount; + size_t samplesPerEvent; + } gaudin_params; +/* @} */ + +/** + * @brief These routines are the callbacks that the driver uses. + * @details Defined in the high level GAUDIN code. + * + * @icode + * @notapi + * @{ + */ +extern void GAUDIN_ISR_CompleteI(audin_sample_t *buffer, size_t n); +extern void GAUDIN_ISR_ErrorI(void); +/** + * @} + */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialise the driver + * + * @api + */ +void gaudin_lld_init(const gaudin_params *paud); + +/** + * @brief Start the audio input sampling + * + * @api + */ +void gadc_lld_start(void); + +/** + * @brief Stop the audio input sampling + * + * @api + */ +void gadc_lld_stop(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GADC */ + +#endif /* _GADC_LLD_H */ +/** @} */ diff --git a/include/gfx.h b/include/gfx.h index 552e3294..e6b8d03e 100644 --- a/include/gfx.h +++ b/include/gfx.h @@ -1,170 +1,170 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - This file is part of ChibiOS/GFX. - - ChibiOS/GFX 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 3 of the License, or - (at your option) any later version. - - ChibiOS/GFX 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 . -*/ - -/** - * @file include/gfx.h - * @brief GFX system header file. - * - * @addtogroup GFX - * @{ - */ - -#ifndef _GFX_H -#define _GFX_H - -/* gfxconf.h is the user's project configuration for the GFX system. */ -#include "gfxconf.h" - -/** - * @name GFX sub-systems that can be turned on - * @{ - */ - /** - * @brief GFX Graphics Display Basic API - * @details Defaults to FALSE - * @note Also add the specific hardware driver to your makefile. - * Eg. include $(GFXLIB)/drivers/gdisp/Nokia6610/gdisp_lld.mk - */ - #ifndef GFX_USE_GDISP - #define GFX_USE_GDISP FALSE - #endif - /** - * @brief GFX Text Display Basic API - * @details Defaults to FALSE - * @note Also add the specific hardware driver to your makefile. - * Eg. include $(GFXLIB)/drivers/tdisp/HD44780/tdisp_lld.mk - */ - #ifndef GFX_USE_TDISP - #define GFX_USE_TDISP FALSE - #endif - /** - * @brief GFX Graphics Windowing API - * @details Defaults to FALSE - * @details Extends the GDISP API to add the concept of graphic windows. - * @note Also supports high-level "window" objects such as console windows, - * buttons, graphing etc - */ - #ifndef GFX_USE_GWIN - #define GFX_USE_GWIN FALSE - #endif - /** - * @brief GFX Event API - * @details Defaults to FALSE - * @details Defines the concept of a "Source" that can send "Events" to "Listeners". - */ - #ifndef GFX_USE_GEVENT - #define GFX_USE_GEVENT FALSE - #endif - /** - * @brief GFX Timer API - * @details Defaults to FALSE - * @details Provides thread context timers - both one-shot and periodic. - */ - #ifndef GFX_USE_GTIMER - #define GFX_USE_GTIMER FALSE - #endif - /** - * @brief GFX Input Device API - * @details Defaults to FALSE - * @note Also add the specific hardware drivers to your makefile. - * Eg. - * include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk - * and... - * include $(GFXLIB)/drivers/ginput/touch/MCU/ginput_lld.mk - */ - #ifndef GFX_USE_GINPUT - #define GFX_USE_GINPUT FALSE - #endif - /** - * @brief GFX Generic Periodic ADC API - * @details Defaults to FALSE - */ - #ifndef GFX_USE_GADC - #define GFX_USE_GADC FALSE - #endif - /** - * @brief GFX Audio Input Device API - * @details Defaults to FALSE - * @note Also add the specific hardware drivers to your makefile. - * Eg. - * include $(GFXLIB)/drivers/gaudin/GADC/gaudin_lld.mk - */ - #ifndef GFX_USE_GAUDIN - #define GFX_USE_GAUDIN FALSE - #endif - /** - * @brief GFX Audio Output Device API - * @details Defaults to FALSE - * @note Also add the specific hardware drivers to your makefile. - * Eg. - * include $(GFXLIB)/drivers/gaudout/PWM/gaudout_lld.mk - */ - #ifndef GFX_USE_GAUDOUT - #define GFX_USE_GAUDOUT FALSE - #endif - /** - * @brief GFX Miscellaneous Routines API - * @details Defaults to FALSE - * @note Turning this on without turning on any GMISC_NEED_xxx macros will result - * in no extra code being compiled in. GMISC is made up from the sum of its - * parts. - */ - #ifndef GFX_USE_GMISC - #define GFX_USE_GMISC FALSE - #endif -/** @} */ - -/** - * Get all the options for each sub-system. - * - */ -#include "gmisc/options.h" -#include "gevent/options.h" -#include "gtimer/options.h" -#include "gdisp/options.h" -#include "gwin/options.h" -#include "ginput/options.h" -#include "tdisp/options.h" -#include "gadc/options.h" -#include "gaudin/options.h" -#include "gaudout/options.h" - -/** - * Inter-dependancy safety checks on the sub-systems. - * - */ -#include "gfx_rules.h" - -/** - * Include the sub-system header files - */ -#include "gevent/gevent.h" -#include "gtimer/gtimer.h" -#include "gdisp/gdisp.h" -#include "gwin/gwin.h" -#include "ginput/ginput.h" -#include "tdisp/tdisp.h" -#include "gadc/gadc.h" -#include "gaudin/gaudin.h" -#include "gaudout/gaudout.h" -#include "gmisc/gmisc.h" - -#endif /* _GFX_H */ -/** @} */ +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ + +/** + * @file include/gfx.h + * @brief GFX system header file. + * + * @addtogroup GFX + * @{ + */ + +#ifndef _GFX_H +#define _GFX_H + +/* gfxconf.h is the user's project configuration for the GFX system. */ +#include "gfxconf.h" + +/** + * @name GFX sub-systems that can be turned on + * @{ + */ + /** + * @brief GFX Graphics Display Basic API + * @details Defaults to FALSE + * @note Also add the specific hardware driver to your makefile. + * Eg. include $(GFXLIB)/drivers/gdisp/Nokia6610/gdisp_lld.mk + */ + #ifndef GFX_USE_GDISP + #define GFX_USE_GDISP FALSE + #endif + /** + * @brief GFX Text Display Basic API + * @details Defaults to FALSE + * @note Also add the specific hardware driver to your makefile. + * Eg. include $(GFXLIB)/drivers/tdisp/HD44780/tdisp_lld.mk + */ + #ifndef GFX_USE_TDISP + #define GFX_USE_TDISP FALSE + #endif + /** + * @brief GFX Graphics Windowing API + * @details Defaults to FALSE + * @details Extends the GDISP API to add the concept of graphic windows. + * @note Also supports high-level "window" objects such as console windows, + * buttons, graphing etc + */ + #ifndef GFX_USE_GWIN + #define GFX_USE_GWIN FALSE + #endif + /** + * @brief GFX Event API + * @details Defaults to FALSE + * @details Defines the concept of a "Source" that can send "Events" to "Listeners". + */ + #ifndef GFX_USE_GEVENT + #define GFX_USE_GEVENT FALSE + #endif + /** + * @brief GFX Timer API + * @details Defaults to FALSE + * @details Provides thread context timers - both one-shot and periodic. + */ + #ifndef GFX_USE_GTIMER + #define GFX_USE_GTIMER FALSE + #endif + /** + * @brief GFX Input Device API + * @details Defaults to FALSE + * @note Also add the specific hardware drivers to your makefile. + * Eg. + * include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk + * and... + * include $(GFXLIB)/drivers/ginput/touch/MCU/ginput_lld.mk + */ + #ifndef GFX_USE_GINPUT + #define GFX_USE_GINPUT FALSE + #endif + /** + * @brief GFX Generic Periodic ADC API + * @details Defaults to FALSE + */ + #ifndef GFX_USE_GADC + #define GFX_USE_GADC FALSE + #endif + /** + * @brief GFX Audio Input Device API + * @details Defaults to FALSE + * @note Also add the specific hardware drivers to your makefile. + * Eg. + * include $(GFXLIB)/drivers/gaudin/GADC/gaudin_lld.mk + */ + #ifndef GFX_USE_GAUDIN + #define GFX_USE_GAUDIN FALSE + #endif + /** + * @brief GFX Audio Output Device API + * @details Defaults to FALSE + * @note Also add the specific hardware drivers to your makefile. + * Eg. + * include $(GFXLIB)/drivers/gaudout/PWM/gaudout_lld.mk + */ + #ifndef GFX_USE_GAUDOUT + #define GFX_USE_GAUDOUT FALSE + #endif + /** + * @brief GFX Miscellaneous Routines API + * @details Defaults to FALSE + * @note Turning this on without turning on any GMISC_NEED_xxx macros will result + * in no extra code being compiled in. GMISC is made up from the sum of its + * parts. + */ + #ifndef GFX_USE_GMISC + #define GFX_USE_GMISC FALSE + #endif +/** @} */ + +/** + * Get all the options for each sub-system. + * + */ +#include "gmisc/options.h" +#include "gevent/options.h" +#include "gtimer/options.h" +#include "gdisp/options.h" +#include "gwin/options.h" +#include "ginput/options.h" +#include "tdisp/options.h" +#include "gadc/options.h" +#include "gaudin/options.h" +#include "gaudout/options.h" + +/** + * Inter-dependancy safety checks on the sub-systems. + * + */ +#include "gfx_rules.h" + +/** + * Include the sub-system header files + */ +#include "gmisc/gmisc.h" +#include "gevent/gevent.h" +#include "gtimer/gtimer.h" +#include "gdisp/gdisp.h" +#include "gwin/gwin.h" +#include "ginput/ginput.h" +#include "tdisp/tdisp.h" +#include "gadc/gadc.h" +#include "gaudin/gaudin.h" +#include "gaudout/gaudout.h" + +#endif /* _GFX_H */ +/** @} */ diff --git a/include/gfx_rules.h b/include/gfx_rules.h index ce6bea50..27316204 100644 --- a/include/gfx_rules.h +++ b/include/gfx_rules.h @@ -99,6 +99,14 @@ #if GFX_USE_TDISP #endif +#if GFX_USE_GAUDIN + #if GFX_USE_GEVENT && !GFX_USE_GTIMER + #warning "GAUDIN: GFX_USE_GTIMER is required if GFX_USE_GAUDIN and GFX_USE_GEVENT are TRUE. It has been turned on for you." + #undef GFX_USE_GTIMER + #define GFX_USE_GTIMER TRUE + #endif +#endif + #if GFX_USE_GADC #if !CH_USE_MUTEXES || !CH_USE_SEMAPHORES #error "GADC: CH_USE_MUTEXES and CH_USE_SEMAPHORES must be defined in chconf.h" @@ -123,9 +131,6 @@ #endif #endif -#if GFX_USE_GAUDIN -#endif - #if GFX_USE_GAUDOUT #endif diff --git a/include/gmisc/gmisc.h b/include/gmisc/gmisc.h index c68e5ca2..b11a912b 100644 --- a/include/gmisc/gmisc.h +++ b/include/gmisc/gmisc.h @@ -1,106 +1,108 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - This file is part of ChibiOS/GFX. - - ChibiOS/GFX 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 3 of the License, or - (at your option) any later version. - - ChibiOS/GFX 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 . -*/ -/** - * @file include/gmisc/gmisc.h - * @brief GMISC - Miscellaneous Routines header file. - * - * @addtogroup GAUDIN - * - * @{ - */ - -#ifndef _GMISC_H -#define _GMISC_H - -#include "gfx.h" - -/*===========================================================================*/ -/* Type definitions */ -/*===========================================================================*/ - -/** - * @brief Sample data formats - */ -typedef enum ArrayDataFormat_e { - ARRAY_DATA_4BITUNSIGNED = 4, ARRAY_DATA_4BITSIGNED = 5, - ARRAY_DATA_8BITUNSIGNED = 8, ARRAY_DATA_8BITSIGNED = 9, - ARRAY_DATA_10BITUNSIGNED = 10, ARRAY_DATA_10BITSIGNED = 11, - ARRAY_DATA_12BITUNSIGNED = 12, ARRAY_DATA_12BITSIGNED = 13, - ARRAY_DATA_14BITUNSIGNED = 14, ARRAY_DATA_14BITSIGNED = 15, - ARRAY_DATA_16BITUNSIGNED = 16, ARRAY_DATA_16BITSIGNED = 17, - } ArrayDataFormat; - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#if GFX_USE_GMISC || defined(__DOXYGEN__) - -#ifdef __cplusplus -extern "C" { -#endif - -#if GMISC_NEED_ARRAYOPS || defined(__DOXYGEN__) - /** - * @brief Convert from one array format to another array format. - * - * @param[in] srcfmt The format of the source array - * @param[in] src The source array - * @param[in] dstfmt The format of the destination array - * @param[in] dst The dstination array - * @param[in] cnt The number of array elements to convert - * - * @note Assumes the destination buffer is large enough for the resultant data. - * @note This routine is optimised to perform as fast as possible. - * @note No type checking is performed on the source format. It is assumed to - * have only valid values eg. ARRAY_DATA_4BITSIGNED will have values - * 0000 -> 0111 for positive numbers and 1111 -> 1000 for negative numbers - * Bits 5 -> 8 in the storage byte are treated in an undefined manner. - * @note If srcfmt or dstfmt is an unknown format, this routine does nothing - * with no warning that something is wrong - * - * @api - */ - void gmiscArrayConvert(ArrayDataFormat srcfmt, void *src, ArrayDataFormat dstfmt, void *dst, size_t cnt); - - #if 0 - void gmiscArrayTranslate(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int trans); - - void gmiscArrayMultiply(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult); - - void gmiscArrayDivide(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mdiv); - - void gmiscArrayMultDiv(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult, int div); - - void gmiscArrayAdd(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt); - - void gmiscArrayAddNoOverflow(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt); - #endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* GFX_USE_MISC */ - -#endif /* _GMISC_H */ -/** @} */ - +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ +/** + * @file include/gmisc/gmisc.h + * @brief GMISC - Miscellaneous Routines header file. + * + * @addtogroup GAUDIN + * + * @{ + */ + +#ifndef _GMISC_H +#define _GMISC_H + +#include "gfx.h" + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +/** + * @brief Sample data formats + * @note These are defined regardless of whether you use the GMISC module + * or not as they are used in lots of places. + */ +typedef enum ArrayDataFormat_e { + ARRAY_DATA_4BITUNSIGNED = 4, ARRAY_DATA_4BITSIGNED = 5, + ARRAY_DATA_8BITUNSIGNED = 8, ARRAY_DATA_8BITSIGNED = 9, + ARRAY_DATA_10BITUNSIGNED = 10, ARRAY_DATA_10BITSIGNED = 11, + ARRAY_DATA_12BITUNSIGNED = 12, ARRAY_DATA_12BITSIGNED = 13, + ARRAY_DATA_14BITUNSIGNED = 14, ARRAY_DATA_14BITSIGNED = 15, + ARRAY_DATA_16BITUNSIGNED = 16, ARRAY_DATA_16BITSIGNED = 17, + } ArrayDataFormat; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if GFX_USE_GMISC || defined(__DOXYGEN__) + +#ifdef __cplusplus +extern "C" { +#endif + +#if GMISC_NEED_ARRAYOPS || defined(__DOXYGEN__) + /** + * @brief Convert from one array format to another array format. + * + * @param[in] srcfmt The format of the source array + * @param[in] src The source array + * @param[in] dstfmt The format of the destination array + * @param[in] dst The dstination array + * @param[in] cnt The number of array elements to convert + * + * @note Assumes the destination buffer is large enough for the resultant data. + * @note This routine is optimised to perform as fast as possible. + * @note No type checking is performed on the source format. It is assumed to + * have only valid values eg. ARRAY_DATA_4BITSIGNED will have values + * 0000 -> 0111 for positive numbers and 1111 -> 1000 for negative numbers + * Bits 5 -> 8 in the storage byte are treated in an undefined manner. + * @note If srcfmt or dstfmt is an unknown format, this routine does nothing + * with no warning that something is wrong + * + * @api + */ + void gmiscArrayConvert(ArrayDataFormat srcfmt, void *src, ArrayDataFormat dstfmt, void *dst, size_t cnt); + + #if 0 + void gmiscArrayTranslate(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int trans); + + void gmiscArrayMultiply(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult); + + void gmiscArrayDivide(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mdiv); + + void gmiscArrayMultDiv(ArrayDataFormat fmt, void *src, void *dst, size_t cnt, int mult, int div); + + void gmiscArrayAdd(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt); + + void gmiscArrayAddNoOverflow(ArrayDataFormat fmt, void *src1, void *src2, void *dst, size_t cnt); + #endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_MISC */ + +#endif /* _GMISC_H */ +/** @} */ + diff --git a/src/gadc/gadc.c b/src/gadc/gadc.c index 509557d3..8a3cfb8d 100644 --- a/src/gadc/gadc.c +++ b/src/gadc/gadc.c @@ -83,6 +83,7 @@ static struct hsdev { size_t remaining; BinarySemaphore *bsem; GEventADC *pEvent; + GADCISRCallbackFunction isrfn; } hs; static struct lsdev { @@ -181,6 +182,11 @@ void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n) { hs.pEvent->buffer = hs.lastbuffer; hs.pEvent->flags = hs.lastflags; } + + /* Our three signalling mechanisms */ + if (hs.isrfn) + hs.isrfn(buffer, n); + if (hs.bsem) chBSemSignalI(hs.bsem); @@ -344,6 +350,7 @@ void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer hs.remaining = bufcount; hs.bsem = 0; hs.pEvent = 0; + hs.isrfn = 0; } #if GFX_USE_GEVENT @@ -356,6 +363,10 @@ void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer } #endif +void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn) { + hs.isrfn = isrfn; +} + void gadcHighSpeedSetBSem(BinarySemaphore *pbsem, GEventADC *pEvent) { DoInit(); diff --git a/src/gaudin/gaudin.c b/src/gaudin/gaudin.c index 120d7d81..4ce04132 100644 --- a/src/gaudin/gaudin.c +++ b/src/gaudin/gaudin.c @@ -1,38 +1,158 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - This file is part of ChibiOS/GFX. - - ChibiOS/GFX 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 3 of the License, or - (at your option) any later version. - - ChibiOS/GFX 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 . -*/ - -/** - * @file src/gaudin/gaudin.c - * @brief GAUDIN sub-system code. - * - * @addtogroup GAUDIN - * @{ - */ -#include "ch.h" -#include "hal.h" -#include "gfx.h" - -#if GFX_USE_GAUDIN || defined(__DOXYGEN__) - - #error "GAUDIN: Not implemented yet" - -#endif /* GFX_USE_GAUDIN */ -/** @} */ - +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX 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 . +*/ + +/** + * @file src/gaudin/gaudin.c + * @brief GAUDIN sub-system code. + * + * @addtogroup GAUDIN + * @{ + */ +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_GAUDIN + +/* Include the driver defines */ +#include "gaudin/lld/gaudin_lld.h" + +static gaudin_params aud; +static BinarySemaphore *paudSem; +static GEventAudioIn *paudEvent; +static audin_sample_t *lastbuffer; +static size_t lastcount; +static uint16_t audFlags; + #define AUDFLG_RUNNING 0x0001 + #define AUDFLG_USE_EVENTS 0x0002 + +#if GFX_USE_GEVENT + static GTIMER_DECL(AudGTimer); + + static void AudGTimerCallback(void *param) { + (void) param; + GSourceListener *psl; + GEventADC *pe; + + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) { + if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) { + // This listener is missing - save this. + psl->srcflags |= GADC_AUDIO_IN_LOSTEVENT; + continue; + } + + pe->type = GEVENT_AUDIO_IN; + pe->channel = aud.channel; + pe->count = lastcount; + pe->buffer = lastbuffer; + pe->flags = psl->srcflags; + psl->srcflags = 0; + geventSendEvent(psl); + } + } +#endif + +void GAUDIN_ISR_CompleteI(audin_sample_t *buffer, size_t n) { + /* Save the details */ + lastcount = n; + lastbuffer = buffer; + + /* Signal the user with the data */ + if (paudEvent) { + #if GFX_USE_GEVENT + paudEvent->type = GEVENT_AUDIO_IN; + #endif + paudEvent->channel = aud.channel; + paudEvent->count = lastcount; + paudEvent->buffer = lastbuffer; + paudEvent->flags = 0; + } + + /* Our two signalling mechanisms */ + if (paudSem) + chBSemSignalI(paudSem); + + #if GFX_USE_GEVENT + if (audFlags & AUDFLG_USE_EVENTS) + gtimerJabI(&AudGTimer); + #endif +} + +void GAUDIN_ISR_ErrorI(void) { + /* Ignore any errors for now */ +} + +bool_t gaudinInit(uint16_t channel, uint32_t frequency, audin_sample_t *buffer, size_t bufcount, size_t samplesPerEvent) { + /* Check the channel is valid */ + if (channel >= GAUDIN_NUM_CHANNELS || frequency > GAUDIN_MAX_SAMPLE_FREQUENCY) + return FALSE; + + /* Stop any existing transfers */ + if ((audFlags & AUDFLG_RUNNING)) + gadc_lld_stop(); + audFlags = 0; + + /* Initialise everything */ + aud.channel = channel; + aud.frequency = frequency; + aud.buffer = buffer; + aud.bufcount = bufcount; + aud.samplesPerEvent = samplesPerEvent; + paudSem = 0; + paudEvent = 0; + + /* Set up the low level driver */ + gaudin_lld_init(&aud); + return TRUE; +} + +#if GFX_USE_GEVENT + GSourceHandle gaudinGetSource(void) { + if (!gtimerIsActive(&AudGTimer)) + gtimerStart(&AudGTimer, AudGTimerCallback, NULL, TRUE, TIME_INFINITE); + audFlags |= AUDFLG_USE_EVENTS; + return (GSourceHandle)&aud; + } +#endif + +void gaudinSetBSem(BinarySemaphore *pbsem, GEventAudioIn *pEvent) { + chSysLock(); + paudSem = pbsem; + paudEvent = pEvent; + chSysUnlock(); +} + +void gaudinStart(void) { + if (!(audFlags & AUDFLG_RUNNING)) { + audFlags |= AUDFLG_RUNNING; + gadc_lld_start(); + } +} + +void gaudinStop(void) { + if ((audFlags & AUDFLG_RUNNING)) { + gadc_lld_stop(); + audFlags &= ~AUDFLG_RUNNING; + } +} + +#endif /* GFX_USE_GAUDIN */ +/** @} */