Skip to content

Commit

Permalink
Implement calibrated ADC API for S3 (#641)
Browse files Browse the repository at this point in the history
* adc_cal: s3: Add efuse functions for reading calibration

* Add changelog entry

* Implement calibrated ADC API for S3

* adc_cal: s3: Add calibrated ADC reading example

* Clean up

* Prefer where clauses

* Clean up unnecessary unsafe blocks

* Fix autolinks

---------

Co-authored-by: Scott Mabin <scott@mabez.dev>
  • Loading branch information
bugadani and MabezDev committed Jul 24, 2023
1 parent 10ec264 commit 2472b6d
Show file tree
Hide file tree
Showing 13 changed files with 850 additions and 282 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add initial LP-IO support for ESP32-C6 (#639)
- Implement sleep with some wakeup methods for `esp32` (#574)
- Add a new RMT driver (#653, #667)
- Implemented calibrated ADC API for ESP32-S3 (#641)
- Add MCPWM DeadTime configuration (#406)

### Changed
Expand Down
11 changes: 9 additions & 2 deletions esp-hal-common/src/analog/adc/cal_basic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use core::marker::PhantomData;

use crate::adc::{AdcCalEfuse, AdcCalScheme, AdcCalSource, AdcConfig, Attenuation, RegisterAccess};
use crate::adc::{
AdcCalEfuse,
AdcCalScheme,
AdcCalSource,
AdcConfig,
Attenuation,
CalibrationAccess,
};

/// Basic ADC calibration scheme
///
Expand All @@ -18,7 +25,7 @@ pub struct AdcCalBasic<ADCI> {

impl<ADCI> AdcCalScheme<ADCI> for AdcCalBasic<ADCI>
where
ADCI: AdcCalEfuse + RegisterAccess,
ADCI: AdcCalEfuse + CalibrationAccess,
{
fn new_cal(atten: Attenuation) -> Self {
// Try to get init code (Dout0) from efuse
Expand Down
4 changes: 2 additions & 2 deletions esp-hal-common/src/analog/adc/cal_curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::adc::{
AdcCalScheme,
AdcHasLineCal,
Attenuation,
RegisterAccess,
CalibrationAccess,
};

const COEFF_MUL: i64 = 1 << 52;
Expand Down Expand Up @@ -52,7 +52,7 @@ pub struct AdcCalCurve<ADCI> {

impl<ADCI> AdcCalScheme<ADCI> for AdcCalCurve<ADCI>
where
ADCI: AdcCalEfuse + AdcHasLineCal + AdcHasCurveCal + RegisterAccess,
ADCI: AdcCalEfuse + AdcHasLineCal + AdcHasCurveCal + CalibrationAccess,
{
fn new_cal(atten: Attenuation) -> Self {
let line = AdcCalLine::<ADCI>::new_cal(atten);
Expand Down
8 changes: 4 additions & 4 deletions esp-hal-common/src/analog/adc/cal_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::adc::{
AdcCalSource,
AdcConfig,
Attenuation,
RegisterAccess,
CalibrationAccess,
};

/// Marker trait for ADC units which support line fitting
Expand Down Expand Up @@ -46,7 +46,7 @@ pub struct AdcCalLine<ADCI> {

impl<ADCI> AdcCalScheme<ADCI> for AdcCalLine<ADCI>
where
ADCI: AdcCalEfuse + AdcHasLineCal + RegisterAccess,
ADCI: AdcCalEfuse + AdcHasLineCal + CalibrationAccess,
{
fn new_cal(atten: Attenuation) -> Self {
let basic = AdcCalBasic::<ADCI>::new_cal(atten);
Expand Down Expand Up @@ -93,8 +93,8 @@ where
}
}

#[cfg(any(esp32c2, esp32c3, esp32c6))]
#[cfg(any(esp32c2, esp32c3, esp32c6, esp32s3))]
impl AdcHasLineCal for crate::adc::ADC1 {}

#[cfg(esp32c3)]
#[cfg(any(esp32c3, esp32s3))]
impl AdcHasLineCal for crate::adc::ADC2 {}
141 changes: 85 additions & 56 deletions esp-hal-common/src/analog/adc/riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ cfg_if::cfg_if! {

const ADC_VAL_MASK: u16 = 0xfff;
const ADC_CAL_CNT_MAX: u16 = 32;
const ADC_CAL_CHANNEL: u32 = 0xf;
const ADC_CAL_CHANNEL: u16 = 15;

const ADC_SAR1_ENCAL_GND_ADDR: u8 = 0x7;
const ADC_SAR1_ENCAL_GND_ADDR_MSB: u8 = 5;
Expand Down Expand Up @@ -166,7 +166,10 @@ pub struct AdcPin<PIN, ADCI, CS = ()> {
_phantom: PhantomData<ADCI>,
}

impl<PIN: Channel<ADCI, ID = u8>, ADCI, CS> Channel<ADCI> for AdcPin<PIN, ADCI, CS> {
impl<PIN, ADCI, CS> Channel<ADCI> for AdcPin<PIN, ADCI, CS>
where
PIN: Channel<ADCI, ID = u8>,
{
type ID = u8;

fn channel() -> Self::ID {
Expand All @@ -188,11 +191,10 @@ where
Self::default()
}

pub fn enable_pin<PIN: Channel<ADCI, ID = u8>>(
&mut self,
pin: PIN,
attenuation: Attenuation,
) -> AdcPin<PIN, ADCI, ()> {
pub fn enable_pin<PIN>(&mut self, pin: PIN, attenuation: Attenuation) -> AdcPin<PIN, ADCI>
where
PIN: Channel<ADCI, ID = u8>,
{
self.attenuations[PIN::channel() as usize] = Some(attenuation);

AdcPin {
Expand All @@ -202,11 +204,16 @@ where
}
}

pub fn enable_pin_with_cal<PIN: Channel<ADCI, ID = u8>, CS: AdcCalScheme<ADCI>>(
pub fn enable_pin_with_cal<PIN, CS>(
&mut self,
pin: PIN,
attenuation: Attenuation,
) -> AdcPin<PIN, ADCI, CS> {
) -> AdcPin<PIN, ADCI, CS>
where
ADCI: CalibrationAccess,
PIN: Channel<ADCI, ID = u8>,
CS: AdcCalScheme<ADCI>,
{
self.attenuations[PIN::channel() as usize] = Some(attenuation);

AdcPin {
Expand All @@ -217,7 +224,10 @@ where
}

/// Calibrate ADC with specified attenuation and voltage source
pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16 {
pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
where
ADCI: CalibrationAccess,
{
let mut adc_max: u16 = 0;
let mut adc_min: u16 = u16::MAX;
let mut adc_sum: u32 = 0;
Expand Down Expand Up @@ -290,13 +300,19 @@ pub trait RegisterAccess {
/// Reset flags
fn reset();

/// Set calibration parameter to ADC hardware
fn set_init_code(data: u16);
}

pub trait CalibrationAccess: RegisterAccess {
const ADC_CAL_CNT_MAX: u16;
const ADC_CAL_CHANNEL: u16;
const ADC_VAL_MASK: u16;

fn enable_vdef(enable: bool);

/// Enable internal connect GND (for calibration)
/// Enable internal calibration voltage source
fn connect_cal(source: AdcCalSource, enable: bool);

/// Set calibration parameter to ADC hardware
fn set_init_code(data: u16);
}

impl RegisterAccess for ADC1 {
Expand Down Expand Up @@ -347,6 +363,33 @@ impl RegisterAccess for ADC1 {
.modify(|_, w| w.saradc_onetime_start().clear_bit());
}

fn set_init_code(data: u16) {
let [msb, lsb] = data.to_be_bytes();

regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR1_INITIAL_CODE_HIGH_ADDR,
ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB,
ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB,
msb as _,
);
regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR1_INITIAL_CODE_LOW_ADDR,
ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB,
ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB,
lsb as _,
);
}
}

impl CalibrationAccess for ADC1 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
const ADC_VAL_MASK: u16 = ADC_VAL_MASK;

fn enable_vdef(enable: bool) {
let value = enable as _;
regi2c_write_mask(
Expand Down Expand Up @@ -380,27 +423,6 @@ impl RegisterAccess for ADC1 {
),
}
}

fn set_init_code(data: u16) {
let [msb, lsb] = data.to_be_bytes();

regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR1_INITIAL_CODE_HIGH_ADDR,
ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB,
ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB,
msb as _,
);
regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR1_INITIAL_CODE_LOW_ADDR,
ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB,
ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB,
lsb as _,
);
}
}

#[cfg(esp32c3)]
Expand Down Expand Up @@ -450,6 +472,34 @@ impl RegisterAccess for ADC2 {
.modify(|_, w| w.saradc_onetime_start().clear_bit());
}

fn set_init_code(data: u16) {
let [msb, lsb] = data.to_be_bytes();

regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR2_INITIAL_CODE_HIGH_ADDR,
ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB,
ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB,
msb as _,
);
regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR2_INITIAL_CODE_LOW_ADDR,
ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB,
ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB,
lsb as _,
);
}
}

#[cfg(esp32c3)]
impl CalibrationAccess for ADC2 {
const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
const ADC_VAL_MASK: u16 = ADC_VAL_MASK;

fn enable_vdef(enable: bool) {
let value = enable as _;
regi2c_write_mask(
Expand Down Expand Up @@ -483,27 +533,6 @@ impl RegisterAccess for ADC2 {
),
}
}

fn set_init_code(data: u16) {
let [msb, lsb] = data.to_be_bytes();

regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR2_INITIAL_CODE_HIGH_ADDR,
ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB,
ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB,
msb as _,
);
regi2c_write_mask(
I2C_SAR_ADC,
I2C_SAR_ADC_HOSTID,
ADC_SAR2_INITIAL_CODE_LOW_ADDR,
ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB,
ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB,
lsb as _,
);
}
}

pub struct ADC<'d, ADCI> {
Expand Down
Loading

0 comments on commit 2472b6d

Please sign in to comment.