Skip to content

Commit 5c695a9

Browse files
committed
lpc1756 added adc driver
1 parent 4e59536 commit 5c695a9

3 files changed

Lines changed: 213 additions & 0 deletions

File tree

targets/chip/lpc1756/io/adc.hpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#ifndef KLIB_LPC1756_ADC_HPP
2+
#define KLIB_LPC1756_ADC_HPP
3+
4+
#include <cstdint>
5+
6+
#include <targets/core/nxp/lpc175x/adc.hpp>
7+
#include "pins.hpp"
8+
9+
namespace klib::lpc1756::io::periph::detail::adc {
10+
template <typename Pin, typename Periph>
11+
struct adc {
12+
// pin of the peripheral
13+
using pin = Pin;
14+
15+
// alternate function
16+
using periph = Periph;
17+
};
18+
}
19+
20+
namespace klib::lpc1756::io::periph::lqfp_80 {
21+
struct adc0 {
22+
// peripheral id (e.g adc0, adc1)
23+
constexpr static uint32_t id = 0;
24+
25+
// peripheral clock bit position
26+
constexpr static uint32_t clock_id = 12;
27+
28+
// interrupt id (including the arm vector table)
29+
constexpr static uint32_t interrupt_id = 22 + 16;
30+
31+
// port to the ADC hardware
32+
static inline ADC_Type *const port = ADC;
33+
34+
// pins allowed per output pin. Used for determining if a pin is valid on compile time
35+
using pins = std::tuple<
36+
detail::adc::adc<pins::package::lqfp_80::p7, core::lpc175x::io::detail::alternate::func_1>,
37+
detail::adc::adc<pins::package::lqfp_80::p6, core::lpc175x::io::detail::alternate::func_1>,
38+
detail::adc::adc<pins::package::lqfp_80::p18, core::lpc175x::io::detail::alternate::func_3>,
39+
detail::adc::adc<pins::package::lqfp_80::p17, core::lpc175x::io::detail::alternate::func_3>,
40+
detail::adc::adc<pins::package::lqfp_80::p79, core::lpc175x::io::detail::alternate::func_2>
41+
>;
42+
};
43+
}
44+
45+
namespace klib::lpc1756::io {
46+
template <typename Adc>
47+
using adc = core::lpc175x::io::adc<Adc>;
48+
49+
template <typename Adc, typename Pin>
50+
using adc_channel = core::lpc175x::io::adc_channel<Adc, Pin>;
51+
}
52+
53+
#endif

targets/chip/lpc1756/io/pins.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ namespace klib::lpc1756::pins::package::lqfp_80 {
3232

3333
// bit number in port
3434
constexpr static uint32_t number = 26;
35+
36+
// bit number for the adc
37+
constexpr static uint32_t analog_number = 3;
3538
};
3639

3740
struct p7 {
@@ -40,6 +43,9 @@ namespace klib::lpc1756::pins::package::lqfp_80 {
4043

4144
// bit number in port
4245
constexpr static uint32_t number = 25;
46+
47+
// bit number for the adc
48+
constexpr static uint32_t analog_number = 2;
4349
};
4450

4551
struct p8 {
@@ -84,6 +90,9 @@ namespace klib::lpc1756::pins::package::lqfp_80 {
8490

8591
// bit number in port
8692
constexpr static uint32_t number = 31;
93+
94+
// bit number for the adc
95+
constexpr static uint32_t analog_number = 5;
8796
};
8897

8998
struct p18 {
@@ -92,6 +101,9 @@ namespace klib::lpc1756::pins::package::lqfp_80 {
92101

93102
// bit number in port
94103
constexpr static uint32_t number = 30;
104+
105+
// bit number for the adc
106+
constexpr static uint32_t analog_number = 4;
95107
};
96108

97109
struct p19 {
@@ -524,6 +536,9 @@ namespace klib::lpc1756::pins::package::lqfp_80 {
524536

525537
// bit number in port
526538
constexpr static uint32_t number = 2;
539+
540+
// bit number for the adc
541+
constexpr static uint32_t analog_number = 7;
527542
};
528543

529544
struct p80 {
@@ -532,6 +547,9 @@ namespace klib::lpc1756::pins::package::lqfp_80 {
532547

533548
// bit number in port
534549
constexpr static uint32_t number = 3;
550+
551+
// bit number for the adc
552+
constexpr static uint32_t analog_number = 6;
535553
};
536554
}
537555

targets/core/nxp/lpc175x/adc.hpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#ifndef KLIB_NXP_LPC175X_ADC_HPP
2+
#define KLIB_NXP_LPC175X_ADC_HPP
3+
4+
#include <klib/klib.hpp>
5+
#include <klib/io/peripheral.hpp>
6+
7+
#include <io/power.hpp>
8+
#include <io/port.hpp>
9+
#include <io/clocks.hpp>
10+
11+
namespace klib::core::lpc175x::io {
12+
template <typename Adc>
13+
class adc {
14+
public:
15+
// amount of bits in the ADC
16+
constexpr static uint32_t bits = 12;
17+
18+
/**
19+
* @brief Start sampling the input pins
20+
*
21+
* @note conversions require 65 clock
22+
* cycles
23+
*/
24+
static void sample() {
25+
// check if burst mode is enabled. If it is we
26+
// do nothing here
27+
if (Adc::port->CR & (0x1 << 16)) {
28+
// do nothing here
29+
return;
30+
}
31+
32+
// start a conversion now
33+
Adc::port->CR = (Adc::port->CR & (~(0b111 << 24))) | (0b001 << 24);
34+
}
35+
36+
/**
37+
* @brief Returns if the adc is busy sampling. Only valid after starting
38+
* a sample request.
39+
*
40+
* @warning Undefined value is returned if calling this function before
41+
* starting a measurement
42+
*
43+
* @note This value is cleared after reading
44+
*
45+
* @return status
46+
*/
47+
static bool is_busy() {
48+
return !(Adc::port->GDR & (0x1 << 31));
49+
}
50+
51+
/**
52+
* @brief Init the adc peripheral
53+
*
54+
* @tparam FreeRun
55+
* @tparam Divider
56+
*/
57+
template <bool FreeRun = false, uint8_t Divider = 0>
58+
static void init() {
59+
// enable power to the adc
60+
target::io::power_control::enable<Adc>();
61+
62+
// make the adc operational by setting the pdn
63+
// bit. FreeRun enables burst mode. That will
64+
// allow conversions up to 200 kHz
65+
Adc::port->CR = (
66+
(Divider << 8) | (0x1 << 21) | (FreeRun << 16)
67+
);
68+
}
69+
};
70+
71+
template <typename Adc, typename Pin>
72+
class adc_channel {
73+
public:
74+
// amount of bits in the ADC
75+
constexpr static uint32_t bits = adc<Adc>::bits;
76+
77+
/**
78+
* @brief Init the adc channel for a specific pin
79+
*
80+
*/
81+
static void init() {
82+
static_assert(Pin::analog_number < 8, "Invalid analog pin number");
83+
using pin = std::tuple_element<klib::io::peripheral::get_index<Pin, typename Adc::pins>(), typename Adc::pins>::type;
84+
85+
// switch the gpio to adc mode
86+
target::io::detail::pins::set_peripheral<typename pin::pin, typename pin::periph>();
87+
88+
// init the channel
89+
Adc::port->CR |= (0x1 << Pin::analog_number);
90+
}
91+
92+
/**
93+
* @brief Do a sample request.
94+
*
95+
*/
96+
static void sample() {
97+
// Note: we sample all the enabled channels with this request
98+
adc<Adc>::sample();
99+
}
100+
101+
/**
102+
* @brief Returns if the adc is busy sampling. Only valid after starting
103+
* a sample request.
104+
*
105+
* @warning Undefined value is returned if calling this function before
106+
* starting a measurement
107+
*
108+
* @return status
109+
*/
110+
static bool is_busy() {
111+
return !(Adc::port->STAT & (0x1 << Pin::analog_number));
112+
}
113+
114+
/**
115+
* @brief Read a sampled result. If the async flag is set to false this will
116+
* sample and wait until the conversion is complete
117+
*
118+
* @tparam Async
119+
* @tparam Override
120+
* @return uint32_t
121+
*/
122+
template <bool Async = true>
123+
static uint32_t get() {
124+
// check if we need to sample the data or if we only
125+
// need to read the result
126+
if constexpr (!Async) {
127+
// start a measurement
128+
sample();
129+
130+
// wait until the current channel is done
131+
while (is_busy()) {
132+
// do nothing
133+
}
134+
}
135+
136+
// return the result
137+
return (Adc::port->DR[Pin::analog_number] >> 4) & 0xfff;
138+
}
139+
};
140+
}
141+
142+
#endif

0 commit comments

Comments
 (0)