diff --git a/os/io/adc.c b/os/io/adc.c index 637820d5b..d4fb20bab 100644 --- a/os/io/adc.c +++ b/os/io/adc.c @@ -38,7 +38,7 @@ void adcInit(void) { /** * @brief Initializes the standard part of a @p ADCDriver structure. * - * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] adcp pointer to the @p ADCDriver object */ void adcObjectInit(ADCDriver *adcp) { @@ -50,48 +50,66 @@ void adcObjectInit(ADCDriver *adcp) { /** * @brief Configures and activates the ADC peripheral. * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] config pointer to the @p ADCConfig object + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] config pointer to the @p ADCConfig object */ void adcStart(ADCDriver *adcp, const ADCConfig *config) { chDbgCheck((adcp != NULL) && (config != NULL), "adcStart"); + + chSysLock(); chDbgAssert((adcp->adc_state == ADC_STOP) || (adcp->adc_state == ADC_READY), "adcStart(), #1", "invalid state"); - adcp->adc_config = config; adc_lld_start(adcp); adcp->adc_state = ADC_READY; + chSysUnlock(); } /** * @brief Deactivates the ADC peripheral. * - * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] adcp pointer to the @p ADCDriver object */ void adcStop(ADCDriver *adcp) { chDbgCheck(adcp != NULL, "adcStop"); - chDbgAssert((adcp->spd_state == ADC_STOP) || (adcp->spd_state == ADC_READY), + + chSysLock(); + chDbgAssert((adcp->adc_state == ADC_STOP) || (adcp->adc_state == ADC_READY), "adcStop(), #1", "invalid state"); - adc_lld_stop(adcp); - adcp->spd_state = ADC_STOP; + adcp->adc_state = ADC_STOP; + chSysUnlock(); } /** * @brief Starts an ADC conversion. + * @details Starts a conversion operation, there are two kind of conversion + * modes: + * - LINEAR, this mode is activated when the @p callback + * parameter is set to @p NULL, in this mode the buffer is filled + * once and then the conversion stops automatically. + * - CIRCULAR, when a callback function is defined the + * conversion never stops and the buffer is filled circularly. + * During the conversion the callback function is invoked when + * the buffer is 50% filled and when the buffer is 100% filled, + * this way is possible to process the conversion stream in real + * time. This kind of conversion can only be stopped by explicitly + * invoking @p adcStopConversion(). + * . * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] grpp pointer to a @p ADCConversionGroup object - * @param[out] samples pointer to the samples buffer - * @param[in] depth buffer depth (matrix rows number). The buffer depth must - * be one or an even number. + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] grpp pointer to a @p ADCConversionGroup object + * @param[out] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * @param[in] callback pointer to the conversion callback function * @return The operation status. - * @retval FALSE the conversion has been started. - * @retval TRUE the driver is busy, conversion not started. + * @retval FALSE the conversion has been started. + * @retval TRUE the driver is busy, conversion not started. * * @note The buffer is organized as a matrix of M*N elements where M is the * channels number configured into the conversion group and N is the @@ -101,27 +119,24 @@ void adcStop(ADCDriver *adcp) { bool_t adcStartConversion(ADCDriver *adcp, ADCConversionGroup *grpp, void *samples, - size_t depth) { + size_t depth, + adccallback_t callback) { chDbgCheck((adcp != NULL) && (grpp != NULL) && (samples != NULL) && ((depth == 1) || ((depth & 1) == 0)), "adcStartConversion"); chSysLock(); - chDbgAssert((adcp->adc_state == ADC_READY) || (adcp->adc_state == ADC_RUNNING), "adcStartConversion(), #1", "invalid state"); - if (adcp->adc_state == ADC_RUNNING) { chSysUnlock(); return TRUE; } - - adc_lld_start_conversion(adcp, grpp, samples); + adc_lld_start_conversion(adcp, grpp, samples, depth, callback); adcp->adc_state = ADC_RUNNING; - chSysUnlock(); return FALSE; } @@ -136,40 +151,35 @@ void adcStopConversion(ADCDriver *adcp) { chDbgCheck(adcp != NULL, "adcStopConversion"); chSysLock(); - chDbgAssert((adcp->adc_state == ADC_READY) || (adcp->adc_state == ADC_RUNNING), "adcStopConversion(), #1", "invalid state"); - adc_lld_stop_conversion(adcp); adcp->adc_state = ADC_READY; - chSysUnlock(); } /** * @brief Waits for completion. * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] timeout the number of ticks before the operation timeouts, - * the following special values are allowed: - * - @a TIME_IMMEDIATE immediate timeout. - * - @a TIME_INFINITE no timeout. - * . + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . * @return The operation result. * @retval RDY_OK conversion finished (or not started). * @retval RDY_TIMEOUT conversion not finished within the specified time. */ -msg_t adcWaitConversion(ADCDriver *adcp, systme_t timeout) { +msg_t adcWaitConversion(ADCDriver *adcp, systime_t timeout) { chSysLock(); - chDbgAssert((adcp->adc_state == ADC_READY) || (adcp->adc_state == ADC_RUNNING), "adcWaitConversion(), #1", "invalid state"); - if (adcp->adc_state == ADC_RUNNING) { if (chSemWaitTimeoutS(&adcp->adc_sem, timeout) == RDY_TIMEOUT) { chSysUnlock(); diff --git a/os/io/adc.h b/os/io/adc.h index 07fc19074..9fcaba508 100644 --- a/os/io/adc.h +++ b/os/io/adc.h @@ -48,13 +48,15 @@ extern "C" { #endif void adcInit(void); void adcObjectInit(ADCDriver *adcp); - void adcStart(ADCDriver *adcp, const ADCDriver *config); + void adcStart(ADCDriver *adcp, const ADCConfig *config); void adcStop(ADCDriver *adcp); bool_t adcStartConversion(ADCDriver *adcp, ADCConversionGroup *grpp, - void *samples); + void *samples, + size_t depth, + adccallback_t callback); void adcStopConversion(ADCDriver *adcp); - msg_t adcWaitConversion(ADCDriver *adcp, systme_t timeout); + msg_t adcWaitConversion(ADCDriver *adcp, systime_t timeout); #ifdef __cplusplus } #endif diff --git a/os/io/io.dox b/os/io/io.dox index f53bb3271..1f68a29c0 100644 --- a/os/io/io.dox +++ b/os/io/io.dox @@ -148,7 +148,7 @@ edge [fontname=Helvetica, fontsize=8]; uninit [label="SPI_UNINIT", style="bold"]; stop [label="SPI_STOP\nLow Power"]; - ready [label="SPI_IDLE\nClock Enabled"]; + ready [label="SPI_READY\nClock Enabled"]; active [label="SPI_ACTIVE\nBus Active"]; uninit -> stop [label="spiInit()"]; stop -> ready [label="spiStart()"]; @@ -176,6 +176,46 @@ * @ingroup SPI */ +/** + * @defgroup ADC ADC Driver + * @brief Generic ADC Driver. + * @details This module implements a generic ADC driver. The driver implements + * a state machine internally: + * @dot + digraph example { + rankdir="LR"; + node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"]; + edge [fontname=Helvetica, fontsize=8]; + uninit [label="ADC_UNINIT", style="bold"]; + stop [label="ADC_STOP\nLow Power"]; + ready [label="ADC_READY\nClock Enabled"]; + running [label="ADC_RUNNING\nConverting"]; + uninit -> stop [label="adcInit()"]; + stop -> ready [label="adcStart()"]; + ready -> ready [label="adcStart()"]; + ready -> stop [label="adcStop()"]; + stop -> stop [label="adcStop()"]; + ready -> running [label="adcStartConversion()"]; + running -> ready [label="adcStopConversion()"]; + running -> ready [label="End of Conversion"]; + } + * @enddot + * + * The driver supports a continuous conversion mode with circular buffer, + * callback functions allow to process the converted data in real time. + * Please refer to the documentation of the function @p adcStartConversion(). + * + * @ingroup IO + */ + +/** + * @defgroup ADC_LLD ADC Low Level Driver + * @brief @ref ADC low level driver template. + * @details This file is a template for a ADC low level driver. + * + * @ingroup ADC + */ + /** * @defgroup MAC MAC Driver * @brief Generic MAC driver. diff --git a/os/io/platforms/STM32/platform.dox b/os/io/platforms/STM32/platform.dox index 6ec9fbe20..5b25bde72 100644 --- a/os/io/platforms/STM32/platform.dox +++ b/os/io/platforms/STM32/platform.dox @@ -23,6 +23,8 @@ * @details The STM32 support includes: * - I/O ports driver. * - Buffered, interrupt driven, serial driver. + * - DMA capable, high performance, SPI driver. + * - DMA capable, high performance, ADC driver. * - A demo supporting the kernel test suite. * . * @ingroup ARMCM3 @@ -65,7 +67,34 @@ * @defgroup STM32_SERIAL STM32 USART Support * @brief USART peripherals support. * @details The serial driver supports the STM32 USARTs in asynchronous - * mode. + * mode. + * + * @ingroup STM32 + */ + +/** + * @defgroup STM32_DMA STM32 DMA Support + * @brief DMA support. + * @details The DMA help driver allows to stop the DMA clock when no other + * drivers require its services. + * + * @ingroup STM32 + */ + +/** + * @defgroup STM32_SPI STM32 SPI Support + * @brief SPI peripherals support. + * @details The serial driver supports the STM32 SPIs using DMA channels for + * improved performance. + * + * @ingroup STM32 + */ + +/** + * @defgroup STM32_ADC STM32 ADC Support + * @brief ADC peripherals support. + * @details The serial driver supports the STM32 ADCs using DMA channels for + * improved performance. * * @ingroup STM32 */ diff --git a/os/io/platforms/STM32/spi_lld.c b/os/io/platforms/STM32/spi_lld.c index 591ade2aa..a950095b9 100644 --- a/os/io/platforms/STM32/spi_lld.c +++ b/os/io/platforms/STM32/spi_lld.c @@ -18,9 +18,9 @@ */ /** - * @file templates/spi_lld.c - * @brief SPI Driver subsystem low level driver source template - * @addtogroup SPI_LLD + * @file STM32/spi_lld.c + * @brief STM32 SPI subsystem low level driver source + * @addtogroup STM32_SPI * @{ */ diff --git a/os/io/platforms/STM32/spi_lld.h b/os/io/platforms/STM32/spi_lld.h index f24a08e13..f4633d5b2 100644 --- a/os/io/platforms/STM32/spi_lld.h +++ b/os/io/platforms/STM32/spi_lld.h @@ -18,9 +18,9 @@ */ /** - * @file templates/spi_lld.h - * @brief SPI Driver subsystem low level driver header template - * @addtogroup SPI_LLD + * @file STM32/spi_lld.h + * @brief STM32 SPI subsystem low level driver header + * @addtogroup STM32_SPI * @{ */ diff --git a/os/io/templates/adc_lld.c b/os/io/templates/adc_lld.c index 0f3246cf0..f8fdb609a 100644 --- a/os/io/templates/adc_lld.c +++ b/os/io/templates/adc_lld.c @@ -49,11 +49,11 @@ void adc_lld_init(void) { /** * @brief Configures and activates the ADC peripheral. * - * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] adcp pointer to the @p ADCDriver object */ void adc_lld_start(ADCDriver *adcp) { - if (adcp->spd_state == ADC_STOP) { + if (adcp->adc_state == ADC_STOP) { /* Clock activation.*/ } /* Configuration.*/ @@ -62,7 +62,7 @@ void adc_lld_start(ADCDriver *adcp) { /** * @brief Deactivates the ADC peripheral. * - * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] adcp pointer to the @p ADCDriver object */ void adc_lld_stop(ADCDriver *adcp) { @@ -70,21 +70,47 @@ void adc_lld_stop(ADCDriver *adcp) { /** * @brief Starts an ADC conversion. + * @details Starts a conversion operation, there are two kind of conversion + * modes: + * - LINEAR, this mode is activated when the @p callback + * parameter is set to @p NULL, in this mode the buffer is filled + * once and then the conversion stops automatically. + * - CIRCULAR, when a callback function is defined the + * conversion never stops and the buffer is filled circularly. + * During the conversion the callback function is invoked when + * the buffer is 50% filled and when the buffer is 100% filled, + * this way is possible to process the conversion stream in real + * time. This kind of conversion can only be stopped by explicitly + * invoking @p adcStopConversion(). + * . * - * @param[in] adcp pointer to the @p ADCDriver object - * @param[in] grpp pointer to a @p ADCConversionGroup object - * @param[out] samples pointer to the samples buffer + * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] grpp pointer to a @p ADCConversionGroup object + * @param[out] samples pointer to the samples buffer + * @param[in] depth buffer depth (matrix rows number). The buffer depth + * must be one or an even number. + * @param[in] callback pointer to the conversion callback function + * @return The operation status. + * @retval FALSE the conversion has been started. + * @retval TRUE the driver is busy, conversion not started. + * + * @note The buffer is organized as a matrix of M*N elements where M is the + * channels number configured into the conversion group and N is the + * buffer depth. The samples are sequentially written into the buffer + * with no gaps. */ void adc_lld_start_conversion(ADCDriver *adcp, ADCConversionGroup *grpp, - void *samples) { + void *samples, + size_t depth, + adccallback_t callback) { } /** * @brief Stops an ongoing conversion. * - * @param[in] adcp pointer to the @p ADCDriver object + * @param[in] adcp pointer to the @p ADCDriver object */ void adc_lld_stop_conversion(ADCDriver *adcp) { diff --git a/os/io/templates/adc_lld.h b/os/io/templates/adc_lld.h index 6fde9c181..db67a65cd 100644 --- a/os/io/templates/adc_lld.h +++ b/os/io/templates/adc_lld.h @@ -35,20 +35,6 @@ /* Driver constants. */ /*===========================================================================*/ -/** - * @brief Linear buffering mode. - * @details In the linear buffering mode the buffer is filled one time and - * then the operation automatically stops. - */ -#define ADC_GROUP_BUFFER_LINEAR 0 - -/** - * @brief Circular buffering mode. - * @details In the circular buffering mode the buffer is filled one time and - * then the operation automatically starts again. - */ -#define ADC_GROUP_BUFFER_CIRCULAR 1 - /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ @@ -82,32 +68,10 @@ typedef void (*adccallback_t)(adcsample_t *buffer, * operation. */ typedef struct { - /** - * @brief Group mode flags. - */ - uint_least8_t acg_mode; - /** * @brief Number of the analog channels belonging to the conversion group. */ adc_channels_num_t acg_num_channels; - - /** - * @brief Samples buffer depth. - * @note The buffer depth must be an even number or one. The 50% callback - * behavior for buffers with odd depth is unspecified. - */ - adc_buffer_depth_t acg_buffer_depth; - - /** - * @brief Data streaming callback. - * @details This callback is invoked at 50% and 100% buffer fill level in - * order to allow realtime processing of the conversion results - * when the circular buffer mode is selected. - * @note The 50% callback is only invoked if @p acg_num_samples is greater - * than 1. - */ - adccallback_t acg_callback; } ADCConversionGroup; /** @@ -148,7 +112,9 @@ extern "C" { void adc_lld_stop(ADCDriver *adcp); void adc_lld_start_conversion(ADCDriver *adcp, ADCConversionGroup *grpp, - void *samples); + void *samples, + size_t depth, + adccallback_t callback); void adc_lld_stop_conversion(ADCDriver *adcp); #ifdef __cplusplus } diff --git a/readme.txt b/readme.txt index d3d83ec80..77450536f 100644 --- a/readme.txt +++ b/readme.txt @@ -10,6 +10,7 @@ - FIX: Fixed AIC initialization in AT91SAM7X support (bug 2888583). - NEW: New SPI (master) driver model. - NEW: SPI driver for STM32 implementing the new SPI driver model. +- NEW: New ADC (streaming capable) driver model. *** 1.3.3 *** - FIX: Fixed bug in the LPC2148 PAL driver (bug 2881380).