From cdf2dd1c9137071132f4afb607a34d3beffa8eea Mon Sep 17 00:00:00 2001 From: "Y. Sapir" Date: Fri, 19 Jul 2019 03:06:12 +0300 Subject: [PATCH] Add wrappers for Uart0 and GPIO --- Cargo.toml | 3 ++ src/gpio.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ src/serial.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 src/gpio.rs create mode 100644 src/serial.rs diff --git a/Cargo.toml b/Cargo.toml index eddff0af3..2578833fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,6 @@ authors = ["Y. Sapir "] edition = "2018" [dependencies] +embedded-hal = { version = "0.2.3", features = ["unproven"] } +esp32-sys = { path = "../esp32-sys/esp32-sys" } +nb = "0.1.2" diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 000000000..63296df79 --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,81 @@ +use core::convert::TryInto; +use embedded_hal::digital::v2 as hal; +use esp32_sys::{ + gpio_input_get, gpio_input_get_high, gpio_mode_t_GPIO_MODE_INPUT, gpio_mode_t_GPIO_MODE_OUTPUT, + gpio_pad_pulldown, gpio_pad_pullup, gpio_pad_select_gpio, gpio_set_direction, gpio_set_level, +}; + +#[derive(Clone, Debug)] +pub enum Error {} + +pub enum PullDir { + Up, + Down, +} + +pub struct InputPin { + which: u8, +} + +impl InputPin { + pub unsafe fn new(which: u8, pulldir: PullDir) -> Self { + gpio_pad_select_gpio(which.try_into().unwrap()); + + match pulldir { + PullDir::Up => gpio_pad_pullup(which), + PullDir::Down => gpio_pad_pulldown(which), + }; + + gpio_set_direction(which.into(), gpio_mode_t_GPIO_MODE_INPUT); + + Self { which } + } +} + +impl hal::InputPin for InputPin { + type Error = Error; + + fn is_high(&self) -> Result { + let (bitmask, bit) = match self.which { + 0..=31 => (unsafe { gpio_input_get() }, self.which), + 32..=39 => (unsafe { gpio_input_get_high() }, self.which - 32), + _ => unreachable!(), + }; + + Ok((bitmask & (1 << bit)) != 0) + } + + fn is_low(&self) -> Result { + self.is_high().map(|x| !x) + } +} + +pub struct OutputPin { + which: u32, +} + +impl OutputPin { + pub unsafe fn new(which: u32) -> Self { + gpio_pad_select_gpio(which.try_into().unwrap()); + gpio_set_direction(which, gpio_mode_t_GPIO_MODE_OUTPUT); + Self { which } + } +} + +impl hal::OutputPin for OutputPin { + type Error = Error; + + fn set_high(&mut self) -> Result<(), Error> { + unsafe { + gpio_set_level(self.which, 1); + } + Ok(()) + } + + fn set_low(&mut self) -> Result<(), Error> { + unsafe { + gpio_set_level(self.which, 0); + } + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 0c9ac1ac8..1d0a5967c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,4 @@ #![no_std] + +pub mod gpio; +pub mod serial; diff --git a/src/serial.rs b/src/serial.rs new file mode 100644 index 000000000..a2a3b1536 --- /dev/null +++ b/src/serial.rs @@ -0,0 +1,88 @@ +use core::ptr; +use embedded_hal::serial::{Read, Write}; +use esp32_sys::{ + uart_config_t, uart_driver_install, uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_DISABLE, + uart_param_config, uart_parity_t_UART_PARITY_DISABLE, uart_port_t_UART_NUM_0, uart_read_bytes, + uart_set_pin, uart_stop_bits_t_UART_STOP_BITS_1, uart_wait_tx_done, + uart_word_length_t_UART_DATA_8_BITS, uart_write_bytes, ESP_ERR_TIMEOUT, ESP_OK, + UART_PIN_NO_CHANGE, +}; + +const BUF_SIZE: i32 = 1024; + +#[derive(Clone, Debug)] +pub enum Error {} + +pub struct Uart0; + +impl Uart0 { + pub unsafe fn new(tx_pin: i32, rx_pin: i32) -> Self { + let uart_config = uart_config_t { + baud_rate: 115200, + data_bits: uart_word_length_t_UART_DATA_8_BITS, + parity: uart_parity_t_UART_PARITY_DISABLE, + stop_bits: uart_stop_bits_t_UART_STOP_BITS_1, + flow_ctrl: uart_hw_flowcontrol_t_UART_HW_FLOWCTRL_DISABLE, + rx_flow_ctrl_thresh: 0, + use_ref_tick: false, + }; + + unsafe { + uart_param_config(uart_port_t_UART_NUM_0, &uart_config); + uart_set_pin( + uart_port_t_UART_NUM_0, + tx_pin, + rx_pin, + UART_PIN_NO_CHANGE, // RTS + UART_PIN_NO_CHANGE, // CTS + ); + uart_driver_install( + uart_port_t_UART_NUM_0, + BUF_SIZE * 2, + 0, + 0, + ptr::null_mut(), + 0, + ); + } + + Self + } +} + +impl Write for Uart0 { + type Error = Error; + + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + unsafe { + uart_write_bytes(uart_port_t_UART_NUM_0, &word as *const u8 as *const _, 1); + } + + Ok(()) + } + + /// Ensures that none of the previously written words are still buffered + fn flush(&mut self) -> nb::Result<(), Self::Error> { + let result = unsafe { uart_wait_tx_done(uart_port_t_UART_NUM_0, 0) }; + match result as u32 { + ESP_OK => Ok(()), + ESP_ERR_TIMEOUT => Err(nb::Error::WouldBlock), + _ => unreachable!(), + } + } +} + +impl Read for Uart0 { + type Error = Error; + + fn read(&mut self) -> nb::Result { + let mut c = 0; + let n = + unsafe { uart_read_bytes(uart_port_t_UART_NUM_0, &mut c as *mut u8 as *mut _, 1, 0) }; + match n { + -1 => Err(nb::Error::WouldBlock), + 1 => Ok(c), + _ => unreachable!(), + } + } +}