Skip to content

Commit

Permalink
feat(v0.0.9): example usage with esp32
Browse files Browse the repository at this point in the history
  • Loading branch information
zpg6 committed Jul 6, 2024
1 parent 25f0c6c commit 646ef65
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mcp2003a"
version = "0.0.8"
version = "0.0.9"
description = "Rust no_std LIN Bus communication using the MCP2003A LIN transceiver."
edition = "2021"
license = "MIT"
Expand Down
21 changes: 21 additions & 0 deletions examples/mcp2003a-esp-rs/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[build]
target = "xtensa-esp32-espidf"

[target.xtensa-esp32-espidf]
linker = "ldproxy"
# runner = "espflash --monitor" # Select this runner for espflash v1.x.x
runner = "espflash flash --monitor" # Select this runner for espflash v2.x.x
rustflags = [ "--cfg", "espidf_time64"] # Extending time_t for ESP IDF 5: https://github.com/esp-rs/rust/issues/110

[unstable]
build-std = ["std", "panic_abort"]

[env]
MCU="esp32"
# Note: this variable is not used by the pio builder (`cargo build --features pio`)
ESP_IDF_VERSION = "v5.1.3"

# Workaround for https://github.com/esp-rs/esp-idf-template/issues/174 until
# https://github.com/esp-rs/esp-idf-hal/pull/387 gets released and the template
# updated.
CRATE_CC_NO_DEFAULTS = "1"
4 changes: 4 additions & 0 deletions examples/mcp2003a-esp-rs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/.vscode
/.embuild
/target
/Cargo.lock
36 changes: 36 additions & 0 deletions examples/mcp2003a-esp-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "mcp2003a-esp-rs"
version = "0.0.1"
authors = ["Zach Grimaldi"]
edition = "2021"
resolver = "2"
rust-version = "1.71"

[[bin]]
name = "mcp2003a-esp-rs"
harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors

[profile.release]
opt-level = "s"

[profile.dev]
debug = true # Symbols are nice and they don't increase the size on Flash
opt-level = "z"

[features]
default = ["std", "embassy", "esp-idf-svc/native"]

pio = ["esp-idf-svc/pio"]
std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"]
alloc = ["esp-idf-svc/alloc"]
nightly = ["esp-idf-svc/nightly"]
experimental = ["esp-idf-svc/experimental"]
embassy = ["esp-idf-svc/embassy-sync", "esp-idf-svc/critical-section", "esp-idf-svc/embassy-time-driver"]

[dependencies]
log = { version = "0.4", default-features = false }
esp-idf-svc = { version = "0.48", default-features = false }
mcp2003a = { path = "../../" }

[build-dependencies]
embuild = "0.31.3"
3 changes: 3 additions & 0 deletions examples/mcp2003a-esp-rs/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
embuild::espidf::sysenv::output();
}
2 changes: 2 additions & 0 deletions examples/mcp2003a-esp-rs/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "esp"
10 changes: 10 additions & 0 deletions examples/mcp2003a-esp-rs/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Rust often needs a bit of an extra main task stack size compared to C (the default is 3K)
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8000

# Use this to set FreeRTOS kernel tick frequency to 1000 Hz (100 Hz by default).
# This allows to use 1 ms granuality for thread sleeps (10 ms by default).
#CONFIG_FREERTOS_HZ=1000

# Workaround for https://github.com/espressif/esp-idf/issues/7631
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n
#CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n
107 changes: 107 additions & 0 deletions examples/mcp2003a-esp-rs/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use esp_idf_svc::hal::{
delay::{Ets, FreeRtos},
gpio::{Gpio0, Gpio1, PinDriver},
peripherals::Peripherals,
uart::{
config::{Config as UartConfig, DataBits, StopBits},
UartDriver,
},
units::Hertz,
};
use mcp2003a::{
config::{LinBreakDuration, LinBusConfig, LinBusSpeed, LinInterFrameSpace, LinReadDeviceResponseTimeout, LinWakeupDuration},
Mcp2003a, Mcp2003aError,
};

fn main() {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_svc::sys::link_patches();

// Bind the log crate to the ESP Logging facilities
esp_idf_svc::log::EspLogger::initialize_default();

// Take the peripherals from the ESP-IDF framework
let peripherals = Peripherals::take().unwrap();

// Configure UART2 for sending and receiving LIN Bus frames between
// this and the MCP2003A LIN Transceiver.
let uart2 = peripherals.uart2;
let uart2_rx = peripherals.pins.gpio16;
let uart2_tx = peripherals.pins.gpio17;
let uart2_config = UartConfig::default()
.baudrate(Hertz(19200))
.data_bits(DataBits::DataBits8)
.parity_none()
.stop_bits(StopBits::STOP1);
let uart2_driver = UartDriver::new(uart2, uart2_tx, uart2_rx, Option::<Gpio0>::None, Option::<Gpio1>::None, &uart2_config).unwrap();

// Configure the GPIO pin for the LIN Bus break signal
let break_pin = peripherals.pins.gpio15;
let break_pin_driver = PinDriver::output(break_pin).unwrap();

// Use Ets to delay for small periods of time
let delay = Ets;

// Configure the LIN Bus with the following parameters:
let lin_bus_config = LinBusConfig {
speed: LinBusSpeed::Baud19200,
break_duration: LinBreakDuration::Minimum13Bits, // Test for your application
wakeup_duration: LinWakeupDuration::Minimum250Microseconds, // Test for your application
read_device_response_timeout: LinReadDeviceResponseTimeout::DelayMilliseconds(2), // Test for your application
inter_frame_space: LinInterFrameSpace::DelayMilliseconds(1), // Test for your application
};

// Initialize the MCP2003A LIN Transceiver
let mut mcp2003a = Mcp2003a::new(uart2_driver, break_pin_driver, delay, lin_bus_config);

log::info!("MCP2003A LIN Transceiver initialized");

// Wakeup the LIN Bus
mcp2003a.send_wakeup();

loop {
// Send a frame on the LIN bus to a device with Command frame of 0x00:
// - LIN Id: 0x00 --> PID: 0x80
// - Data: [0x00, 0xF0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x08]
// - Checksum: 0x7C
match mcp2003a.send_frame(0x80, &[0x00, 0xF0, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x08], 0x7C) {
Ok(frame) => {
// Frame sent
log::info!("Sent data to LIN Id 0x00: {:?}", frame);
}
Err(e) => {
// Error sending the frame
log::error!("Error sending frame: {:?}", e);
}
}

// Over-sending not needed, so delay between frames
FreeRtos::delay_ms(500);

// Read the feedback / diagnostic frame 0x01 from the LIN bus:
// - LIN Id: 0x01 --> PID: 0xC1
// - Data: We provide an 8-byte buffer to store the data
let mut data = [0u8; 11];
match mcp2003a.read_frame(0xC1, &mut data) {
Ok(len) => {
// Data is stored in the buffer
log::info!("Received data from LIN Id 0x01: {:?}", &data[..len]);
}
Err(e) => {
// Error reading the frame
match e {
Mcp2003aError::LinDeviceTimeoutNoResponse => {
log::warn!("No response from LIN Id 0x01... this device may be offline.");
}
_ => {
log::error!("Error reading frame: {:?}", e);
}
}
}
}

// Over-sending not needed, so delay between frames
FreeRtos::delay_ms(500);
}
}

0 comments on commit 646ef65

Please sign in to comment.