2013-05-01 23:53:28 +00:00
|
|
|
/*
|
2013-06-15 11:37:22 +00:00
|
|
|
* This file is subject to the terms of the GFX License. If a copy of
|
2013-05-03 14:36:17 +00:00
|
|
|
* the license was not distributed with this file, you can obtain one at:
|
|
|
|
*
|
2013-07-21 20:20:37 +00:00
|
|
|
* http://ugfx.org/license.html
|
2013-05-03 14:36:17 +00:00
|
|
|
*/
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @file src/gadc/gadc.c
|
|
|
|
* @brief GADC sub-system code.
|
|
|
|
*
|
|
|
|
* @addtogroup GADC
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
#include "gfx.h"
|
|
|
|
|
|
|
|
#if GFX_USE_GADC
|
|
|
|
|
|
|
|
/* Include the driver defines */
|
2014-02-18 14:36:52 +00:00
|
|
|
#include "src/gadc/driver.h"
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
#if GADC_MAX_HIGH_SPEED_SAMPLERATE > GADC_MAX_SAMPLE_FREQUENCY/2
|
|
|
|
#error "GADC: GADC_MAX_HIGH_SPEED_SAMPLERATE has been set too high. It must be less than half the maximum CPU rate"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define GADC_MAX_LOWSPEED_DEVICES ((GADC_MAX_SAMPLE_FREQUENCY/GADC_MAX_HIGH_SPEED_SAMPLERATE)-1)
|
|
|
|
#if GADC_MAX_LOWSPEED_DEVICES > 4
|
|
|
|
#undef GADC_MAX_LOWSPEED_DEVICES
|
|
|
|
#define GADC_MAX_LOWSPEED_DEVICES 4
|
|
|
|
#endif
|
|
|
|
|
|
|
|
volatile bool_t GADC_Timer_Missed;
|
|
|
|
|
2013-05-24 15:26:52 +00:00
|
|
|
static gfxSem gadcsem;
|
|
|
|
static gfxMutex gadcmutex;
|
|
|
|
static GTimer LowSpeedGTimer;
|
2013-02-18 07:33:35 +00:00
|
|
|
#if GFX_USE_GEVENT
|
2013-05-24 15:26:52 +00:00
|
|
|
static GTimer HighSpeedGTimer;
|
2013-02-18 07:33:35 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static volatile uint16_t gflags = 0;
|
2013-05-24 15:26:52 +00:00
|
|
|
#define GADC_GFLG_ISACTIVE 0x0001
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
#define GADC_FLG_ISACTIVE 0x0001
|
|
|
|
#define GADC_FLG_ISDONE 0x0002
|
|
|
|
#define GADC_FLG_ERROR 0x0004
|
|
|
|
#define GADC_FLG_GTIMER 0x0008
|
|
|
|
|
|
|
|
static struct hsdev {
|
|
|
|
// Our status flags
|
|
|
|
uint16_t flags;
|
|
|
|
|
|
|
|
// What we started with
|
|
|
|
uint32_t frequency;
|
|
|
|
adcsample_t *buffer;
|
|
|
|
size_t bufcount;
|
|
|
|
size_t samplesPerEvent;
|
|
|
|
|
|
|
|
// The last set of results
|
|
|
|
size_t lastcount;
|
|
|
|
adcsample_t *lastbuffer;
|
|
|
|
uint16_t lastflags;
|
|
|
|
|
2013-05-24 15:26:52 +00:00
|
|
|
// Other stuff we need to track progress and for signaling
|
2013-02-18 07:33:35 +00:00
|
|
|
GadcLldTimerData lld;
|
|
|
|
size_t samplesPerConversion;
|
|
|
|
size_t remaining;
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSem *bsem;
|
2013-02-18 07:33:35 +00:00
|
|
|
GEventADC *pEvent;
|
2013-02-28 23:04:52 +00:00
|
|
|
GADCISRCallbackFunction isrfn;
|
2013-02-18 07:33:35 +00:00
|
|
|
} hs;
|
|
|
|
|
|
|
|
static struct lsdev {
|
|
|
|
// Our status flags
|
|
|
|
uint16_t flags;
|
|
|
|
|
|
|
|
// What we started with
|
|
|
|
GadcLldNonTimerData lld;
|
|
|
|
GADCCallbackFunction fn;
|
|
|
|
void *param;
|
|
|
|
} ls[GADC_MAX_LOWSPEED_DEVICES];
|
|
|
|
|
|
|
|
static struct lsdev *curlsdev;
|
|
|
|
|
|
|
|
/* Find the next conversion to activate */
|
2013-03-04 22:50:21 +00:00
|
|
|
static inline void FindNextConversionI(void) {
|
2013-02-18 07:33:35 +00:00
|
|
|
if (curlsdev) {
|
|
|
|
/**
|
|
|
|
* Now we have done a low speed conversion - start looking for the next conversion
|
|
|
|
* We only look forward to ensure we get a high speed conversion at least once
|
|
|
|
* every GADC_MAX_LOWSPEED_DEVICES conversions.
|
|
|
|
*/
|
|
|
|
curlsdev++;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* Now we have done a high speed conversion - start looking for low speed conversions */
|
|
|
|
curlsdev = ls;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Look for the next thing to do.
|
|
|
|
*/
|
|
|
|
while(curlsdev < &ls[GADC_MAX_LOWSPEED_DEVICES]) {
|
|
|
|
if ((curlsdev->flags & (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) == GADC_FLG_ISACTIVE) {
|
|
|
|
gadc_lld_adc_nontimerI(&curlsdev->lld);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
curlsdev++;
|
|
|
|
}
|
|
|
|
curlsdev = 0;
|
|
|
|
|
|
|
|
/* No more low speed devices - do a high speed conversion */
|
|
|
|
if (hs.flags & GADC_FLG_ISACTIVE) {
|
|
|
|
hs.lld.now = GADC_Timer_Missed ? TRUE : FALSE;
|
|
|
|
GADC_Timer_Missed = 0;
|
|
|
|
gadc_lld_adc_timerI(&hs.lld);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Nothing more to do */
|
|
|
|
gflags &= ~GADC_GFLG_ISACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
|
|
|
|
(void) adcp;
|
|
|
|
|
|
|
|
if (curlsdev) {
|
|
|
|
/* This interrupt must be in relation to the low speed device */
|
|
|
|
|
|
|
|
if (curlsdev->flags & GADC_FLG_ISACTIVE) {
|
|
|
|
/**
|
|
|
|
* As we only handle a single low speed conversion at a time, we know
|
|
|
|
* we know we won't get any half completion interrupts.
|
|
|
|
*/
|
|
|
|
curlsdev->flags |= GADC_FLG_ISDONE;
|
|
|
|
gtimerJabI(&LowSpeedGTimer);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if ADC_ISR_FULL_CODE_BUG
|
|
|
|
/**
|
|
|
|
* Oops - We have just finished a low speed conversion but a bug prevents us
|
|
|
|
* restarting the ADC here. Other code will restart it in the thread based
|
|
|
|
* ADC handler.
|
|
|
|
*/
|
|
|
|
gflags &= ~GADC_GFLG_ISACTIVE;
|
|
|
|
return;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* This interrupt must be in relation to the high speed device */
|
|
|
|
|
|
|
|
if (hs.flags & GADC_FLG_ISACTIVE) {
|
|
|
|
/* Save the details */
|
|
|
|
hs.lastcount = n;
|
|
|
|
hs.lastbuffer = buffer;
|
|
|
|
hs.lastflags = GADC_Timer_Missed ? GADC_HSADC_LOSTEVENT : 0;
|
|
|
|
|
|
|
|
/* Signal the user with the data */
|
|
|
|
if (hs.pEvent) {
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
hs.pEvent->type = GEVENT_ADC;
|
|
|
|
#endif
|
|
|
|
hs.pEvent->count = hs.lastcount;
|
|
|
|
hs.pEvent->buffer = hs.lastbuffer;
|
|
|
|
hs.pEvent->flags = hs.lastflags;
|
|
|
|
}
|
2013-02-28 23:04:52 +00:00
|
|
|
|
|
|
|
/* Our three signalling mechanisms */
|
|
|
|
if (hs.isrfn)
|
|
|
|
hs.isrfn(buffer, n);
|
|
|
|
|
2013-02-18 07:33:35 +00:00
|
|
|
if (hs.bsem)
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSemSignalI(hs.bsem);
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
if (hs.flags & GADC_FLG_GTIMER)
|
|
|
|
gtimerJabI(&HighSpeedGTimer);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Adjust what we have left to do */
|
|
|
|
hs.lld.count -= n;
|
|
|
|
hs.remaining -= n;
|
|
|
|
|
|
|
|
/* Half completion - We have done all we can for now - wait for the next interrupt */
|
|
|
|
if (hs.lld.count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Our buffer is cyclic - set up the new buffer pointers */
|
|
|
|
if (hs.remaining) {
|
|
|
|
hs.lld.buffer = buffer + (n * hs.samplesPerConversion);
|
|
|
|
} else {
|
|
|
|
hs.remaining = hs.bufcount;
|
|
|
|
hs.lld.buffer = hs.buffer;
|
|
|
|
}
|
|
|
|
hs.lld.count = hs.remaining < hs.samplesPerEvent ? hs.remaining : hs.samplesPerEvent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Look for the next thing to do.
|
|
|
|
*/
|
|
|
|
FindNextConversionI();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GADC_ISR_ErrorI(ADCDriver *adcp, adcerror_t err) {
|
|
|
|
(void) adcp;
|
|
|
|
(void) err;
|
|
|
|
|
|
|
|
if (curlsdev) {
|
|
|
|
if ((curlsdev->flags & (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) == GADC_FLG_ISACTIVE)
|
|
|
|
/* Mark the error then try to repeat it */
|
|
|
|
curlsdev->flags |= GADC_FLG_ERROR;
|
|
|
|
|
|
|
|
#if ADC_ISR_FULL_CODE_BUG
|
|
|
|
/**
|
|
|
|
* Oops - We have just finished a low speed conversion but a bug prevents us
|
|
|
|
* restarting the ADC here. Other code will restart it in the thread based
|
|
|
|
* ADC handler.
|
|
|
|
*/
|
|
|
|
gflags &= ~GADC_GFLG_ISACTIVE;
|
|
|
|
gtimerJabI(&LowSpeedGTimer);
|
|
|
|
return;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (hs.flags & GADC_FLG_ISACTIVE)
|
|
|
|
/* Mark the error and then try to repeat it */
|
|
|
|
hs.flags |= GADC_FLG_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Start the next conversion */
|
|
|
|
FindNextConversionI();
|
|
|
|
}
|
|
|
|
|
2013-05-24 15:26:52 +00:00
|
|
|
/* Our module initialiser */
|
2014-02-02 18:24:43 +00:00
|
|
|
void _gadcInit(void)
|
|
|
|
{
|
2013-05-24 15:26:52 +00:00
|
|
|
gadc_lld_init();
|
|
|
|
gfxSemInit(&gadcsem, GADC_MAX_LOWSPEED_DEVICES, GADC_MAX_LOWSPEED_DEVICES);
|
|
|
|
gfxMutexInit(&gadcmutex);
|
|
|
|
gtimerInit(&LowSpeedGTimer);
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
gtimerInit(&HighSpeedGTimer);
|
|
|
|
#endif
|
2013-02-18 07:33:35 +00:00
|
|
|
}
|
|
|
|
|
2014-02-02 18:24:43 +00:00
|
|
|
void _gadcDeinit(void)
|
|
|
|
{
|
2014-02-02 18:52:46 +00:00
|
|
|
/* commented stuff is ToDo */
|
|
|
|
|
|
|
|
// gadc_lld_deinit();
|
|
|
|
gfxSemDestroy(&gadcsem);
|
|
|
|
gfxMutexDestroy(&gadcmutex);
|
2014-02-02 18:55:20 +00:00
|
|
|
gtimerDeinit(&LowSpeedGTimer);
|
2014-02-02 18:52:46 +00:00
|
|
|
#if GFX_USE_GEVENT
|
2014-02-02 18:55:20 +00:00
|
|
|
gtimerDeinit(&HighSpeedGTimer);
|
2014-02-02 18:52:46 +00:00
|
|
|
#endif
|
2014-02-02 18:24:43 +00:00
|
|
|
}
|
|
|
|
|
2013-03-04 22:50:21 +00:00
|
|
|
static inline void StartADC(bool_t onNoHS) {
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSystemLock();
|
2013-02-18 07:33:35 +00:00
|
|
|
if (!(gflags & GADC_GFLG_ISACTIVE) || (onNoHS && !curlsdev))
|
|
|
|
FindNextConversionI();
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSystemUnlock();
|
2013-02-18 07:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void BSemSignalCallback(adcsample_t *buffer, void *param) {
|
|
|
|
(void) buffer;
|
|
|
|
|
|
|
|
/* Signal the BinarySemaphore parameter */
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSemSignal((gfxSem *)param);
|
2013-02-18 07:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
static void HighSpeedGTimerCallback(void *param) {
|
|
|
|
(void) param;
|
|
|
|
GSourceListener *psl;
|
|
|
|
GEventADC *pe;
|
|
|
|
|
|
|
|
psl = 0;
|
|
|
|
while ((psl = geventGetSourceListener((GSourceHandle)(&HighSpeedGTimer), psl))) {
|
|
|
|
if (!(pe = (GEventADC *)geventGetEventBuffer(psl))) {
|
|
|
|
// This listener is missing - save this.
|
|
|
|
psl->srcflags |= GADC_HSADC_LOSTEVENT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
pe->type = GEVENT_ADC;
|
|
|
|
pe->count = hs.lastcount;
|
|
|
|
pe->buffer = hs.lastbuffer;
|
|
|
|
pe->flags = hs.lastflags | psl->srcflags;
|
|
|
|
psl->srcflags = 0;
|
|
|
|
geventSendEvent(psl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void LowSpeedGTimerCallback(void *param) {
|
|
|
|
(void) param;
|
|
|
|
GADCCallbackFunction fn;
|
|
|
|
void *prm;
|
|
|
|
adcsample_t *buffer;
|
|
|
|
struct lsdev *p;
|
|
|
|
|
|
|
|
#if ADC_ISR_FULL_CODE_BUG
|
|
|
|
/* Ensure the ADC is running if it needs to be - Bugfix HACK */
|
|
|
|
StartADC(FALSE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Look for completed low speed timers.
|
|
|
|
* We don't need to take the mutex as we are the only place that things are freed and we
|
|
|
|
* do that atomically.
|
|
|
|
*/
|
|
|
|
for(p=ls; p < &ls[GADC_MAX_LOWSPEED_DEVICES]; p++) {
|
|
|
|
if ((p->flags & (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) == (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) {
|
|
|
|
/* This item is done - perform its callback */
|
|
|
|
fn = p->fn; // Save the callback details
|
|
|
|
prm = p->param;
|
|
|
|
buffer = p->lld.buffer;
|
|
|
|
p->fn = 0; // Needed to prevent the compiler removing the local variables
|
|
|
|
p->param = 0; // Needed to prevent the compiler removing the local variables
|
|
|
|
p->lld.buffer = 0; // Needed to prevent the compiler removing the local variables
|
|
|
|
p->flags = 0; // The slot is available (indivisible operation)
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSemSignal(&gadcsem); // Tell everyone
|
2013-02-18 07:33:35 +00:00
|
|
|
fn(buffer, prm); // Perform the callback
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent)
|
|
|
|
{
|
|
|
|
gadcHighSpeedStop(); /* This does the init for us */
|
|
|
|
|
|
|
|
/* Just save the details and reset everything for now */
|
|
|
|
hs.frequency = frequency;
|
|
|
|
hs.buffer = buffer;
|
|
|
|
hs.bufcount = bufcount;
|
|
|
|
hs.samplesPerEvent = samplesPerEvent;
|
|
|
|
hs.lastcount = 0;
|
|
|
|
hs.lastbuffer = 0;
|
|
|
|
hs.lastflags = 0;
|
|
|
|
hs.lld.physdev = physdev;
|
|
|
|
hs.lld.buffer = buffer;
|
|
|
|
hs.lld.count = samplesPerEvent;
|
|
|
|
hs.lld.now = FALSE;
|
|
|
|
hs.samplesPerConversion = gadc_lld_samples_per_conversion(physdev);
|
|
|
|
hs.remaining = bufcount;
|
|
|
|
hs.bsem = 0;
|
|
|
|
hs.pEvent = 0;
|
2013-02-28 23:04:52 +00:00
|
|
|
hs.isrfn = 0;
|
2013-02-18 07:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if GFX_USE_GEVENT
|
|
|
|
GSourceHandle gadcHighSpeedGetSource(void) {
|
|
|
|
if (!gtimerIsActive(&HighSpeedGTimer))
|
2013-12-21 03:21:59 +00:00
|
|
|
gtimerStart(&HighSpeedGTimer, HighSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
|
2013-02-18 07:33:35 +00:00
|
|
|
hs.flags |= GADC_FLG_GTIMER;
|
|
|
|
return (GSourceHandle)&HighSpeedGTimer;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-02-28 23:04:52 +00:00
|
|
|
void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn) {
|
|
|
|
hs.isrfn = isrfn;
|
|
|
|
}
|
|
|
|
|
2013-05-24 15:26:52 +00:00
|
|
|
void gadcHighSpeedSetBSem(gfxSem *pbsem, GEventADC *pEvent) {
|
2013-02-18 07:33:35 +00:00
|
|
|
/* Use the system lock to ensure they occur atomically */
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSystemLock();
|
2013-02-18 07:33:35 +00:00
|
|
|
hs.pEvent = pEvent;
|
|
|
|
hs.bsem = pbsem;
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSystemUnlock();
|
2013-02-18 07:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void gadcHighSpeedStart(void) {
|
|
|
|
/* If its already going we don't need to do anything */
|
|
|
|
if (hs.flags & GADC_FLG_ISACTIVE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gadc_lld_start_timer(hs.lld.physdev, hs.frequency);
|
|
|
|
hs.flags = GADC_FLG_ISACTIVE;
|
|
|
|
StartADC(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gadcHighSpeedStop(void) {
|
|
|
|
if (hs.flags & GADC_FLG_ISACTIVE) {
|
|
|
|
/* No more from us */
|
|
|
|
hs.flags = 0;
|
|
|
|
gadc_lld_stop_timer(hs.lld.physdev);
|
|
|
|
/*
|
|
|
|
* We have to pass TRUE to StartADC() as we might have the ADC marked as active when it isn't
|
|
|
|
* due to stopping the timer while it was converting.
|
|
|
|
*/
|
|
|
|
StartADC(TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer) {
|
2013-05-24 15:26:52 +00:00
|
|
|
struct lsdev *p;
|
|
|
|
gfxSem mysem;
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
/* Start the Low Speed Timer */
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSemInit(&mysem, 1, 1);
|
|
|
|
gfxMutexEnter(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
if (!gtimerIsActive(&LowSpeedGTimer))
|
2013-12-21 03:21:59 +00:00
|
|
|
gtimerStart(&LowSpeedGTimer, LowSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxMutexExit(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
while(1) {
|
|
|
|
/* Wait for an available slot */
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSemWait(&gadcsem, TIME_INFINITE);
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
/* Find a slot */
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxMutexEnter(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
for(p = ls; p < &ls[GADC_MAX_LOWSPEED_DEVICES]; p++) {
|
|
|
|
if (!(p->flags & GADC_FLG_ISACTIVE)) {
|
|
|
|
p->lld.physdev = physdev;
|
|
|
|
p->lld.buffer = buffer;
|
|
|
|
p->fn = BSemSignalCallback;
|
|
|
|
p->param = &mysem;
|
|
|
|
p->flags = GADC_FLG_ISACTIVE;
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxMutexExit(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
StartADC(FALSE);
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSemWait(&mysem, TIME_INFINITE);
|
2013-02-18 07:33:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxMutexExit(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* We should never get here - the count semaphore must be wrong.
|
|
|
|
* Decrement it and try again.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param) {
|
|
|
|
struct lsdev *p;
|
|
|
|
|
|
|
|
/* Start the Low Speed Timer */
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxMutexEnter(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
if (!gtimerIsActive(&LowSpeedGTimer))
|
2013-12-21 03:21:59 +00:00
|
|
|
gtimerStart(&LowSpeedGTimer, LowSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
|
2013-02-18 07:33:35 +00:00
|
|
|
|
|
|
|
/* Find a slot */
|
|
|
|
for(p = ls; p < &ls[GADC_MAX_LOWSPEED_DEVICES]; p++) {
|
|
|
|
if (!(p->flags & GADC_FLG_ISACTIVE)) {
|
|
|
|
/* We know we have a slot - this should never wait anyway */
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxSemWait(&gadcsem, TIME_IMMEDIATE);
|
2013-02-18 07:33:35 +00:00
|
|
|
p->lld.physdev = physdev;
|
|
|
|
p->lld.buffer = buffer;
|
|
|
|
p->fn = fn;
|
|
|
|
p->param = param;
|
|
|
|
p->flags = GADC_FLG_ISACTIVE;
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxMutexExit(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
StartADC(FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
2013-05-24 15:26:52 +00:00
|
|
|
gfxMutexExit(&gadcmutex);
|
2013-02-18 07:33:35 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* GFX_USE_GADC */
|
|
|
|
/** @} */
|
|
|
|
|