/****************************************************************************
* drivers/adc.c
*
- * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
+ * Copyright 2012-2016 Nathael Pajani <nathael.pajani@ed3l.fr>
*
* 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
#include "drivers/adc.h"
/* Should be as near to 9MHz as possible */
-#define adc_clk_Val 9000000
+#define adc_clk_Val (9 * 1000 * 1000)
/***************************************************************************** */
/* Generic ADC handler */
+void (*adc_int_callback)(uint32_t) = NULL;
void ADC_Handler(void)
{
-/*
- volatile struct lpc_adc* adc = LPC_ADC;
+ volatile struct lpc_adc* adc = LPC_ADC_REGS;
uint32_t status = adc->status;
-*/
- /* .... What to do ... is specific to your application */
- /* FIXME : Add an handler callback. */
+
+ if (adc_int_callback != NULL) {
+ adc_int_callback(status);
+ }
}
/* 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 0 if the value is a new one and no overrun occured.
- * Return -1 if channel does not exist
+ * Return -EINVAL 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)
+int adc_get_value(uint16_t * val, uint8_t channel)
{
- struct lpc_adc* adc = LPC_ADC;
+ struct lpc_adc* adc = LPC_ADC_REGS;
uint32_t save_reg = 0;
- if (channel > 7)
- return -1;
+ if (channel >= NB_ADC_CHANNELS)
+ return -EINVAL;
/* Save the whole register as some bits are cleared when register is read */
save_reg = adc->data[channel];
}
/* Start a conversion on the given channel (0 to 7) */
-void adc_start_convertion_once(unsigned int channel, int use_int)
+void adc_start_convertion_once(uint8_t channel, uint8_t seq_num, uint8_t use_int)
{
- struct lpc_adc* adc = LPC_ADC;
+ struct lpc_adc* adc = LPC_ADC_REGS;
uint32_t reg_val = 0;
- if (channel > 7)
+ if (channel >= NB_ADC_CHANNELS)
return;
/* Get a clean control register */
- reg_val = adc->ctrl & ~(LPC_ADC_CHANNEL_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
+ reg_val = adc->ctrl & ~(ADC_MCH_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
/* Set conversion channel bit */
- reg_val |= LPC_ADC_CHANNEL(channel);
+ reg_val |= ADC_MCH(channel);
/* Use of interrupts for the specified channel ? */
if (use_int) {
/* Set interrupt Bit */
- adc->int_en = LPC_ADC_CHANNEL(channel);
+ adc->int_en = ADC_MCH(channel);
} else {
adc->int_en = 0;
}
/* Start burst conversions.
* channels is a bit mask of requested channels.
- * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection.
+ * Use ADC_MCH(x) (x = 0 .. 7) for channels selection.
*/
-void adc_start_burst_conversion(uint8_t channels)
+void adc_start_burst_conversion(uint16_t channels, uint8_t seq_num)
{
- struct lpc_adc* adc = LPC_ADC;
+ struct lpc_adc* adc = LPC_ADC_REGS;
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);
+ reg_val = adc->ctrl & ~(ADC_MCH_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
/* Set conversion channel bits and burst mode */
reg_val |= channels;
adc->ctrl = (reg_val & LPC_ADC_CTRL_MASK);
}
+void adc_stop_burst_conversion(uint8_t seq_num)
+{
+}
+
/* 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(uint8_t channels, uint8_t event, int use_int)
+void adc_prepare_conversion_on_event(uint16_t channels, uint8_t seq_num, uint8_t event,
+ uint8_t use_int, uint32_t mode)
{
- struct lpc_adc* adc = LPC_ADC;
+ struct lpc_adc* adc = LPC_ADC_REGS;
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);
+ reg_val = adc->ctrl & ~(ADC_MCH_MASK | LPC_ADC_START_CONV_MASK | LPC_ADC_BURST);
/* Set conversion channel bits and burst mode */
- reg_val |= channels;
+ reg_val |= (channels & ADC_MCH_MASK);
/* 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;
+ reg_val |= LPC_ADC_START_CONV_EVENT(event);
+ if (mode != 0) {
+ reg_val |= (mode & LPC_ADC_ADDITIONAL_MODE_MASK);
}
/* Use of interrupts for the specified channel ? */
}
+/* Software trigger of the given configured sequence */
+void adc_trigger_sequence_conversion(uint8_t seq_num)
+{
+ struct lpc_adc* adc = LPC_ADC_REGS;
+
+ adc->ctrl &= ~(LPC_ADC_START_CONV_MASK);
+ adc->ctrl |= LPC_ADC_START_CONV_NOW;
+}
+
/***************************************************************************** */
/* ADC Setup : private part : Clocks, Power and Mode */
void adc_clk_update(void)
{
- struct lpc_adc* adc = LPC_ADC;
+ struct lpc_adc* adc = LPC_ADC_REGS;
uint32_t main_clock = get_main_clock();
uint32_t clkdiv = 0;
}
-void adc_on(void)
+void adc_on(void (*adc_callback)(uint32_t))
{
struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
- struct lpc_adc* adc = LPC_ADC;
+ struct lpc_adc* adc = LPC_ADC_REGS;
/* Disable ADC Interrupt */
NVIC_DisableIRQ(ADC_IRQ);
/* Remove the default global interrupt enabled setting */
adc->int_en = 0;
+ /* Register a possible calback */
+ adc_int_callback = adc_callback;
/* Enable ADC Interrupt */
NVIC_EnableIRQ(ADC_IRQ);
/* Disable ADC Interrupt */
NVIC_DisableIRQ(ADC_IRQ);
+ /* Remove callback */
+ adc_int_callback = NULL;
/* Power Down ADC */
sys_config->powerdown_run_cfg |= LPC_POWER_DOWN_ADC;
/* Remove clock from ADC block */
* Refer to LPC122x documentation (UM10441.pdf) for more information.
*/
-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,
-};
+#define NB_ADC_CHANNELS 8
+#define NB_ADC_SEQUENCES 1
+
+#define LPC_ADC_SEQ(x) 0
-/* Read the conversion from the given channel (0 to 7)
+/* Read the conversion from the given channel
* 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
+ * Return 0 if the value is a new one and no overrun occured.
+ * Return -EINVAL 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);
+int adc_get_value(uint16_t * val, uint8_t channel);
/* Start a conversion on the given channel (0 to 7)
* Unsupported yet : Set use_int to 1 to have your interrupt callback called upon conversion done.
*/
-void adc_start_convertion_once(unsigned int channel, int use_int);
+void adc_start_convertion_once(uint8_t channel, uint8_t seq_num, uint8_t use_int);
/* Start burst conversions.
* channels is a bit mask of requested channels.
- * Use LPC_ADC_CHANNEL(x) (x = 0 .. 7) for channels selection.
+ * Use ADC_MCH(x) (x = 0 .. 7) for channels selection.
*/
-void adc_start_burst_conversion(uint8_t channels);
+void adc_start_burst_conversion(uint16_t channels, uint8_t seq_num);
+void adc_stop_burst_conversion(uint8_t seq_num);
+
+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,
+};
/* 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(uint8_t channels, uint8_t event, int use_int);
+void adc_prepare_conversion_on_event(uint16_t channels, uint8_t seq_num, uint8_t event,
+ uint8_t use_int, uint32_t mode);
+
+/* Software trigger of the given configured sequence.
+ * Note : If the sequence was configured for triggering on an external event, it won't be anymore.
+ */
+void adc_trigger_sequence_conversion(uint8_t seq_num);
/***************************************************************************** */
/* ADC Setup : private part : Clocks, Pins, Power and Mode */
-void adc_clk_update(void);
-void adc_on(void);
+void adc_on(void (*adc_callback)(uint32_t));
void adc_off(void);