More ADCv3 work.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8576 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
Giovanni Di Sirio 2015-12-10 14:34:42 +00:00
parent f33a1bf193
commit c22bbe5104
3 changed files with 221 additions and 50 deletions

View File

@ -81,6 +81,27 @@ static const ADCConfig default_config = {
/* Driver local functions. */
/*===========================================================================*/
static void adc_lld_disable_clocks(void) {
bool disable;
#if defined(STM32F3XX)
#endif
#if defined(STM32L4XX)
#endif
#if STM32_ADC_USE_ADC1
if (&ADCD1 == adcp) {
rccDisableADC12(FALSE);
}
#endif
#if STM32_ADC_USE_ADC3
if (&ADCD3 == adcp)
rccDisableADC34(FALSE);
#endif
}
/**
* @brief Enables the ADC voltage regulator.
*
@ -88,12 +109,23 @@ static const ADCConfig default_config = {
*/
static void adc_lld_vreg_on(ADCDriver *adcp) {
#if defined(STM32F3XX)
adcp->adcm->CR = 0; /* RM 12.4.3.*/
adcp->adcm->CR = ADC_CR_ADVREGEN_0;
#if STM32_ADC_DUAL_MODE
adcp->adcs->CR = ADC_CR_ADVREGEN_0;
#endif
osalSysPolledDelayX(OSAL_US2RTC(STM32_HCLK, 10));
#endif
#if defined(STM32L4XX)
adcp->adcm->CR = 0; /* RM 16.3.6.*/
adcp->adcm->CR = ADC_CR_ADVREGEN;
#if STM32_ADC_DUAL_MODE
adcp->adcs->CR = ADC_CR_ADVREGEN;
#endif
osalSysPolledDelayX(OSAL_US2RTC(STM32_HCLK, 20));
#endif
}
/**
@ -103,11 +135,23 @@ static void adc_lld_vreg_on(ADCDriver *adcp) {
*/
static void adc_lld_vreg_off(ADCDriver *adcp) {
#if defined(STM32F3XX)
adcp->adcm->CR = 0; /* RM 12.4.3.*/
adcp->adcm->CR = ADC_CR_ADVREGEN_1;
#if STM32_ADC_DUAL_MODE
adcp->adcs->CR = 0;
adcp->adcs->CR = ADC_CR_ADVREGEN_1;
#endif
#endif
#if defined(STM32L4XX)
adcp->adcm->CR = 0; /* RM 12.4.3.*/
adcp->adcm->CR = ADC_CR_DEEPPWD;
#if STM32_ADC_DUAL_MODE
adcp->adcs->CR = 0;
adcp->adcs->CR = ADC_CR_DEEPPWD;
#endif
#endif
}
/**
@ -117,6 +161,7 @@ static void adc_lld_vreg_off(ADCDriver *adcp) {
*/
static void adc_lld_analog_on(ADCDriver *adcp) {
#if defined(STM32F3XX)
adcp->adcm->CR |= ADC_CR_ADEN;
while ((adcp->adcm->ISR & ADC_ISR_ADRD) == 0)
;
@ -125,6 +170,18 @@ static void adc_lld_analog_on(ADCDriver *adcp) {
while ((adcp->adcs->ISR & ADC_ISR_ADRD) == 0)
;
#endif
#endif
#if defined(STM32L4XX)
adcp->adcm->CR |= ADC_CR_ADEN;
while ((adcp->adcm->ISR & ADC_ISR_ADRDY) == 0)
;
#if STM32_ADC_DUAL_MODE
adcp->adcs->CR |= ADC_CR_ADEN;
while ((adcp->adcs->ISR & ADC_ISR_ADRDY) == 0)
;
#endif
#endif
}
/**
@ -151,6 +208,7 @@ static void adc_lld_analog_off(ADCDriver *adcp) {
*/
static void adc_lld_calibrate(ADCDriver *adcp) {
#if defined(STM32F3XX)
osalDbgAssert(adcp->adcm->CR == ADC_CR_ADVREGEN_0, "invalid register state");
adcp->adcm->CR |= ADC_CR_ADCAL;
while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0)
@ -161,6 +219,20 @@ static void adc_lld_calibrate(ADCDriver *adcp) {
while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0)
;
#endif
#endif
#if defined(STM32L4XX)
osalDbgAssert(adcp->adcm->CR == ADC_CR_ADVREGEN, "invalid register state");
adcp->adcm->CR |= ADC_CR_ADCAL;
while ((adcp->adcm->CR & ADC_CR_ADCAL) != 0)
;
#if STM32_ADC_DUAL_MODE
osalDbgAssert(adcp->adcs->CR == ADC_CR_ADVREGEN, "invalid register state");
adcp->adcs->CR |= ADC_CR_ADCAL;
while ((adcp->adcs->CR & ADC_CR_ADCAL) != 0)
;
#endif
#endif
}
/**
@ -326,18 +398,14 @@ void adc_lld_init(void) {
#if STM32_ADC_USE_ADC1
/* Driver initialization.*/
adcObjectInit(&ADCD1);
#if defined(ADC1_2_COMMON)
ADCD1.adcc = ADC1_2_COMMON;
#else
ADCD1.adcc = ADC1_COMMON;
#endif
ADCD1.adcm = ADC1;
#if STM32_ADC_DUAL_MODE
ADCD1.adcs = ADC2;
ADCD1.adcc = ADC1_2_COMMON;
#endif
ADCD1.dmastp = STM32_DMA1_STREAM1;
ADCD1.dmamode = ADC_DMA_SIZE |
STM32_DMA_CR_PL(STM32_ADC_ADC12_DMA_PRIORITY) |
STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
@ -347,18 +415,14 @@ void adc_lld_init(void) {
#if STM32_ADC_USE_ADC3
/* Driver initialization.*/
adcObjectInit(&ADCD3);
#if defined(ADC3_4_COMMON)
ADCD3.adcc = ADC3_4_COMMON;
#else
ADCD3.adcc = ADC3_COMMON;
#endif
ADCD3.adcm = ADC3;
#if STM32_ADC_DUAL_MODE
ADCD3.adcs = ADC4;
ADCD3.adcc = ADC3_4_COMMON;
#endif
ADCD3.dmastp = STM32_DMA2_STREAM5;
ADCD3.dmamode = ADC_DMA_SIZE |
STM32_DMA_CR_PL(STM32_ADC_ADC12_DMA_PRIORITY) |
STM32_DMA_CR_PL(STM32_ADC_ADC3_DMA_PRIORITY) |
STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE |
STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE;
@ -367,6 +431,28 @@ void adc_lld_init(void) {
nvicEnableVector(ADC4_IRQn, STM32_ADC_ADC34_IRQ_PRIORITY);
#endif
#endif /* STM32_ADC_USE_ADC3 */
#if defined(STM32F3XX)
#if STM32_ADC_USE_ADC1 || STM32_ADC_USE_ADC2
rccEnableADC12(FALSE);
osalSysPolledDelayX(12);
ADC1_2_COMMON->CCR = STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA;
rccDisableADC12(FALSE);
#endif
#if STM32_ADC_USE_ADC3 || STM32_ADC_USE_ADC4
rccEnableADC34(FALSE);
osalSysPolledDelayX(12);
ADC3_4_COMMON->CCR = STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA;
rccDisableADC34(FALSE);
#endif
#endif
#if defined(STM32L4XX)
rccEnableADC123(FALSE);
osalSysPolledDelayX(12);
ADC123_COMMON->CCR = STM32_ADC_ADC123_CLOCK_MODE | ADC_DMA_MDMA;
rccDisableADC123(FALSE);
#endif
}
/**
@ -389,11 +475,16 @@ void adc_lld_start(ADCDriver *adcp) {
if (&ADCD1 == adcp) {
bool b;
b = dmaStreamAllocate(adcp->dmastp,
STM32_ADC_ADC12_DMA_IRQ_PRIORITY,
STM32_ADC_ADC1_DMA_IRQ_PRIORITY,
(stm32_dmaisr_t)adc_lld_serve_dma_interrupt,
(void *)adcp);
osalDbgAssert(!b, "stream already allocated");
#if defined(STM32F3XX)
rccEnableADC12(FALSE);
#endif
#if defined(STM32L4XX)
rccEnableADC123(FALSE);
#endif
}
#endif /* STM32_ADC_USE_ADC1 */
@ -401,11 +492,16 @@ void adc_lld_start(ADCDriver *adcp) {
if (&ADCD3 == adcp) {
bool b;
b = dmaStreamAllocate(adcp->dmastp,
STM32_ADC_ADC34_DMA_IRQ_PRIORITY,
STM32_ADC_ADC3_DMA_IRQ_PRIORITY,
(stm32_dmaisr_t)adc_lld_serve_dma_interrupt,
(void *)adcp);
osalDbgAssert(!b, "stream already allocated");
#if defined(STM32F3XX)
rccEnableADC34(FALSE);
#endif
#if defined(STM32L4XX)
rccEnableADC123(FALSE);
#endif
}
#endif /* STM32_ADC_USE_ADC2 */
@ -416,10 +512,6 @@ void adc_lld_start(ADCDriver *adcp) {
dmaStreamSetPeripheral(adcp->dmastp, &adcp->adcm->DR);
#endif
/* Clock source setting.*/
adcp->adcc->CCR = STM32_ADC_ADC12_CLOCK_MODE | ADC_DMA_MDMA;
/* Differential channels setting.*/
#if STM32_ADC_DUAL_MODE
adcp->adcm->DIFSEL = adcp->config->difsel;
@ -459,15 +551,7 @@ void adc_lld_stop(ADCDriver *adcp) {
adc_lld_analog_off(adcp);
adc_lld_vreg_off(adcp);
#if STM32_ADC_USE_ADC1
if (&ADCD1 == adcp)
rccDisableADC12(FALSE);
#endif
#if STM32_ADC_USE_ADC3
if (&ADCD3 == adcp)
rccDisableADC34(FALSE);
#endif
adc_lld_disable_clocks();
}
}
@ -479,16 +563,17 @@ void adc_lld_stop(ADCDriver *adcp) {
* @notapi
*/
void adc_lld_start_conversion(ADCDriver *adcp) {
uint32_t dmamode, ccr, cfgr;
uint32_t dmamode, cfgr;
const ADCConversionGroup *grpp = adcp->grpp;
#if STM32_ADC_DUAL_MODE
uint32_t ccr = grpp->ccr & ~(ADC_CCR_CKMODE_MASK | ADC_CCR_MDMA_MASK);
#endif
osalDbgAssert(!STM32_ADC_DUAL_MODE || ((grpp->num_channels & 1) == 0),
"odd number of channels in dual mode");
/* Calculating control registers values.*/
dmamode = adcp->dmamode;
ccr = grpp->ccr | (adcp->adcc->CCR & (ADC_CCR_CKMODE_MASK |
ADC_CCR_MDMA_MASK));
cfgr = grpp->cfgr | ADC_CFGR_DMAEN;
if (grpp->circular) {
dmamode |= STM32_DMA_CR_CIRC;
@ -516,17 +601,19 @@ void adc_lld_start_conversion(ADCDriver *adcp) {
dmaStreamSetMode(adcp->dmastp, dmamode);
dmaStreamEnable(adcp->dmastp);
/* Configuring the CCR register with the static settings ORed with
the user-specified settings in the conversion group configuration
structure.*/
adcp->adcc->CCR = ccr;
/* ADC setup, if it is defined a callback for the analog watch dog then it
is enabled.*/
adcp->adcm->ISR = adcp->adcm->ISR;
adcp->adcm->IER = ADC_IER_OVR | ADC_IER_AWD1;
adcp->adcm->TR1 = grpp->tr1;
#if STM32_ADC_DUAL_MODE
/* Configuring the CCR register with the user-specified settings
in the conversion group configuration structure, static settings are
preserved.*/
adcp->adcc->CCR = (adcp->adcc->CCR &
(ADC_CCR_CKMODE_MASK | ADC_CCR_MDMA_MASK)) | ccr;
adcp->adcm->SMPR1 = grpp->smpr[0];
adcp->adcm->SMPR2 = grpp->smpr[1];
adcp->adcm->SQR1 = grpp->sqr[0] | ADC_SQR1_NUM_CH(grpp->num_channels / 2);
@ -569,6 +656,72 @@ void adc_lld_stop_conversion(ADCDriver *adcp) {
adc_lld_stop_adc(adcp);
}
/**
* @brief Enables the VREFEN bit.
* @details The VREFEN bit is required in order to sample the VREF channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*/
void adcSTM32EnableVREF(void) {
ADC123_COMMON->CCR |= ADC_CCR_VBATEN;
}
/**
* @brief Disables the VREFEN bit.
* @details The VREFEN bit is required in order to sample the VREF channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*/
void adcSTM32DisableVREF(void) {
ADC123_COMMON->CCR &= ~ADC_CCR_VBATEN;
}
/**
* @brief Enables the TSEN bit.
* @details The TSEN bit is required in order to sample the internal
* temperature sensor and internal reference voltage.
* @note This is an STM32-only functionality.
*/
void adcSTM32EnableTS(void) {
ADC123_COMMON->CCR |= ADC_CCR_TSEN;
}
/**
* @brief Disables the TSEN bit.
* @details The TSEN bit is required in order to sample the internal
* temperature sensor and internal reference voltage.
* @note This is an STM32-only functionality.
*/
void adcSTM32DisableTS(void) {
ADC123_COMMON->CCR &= ~ADC_CCR_TSEN;
}
/**
* @brief Enables the VBATEN bit.
* @details The VBATEN bit is required in order to sample the VBAT channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*/
void adcSTM32EnableVBAT(void) {
ADC123_COMMON->CCR |= ADC_CCR_VBATEN;
}
/**
* @brief Disables the VBATEN bit.
* @details The VBATEN bit is required in order to sample the VBAT channel.
* @note This is an STM32-only functionality.
* @note This function is meant to be called after @p adcStart().
*/
void adcSTM32DisableVBAT(void) {
ADC123_COMMON->CCR &= ~ADC_CCR_VBATEN;
}
#endif /* HAL_USE_ADC */
/** @} */

View File

@ -338,11 +338,19 @@
/* Units checks related to dual mode.*/
#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC1 && !STM32_HAS_ADC2
#error "ADC2 not present in the selected device"
#error "ADC2 not present in the selected device, required for dual mode"
#endif
#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC3 && !STM32_HAS_ADC4
#error "ADC4 not present in the selected device"
#error "ADC4 not present in the selected device, required for dual mode"
#endif
#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC2
#error "ADC2 cannot be used in dual mode"
#endif
#if STM32_ADC_DUAL_MODE && STM32_ADC_USE_ADC4
#error "ADC4 cannot be used in dual mode"
#endif
/* At least one ADC must be assigned.*/
@ -555,12 +563,6 @@ typedef struct {
* @brief ADC TR1 register initialization data.
*/
uint32_t tr1;
/**
* @brief ADC CCR register initialization data.
* @note The bits CKMODE, MDMA, DMACFG are enforced internally to the
* driver, keep them to zero.
*/
uint32_t ccr;
/**
* @brief ADC SMPRx registers initialization data.
*/
@ -570,12 +572,21 @@ typedef struct {
*/
uint32_t sqr[4];
#if STM32_ADC_DUAL_MODE || defined(__DOXYGEN__)
/**
* @brief ADC CCR register initialization data.
* @note The bits CKMODE, MDMA, DMACFG are enforced internally to the
* driver, keep them to zero.
* @note This field is only present in dual mode.
*/
uint32_t ccr;
/**
* @brief Slave ADC SMPRx registers initialization data.
* @note This field is only present in dual mode.
*/
uint32_t ssmpr[2];
/**
* @brief Slave ADC SQRx register initialization data.
* @note This field is only present in dual mode.
*/
uint32_t ssqr[4];
#endif /* STM32_ADC_DUAL_MODE */
@ -631,10 +642,6 @@ struct ADCDriver {
ADC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the common ADCx_y registers block.
*/
ADC_Common_TypeDef *adcc;
/**
* @brief Pointer to the master ADCx registers block.
*/
@ -644,6 +651,10 @@ struct ADCDriver {
* @brief Pointer to the slave ADCx registers block.
*/
ADC_TypeDef *adcs;
/**
* @brief Pointer to the common ADCx_y registers block.
*/
ADC_Common_TypeDef *adcc;
#endif /* STM32_ADC_DUAL_MODE */
/**
* @brief Pointer to associated DMA channel.
@ -749,6 +760,12 @@ extern "C" {
void adc_lld_stop(ADCDriver *adcp);
void adc_lld_start_conversion(ADCDriver *adcp);
void adc_lld_stop_conversion(ADCDriver *adcp);
void adcSTM32EnableVREF(void);
void adcSTM32DisableVREF(void);
void adcSTM32EnableTS(void);
void adcSTM32DisableTS(void);
void adcSTM32EnableVBAT(void);
void adcSTM32DisableVBAT(void);
#ifdef __cplusplus
}
#endif

View File

@ -145,9 +145,9 @@ int main(void) {
chSysInit();
/*
* Activates the serial driver 1 using the driver default configuration.
* Activates the serial driver 2 using the driver default configuration.
*/
sdStart(&SD1, NULL);
sdStart(&SD2, NULL);
/*
* Starting GPT4 driver, it is used for triggering the ADC.
@ -164,7 +164,8 @@ int main(void) {
* Activates the ADC1 driver and the temperature sensor.
*/
adcStart(&ADCD1, NULL);
adcSTM32EnableTSVREFE();
adcSTM32EnableVREF();
adcSTM32EnableTS();
/*
* Starts an ADC continuous conversion triggered with a period of