diff options
| author | Andrew Hannam <andrewh@inmarket.com.au> | 2013-02-18 17:33:35 +1000 | 
|---|---|---|
| committer | Andrew Hannam <andrewh@inmarket.com.au> | 2013-02-18 17:33:35 +1000 | 
| commit | 9bec5967b293d6c23c9d7e9338d8ece4873f6eac (patch) | |
| tree | 2af82d8674eb0c69c8a2d8b9055f3a5e57833cfe /demos/modules/gadc | |
| parent | 2ed57aea77103e864c25f2478ef7fc43352163f0 (diff) | |
| download | uGFX-9bec5967b293d6c23c9d7e9338d8ece4873f6eac.tar.gz uGFX-9bec5967b293d6c23c9d7e9338d8ece4873f6eac.tar.bz2 uGFX-9bec5967b293d6c23c9d7e9338d8ece4873f6eac.zip  | |
GADC implementation with demo program
Also includes driver for AT91SAM7 cpu
Diffstat (limited to 'demos/modules/gadc')
| -rw-r--r-- | demos/modules/gadc/gfxconf.h | 105 | ||||
| -rw-r--r-- | demos/modules/gadc/gwinosc.c | 183 | ||||
| -rw-r--r-- | demos/modules/gadc/gwinosc.h | 89 | ||||
| -rw-r--r-- | demos/modules/gadc/main.c | 176 | ||||
| -rw-r--r-- | demos/modules/gadc/results_264x264.jpg | bin | 0 -> 21130 bytes | 
5 files changed, 553 insertions, 0 deletions
diff --git a/demos/modules/gadc/gfxconf.h b/demos/modules/gadc/gfxconf.h new file mode 100644 index 00000000..58475fba --- /dev/null +++ b/demos/modules/gadc/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			FALSE +#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			TRUE +#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		TRUE +#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			TRUE +#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		TRUE +#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/gadc/gwinosc.c b/demos/modules/gadc/gwinosc.c new file mode 100644 index 00000000..d08fbc0d --- /dev/null +++ b/demos/modules/gadc/gwinosc.c @@ -0,0 +1,183 @@ +/* +    ChibiOS/GFX - Copyright (C) 2012, 2013 +                 Joel Bodenmann aka Tectu <joel@unormal.org> + +    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 <http://www.gnu.org/licenses/>. +*/ + +/** + * --------------------------- Our Custom GWIN Oscilloscope --------------- + * + * This GWIN superset implements a simple audio oscilloscope using the GADC high speed device. + */ +#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, uint32_t physdev, 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 */ +	gadcHighSpeedInit(physdev, frequency, gs->audiobuf, AUDIOBUFSZ, AUDIOBUFSZ/2); +	gadcHighSpeedSetBSem(&gs->bsem, &gs->myEvent); +	gadcHighSpeedStart(); + +	return (GHandle)gs; +} + +void gwinWaitForScopeTrace(GHandle gh) { +	#define 		gs	((GScopeObject *)(gh)) +	int				i; +	coord_t			x, y; +	coord_t			yoffset; +	adcsample_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<<SCOPE_Y_BITS)/2; +	x = gs->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 GADC_BITS_PER_SAMPLE > SCOPE_Y_BITS +			y = yoffset - (*pa++ >> (GADC_BITS_PER_SAMPLE - SCOPE_Y_BITS)); +		#else +			y = yoffset - (*pa++ << (SCOPE_Y_BITS - GADC_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/gadc/gwinosc.h b/demos/modules/gadc/gwinosc.h new file mode 100644 index 00000000..ec44937d --- /dev/null +++ b/demos/modules/gadc/gwinosc.h @@ -0,0 +1,89 @@ +/* +    ChibiOS/GFX - Copyright (C) 2012, 2013 +                 Joel Bodenmann aka Tectu <joel@unormal.org> + +    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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef _GWINOSC_H +#define _GWINOSC_H + +/** + * --------------------------- Our Custom GWIN Oscilloscope --------------- + * + * This GWIN superset implements a simple audio oscilloscope using the GADC high speed device. + */ + +/* The extent of scaling for our audio data - fixed scale at the moment */ +#ifndef SCOPE_Y_BITS +	#define SCOPE_Y_BITS			7					// 7 bits = 0..128 +#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 +	adcsample_t			*audiobuf;				// To store audio samples +	GEventADC			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, uint32_t physdev, 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/gadc/main.c b/demos/modules/gadc/main.c new file mode 100644 index 00000000..07802521 --- /dev/null +++ b/demos/modules/gadc/main.c @@ -0,0 +1,176 @@ +/* +    ChibiOS/GFX - Copyright (C) 2012, 2013 +                 Joel Bodenmann aka Tectu <joel@unormal.org> + +    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 <http://www.gnu.org/licenses/>. +*/ + +/** + * This demo demonstrates the use of the GADC module using it read both a microphone, + * an analogue dial wheel and a temperature sensor. + * The microphone gets read at high frequency to display a very simple oscilloscope. + * The dial and temperature gets read at a low frequency to just print when + * it changes value. + * + * It also demonstrates how to write your own custom GWIN window type. + */ +#include "ch.h" +#include "hal.h" +#include "chprintf.h" + +#include "gfx.h" + +/* Include our custom gwin oscilloscope */ +#include "gwinosc.h" + +/* + * Match these to your hardware + * If you don't have a DIAL device or a TEMP device - just don't define it. + */ +#define MY_MIC_DEVICE		GADC_PHYSDEV_MICROPHONE +#define MY_DIAL_DEVICE		GADC_PHYSDEV_DIAL +#define MY_TEMP_DEVICE		GADC_PHYSDEV_TEMPERATURE +#define MY_DIAL_JITTER		1 +#define MY_TEMP_JITTER		3 + +/* Specify our timing parameters */ +#define	MY_MIC_FREQUENCY	4000			/* 4khz */ +#define MY_LS_DELAY			200				/* 200ms (5 times per second) for the dial and temperature */ + +/* The desired size for our scope window */ +#define SCOPE_CX			64 +#define SCOPE_CY			64 + +/* Data */ +static GScopeObject			gScopeWindow; +static GConsoleObject		gTextWindow; +static GTimer				lsTimer; + +#ifdef MY_DIAL_DEVICE +	static adcsample_t			dialvalue; +	static adcsample_t			lastdial = -(MY_DIAL_JITTER+1); + +	/** +	 * We have got a dial reading - handle it +	 */ +	static void GotDialReading(adcsample_t *buffer, void *param) { +		(void) buffer; + +		/* Buffer should always point to "dialvalue" anyway */ + +		/* Remove jitter from the value */ +		if ((dialvalue > lastdial && dialvalue - lastdial > MY_DIAL_JITTER) +				|| (lastdial > dialvalue && lastdial - dialvalue > MY_DIAL_JITTER)) { + +			/* Write the value */ +			chprintf((BaseSequentialStream *)param, "DIAL: %u\n", dialvalue); + +			/* Save for next time */ +			lastdial = dialvalue; +		} +	} +#endif + +#ifdef MY_TEMP_DEVICE +	static adcsample_t			tempvalue; +	static adcsample_t			lasttemp = -(MY_TEMP_JITTER+1); + +	/** +	 * We have got a temperature reading - handle it +	 */ +	static void GotTempReading(adcsample_t *buffer, void *param) { +		(void) buffer; + +		/* Buffer should always point to "tempvalue" anyway */ + +		/* Remove jitter from the value */ +		if ((tempvalue > lasttemp && tempvalue - lasttemp > MY_TEMP_JITTER) +				|| (lasttemp > tempvalue && lasttemp - tempvalue > MY_TEMP_JITTER)) { + +			/* Write the value */ +			chprintf((BaseSequentialStream *)param, "TEMP: %u\n", tempvalue); + +			/* Save for next time */ +			lasttemp = tempvalue; +		} +	} +#endif + +#if defined(MY_DIAL_DEVICE) || defined(MY_TEMP_DEVICE) +	/** +	 * Start a read of the dial and temperature +	 */ +	static void LowSpeedTimer(void *param) { +		/* We are not checking for an error here - but who cares, this is just a demo */ +		#ifdef MY_DIAL_DEVICE +			gadcLowSpeedStart(MY_DIAL_DEVICE, &dialvalue, GotDialReading, param); +		#endif +		#ifdef MY_TEMP_DEVICE +			gadcLowSpeedStart(MY_TEMP_DEVICE, &tempvalue, GotTempReading, param); +		#endif +	} +#endif + +/* + * Application entry point. + */ +int main(void) { +	GHandle					ghScope; +	coord_t					swidth, sheight; +	#if defined(MY_DIAL_DEVICE) || defined(MY_TEMP_DEVICE) +		GHandle					ghText; +		BaseSequentialStream	*gsText; +		font_t					font; +	#endif + +	halInit(); +	chSysInit(); +	gdispInit(); +	gdispClear(Black); + +	/* Get the screen dimensions */ +	swidth = gdispGetWidth(); +	sheight = gdispGetHeight(); + +	#if defined(MY_DIAL_DEVICE) || defined(MY_TEMP_DEVICE) +		/* Set up the console window we use for dial readings */ +		font = gdispOpenFont("UI2"); +		ghText = gwinCreateConsole(&gTextWindow, 0, 0, swidth-SCOPE_CX, sheight, font); +		gwinSetBgColor(ghText, Black); +		gwinSetColor(ghText, Yellow); +		gwinClear(ghText); +		gsText = gwinGetConsoleStream(ghText); + +		/* Start our timer for reading the dial */ +		gtimerInit(&lsTimer); +		gtimerStart(&lsTimer, LowSpeedTimer, gsText, TRUE, MY_LS_DELAY); +	#endif + +	/* Set up the scope window in the top right on the screen */ +	ghScope = gwinCreateScope(&gScopeWindow, swidth-SCOPE_CX, 0, SCOPE_CX, SCOPE_CY, MY_MIC_DEVICE, MY_MIC_FREQUENCY); +	gwinSetBgColor(ghScope, White); +	gwinSetColor(ghScope, Red); +	gwinClear(ghScope); + +	/* Just keep displaying the scope traces */ +	while (TRUE) { +		/** +		 * The function below internally performs a wait thus giving the timer thread a +		 * chance to run. +		 */ +		gwinWaitForScopeTrace(ghScope); +	} +} diff --git a/demos/modules/gadc/results_264x264.jpg b/demos/modules/gadc/results_264x264.jpg Binary files differnew file mode 100644 index 00000000..25aadf81 --- /dev/null +++ b/demos/modules/gadc/results_264x264.jpg  | 
