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}