From 2730fd214fe5294004b74f59af069ff92b425ba6 Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Fri, 26 Sep 2014 12:09:51 +0200 Subject: [PATCH] Add partial support for event driven conversions Only two events supported yet. Support for new ones will be easy but requires some code refactoring. --- drivers/adc.c | 119 +++++++++++++++++++++++++---------- include/core/lpc_regs_12xx.h | 11 ++++ include/drivers/adc.h | 27 ++++++-- 3 files changed, 119 insertions(+), 38 deletions(-) diff --git a/drivers/adc.c b/drivers/adc.c index 669960f..8d4dfc9 100644 --- a/drivers/adc.c +++ b/drivers/adc.c @@ -29,6 +29,7 @@ #include "core/lpc_core_cm0.h" #include "core/system.h" #include "core/pio.h" +#include "drivers/adc.h" /* Should be as near to 9MHz as possible */ #define adc_clk_Val 9000000 @@ -47,34 +48,13 @@ void ADC_Handler(void) /* FIXME : Add an handler callback. */ } -/* 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) | LPC_ADC_CHANNEL(channel)); - if (use_int) { - /* Set interrupt Bit */ - adc->int_en = LPC_ADC_CHANNEL(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 0 if the value is a new one and no overrun occured. * Return -1 if channel does not exist + * Retuen 1 if the value is an old one + * Return 2 if an overrun occured */ int adc_get_value(uint16_t * val, int channel) { @@ -89,11 +69,43 @@ int adc_get_value(uint16_t * val, int 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; + } + if (save_reg & LPC_ADC_OVERRUN) { + return 2; } - return 1; + return 0; } +/* 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; + uint32_t reg_val = 0; + + if (channel > 7) + return; + + /* Get a clean control register */ + reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST); + + /* Set conversion channel bit */ + reg_val |= LPC_ADC_CHANNEL(channel); + + /* Use of interrupts for the specified channel ? */ + if (use_int) { + /* Set interrupt Bit */ + adc->int_en = LPC_ADC_CHANNEL(channel); + } else { + adc->int_en = 0; + } + + /* Start conversion */ + reg_val |= LPC_ADC_START_CONV_NOW; + adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK); +} + + /* Start burst conversions. * channels is a bit mask of requested channels. * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection. @@ -103,20 +115,58 @@ void adc_start_burst_conversion(uint8_t channels) struct lpc_adc* adc = LPC_ADC; uint32_t reg_val = 0; + /* Get a clean control register */ + reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST); + /* Set conversion channel bits and burst mode */ - reg_val = ((adc->ctrl & ~LPC_ADC_CHANNEL_MASK) | channels); + reg_val |= channels; reg_val |= LPC_ADC_BURST; + + /* Use of interrupts for the specified channels ? */ + /* FIXME : Need to choose between one single global interrupt or specific interrupts .... */ + /* FIXME : Actually none. */ + adc->int_en = 0; + + /* Start conversion */ adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK); } -/* 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) +void adc_prepare_conversion_on_event(uint8_t channels, uint8_t event, int use_int) { - /* Unsupported Yet */ + struct lpc_adc* adc = LPC_ADC; + uint32_t reg_val = 0; + + /* Get a clean control register */ + reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST); + /* Set conversion channel bits and burst mode */ + reg_val |= channels; + /* Set conversion condition bits */ + switch (event) { + case ADC_CONV_ON_CT32B0_MAT0_RISING : + reg_val |= LPC_ADC_START_CONV_EVENT(LPC_ADC_START_CONV_EDGE_CT32B0_MAT0); + reg_val |= LPC_ADC_START_EDGE_RISING; + break; + case ADC_CONV_ON_CT16B0_MAT0_RISING : + reg_val |= LPC_ADC_START_CONV_EVENT(LPC_ADC_START_CONV_EDGE_CT16B0_MAT0); + reg_val |= LPC_ADC_START_EDGE_RISING; + break; + default: + break; + } + + /* Use of interrupts for the specified channel ? */ + if (use_int) { + /* FIXME : Need to choose between one single global interrupt or specific interrupts .... */ + } else { + adc->int_en = 0; + } + + /* Enable conversion on selected event */ + adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK); } @@ -142,9 +192,9 @@ void adc_clk_update(void) uint32_t main_clock = get_main_clock(); uint32_t clkdiv = 0; - /* Configure ADC */ - clkdiv = (main_clock/adc_clk_Val); - adc->ctrl |= ((clkdiv & 0x0F) << 8); + /* Configure ADC clock to get the 9MHz sample clock */ + clkdiv = (main_clock / adc_clk_Val); + adc->ctrl |= ((clkdiv & 0xFF) << 8); } @@ -164,6 +214,9 @@ void adc_on(void) /* Prevent unconfigured conversion start */ adc->ctrl &= ~LPC_ADC_START_CONV_MASK; + /* Remove the default global interrupt enabled setting */ + adc->int_en = 0; + /* Configure ADC pins */ set_adc_pins(); diff --git a/include/core/lpc_regs_12xx.h b/include/core/lpc_regs_12xx.h index dce2aaf..d4cdff2 100644 --- a/include/core/lpc_regs_12xx.h +++ b/include/core/lpc_regs_12xx.h @@ -747,6 +747,17 @@ struct lpc_adc #define LPC_ADC_BURST (0x01 << 16) #define LPC_ADC_START_CONV_NOW (0x01 << 24) +enum lpc_adc_start_conv_events { + LPC_ADC_START_CONV_EDGE_CT16B0_CAP0 = 2, + LPC_ADC_START_CONV_EDGE_CT32B0_CAP0, + LPC_ADC_START_CONV_EDGE_CT32B0_MAT0, + LPC_ADC_START_CONV_EDGE_CT32B0_MAT1, + LPC_ADC_START_CONV_EDGE_CT16B0_MAT0, + LPC_ADC_START_CONV_EDGE_CT16B0_MAT1, +}; +#define LPC_ADC_START_CONV_EVENT(x) (((x) & 0x7) << 24) +#define LPC_ADC_START_EDGE_FALLING (0x1 << 27) +#define LPC_ADC_START_EDGE_RISING (0x0 << 27) #define LPC_ADC_START_CONV_MASK (0x07 << 24) /* ADC Data register bits */ diff --git a/include/drivers/adc.h b/include/drivers/adc.h index aef8e9f..49999d7 100644 --- a/include/drivers/adc.h +++ b/include/drivers/adc.h @@ -22,14 +22,29 @@ #define DRIVERS_ADC_H +#include + /***************************************************************************** */ /* Analog to Digital Converter (ADC) */ /***************************************************************************** */ -#include +enum adc_events { + /* CT32B0 */ + ADC_CONV_ON_CT32B0_CAP0_RISING, + ADC_CONV_ON_CT32B0_CAP0_FALLING, + ADC_CONV_ON_CT32B0_MAT0_RISING, + ADC_CONV_ON_CT32B0_MAT0_FALLING, + ADC_CONV_ON_CT32B0_MAT1_RISING, + ADC_CONV_ON_CT32B0_MAT1_FALLING, + /* CT16B0 */ + ADC_CONV_ON_CT16B0_CAP0_RISING, + ADC_CONV_ON_CT16B0_CAP0_FALLING, + ADC_CONV_ON_CT16B0_MAT0_RISING, + ADC_CONV_ON_CT16B0_MAT0_FALLING, + ADC_CONV_ON_CT16B0_MAT1_RISING, + ADC_CONV_ON_CT16B0_MAT1_FALLING, +}; -/* 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 @@ -39,17 +54,19 @@ void adc_start_convertion_once(unsigned int channel, int use_int); */ int adc_get_value(uint16_t * val, int channel); +/* Start a conversion on the given channel (0 to 7) */ +void adc_start_convertion_once(unsigned int channel, int use_int); + /* Start burst conversions. * channels is a bit mask of requested channels. * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection. */ 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); +void adc_prepare_conversion_on_event(uint8_t channels, uint8_t event, int use_int); /***************************************************************************** */ -- 2.43.0