Skip to content

Commit d923083

Browse files
committed
atsam4s added adc implementation
1 parent 4efe890 commit d923083

File tree

3 files changed

+194
-0
lines changed

3 files changed

+194
-0
lines changed

targets/chip/atsam4s2b/io/adc.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef KLIB_ATSAM4S2B_ADC_HPP
2+
#define KLIB_ATSAM4S2B_ADC_HPP
3+
4+
#include <targets/core/atmel/atsam4s/adc.hpp>
5+
6+
#include "pins.hpp"
7+
8+
namespace klib::atsam4s2b::io::periph::wlcsp_64 {
9+
struct adc0 {
10+
// peripheral id (e.g adc0, adc1)
11+
constexpr static uint32_t id = 0;
12+
13+
// peripheral clock bit position
14+
constexpr static uint32_t clock_id = 29;
15+
16+
// interrupt id (including the arm vector table)
17+
constexpr static uint32_t interrupt_id = 29 + 16;
18+
19+
// port to the adc hardware
20+
static inline ADC_Type *const port = ADC;
21+
};
22+
}
23+
24+
namespace klib::atsam4s2b::io {
25+
template <typename Adc>
26+
using adc = core::atsam4s::io::adc<Adc>;
27+
28+
template <typename Adc, typename Pin>
29+
using adc_channel = core::atsam4s::io::adc_channel<Adc, Pin>;
30+
}
31+
32+
#endif

targets/chip/atsam4s2b/io/pins.hpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
147147

148148
// bit number in port
149149
constexpr static uint32_t number = 0;
150+
151+
// bit number for the adc
152+
constexpr static uint32_t adc_number = 4;
150153
};
151154

152155
struct pc7 {
@@ -155,6 +158,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
155158

156159
// bit number in port
157160
constexpr static uint32_t number = 2;
161+
162+
// bit number for the adc
163+
constexpr static uint32_t adc_number = 6;
158164
};
159165

160166
struct pc8 {
@@ -163,6 +169,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
163169

164170
// bit number in port
165171
constexpr static uint32_t number = 1;
172+
173+
// bit number for the adc
174+
constexpr static uint32_t adc_number = 5;
166175
};
167176

168177
struct pd1 {
@@ -223,6 +232,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
223232

224233
// bit number in port
225234
constexpr static uint32_t number = 3;
235+
236+
// bit number for the adc
237+
constexpr static uint32_t adc_number = 7;
226238
};
227239

228240
struct pe1 {
@@ -271,6 +283,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
271283

272284
// bit number in port
273285
constexpr static uint32_t number = 18;
286+
287+
// bit number for the adc
288+
constexpr static uint32_t adc_number = 1;
274289
};
275290

276291
struct pe7 {
@@ -279,6 +294,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
279294

280295
// bit number in port
281296
constexpr static uint32_t number = 17;
297+
298+
// bit number for the adc
299+
constexpr static uint32_t adc_number = 0;
282300
};
283301

284302
struct pe8 {
@@ -323,6 +341,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
323341

324342
// bit number in port
325343
constexpr static uint32_t number = 22;
344+
345+
// bit number for the adc
346+
constexpr static uint32_t adc_number = 9;
326347
};
327348

328349
struct pf7 {
@@ -331,6 +352,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
331352

332353
// bit number in port
333354
constexpr static uint32_t number = 21;
355+
356+
// bit number for the adc
357+
constexpr static uint32_t adc_number = 8;
334358
};
335359

336360
struct pf8 {
@@ -391,6 +415,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
391415

392416
// bit number in port
393417
constexpr static uint32_t number = 19;
418+
419+
// bit number for the adc
420+
constexpr static uint32_t adc_number = 2;
394421
};
395422

396423
struct ph1 {
@@ -447,6 +474,9 @@ namespace klib::atsam4s2b::pins::package::wlcsp_64 {
447474

448475
// bit number in port
449476
constexpr static uint32_t number = 20;
477+
478+
// bit number for the adc
479+
constexpr static uint32_t adc_number = 3;
450480
};
451481
}
452482

targets/core/atmel/atsam4s/adc.hpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#ifndef KLIB_ATMEL_ATSAM4S_ADC_HPP
2+
#define KLIB_ATMEL_ATSAM4S_ADC_HPP
3+
4+
#include <io/power.hpp>
5+
6+
namespace klib::core::atsam4s::io {
7+
template <typename Adc>
8+
class adc {
9+
public:
10+
// amount of bits in the ADC
11+
constexpr static uint32_t bits = 12;
12+
13+
/**
14+
* @brief Available hardware trigger modes
15+
*
16+
*/
17+
enum class trigger_mode {
18+
disabled,
19+
external = 0x0,
20+
timer_0 = 0x1,
21+
timer_1 = 0x2,
22+
timer_2 = 0x3,
23+
pwm_event_0 = 0x4,
24+
pwm_event_1 = 0x5,
25+
};
26+
27+
/**
28+
* @brief Start to sample on all the enabled channels
29+
*
30+
*/
31+
static void sample() {
32+
// start the conversion for all the enabled channels
33+
Adc::port->CR = 0x1 << 1;
34+
}
35+
36+
/**
37+
* @brief Initialize the ADC
38+
*
39+
* @tparam FreeRun
40+
* @tparam Mode
41+
* @tparam Sleep
42+
* @tparam FastWakeup
43+
* @tparam startup
44+
* @tparam prescale
45+
*/
46+
template <bool FreeRun = false, trigger_mode Mode = trigger_mode::disabled, bool Sleep = false, bool FastWakeup = true, uint8_t startup = 0, uint8_t prescale = 1>
47+
static void init() {
48+
// enable power to the adc
49+
target::io::power_control::enable<Adc>();
50+
51+
// flag if we have a hardware trigger
52+
const bool hardware_trigger = (Mode != trigger_mode::disabled);
53+
54+
// disable the write protection
55+
Adc::port->WPMR = (0x414443 << 8);
56+
57+
// setup the adc with the provided configuration
58+
Adc::port->MR = (
59+
hardware_trigger | (hardware_trigger ? (static_cast<uint32_t>(Mode) << 1) : 0x00) |
60+
(Sleep << 5) | (FastWakeup << 6) | (FreeRun << 7) | (startup << 16) |
61+
(prescale << 8) | (2 << 28)
62+
);
63+
}
64+
};
65+
66+
template <typename Adc, typename Pin>
67+
class adc_channel {
68+
public:
69+
// amount of bits in the ADC
70+
constexpr static uint32_t bits = adc<Adc>::bits;
71+
72+
/**
73+
* @brief Init the adc channel for a specific pin
74+
*
75+
*/
76+
static void init() {
77+
// init the channel
78+
Adc::port->CHER |= (0x1 << Pin::adc_number);
79+
}
80+
81+
/**
82+
* @brief Do a sample request.
83+
*
84+
*/
85+
static void sample() {
86+
// Note: we cannot sample a single channel. Sample all the enabled
87+
// channels
88+
adc<Adc>::sample();
89+
}
90+
91+
/**
92+
* @brief Returns if the adc is busy sampling. Only valid after starting
93+
* a sample request.
94+
*
95+
* @warning Undefined value is returned if calling this function before
96+
* starting a measurement
97+
*
98+
* @return status
99+
*/
100+
static bool is_busy() {
101+
return !(Adc::port->ISR & (0x1 << Pin::adc_number));
102+
}
103+
104+
/**
105+
* @brief Read a sampled result. If the async flag is set to false this will
106+
* sample and wait until the conversion is complete
107+
*
108+
* @tparam Async
109+
* @tparam Override
110+
* @return uint32_t
111+
*/
112+
template <bool Async = true>
113+
static uint32_t get() {
114+
// check if we need to sample the data or if we only
115+
// need to read the result
116+
if constexpr (!Async) {
117+
// start a measurement
118+
sample();
119+
120+
// wait until the current channel is done
121+
while (is_busy()) {
122+
// do nothing
123+
}
124+
}
125+
126+
// return the result
127+
return Adc::port->CDR[Pin::adc_number] & 0xffff;
128+
}
129+
};
130+
}
131+
132+
#endif

0 commit comments

Comments
 (0)