GADC implementation with demo program
Also includes driver for AT91SAM7 cpuremotes/origin_old/ugfx_release_2.6
parent
2ed57aea77
commit
9bec5967b2
|
@ -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 */
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @file include/gadc/lld/gadc_lld.c
|
||||
* @brief GADC - Periodic ADC driver source file for the AT91SAM7 cpu.
|
||||
*
|
||||
* @defgroup Driver Driver
|
||||
* @ingroup GADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
#include "gfx.h"
|
||||
|
||||
#if GFX_USE_GADC
|
||||
|
||||
#include "gadc/lld/gadc_lld.h"
|
||||
|
||||
static ADCConversionGroup acg = {
|
||||
FALSE, // circular
|
||||
1, // num_channels
|
||||
GADC_ISR_CompleteI, // end_cb
|
||||
GADC_ISR_ErrorI, // error_cb
|
||||
0, // channelselects
|
||||
0, // trigger
|
||||
0, // frequency
|
||||
};
|
||||
|
||||
void gadc_lld_init(void) {
|
||||
adcStart(&ADCD1, NULL);
|
||||
}
|
||||
|
||||
size_t gadc_lld_samples_per_conversion(uint32_t physdev) {
|
||||
size_t cnt;
|
||||
int i;
|
||||
|
||||
/* The AT91SAM7 has AD0..7 - physdev is a bitmap of those channels */
|
||||
for(cnt = 0, i = 0; i < 8; i++, physdev >>= 1)
|
||||
if (physdev & 0x01)
|
||||
cnt++;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void gadc_lld_start_timer(uint32_t physdev, uint32_t frequency) {
|
||||
(void) physdev;
|
||||
/**
|
||||
* The AT91SAM7 ADC driver supports triggering the ADC using a timer without having to implement
|
||||
* an interrupt handler for the timer. The driver also initialises the timer correctly for us.
|
||||
* Because we aren't trapping the interrupt ourselves we can't increment GADC_Timer_Missed if an
|
||||
* interrupt is missed.
|
||||
*/
|
||||
acg.frequency = frequency;
|
||||
}
|
||||
|
||||
void gadc_lld_stop_timer(uint32_t physdev) {
|
||||
(void) physdev;
|
||||
if ((acg.trigger & ~ADC_TRIGGER_SOFTWARE) == ADC_TRIGGER_TIMER)
|
||||
adcStop(&ADCD1);
|
||||
}
|
||||
|
||||
void gadc_lld_adc_timerI(GadcLldTimerData *pgtd) {
|
||||
/**
|
||||
* We don't need to calculate num_channels because the AT91SAM7 ADC does this for us.
|
||||
*/
|
||||
acg.channelselects = pgtd->physdev;
|
||||
acg.trigger = pgtd->now ? (ADC_TRIGGER_TIMER|ADC_TRIGGER_SOFTWARE) : ADC_TRIGGER_TIMER;
|
||||
|
||||
adcStartConversionI(&ADCD1, &acg, pgtd->buffer, pgtd->count);
|
||||
|
||||
/* Next time assume the same (still running) timer */
|
||||
acg.frequency = 0;
|
||||
}
|
||||
|
||||
void gadc_lld_adc_nontimerI(GadcLldNonTimerData *pgntd) {
|
||||
/**
|
||||
* We don't need to calculate num_channels because the AT91SAM7 ADC does this for us.
|
||||
*/
|
||||
acg.channelselects = pgntd->physdev;
|
||||
acg.trigger = ADC_TRIGGER_SOFTWARE;
|
||||
adcStartConversionI(&ADCD1, &acg, pgntd->buffer, 1);
|
||||
}
|
||||
|
||||
#endif /* GFX_USE_GADC */
|
||||
/** @} */
|
|
@ -0,0 +1,5 @@
|
|||
# List the required driver.
|
||||
GFXSRC += $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.c
|
||||
|
||||
# Required include directories
|
||||
GFXINC += $(GFXLIB)/drivers/gadc/AT91SAM7
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h
|
||||
* @brief GADC Driver config file.
|
||||
*
|
||||
* @addtogroup GADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _GADC_LLD_BOARD_OLIMEXSAM7EX256_H
|
||||
#define _GADC_LLD_BOARD_OLIMEXSAM7EX256_H
|
||||
|
||||
#if GFX_USE_GADC
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Analogue devices on this board */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define GADC_PHYSDEV_MICROPHONE 0x00000080
|
||||
#define GADC_PHYSDEV_DIAL 0x00000040
|
||||
#define GADC_PHYSDEV_TEMPERATURE 0x00000020
|
||||
|
||||
#endif /* GFX_USE_GADC */
|
||||
|
||||
#endif /* _GADC_LLD_BOARD_OLIMEXSAM7EX256_H */
|
||||
/** @} */
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file drivers/gadc/AT91SAM7/gadc_lld_config.h
|
||||
* @brief GADC Driver config file.
|
||||
*
|
||||
* @addtogroup GADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef GADC_LLD_CONFIG_H
|
||||
#define GADC_LLD_CONFIG_H
|
||||
|
||||
#if GFX_USE_GADC
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver hardware support. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief ChibiOS has a nasty bug in its _adc_isr_full_code() routine (defined in adc.h as a macro).
|
||||
* Do we have the version of ChibiOS with this bug.
|
||||
* @detail Set to TRUE if ChibiOS has this bug.
|
||||
* @note Fixed in ChibiOS 2.4.4stable and 2.5.2unstable (and the repository from 18th Feb 2013)
|
||||
* @note This bug prevents us re-calling adcStartConversionI() from with the ISR even though
|
||||
* it is clearly designed to handle it. For some reason (on this micro) the high speed timer
|
||||
* is not affected only the single sample low speed timer. In that situation we wait until
|
||||
* we get back to thread land. This is terrible for the accuracy of the high speed timer
|
||||
* but what can we do (other than fix the bug).
|
||||
* @note For the AT91SAM7 ADC driver, it post-dates the finding of the bug so we safely
|
||||
* say that the bug doesn't exist for this driver.
|
||||
*/
|
||||
#define ADC_ISR_FULL_CODE_BUG FALSE
|
||||
|
||||
/**
|
||||
* @brief The maximum sample frequency supported by this CPU
|
||||
*/
|
||||
#define GADC_MAX_SAMPLE_FREQUENCY 132000
|
||||
|
||||
/**
|
||||
* @brief The number of bits in a sample
|
||||
*/
|
||||
#define GADC_BITS_PER_SAMPLE AT91_ADC1_RESOLUTION
|
||||
|
||||
/* Pull in board specific defines */
|
||||
#if defined(GADC_USE_CUSTOM_BOARD) && GADC_USE_CUSTOM_BOARD
|
||||
/* Include the user supplied board definitions */
|
||||
#include "gadc_lld_board.h"
|
||||
#elif defined(BOARD_OLIMEX_SAM7_EX256)
|
||||
#include "gadc_lld_board_olimexsam7ex256.h"
|
||||
#else
|
||||
/* Include the user supplied board definitions */
|
||||
#include "gadc_lld_board.h"
|
||||
#endif
|
||||
|
||||
#endif /* GFX_USE_GADC */
|
||||
|
||||
#endif /* _GDISP_LLD_CONFIG_H */
|
||||
/** @} */
|
||||
|
|
@ -96,10 +96,8 @@
|
|||
#define GDISP_SCREEN_HEIGHT 240
|
||||
#define GDISP_USE_FSMC
|
||||
#define GDISP_USE_GPIO
|
||||
|
||||
#define TDISP_COLUMNS 16
|
||||
#define TDISP_ROWS 2
|
||||
*/
|
||||
|
||||
#endif /* _GFXCONF_H */
|
||||
|
||||
|
|
|
@ -1,250 +1,258 @@
|
|||
/*
|
||||
ChibiOS/GFX - Copyright (C) 2012
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @file include/gadc/gadc.h
|
||||
* @brief GADC - Periodic ADC subsystem header file.
|
||||
*
|
||||
* @addtogroup GADC
|
||||
*
|
||||
* @details The reason why ChibiOS/GFX has it's own ADC abstraction is because
|
||||
* the Chibi-OS drivers are very CPU specific and do not
|
||||
* provide a way across all hardware platforms to create periodic
|
||||
* ADC conversions. There are also issues with devices with different
|
||||
* characteristics or periodic requirements on the same ADC
|
||||
* device (but different channels). This layer attempts to solve these
|
||||
* problems to provide a architecture neutral API. It also provides extra
|
||||
* features such as multi-buffer chaining for high speed ADC sources.
|
||||
* It provides one high speed virtual ADC device (eg a microphone) and
|
||||
* numerous low speed (less than 100Hz) virtual ADC devices (eg dials,
|
||||
* temperature sensors etc). The high speed device has timer based polling
|
||||
* to ensure exact conversion periods and a buffer management system.
|
||||
* The low speed devices are assumed to be non-critical timing devices
|
||||
* and do not have any buffer management.
|
||||
* Note that while only one high speed device has been provided it can
|
||||
* be used to read multiple physical ADC channels on the one physical
|
||||
* ADC device.
|
||||
* All callback routines are thread based unlike the Chibi-OS interrupt based
|
||||
* routines.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _GADC_H
|
||||
#define _GADC_H
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
#if GFX_USE_GADC || defined(__DOXYGEN__)
|
||||
|
||||
/* Include the driver defines */
|
||||
#include "gadc_lld_config.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Type definitions */
|
||||
/*===========================================================================*/
|
||||
|
||||
// Event types for GADC
|
||||
#define GEVENT_ADC (GEVENT_GADC_FIRST+0)
|
||||
|
||||
/**
|
||||
* @brief The High Speed ADC event structure.
|
||||
* @{
|
||||
*/
|
||||
typedef struct GEventADC_t {
|
||||
/**
|
||||
* @brief The type of this event (GEVENT_ADC)
|
||||
*/
|
||||
GEventType type;
|
||||
/**
|
||||
* @brief The event flags
|
||||
*/
|
||||
uint16_t flags;
|
||||
/**
|
||||
* @brief The event flag values.
|
||||
* @{
|
||||
*/
|
||||
#define GADC_HSADC_LOSTEVENT 0x0001 /**< @brief The last GEVENT_HSDADC event was lost */
|
||||
/** @} */
|
||||
/**
|
||||
* @brief The number of conversions in the buffer
|
||||
*/
|
||||
size_t count;
|
||||
/**
|
||||
* @brief The buffer containing the conversion samples
|
||||
*/
|
||||
adcsample_t *buffer;
|
||||
} GEventADC;
|
||||
|
||||
/**
|
||||
* @brief A callback function (executed in a thread context)
|
||||
*/
|
||||
typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param);
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialise the high speed ADC.
|
||||
* @details Initialises but does not start the conversions.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
* @param[in] frequency The frequency to create ADC conversions
|
||||
* @param[in] buffer The static buffer to put the ADC 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 high speed ADC is running it will be stopped.
|
||||
* @note Due to a bug 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'
|
||||
* and 'countPerEvent' parameters describe the number of conversions not the
|
||||
* number of samples.
|
||||
* As an example, if physdev turns on 2 devices then the buffer contains
|
||||
* alternate device samples and the buffer must contain 2 * bufcount samples.
|
||||
* The exact meaning of physdev is hardware dependent.
|
||||
* @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.
|
||||
* @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).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcHighSpeedInit(uint32_t physdev, 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_ADC events.
|
||||
*
|
||||
* @note The high speed ADC 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 the high speed ADC.
|
||||
* Once turned on it cannot be turned off.
|
||||
* @note The high speed ADC is capable of signalling via this method and a binary semaphore
|
||||
* at the same time.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
GSourceHandle gadcHighSpeedGetSource(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Allow retrieving of results from the high speed ADC 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 high speed ADC is capable of signalling via this method and the GEVENT
|
||||
* sub-system at the same time.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcHighSpeedSetBSem(BinarySemaphore *pbsem, GEventADC *pEvent);
|
||||
|
||||
/**
|
||||
* @brief Start the high speed ADC conversions.
|
||||
* @pre It must have been initialised first with @p gadcHighSpeedInit()
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
GSourceHandle gadcHighSpeedStart(void);
|
||||
|
||||
/**
|
||||
* @brief Stop the high speed ADC conversions.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcHighSpeedStop(void);
|
||||
|
||||
/**
|
||||
* @brief Perform a single low speed ADC conversion
|
||||
* @details Blocks until the conversion is complete
|
||||
* @pre This should not be called from within a GTimer callback as this routine
|
||||
* blocks until the conversion is ready.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
* @param[in] buffer The static buffer to put the ADC samples into.
|
||||
*
|
||||
* @note This may take a while to complete if the high speed ADC is running as the
|
||||
* conversion is interleaved with the high speed ADC conversions on a buffer
|
||||
* completion.
|
||||
* @note The result buffer must be large enough to store one sample per device
|
||||
* described by the 'physdev' parameter.
|
||||
* @note If calling this routine would exceed @p GADC_MAX_LOWSPEED_DEVICES simultaneous low
|
||||
* speed devices, the routine will wait for an available slot to complete the
|
||||
* conversion.
|
||||
* @note Specifying more than one device in physdev is possible but discouraged as the
|
||||
* calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
|
||||
* from over-running the high speed ADC include high speed samples being lost.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer);
|
||||
|
||||
/**
|
||||
* @brief Perform a low speed ADC conversion with callback (in a thread context)
|
||||
* @details Returns FALSE if there are no free low speed ADC slots. See @p GADC_MAX_LOWSPEED_DEVICES for details.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
* @param[in] buffer The static buffer to put the ADC samples into.
|
||||
* @param[in] fn The callback function to call when the conversion is complete.
|
||||
* @param[in] param A parameter to pass to the callback function.
|
||||
*
|
||||
* @note This may be safely called from within a GTimer callback.
|
||||
* @note The callback may take a while to occur if the high speed ADC is running as the
|
||||
* conversion is interleaved with the high speed ADC conversions on a buffer
|
||||
* completion.
|
||||
* @note The result buffer must be large enough to store one sample per device
|
||||
* described by the 'physdev' parameter.
|
||||
* @note As this routine uses a low speed ADC, it asserts if you try to run more than @p GADC_MAX_LOWSPEED_DEVICES
|
||||
* at the same time.
|
||||
* @note Specifying more than one device in physdev is possible but discouraged as the
|
||||
* calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
|
||||
* from over-running the high speed ADC include high speed samples being lost.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GFX_USE_GADC */
|
||||
|
||||
#endif /* _GADC_H */
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @file include/gadc/gadc.h
|
||||
* @brief GADC - Periodic ADC subsystem header file.
|
||||
*
|
||||
* @addtogroup GADC
|
||||
*
|
||||
* @details The reason why ChibiOS/GFX has it's own ADC abstraction is because
|
||||
* the Chibi-OS drivers are very CPU specific and do not
|
||||
* provide a way across all hardware platforms to create periodic
|
||||
* ADC conversions. There are also issues with devices with different
|
||||
* characteristics or periodic requirements on the same ADC
|
||||
* device (but different channels). This layer attempts to solve these
|
||||
* problems to provide a architecture neutral API. It also provides extra
|
||||
* features such as multi-buffer chaining for high speed ADC sources.
|
||||
* It provides one high speed virtual ADC device (eg a microphone) and
|
||||
* numerous low speed (less than 100Hz) virtual ADC devices (eg dials,
|
||||
* temperature sensors etc). The high speed device has timer based polling
|
||||
* to ensure exact conversion periods and a buffer management system.
|
||||
* The low speed devices are assumed to be non-critical timing devices
|
||||
* and do not have any buffer management.
|
||||
* Note that while only one high speed device has been provided it can
|
||||
* be used to read multiple physical ADC channels on the one physical
|
||||
* ADC device.
|
||||
* All callback routines are thread based unlike the Chibi-OS interrupt based
|
||||
* routines.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _GADC_H
|
||||
#define _GADC_H
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
#if GFX_USE_GADC || defined(__DOXYGEN__)
|
||||
|
||||
/* Include the driver defines */
|
||||
#include "gadc_lld_config.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Type definitions */
|
||||
/*===========================================================================*/
|
||||
|
||||
// Event types for GADC
|
||||
#define GEVENT_ADC (GEVENT_GADC_FIRST+0)
|
||||
|
||||
/**
|
||||
* @brief The High Speed ADC event structure.
|
||||
* @{
|
||||
*/
|
||||
typedef struct GEventADC_t {
|
||||
#if GFX_USE_GEVENT || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief The type of this event (GEVENT_ADC)
|
||||
*/
|
||||
GEventType type;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The event flags
|
||||
*/
|
||||
uint16_t flags;
|
||||
/**
|
||||
* @brief The event flag values.
|
||||
* @{
|
||||
*/
|
||||
#define GADC_HSADC_LOSTEVENT 0x0001 /**< @brief The last GEVENT_HSDADC event was lost */
|
||||
/** @} */
|
||||
/**
|
||||
* @brief The number of conversions in the buffer
|
||||
*/
|
||||
size_t count;
|
||||
/**
|
||||
* @brief The buffer containing the conversion samples
|
||||
*/
|
||||
adcsample_t *buffer;
|
||||
} GEventADC;
|
||||
|
||||
/**
|
||||
* @brief A callback function (executed in a thread context)
|
||||
*/
|
||||
typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param);
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialise the high speed ADC.
|
||||
* @details Initialises but does not start the conversions.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
* @param[in] frequency The frequency to create ADC conversions
|
||||
* @param[in] buffer The static buffer to put the ADC 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 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
|
||||
* to process the old data.
|
||||
* @note Due to a bug 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'
|
||||
* and 'countPerEvent' parameters describe the number of conversions not the
|
||||
* number of samples.
|
||||
* As an example, if physdev turns on 2 devices then the buffer contains
|
||||
* alternate device samples and the buffer must contain 2 * bufcount samples.
|
||||
* The exact meaning of physdev is hardware dependent.
|
||||
* @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.
|
||||
* @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).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcHighSpeedInit(uint32_t physdev, 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_ADC events.
|
||||
*
|
||||
* @note The high speed ADC 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 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.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
GSourceHandle gadcHighSpeedGetSource(void);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Allow retrieving of results from the high speed ADC 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 as will calling
|
||||
* @p gadcHighSpeedInit().
|
||||
* @note The high speed ADC is capable of signalling via this method and the GEVENT
|
||||
* sub-system at the same time.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcHighSpeedSetBSem(BinarySemaphore *pbsem, GEventADC *pEvent);
|
||||
|
||||
/**
|
||||
* @brief Start the high speed ADC conversions.
|
||||
* @pre It must have been initialised first with @p gadcHighSpeedInit()
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcHighSpeedStart(void);
|
||||
|
||||
/**
|
||||
* @brief Stop the high speed ADC conversions.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcHighSpeedStop(void);
|
||||
|
||||
/**
|
||||
* @brief Perform a single low speed ADC conversion
|
||||
* @details Blocks until the conversion is complete
|
||||
* @pre This should not be called from within a GTimer callback as this routine
|
||||
* blocks until the conversion is ready.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
* @param[in] buffer The static buffer to put the ADC samples into.
|
||||
*
|
||||
* @note This may take a while to complete if the high speed ADC is running as the
|
||||
* conversion is interleaved with the high speed ADC conversions on a buffer
|
||||
* completion.
|
||||
* @note The result buffer must be large enough to store one sample per device
|
||||
* described by the 'physdev' parameter.
|
||||
* @note If calling this routine would exceed @p GADC_MAX_LOWSPEED_DEVICES simultaneous low
|
||||
* speed devices, the routine will wait for an available slot to complete the
|
||||
* conversion.
|
||||
* @note Specifying more than one device in physdev is possible but discouraged as the
|
||||
* calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
|
||||
* from over-running the high speed ADC include high speed samples being lost.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer);
|
||||
|
||||
/**
|
||||
* @brief Perform a low speed ADC conversion with callback (in a thread context)
|
||||
* @details Returns FALSE if there are no free low speed ADC slots. See @p GADC_MAX_LOWSPEED_DEVICES for details.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
* @param[in] buffer The static buffer to put the ADC samples into.
|
||||
* @param[in] fn The callback function to call when the conversion is complete.
|
||||
* @param[in] param A parameter to pass to the callback function.
|
||||
*
|
||||
* @note This may be safely called from within a GTimer callback.
|
||||
* @note The callback may take a while to occur if the high speed ADC is running as the
|
||||
* conversion is interleaved with the high speed ADC conversions on a buffer
|
||||
* completion.
|
||||
* @note The result buffer must be large enough to store one sample per device
|
||||
* described by the 'physdev' parameter.
|
||||
* @note As this routine uses a low speed ADC, it asserts if you try to run more than @p GADC_MAX_LOWSPEED_DEVICES
|
||||
* at the same time.
|
||||
* @note Specifying more than one device in physdev is possible but discouraged as the
|
||||
* calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
|
||||
* from over-running the high speed ADC include high speed samples being lost.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GFX_USE_GADC */
|
||||
|
||||
#endif /* _GADC_H */
|
||||
/** @} */
|
||||
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* @file include/gadc/lld/gadc_lld.h
|
||||
* @brief GADC - Periodic ADC driver header file.
|
||||
*
|
||||
* @defgroup Driver Driver
|
||||
* @ingroup GADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _GADC_LLD_H
|
||||
#define _GADC_LLD_H
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
#if GFX_USE_GADC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Type definitions */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief The structure passed to start a timer conversion
|
||||
* @note We use the structure instead of parameters purely to save
|
||||
* interrupt stack space which is very limited in some platforms.
|
||||
* @{
|
||||
*/
|
||||
typedef struct GadcLldTimerData_t {
|
||||
uint32_t physdev; /* @< A value passed to describe which physical ADC devices/channels to use. */
|
||||
adcsample_t *buffer; /* @< The static buffer to put the ADC samples into. */
|
||||
size_t count; /* @< The number of conversions to do before doing a callback and stopping the ADC. */
|
||||
bool_t now; /* @< Trigger the first conversion now rather than waiting for the first timer interrupt (if possible) */
|
||||
} GadcLldTimerData;
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* @brief The structure passed to start a non-timer conversion
|
||||
* @note We use the structure instead of parameters purely to save
|
||||
* interrupt stack space which is very limited in some platforms.
|
||||
* @{
|
||||
*/
|
||||
typedef struct GadcLldNonTimerData_t {
|
||||
uint32_t physdev; /* @< A value passed to describe which physical ADC devices/channels to use. */
|
||||
adcsample_t *buffer; /* @< The static buffer to put the ADC samples into. */
|
||||
} GadcLldNonTimerData;
|
||||
/* @} */
|
||||
|
||||
/**
|
||||
* @brief These routines are the callbacks that the driver uses.
|
||||
* @details Defined in the high level GADC code.
|
||||
*
|
||||
* @notapi
|
||||
* @{
|
||||
*/
|
||||
extern void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n);
|
||||
extern void GADC_ISR_ErrorI(ADCDriver *adcp, adcerror_t err);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief This can be incremented by the low level driver if a timer interrupt is missed.
|
||||
* @details Defined in the high level GADC code.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
extern volatile bool_t GADC_Timer_Missed;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialise the driver
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadc_lld_init(void);
|
||||
|
||||
/**
|
||||
* @brief Get the number of samples in a conversion.
|
||||
* @details Calculates and returns the number of samples per conversion for the specified physdev.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
*
|
||||
* @note A physdev describing a mono device would return 1, a stereo device would return 2.
|
||||
* For most ADC's physdev is a bitmap so it is only a matter of counting the bits.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
size_t gadc_lld_samples_per_conversion(uint32_t physdev);
|
||||
|
||||
/**
|
||||
* @brief Start a periodic timer for high frequency conversions.
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
|
||||
* @param[in] frequency The frequency to create ADC conversions
|
||||
*
|
||||
* @note The exact meaning of physdev is hardware dependent. It describes the channels
|
||||
* the will be used later on when a "timer" conversion is actually scheduled.
|
||||
* @note It is assumed that the timer is capable of free-running even when the ADC
|
||||
* is stopped or doing something else.
|
||||
* @details When a timer interrupt occurs a conversion should start if these is a "timer" conversion
|
||||
* active.
|
||||
* @note If the ADC is stopped, doesn't have a "timer" conversion active or is currently executing
|
||||
* a non-timer conversion then the interrupt can be ignored other than (optionally) incrementing
|
||||
* the GADC_Timer_Missed variable.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadc_lld_start_timer(uint32_t physdev, uint32_t frequency);
|
||||
|
||||
/**
|
||||
* @brief Stop the periodic timer for high frequency conversions.
|
||||
* @details Also stops any current "timer" conversion (but not a current "non-timer" conversion).
|
||||
*
|
||||
* @param[in] physdev A value passed to describe which physical ADC devices/channels in use.
|
||||
*
|
||||
* @note The exact meaning of physdev is hardware dependent.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gadc_lld_stop_timer(uint32_t physdev);
|
||||
|
||||
/**
|
||||