msp432/adc.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Analog-Digital Converter (ADC)
6
7use crate::{dma, ref_module, timer};
8use core::cell::Cell;
9use core::{mem, slice};
10use kernel::hil;
11use kernel::utilities::cells::{OptionalCell, TakeCell};
12use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
13use kernel::utilities::registers::{
14 register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
15};
16use kernel::utilities::StaticRef;
17use kernel::ErrorCode;
18
19const ADC_BASE: StaticRef<AdcRegisters> =
20 unsafe { StaticRef::new(0x4001_2000 as *const AdcRegisters) };
21
22const AVAILABLE_ADC_CHANNELS: usize = 24;
23const DEFAULT_ADC_RESOLUTION: AdcResolution = AdcResolution::Bits14;
24// Maximum sampling frequency is 1Msps, but due to the timer, limit it to 150kHz
25const MAX_SAMPLE_FREQ_HZ: u32 = 150_000;
26
27register_structs! {
28 /// ADC14
29 AdcRegisters {
30 /// ADC control 0 register
31 (0x000 => ctl0: ReadWrite<u32, CTL0::Register>),
32 /// ADC control 1 register
33 (0x004 => ctl1: ReadWrite<u32, CTL1::Register>),
34 /// Window comparator low threshold 0 register
35 (0x008 => lo0: ReadWrite<u32>),
36 /// Window comparator high threshold 1
37 (0x00C => hi0: ReadWrite<u32>),
38 /// Window comparator low threshold 1 register
39 (0x010 => lo1: ReadWrite<u32>),
40 /// Window comparator high threshold 1 register
41 (0x014 => hi1: ReadWrite<u32>),
42 /// Memory control register 0-31
43 (0x018 => mctl: [ReadWrite<u32, MCTLx::Register>; 32]),
44 /// Memory register 0-31
45 (0x098 => mem: [ReadWrite<u32>; 32]),
46 (0x118 => _reserved),
47 /// Interrupt enable 0 register
48 (0x13C => ie0: ReadWrite<u32>),
49 /// Interrupt enable 1 register
50 (0x140 => ie1: ReadWrite<u32, IER1::Register>),
51 /// Interrupt flag 0 register
52 (0x144 => ifg0: ReadOnly<u32>),
53 /// Interrupt flag 1 register
54 (0x148 => ifg1: ReadOnly<u32, IFGR1::Register>),
55 /// Clear interrupt flag 0 register
56 (0x14C => clrifg0: WriteOnly<u32>),
57 /// Clear interrupt flag 1 register
58 (0x150 => clrifg1: WriteOnly<u32, CLRIFGR1::Register>),
59 /// Interrupt vector register
60 (0x154 => iv: ReadOnly<u32, IV::Register>),
61 (0x158 => @END),
62 }
63}
64
65register_bitfields![u32,
66 /// ADC Control 0 register
67 CTL0 [
68 /// ADC Start conversion
69 SC OFFSET(0) NUMBITS(1) [],
70 /// ADC Enable conversion
71 ENC OFFSET(1) NUMBITS(1) [],
72 // ADC on
73 ON OFFSET(4) NUMBITS(1) [],
74 /// ADC multiple sample an conversion
75 MSC OFFSET(7) NUMBITS(1) [],
76 /// ADC sample-and-hold time for pulse sample mode.
77 /// Valid for ADCMEM0 to ADCMEM7 and ADCMEM24 to ADCMEM31.
78 SHTOx OFFSET(8) NUMBITS(4) [
79 /// 4 clock cycles sample-and-hold time
80 Cycles4 = 0,
81 /// 8 clock cycles sample-and-hold time
82 Cycles8 = 1,
83 /// 16 clock cycles sample-and-hold time
84 Cycles16 = 2,
85 /// 32 clock cycles sample-and-hold time
86 Cycles32 = 3,
87 /// 64 clock cycles sample-and-hold time
88 Cycles64 = 4,
89 /// 96 clock cycles sample-and-hold time
90 Cycles96 = 5,
91 /// 128 clock cycles sample-and-hold time
92 Cycles128 = 6,
93 /// 192 clock cycles sample-and-hold time
94 Cycles192 = 7
95 ],
96 /// ADC sample-and-hold time for pulse sample mode.
97 /// Valid for ADCMEM8 to ADCMEM23.
98 SHT1x OFFSET(12) NUMBITS(4) [
99 /// 4 clock cycles sample-and-hold time
100 Cycles4 = 0,
101 /// 8 clock cycles sample-and-hold time
102 Cycles8 = 1,
103 /// 16 clock cycles sample-and-hold time
104 Cycles16 = 2,
105 /// 32 clock cycles sample-and-hold time
106 Cycles32 = 3,
107 /// 64 clock cycles sample-and-hold time
108 Cycles64 = 4,
109 /// 96 clock cycles sample-and-hold time
110 Cycles96 = 5,
111 /// 128 clock cycles sample-and-hold time
112 Cycles128 = 6,
113 /// 192 clock cycles sample-and-hold time
114 Cycles192 = 7
115 ],
116 /// ADC Busy
117 BUSY OFFSET(16) NUMBITS(1) [],
118 /// ADC conversion sequence mode select
119 CONSEQx OFFSET(17) NUMBITS(2) [
120 /// Single channel, single conversion
121 SingleChannelSingleConversion = 0,
122 /// Sequence of channels
123 SingleChannelSequence = 1,
124 /// Repeat single channel
125 RepeatSingleChannel = 2,
126 /// Repeat sequence of channels
127 RepeatChannelSequence = 3
128 ],
129 /// ADC clock source select
130 SSELx OFFSET(19) NUMBITS(3) [
131 /// MODCLK
132 MODCLK = 0,
133 /// SYSCLK
134 SYSCLK = 1,
135 /// ACLK
136 ACLK = 2,
137 /// MCLK
138 MCLK = 3,
139 /// SMCLK
140 SMCLK = 4,
141 /// HSMCLK
142 HSMCLK = 5
143 ],
144 /// ADC clock divider
145 DIVx OFFSET(22) NUMBITS(3) [
146 /// Divide clock by 1
147 DivideBy1 = 0,
148 /// Divide clock by 2
149 DivideBy2 = 1,
150 /// Divide clock by 3
151 DivideBy3 = 2,
152 /// Divide clock by 4
153 DivideBy4 = 3,
154 /// Divide clock by 5
155 DivideBy5 = 4,
156 /// Divide clock by 6
157 DivideBy6 = 5,
158 /// Divide clock by 7
159 DivideBy7 = 6,
160 /// Divide clock by 8
161 DivideBy8 = 7
162 ],
163 /// ADC invert signal sample-and-hold
164 ISSH OFFSET(25) NUMBITS(1) [],
165 /// ADC sample-and-hold pulse-mode select
166 SHP OFFSET(26) NUMBITS(1) [],
167 /// ADC sample-and-hold souce select
168 SHSx OFFSET(27) NUMBITS(3) [
169 /// ADC14SC bit
170 SCBit = 0,
171 /// Source 1, see device-specific datasheet
172 Source1 = 1,
173 /// Source 2, see device-specific datasheet
174 Source2 = 2,
175 /// Source 3, see device-specific datasheet
176 Source3 = 3,
177 /// Source 4, see device-specific datasheet
178 Source4 = 4,
179 /// Source 5, see device-specific datasheet
180 Source5 = 5,
181 /// Source 6, see device-specific datasheet
182 Source6 = 6,
183 /// Source 7, see device-specific datasheet
184 Source7 = 7
185 ],
186 /// ADC pre-divider
187 PDIV OFFSET(30) NUMBITS(2) [
188 /// Pre-divde by 1
189 PreDivideBy1 = 0,
190 /// Pre-divde by 4
191 PreDivideBy4 = 1,
192 /// Pre-divde by 32
193 PreDivideBy32 = 2,
194 /// Pre-divde by 64
195 PreDivideBy64 = 3
196 ]
197 ],
198 /// ADC control 1 register
199 CTL1 [
200 /// ADC power modes
201 PWRMD OFFSET(0) NUMBITS(2) [
202 /// Regular power mode with any resolution setting. Sample-rate up to 1Msps.
203 Regular = 0,
204 /// Low-power mode for 12-, 10-, and 8-bit resolutions. Sample-rate up to 200ksps.
205 LowPower = 1
206 ],
207 /// ADC reference buffer burst
208 REFBURST OFFSET(2) NUMBITS(1) [
209 /// ADC reference buffer on continuously
210 Continuously = 0,
211 /// ADC reference buffer on only during sample-and-conversion
212 DuringSampleAndConversion = 1
213 ],
214 /// ADC data read-back format. Data is always stored in the binary unsigned format.
215 DF OFFSET(3) NUMBITS(1) [
216 /// Binary unsigned, at 14bit: -Vref = 0, +Vref = 0x3FFF
217 Unsigned = 0,
218 /// Binary signed, at 14bit: -Vref = 0x8000, +Vref = 0x7FFC
219 Signed = 1
220 ],
221 /// ADC resolution
222 RES OFFSET(4) NUMBITS(2) [
223 /// 8bit (9 clock cycles conversion time)
224 Resolution8Bit = 0,
225 /// 10bit (11 clock cycles conversion time)
226 Resolution11Bit = 1,
227 /// 12bit (14 clock cycles conversion time)
228 Resolution14Bit = 2,
229 /// 14bit (16 clock cycles conversion time)
230 Resolution16Bit = 3
231 ],
232 /// ADC conversion start address, select ADC14MEM0 to ADC14MEM31
233 STARTADDx OFFSET(16) NUMBITS(5) [],
234 /// Controls 1/2 AVCC ADC input channel selection
235 BATMAP OFFSET(22) NUMBITS(1) [
236 /// ADC internal 1/2 x AVCC channel is not selected for ADC
237 NotSelected = 0,
238 /// ADC internal 1/2 x AVCC channel is selected for ADC input channel MAX
239 Selected = 1
240 ],
241 /// Controls temperature sensor ADC input channel selection
242 TCMAP OFFSET(23) NUMBITS(1) [
243 /// ADC internal temperature sensor is not selected
244 NotSelected = 0,
245 /// ADC internal temperature sensor is selected
246 Selected = 1
247 ],
248 /// Controls internal channel 0 selection to ADC input channel MAX - 2
249 CH0MAP OFFSET(24) NUMBITS(1) [],
250 /// Controls internal channel 1 selection to ADC input channel MAX - 3
251 CH1MAP OFFSET(25) NUMBITS(1) [],
252 /// Controls internal channel 2 selection to ADC input channel MAX - 4
253 CH2MAP OFFSET(26) NUMBITS(1) [],
254 /// Controls internal channel 3 selection to ADC input channel MAX - 5
255 CH3MAP OFFSET(27) NUMBITS(1) []
256 ],
257 /// ADC conversion memory control x register
258 MCTLx [
259 /// Input channel select. If even channels are set as differential then odd channel configuration is ignored.
260 INCHx OFFSET(0) NUMBITS(5) [
261 /// If ADC14DIF = 0: A0; If ADC14DIF = 1: Ain+ = A0, Ain- = A1
262 A0A1Even = 0,
263 /// If ADC14DIF = 0: A1; If ADC14DIF = 1: Ain+ = A0, Ain- = A1
264 A0A1Odd = 1,
265 /// If ADC14DIF = 0: A2; If ADC14DIF = 1: Ain+ = A2, Ain- = A3
266 A2A3Even = 2,
267 /// If ADC14DIF = 0: A3; If ADC14DIF = 1: Ain+ = A2, Ain- = A3
268 A2A3Odd = 3,
269 /// If ADC14DIF = 0: A4; If ADC14DIF = 1: Ain+ = A4, Ain- = A5
270 A4A5Even = 4,
271 /// If ADC14DIF = 0: A5; If ADC14DIF = 1: Ain+ = A4, Ain- = A5
272 A4A5Odd = 5,
273 /// If ADC14DIF = 0: A6; If ADC14DIF = 1: Ain+ = A6, Ain- = A7
274 A6A7Even = 6,
275 /// If ADC14DIF = 0: A7; If ADC14DIF = 1: Ain+ = A6, Ain- = A7
276 A6A7Odd = 7,
277 /// If ADC14DIF = 0: A8; If ADC14DIF = 1: Ain+ = A8, Ain- = A9
278 A8A9Even = 8,
279 /// If ADC14DIF = 0: A9; If ADC14DIF = 1: Ain+ = A8, Ain- = A9
280 A8A9Odd = 9,
281 /// If ADC14DIF = 0: A10; If ADC14DIF = 1: Ain+ = A10, Ain- = A11
282 A10A11Even = 10,
283 /// If ADC14DIF = 0: A11; If ADC14DIF = 1: Ain+ = A10, Ain- = A11
284 A10A11Odd = 11,
285 /// If ADC14DIF = 0: A12; If ADC14DIF = 1: Ain+ = A12, Ain- = A13
286 A12A13Even = 12,
287 /// If ADC14DIF = 0: A13; If ADC14DIF = 1: Ain+ = A12, Ain- = A13
288 A12A13Odd = 13,
289 /// If ADC14DIF = 0: A14; If ADC14DIF = 1: Ain+ = A14, Ain- = A15
290 A14A15Even = 14,
291 /// If ADC14DIF = 0: A15; If ADC14DIF = 1: Ain+ = A14, Ain- = A15
292 A14A15Odd = 15,
293 /// If ADC14DIF = 0: A16; If ADC14DIF = 1: Ain+ = A16, Ain- = A17
294 A16A17Even = 16,
295 /// If ADC14DIF = 0: A17; If ADC14DIF = 1: Ain+ = A16, Ain- = A17
296 A16A17Odd = 17,
297 /// If ADC14DIF = 0: A18; If ADC14DIF = 1: Ain+ = A18, Ain- = A19
298 A18A19Even = 18,
299 /// If ADC14DIF = 0: A19; If ADC14DIF = 1: Ain+ = A18, Ain- = A19
300 A18A19Odd = 19,
301 /// If ADC14DIF = 0: A20; If ADC14DIF = 1: Ain+ = A20, Ain- = A21
302 A20A21Even = 20,
303 /// If ADC14DIF = 0: A21; If ADC14DIF = 1: Ain+ = A20, Ain- = A21
304 A20A21Odd = 21,
305 /// If ADC14DIF = 0: A22; If ADC14DIF = 1: Ain+ = A22, Ain- = A23
306 A22A23Even = 22,
307 /// If ADC14DIF = 0: A23; If ADC14DIF = 1: Ain+ = A22, Ain- = A23
308 A22A23Odd = 23,
309 /// If ADC14DIF = 0: A24; If ADC14DIF = 1: Ain+ = A24, Ain- = A25
310 A24A25Even = 24,
311 /// If ADC14DIF = 0: A25; If ADC14DIF = 1: Ain+ = A24, Ain- = A25
312 A24A25Odd = 25,
313 /// If ADC14DIF = 0: A26; If ADC14DIF = 1: Ain+ = A26, Ain- = A27
314 A26A27Even = 26,
315 /// If ADC14DIF = 0: A27; If ADC14DIF = 1: Ain+ = A26, Ain- = A27
316 A26A27Odd = 27,
317 /// If ADC14DIF = 0: A28; If ADC14DIF = 1: Ain+ = A28, Ain- = A29
318 A28A29Even = 28,
319 /// If ADC14DIF = 0: A29; If ADC14DIF = 1: Ain+ = A28, Ain- = A29
320 A28A29Odd = 29,
321 /// If ADC14DIF = 0: A30; If ADC14DIF = 1: Ain+ = A30, Ain- = A31
322 A30A31Even = 30,
323 /// If ADC14DIF = 0: A31; If ADC14DIF = 1: Ain+ = A30, Ain- = A31
324 A30A31Odd = 31
325 ],
326 /// End of sequence. Indicates the last conversion in a sequence.
327 EOS OFFSET(7) NUMBITS(1) [],
328 /// Selects combinations of +Vref and -Vref sources as well as the buffer selection and buffer on or off.
329 VRSEL OFFSET(8) NUMBITS(4) [
330 /// +Vref = AVCC, -Vref = AVSS
331 AvccAvss = 0,
332 /// +Vref = VREF buffered, -Vref = AVSS
333 VRefBufferedAvss = 1,
334 /// +Vref = VeREF+, -Vref = VeRE-
335 VeRef = 14,
336 /// +Vref = VeREF+ buffered, -Vref = VeREF-
337 VeRefBuffered = 15
338 ],
339 /// Differential mode
340 DIF OFFSET(13) NUMBITS(1) [
341 /// Single-ended mode enabled
342 SingleEnded = 0,
343 /// Differential mode enabled
344 Differential = 1
345 ],
346 /// Comparator window enable
347 WINC OFFSET(14) NUMBITS(1) [],
348 /// Window comparator threshold register selection
349 WINCTH OFFSET(15) NUMBITS(1) [
350 /// Use window comparator thresholds 0, ADC14LO0 and ADC14HI0
351 Threshold0 = 0,
352 /// Use window comparator thresholds 1, ADC14LO1 and ADC14HI1
353 Threshold1 = 1
354 ]
355 ],
356 /// ADC interrupt enable 1 register
357 IER1 [
358 /// Interrupt enable for the ADC14MEMx result register being greater than the ADC14LO
359 /// threshold and below the ADC14HI threshold
360 INIE OFFSET(1) NUMBITS(1) [],
361 /// Interrupt enable for the falling short of the lower limit interrupt of the window
362 /// comparator for the ADC14MEMx result registers.
363 LOIE OFFSET(2) NUMBITS(1) [],
364 /// Interrupt enable for the exceeding the upper limit interrupt of the window
365 /// comparator for ADC14MEMx result register.
366 HIIE OFFSET(3) NUMBITS(1) [],
367 /// ADC14MEMx overflow interrupt enable
368 OVIE OFFSET(4) NUMBITS(1) [],
369 /// ADC14 conversion-time-overflow interrupt enable
370 TOVIE OFFSET(5) NUMBITS(1) [],
371 /// ADC14 local buffered reference ready interrupt enable
372 RDYIE OFFSET(6) NUMBITS(1) []
373 ],
374 /// ADC interrupt flag 1 register
375 IFGR1 [
376 /// Interrupt flag for the ADC14MEMx result register being greater than the ADC14LO
377 /// threshold and below the ADC14HI threshold
378 INIFG OFFSET(1) NUMBITS(1) [],
379 /// Interrupt flag for the falling short of the lower limit interrupt of the window
380 /// comparator for the ADC14MEMx result registers.
381 LOIFG OFFSET(2) NUMBITS(1) [],
382 /// Interrupt flag for the exceeding the upper limit interrupt of the window
383 /// comparator for ADC14MEMx result register.
384 HIIFG OFFSET(3) NUMBITS(1) [],
385 /// ADC14MEMx overflow interrupt flag
386 OVIFG OFFSET(4) NUMBITS(1) [],
387 /// ADC14 conversion-time-overflow interrupt flag
388 TOVIFG OFFSET(5) NUMBITS(1) [],
389 /// ADC14 local buffered reference ready interrupt flag
390 RDYIFG OFFSET(6) NUMBITS(1) []
391 ],
392 /// ADC clear interrupt flag 1 register
393 CLRIFGR1 [
394 /// Clear INIFG
395 CLRINIFG OFFSET(1) NUMBITS(1) [],
396 /// Clear LOIFG
397 CLRLOIFG OFFSET(2) NUMBITS(1) [],
398 /// Clear HIIFG
399 CLRHIIFG OFFSET(3) NUMBITS(1) [],
400 /// Clear OVIFG
401 CLROVIFG OFFSET(4) NUMBITS(1) [],
402 /// Clear TOIFG
403 CLRTOVIFG OFFSET(5) NUMBITS(1) [],
404 /// Clear RDYIFG
405 CLRRDYIFG OFFSET(6) NUMBITS(1) []
406 ],
407 /// ADC interrupt vector register
408 IV [
409 /// ADC interrupt vector value
410 IVx OFFSET(0) NUMBITS(32) [
411 /// No interrupt pending
412 NoInterrupt = 0x00,
413 /// ADC14MEMx overflow, highest priority
414 MemOverflow = 0x02,
415 /// Conversion time overflow
416 ConversionTimeOverflow = 0x04,
417 /// ADC window high interrupt flag
418 WindowHigh = 0x06,
419 /// ADC window low interrupt flag
420 WindowLow = 0x08,
421 /// ADC in-window interrupt flag
422 WindowIn = 0x0A,
423 /// MEM0 interrupt flag
424 Mem0 = 0x0C,
425 /// MEM1 interrupt flag
426 Mem1 = 0x0E,
427 /// MEM2 interrupt flag
428 Mem2 = 0x10,
429 /// MEM3 interrupt flag
430 Mem3 = 0x12,
431 /// MEM4 interrupt flag
432 Mem4 = 0x14,
433 /// MEM5 interrupt flag
434 Mem5 = 0x16,
435 /// MEM6 interrupt flag
436 Mem6 = 0x18,
437 /// MEM7 interrupt flag
438 Mem7 = 0x1A,
439 /// MEM8 interrupt flag
440 Mem8 = 0x1C,
441 /// MEM9 interrupt flag
442 Mem9 = 0x1E,
443 /// MEM10 interrupt flag
444 Mem10 = 0x20,
445 /// MEM11 interrupt flag
446 Mem11 = 0x22,
447 /// MEM12 interrupt flag
448 Mem12 = 0x24,
449 /// MEM13 interrupt flag
450 Mem13 = 0x26,
451 /// MEM14 interrupt flag
452 Mem14 = 0x28,
453 /// MEM15 interrupt flag
454 Mem15 = 0x2A,
455 /// MEM16 interrupt flag
456 Mem16 = 0x2C,
457 /// MEM17 interrupt flag
458 Mem17 = 0x2E,
459 /// MEM18 interrupt flag
460 Mem18 = 0x30,
461 /// MEM19 interrupt flag
462 Mem19 = 0x32,
463 /// MEM20 interrupt flag
464 Mem20 = 0x34,
465 /// MEM21 interrupt flag
466 Mem21 = 0x36,
467 /// MEM22 interrupt flag
468 Mem22 = 0x38,
469 /// MEM23 interrupt flag
470 Mem23 = 0x3A,
471 /// MEM24 interrupt flag
472 Mem24 = 0x3C,
473 /// MEM25 interrupt flag
474 Mem25 = 0x3E,
475 /// MEM26 interrupt flag
476 Mem26 = 0x40,
477 /// MEM27 interrupt flag
478 Mem27 = 0x42,
479 /// MEM28 interrupt flag
480 Mem28 = 0x44,
481 /// MEM29 interrupt flag
482 Mem29 = 0x46,
483 /// MEM30 interrupt flag
484 Mem30 = 0x48,
485 /// MEM31 interrupt flag
486 Mem31 = 0x4A,
487 /// RDYIFG interrupt flag
488 Ready = 0x4C
489 ]
490 ]
491];
492
493pub struct Adc<'a> {
494 registers: StaticRef<AdcRegisters>,
495 resolution: AdcResolution,
496 mode: Cell<AdcMode>,
497 active_channel: Cell<Channel>,
498 ref_module: OptionalCell<&'a dyn ref_module::AnalogReference>,
499 timer: OptionalCell<&'a dyn timer::InternalTimer>,
500 dma: OptionalCell<&'a dma::DmaChannel<'a>>,
501 pub(crate) dma_chan: usize,
502 dma_src: u8,
503 buffer1: TakeCell<'static, [u16]>,
504 buffer2: TakeCell<'static, [u16]>,
505 client: OptionalCell<&'a dyn hil::adc::Client>,
506 highspeed_client: OptionalCell<&'a dyn hil::adc::HighSpeedClient>,
507}
508
509impl Adc<'_> {
510 pub fn new() -> Self {
511 Self {
512 registers: ADC_BASE,
513 resolution: DEFAULT_ADC_RESOLUTION,
514 mode: Cell::new(AdcMode::Disabled),
515 active_channel: Cell::new(Channel::Channel0),
516 ref_module: OptionalCell::empty(),
517 timer: OptionalCell::empty(), // must be TIMER_A3!
518 dma: OptionalCell::empty(),
519 dma_chan: 7,
520 dma_src: 7,
521 buffer1: TakeCell::empty(),
522 buffer2: TakeCell::empty(),
523 client: OptionalCell::empty(),
524 highspeed_client: OptionalCell::empty(),
525 }
526 }
527}
528
529#[repr(u32)]
530#[derive(Copy, Clone, PartialEq)]
531pub enum Channel {
532 Channel0 = 0,
533 Channel1 = 1,
534 Channel2 = 2,
535 Channel3 = 3,
536 Channel4 = 4,
537 Channel5 = 5,
538 Channel6 = 6,
539 Channel7 = 7,
540 Channel8 = 8,
541 Channel9 = 9,
542 Channel10 = 10,
543 Channel11 = 11,
544 Channel12 = 12,
545 Channel13 = 13,
546 Channel14 = 14,
547 Channel15 = 15,
548 Channel16 = 16,
549 Channel17 = 17,
550 Channel18 = 18,
551 Channel19 = 19,
552 Channel20 = 20,
553 Channel21 = 21,
554 Channel22 = 22,
555 Channel23 = 23,
556}
557
558#[allow(dead_code)]
559#[repr(u32)]
560#[derive(Copy, Clone, PartialEq)]
561enum AdcResolution {
562 Bits8 = 0,
563 Bits10 = 1,
564 Bits12 = 2,
565 Bits14 = 3,
566}
567
568#[allow(dead_code)]
569#[derive(Copy, Clone, PartialEq)]
570enum AdcMode {
571 Single,
572 Repeated,
573 Highspeed,
574 Disabled,
575}
576
577/// This function converts a `&'static mut [u8]` slice reference to a
578/// `&'static mut [u16]` slice.
579///
580/// ## Safety
581///
582/// It is a necessary condition for the passed buffer to have an even
583/// length, otherwise the function will panic because the conversion
584/// from `u8` to `u16` would end up in undefined behavior if the last
585/// word of the buffer converted is accessed!
586///
587/// Furthermore, this function assumes that the passed buffer is well
588/// aligned, to `core::mem::align_of::<u16>()`. Improper alignment of
589/// the passed buffer will result in undefined behavior.
590///
591/// This function is necessary since the DMA returns only `u8`-buffers
592/// whereas the ADC-traits only work with `u16`-buffers.
593unsafe fn buf_u8_to_buf_u16(buf: &'static mut [u8]) -> &'static mut [u16] {
594 if (buf.len() % 2) > 0 {
595 panic!("ADC: cannot convert an u8 array with an odd length to an u16 array");
596 }
597
598 let buf_ptr = mem::transmute::<*mut u8, *mut u16>(buf.as_mut_ptr());
599 slice::from_raw_parts_mut(buf_ptr, buf.len() / 2)
600}
601
602/// This function converts a `&'static mut [u16]` slice reference to a
603/// `&'static mut [u8]` slice reference.
604///
605/// Since the DMA only accepts only `u8`-buffers and the ADC-traits
606/// use `u16`-buffers, they have to be converted.
607unsafe fn buf_u16_to_buf_u8(buf: &'static mut [u16]) -> &'static mut [u8] {
608 let buf_ptr = mem::transmute::<*mut u16, *mut u8>(buf.as_mut_ptr());
609 slice::from_raw_parts_mut(buf_ptr, buf.len() * 2)
610}
611
612impl<'a> Adc<'a> {
613 fn is_enabled(&self) -> bool {
614 self.registers.ctl0.is_set(CTL0::ON)
615 }
616
617 fn stop(&self) {
618 // This is the recommended way to stop a conversation in any mode.
619 // See datasheet p. 855 section 22.2.8.6.
620 self.registers
621 .ctl0
622 .modify(CTL0::ENC::CLEAR + CTL0::CONSEQx::SingleChannelSequence);
623
624 // Disable all interrupts
625 self.registers.ie0.set(0);
626
627 // Clear all pending interrupts
628 self.registers.clrifg0.set(u32::MAX);
629 self.registers.clrifg1.set(u32::MAX);
630 }
631
632 fn setup(&self) {
633 self.stop();
634
635 for i in 0..AVAILABLE_ADC_CHANNELS {
636 // Set the input for the channel
637 // Set Reference voltage to Internal AVCC for Vref+ and AVSS (GND) for Vref-
638 // Configure the channel for single-ended mode
639 // Disable comparator window
640 self.registers.mctl[i].modify(
641 MCTLx::INCHx.val(i as u32)
642 + MCTLx::VRSEL::AvccAvss
643 + MCTLx::DIF::SingleEnded
644 + MCTLx::WINC::CLEAR,
645 );
646 }
647
648 // Set predivider of the ADC-clock to 1
649 // Set divider of the ADC-clock to 1
650 // Set ADC-clock source to HSMCLK
651 // Set the sample-and-hold time to 4 clock-cyles for channel 0-7 and 24-31
652 // Set the sample-and-hold time to 4 clock-cyles for channel 8-23
653 self.registers.ctl0.modify(
654 CTL0::PDIV::PreDivideBy1
655 + CTL0::DIVx::DivideBy1
656 + CTL0::SSELx::HSMCLK
657 + CTL0::SHTOx::Cycles4
658 + CTL0::SHT1x::Cycles4,
659 );
660
661 // Enable the battery monitor on channel 23 (measures 1/2 * AVCC)
662 // Enable the internal temperature sensor on channel 22
663 // Set the ADC resolution
664 self.registers.ctl1.modify(
665 CTL1::BATMAP::Selected + CTL1::TCMAP::Selected + CTL1::RES.val(self.resolution as u32),
666 );
667
668 let dma_conf = dma::DmaConfig {
669 src_chan: self.dma_src,
670 mode: dma::DmaMode::PingPong,
671 width: dma::DmaDataWidth::Width16Bit,
672 src_incr: dma::DmaPtrIncrement::NoIncr,
673 dst_incr: dma::DmaPtrIncrement::Incr16Bit,
674 };
675
676 // Setup DMA
677 self.dma.map(|dma| dma.initialize(&dma_conf));
678
679 // Enable ADC
680 self.registers.ctl0.modify(CTL0::ON::SET);
681 }
682
683 fn get_sample(&self, chan: Channel) -> u16 {
684 // calculate the number of shifts which are necessary to align the sample to u16
685 let shift = 8 - 2 * (self.resolution as usize);
686
687 // Align the sample
688 (self.registers.mem[chan as usize].get() << shift) as u16
689 }
690
691 fn enable_interrupt(&self, chan: Channel) {
692 self.registers
693 .ie0
694 .set(self.registers.ie0.get() | (1 << (chan as u32)));
695 }
696
697 fn disable_interrupt(&self, chan: Channel) {
698 self.registers
699 .ie0
700 .set(self.registers.ie0.get() & !(1 << (chan as u32)));
701 }
702
703 pub fn set_modules(
704 &self,
705 ref_module: &'a dyn ref_module::AnalogReference,
706 timer: &'a dyn timer::InternalTimer,
707 dma: &'a dma::DmaChannel<'a>,
708 ) {
709 self.ref_module.set(ref_module);
710 self.timer.set(timer);
711 self.dma.set(dma);
712 }
713
714 pub fn handle_interrupt(&self) {
715 let chan = self.active_channel.get();
716 let chan_nr = chan as usize;
717 let int_bit = 1 << (chan as u32);
718 let mode = self.mode.get();
719
720 if (self.registers.ifg0.get() & int_bit) > 0 {
721 // Clear interrupt flag
722 self.registers.clrifg0.set(int_bit);
723
724 if mode == AdcMode::Single {
725 self.mode.set(AdcMode::Disabled);
726
727 self.disable_interrupt(chan);
728
729 // Stop sampling
730 self.registers.ctl0.modify(CTL0::ENC::CLEAR);
731 }
732
733 // Throw callback
734 self.client.map(|client| {
735 client.sample_ready(self.get_sample(chan));
736 });
737 } else {
738 panic!("ADC: unhandled interrupt: channel {}", chan_nr);
739 }
740 }
741}
742
743impl dma::DmaClient for Adc<'_> {
744 fn transfer_done(
745 &self,
746 _tx_buf: Option<&'static mut [u8]>,
747 rx_buf: Option<&'static mut [u8]>,
748 transmitted_bytes: usize,
749 ) {
750 if let Some(buffer) = rx_buf {
751 // Cast the [u8] buffer back to [u16]
752 let buf = unsafe { buf_u8_to_buf_u16(buffer) };
753
754 // Align the received data to 16bit
755 let samples = transmitted_bytes / 2;
756 let shift = 8 - 2 * (self.resolution as usize);
757 for i in 0..samples {
758 buf[i] <<= shift;
759 }
760
761 self.highspeed_client.map(|client| {
762 client.samples_ready(buf, samples);
763 });
764 }
765 }
766}
767
768impl<'a> hil::adc::Adc<'a> for Adc<'a> {
769 type Channel = Channel;
770
771 fn sample(&self, channel: &Self::Channel) -> Result<(), ErrorCode> {
772 if !self.is_enabled() {
773 self.setup();
774 }
775
776 if self.mode.get() != AdcMode::Disabled {
777 return Err(ErrorCode::BUSY);
778 }
779
780 self.mode.set(AdcMode::Repeated);
781 self.active_channel.set(*channel);
782
783 // Set the channel-number where to start sampling
784 self.registers
785 .ctl1
786 .modify(CTL1::STARTADDx.val(*channel as u32));
787
788 self.enable_interrupt(*channel);
789
790 // Set ADC to mode where a single channel gets sampled once
791 // Set the sample-and-hold source select to software-based
792 // Set the sampling-timer for generating the sample-period
793 // Enable conversation
794 // Start conversation
795 self.registers.ctl0.modify(
796 CTL0::CONSEQx::SingleChannelSingleConversion
797 + CTL0::SHSx::SCBit
798 + CTL0::SHP::SET
799 + CTL0::ENC::SET
800 + CTL0::SC::SET,
801 );
802
803 Ok(())
804 }
805
806 fn sample_continuous(&self, channel: &Self::Channel, frequency: u32) -> Result<(), ErrorCode> {
807 if !self.is_enabled() {
808 self.setup();
809 }
810
811 if self.mode.get() != AdcMode::Disabled {
812 return Err(ErrorCode::BUSY);
813 }
814
815 if frequency == 0 || frequency > 5000 {
816 // Limit the frequency to 5kHz since the overhead of the callback and the interrupt
817 // handler is too big otherwise and the timing starts becoming incorrect
818 return Err(ErrorCode::INVAL);
819 }
820
821 self.mode.set(AdcMode::Repeated);
822 self.active_channel.set(*channel);
823
824 // Setup timer
825 self.timer
826 .map(|timer| timer.start(frequency, timer::InternalTrigger::CaptureCompare1));
827
828 // Set the channel-number where to start sampling
829 self.registers
830 .ctl1
831 .modify(CTL1::STARTADDx.val(*channel as u32));
832
833 self.enable_interrupt(*channel);
834
835 // Set ADC to mode where a single channel gets sampled continuously
836 // Set the sample-and-hold source select to timer-triggered
837 // Use TIMER_A3 to generate the SAMPCON signal
838 // Enable multiple sample and conversions
839 // Enable conversation
840 self.registers.ctl0.modify(
841 CTL0::CONSEQx::RepeatSingleChannel
842 + CTL0::SHSx::Source7
843 + CTL0::SHP::CLEAR
844 + CTL0::MSC::SET
845 + CTL0::ENC::SET,
846 );
847
848 Ok(())
849 }
850
851 fn stop_sampling(&self) -> Result<(), ErrorCode> {
852 let mode = self.mode.get();
853
854 if mode == AdcMode::Disabled {
855 return Err(ErrorCode::OFF);
856 }
857
858 self.timer.map(|timer| timer.stop());
859 self.stop();
860 if mode == AdcMode::Highspeed {
861 self.dma.map(|dma| {
862 let (_nr_bytes, _tx1, rx1, _tx2, rx2) = dma.stop();
863
864 if let Some(buffer) = rx1 {
865 let buf = unsafe { buf_u8_to_buf_u16(buffer) };
866 self.buffer1.replace(buf);
867 }
868
869 if let Some(buffer) = rx2 {
870 let buf = unsafe { buf_u8_to_buf_u16(buffer) };
871 self.buffer2.replace(buf);
872 }
873 });
874 }
875
876 self.mode.set(AdcMode::Disabled);
877 Ok(())
878 }
879
880 fn get_resolution_bits(&self) -> usize {
881 match self.resolution {
882 AdcResolution::Bits8 => 8,
883 AdcResolution::Bits10 => 10,
884 AdcResolution::Bits12 => 12,
885 AdcResolution::Bits14 => 14,
886 }
887 }
888
889 fn get_voltage_reference_mv(&self) -> Option<usize> {
890 self.ref_module.map(|ref_mod| ref_mod.ref_voltage_mv())
891 }
892
893 fn set_client(&self, client: &'a dyn hil::adc::Client) {
894 self.client.set(client);
895 }
896}
897
898impl<'a> hil::adc::AdcHighSpeed<'a> for Adc<'a> {
899 fn sample_highspeed(
900 &self,
901 channel: &Self::Channel,
902 frequency: u32,
903 buffer1: &'static mut [u16],
904 length1: usize,
905 buffer2: &'static mut [u16],
906 length2: usize,
907 ) -> Result<(), (ErrorCode, &'static mut [u16], &'static mut [u16])> {
908 if !self.is_enabled() {
909 self.setup();
910 }
911 if self.mode.get() != AdcMode::Disabled {
912 return Err((ErrorCode::BUSY, buffer1, buffer2));
913 }
914 if frequency == 0 || frequency > MAX_SAMPLE_FREQ_HZ {
915 return Err((ErrorCode::INVAL, buffer1, buffer2));
916 }
917 if length1 == 0 {
918 return Err((ErrorCode::INVAL, buffer1, buffer2));
919 }
920
921 self.mode.set(AdcMode::Highspeed);
922 self.active_channel.set(*channel);
923
924 // Set the channel-number where to start sampling
925 self.registers
926 .ctl1
927 .modify(CTL1::STARTADDx.val(*channel as u32));
928
929 // Set ADC to mode where a single channel gets sampled continuously
930 // Set the sample-and-hold source select to timer-triggered
931 // Use TIMER_A3 to generate the SAMPCON signal
932 // Enable multiple sample and conversions
933 // Enable conversation
934 self.registers.ctl0.modify(
935 CTL0::CONSEQx::RepeatSingleChannel
936 + CTL0::SHSx::Source7
937 + CTL0::SHP::CLEAR
938 + CTL0::MSC::SET
939 + CTL0::ENC::SET,
940 );
941
942 let adc_reg =
943 (core::ptr::from_ref::<ReadWrite<u32>>(&self.registers.mem[*channel as usize]))
944 .cast::<()>();
945
946 // Convert the [u16] into an [u8] since the DMA works only with [u8]
947 let buf1 = unsafe { buf_u16_to_buf_u8(buffer1) };
948 let buf2 = unsafe { buf_u16_to_buf_u8(buffer2) };
949
950 // Setup the DMA transfer
951 if length2 == 0 {
952 // If only 1 buffer is provided, we do a simple DMA transfer without toggling
953 // the buffers
954 self.dma
955 .map(move |dma| dma.transfer_periph_to_mem(adc_reg, buf1, length1 * 2));
956 } else {
957 // If two buffers are provided, we use the pingpong mode of the DMA which can toggle
958 // between 2 buffers
959 self.dma.map(move |dma| {
960 dma.transfer_periph_to_mem_pingpong(adc_reg, buf1, length1 * 2, buf2, length2 * 2)
961 });
962 }
963
964 // Setup the timer
965 self.timer
966 .map(|timer| timer.start(frequency, timer::InternalTrigger::CaptureCompare1));
967
968 Ok(())
969 }
970
971 fn provide_buffer(
972 &self,
973 buffer: &'static mut [u16],
974 length: usize,
975 ) -> Result<(), (ErrorCode, &'static mut [u16])> {
976 if self.mode.get() != AdcMode::Highspeed {
977 panic!("ADC: cannot provide buffers in a different mode than Highspeed!");
978 }
979
980 let buf = unsafe { buf_u16_to_buf_u8(buffer) };
981 self.dma
982 .map(move |dma| dma.provide_new_buffer(buf, length * 2));
983 Ok(())
984 }
985
986 fn retrieve_buffers(
987 &self,
988 ) -> Result<(Option<&'static mut [u16]>, Option<&'static mut [u16]>), ErrorCode> {
989 if self.mode.get() != AdcMode::Disabled {
990 // When the device is active, the buffers cannot be returned
991 Err(ErrorCode::INVAL)
992 } else {
993 Ok((self.buffer1.take(), self.buffer2.take()))
994 }
995 }
996
997 fn set_highspeed_client(&self, client: &'a dyn hil::adc::HighSpeedClient) {
998 self.highspeed_client.set(client);
999 }
1000}