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