1 /****************************************************************************
4 * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *************************************************************************** */
23 /***************************************************************************** */
24 /* Analog to Digital Converter (ADC) */
25 /***************************************************************************** */
27 /* ADC driver for the integrated ADC module of the LPC82x.
28 * Refer to LPC82x documentation (UM10800.pdf) for more information.
31 #include "core/system.h"
32 #include "drivers/adc.h"
34 /* ADC Clock should be as near to 30MHz as possible */
35 #define adc_clk_Val (30 * 1000 * 1000)
39 /***************************************************************************** */
40 /* Generic ADC handler */
41 void (*adc_int_callback)(uint32_t) = NULL;
42 void ADC_Handler(void)
44 volatile struct lpc_adc* adc = LPC_ADC_REGS;
45 uint32_t flags = adc->flags;
47 if (adc_int_callback != NULL) {
48 adc_int_callback(flags);
51 void ADC_SEQA_Handler(void) __attribute__ ((alias ("ADC_Handler")));
52 void ADC_SEQB_Handler(void) __attribute__ ((alias ("ADC_Handler")));
53 void ADC_THCMP_Handler(void) __attribute__ ((alias ("ADC_Handler")));
54 void ADC_OVR_Handler(void) __attribute__ ((alias ("ADC_Handler")));
56 /* Read the conversion from the given channel
57 * This function reads the conversion value directly in the data register and
58 * always returns a value.
59 * Return 0 if the value is a new one and no overrun occured.
60 * Return -EINVAL if channel does not exist
61 * Retuen 1 if the value is an old one
62 * Return 2 if an overrun occured
64 int adc_get_value(uint16_t * val, uint8_t channel)
66 struct lpc_adc* adc = LPC_ADC_REGS;
67 uint32_t save_reg = 0;
69 if (channel >= NB_ADC_CHANNELS)
72 /* Save the whole register as some bits are cleared when register is read */
73 save_reg = adc->data[channel];
74 *val = ((save_reg >> LPC_ADC_RESULT_SHIFT) & LPC_ADC_RESULT_MASK);
75 /* Has this conversion value been already read ? */
76 if (! (save_reg & LPC_ADC_CONV_DONE)) {
79 if (save_reg & LPC_ADC_OVERRUN) {
85 /* Start a conversion on the given channel (0 to 7) */
86 void adc_start_convertion_once(uint8_t channel, uint8_t seq_num, uint8_t use_int)
88 struct lpc_adc* adc = LPC_ADC_REGS;
91 if (channel >= NB_ADC_CHANNELS) {
94 if (seq_num >= NB_ADC_SEQUENCES) {
98 /* Set conversion channel bit */
99 reg_val = ADC_MCH(channel);
101 /* Use of interrupts for the specified channel ? */
103 /* Set interrupt Bit */
104 adc->int_en = ADC_MCH(channel);
109 /* Start conversion */
110 reg_val |= (LPC_ADC_START_CONV_NOW | LPC_ADC_SEQ_EN);
111 adc->seqctrl[seq_num] = reg_val;
115 /* Start burst conversions.
116 * channels is a bit mask of requested channels.
117 * Use ADC_MCH(x) (x = 0 .. 7) for channels selection.
119 void adc_start_burst_conversion(uint16_t channels, uint8_t seq_num)
121 struct lpc_adc* adc = LPC_ADC_REGS;
122 uint32_t reg_val = 0;
124 if (seq_num >= NB_ADC_SEQUENCES) {
128 /* Set conversion channel bits and burst mode */
129 reg_val = (channels & ADC_MCH_MASK);
130 reg_val |= LPC_ADC_BURST;
132 /* Do not use of interrupts in burst mode. */
133 /* If you need to, then you should also use DMA for data transfer, and make sure your code is
134 * able to handle the load */
135 if (seq_num == LPC_ADC_SEQA) {
136 adc->int_en &= ~(LPC_ADC_SEQA_INTEN);
138 adc->int_en &= ~(LPC_ADC_SEQB_INTEN);
141 /* Start conversion */
142 adc->seqctrl[seq_num] = (reg_val | LPC_ADC_SEQ_EN);
144 void adc_stop_burst_conversion(uint8_t seq_num)
146 struct lpc_adc* adc = LPC_ADC_REGS;
147 if (seq_num >= NB_ADC_SEQUENCES) {
150 adc->seqctrl[seq_num] &= ~LPC_ADC_BURST;
154 /* This should be used to configure conversion start on falling or rising edges of
155 * some signals, or on timer for burst conversions.
157 void adc_prepare_conversion_on_event(uint16_t channels, uint8_t event, uint8_t seq_num,
158 uint8_t use_int, uint32_t mode)
160 struct lpc_adc* adc = LPC_ADC_REGS;
161 uint32_t reg_val = 0;
163 if (seq_num >= NB_ADC_SEQUENCES) {
167 /* Set conversion channel bits and burst mode */
168 reg_val |= (channels & ADC_MCH_MASK);
169 /* Set conversion condition bits */
171 case LPC_ADC_START_CONV_ADC_PINTRIG_0:
172 case LPC_ADC_START_CONV_ADC_PINTRIG_1:
173 case LPC_ADC_START_CONV_SCT0_OUT3:
174 case LPC_ADC_START_CONV_ACMP_OUT:
175 case LPC_ADC_START_CONV_ARM_TXEV:
176 reg_val |= LPC_ADC_START_CONV_EVENT(event);
179 case LPC_ADC_START_CONV_SOFT:
180 /* Trigger = 0 : already OK */
184 reg_val |= (mode & LPC_ADC_ADDITIONAL_MODE_MASK);
187 /* Use of interrupts for the specified channel ? */
189 if (seq_num == LPC_ADC_SEQA) {
190 adc->int_en = LPC_ADC_SEQA_INTEN;
192 adc->int_en = LPC_ADC_SEQB_INTEN;
198 /* Enable conversion on selected event */
199 adc->seqctrl[seq_num] = (reg_val | LPC_ADC_SEQ_EN);
202 /* Software trigger of the given configured sequence */
203 void adc_trigger_sequence_conversion(uint8_t seq_num)
205 struct lpc_adc* adc = LPC_ADC_REGS;
207 if (seq_num >= NB_ADC_SEQUENCES) {
211 adc->seqctrl[seq_num] |= (LPC_ADC_START_CONV_NOW);
215 /***************************************************************************** */
216 /* ADC Setup : private part : Clocks, Power and Mode */
218 /* When lowpower_en is not 0 the ADC low power mode is selected, which adds a 15ADC clock delay
219 * before each set of consecutive conversions (but not between consecutive conversions)
221 void adc_set_low_power(int lowpower_en)
223 struct lpc_adc* adc = LPC_ADC_REGS;
225 adc->ctrl |= LPC_ADC_LOW_POWER_EN;
227 adc->ctrl &= ~(LPC_ADC_LOW_POWER_EN);
231 void adc_clk_update(void)
233 struct lpc_adc* adc = LPC_ADC_REGS;
234 uint32_t main_clock = get_main_clock();
237 /* Configure ADC clock to get the 9MHz sample clock */
238 clkdiv = (main_clock / adc_clk_Val);
239 adc->ctrl &= ~LPC_ADC_CLK_MASK;
240 adc->ctrl |= LPC_ADC_CLK_DIV(clkdiv);
244 void adc_on(void (*adc_callback)(uint32_t))
246 struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
247 struct lpc_adc* adc = LPC_ADC_REGS;
249 /* Disable ADC Interrupts */
250 NVIC_DisableIRQ(ADC_SEQA_IRQ);
251 NVIC_DisableIRQ(ADC_SEQB_IRQ);
252 NVIC_DisableIRQ(ADC_THCMP_IRQ);
253 NVIC_DisableIRQ(ADC_OVR_IRQ);
256 sys_config->powerdown_run_cfg &= ~LPC_POWER_DOWN_ADC;
257 /* Provide clock to ADC */
258 subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 1);
262 /* Prevent unconfigured conversion start */
266 /* Remove the default global interrupt enabled setting */
268 /* Register a possible calback */
269 adc_int_callback = adc_callback;
271 /* Enable ADC Interrupts */
272 NVIC_EnableIRQ(ADC_SEQA_IRQ);
273 NVIC_EnableIRQ(ADC_SEQB_IRQ);
274 NVIC_EnableIRQ(ADC_THCMP_IRQ);
275 NVIC_EnableIRQ(ADC_OVR_IRQ);
280 struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
282 /* Disable ADC Interrupts */
283 NVIC_DisableIRQ(ADC_SEQA_IRQ);
284 NVIC_DisableIRQ(ADC_SEQB_IRQ);
285 NVIC_DisableIRQ(ADC_THCMP_IRQ);
286 NVIC_DisableIRQ(ADC_OVR_IRQ);
287 /* Remove callback */
288 adc_int_callback = NULL;
290 sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_ADC;
291 /* Remove clock from ADC block */
292 subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 0);