From: Nathael Pajani Date: Wed, 6 Nov 2013 01:05:55 +0000 (+0100) Subject: Add ADC support X-Git-Url: http://git.techno-innov.fr/?a=commitdiff_plain;h=655b6376edfa049fcd3d42346070bdb4c8baaca1;p=soft%2Flpc122x%2Fcore Add ADC support --- diff --git a/README b/README index c0000cc..bbfed75 100644 --- a/README +++ b/README @@ -75,6 +75,7 @@ SUPPORTED FEATURES and INTERFACES - I²C - I²C EEPROM - TMP101 temperature sensor + - ADC - GPIO @@ -82,7 +83,6 @@ SUPPORTED FEATURES and INTERFACES TODO : - Deep sleep mode support. -- ADC support - Test all the GPIO in different modes - Add support for SPI - Add support for SDCard over SPI diff --git a/core/system.c b/core/system.c index 5d0db4f..4f2a056 100644 --- a/core/system.c +++ b/core/system.c @@ -243,12 +243,14 @@ void Dummy_Clk_Updater(void) { void uart_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater"))); void i2c_clock_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater"))); void spi_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater"))); +void adc_clk_update(void) __attribute__ ((weak, alias ("Dummy_Clk_Updater"))); static void propagate_main_clock(void) { uart_clk_update(); i2c_clock_update(); spi_clk_update(); + adc_clk_update(); } /* IO config clock */ @@ -286,6 +288,7 @@ void set_i2c_pins(void) __attribute__ ((weak, alias ("Dummy_Pin_Config"))); void set_spi_pins(void) __attribute__ ((weak, alias ("Dummy_Pin_Config"))); void set_uarts_pins(void) __attribute__ ((weak, alias ("Dummy_Pin_Config"))); void set_gpio_pins(void) __attribute__ ((weak, alias ("Dummy_Pin_Config"))); +void set_adc_pins(void) __attribute__ ((weak, alias ("Dummy_Pin_Config"))); void system_set_default_pins(void) { @@ -293,4 +296,5 @@ void system_set_default_pins(void) set_i2c_pins(); set_spi_pins(); set_gpio_pins(); + set_adc_pins(); } diff --git a/drivers/adc.c b/drivers/adc.c new file mode 100644 index 0000000..de786ce --- /dev/null +++ b/drivers/adc.c @@ -0,0 +1,186 @@ +/**************************************************************************** + * drivers/adc.c + * + * Copyright 2012 Nathael Pajani + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + *************************************************************************** */ + + + +/***************************************************************************** */ +/* Analog to Digital Converter (ADC) */ +/***************************************************************************** */ + +#include +#include "core/lpc_regs_12xx.h" +#include "core/lpc_core_cm0.h" +#include "core/system.h" + +/* Should be as near to 9MHz as possible */ +#define adc_clk_Val 9000000 + + + +/***************************************************************************** */ +/* Generic ADC handler */ +void ADC_Handler(void) +{ +/* + volatile struct lpc_adc* adc = LPC_ADC; + uint32_t status = adc->status; +*/ + /* .... What to do ... is specific to your application */ +} + +/* Start a conversion on the given channel (0 to 7) */ +void adc_start_convertion_once(unsigned int channel, int use_int) +{ + struct lpc_adc* adc = LPC_ADC; + + if (channel > 7) + return; + + /* Set conversion channel bit */ + adc->ctrl = ((adc->ctrl & ~LPC_ADC_CHANNEL_MASK) | (0x01 << channel)); + if (use_int) { + /* Set interrupt Bit */ + adc->int_en = (0x01 << channel); + } else { + adc->int_en = 0; + } + /* Clear burst conversion if running ? */ + adc->ctrl &= ~LPC_ADC_BURST; + /* Start conversion */ + adc->ctrl = ((adc->ctrl & ~LPC_ADC_START_CONV_MASK) | LPC_ADC_START_CONV_NOW); +} + + +/* Read the conversion from the given channel (0 to 7) + * This function reads the conversion value directly in the data register and + * always returns a value. + * Return 1 if the value is a new one, else return 0. + * Return -1 if channel does not exist + */ +int adc_get_value(uint16_t * val, int channel) +{ + struct lpc_adc* adc = LPC_ADC; + uint32_t save_reg = 0; + + if (channel > 7) + return -1; + + /* Save the whole register as some bits are cleared when register is read */ + save_reg = adc->data[channel]; + *val = ((save_reg >> LPC_ADC_RESULT_SHIFT) & LPC_ADC_RESULT_MASK); + /* Has this conversion value been already read ? */ + if (! (save_reg & LPC_ADC_CONV_DONE)) { + return 0; + } + return 1; +} + +/* Start burst conversions. + * channels is a bit mask of requested channels. + * Use LPC_ADC_CHANNEL_0 .. 7 + */ +void adc_start_burst_conversion(uint8_t channels) +{ + struct lpc_adc* adc = LPC_ADC; + + /* Set conversion channel bits */ + adc->ctrl = ((adc->ctrl & ~LPC_ADC_CHANNEL_MASK) | channels); + adc->ctrl |= LPC_ADC_BURST; +} + +/* Unsupported Yet */ +/* This should be used to configure conversion start on falling or rising edges of + * some signals, or on timer for burst conversions. + */ +void adc_prepare_conversion_on_event(void) +{ + /* Unsupported Yet */ +} + +/* On LPC1224 there is no possibility to change the ADC resolution */ +void adc_set_resolution(int bits) +{ +} + + + +/***************************************************************************** */ +/* ADC Setup : private part : Clocks, Pins, Power and Mode */ +void set_adc_pins(void) +{ + struct lpc_io_control* ioctrl = LPC_IO_CONTROL; + + /* Make sure IO_Config is clocked */ + io_config_clk_on(); + /* Configure ADC pins */ + ioctrl->pio0_30 = LPC_IO_FUNC_ALT(3) | LPC_IO_ANALOG; + ioctrl->pio0_31 = LPC_IO_FUNC_ALT(3) | LPC_IO_ANALOG; + ioctrl->pio1_0 = LPC_IO_FUNC_ALT(2) | LPC_IO_ANALOG; + ioctrl->pio1_1 = LPC_IO_FUNC_ALT(2) | LPC_IO_ANALOG; + ioctrl->pio1_2 = LPC_IO_FUNC_ALT(2) | LPC_IO_ANALOG; + ioctrl->pio1_3 = LPC_IO_FUNC_ALT(1) | LPC_IO_ANALOG; + /* Config done, power off IO_CONFIG block */ + io_config_clk_off(); +} + +void adc_clk_update(void) +{ + struct lpc_adc* adc = LPC_ADC; + uint32_t main_clock = get_main_clock(); + uint32_t clkdiv = 0; + + /* Configure ADC */ + clkdiv = (main_clock/adc_clk_Val); + adc->ctrl |= ((clkdiv & 0x0F) << 8); +} + + +void adc_on(void) +{ + struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL; + struct lpc_adc* adc = LPC_ADC; + + /* Disable ADC Interrupt */ + NVIC_DisableIRQ(ADC_IRQ); + /* Power-up ADC */ + sys_ctrl->powerdown_run_cfg &= ~LPC_POWER_DOWN_ADC; + /* Provide clock to ADC */ + subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 1); + adc_clk_update(); + + /* Prevent unconfigured conversion start */ + adc->ctrl &= ~LPC_ADC_START_CONV_MASK; + + /* Enable ADC Interrupt */ + NVIC_EnableIRQ(ADC_IRQ); +} + +void adc_off(void) +{ + struct lpc_sys_control* sys_ctrl = LPC_SYS_CONTROL; + + /* Disable ADC Interrupt */ + NVIC_DisableIRQ(ADC_IRQ); + /* Power Down ADC */ + sys_ctrl->powerdown_run_cfg |= LPC_POWER_DOWN_ADC; + /* Remove clock from ADC block */ + subsystem_power(LPC_SYS_ABH_CLK_CTRL_ADC, 0); +} + diff --git a/drivers/gpio.c b/drivers/gpio.c index aff5e3c..6b589ac 100644 --- a/drivers/gpio.c +++ b/drivers/gpio.c @@ -83,14 +83,14 @@ void set_gpio_pins(void) ioctrl->pio0_27 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; ioctrl->pio0_28 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; ioctrl->pio0_29 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; - /* Configure ADC pins */ - ioctrl->pio0_30 = LPC_IO_FUNC_ALT(1) | LPC_IO_ANALOG; - ioctrl->pio0_31 = LPC_IO_FUNC_ALT(1) | LPC_IO_ANALOG; - ioctrl->pio1_0 = LPC_IO_FUNC_ALT(1) | LPC_IO_ANALOG; - ioctrl->pio1_1 = LPC_IO_FUNC_ALT(1) | LPC_IO_ANALOG; - ioctrl->pio1_2 = LPC_IO_FUNC_ALT(1) | LPC_IO_ANALOG; - ioctrl->pio1_3 = LPC_IO_FUNC_ALT(1) | LPC_IO_ANALOG; - +#if 0 /* ADC pins configured in ADC driver. Kept for info, for those not using them as ADC */ +- ioctrl->pio0_30 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; +- ioctrl->pio0_31 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; +- ioctrl->pio1_0 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; +- ioctrl->pio1_1 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; +- ioctrl->pio1_2 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; +- ioctrl->pio1_3 = LPC_IO_FUNC_ALT(0) | LPC_IO_MODE_PULL_UP; +#endif /* Config done, power off IO_CONFIG block */ io_config_clk_off(); } diff --git a/include/core/lpc_regs_12xx.h b/include/core/lpc_regs_12xx.h index 4629a45..d9dce50 100644 --- a/include/core/lpc_regs_12xx.h +++ b/include/core/lpc_regs_12xx.h @@ -640,18 +640,32 @@ struct lpc_adc }; #define LPC_ADC ((struct lpc_adc *) LPC_ADC_BASE) +/* ADC Control register bits */ +/* LPC_ADC_CHANNEL_* are also used for interrupt register */ +#define LPC_ADC_CHANNEL_MASK (0xFF << 0) +#define LPC_ADC_CHANNEL_0 (0x01 << 0) +#define LPC_ADC_CHANNEL_1 (0x01 << 1) +#define LPC_ADC_CHANNEL_2 (0x01 << 2) +#define LPC_ADC_CHANNEL_3 (0x01 << 3) +#define LPC_ADC_CHANNEL_4 (0x01 << 4) +#define LPC_ADC_CHANNEL_5 (0x01 << 5) +#define LPC_ADC_CHANNEL_6 (0x01 << 6) +#define LPC_ADC_CHANNEL_7 (0x01 << 7) +#define LPC_ADC_BURST (0x01 << 16) +/* These are unused for LPC1224 */ #define LPC_ADC_10BITS (0x00 << 17) -#define LPC_ADC_9BITS (0x01 << 17) -#define LPC_ADC_8BITS (0x02 << 17) -#define LPC_ADC_7BITS (0x03 << 17) -#define LPC_ADC_6BITS (0x04 << 17) +#define LPC_ADC_9BITS (0x01 << 17) +#define LPC_ADC_8BITS (0x02 << 17) +#define LPC_ADC_7BITS (0x03 << 17) +#define LPC_ADC_6BITS (0x04 << 17) #define LPC_ADC_START_CONV_NOW (0x01 << 24) #define LPC_ADC_START_CONV_MASK (0x07 << 24) -#define LPC_ADC_CONV_AD0 (0x01 << 0) - -#define LPC_ADC_INT_EN_AD0 (0x01 << 0) - +/* ADC Data register bits */ +#define LPC_ADC_RESULT_SHIFT 6 +#define LPC_ADC_RESULT_MASK 0x3FF +#define LPC_ADC_OVERRUN (0x01 << 30) +#define LPC_ADC_CONV_DONE (0x01 << 31) #endif /* LPC_REGS_H */ diff --git a/include/drivers/adc.h b/include/drivers/adc.h new file mode 100644 index 0000000..b5e29f9 --- /dev/null +++ b/include/drivers/adc.h @@ -0,0 +1,65 @@ +/**************************************************************************** + * drivers/adc.h + * + * Copyright 2012 Nathael Pajani + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + *************************************************************************** */ + + + +/***************************************************************************** */ +/* Analog to Digital Converter (ADC) */ +/***************************************************************************** */ + +#include +#include "core/lpc_regs_12xx.h" +#include "core/lpc_core_cm0.h" +#include "core/system.h" + +/* Start a conversion on the given channel (0 to 7) */ +void adc_start_convertion_once(unsigned int channel, int use_int); + +/* Read the conversion from the given channel (0 to 7) + * This function reads the conversion value directly in the data register and + * always returns a value. + * Return 1 if the value is a new one, else return 0. + * Return -1 if channel does not exist + */ +int adc_get_value(uint16_t * val, int channel); + +/* Start burst conversions. + * channels is a bit mask of requested channels. + * Use LPC_ADC_CHANNEL_0 .. 7 + */ +void adc_start_burst_conversion(uint8_t channels); + +/* Unsupported Yet */ +/* This should be used to configure conversion start on falling or rising edges of + * some signals, or on timer for burst conversions. + */ +void adc_prepare_conversion_on_event(void); + +/* On LPC1224 there is no possibility to change the ADC resolution */ +void adc_set_resolution(int bits); + + +/***************************************************************************** */ +/* ADC Setup : private part : Clocks, Pins, Power and Mode */ +void set_adc_pins(void); +void adc_clk_update(void); +void adc_on(void); +void adc_off(void); +