diff options
-rw-r--r-- | chip/stm32/adc-stm32f0.c | 117 | ||||
-rw-r--r-- | chip/stm32/registers.h | 43 | ||||
-rw-r--r-- | common/adc.c | 3 | ||||
-rw-r--r-- | include/adc.h | 4 | ||||
-rw-r--r-- | include/config.h | 14 |
5 files changed, 150 insertions, 31 deletions
diff --git a/chip/stm32/adc-stm32f0.c b/chip/stm32/adc-stm32f0.c index 17cc8b7e2d..ca111d055e 100644 --- a/chip/stm32/adc-stm32f0.c +++ b/chip/stm32/adc-stm32f0.c @@ -18,18 +18,64 @@ struct mutex adc_lock; -static const struct dma_option dma_adc_option = { +struct adc_profile_t { + /* Register values. */ + uint32_t cfgr1_reg; + uint32_t cfgr2_reg; + uint32_t smpr_reg; + uint32_t ier_reg; + /* DMA config. */ + const struct dma_option *dma_option; + /* Size of DMA buffer, in units of ADC_CH_COUNT. */ + int dma_buffer_size; +}; + +#ifdef CONFIG_ADC_PROFILE_SINGLE +static const struct dma_option dma_single = { STM32_DMAC_ADC, (void *)&STM32_ADC_DR, STM32_DMA_CCR_MSIZE_32_BIT | STM32_DMA_CCR_PSIZE_32_BIT, }; +static const struct adc_profile_t profile = { + /* Sample all channels once using DMA */ + .cfgr1_reg = STM32_ADC_CFGR1_OVRMOD, + .cfgr2_reg = 0, + .smpr_reg = STM32_ADC_SMPR_13_5_CY, + .ier_reg = 0, + .dma_option = &dma_single, + .dma_buffer_size = 1, +}; +#endif + +#ifdef CONFIG_ADC_PROFILE_FAST_CONTINUOUS +static const struct dma_option dma_continuous = { + STM32_DMAC_ADC, (void *)&STM32_ADC_DR, + STM32_DMA_CCR_MSIZE_32_BIT | STM32_DMA_CCR_PSIZE_32_BIT | + STM32_DMA_CCR_CIRC, +}; + +static const struct adc_profile_t profile = { + /* Sample all channels continuously using DMA */ + .cfgr1_reg = STM32_ADC_CFGR1_OVRMOD | + STM32_ADC_CFGR1_CONT | + STM32_ADC_CFGR1_DMACFG, + .cfgr2_reg = 0, + .smpr_reg = STM32_ADC_SMPR_1_5_CY, + /* Fire interrupt at end of sequence. */ + .ier_reg = STM32_ADC_IER_EOSEQIE, + .dma_option = &dma_continuous, + /* Double-buffer our samples. */ + .dma_buffer_size = 2, +}; +#endif + static void adc_configure(int ain_id) { /* Select channel to convert */ STM32_ADC_CHSELR = 1 << ain_id; /* Disable DMA */ - STM32_ADC_CFGR1 &= ~0x1; + STM32_ADC_CFGR1 &= ~STM32_ADC_CFGR1_DMAEN; } #ifdef CONFIG_ADC_WATCHDOG @@ -42,7 +88,7 @@ static void adc_continuous_read(int ain_id) adc_configure(ain_id); /* CONT=1 -> continuous mode on */ - STM32_ADC_CFGR1 |= 1 << 13; + STM32_ADC_CFGR1 |= STM32_ADC_CFGR1_CONT; /* Start continuous conversion */ STM32_ADC_CR |= 1 << 2; /* ADSTART */ @@ -58,7 +104,7 @@ static void adc_continuous_stop(void) ; /* CONT=0 -> continuous mode off */ - STM32_ADC_CFGR1 &= ~(1 << 13); + STM32_ADC_CFGR1 &= ~STM32_ADC_CFGR1_CONT; } static void adc_interval_read(int ain_id, int interval_ms) @@ -66,10 +112,12 @@ static void adc_interval_read(int ain_id, int interval_ms) adc_configure(ain_id); /* EXTEN=01 -> hardware trigger detection on rising edge */ - STM32_ADC_CFGR1 = (STM32_ADC_CFGR1 & ~0xc00) | (1 << 10); + STM32_ADC_CFGR1 = (STM32_ADC_CFGR1 & ~STM32_ADC_CFGR1_EXTEN_MASK) + | STM32_ADC_CFGR1_EXTEN_RISE; /* EXTSEL=TRG3 -> Trigger on TIM3_TRGO */ - STM32_ADC_CFGR1 = (STM32_ADC_CFGR1 & ~0x1c0) | (3 << 6); + STM32_ADC_CFGR1 = (STM32_ADC_CFGR1 & ~STM32_ADC_CFGR1_TRG_MASK) | + STM32_ADC_CFGR1_TRG3; __hw_timer_enable_clock(TIM_ADC, 1); @@ -96,7 +144,7 @@ static void adc_interval_read(int ain_id, int interval_ms) static void adc_interval_stop(void) { /* EXTEN=00 -> hardware trigger detection disabled */ - STM32_ADC_CFGR1 &= ~0xc00; + STM32_ADC_CFGR1 &= ~STM32_ADC_CFGR1_EXTEN_MASK; /* Set ADSTP to clear ADSTART */ STM32_ADC_CR |= 1 << 4; /* ADSTP */ @@ -111,22 +159,22 @@ static void adc_interval_stop(void) static int adc_watchdog_enabled(void) { - return STM32_ADC_CFGR1 & (1 << 23); + return STM32_ADC_CFGR1 & STM32_ADC_CFGR1_AWDEN; } static int adc_enable_watchdog_no_lock(void) { /* Select channel */ - STM32_ADC_CFGR1 = (STM32_ADC_CFGR1 & ~0x7c000000) | + STM32_ADC_CFGR1 = (STM32_ADC_CFGR1 & ~STM32_ADC_CFGR1_AWDCH_MASK) | (watchdog_ain_id << 26); adc_configure(watchdog_ain_id); /* Clear AWD interupt flag */ STM32_ADC_ISR = 0x80; /* Set Watchdog enable bit on a single channel */ - STM32_ADC_CFGR1 |= (1 << 23) | (1 << 22); + STM32_ADC_CFGR1 |= STM32_ADC_CFGR1_AWDEN | STM32_ADC_CFGR1_AWDSGL; /* Enable interrupt */ - STM32_ADC_IER |= 1 << 7; + STM32_ADC_IER |= STM32_ADC_IER_AWDIE; if (watchdog_delay_ms) adc_interval_read(watchdog_ain_id, watchdog_delay_ms); @@ -160,7 +208,7 @@ static int adc_disable_watchdog_no_lock(void) adc_continuous_stop(); /* Clear Watchdog enable bit */ - STM32_ADC_CFGR1 &= ~(1 << 23); + STM32_ADC_CFGR1 &= ~STM32_ADC_CFGR1_AWDEN; return EC_SUCCESS; } @@ -240,14 +288,15 @@ int adc_read_all_channels(int *data) { int i; uint32_t channels = 0; - uint32_t raw_data[ADC_CH_COUNT]; const struct adc_t *adc; int restore_watchdog = 0; int ret = EC_SUCCESS; + int blocking_read = !profile.ier_reg; mutex_lock(&adc_lock); if (adc_watchdog_enabled()) { + ASSERT(blocking_read); restore_watchdog = 1; adc_disable_watchdog_no_lock(); } @@ -258,31 +307,41 @@ int adc_read_all_channels(int *data) STM32_ADC_CHSELR = channels; /* Enable DMA */ - STM32_ADC_CFGR1 |= 0x1; + STM32_ADC_CFGR1 |= STM32_ADC_CFGR1_DMAEN; dma_clear_isr(STM32_DMAC_ADC); - dma_start_rx(&dma_adc_option, ADC_CH_COUNT, raw_data); + dma_start_rx(profile.dma_option, + profile.dma_buffer_size * ADC_CH_COUNT, + data); /* Clear flags */ STM32_ADC_ISR = 0xe; + /* Enable requested interrupt(s) */ + STM32_ADC_IER |= profile.ier_reg; + if (!blocking_read) + task_enable_irq(STM32_IRQ_ADC_COMP); STM32_ADC_CR |= 1 << 2; /* ADSTART */ - if (dma_wait(STM32_DMAC_ADC)) { - ret = EC_ERROR_UNKNOWN; - goto fail; /* goto fail; goto fail; */ - } - - for (i = 0; i < ADC_CH_COUNT; ++i) { - adc = adc_channels + i; - data[i] = (raw_data[i] & 0xffff) * - adc->factor_mul / adc->factor_div + adc->shift; + if (blocking_read) { + if (dma_wait(STM32_DMAC_ADC)) { + ret = EC_ERROR_UNKNOWN; + goto fail; + } + + for (i = 0; i < ADC_CH_COUNT; ++i) { + adc = adc_channels + i; + data[i] = (data[i] & 0xffff) * + adc->factor_mul / adc->factor_div + + adc->shift; + } } fail: if (restore_watchdog) adc_enable_watchdog_no_lock(); - mutex_unlock(&adc_lock); + if (blocking_read) + mutex_unlock(&adc_lock); return ret; } @@ -306,11 +365,11 @@ static void adc_init(void) ; /* Single conversion, right aligned, 12-bit */ - STM32_ADC_CFGR1 = 1 << 12; /* (1 << 15) => AUTOOFF */; + STM32_ADC_CFGR1 = profile.cfgr1_reg; /* clock is ADCCLK (ADEN must be off when writing this reg) */ - STM32_ADC_CFGR2 = 0; - /* Sampling time : 13.5 ADC clock cycles. */ - STM32_ADC_SMPR = 2; + STM32_ADC_CFGR2 = profile.cfgr2_reg; + /* Sampling time */ + STM32_ADC_SMPR = profile.smpr_reg; /* * ADC enable (note: takes 4 ADC clocks between end of calibration diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 9352584d28..57fb2a9ec0 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -848,12 +848,55 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_ADC_ISR REG32(STM32_ADC1_BASE + 0x00) #define STM32_ADC_ISR_ADRDY (1 << 0) #define STM32_ADC_IER REG32(STM32_ADC1_BASE + 0x04) +#define STM32_ADC_IER_AWDIE (1 << 7) +#define STM32_ADC_IER_OVRIE (1 << 4) +#define STM32_ADC_IER_EOSEQIE (1 << 3) +#define STM32_ADC_IER_EOCIE (1 << 2) +#define STM32_ADC_IER_EOSMPIE (1 << 1) +#define STM32_ADC_IER_ADRDYIE (1 << 0) + #define STM32_ADC_CR REG32(STM32_ADC1_BASE + 0x08) #define STM32_ADC_CR_ADEN (1 << 0) #define STM32_ADC_CR_ADCAL (1 << 31) #define STM32_ADC_CFGR1 REG32(STM32_ADC1_BASE + 0x0C) +/* Analog watchdog channel selection */ +#define STM32_ADC_CFGR1_AWDCH_MASK (0x1f << 26) +#define STM32_ADC_CFGR1_AWDEN (1 << 23) +#define STM32_ADC_CFGR1_AWDSGL (1 << 22) +/* Selects single vs continuous */ +#define STM32_ADC_CFGR1_CONT (1 << 13) +/* Selects ADC_DR overwrite vs preserve */ +#define STM32_ADC_CFGR1_OVRMOD (1 << 12) +/* External trigger polarity selection */ +#define STM32_ADC_CFGR1_EXTEN_DIS (0 << 10) +#define STM32_ADC_CFGR1_EXTEN_RISE (1 << 10) +#define STM32_ADC_CFGR1_EXTEN_FALL (2 << 10) +#define STM32_ADC_CFGR1_EXTEN_BOTH (3 << 10) +#define STM32_ADC_CFGR1_EXTEN_MASK (3 << 10) +/* External trigger selection */ +#define STM32_ADC_CFGR1_TRG0 (0 << 6) +#define STM32_ADC_CFGR1_TRG1 (1 << 6) +#define STM32_ADC_CFGR1_TRG2 (2 << 6) +#define STM32_ADC_CFGR1_TRG3 (3 << 6) +#define STM32_ADC_CFGR1_TRG4 (4 << 6) +#define STM32_ADC_CFGR1_TRG5 (5 << 6) +#define STM32_ADC_CFGR1_TRG6 (6 << 6) +#define STM32_ADC_CFGR1_TRG7 (7 << 6) +#define STM32_ADC_CFGR1_TRG_MASK (7 << 6) +/* Selects circular vs one-shot */ +#define STM32_ADC_CFGR1_DMACFG (1 << 1) +#define STM32_ADC_CFGR1_DMAEN (1 << 0) #define STM32_ADC_CFGR2 REG32(STM32_ADC1_BASE + 0x10) +/* Sampling time selection - 1.5 ADC cycles min, 239.5 cycles max */ #define STM32_ADC_SMPR REG32(STM32_ADC1_BASE + 0x14) +#define STM32_ADC_SMPR_1_5_CY 0x0 +#define STM32_ADC_SMPR_7_5_CY 0x1 +#define STM32_ADC_SMPR_13_5_CY 0x2 +#define STM32_ADC_SMPR_28_5_CY 0x3 +#define STM32_ADC_SMPR_41_5_CY 0x4 +#define STM32_ADC_SMPR_55_5_CY 0x5 +#define STM32_ADC_SMPR_71_5_CY 0x6 +#define STM32_ADC_SMPR_239_5_CY 0x7 #define STM32_ADC_TR REG32(STM32_ADC1_BASE + 0x20) #define STM32_ADC_CHSELR REG32(STM32_ADC1_BASE + 0x28) #define STM32_ADC_DR REG32(STM32_ADC1_BASE + 0x40) diff --git a/common/adc.c b/common/adc.c index 696b017788..10e9399bdb 100644 --- a/common/adc.c +++ b/common/adc.c @@ -11,6 +11,8 @@ #include "console.h" #include "util.h" +/* 'adc' console command is not supported in continuous mode */ +#ifndef CONFIG_ADC_PROFILE_FAST_CONTINUOUS static enum adc_channel find_adc_channel_by_name(const char *name) { const struct adc_t *ch = adc_channels; @@ -55,3 +57,4 @@ DECLARE_CONSOLE_COMMAND(adc, command_adc, "[name]", "Print ADC channel(s)", NULL); +#endif diff --git a/include/adc.h b/include/adc.h index f7fbb0d3ac..a42fc376ee 100644 --- a/include/adc.h +++ b/include/adc.h @@ -33,7 +33,9 @@ int adc_read_channel(enum adc_channel ch); * Read all ADC channels. * * @param data Destination array for channel data; must be - * ADC_CH_COUNT elements long. + * ADC_CH_COUNT elements long for single-read profile, + * or sized according to dma_buffer_size in + * continuous profiles. * * @return EC_SUCCESS, or non-zero on error. */ diff --git a/include/config.h b/include/config.h index 1ca46f1d98..24daae1b34 100644 --- a/include/config.h +++ b/include/config.h @@ -84,13 +84,25 @@ /* Compile chip support for analog-to-digital convertor */ #undef CONFIG_ADC -/* ADC sample time selection. The value is chip-dependent. */ +/* + * ADC sample time selection. The value is chip-dependent. + * TODO: Replace this with CONFIG_ADC_PROFILE entries. + */ #undef CONFIG_ADC_SAMPLE_TIME /* Include the ADC analog watchdog feature in the ADC code */ #define CONFIG_ADC_WATCHDOG /* + * Chip-dependent ADC configuration - select one. + * SINGLE - Sample all inputs once when requested. + * FAST_CONTINUOUS - Sample all inputs continuously using DMA, with minimal + * sample time. + */ +#define CONFIG_ADC_PROFILE_SINGLE +#undef CONFIG_ADC_PROFILE_FAST_CONTINUOUS + +/* * Some ALS modules may be connected to the EC. We need the command, and * specific drivers for each module. */ |