Skip to content

Commit c812a40

Browse files
committed
lpc176x: Add ADC support
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
1 parent 65613ae commit c812a40

3 files changed

Lines changed: 100 additions & 0 deletions

File tree

src/lpc176x/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ config LPC_SELECT
66
bool
77
default y
88
select HAVE_GPIO
9+
select HAVE_GPIO_ADC
910

1011
config BOARD_DIRECTORY
1112
string

src/lpc176x/gpio.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
// This file may be distributed under the terms of the GNU GPLv3 license.
66

77
#include "LPC17xx.h" // LPC_PINCON
8+
#include "autoconf.h" // CONFIG_CLOCK_FREQ
89
#include "board/irq.h" // irq_save
10+
#include "board/misc.h" // timer_from_us
911
#include "command.h" // shutdown
1012
#include "gpio.h" // gpio_out_setup
1113
#include "internal.h" // gpio_peripheral
@@ -117,3 +119,92 @@ gpio_in_read(struct gpio_in g)
117119
LPC_GPIO_TypeDef *regs = g.regs;
118120
return !!(regs->FIOPIN & g.bit);
119121
}
122+
123+
124+
/****************************************************************
125+
* Analog to Digital Converter (ADC) pins
126+
****************************************************************/
127+
128+
static const uint8_t adc_pins[] = {
129+
GPIO(0, 23), GPIO(0, 24), GPIO(0, 25), GPIO(0, 26),
130+
GPIO(1, 30), GPIO(1, 31), GPIO(0, 3), GPIO(0, 2),
131+
};
132+
133+
static const uint8_t adc_pin_funcs[] = {
134+
1, 1, 1, 1, 3, 3, 2, 2
135+
};
136+
137+
#define ADC_FREQ_MAX 13000000
138+
DECL_CONSTANT(ADC_MAX, 4095);
139+
140+
struct gpio_adc
141+
gpio_adc_setup(uint8_t pin)
142+
{
143+
// Find pin in adc_pins table
144+
int chan;
145+
for (chan=0; ; chan++) {
146+
if (chan >= ARRAY_SIZE(adc_pins))
147+
shutdown("Not a valid ADC pin");
148+
if (adc_pins[chan] == pin)
149+
break;
150+
}
151+
152+
uint32_t prescal = DIV_ROUND_UP(CONFIG_CLOCK_FREQ*4, ADC_FREQ_MAX) - 1;
153+
uint32_t adcr = (1<<21) | ((prescal & 0xff) << 8);
154+
if (!(LPC_SC->PCONP & (1<<12))) {
155+
// Power up ADC
156+
LPC_SC->PCONP |= 1<<12;
157+
LPC_SC->PCLKSEL0 = (LPC_SC->PCLKSEL0 & ~(0x3<<24)) | (0x1<<24);
158+
LPC_ADC->ADCR = adcr;
159+
}
160+
161+
gpio_peripheral(GPIO2PORT(pin), pin % 32, adc_pin_funcs[chan], 0);
162+
163+
return (struct gpio_adc){ .cmd = adcr | (1 << chan) | (1 << 24) };
164+
}
165+
166+
static uint32_t adc_status;
167+
168+
// Try to sample a value. Returns zero if sample ready, otherwise
169+
// returns the number of clock ticks the caller should wait before
170+
// retrying this function.
171+
uint32_t
172+
gpio_adc_sample(struct gpio_adc g)
173+
{
174+
uint32_t status = adc_status;
175+
if (status == g.cmd) {
176+
// Sample already underway - check if it is ready
177+
uint32_t val = LPC_ADC->ADGDR;
178+
if (val & (1<<31))
179+
// Sample ready
180+
return 0;
181+
goto need_delay;
182+
}
183+
if (status)
184+
// ADC busy on some other channel
185+
goto need_delay;
186+
187+
// Start new sample
188+
adc_status = g.cmd;
189+
LPC_ADC->ADCR = g.cmd;
190+
191+
need_delay:
192+
return (65 * DIV_ROUND_UP(CONFIG_CLOCK_FREQ*4, ADC_FREQ_MAX)
193+
+ timer_from_us(10));
194+
}
195+
196+
// Read a value; use only after gpio_adc_sample() returns zero
197+
uint16_t
198+
gpio_adc_read(struct gpio_adc g)
199+
{
200+
adc_status = 0;
201+
return (LPC_ADC->ADGDR >> 4) & 0x0fff;
202+
}
203+
204+
// Cancel a sample that may have been started with gpio_adc_sample()
205+
void
206+
gpio_adc_cancel_sample(struct gpio_adc g)
207+
{
208+
if (adc_status == g.cmd)
209+
adc_status = 0;
210+
}

src/lpc176x/gpio.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,12 @@ struct gpio_in {
1919
struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
2020
uint8_t gpio_in_read(struct gpio_in g);
2121

22+
struct gpio_adc {
23+
uint32_t cmd;
24+
};
25+
struct gpio_adc gpio_adc_setup(uint8_t pin);
26+
uint32_t gpio_adc_sample(struct gpio_adc g);
27+
uint16_t gpio_adc_read(struct gpio_adc g);
28+
void gpio_adc_cancel_sample(struct gpio_adc g);
29+
2230
#endif // gpio.h

0 commit comments

Comments
 (0)