mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-30 05:40:39 +00:00
Add mechanism to configure UART source clock (#1416)
* Creating mechanism for setting UART source clock * Format + examples updating * Changelog entry * Smaller fixes (reviews) * Move RC_FAST_CLK constant to soc * Fix REF_TICK value * Add doc comments update doc comments * fmt
This commit is contained in:
parent
111dcda103
commit
6f91367d6c
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Inherent implementions of GPIO pin `set_low`, `is_low`, etc.
|
||||
- Warn users when attempting to build using the `dev` profile (#1420)
|
||||
- Async uart now reports interrupt errors(overflow, glitch, frame error, parity) back to user of read/write. uart clock decimal part configured for c2,c3,s3 (#1168, #1445)
|
||||
- Add mechanism to configure UART source clock (#1416)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -28,6 +28,8 @@ pub(crate) mod constants {
|
||||
|
||||
pub const SOC_DRAM_LOW: u32 = 0x3FFA_E000;
|
||||
pub const SOC_DRAM_HIGH: u32 = 0x4000_0000;
|
||||
|
||||
pub const REF_TICK: fugit::HertzU32 = fugit::HertzU32::MHz(1);
|
||||
}
|
||||
|
||||
/// Function initializes ESP32 specific memories (RTC slow and fast) and
|
||||
|
@ -22,6 +22,8 @@ pub(crate) mod registers {
|
||||
pub(crate) mod constants {
|
||||
pub const SOC_DRAM_LOW: u32 = 0x3FCA_0000;
|
||||
pub const SOC_DRAM_HIGH: u32 = 0x3FCE_0000;
|
||||
|
||||
pub const RC_FAST_CLK: fugit::HertzU32 = fugit::HertzU32::kHz(17500);
|
||||
}
|
||||
|
||||
#[export_name = "__post_init"]
|
||||
|
@ -34,6 +34,8 @@ pub(crate) mod constants {
|
||||
|
||||
pub const SOC_DRAM_LOW: u32 = 0x3FC8_0000;
|
||||
pub const SOC_DRAM_HIGH: u32 = 0x3FCE_0000;
|
||||
|
||||
pub const RC_FAST_CLK: fugit::HertzU32 = fugit::HertzU32::kHz(17500);
|
||||
}
|
||||
|
||||
#[export_name = "__post_init"]
|
||||
|
@ -40,6 +40,8 @@ pub(crate) mod constants {
|
||||
|
||||
pub const SOC_DRAM_LOW: u32 = 0x4080_0000;
|
||||
pub const SOC_DRAM_HIGH: u32 = 0x4088_0000;
|
||||
|
||||
pub const RC_FAST_CLK: fugit::HertzU32 = fugit::HertzU32::kHz(17500);
|
||||
}
|
||||
|
||||
#[export_name = "__post_init"]
|
||||
|
@ -39,6 +39,8 @@ pub(crate) mod constants {
|
||||
|
||||
pub const SOC_DRAM_LOW: u32 = 0x4080_0000;
|
||||
pub const SOC_DRAM_HIGH: u32 = 0x4085_0000;
|
||||
|
||||
pub const RC_FAST_CLK: fugit::HertzU32 = fugit::HertzU32::kHz(17500);
|
||||
}
|
||||
|
||||
#[export_name = "__post_init"]
|
||||
|
@ -32,6 +32,8 @@ pub(crate) mod constants {
|
||||
|
||||
pub const SOC_DRAM_LOW: u32 = 0x3FFB_0000;
|
||||
pub const SOC_DRAM_HIGH: u32 = 0x4000_0000;
|
||||
|
||||
pub const REF_TICK: fugit::HertzU32 = fugit::HertzU32::MHz(1);
|
||||
}
|
||||
|
||||
/// Function initializes ESP32 specific memories (RTC slow and fast) and
|
||||
|
@ -35,6 +35,8 @@ pub(crate) mod constants {
|
||||
|
||||
pub const SOC_DRAM_LOW: u32 = 0x3FC8_8000;
|
||||
pub const SOC_DRAM_HIGH: u32 = 0x3FD0_0000;
|
||||
|
||||
pub const RC_FAST_CLK: fugit::HertzU32 = fugit::HertzU32::kHz(17500);
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
|
@ -19,20 +19,14 @@
|
||||
//! specified.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! let config = Config {
|
||||
//! baudrate: 115_200,
|
||||
//! data_bits: DataBits::DataBits8,
|
||||
//! parity: Parity::ParityNone,
|
||||
//! stop_bits: StopBits::STOP1,
|
||||
//! };
|
||||
//!
|
||||
//! let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
//! let pins = TxRxPins::new_tx_rx(
|
||||
//! io.pins.gpio1.into_push_pull_output(),
|
||||
//! io.pins.gpio2.into_floating_input(),
|
||||
//! );
|
||||
//!
|
||||
//! let mut uart1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks);
|
||||
//! let mut uart1 =
|
||||
//! Uart::new_with_config(peripherals.UART1, Config::default(), Some(pins), &clocks);
|
||||
//! ```
|
||||
//!
|
||||
//! ## Usage
|
||||
@ -92,6 +86,11 @@ use crate::{
|
||||
const CONSOLE_UART_NUM: usize = 0;
|
||||
const UART_FIFO_SIZE: u16 = 128;
|
||||
|
||||
#[cfg(not(any(esp32, esp32s2)))]
|
||||
use crate::soc::constants::RC_FAST_CLK;
|
||||
#[cfg(any(esp32, esp32s2))]
|
||||
use crate::soc::constants::REF_TICK;
|
||||
|
||||
/// UART Error
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
@ -123,6 +122,26 @@ impl embedded_io::Error for Error {
|
||||
}
|
||||
}
|
||||
|
||||
// (outside of `config` module in order not to "use" it an extra time)
|
||||
/// UART clock source
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum ClockSource {
|
||||
/// APB_CLK clock source (default for UART on all the chips except of
|
||||
/// esp32c6 and esp32h2)
|
||||
Apb,
|
||||
#[cfg(not(any(esp32, esp32s2)))]
|
||||
/// RC_FAST_CLK clock source (17.5 MHz)
|
||||
RcFast,
|
||||
#[cfg(not(any(esp32, esp32s2)))]
|
||||
/// XTAL_CLK clock source (default for UART on esp32c6 and esp32h2 and
|
||||
/// LP_UART)
|
||||
Xtal,
|
||||
#[cfg(any(esp32, esp32s2))]
|
||||
/// REF_TICK clock source (derived from XTAL or RC_FAST, 1MHz)
|
||||
RefTick,
|
||||
}
|
||||
|
||||
/// UART Configuration
|
||||
pub mod config {
|
||||
/// Number of data bits
|
||||
@ -164,6 +183,7 @@ pub mod config {
|
||||
pub data_bits: DataBits,
|
||||
pub parity: Parity,
|
||||
pub stop_bits: StopBits,
|
||||
pub clock_source: super::ClockSource,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@ -197,6 +217,11 @@ pub mod config {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clock_source(mut self, source: super::ClockSource) -> Self {
|
||||
self.clock_source = source;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn symbol_length(&self) -> u8 {
|
||||
let mut length: u8 = 1; // start bit
|
||||
length += match self.data_bits {
|
||||
@ -224,6 +249,10 @@ pub mod config {
|
||||
data_bits: DataBits::DataBits8,
|
||||
parity: Parity::ParityNone,
|
||||
stop_bits: StopBits::STOP1,
|
||||
#[cfg(any(esp32c6, esp32h2, lp_uart))]
|
||||
clock_source: super::ClockSource::Xtal,
|
||||
#[cfg(not(any(esp32c6, esp32h2, lp_uart)))]
|
||||
clock_source: super::ClockSource::Apb,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -538,7 +567,7 @@ where
|
||||
symbol_len: config.symbol_length(),
|
||||
};
|
||||
|
||||
serial.change_baud_internal(config.baudrate, clocks);
|
||||
serial.change_baud_internal(config.baudrate, config.clock_source, clocks);
|
||||
serial.change_data_bits(config.data_bits);
|
||||
serial.change_parity(config.parity);
|
||||
serial.change_stop_bits(config.stop_bits);
|
||||
@ -869,15 +898,22 @@ where
|
||||
}
|
||||
|
||||
#[cfg(any(esp32c2, esp32c3, esp32s3))]
|
||||
fn change_baud_internal(&self, baudrate: u32, clocks: &Clocks) {
|
||||
// we force the clock source to be APB and don't use the decimal part of the
|
||||
// divider
|
||||
let clk = clocks.apb_clock.to_Hz();
|
||||
let max_div = 0b1111_1111_1111; // 12 bit clkdiv
|
||||
fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) {
|
||||
let clk = match clock_source {
|
||||
ClockSource::Apb => clocks.apb_clock.to_Hz(),
|
||||
ClockSource::Xtal => clocks.xtal_clock.to_Hz(),
|
||||
ClockSource::RcFast => RC_FAST_CLK.to_Hz(),
|
||||
};
|
||||
|
||||
let max_div = 0b1111_1111_1111 - 1;
|
||||
let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate);
|
||||
T::register_block().clk_conf().write(|w| unsafe {
|
||||
w.sclk_sel()
|
||||
.bits(1) // APB
|
||||
.bits(match clock_source {
|
||||
ClockSource::Apb => 1,
|
||||
ClockSource::RcFast => 2,
|
||||
ClockSource::Xtal => 3,
|
||||
})
|
||||
.sclk_div_a()
|
||||
.bits(0)
|
||||
.sclk_div_b()
|
||||
@ -899,10 +935,13 @@ where
|
||||
}
|
||||
|
||||
#[cfg(any(esp32c6, esp32h2))]
|
||||
fn change_baud_internal(&self, baudrate: u32, clocks: &Clocks) {
|
||||
// we force the clock source to be XTAL and don't use the decimal part of
|
||||
// the divider
|
||||
let clk = clocks.xtal_clock.to_Hz();
|
||||
fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) {
|
||||
let clk = match clock_source {
|
||||
ClockSource::Apb => clocks.apb_clock.to_Hz(),
|
||||
ClockSource::Xtal => clocks.xtal_clock.to_Hz(),
|
||||
ClockSource::RcFast => RC_FAST_CLK.to_Hz(),
|
||||
};
|
||||
|
||||
let max_div = 0b1111_1111_1111 - 1;
|
||||
let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate);
|
||||
|
||||
@ -922,7 +961,11 @@ where
|
||||
.uart0_sclk_div_num()
|
||||
.bits(clk_div as u8 - 1)
|
||||
.uart0_sclk_sel()
|
||||
.bits(0x3) // TODO: this probably shouldn't be hard-coded
|
||||
.bits(match clock_source {
|
||||
ClockSource::Apb => 1,
|
||||
ClockSource::RcFast => 2,
|
||||
ClockSource::Xtal => 3,
|
||||
})
|
||||
.uart0_sclk_en()
|
||||
.set_bit()
|
||||
});
|
||||
@ -959,14 +1002,20 @@ where
|
||||
}
|
||||
|
||||
#[cfg(any(esp32, esp32s2))]
|
||||
fn change_baud_internal(&self, baudrate: u32, clocks: &Clocks) {
|
||||
// we force the clock source to be APB and don't use the decimal part of the
|
||||
// divider
|
||||
let clk = clocks.apb_clock.to_Hz();
|
||||
fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) {
|
||||
let clk = match clock_source {
|
||||
ClockSource::Apb => clocks.apb_clock.to_Hz(),
|
||||
ClockSource::RefTick => REF_TICK.to_Hz(), /* ESP32(/-S2) TRM, section 3.2.4.2
|
||||
* (6.2.4.2 for S2) */
|
||||
};
|
||||
|
||||
T::register_block().conf0().modify(|_, w| {
|
||||
w.tick_ref_always_on().bit(match clock_source {
|
||||
ClockSource::Apb => true,
|
||||
ClockSource::RefTick => false,
|
||||
})
|
||||
});
|
||||
|
||||
T::register_block()
|
||||
.conf0()
|
||||
.modify(|_, w| w.tick_ref_always_on().bit(true));
|
||||
let divider = clk / baudrate;
|
||||
|
||||
T::register_block()
|
||||
@ -992,8 +1041,8 @@ where
|
||||
}
|
||||
|
||||
/// Modify UART baud rate and reset TX/RX fifo.
|
||||
pub fn change_baud(&mut self, baudrate: u32, clocks: &Clocks) {
|
||||
self.change_baud_internal(baudrate, clocks);
|
||||
pub fn change_baud(&mut self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) {
|
||||
self.change_baud_internal(baudrate, clock_source, clocks);
|
||||
self.txfifo_reset();
|
||||
self.rxfifo_reset();
|
||||
}
|
||||
@ -2130,7 +2179,7 @@ pub mod lp_uart {
|
||||
|
||||
// Override protocol parameters from the configuration
|
||||
// uart_hal_set_baudrate(&hal, cfg->uart_proto_cfg.baud_rate, sclk_freq);
|
||||
me.change_baud_internal(config.baudrate);
|
||||
me.change_baud_internal(config.baudrate, config.clock_source);
|
||||
// uart_hal_set_parity(&hal, cfg->uart_proto_cfg.parity);
|
||||
me.change_parity(config.parity);
|
||||
// uart_hal_set_data_bit_num(&hal, cfg->uart_proto_cfg.data_bits);
|
||||
@ -2172,9 +2221,8 @@ pub mod lp_uart {
|
||||
}
|
||||
}
|
||||
|
||||
fn change_baud_internal(&mut self, baudrate: u32) {
|
||||
// we force the clock source to be XTAL and don't use the decimal part of
|
||||
// the divider
|
||||
fn change_baud_internal(&mut self, baudrate: u32, clock_source: super::ClockSource) {
|
||||
// TODO: Currently it's not possible to use XtalD2Clk
|
||||
let clk = 16_000_000;
|
||||
let max_div = 0b1111_1111_1111 - 1;
|
||||
let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate);
|
||||
@ -2187,7 +2235,11 @@ pub mod lp_uart {
|
||||
.sclk_div_num()
|
||||
.bits(clk_div as u8 - 1)
|
||||
.sclk_sel()
|
||||
.bits(0x3) // TODO: this probably shouldn't be hard-coded
|
||||
.bits(match clock_source {
|
||||
super::ClockSource::Xtal => 3,
|
||||
super::ClockSource::RcFast => 2,
|
||||
super::ClockSource::Apb => panic!("Wrong clock source for LP_UART"),
|
||||
})
|
||||
.sclk_en()
|
||||
.set_bit()
|
||||
});
|
||||
@ -2204,8 +2256,8 @@ pub mod lp_uart {
|
||||
}
|
||||
|
||||
/// Modify UART baud rate and reset TX/RX fifo.
|
||||
pub fn change_baud(&mut self, baudrate: u32) {
|
||||
self.change_baud_internal(baudrate);
|
||||
pub fn change_baud(&mut self, baudrate: u32, clock_source: super::ClockSource) {
|
||||
self.change_baud_internal(baudrate, clock_source);
|
||||
self.txfifo_reset();
|
||||
self.rxfifo_reset();
|
||||
}
|
||||
|
@ -19,11 +19,7 @@ use esp_hal::{
|
||||
gpio::IO,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
uart::{
|
||||
config::{Config, DataBits, Parity, StopBits},
|
||||
TxRxPins,
|
||||
Uart,
|
||||
},
|
||||
uart::{config::Config, TxRxPins, Uart},
|
||||
};
|
||||
use esp_println::println;
|
||||
use nb::block;
|
||||
@ -34,20 +30,19 @@ fn main() -> ! {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let config = Config {
|
||||
baudrate: 115200,
|
||||
data_bits: DataBits::DataBits8,
|
||||
parity: Parity::ParityNone,
|
||||
stop_bits: StopBits::STOP1,
|
||||
};
|
||||
|
||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
let pins = TxRxPins::new_tx_rx(
|
||||
io.pins.gpio4.into_push_pull_output(),
|
||||
io.pins.gpio5.into_floating_input(),
|
||||
);
|
||||
|
||||
let mut serial1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks, None);
|
||||
let mut serial1 = Uart::new_with_config(
|
||||
peripherals.UART1,
|
||||
Config::default(),
|
||||
Some(pins),
|
||||
&clocks,
|
||||
None,
|
||||
);
|
||||
|
||||
let delay = Delay::new(&clocks);
|
||||
|
||||
|
@ -36,19 +36,18 @@ fn main() -> ! {
|
||||
|
||||
// Set up (HP) UART1:
|
||||
|
||||
let config = Config {
|
||||
baudrate: 115_200,
|
||||
data_bits: DataBits::DataBits8,
|
||||
parity: Parity::ParityNone,
|
||||
stop_bits: StopBits::STOP1,
|
||||
};
|
||||
|
||||
let pins = TxRxPins::new_tx_rx(
|
||||
io.pins.gpio6.into_push_pull_output(),
|
||||
io.pins.gpio7.into_floating_input(),
|
||||
);
|
||||
|
||||
let mut uart1 = Uart::new_with_config(peripherals.UART1, config, Some(pins), &clocks, None);
|
||||
let mut uart1 = Uart::new_with_config(
|
||||
peripherals.UART1,
|
||||
Config::default(),
|
||||
Some(pins),
|
||||
&clocks,
|
||||
None,
|
||||
);
|
||||
|
||||
// Set up (LP) UART:
|
||||
let lp_tx = io.pins.gpio5.into_low_power().into_push_pull_output();
|
||||
|
@ -17,11 +17,7 @@ use esp_hal::{
|
||||
gpio::IO,
|
||||
peripherals::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
uart::{
|
||||
config::{Config, DataBits, Parity, StopBits},
|
||||
TxRxPins,
|
||||
Uart,
|
||||
},
|
||||
uart::{config::Config, TxRxPins, Uart},
|
||||
Blocking,
|
||||
};
|
||||
use nb::block;
|
||||
@ -40,14 +36,8 @@ impl Context {
|
||||
io.pins.gpio2.into_push_pull_output(),
|
||||
io.pins.gpio4.into_floating_input(),
|
||||
);
|
||||
let config = Config {
|
||||
baudrate: 115200,
|
||||
data_bits: DataBits::DataBits8,
|
||||
parity: Parity::ParityNone,
|
||||
stop_bits: StopBits::STOP1,
|
||||
};
|
||||
|
||||
let uart = Uart::new_with_config(peripherals.UART0, config, Some(pins), &clocks, None);
|
||||
let uart = Uart::new_with_config(peripherals.UART0, Config::default(), Some(pins), &clocks, None);
|
||||
|
||||
Context { uart }
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use esp_hal::{
|
||||
peripherals::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
uart::{
|
||||
config::{Config, DataBits, Parity, StopBits},
|
||||
config::Config,
|
||||
TxRxPins,
|
||||
Uart,
|
||||
UartRx,
|
||||
@ -41,14 +41,8 @@ impl Context {
|
||||
io.pins.gpio2.into_push_pull_output(),
|
||||
io.pins.gpio4.into_floating_input(),
|
||||
);
|
||||
let config = Config {
|
||||
baudrate: 115200,
|
||||
data_bits: DataBits::DataBits8,
|
||||
parity: Parity::ParityNone,
|
||||
stop_bits: StopBits::STOP1,
|
||||
};
|
||||
|
||||
let uart = Uart::new_async_with_config(peripherals.UART0, config, Some(pins), &clocks);
|
||||
let uart = Uart::new_async_with_config(peripherals.UART0, Config::default(), Some(pins), &clocks);
|
||||
let (tx, rx) = uart.split();
|
||||
|
||||
Context { rx, tx }
|
||||
|
Loading…
x
Reference in New Issue
Block a user