From 8ba7e03ed5fbb8c642fbd0c665b1c8a3f37d6dbc Mon Sep 17 00:00:00 2001 From: pcirillo Date: Mon, 18 Nov 2013 14:23:46 +0000 Subject: [PATCH] git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@6487 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/SPC5xx/ADC_v1/adc_lld.c | 208 ++++++++++++++++++----- os/hal/platforms/SPC5xx/ADC_v1/adc_lld.h | 114 +++++++------ 2 files changed, 222 insertions(+), 100 deletions(-) diff --git a/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.c b/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.c index 2080c6fde..07c49e564 100644 --- a/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.c +++ b/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.c @@ -271,12 +271,22 @@ void adc_lld_init(void) { INTC.PSR[SPC5_ADC0_EOC_NUMBER].R = SPC5_ADC_ADC0_EOC_PRIORITY; INTC.PSR[SPC5_ADC0_ER_NUMBER].R = SPC5_ADC_ADC0_ER_PRIORITY; INTC.PSR[SPC5_ADC0_WD_NUMBER].R = SPC5_ADC_ADC0_WD_PRIORITY; + + /* Sets peripheral clock.*/ + halSPCSetPeripheralClockMode(SPC5_ADC0_PCTL, SPC5_ADC_ADC0_START_PCTL); + ADCD1.adc_tagp->MCR.B.ADCLKSEL = SPC5_ADC_ADC0_CLK_FREQUENCY; + halSPCSetPeripheralClockMode(SPC5_ADC0_PCTL, SPC5_ADC_ADC0_STOP_PCTL); #endif #if SPC5_ADC_USE_ADC1 INTC.PSR[SPC5_ADC1_EOC_NUMBER].R = SPC5_ADC_ADC1_EOC_PRIORITY; INTC.PSR[SPC5_ADC1_ER_NUMBER].R = SPC5_ADC_ADC1_ER_PRIORITY; INTC.PSR[SPC5_ADC1_WD_NUMBER].R = SPC5_ADC_ADC1_WD_PRIORITY; + + /* Sets peripheral clock.*/ + halSPCSetPeripheralClockMode(SPC5_ADC1_PCTL, SPC5_ADC_ADC1_START_PCTL); + ADCD2.adc_tagp->MCR.B.ADCLKSEL = SPC5_ADC_ADC1_CLK_FREQUENCY; + halSPCSetPeripheralClockMode(SPC5_ADC1_PCTL, SPC5_ADC_ADC1_STOP_PCTL); #endif } @@ -328,15 +338,7 @@ void adc_lld_start(ADCDriver *adcp) { adcp->adc_tagp->MCR.B.PWDN = 0; /* Power up delay.*/ - /* TODO: add a delay of 5uS.*/ - - /* Sets analog clock.*/ - /* TODO: make it a static option, move in adc_lld_init().*/ - if (adcp->config->clock == HALF_PERIPHERAL_SET_CLOCK_FREQUENCY) { - adcp->adc_tagp->MCR.B.ADCLKSEL = 0; - } else if (adcp->config->clock == PERIPHERAL_SET_CLOCK_FREQUENCY) { - adcp->adc_tagp->MCR.B.ADCLKSEL = 1; - } + osalThreadSleep(US2ST(5)); /* Sets MCR Register.*/ adcp->adc_tagp->MCR.R = ADC_MCR_OWREN | ADC_MCR_MODE; @@ -358,22 +360,54 @@ void adc_lld_stop(ADCDriver *adcp) { /* Releases the allocated DMA channel.*/ edmaChannelRelease(adcp->adc_dma_channel); - /* Clears thresholds’ values and deactives watchdog threshold interrupts.*/ - /* TODO: make the number of WD registers a parameter in the registry, modify - the configuration structure.*/ - if (adcp->grpp->wtimr != 0) { - adcp->adc_tagp->TRC[0].R = 0; - adcp->adc_tagp->TRC[1].R = 0; - adcp->adc_tagp->TRC[2].R = 0; - adcp->adc_tagp->TRC[3].R = 0; - adcp->adc_tagp->THRHLR[0].R = 0; - adcp->adc_tagp->THRHLR[1].R = 0; - adcp->adc_tagp->THRHLR[2].R = 0; - adcp->adc_tagp->THRHLR[3].R = 0; - adcp->adc_tagp->WTIMR.R = 0; - } + /* Clears thresholds’ values and deactive watchdog threshold interrupts.*/ +#if SPC5_ADC_NTRESHOLD == 4 + adcp->adc_tagp->TRC[0].R = 0; + adcp->adc_tagp->TRC[1].R = 0; + adcp->adc_tagp->TRC[2].R = 0; + adcp->adc_tagp->TRC[3].R = 0; + adcp->adc_tagp->THRHLR[0].R = 0; + adcp->adc_tagp->THRHLR[1].R = 0; + adcp->adc_tagp->THRHLR[2].R = 0; + adcp->adc_tagp->THRHLR[3].R = 0; + adcp->adc_tagp->WTIMR.R = 0; - /* Deactives ADC channels and the ADC DMA channels.*/ + /* Disables the watchdog interrupts if any.*/ + adcp->adc_tagp->CIMR[0].R = 0; + + /* Clears watchdog interrupts if any.*/ + adcp->adc_tagp->WTISR.R = 0xFFFF; +#elif SPC5_ADC_NTRESHOLD == 16 + adcp->adc_tagp->THRHLR[0].R = 0; + adcp->adc_tagp->THRHLR[1].R = 0; + adcp->adc_tagp->THRHLR[2].R = 0; + adcp->adc_tagp->THRHLR[3].R = 0; + adcp->adc_tagp->THRHLR_2[0].R = 0; + adcp->adc_tagp->THRHLR_2[1].R = 0; + adcp->adc_tagp->THRHLR_2[2].R = 0; + adcp->adc_tagp->THRHLR_2[3].R = 0; + adcp->adc_tagp->THRHLR_2[4].R = 0; + adcp->adc_tagp->THRHLR_2[5].R = 0; + adcp->adc_tagp->THRHLR_2[6].R = 0; + adcp->adc_tagp->THRHLR_2[7].R = 0; + adcp->adc_tagp->THRHLR_2[8].R = 0; + adcp->adc_tagp->THRHLR_2[9].R = 0; + adcp->adc_tagp->THRHLR_2[10].R = 0; + adcp->adc_tagp->THRHLR_2[11].R = 0; + adcp->adc_tagp->CWSEL[0].R = 0; + adcp->adc_tagp->CWSEL[1].R = 0; + adcp->adc_tagp->CWENR[0].R = 0; + adcp->adc_tagp->AWORR[0].R = 0; + adcp->adc_tagp->WTIMR.R = 0; + + /* Disables the watchdog interrupts if any.*/ + adcp->adc_tagp->CIMR[0].R = 0; + + /* Clears watchdog interrupts if any.*/ + adcp->adc_tagp->WTISR.R = 0xFFFFFFFF; +#endif + + /* Deactive ADC channels and the ADC DMA channels.*/ adcp->adc_tagp->NCMR[0].R = 0; adcp->adc_tagp->DMAR[0].R = 0; @@ -405,14 +439,12 @@ void adc_lld_stop(ADCDriver *adcp) { * @notapi */ void adc_lld_start_conversion(ADCDriver *adcp) { + uint32_t ch_mask; uint8_t i; - //osalDbgAssert(adcp->grpp->num_channels*2 >= adcp->depth, - // "adc_lld_start_conversion(), #1", "too many elements"); - /* Setting up DMA TCD parameters.*/ edmaChannelSetup(adcp->adc_dma_channel, /* channel. */ - ((uint8_t *)adcp->adc_tagp->CDR[adcp->grpp->init_channel].R) + 2, /* src. */ + ((uint8_t *)&adcp->adc_tagp->CDR[adcp->grpp->init_channel].R) + 2, /* src. */ adcp->samples, /* dst. */ 4, /* soff, advance by four. */ 2, /* doff, advance by two. */ @@ -434,25 +466,111 @@ void adc_lld_start_conversion(ADCDriver *adcp) { /* TODO: make the number of WD registers a parameter in the registry, modify the configuration structure.*/ /* Sets thresholds’ values and active watchdog threshold interrupts if any.*/ - if (adcp->grpp->wtimr != 0) { - adcp->adc_tagp->TRC[0].R = adcp->grpp->trcr[0]; - adcp->adc_tagp->TRC[1].R = adcp->grpp->trcr[1]; - adcp->adc_tagp->TRC[2].R = adcp->grpp->trcr[2]; - adcp->adc_tagp->TRC[3].R = adcp->grpp->trcr[3]; - adcp->adc_tagp->THRHLR[0].R = adcp->grpp->thrhlr[0]; - adcp->adc_tagp->THRHLR[1].R = adcp->grpp->thrhlr[1]; - adcp->adc_tagp->THRHLR[2].R = adcp->grpp->thrhlr[2]; - adcp->adc_tagp->THRHLR[3].R = adcp->grpp->thrhlr[3]; - adcp->adc_tagp->WTIMR.R = adcp->grpp->wtimr; - } +#if SPC5_ADC_NTRESHOLD == 4 + for (i = 0; i < SPC5_ADC_NTRESHOLD; i++) { + switch (adcp->grpp->thresholds[i].threshold_mode){ + case ADC_THRHLR_DISABLED: + break; + case ADC_THRHLR_HIGHER: + /* Sets threshold registers.*/ + adcp->adc_tagp->TRC[i].R = (1U << 15) | adcp->grpp->thresholds[i].adc_ch; + adcp->adc_tagp->THRHLR[i].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; - /* mask = ((1 << nchannels) - 1) << firstchannel.*/ - /* TODO: Make the channels a mash in the configuration and just assign it.*/ - /* Active ADC channels for the conversion and sets the ADC DMA channels.*/ - for (i = adcp->grpp->init_channel; i <= adcp->grpp->final_channel; i++) { - adcp->adc_tagp->NCMR[0].R |= 1U << i; - adcp->adc_tagp->DMAR[0].R |= 1U << i; + /* Active interrupts.*/ + adcp->adc_tagp->WTIMR.R = 1U << (4U + i); + adcp->adc_tagp->CIMR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + break; + case ADC_THRHLR_LOWER: + /* Sets threshold registers.*/ + adcp->adc_tagp->TRC[i].R = (1U << 15) | adcp->grpp->thresholds[i].adc_ch; + adcp->adc_tagp->THRHLR[i].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + + /* Active interrupts.*/ + adcp->adc_tagp->WTIMR.R = 1U << i; + adcp->adc_tagp->CIMR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + break; + case ADC_THRHLR_BOTH_HL: + /* Sets threshold registers.*/ + adcp->adc_tagp->TRC[i].R = (1U << 15) | adcp->grpp->thresholds[i].adc_ch; + adcp->adc_tagp->THRHLR[i].B.THRL = adcp->grpp->thresholds[i].low_threshold_value; + adcp->adc_tagp->THRHLR[i].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + + /* Active interrupts.*/ + adcp->adc_tagp->WTIMR.R = (1U << i) | (1U << (4U + i)); + adcp->adc_tagp->CIMR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + break; + } } +#elif SPC5_ADC_NTRESHOLD == 16 + for (i = 0; i < SPC5_ADC_NTRESHOLD; i++) { + switch (adcp->grpp->thresholds[i].threshold_mode){ + case ADC_THRHLR_DISABLED: + break; + case ADC_THRHLR_HIGHER: + /* Sets threshold registers.*/ + if (adcp->grpp->thresholds[i].adc_ch > 7U) { + adcp->adc_tagp->CWSEL[1].R = i << ((adcp->grpp->thresholds[i].adc_ch - 8U) * 4U); + } else { + adcp->adc_tagp->CWSEL[0].R = i << (adcp->grpp->thresholds[i].adc_ch * 4U); + } + + adcp->adc_tagp->CWENR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + if (i > 4U) { + adcp->adc_tagp->THRHLR_2[i - 4U].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + } else { + adcp->adc_tagp->THRHLR[i].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + } + + /* Active interrupts.*/ + adcp->adc_tagp->WTIMR.R = 1U << (1U + i * 2U); + adcp->adc_tagp->CIMR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + break; + case ADC_THRHLR_LOWER: + /* Sets threshold registers.*/ + if (adcp->grpp->thresholds[i].adc_ch > 7U) { + adcp->adc_tagp->CWSEL[1].R = i << ((adcp->grpp->thresholds[i].adc_ch - 8U) * 4U); + } else { + adcp->adc_tagp->CWSEL[0].R = i << (adcp->grpp->thresholds[i].adc_ch * 4U); + } + adcp->adc_tagp->CWENR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + if (i > 4U) { + adcp->adc_tagp->THRHLR_2[i - 4U].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + } else { + adcp->adc_tagp->THRHLR[i].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + } + + /* Active interrupts.*/ + adcp->adc_tagp->WTIMR.R = 1U << (i * 2U); + adcp->adc_tagp->CIMR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + break; + case ADC_THRHLR_BOTH_HL: + /* Sets threshold registers.*/ + if (adcp->grpp->thresholds[i].adc_ch > 7U) { + adcp->adc_tagp->CWSEL[1].R = i << ((adcp->grpp->thresholds[i].adc_ch - 8U) * 4U); + } else { + adcp->adc_tagp->CWSEL[0].R = i << (adcp->grpp->thresholds[i].adc_ch * 4U); + } + adcp->adc_tagp->CWENR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + if (i > 4U) { + adcp->adc_tagp->THRHLR_2[i - 4U].B.THRL = adcp->grpp->thresholds[i].low_threshold_value; + adcp->adc_tagp->THRHLR_2[i - 4U].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + } else { + adcp->adc_tagp->THRHLR[i].B.THRL = adcp->grpp->thresholds[i].low_threshold_value; + adcp->adc_tagp->THRHLR[i].B.THRH = adcp->grpp->thresholds[i].high_threshold_value; + } + + /* Active interrupts.*/ + adcp->adc_tagp->WTIMR.R = (1U << (1U + i * 2U)) | (1U << (i * 2U)); + adcp->adc_tagp->CIMR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch; + break; + } + } +#endif + + /* Active ADC channels for the conversion and sets the ADC DMA channels.*/ + ch_mask = ((1 << adcp->grpp->num_channels) - 1) << adcp->grpp->init_channel; + adcp->adc_tagp->NCMR[0].R = ch_mask; + adcp->adc_tagp->DMAR[0].R = ch_mask; /* Sets ADC conversion timing register.*/ adcp->adc_tagp->CTR[0].R = adcp->grpp->ctr; diff --git a/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.h b/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.h index b08c0f1a1..da46b14ca 100644 --- a/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.h +++ b/os/hal/platforms/SPC5xx/ADC_v1/adc_lld.h @@ -37,42 +37,23 @@ * @name Analog channel identifiers * @{ */ -#if SPC5_HAS_ADC0 || defined(__DOXYGEN__) -#define ADC0_CHN_AN0 0U -#define ADC0_CHN_AN1 1U -#define ADC0_CHN_AN2 2U -#define ADC0_CHN_AN3 3U -#define ADC0_CHN_AN4 4U -#define ADC0_CHN_AN5 5U -#define ADC0_CHN_AN6 6U -#define ADC0_CHN_AN7 7U -#define ADC0_CHN_AN8 8U -#define ADC0_CHN_AN9 9U -#define ADC0_CHN_AN10 10U -#define ADC0_CHN_AN11 11U -#define ADC0_CHN_AN12 12U -#define ADC0_CHN_AN13 13U -#define ADC0_CHN_AN14 14U -#define ADC0_CHN_AN15 15U -#endif - -#if SPC5_HAS_ADC1 || defined(__DOXYGEN__) -#define ADC1_CHN_AN0 0U -#define ADC1_CHN_AN1 1U -#define ADC1_CHN_AN2 2U -#define ADC1_CHN_AN3 3U -#define ADC1_CHN_AN4 4U -#define ADC1_CHN_AN5 5U -#define ADC1_CHN_AN6 6U -#define ADC1_CHN_AN7 7U -#define ADC1_CHN_AN8 8U -#define ADC1_CHN_AN9 9U -#define ADC1_CHN_AN10 10U -#define ADC1_CHN_AN11 11U -#define ADC1_CHN_AN12 12U -#define ADC1_CHN_AN13 13U -#define ADC1_CHN_AN14 14U -#define ADC1_CHN_AN15 15U +#if SPC5_HAS_ADC0 || SPC5_HAS_ADC1 || defined(__DOXYGEN__) +#define ADC_CHN_AN0 0U +#define ADC_CHN_AN1 1U +#define ADC_CHN_AN2 2U +#define ADC_CHN_AN3 3U +#define ADC_CHN_AN4 4U +#define ADC_CHN_AN5 5U +#define ADC_CHN_AN6 6U +#define ADC_CHN_AN7 7U +#define ADC_CHN_AN8 8U +#define ADC_CHN_AN9 9U +#define ADC_CHN_AN10 10U +#define ADC_CHN_AN11 11U +#define ADC_CHN_AN12 12U +#define ADC_CHN_AN13 13U +#define ADC_CHN_AN14 14U +#define ADC_CHN_AN15 15U #endif /** @} */ @@ -323,6 +304,17 @@ typedef enum { PERIPHERAL_SET_CLOCK_FREQUENCY = 1 /**< ADC clock frequency is equal to Peripheral Set Clock frequency. */ } adc_clock; +/** + * @brief ADC thresholds. + */ +typedef enum { + ADC_THRHLR_DISABLED = 0, /**< Watchdog threshold disabled. */ + ADC_THRHLR_HIGHER = 1, /**< Watchdog higher threshold enabled. */ + ADC_THRHLR_LOWER = 2, /**< Watchdog lower threshold enabled. */ + ADC_THRHLR_BOTH_HL = 3, /**< Watchdog higher and lower thresholds enabled.*/ + +} adcthrhlr_t; + /** * @brief ADC sample data type. */ @@ -348,6 +340,7 @@ typedef enum { ADC_ERR_AWD2_LT = 6, /**< Watchdog 2 triggered Lower Threshold. */ ADC_ERR_AWD3_HT = 7, /**< Watchdog 3 triggered Higher Threshold. */ ADC_ERR_AWD3_LT = 8, /**< Watchdog 3 triggered Lower Threshold. */ + } adcerror_t; /** @@ -374,6 +367,28 @@ typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n); */ typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err); +/** + * @brief ADC threshold structure. + */ +typedef struct { + /** + * @brief ADC channel watchdog mode selection. + */ + adcthrhlr_t threshold_mode; + /** + * @brief ADC channel selection. + */ + uint16_t adc_ch; + /** + * @brief ADC channel high threshold value. + */ + uint16_t high_threshold_value; + /** + * @brief ADC channel low threshold value. + */ + uint16_t low_threshold_value; +} ADCThrhlr; + /** * @brief Conversion group configuration structure. * @details This implementation-dependent structure describes a conversion @@ -400,17 +415,13 @@ typedef struct { adcerrorcallback_t error_cb; /* End of the mandatory fields.*/ /** - * @brief ADC WTIMR register initialization data. + * @brief ADC Threshold configuration data. */ - uint32_t wtimr; - /** - * @brief ADC TRCx register initialization data. - */ - uint32_t trcr[4]; - /** - * @brief ADC THRHLRx register initialization data. - */ - uint32_t thrhlr[4]; +#if SPC5_ADC_NTRESHOLD == 4 + ADCThrhlr thresholds[4]; +#elif SPC5_ADC_NTRESHOLD == 16 + ADCThrhlr thresholds[16]; +#endif /** * @brief ADC CTR0 register initialization data. */ @@ -423,21 +434,14 @@ typedef struct { * @brief ADC Initial conversion channel. */ uint32_t init_channel; - /** - * @brief ADC Final conversion channel. - */ - uint32_t final_channel; } ADCConversionGroup; /** * @brief Driver configuration structure. - * @note It could be empty on some architectures. + * @note Empty in this implementation can be ignored. */ typedef struct { - /** - * @brief Analog clock frequency. - */ - adc_clock clock; + uint32_t dummy; } ADCConfig; /**