From 12b06a0fa99c5c60f5d47981f20ed718731abcb7 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Sat, 31 Aug 2019 23:24:24 +0100 Subject: [PATCH 1/3] add I2C and 24xx EEPROM driver --- Cargo.toml | 0 src/eeprom.rs | 23 +++++++ src/i2c.rs | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) mode change 100644 => 100755 Cargo.toml create mode 100755 src/eeprom.rs create mode 100755 src/i2c.rs diff --git a/Cargo.toml b/Cargo.toml old mode 100644 new mode 100755 diff --git a/src/eeprom.rs b/src/eeprom.rs new file mode 100755 index 0000000..5f54d1f --- /dev/null +++ b/src/eeprom.rs @@ -0,0 +1,23 @@ +use stm32h7::stm32h743 as pac; +use super::i2c; + +const I2C_ADDR: u8 = 0xa0; + +pub fn read_eui48<'a>(i2c: &pac::I2C2) -> Result<[u8; 6], i2c::Error> { + let mut buffer = [0u8; 6]; + i2c::write_read(i2c, I2C_ADDR, &[0xFAu8], &mut buffer)?; + Ok(buffer) +} + +pub fn read(i2c: &pac::I2C2, addr: u8, mut buffer: &mut [u8]) -> Result<(), i2c::Error> { + i2c::write_read(i2c, I2C_ADDR, &[addr], &mut buffer)?; + Ok(()) +} + +pub fn write(i2c: &pac::I2C2, addr: u8, buffer: &[u8]) -> Result<(), i2c::Error> { + for (i, &byte) in buffer.iter().enumerate() { + i2c::write(i2c, I2C_ADDR, &[addr+i as u8, byte])?; + } + + Ok(()) +} diff --git a/src/i2c.rs b/src/i2c.rs new file mode 100755 index 0000000..e6c0266 --- /dev/null +++ b/src/i2c.rs @@ -0,0 +1,182 @@ +use stm32h7::stm32h743 as pac; + +// Adapted from stm32h7xx embedded-hal + +// I2C error +#[derive(Debug)] +pub enum Error { + // Bus error + Bus, + // Arbitration loss + Arbitration, + // Address not ACKd within a reasonable time (no device present?) + Timeout, + // Unexpected NACK during transfer + NAck +} + +// Maximum number of times to retry NACKed address phase before timing out +// Note that many devices indicate a busy condition by NACKing (e.g. 24xx +// EEPROMs during write) +const N_RETRY: usize = 100; // ~ 10ms @ 100 kHz bus clock + + +pub fn setup(rcc: &pac::RCC, i2c: &pac::I2C2) { + rcc.apb1lenr.modify(|_,w| + w.i2c2en().set_bit() + ); + + // Disable the peripheral before setting timings + i2c.cr1.modify(|_, w| w.pe().clear_bit()); + + // Values from STM32MXCube for 100 kHz I2C clock with 100 MHz peripheral clock + i2c.timingr.modify( |_,w| + w.presc().bits(1) + .scldel().bits(0x12) + .sdadel().bits(0) + .sclh().bits(0xec) + .scll().bits(0xff) + ); + + // Enable the peripheral + i2c.cr1.write(|w| w.pe().set_bit()); +} + + +// Busy-wait for a flag to be asserted, erroring out on unrecoverable problems +macro_rules! busy_wait_errors { + ($i2c:expr, $flag:ident) => { + loop { + let isr = $i2c.isr.read(); + + if isr.berr().bit_is_set() { + return Err(Error::Bus); + } else if isr.arlo().bit_is_set() { + return Err(Error::Arbitration); + } else if isr.nackf().bit_is_set() { + return Err(Error::NAck); + } else if isr.$flag().bit_is_set() { + break; + } + } + }; +} + + +fn poll_for_start_ack( + i2c: &pac::I2C2, + addr: u8, + r_wn: bool, + data_len: usize, + autoend: bool, + start: bool +) -> Result<(), Error> +{ + for _i in 0..N_RETRY { + // START and prepare to send `data_len` + i2c.cr2.write(|w| { + w.start().bit(start) + .sadd().bits(addr as u16) + .add10().clear_bit() + .rd_wrn().bit(r_wn) + .nbytes().bits( data_len as u8 ) + .autoend().bit(autoend) + }); + + loop { + let isr = i2c.isr.read(); + + if isr.berr().bit_is_set() { + return Err(Error::Bus); + } else if isr.arlo().bit_is_set() { + return Err(Error::Arbitration); + } else if isr.nackf().bit_is_set() { + i2c.icr.write(|w| { w.nackcf().set_bit() }); + // Wait to finish handling NACK-STOP + loop { + if i2c.isr.read().busy().bit_is_clear() { + break; + } + } + break; + } else if isr.txis().bit_is_set() || isr.rxne().bit_is_set() { + return Ok(()) + } + } + } + + return Err(Error::Timeout); +} + + +pub fn write( + i2c: &pac::I2C2, + addr: u8, + bytes: &[u8] +) -> Result<(), Error> { + assert!(bytes.len() < 256 && bytes.len() > 0); + + poll_for_start_ack(i2c, addr|0, false, bytes.len(), true, true)?; + + for byte in bytes { + busy_wait_errors!(i2c, txis); + i2c.txdr.write(|w| w.txdata().bits(*byte)); + } + // automatic STOP + + Ok(()) +} + + +pub fn write_read( + i2c: &pac::I2C2, + addr: u8, + bytes: &[u8], + buffer: &mut [u8], +) -> Result<(), Error> { + assert!(bytes.len() < 256 && bytes.len() > 0); + assert!(buffer.len() < 256 && buffer.len() > 0); + + poll_for_start_ack(i2c, addr|0, false, bytes.len(), false, true)?; + + for byte in bytes { + // Wait until we are allowed to send data (START has been ACKed or last + // byte when through) + busy_wait_errors!(i2c, txis); + i2c.txdr.write(|w| w.txdata().bits(*byte)); + } + + // Wait until the last transmission is finished + busy_wait_errors!(i2c, tc); + + poll_for_start_ack(i2c, addr|1, true, buffer.len(), true, true)?; + + for byte in buffer { + // Wait until we have received something + busy_wait_errors!(i2c, rxne); + *byte = i2c.rxdr.read().rxdata().bits(); + } + + // automatic STOP + Ok(()) +} + + +pub fn read( + i2c: &pac::I2C2, + addr: u8, + buffer: &mut [u8], +) -> Result<(), Error> { + assert!(buffer.len() < 256 && buffer.len() > 0); + + poll_for_start_ack(i2c, addr|0, true, buffer.len(), true, true)?; + + for byte in buffer { + // Wait until we have received something + busy_wait_errors!(i2c, rxne); + *byte = i2c.rxdr.read().rxdata().bits(); + } + + // automatic STOP + Ok(()) +} From 30faa5b703b3949c914cdcc18cec0abe3bb7002e Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Thu, 5 Sep 2019 00:54:00 +0100 Subject: [PATCH 2/3] read MAC address from EEPROM --- src/main.rs | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/main.rs diff --git a/src/main.rs b/src/main.rs old mode 100644 new mode 100755 index ac9a075..4a6da1a --- a/src/main.rs +++ b/src/main.rs @@ -38,6 +38,9 @@ mod eth; mod iir; use iir::*; +pub mod i2c; +mod eeprom; + #[cfg(not(feature = "semihosting"))] fn init_log() {} @@ -291,6 +294,20 @@ fn gpio_setup(gpioa: &pac::GPIOA, gpiob: &pac::GPIOB, gpiod: &pac::GPIOD, .odr15().low() ); + // I2C2: SDA,SCL: PF0,PF1 + gpiof.moder.modify(|_, w| + w.moder0().alternate() + .moder1().alternate() + ); + gpiof.afrl.modify(|_, w| + w.afr0().af4() + .afr1().af4() + ); + gpiof.otyper.modify(|_, w| + w.ot0().open_drain() + .ot1().open_drain() + ); + // ADC1 // SCK: PF6 gpiof.moder.modify(|_, w| w.moder7().alternate()); @@ -524,6 +541,7 @@ macro_rules! create_socket { const APP: () = { struct Resources { spi: (pac::SPI1, pac::SPI2, pac::SPI4, pac::SPI5), + i2c: pac::I2C2, ethernet_periph: (pac::ETHERNET_MAC, pac::ETHERNET_DMA, pac::ETHERNET_MTL), #[init([[0.; 5]; 2])] iir_state: [IIRState; 2], @@ -611,6 +629,9 @@ const APP: () = { tim2_setup(&dp.TIM2); + let i2c2 = dp.I2C2; + i2c::setup(&rcc, &i2c2); + eth::setup(&rcc, &dp.SYSCFG); eth::setup_pins(&dp.GPIOA, &dp.GPIOB, &dp.GPIOC, &dp.GPIOG); @@ -618,15 +639,24 @@ const APP: () = { init::LateResources { spi: (spi1, spi2, spi4, spi5), + i2c: i2c2, ethernet_periph: (dp.ETHERNET_MAC, dp.ETHERNET_DMA, dp.ETHERNET_MTL), } } - #[idle(resources = [ethernet, ethernet_periph, iir_state, iir_ch])] + #[idle(resources = [ethernet, ethernet_periph, iir_state, iir_ch, i2c])] fn idle(c: idle::Context) -> ! { let (MAC, DMA, MTL) = c.resources.ethernet_periph; - let hardware_addr = net::wire::EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00]); + let hardware_addr = match eeprom::read_eui48(c.resources.i2c) { + Err(_) => { + info!("Could not read EEPROM, using default MAC address"); + net::wire::EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00]) + }, + Ok(raw_mac) => net::wire::EthernetAddress(raw_mac) + }; + info!("MAC: {}", hardware_addr); + unsafe { c.resources.ethernet.init(hardware_addr, MAC, DMA, MTL) }; let mut neighbor_cache_storage = [None; 8]; let neighbor_cache = net::iface::NeighborCache::new(&mut neighbor_cache_storage[..]); From 85b037c48634145d0cd8fb8b662db3fe94903c48 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2019 14:11:37 +0000 Subject: [PATCH 3/3] build(deps): bump serde from 1.0.99 to 1.0.100 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.99 to 1.0.100. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.99...v1.0.100) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8b03ce..5d026b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -268,7 +268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", @@ -280,7 +280,7 @@ version = "0.0.1" source = "git+https://github.com/quartiq/serde-json-core.git?rev=fc764de#fc764deb8dfb82e5cfcc6c5059d8d5c3031e0591" dependencies = [ "heapless 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -314,7 +314,7 @@ dependencies = [ "heapless 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "panic-semihosting 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", "serde-json-core 0.0.1 (git+https://github.com/quartiq/serde-json-core.git?rev=fc764de)", "smoltcp 0.5.0 (git+https://github.com/m-labs/smoltcp.git?rev=1ada3da)", "stm32h7 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -419,7 +419,7 @@ dependencies = [ "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a" "checksum serde-json-core 0.0.1 (git+https://github.com/quartiq/serde-json-core.git?rev=fc764de)" = "" "checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" "checksum smoltcp 0.5.0 (git+https://github.com/m-labs/smoltcp.git?rev=1ada3da)" = ""