Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement calibrated ADC API for S3 #641

Merged
merged 9 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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