git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@6487 35acf78f-673a-0410-8e92-d51de3d6d3f4

This commit is contained in:
pcirillo 2013-11-18 14:23:46 +00:00
parent d9385f98fa
commit 8ba7e03ed5
2 changed files with 222 additions and 100 deletions

View File

@ -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_EOC_NUMBER].R = SPC5_ADC_ADC0_EOC_PRIORITY;
INTC.PSR[SPC5_ADC0_ER_NUMBER].R = SPC5_ADC_ADC0_ER_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; 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 #endif
#if SPC5_ADC_USE_ADC1 #if SPC5_ADC_USE_ADC1
INTC.PSR[SPC5_ADC1_EOC_NUMBER].R = SPC5_ADC_ADC1_EOC_PRIORITY; 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_ER_NUMBER].R = SPC5_ADC_ADC1_ER_PRIORITY;
INTC.PSR[SPC5_ADC1_WD_NUMBER].R = SPC5_ADC_ADC1_WD_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 #endif
} }
@ -328,15 +338,7 @@ void adc_lld_start(ADCDriver *adcp) {
adcp->adc_tagp->MCR.B.PWDN = 0; adcp->adc_tagp->MCR.B.PWDN = 0;
/* Power up delay.*/ /* Power up delay.*/
/* TODO: add a delay of 5uS.*/ osalThreadSleep(US2ST(5));
/* 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;
}
/* Sets MCR Register.*/ /* Sets MCR Register.*/
adcp->adc_tagp->MCR.R = ADC_MCR_OWREN | ADC_MCR_MODE; 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.*/ /* Releases the allocated DMA channel.*/
edmaChannelRelease(adcp->adc_dma_channel); edmaChannelRelease(adcp->adc_dma_channel);
/* Clears thresholds values and deactives watchdog threshold interrupts.*/ /* Clears thresholds values and deactive watchdog threshold interrupts.*/
/* TODO: make the number of WD registers a parameter in the registry, modify #if SPC5_ADC_NTRESHOLD == 4
the configuration structure.*/ adcp->adc_tagp->TRC[0].R = 0;
if (adcp->grpp->wtimr != 0) { adcp->adc_tagp->TRC[1].R = 0;
adcp->adc_tagp->TRC[0].R = 0; adcp->adc_tagp->TRC[2].R = 0;
adcp->adc_tagp->TRC[1].R = 0; adcp->adc_tagp->TRC[3].R = 0;
adcp->adc_tagp->TRC[2].R = 0; adcp->adc_tagp->THRHLR[0].R = 0;
adcp->adc_tagp->TRC[3].R = 0; adcp->adc_tagp->THRHLR[1].R = 0;
adcp->adc_tagp->THRHLR[0].R = 0; adcp->adc_tagp->THRHLR[2].R = 0;
adcp->adc_tagp->THRHLR[1].R = 0; adcp->adc_tagp->THRHLR[3].R = 0;
adcp->adc_tagp->THRHLR[2].R = 0; adcp->adc_tagp->WTIMR.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->NCMR[0].R = 0;
adcp->adc_tagp->DMAR[0].R = 0; adcp->adc_tagp->DMAR[0].R = 0;
@ -405,14 +439,12 @@ void adc_lld_stop(ADCDriver *adcp) {
* @notapi * @notapi
*/ */
void adc_lld_start_conversion(ADCDriver *adcp) { void adc_lld_start_conversion(ADCDriver *adcp) {
uint32_t ch_mask;
uint8_t i; uint8_t i;
//osalDbgAssert(adcp->grpp->num_channels*2 >= adcp->depth,
// "adc_lld_start_conversion(), #1", "too many elements");
/* Setting up DMA TCD parameters.*/ /* Setting up DMA TCD parameters.*/
edmaChannelSetup(adcp->adc_dma_channel, /* channel. */ 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. */ adcp->samples, /* dst. */
4, /* soff, advance by four. */ 4, /* soff, advance by four. */
2, /* doff, advance by two. */ 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 /* TODO: make the number of WD registers a parameter in the registry, modify
the configuration structure.*/ the configuration structure.*/
/* Sets thresholds values and active watchdog threshold interrupts if any.*/ /* Sets thresholds values and active watchdog threshold interrupts if any.*/
if (adcp->grpp->wtimr != 0) { #if SPC5_ADC_NTRESHOLD == 4
adcp->adc_tagp->TRC[0].R = adcp->grpp->trcr[0]; for (i = 0; i < SPC5_ADC_NTRESHOLD; i++) {
adcp->adc_tagp->TRC[1].R = adcp->grpp->trcr[1]; switch (adcp->grpp->thresholds[i].threshold_mode){
adcp->adc_tagp->TRC[2].R = adcp->grpp->trcr[2]; case ADC_THRHLR_DISABLED:
adcp->adc_tagp->TRC[3].R = adcp->grpp->trcr[3]; break;
adcp->adc_tagp->THRHLR[0].R = adcp->grpp->thrhlr[0]; case ADC_THRHLR_HIGHER:
adcp->adc_tagp->THRHLR[1].R = adcp->grpp->thrhlr[1]; /* Sets threshold registers.*/
adcp->adc_tagp->THRHLR[2].R = adcp->grpp->thrhlr[2]; adcp->adc_tagp->TRC[i].R = (1U << 15) | adcp->grpp->thresholds[i].adc_ch;
adcp->adc_tagp->THRHLR[3].R = adcp->grpp->thrhlr[3]; adcp->adc_tagp->THRHLR[i].B.THRH = adcp->grpp->thresholds[i].high_threshold_value;
adcp->adc_tagp->WTIMR.R = adcp->grpp->wtimr;
}
/* mask = ((1 << nchannels) - 1) << firstchannel.*/ /* Active interrupts.*/
/* TODO: Make the channels a mash in the configuration and just assign it.*/ adcp->adc_tagp->WTIMR.R = 1U << (4U + i);
/* Active ADC channels for the conversion and sets the ADC DMA channels.*/ adcp->adc_tagp->CIMR[0].R = 1U << adcp->grpp->thresholds[i].adc_ch;
for (i = adcp->grpp->init_channel; i <= adcp->grpp->final_channel; i++) { break;
adcp->adc_tagp->NCMR[0].R |= 1U << i; case ADC_THRHLR_LOWER:
adcp->adc_tagp->DMAR[0].R |= 1U << i; /* 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.*/ /* Sets ADC conversion timing register.*/
adcp->adc_tagp->CTR[0].R = adcp->grpp->ctr; adcp->adc_tagp->CTR[0].R = adcp->grpp->ctr;

View File

@ -37,42 +37,23 @@
* @name Analog channel identifiers * @name Analog channel identifiers
* @{ * @{
*/ */
#if SPC5_HAS_ADC0 || defined(__DOXYGEN__) #if SPC5_HAS_ADC0 || SPC5_HAS_ADC1 || defined(__DOXYGEN__)
#define ADC0_CHN_AN0 0U #define ADC_CHN_AN0 0U
#define ADC0_CHN_AN1 1U #define ADC_CHN_AN1 1U
#define ADC0_CHN_AN2 2U #define ADC_CHN_AN2 2U
#define ADC0_CHN_AN3 3U #define ADC_CHN_AN3 3U
#define ADC0_CHN_AN4 4U #define ADC_CHN_AN4 4U
#define ADC0_CHN_AN5 5U #define ADC_CHN_AN5 5U
#define ADC0_CHN_AN6 6U #define ADC_CHN_AN6 6U
#define ADC0_CHN_AN7 7U #define ADC_CHN_AN7 7U
#define ADC0_CHN_AN8 8U #define ADC_CHN_AN8 8U
#define ADC0_CHN_AN9 9U #define ADC_CHN_AN9 9U
#define ADC0_CHN_AN10 10U #define ADC_CHN_AN10 10U
#define ADC0_CHN_AN11 11U #define ADC_CHN_AN11 11U
#define ADC0_CHN_AN12 12U #define ADC_CHN_AN12 12U
#define ADC0_CHN_AN13 13U #define ADC_CHN_AN13 13U
#define ADC0_CHN_AN14 14U #define ADC_CHN_AN14 14U
#define ADC0_CHN_AN15 15U #define ADC_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
#endif #endif
/** @} */ /** @} */
@ -323,6 +304,17 @@ typedef enum {
PERIPHERAL_SET_CLOCK_FREQUENCY = 1 /**< ADC clock frequency is equal to Peripheral Set Clock frequency. */ PERIPHERAL_SET_CLOCK_FREQUENCY = 1 /**< ADC clock frequency is equal to Peripheral Set Clock frequency. */
} adc_clock; } 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. * @brief ADC sample data type.
*/ */
@ -348,6 +340,7 @@ typedef enum {
ADC_ERR_AWD2_LT = 6, /**< Watchdog 2 triggered Lower Threshold. */ ADC_ERR_AWD2_LT = 6, /**< Watchdog 2 triggered Lower Threshold. */
ADC_ERR_AWD3_HT = 7, /**< Watchdog 3 triggered Higher Threshold. */ ADC_ERR_AWD3_HT = 7, /**< Watchdog 3 triggered Higher Threshold. */
ADC_ERR_AWD3_LT = 8, /**< Watchdog 3 triggered Lower Threshold. */ ADC_ERR_AWD3_LT = 8, /**< Watchdog 3 triggered Lower Threshold. */
} adcerror_t; } 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); 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. * @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion * @details This implementation-dependent structure describes a conversion
@ -400,17 +415,13 @@ typedef struct {
adcerrorcallback_t error_cb; adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
/** /**
* @brief ADC WTIMR register initialization data. * @brief ADC Threshold configuration data.
*/ */
uint32_t wtimr; #if SPC5_ADC_NTRESHOLD == 4
/** ADCThrhlr thresholds[4];
* @brief ADC TRCx register initialization data. #elif SPC5_ADC_NTRESHOLD == 16
*/ ADCThrhlr thresholds[16];
uint32_t trcr[4]; #endif
/**
* @brief ADC THRHLRx register initialization data.
*/
uint32_t thrhlr[4];
/** /**
* @brief ADC CTR0 register initialization data. * @brief ADC CTR0 register initialization data.
*/ */
@ -423,21 +434,14 @@ typedef struct {
* @brief ADC Initial conversion channel. * @brief ADC Initial conversion channel.
*/ */
uint32_t init_channel; uint32_t init_channel;
/**
* @brief ADC Final conversion channel.
*/
uint32_t final_channel;
} ADCConversionGroup; } ADCConversionGroup;
/** /**
* @brief Driver configuration structure. * @brief Driver configuration structure.
* @note It could be empty on some architectures. * @note Empty in this implementation can be ignored.
*/ */
typedef struct { typedef struct {
/** uint32_t dummy;
* @brief Analog clock frequency.
*/
adc_clock clock;
} ADCConfig; } ADCConfig;
/** /**