aboutsummaryrefslogtreecommitdiffstats
path: root/src/gadc
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2014-03-20 23:41:27 +1000
committerinmarket <andrewh@inmarket.com.au>2014-03-20 23:41:27 +1000
commit271f0c743f31d3ae21ede35909e1f14845c6d338 (patch)
tree03541486e35fd48b3dd76db6c0470a8d860cd964 /src/gadc
parent712ff73f77763eeee798d6913f57e5577adcef3f (diff)
downloaduGFX-271f0c743f31d3ae21ede35909e1f14845c6d338.tar.gz
uGFX-271f0c743f31d3ae21ede35909e1f14845c6d338.tar.bz2
uGFX-271f0c743f31d3ae21ede35909e1f14845c6d338.zip
Updates to GADC to use new simpler gfx queued bufferring.
NOTE: code is still buggy (or the one and only driver is buggy).
Diffstat (limited to 'src/gadc')
-rw-r--r--src/gadc/driver.h93
-rw-r--r--src/gadc/gadc.c218
-rw-r--r--src/gadc/sys_defs.h70
-rw-r--r--src/gadc/sys_rules.h11
4 files changed, 173 insertions, 219 deletions
diff --git a/src/gadc/driver.h b/src/gadc/driver.h
index 4427f4f0..6e935576 100644
--- a/src/gadc/driver.h
+++ b/src/gadc/driver.h
@@ -32,9 +32,9 @@
* @{
*/
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. */
+ uint32_t physdev; /* @< Which physical ADC devices/channels to use. Filled in by High Level Code */
+ uint32_t frequency; /* @< The conversion frequency. Filled in by High Level Code */
+ GDataBuffer *pdata; /* @< The buffer to put the ADC samples into. */
bool_t now; /* @< Trigger the first conversion now rather than waiting for the first timer interrupt (if possible) */
} GadcLldTimerData;
/* @} */
@@ -52,30 +52,6 @@ typedef struct GadcLldNonTimerData_t {
/* @} */
/**
- * @brief These routines are the callbacks that the driver uses.
- * @details Defined in the high level GADC code.
- *
- * @notapi
- * @{
- */
-
-/**
- * @param[in] adcp The ADC driver
- * @param[in] buffer The sample buffer
- * @param[in] n The amount of samples
- */
-extern void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n);
-
-/**
- * @param[in] adcp The ADC driver
- * @param[in] err ADC error
- */
-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.
*
@@ -92,70 +68,75 @@ extern "C" {
#endif
/**
- * @brief Initialise the driver
+ * @brief These routines are the callbacks that the driver uses.
+ * @details Defined in the high level GADC code.
*
- * @api
+ * @notapi
+ * @{
+ */
+ /**
+ * @brief The last conversion requested is now complete
+ */
+ void gadcDataReadyI(void);
+
+ /**
+ * @brief The last conversion requested failed
+ */
+ void gadcDataFailI(void);
+/**
+ * @}
*/
-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.
- *
- * @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.
- *
- * @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
+ * @brief Initialise the driver
*
- * @return Number of samples of the convesion
* @api
*/
-size_t gadc_lld_samples_per_conversion(uint32_t physdev);
+void gadc_lld_init(void);
/**
* @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
+ * @param[in] pgtd The structure containing the sample frequency and physical device to use.
*
* @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
+ * @details When a timer interrupt occurs a conversion should start if there 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
+ * @note Timer interrupts occurring before @p gadc_lld_adc_timerI() has been called,
+ * if @p gadc_lld_adc_timerI() has been called quick enough, or while
+ * a non-timer conversion is active should be ignored other than (optionally) incrementing
* the GADC_Timer_Missed variable.
+ * @note The pdata and now members of the pgtd structure are now yet valid.
*
* @api
*/
-void gadc_lld_start_timer(uint32_t physdev, uint32_t frequency);
+void gadc_lld_start_timer(GadcLldTimerData *pgtd);
/**
* @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.
+ * @param[in] pgtd The structure containing the sample frequency and physical device to use.
*
+ * @note After this function returns there should be no more calls to @p gadcDataReadyI()
+ * or @p gadcDataFailI() in relation to timer conversions.
* @api
*/
-void gadc_lld_stop_timer(uint32_t physdev);
+void gadc_lld_stop_timer(GadcLldTimerData *pgtd);
/**
- * @brief Start a "timer" conversion.
+ * @brief Start a set of "timer" conversions.
* @details Starts a series of conversions triggered by the timer.
*
* @param[in] pgtd Contains the parameters for the timer conversion.
*
* @note The exact meaning of physdev is hardware dependent. It is likely described in the
* drivers gadc_lld_config.h
- * @note Some versions of ChibiOS actually call the callback function more than once, once
- * at the half-way point and once on completion. The high level code handles this.
- * @note The driver should call @p GADC_ISR_CompleteI() when it completes the operation
- * (or at the half-way point), or @p GAD_ISR_ErrorI() on an error.
+ * @note The driver should call @p gadcDataReadyI() when it completes the operation
+ * or @p gadcDataFailI() on an error.
* @note The high level code ensures that this is not called while a non-timer conversion is in
* progress
*
@@ -171,8 +152,8 @@ void gadc_lld_adc_timerI(GadcLldTimerData *pgtd);
*
* @note The exact meaning of physdev is hardware dependent. It is likely described in the
* drivers gadc_lld_config.h
- * @note The driver should call @p GADC_ISR_CompleteI() when it completes the operation
- * or @p GAD_ISR_ErrorI() on an error.
+ * @note The driver should call @p gadcDataReadyI() when it completes the operation
+ * or @p gadcDataFailI() on an error.
* @note The high level code ensures that this is not called while a timer conversion is in
* progress
*
diff --git a/src/gadc/gadc.c b/src/gadc/gadc.c
index 8ae431b0..e2d2d461 100644
--- a/src/gadc/gadc.c
+++ b/src/gadc/gadc.c
@@ -31,42 +31,30 @@
volatile bool_t GADC_Timer_Missed;
-static gfxSem gadcsem;
-static gfxMutex gadcmutex;
-static GTimer LowSpeedGTimer;
+static bool_t gadcRunning;
+static gfxSem LowSpeedSlotSem;
+static gfxMutex LowSpeedMutex;
+static GTimer LowSpeedGTimer;
+static gfxQueueGSync HighSpeedBuffers;
+
#if GFX_USE_GEVENT
- static GTimer HighSpeedGTimer;
+ static GTimer HighSpeedGTimer;
#endif
-static volatile uint16_t gflags = 0;
- #define GADC_GFLG_ISACTIVE 0x0001
#define GADC_FLG_ISACTIVE 0x0001
#define GADC_FLG_ISDONE 0x0002
#define GADC_FLG_ERROR 0x0004
#define GADC_FLG_GTIMER 0x0008
+#define GADC_FLG_STALLED 0x0010
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;
-
// Other stuff we need to track progress and for signaling
GadcLldTimerData lld;
- size_t samplesPerConversion;
- size_t remaining;
- gfxSem *bsem;
- GEventADC *pEvent;
+ uint16_t eventflags;
GADCISRCallbackFunction isrfn;
} hs;
@@ -101,49 +89,59 @@ static inline void FindNextConversionI(void) {
/**
* Look for the next thing to do.
*/
- while(curlsdev < &ls[GADC_MAX_LOWSPEED_DEVICES]) {
+ gadcRunning = TRUE;
+ for(; curlsdev < &ls[GADC_MAX_LOWSPEED_DEVICES]; curlsdev++) {
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;
+ hs.lld.pdata = gfxBufferGetI();
+ if (hs.lld.pdata) {
+ hs.lld.now = GADC_Timer_Missed || (hs.flags & GADC_FLG_STALLED);
+ hs.flags &= ~GADC_FLG_STALLED;
+ GADC_Timer_Missed = 0;
+ gadc_lld_adc_timerI(&hs.lld);
+ return;
+ }
+
+ // Oops - no free buffers - mark stalled and go back to low speed devices
+ hs.flags |= GADC_FLG_STALLED;
+ hs.eventflags &= ~GADC_HSADC_RUNNING;
+ for(curlsdev = ls; curlsdev < &ls[GADC_MAX_LOWSPEED_DEVICES]; curlsdev++) {
+ if ((curlsdev->flags & (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) == GADC_FLG_ISACTIVE) {
+ gadc_lld_adc_nontimerI(&curlsdev->lld);
+ return;
+ }
+ }
+ curlsdev = 0;
}
/* Nothing more to do */
- gflags &= ~GADC_GFLG_ISACTIVE;
+ gadcRunning = FALSE;
}
-void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
- (void) adcp;
+void gadcDataReadyI(void) {
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
+ #if GFX_USE_OS_CHIBIOS && CHIBIOS_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;
+ gadcRunning = FALSE;
return;
#endif
@@ -152,49 +150,31 @@ void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
/* 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;
+ if (hs.lld.pdata->len) {
+ /* Save the current buffer on the HighSpeedBuffers */
+ gfxQueueGSyncPutI(&HighSpeedBuffers, (gfxQueueGSyncItem *)hs.lld.pdata);
+ hs.lld.pdata = 0;
+
+ /* Save the details */
+ hs.eventflags = GADC_HSADC_RUNNING|GADC_HSADC_GOTBUFFER;
+ if (GADC_Timer_Missed)
+ hs.eventflags |= GADC_HSADC_LOSTEVENT;
+ if (hs.flags & GADC_FLG_STALLED)
+ hs.eventflags |= GADC_HSADC_STALL;
+
+ /* Our signalling mechanisms */
+ if (hs.isrfn)
+ hs.isrfn();
- /* Signal the user with the data */
- if (hs.pEvent) {
#if GFX_USE_GEVENT
- hs.pEvent->type = GEVENT_ADC;
+ if (hs.flags & GADC_FLG_GTIMER)
+ gtimerJabI(&HighSpeedGTimer);
#endif
- hs.pEvent->count = hs.lastcount;
- hs.pEvent->buffer = hs.lastbuffer;
- hs.pEvent->flags = hs.lastflags;
- }
-
- /* Our three signalling mechanisms */
- if (hs.isrfn)
- hs.isrfn(buffer, n);
-
- if (hs.bsem)
- gfxSemSignalI(hs.bsem);
-
- #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;
+ // Oops - no data in this buffer. Just return it to the free-list
+ gfxBufferRelease(hs.lld.pdata);
+ hs.lld.pdata = 0;
}
- hs.lld.count = hs.remaining < hs.samplesPerEvent ? hs.remaining : hs.samplesPerEvent;
}
}
@@ -204,22 +184,19 @@ void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n) {
FindNextConversionI();
}
-void GADC_ISR_ErrorI(ADCDriver *adcp, adcerror_t err) {
- (void) adcp;
- (void) err;
-
+void gadcDataFailI(void) {
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
+ #if GFX_USE_OS_CHIBIOS && CHIBIOS_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;
+ gadcRunning = FALSE;
gtimerJabI(&LowSpeedGTimer);
return;
@@ -239,8 +216,9 @@ void GADC_ISR_ErrorI(ADCDriver *adcp, adcerror_t err) {
void _gadcInit(void)
{
gadc_lld_init();
- gfxSemInit(&gadcsem, GADC_MAX_LOWSPEED_DEVICES, GADC_MAX_LOWSPEED_DEVICES);
- gfxMutexInit(&gadcmutex);
+ gfxQueueGSyncInit(&HighSpeedBuffers);
+ gfxSemInit(&LowSpeedSlotSem, GADC_MAX_LOWSPEED_DEVICES, GADC_MAX_LOWSPEED_DEVICES);
+ gfxMutexInit(&LowSpeedMutex);
gtimerInit(&LowSpeedGTimer);
#if GFX_USE_GEVENT
gtimerInit(&HighSpeedGTimer);
@@ -252,8 +230,9 @@ void _gadcDeinit(void)
/* commented stuff is ToDo */
// gadc_lld_deinit();
- gfxSemDestroy(&gadcsem);
- gfxMutexDestroy(&gadcmutex);
+ gfxQueueGSyncDeinit(&HighSpeedBuffers);
+ gfxSemDestroy(&LowSpeedSlotSem);
+ gfxMutexDestroy(&LowSpeedMutex);
gtimerDeinit(&LowSpeedGTimer);
#if GFX_USE_GEVENT
gtimerDeinit(&HighSpeedGTimer);
@@ -262,7 +241,7 @@ void _gadcDeinit(void)
static inline void StartADC(bool_t onNoHS) {
gfxSystemLock();
- if (!(gflags & GADC_GFLG_ISACTIVE) || (onNoHS && !curlsdev))
+ if (!gadcRunning || (onNoHS && !curlsdev))
FindNextConversionI();
gfxSystemUnlock();
}
@@ -289,9 +268,7 @@ static void BSemSignalCallback(adcsample_t *buffer, void *param) {
}
pe->type = GEVENT_ADC;
- pe->count = hs.lastcount;
- pe->buffer = hs.lastbuffer;
- pe->flags = hs.lastflags | psl->srcflags;
+ pe->flags = hs.eventflags | psl->srcflags;
psl->srcflags = 0;
geventSendEvent(psl);
}
@@ -305,7 +282,7 @@ static void LowSpeedGTimerCallback(void *param) {
adcsample_t *buffer;
struct lsdev *p;
- #if ADC_ISR_FULL_CODE_BUG
+ #if GFX_USE_OS_CHIBIOS && CHIBIOS_ADC_ISR_FULL_CODE_BUG
/* Ensure the ADC is running if it needs to be - Bugfix HACK */
StartADC(FALSE);
#endif
@@ -325,33 +302,22 @@ static void LowSpeedGTimerCallback(void *param) {
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)
- gfxSemSignal(&gadcsem); // Tell everyone
+ gfxSemSignal(&LowSpeedSlotSem); // Tell everyone
fn(buffer, prm); // Perform the callback
}
}
}
-void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent)
+void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency)
{
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.frequency = frequency;
+ hs.lld.pdata = 0;
hs.lld.now = FALSE;
- hs.samplesPerConversion = gadc_lld_samples_per_conversion(physdev);
- hs.remaining = bufcount;
- hs.bsem = 0;
- hs.pEvent = 0;
hs.isrfn = 0;
}
@@ -368,12 +334,12 @@ void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn) {
hs.isrfn = isrfn;
}
-void gadcHighSpeedSetBSem(gfxSem *pbsem, GEventADC *pEvent) {
- /* Use the system lock to ensure they occur atomically */
- gfxSystemLock();
- hs.pEvent = pEvent;
- hs.bsem = pbsem;
- gfxSystemUnlock();
+GDataBuffer *gadcHighSpeedGetData(delaytime_t ms) {
+ return (GDataBuffer *)gfxQueueGSyncGet(&HighSpeedBuffers, ms);
+}
+
+GDataBuffer *gadcHighSpeedGetDataI(void) {
+ return (GDataBuffer *)gfxQueueGSyncGetI(&HighSpeedBuffers);
}
void gadcHighSpeedStart(void) {
@@ -381,8 +347,8 @@ void gadcHighSpeedStart(void) {
if (hs.flags & GADC_FLG_ISACTIVE)
return;
- gadc_lld_start_timer(hs.lld.physdev, hs.frequency);
hs.flags = GADC_FLG_ISACTIVE;
+ gadc_lld_start_timer(&hs.lld);
StartADC(FALSE);
}
@@ -390,7 +356,15 @@ void gadcHighSpeedStop(void) {
if (hs.flags & GADC_FLG_ISACTIVE) {
/* No more from us */
hs.flags = 0;
- gadc_lld_stop_timer(hs.lld.physdev);
+ gadc_lld_stop_timer(&hs.lld);
+ /*
+ * There might be a buffer still locked up by the driver - if so release it.
+ */
+ if (hs.lld.pdata) {
+ gfxBufferRelease(hs.lld.pdata);
+ hs.lld.pdata = 0;
+ }
+
/*
* 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.
@@ -405,17 +379,17 @@ void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer) {
/* Start the Low Speed Timer */
gfxSemInit(&mysem, 1, 1);
- gfxMutexEnter(&gadcmutex);
+ gfxMutexEnter(&LowSpeedMutex);
if (!gtimerIsActive(&LowSpeedGTimer))
gtimerStart(&LowSpeedGTimer, LowSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
- gfxMutexExit(&gadcmutex);
+ gfxMutexExit(&LowSpeedMutex);
while(1) {
/* Wait for an available slot */
- gfxSemWait(&gadcsem, TIME_INFINITE);
+ gfxSemWait(&LowSpeedSlotSem, TIME_INFINITE);
/* Find a slot */
- gfxMutexEnter(&gadcmutex);
+ gfxMutexEnter(&LowSpeedMutex);
for(p = ls; p < &ls[GADC_MAX_LOWSPEED_DEVICES]; p++) {
if (!(p->flags & GADC_FLG_ISACTIVE)) {
p->lld.physdev = physdev;
@@ -423,13 +397,13 @@ void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer) {
p->fn = BSemSignalCallback;
p->param = &mysem;
p->flags = GADC_FLG_ISACTIVE;
- gfxMutexExit(&gadcmutex);
+ gfxMutexExit(&LowSpeedMutex);
StartADC(FALSE);
gfxSemWait(&mysem, TIME_INFINITE);
return;
}
}
- gfxMutexExit(&gadcmutex);
+ gfxMutexExit(&LowSpeedMutex);
/**
* We should never get here - the count semaphore must be wrong.
@@ -442,7 +416,7 @@ bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunc
struct lsdev *p;
/* Start the Low Speed Timer */
- gfxMutexEnter(&gadcmutex);
+ gfxMutexEnter(&LowSpeedMutex);
if (!gtimerIsActive(&LowSpeedGTimer))
gtimerStart(&LowSpeedGTimer, LowSpeedGTimerCallback, 0, TRUE, TIME_INFINITE);
@@ -450,18 +424,18 @@ bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunc
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 */
- gfxSemWait(&gadcsem, TIME_IMMEDIATE);
+ gfxSemWait(&LowSpeedSlotSem, TIME_IMMEDIATE);
p->lld.physdev = physdev;
p->lld.buffer = buffer;
p->fn = fn;
p->param = param;
p->flags = GADC_FLG_ISACTIVE;
- gfxMutexExit(&gadcmutex);
+ gfxMutexExit(&LowSpeedMutex);
StartADC(FALSE);
return TRUE;
}
}
- gfxMutexExit(&gadcmutex);
+ gfxMutexExit(&LowSpeedMutex);
return FALSE;
}
diff --git a/src/gadc/sys_defs.h b/src/gadc/sys_defs.h
index f6349dfe..21e81fb6 100644
--- a/src/gadc/sys_defs.h
+++ b/src/gadc/sys_defs.h
@@ -73,15 +73,10 @@ typedef struct GEventADC_t {
* @{
*/
#define GADC_HSADC_LOSTEVENT 0x0001 /**< @brief The last GEVENT_HSDADC event was lost */
+ #define GADC_HSADC_RUNNING 0x0002 /**< @brief The High Speed ADC is currently running */
+ #define GADC_HSADC_GOTBUFFER 0x0004 /**< @brief A buffer is ready for processing */
+ #define GADC_HSADC_STALL 0x0008 /**< @brief The High Speed ADC has stalled due to no free buffers */
/** @} */
- /**
- * @brief The number of conversions in the buffer
- */
- size_t count;
- /**
- * @brief The buffer containing the conversion samples
- */
- adcsample_t *buffer;
} GEventADC;
/** @} */
@@ -93,7 +88,7 @@ typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param);
/**
* @brief A callback function (executed in an ISR context) for a high speed conversion
*/
-typedef void (*GADCISRCallbackFunction)(adcsample_t *buffer, size_t size);
+typedef void (*GADCISRCallbackFunction)(void);
/*===========================================================================*/
/* External declarations. */
@@ -109,40 +104,28 @@ extern "C" {
*
* @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] samplesPerEvent 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 overwritten with new data while the application is still trying
- * to process the old data.
- * @note Due to a bug/feature in Chibi-OS countPerEvent must be even. If bufcount is not
- * evenly divisable by countPerEvent, the remainder must also be even.
+ * @note ChibiOS ONLY: Due to a bug in ChibiOS each buffer on the free-list must contain an even number of
+ * samples and for multi-channel devices it must hold a number of samples that is evenly divisible
+ * by 2 times the number of active channels.
* @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.
+ * Each channel is then interleaved into the provided buffer. Make sure your buffers all hold
+ * a number of samples evenly divisible by the number of active channels.
* As an example, if physdev turns on 2 devices then the buffer contains
- * alternate device samples and the buffer must contain 2 * bufcount samples.
+ * alternate device samples and the buffer must contain multiples of 2 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
+ * being created at 50Hz (eg 100 samples/buffer, frequency = 5kHz) then the maximum
* frequency for low speed conversions will be 50Hz.
+ * @note Only a single sample format is supported - that provided by the GADC driver. That sample
+ * format applies to both high speed and low speed sampling.
*
* @api
*/
-void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent);
+void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency);
#if GFX_USE_GEVENT || defined(__DOXYGEN__)
/**
@@ -170,7 +153,7 @@ void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer
*
* @note Passing a NULL for isrfn will turn off signalling via this method as will calling
* @p gadcHighSpeedInit().
- * @note The high speed ADC is capable of signalling via this method, a binary semaphore and the GEVENT
+ * @note The high speed ADC is capable of signalling via this method, a blocked thread and the GEVENT
* sub-system at the same time.
*
* @api
@@ -178,19 +161,24 @@ void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer
void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn);
/**
- * @brief Allow retrieving of results from the high speed ADC using a Binary Semaphore and a static event buffer.
+ * @brief Get a filled buffer from the ADC
+ * @return A GDataBuffer pointer or NULL if the timeout is exceeded
*
- * @param[in] pbsem The 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, an ISR callback and the GEVENT
- * sub-system at the same time.
+ * @params[in] ms The maximum amount of time in milliseconds to wait for data if some is not currently available.
*
+ * @note After processing the data, your application must return the buffer to the free-list so that
+ * it can be used again. This can be done using @p gfxBufferRelease().
+ * @note A buffer may be returned to the free-list before you have finished processing it provided you finish
+ * processing it before GADC re-uses it. This is useful when RAM usage is critical to reduce the number
+ * of buffers required. It works before the free list is a FIFO queue and therefore buffers are kept
+ * in the queue as long as possible before they are re-used.
+ * @note The function ending with "I" is the interrupt class function.
* @api
+ * @{
*/
-void gadcHighSpeedSetBSem(gfxSem *pbsem, GEventADC *pEvent);
+GDataBuffer *gadcHighSpeedGetData(delaytime_t ms);
+GDataBuffer *gadcHighSpeedGetDataI(void);
+/* @} */
/**
* @brief Start the high speed ADC conversions.
diff --git a/src/gadc/sys_rules.h b/src/gadc/sys_rules.h
index 7272337e..363b2434 100644
--- a/src/gadc/sys_rules.h
+++ b/src/gadc/sys_rules.h
@@ -24,6 +24,17 @@
#undef GFX_USE_GTIMER
#define GFX_USE_GTIMER TRUE
#endif
+ #if !GFX_USE_GQUEUE || !GQUEUE_NEED_GSYNC || !GQUEUE_NEED_BUFFERS
+ #if GFX_DISPLAY_RULE_WARNINGS
+ #warning "GADC: GFX_USE_GQUEUE, GQUEUE_NEED_BUFFERS and GQUEUE_NEED_GSYNC are required if GFX_USE_GADC is TRUE. They have been turned on for you."
+ #endif
+ #undef GFX_USE_GQUEUE
+ #define GFX_USE_GQUEUE TRUE
+ #undef GQUEUE_NEED_BUFFERS
+ #define GQUEUE_NEED_BUFFERS TRUE
+ #undef GQUEUE_NEED_GSYNC
+ #define GQUEUE_NEED_GSYNC TRUE
+ #endif
#endif
#endif /* _GADC_RULES_H */