sam4l/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//! Implementation of the SAM4L ADCIFE.
6//!
7//! This is an implementation of the SAM4L analog to digital converter. It is
8//! bare-bones because it provides little flexibility on how samples are taken.
9//! Currently, all samples:
10//!
11//! - are 12 bits
12//! - use the ground pad as the negative reference
13//! - use a VCC/2 positive reference
14//! - use a gain of 0.5x
15//! - are left justified
16//!
17//! Samples can either be collected individually or continuously at a specified
18//! frequency.
19//!
20//! - Author: Philip Levis <pal@cs.stanford.edu>, Branden Ghena <brghena@umich.edu>
21//! - Updated: May 1, 2017
22
23use crate::dma;
24use crate::pm::{self, Clock, PBAClock};
25use crate::scif;
26use core::cell::Cell;
27use core::{cmp, mem, slice};
28use kernel::ErrorCode;
29use kernel::hil;
30use kernel::utilities::StaticRef;
31use kernel::utilities::cells::{OptionalCell, TakeCell};
32use kernel::utilities::math;
33use kernel::utilities::registers::interfaces::{Readable, Writeable};
34use kernel::utilities::registers::{
35 ReadOnly, ReadWrite, WriteOnly, register_bitfields, register_structs,
36};
37
38/// Representation of an ADC channel on the SAM4L.
39#[derive(PartialEq)]
40pub struct AdcChannel {
41 chan_num: u32,
42 internal: u32,
43}
44
45/// SAM4L ADC channels.
46#[derive(Copy, Clone, Debug)]
47#[repr(u8)]
48pub enum Channel {
49 AD0 = 0x00,
50 AD1 = 0x01,
51 AD2 = 0x02,
52 AD3 = 0x03,
53 AD4 = 0x04,
54 AD5 = 0x05,
55 AD6 = 0x06,
56 AD7 = 0x07,
57 AD8 = 0x08,
58 AD9 = 0x09,
59 AD10 = 0x0A,
60 AD11 = 0x0B,
61 AD12 = 0x0C,
62 AD13 = 0x0D,
63 AD14 = 0x0E,
64 Bandgap = 0x0F,
65 ScaledVCC = 0x12,
66 DAC = 0x13,
67 Vsingle = 0x16,
68 ReferenceGround = 0x17,
69}
70
71/// Initialization of an ADC channel.
72impl AdcChannel {
73 /// Create a new ADC channel.
74 ///
75 /// - `channel`: Channel enum representing the channel number and whether it
76 /// is internal
77 pub const fn new(channel: Channel) -> AdcChannel {
78 AdcChannel {
79 chan_num: ((channel as u8) & 0x0F) as u32,
80 internal: (((channel as u8) >> 4) & 0x01) as u32,
81 }
82 }
83}
84
85/// ADC driver code for the SAM4L.
86pub struct Adc<'a> {
87 registers: StaticRef<AdcRegisters>,
88
89 // state tracking for the ADC
90 enabled: Cell<bool>,
91 adc_clk_freq: Cell<u32>,
92 active: Cell<bool>,
93 continuous: Cell<bool>,
94 dma_running: Cell<bool>,
95 cpu_clock: Cell<bool>,
96
97 // timer fire counting for slow sampling rates
98 timer_repeats: Cell<u8>,
99 timer_counts: Cell<u8>,
100
101 // DMA peripheral, buffers, and length
102 rx_dma: OptionalCell<&'static dma::DMAChannel>,
103 rx_dma_peripheral: dma::DMAPeripheral,
104 rx_length: Cell<usize>,
105 next_dma_buffer: TakeCell<'static, [u16]>,
106 next_dma_length: Cell<usize>,
107 stopped_buffer: TakeCell<'static, [u16]>,
108
109 // ADC client to send sample complete notifications to
110 client: OptionalCell<&'a dyn hil::adc::Client>,
111 highspeed_client: OptionalCell<&'a dyn hil::adc::HighSpeedClient>,
112 pm: &'static pm::PowerManager,
113}
114
115register_structs! {
116 /// Memory mapped registers for the ADC.
117 pub AdcRegisters {
118 (0x000 => cr: WriteOnly<u32, Control::Register>),
119 (0x004 => cfg: ReadWrite<u32, Configuration::Register>),
120 (0x008 => sr: ReadOnly<u32, Status::Register>),
121 (0x00C => scr: WriteOnly<u32, Interrupt::Register>),
122 (0x010 => _reserved0: u32),
123 (0x014 => seqcfg: ReadWrite<u32, SequencerConfig::Register>),
124 (0x018 => cdma: WriteOnly<u32>),
125 (0x01C => tim: ReadWrite<u32, TimingConfiguration::Register>),
126 (0x020 => itimer: ReadWrite<u32, InternalTimer::Register>),
127 (0x024 => wcfg: ReadWrite<u32, WindowMonitorConfiguration::Register>),
128 (0x028 => wth: ReadWrite<u32, WindowMonitorThresholdConfiguration::Register>),
129 (0x02C => lcv: ReadOnly<u32, SequencerLastConvertedValue::Register>),
130 (0x030 => ier: WriteOnly<u32, Interrupt::Register>),
131 (0x034 => idr: WriteOnly<u32, Interrupt::Register>),
132 (0x038 => imr: ReadOnly<u32, Interrupt::Register>),
133 (0x03C => calib: ReadWrite<u32>),
134 (0x040 => @END),
135 }
136}
137
138register_bitfields![u32,
139 Control [
140 /// Bandgap buffer request disable
141 BGREQDIS 11,
142 /// Bandgap buffer request enable
143 BGREQEN 10,
144 /// ADCIFE disable
145 DIS 9,
146 /// ADCIFE enable
147 EN 8,
148 /// Reference buffer disable
149 REFBUFDIS 5,
150 /// Reference buffer enable
151 REFBUFEN 4,
152 /// Sequence trigger
153 STRIG 3,
154 /// Internal timer start bit
155 TSTART 2,
156 /// Internal timer stop bit
157 TSTOP 1,
158 /// Software reset
159 SWRST 0
160 ],
161
162 Configuration [
163 /// Prescaler Rate Selection
164 PRESCAL OFFSET(8) NUMBITS(3) [
165 DIV4 = 0,
166 DIV8 = 1,
167 DIV16 = 2,
168 DIV32 = 3,
169 DIV64 = 4,
170 DIV128 = 5,
171 DIV256 = 6,
172 DIV512 = 7
173 ],
174 /// Clock Selection for sequencer/ADC cell
175 CLKSEL OFFSET(6) NUMBITS(1) [
176 GenericClock = 0,
177 ApbClock = 1
178 ],
179 /// ADC current reduction
180 SPEED OFFSET(4) NUMBITS(2) [
181 ksps300 = 0,
182 ksps225 = 1,
183 ksps150 = 2,
184 ksps75 = 3
185 ],
186 /// ADC Reference selection
187 REFSEL OFFSET(1) NUMBITS(3) [
188 Internal1V = 0,
189 VccX0p625 = 1,
190 ExternalRef1 = 2,
191 ExternalRef2 = 3,
192 VccX0p5 = 4
193 ]
194 ],
195
196 Status [
197 /// Bandgap buffer request Status
198 BGREQ 30,
199 /// Reference Buffer Status
200 REFBUF 28,
201 /// Conversion busy
202 CBUSY 27,
203 /// Sequencer busy
204 SBUSY 26,
205 /// Timer busy
206 TBUSY 25,
207 /// Enable Status
208 EN 24,
209 /// Timer time out
210 TTO 5,
211 /// Sequencer missed trigger event
212 SMTRG 3,
213 /// Window monitor
214 WM 2,
215 /// Sequencer last converted value overrun
216 LOVR 1,
217 /// Sequencer end of conversion
218 SEOC 0
219 ],
220
221 Interrupt [
222 /// Timer time out
223 TTO 5,
224 /// Sequencer missed trigger event
225 SMTRG 3,
226 /// Window monitor
227 WM 2,
228 /// Sequencer last converted value overrun
229 LOVR 1,
230 /// Sequencer end of conversion
231 SEOC 0
232 ],
233
234 SequencerConfig [
235 /// Zoom shift/unipolar reference source selection
236 ZOOMRANGE OFFSET(28) NUMBITS(3) [],
237 /// MUX selection on Negative ADC input channel
238 MUXNEG OFFSET(20) NUMBITS(3) [],
239 /// MUS selection of Positive ADC input channel
240 MUXPOS OFFSET(16) NUMBITS(4) [],
241 /// Internal Voltage Sources Selection
242 INTERNAL OFFSET(14) NUMBITS(2) [],
243 /// Resolution
244 RES OFFSET(12) NUMBITS(1) [
245 Bits12 = 0,
246 Bits8 = 1
247 ],
248 /// Trigger selection
249 TRGSEL OFFSET(8) NUMBITS(3) [
250 Software = 0,
251 InternalAdcTimer = 1,
252 InternalTriggerSource = 2,
253 ContinuousMode = 3,
254 ExternalTriggerPinRising = 4,
255 ExternalTriggerPinFalling = 5,
256 ExternalTriggerPinBoth = 6
257 ],
258 /// Gain Compensation
259 GCOMP OFFSET(7) NUMBITS(1) [
260 Disable = 0,
261 Enable = 1
262 ],
263 /// Gain factor
264 GAIN OFFSET(4) NUMBITS(3) [
265 Gain1x = 0,
266 Gain2x = 1,
267 Gain4x = 2,
268 Gain8x = 3,
269 Gain16x = 4,
270 Gain32x = 5,
271 Gain64x = 6,
272 Gain0p5x = 7
273 ],
274 /// Bipolar Mode
275 BIPOLAR OFFSET(2) NUMBITS(1) [
276 Disable = 0,
277 Enable = 1
278 ],
279 /// Half Word Left Adjust
280 HWLA OFFSET(0) NUMBITS(1) [
281 Disable = 0,
282 Enable = 1
283 ]
284 ],
285
286 TimingConfiguration [
287 /// Enable Startup
288 ENSTUP OFFSET(8) NUMBITS(1) [
289 Disable = 0,
290 Enable = 1
291 ],
292 /// Startup time
293 STARTUP OFFSET(0) NUMBITS(5) []
294 ],
295
296 InternalTimer [
297 /// Internal Timer Max Counter
298 ITMC OFFSET(0) NUMBITS(16) []
299 ],
300
301 WindowMonitorConfiguration [
302 /// Window Monitor Mode
303 WM OFFSET(12) NUMBITS(3) []
304 ],
305
306 WindowMonitorThresholdConfiguration [
307 /// High Threshold
308 HT OFFSET(16) NUMBITS(12) [],
309 /// Low Threshold
310 LT OFFSET(0) NUMBITS(12) []
311 ],
312
313 SequencerLastConvertedValue [
314 /// Last converted negative channel
315 LCNC OFFSET(20) NUMBITS(3) [],
316 /// Last converted positive channel
317 LCPC OFFSET(16) NUMBITS(4) [],
318 /// Last converted value
319 LCV OFFSET(0) NUMBITS(16) []
320 ]
321];
322
323// Page 59 of SAM4L data sheet
324const BASE_ADDRESS: StaticRef<AdcRegisters> =
325 unsafe { StaticRef::new(0x40038000 as *const AdcRegisters) };
326
327/// Functions for initializing the ADC.
328impl Adc<'_> {
329 /// Create a new ADC driver.
330 ///
331 /// - `rx_dma_peripheral`: type used for DMA transactions
332 pub fn new(rx_dma_peripheral: dma::DMAPeripheral, pm: &'static pm::PowerManager) -> Self {
333 Self {
334 // pointer to memory mapped I/O registers
335 registers: BASE_ADDRESS,
336
337 // status of the ADC peripheral
338 enabled: Cell::new(false),
339 adc_clk_freq: Cell::new(0),
340 active: Cell::new(false),
341 continuous: Cell::new(false),
342 dma_running: Cell::new(false),
343 cpu_clock: Cell::new(false),
344
345 // timer repeating state for slow sampling rates
346 timer_repeats: Cell::new(0),
347 timer_counts: Cell::new(0),
348
349 // DMA status and stuff
350 rx_dma: OptionalCell::empty(),
351 rx_dma_peripheral,
352 rx_length: Cell::new(0),
353 next_dma_buffer: TakeCell::empty(),
354 next_dma_length: Cell::new(0),
355 stopped_buffer: TakeCell::empty(),
356
357 // higher layer to send responses to
358 client: OptionalCell::empty(),
359 highspeed_client: OptionalCell::empty(),
360 pm,
361 }
362 }
363
364 /// Sets the DMA channel for this driver.
365 ///
366 /// - `rx_dma`: reference to the DMA channel the ADC should use
367 pub fn set_dma(&self, rx_dma: &'static dma::DMAChannel) {
368 self.rx_dma.set(rx_dma);
369 }
370
371 /// Interrupt handler for the ADC.
372 pub fn handle_interrupt(&self) {
373 let status = self.registers.sr.is_set(Status::SEOC);
374
375 if self.enabled.get() && self.active.get() {
376 if status {
377 // sample complete interrupt
378
379 // should we deal with this sample now, or wait for the next
380 // one?
381 if self.timer_counts.get() >= self.timer_repeats.get() {
382 // we actually care about this sample
383
384 // single sample complete. Send value to client
385 let val = self.registers.lcv.read(SequencerLastConvertedValue::LCV) as u16;
386 self.client.map(|client| {
387 client.sample_ready(val);
388 });
389
390 // clean up state
391 if self.continuous.get() {
392 // continuous sampling, reset counts and keep going
393 self.timer_counts.set(0);
394 } else {
395 // single sampling, disable interrupt and set inactive
396 self.active.set(false);
397 self.registers.idr.write(Interrupt::SEOC::SET);
398 }
399 } else {
400 // increment count and wait for next sample
401 self.timer_counts.set(self.timer_counts.get() + 1);
402 }
403
404 // clear status
405 self.registers.scr.write(Interrupt::SEOC::SET);
406 }
407 } else {
408 // we are inactive, why did we get an interrupt?
409 // disable all interrupts, clear status, and just ignore it
410 self.registers.idr.write(
411 Interrupt::TTO::SET
412 + Interrupt::SMTRG::SET
413 + Interrupt::WM::SET
414 + Interrupt::LOVR::SET
415 + Interrupt::SEOC::SET,
416 );
417 self.clear_status();
418 }
419 }
420
421 /// Clear all status bits using the status clear register.
422 fn clear_status(&self) {
423 self.registers.scr.write(
424 Interrupt::TTO::SET
425 + Interrupt::SMTRG::SET
426 + Interrupt::WM::SET
427 + Interrupt::LOVR::SET
428 + Interrupt::SEOC::SET,
429 );
430 }
431
432 // Configures the ADC with the slowest clock that can provide continuous sampling at
433 // the desired frequency and enables the ADC. Subsequent calls with the same frequency
434 // value have no effect. Using the slowest clock also ensures efficient discrete
435 // sampling.
436 fn config_and_enable(&self, frequency: u32) -> Result<(), ErrorCode> {
437 if self.active.get() {
438 // disallow reconfiguration during sampling
439 Err(ErrorCode::BUSY)
440 } else if frequency == self.adc_clk_freq.get() {
441 // already configured to work on this frequency
442 Ok(())
443 } else {
444 // disabling the ADC before switching clocks is necessary to avoid
445 // leaving it in undefined state
446 self.registers.cr.write(Control::DIS::SET);
447
448 // wait until status is disabled
449 let mut timeout = 10000;
450 while self.registers.sr.is_set(Status::EN) {
451 timeout -= 1;
452 if timeout == 0 {
453 // ADC never disabled
454 return Err(ErrorCode::FAIL);
455 }
456 }
457
458 self.enabled.set(true);
459
460 // configure the ADC max speed and reference select
461 let mut cfg_val = Configuration::SPEED::ksps300 + Configuration::REFSEL::VccX0p5;
462
463 // First, enable the clocks
464 // Both the ADCIFE clock and GCLK10 are needed,
465 // but the GCLK10 source depends on the requested sampling frequency
466
467 // turn on ADCIFE bus clock. Already set to the same frequency
468 // as the CPU clock
469 pm::enable_clock(Clock::PBA(PBAClock::ADCIFE));
470
471 // Now, determine the prescalar.
472 // The maximum sampling frequency with the RC clocks is 1/32th of their clock
473 // frequency. This is because of the minimum PRESCAL by a factor of 4 and the
474 // 7+1 cycles needed for conversion in continuous mode. Hence, 4*(7+1)=32.
475 if frequency <= 113600 / 32 {
476 // RC oscillator
477 self.cpu_clock.set(false);
478 let max_freq: u32 = if frequency <= 32000 / 32 {
479 // frequency of the RC32K is 32KHz.
480 scif::generic_clock_enable(
481 scif::GenericClock::GCLK10,
482 scif::ClockSource::RC32K,
483 );
484 32000 / 32
485 } else {
486 // frequency of the RCSYS is 115KHz.
487 scif::generic_clock_enable(
488 scif::GenericClock::GCLK10,
489 scif::ClockSource::RCSYS,
490 );
491 113600 / 32
492 };
493 let divisor = (frequency + max_freq - 1) / frequency; // ceiling of division
494 let divisor_pow2 = divisor.next_power_of_two();
495 let clock_divisor = cmp::min(math::log_base_two(divisor_pow2), 7);
496 self.adc_clk_freq.set(max_freq / (1 << (clock_divisor)));
497 cfg_val += Configuration::PRESCAL.val(clock_divisor);
498 } else {
499 // CPU clock
500 self.cpu_clock.set(true);
501 scif::generic_clock_enable(scif::GenericClock::GCLK10, scif::ClockSource::CLK_CPU);
502 // determine clock divider
503 // we need the ADC_CLK to be a maximum of 1.5 MHz in frequency,
504 // so we need to find the PRESCAL value that will make this
505 // happen.
506 // Formula: f(ADC_CLK) = f(CLK_CPU)/2^(N+2) <= 1.5 MHz
507 // and we solve for N
508 // becomes: N <= ceil(log_2(f(CLK_CPU)/1500000)) - 2
509 let cpu_frequency = self.pm.get_system_frequency();
510 let divisor = cpu_frequency.div_ceil(1500000);
511 let divisor_pow2 = divisor.next_power_of_two();
512 let clock_divisor = cmp::min(math::log_base_two(divisor_pow2).saturating_sub(2), 7);
513 self.adc_clk_freq
514 .set(cpu_frequency / (1 << (clock_divisor + 2)));
515 cfg_val += Configuration::PRESCAL.val(clock_divisor);
516 }
517
518 if self.cpu_clock.get() {
519 cfg_val += Configuration::CLKSEL::ApbClock
520 } else {
521 cfg_val += Configuration::CLKSEL::GenericClock
522 }
523
524 self.registers.cfg.write(cfg_val);
525
526 // set startup to wait 24 cycles
527 self.registers.tim.write(
528 TimingConfiguration::ENSTUP::Enable + TimingConfiguration::STARTUP.val(0x17),
529 );
530
531 // software reset (does not clear registers)
532 self.registers.cr.write(Control::SWRST::SET);
533
534 // enable ADC
535 self.registers.cr.write(Control::EN::SET);
536
537 // wait until status is enabled
538 let mut timeout = 10000;
539 while !self.registers.sr.is_set(Status::EN) {
540 timeout -= 1;
541 if timeout == 0 {
542 // ADC never enabled
543 return Err(ErrorCode::FAIL);
544 }
545 }
546
547 // enable Bandgap buffer and Reference buffer. I don't actually
548 // know what these do, but you need to turn them on
549 self.registers
550 .cr
551 .write(Control::BGREQEN::SET + Control::REFBUFEN::SET);
552
553 // wait until buffers are enabled
554 timeout = 100000;
555 while !self
556 .registers
557 .sr
558 .matches_all(Status::BGREQ::SET + Status::REFBUF::SET + Status::EN::SET)
559 {
560 timeout -= 1;
561 if timeout == 0 {
562 // ADC buffers never enabled
563 return Err(ErrorCode::FAIL);
564 }
565 }
566
567 Ok(())
568 }
569 }
570
571 /// Disables the ADC so that the chip can return to deep sleep
572 fn disable(&self) {
573 // disable ADC
574 self.registers.cr.write(Control::DIS::SET);
575
576 // wait until status is disabled
577 let mut timeout = 10000;
578 while self.registers.sr.is_set(Status::EN) {
579 timeout -= 1;
580 if timeout == 0 {
581 // ADC never disabled
582 return;
583 }
584 }
585
586 // disable bandgap and reference buffers
587 self.registers
588 .cr
589 .write(Control::BGREQDIS::SET + Control::REFBUFDIS::SET);
590
591 self.enabled.set(false);
592 scif::generic_clock_disable(scif::GenericClock::GCLK10);
593 pm::disable_clock(Clock::PBA(PBAClock::ADCIFE));
594 }
595}
596
597/// Implements an ADC capable reading ADC samples on any channel.
598impl<'a> hil::adc::Adc<'a> for Adc<'a> {
599 type Channel = AdcChannel;
600
601 /// Capture a single analog sample, calling the client when complete.
602 /// Returns an error if the ADC is already sampling.
603 ///
604 /// - `channel`: the ADC channel to sample
605 fn sample(&self, channel: &Self::Channel) -> Result<(), ErrorCode> {
606 // always configure to 1KHz to get the slowest clock with single sampling
607 let res = self.config_and_enable(1000);
608
609 if res != Ok(()) {
610 res
611 } else if !self.enabled.get() {
612 Err(ErrorCode::OFF)
613 } else if self.active.get() {
614 // only one operation at a time
615 Err(ErrorCode::BUSY)
616 } else {
617 self.active.set(true);
618 self.continuous.set(false);
619 self.timer_repeats.set(0);
620 self.timer_counts.set(0);
621
622 // MUXNEG.val(0x7) -> ground pad
623 let cfg = SequencerConfig::MUXNEG.val(0x7)
624 + SequencerConfig::MUXPOS.val(channel.chan_num)
625 + SequencerConfig::INTERNAL.val(0x2 | channel.internal)
626 + SequencerConfig::RES::Bits12
627 + SequencerConfig::TRGSEL::Software
628 + SequencerConfig::GCOMP::Disable
629 + SequencerConfig::GAIN::Gain0p5x
630 + SequencerConfig::BIPOLAR::Disable
631 + SequencerConfig::HWLA::Enable;
632 self.registers.seqcfg.write(cfg);
633
634 // clear any current status
635 self.clear_status();
636
637 // enable end of conversion interrupt
638 self.registers.ier.write(Interrupt::SEOC::SET);
639
640 // initiate conversion
641 self.registers.cr.write(Control::STRIG::SET);
642
643 Ok(())
644 }
645 }
646
647 /// Request repeated analog samples on a particular channel, calling after
648 /// each sample. In order to not unacceptably slow down the system
649 /// collecting samples, this interface is limited to one sample every 100
650 /// microseconds (10000 samples per second). To sample faster, use the
651 /// sample_highspeed function.
652 ///
653 /// - `channel`: the ADC channel to sample
654 /// - `frequency`: the number of samples per second to collect
655 fn sample_continuous(&self, channel: &Self::Channel, frequency: u32) -> Result<(), ErrorCode> {
656 let res = self.config_and_enable(frequency);
657
658 if res != Ok(()) {
659 res
660 } else if !self.enabled.get() {
661 Err(ErrorCode::OFF)
662 } else if self.active.get() {
663 // only one sample at a time
664 Err(ErrorCode::BUSY)
665 } else if frequency == 0 || frequency > 10000 {
666 // limit sampling frequencies to a valid range
667 Err(ErrorCode::INVAL)
668 } else {
669 self.active.set(true);
670 self.continuous.set(true);
671
672 // adc sequencer configuration
673 // MUXNEG.val(0x7) -> ground pad
674 let mut cfg = SequencerConfig::MUXNEG.val(0x7)
675 + SequencerConfig::MUXPOS.val(channel.chan_num)
676 + SequencerConfig::INTERNAL.val(0x2 | channel.internal)
677 + SequencerConfig::RES::Bits12
678 + SequencerConfig::GCOMP::Disable
679 + SequencerConfig::GAIN::Gain0p5x
680 + SequencerConfig::BIPOLAR::Disable
681 + SequencerConfig::HWLA::Enable;
682 // set trigger based on how good our clock is
683 if self.cpu_clock.get() {
684 cfg += SequencerConfig::TRGSEL::InternalAdcTimer;
685 } else {
686 cfg += SequencerConfig::TRGSEL::ContinuousMode;
687 }
688 self.registers.seqcfg.write(cfg);
689
690 // stop timer if running
691 self.registers.cr.write(Control::TSTOP::SET);
692
693 if self.cpu_clock.get() {
694 // This logic only applies for sampling off the CPU
695 // setup timer for low-frequency samples. Based on the ADC clock,
696 // the minimum timer frequency is:
697 // 1500000 / (0xFFFF + 1) = 22.888 Hz.
698 // So for any frequency less than 23 Hz, we will keep our own
699 // counter in addition and only actually perform a callback every N
700 // timer fires. This is important to enable low-jitter sampling in
701 // the 1-22 Hz range.
702 let timer_frequency = if frequency < 23 {
703 // set a number of timer repeats before the callback is
704 // performed. 60 here is an arbitrary number which limits the
705 // actual itimer frequency to between 42 and 60 in the desired
706 // range of 1-22 Hz, which seems slow enough to keep the system
707 // from getting bogged down with interrupts
708 let counts = 60 / frequency;
709 self.timer_repeats.set(counts as u8);
710 self.timer_counts.set(0);
711 frequency * counts
712 } else {
713 // we can sample at this frequency directly with the timer
714 self.timer_repeats.set(0);
715 self.timer_counts.set(0);
716 frequency
717 };
718
719 // set timer, limit to bounds
720 // f(timer) = f(adc) / (counter + 1)
721 let mut counter = (self.adc_clk_freq.get() / timer_frequency) - 1;
722 counter = counter.clamp(0, 0xFFFF);
723 self.registers
724 .itimer
725 .write(InternalTimer::ITMC.val(counter));
726 } else {
727 // we can sample at this frequency directly with the timer
728 self.timer_repeats.set(0);
729 self.timer_counts.set(0);
730 }
731
732 // clear any current status
733 self.clear_status();
734
735 // enable end of conversion interrupt
736 self.registers.ier.write(Interrupt::SEOC::SET);
737
738 // start timer
739 self.registers.cr.write(Control::TSTART::SET);
740
741 Ok(())
742 }
743 }
744
745 /// Stop continuously sampling the ADC.
746 /// This is expected to be called to stop continuous sampling operations,
747 /// but can be called to abort any currently running operation. The buffer,
748 /// if any, will be returned via the `samples_ready` callback.
749 fn stop_sampling(&self) -> Result<(), ErrorCode> {
750 if !self.enabled.get() {
751 Err(ErrorCode::OFF)
752 } else if !self.active.get() {
753 // cannot cancel sampling that isn't running
754 Err(ErrorCode::INVAL)
755 } else {
756 // clean up state
757 self.active.set(false);
758 self.continuous.set(false);
759 self.dma_running.set(false);
760
761 // stop internal timer
762 self.registers.cr.write(Control::TSTOP::SET);
763
764 // disable sample interrupts
765 self.registers.idr.write(Interrupt::SEOC::SET);
766
767 // reset the ADC peripheral
768 self.registers.cr.write(Control::SWRST::SET);
769
770 // disable the ADC
771 self.disable();
772
773 // stop DMA transfer if going. This should safely return a None if
774 // the DMA was not being used
775 let dma_buffer = self.rx_dma.map_or(None, |rx_dma| {
776 let dma_buf = rx_dma.abort_transfer();
777 rx_dma.disable();
778 dma_buf
779 });
780 self.rx_length.set(0);
781
782 // store the buffer if it exists
783 dma_buffer.map(|dma_buf| {
784 // change buffer back into a [u16]
785 // the buffer was originally a [u16] so this should be okay
786 let buf_ptr = unsafe { mem::transmute::<*mut u8, *mut u16>(dma_buf.as_mut_ptr()) };
787 let buf = unsafe { slice::from_raw_parts_mut(buf_ptr, dma_buf.len() / 2) };
788
789 // we'll place it here so we can return it to the higher level
790 // later in a `retrieve_buffers` call
791 self.stopped_buffer.replace(buf);
792 });
793
794 Ok(())
795 }
796 }
797
798 /// Resolution of the reading.
799 fn get_resolution_bits(&self) -> usize {
800 12
801 }
802
803 /// Voltage reference is VCC/2, we assume VCC is 3.3 V, and we use a gain
804 /// of 0.5.
805 fn get_voltage_reference_mv(&self) -> Option<usize> {
806 Some(3300)
807 }
808
809 /// Sets the client for this driver.
810 ///
811 /// - `client`: reference to capsule which handles responses
812 fn set_client(&self, client: &'a dyn hil::adc::Client) {
813 self.client.set(client);
814 }
815}
816
817/// Implements an ADC capable of continuous sampling
818impl<'a> hil::adc::AdcHighSpeed<'a> for Adc<'a> {
819 /// Capture buffered samples from the ADC continuously at a given
820 /// frequency, calling the client whenever a buffer fills up. The client is
821 /// then expected to either stop sampling or provide an additional buffer
822 /// to sample into. Note that due to hardware constraints the maximum
823 /// frequency range of the ADC is from 187 kHz to 23 Hz (although its
824 /// precision is limited at higher frequencies due to aliasing).
825 ///
826 /// - `channel`: the ADC channel to sample
827 /// - `frequency`: frequency to sample at
828 /// - `buffer1`: first buffer to fill with samples
829 /// - `length1`: number of samples to collect (up to buffer length)
830 /// - `buffer2`: second buffer to fill once the first is full
831 /// - `length2`: number of samples to collect (up to buffer length)
832 fn sample_highspeed(
833 &self,
834 channel: &Self::Channel,
835 frequency: u32,
836 buffer1: &'static mut [u16],
837 length1: usize,
838 buffer2: &'static mut [u16],
839 length2: usize,
840 ) -> Result<(), (ErrorCode, &'static mut [u16], &'static mut [u16])> {
841 let res = self.config_and_enable(frequency);
842
843 if res != Ok(()) {
844 Err((res.unwrap_err(), buffer1, buffer2))
845 } else if !self.enabled.get() {
846 Err((ErrorCode::OFF, buffer1, buffer2))
847 } else if self.active.get() {
848 // only one sample at a time
849 Err((ErrorCode::BUSY, buffer1, buffer2))
850 } else if frequency <= (self.adc_clk_freq.get() / (0xFFFF + 1)) || frequency > 250000 {
851 // can't sample faster than the max sampling frequency or slower
852 // than the timer can be set to
853 Err((ErrorCode::INVAL, buffer1, buffer2))
854 } else if length1 == 0 {
855 // at least need a valid length for the for the first buffer full of
856 // samples. Otherwise, what are we doing here?
857 Err((ErrorCode::INVAL, buffer1, buffer2))
858 } else {
859 self.active.set(true);
860 self.continuous.set(true);
861
862 // store the second buffer for later use
863 self.next_dma_buffer.replace(buffer2);
864 self.next_dma_length.set(length2);
865
866 // adc sequencer configuration
867 // MUXNEG.val(0x7) -> ground pad
868 let mut cfg = SequencerConfig::MUXNEG.val(0x7)
869 + SequencerConfig::MUXPOS.val(channel.chan_num)
870 + SequencerConfig::INTERNAL.val(0x2 | channel.internal)
871 + SequencerConfig::RES::Bits12
872 + SequencerConfig::GCOMP::Disable
873 + SequencerConfig::GAIN::Gain0p5x
874 + SequencerConfig::BIPOLAR::Disable
875 + SequencerConfig::HWLA::Enable;
876 // set trigger based on how good our clock is
877 if self.cpu_clock.get() {
878 cfg += SequencerConfig::TRGSEL::InternalAdcTimer;
879 } else {
880 cfg += SequencerConfig::TRGSEL::ContinuousMode;
881 }
882 self.registers.seqcfg.write(cfg);
883
884 // stop timer if running
885 self.registers.cr.write(Control::TSTOP::SET);
886
887 if self.cpu_clock.get() {
888 // set timer, limit to bounds
889 // f(timer) = f(adc) / (counter + 1)
890 let mut counter = (self.adc_clk_freq.get() / frequency) - 1;
891 counter = counter.clamp(0, 0xFFFF);
892 self.registers
893 .itimer
894 .write(InternalTimer::ITMC.val(counter));
895 }
896
897 // clear any current status
898 self.clear_status();
899
900 // receive up to the buffer's length samples
901 let dma_len = cmp::min(buffer1.len(), length1);
902
903 // change buffer into a [u8]
904 // this is unsafe but acceptable for the following reasons
905 // * the buffer is aligned based on 16-bit boundary, so the 8-bit
906 // alignment is fine
907 // * the DMA is doing checking based on our expected data width to
908 // make sure we don't go past dma_buf.len()/width
909 // * we will transmute the array back to a [u16] after the DMA
910 // transfer is complete
911 let dma_buf_ptr = unsafe { mem::transmute::<*mut u16, *mut u8>(buffer1.as_mut_ptr()) };
912 let dma_buf = unsafe { slice::from_raw_parts_mut(dma_buf_ptr, buffer1.len() * 2) };
913
914 // set up the DMA
915 self.rx_dma.map(move |dma| {
916 self.dma_running.set(true);
917 dma.enable();
918 self.rx_length.set(dma_len);
919 dma.do_transfer(self.rx_dma_peripheral, dma_buf, dma_len);
920 });
921
922 // start timer
923 self.registers.cr.write(Control::TSTART::SET);
924
925 Ok(())
926 }
927 }
928
929 /// Provide a new buffer to send on-going buffered continuous samples to.
930 /// This is expected to be called after the `samples_ready` callback.
931 ///
932 /// - `buf`: buffer to fill with samples
933 /// - `length`: number of samples to collect (up to buffer length)
934 fn provide_buffer(
935 &self,
936 buf: &'static mut [u16],
937 length: usize,
938 ) -> Result<(), (ErrorCode, &'static mut [u16])> {
939 if !self.enabled.get() {
940 Err((ErrorCode::OFF, buf))
941 } else if !self.active.get() {
942 // cannot continue sampling that isn't running
943 Err((ErrorCode::INVAL, buf))
944 } else if !self.continuous.get() {
945 // cannot continue a single sample operation
946 Err((ErrorCode::INVAL, buf))
947 } else if self.next_dma_buffer.is_some() {
948 // we've already got a second buffer, we don't need a third yet
949 Err((ErrorCode::BUSY, buf))
950 } else {
951 // store the buffer for later use
952 self.next_dma_buffer.replace(buf);
953 self.next_dma_length.set(length);
954
955 Ok(())
956 }
957 }
958
959 /// Reclaim buffers after the ADC is stopped.
960 /// This is expected to be called after `stop_sampling`.
961 fn retrieve_buffers(
962 &self,
963 ) -> Result<(Option<&'static mut [u16]>, Option<&'static mut [u16]>), ErrorCode> {
964 if self.active.get() {
965 // cannot return buffers while running
966 Err(ErrorCode::INVAL)
967 } else {
968 // we're not running, so give back whatever we've got
969 Ok((self.next_dma_buffer.take(), self.stopped_buffer.take()))
970 }
971 }
972
973 fn set_highspeed_client(&self, client: &'a dyn hil::adc::HighSpeedClient) {
974 self.highspeed_client.set(client);
975 }
976}
977
978/// Implements a client of a DMA.
979impl dma::DMAClient for Adc<'_> {
980 /// Handler for DMA transfer completion.
981 ///
982 /// - `pid`: the DMA peripheral that is complete
983 fn transfer_done(&self, pid: dma::DMAPeripheral) {
984 // check if this was an RX transfer
985 if pid == self.rx_dma_peripheral {
986 // RX transfer was completed
987
988 // get buffer filled with samples from DMA
989 let dma_buffer = self.rx_dma.map_or(None, |rx_dma| {
990 self.dma_running.set(false);
991 let dma_buf = rx_dma.abort_transfer();
992 rx_dma.disable();
993 dma_buf
994 });
995
996 // get length of received buffer
997 let length = self.rx_length.get();
998
999 // start a new transfer with the next buffer
1000 // we need to do this quickly in order to keep from missing samples.
1001 // At 175000 Hz, we only have 5.8 us (~274 cycles) to do so
1002 self.next_dma_buffer.take().map(|buf| {
1003 // first determine the buffer's length in samples
1004 let dma_len = cmp::min(buf.len(), self.next_dma_length.get());
1005
1006 // only continue with a nonzero length. If we were given a
1007 // zero-length buffer or length field, assume that the user knew
1008 // what was going on, and just don't use the buffer
1009 if dma_len > 0 {
1010 // change buffer into a [u8]
1011 // this is unsafe but acceptable for the following reasons
1012 // * the buffer is aligned based on 16-bit boundary, so the
1013 // 8-bit alignment is fine
1014 // * the DMA is doing checking based on our expected data
1015 // width to make sure we don't go past
1016 // dma_buf.len()/width
1017 // * we will transmute the array back to a [u16] after the
1018 // DMA transfer is complete
1019 let dma_buf_ptr =
1020 unsafe { mem::transmute::<*mut u16, *mut u8>(buf.as_mut_ptr()) };
1021 let dma_buf = unsafe { slice::from_raw_parts_mut(dma_buf_ptr, buf.len() * 2) };
1022
1023 // set up the DMA
1024 self.rx_dma.map(move |dma| {
1025 self.dma_running.set(true);
1026 dma.enable();
1027 self.rx_length.set(dma_len);
1028 dma.do_transfer(self.rx_dma_peripheral, dma_buf, dma_len);
1029 });
1030 } else {
1031 // if length was zero, just keep the buffer in the takecell
1032 // so we can return it when `stop_sampling` is called
1033 self.next_dma_buffer.replace(buf);
1034 }
1035 });
1036
1037 // alert client
1038 self.highspeed_client.map(|client| {
1039 dma_buffer.map(|dma_buf| {
1040 // change buffer back into a [u16]
1041 // the buffer was originally a [u16] so this should be okay
1042 let buf_ptr =
1043 unsafe { mem::transmute::<*mut u8, *mut u16>(dma_buf.as_mut_ptr()) };
1044 let buf = unsafe { slice::from_raw_parts_mut(buf_ptr, dma_buf.len() / 2) };
1045
1046 // pass the buffer up to the next layer. It will then either
1047 // send down another buffer to continue sampling, or stop
1048 // sampling
1049 client.samples_ready(buf, length);
1050 });
1051 });
1052 }
1053 }
1054}