Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- My Code:
- ```
- #![no_std]
- #![no_main]
- extern crate alloc;
- use core::ops::Range;
- use esp_backtrace as _;
- use esp_println::println;
- use hal::i2c::Error;
- use hal::xtensa_lx::timer::delay;
- use hal::{
- clock::ClockControl, i2c::I2C, peripherals::Peripherals, prelude::*, timer::TimerGroup, Delay,
- Rtc, IO,
- };
- #[global_allocator]
- static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
- fn init_heap() {
- const HEAP_SIZE: usize = 32 * 1024;
- extern "C" {
- static mut _heap_start: u32;
- static mut _heap_end: u32;
- }
- unsafe {
- let heap_start = &_heap_start as *const _ as usize;
- let heap_end = &_heap_end as *const _ as usize;
- assert!(
- heap_end - heap_start > HEAP_SIZE,
- "Not enough available heap memory."
- );
- ALLOCATOR.init(heap_start as *mut u8, HEAP_SIZE);
- }
- }
- const VALID_ADDR_RANGE: Range<u8> = 0x08..0x78;
- #[entry]
- fn main() -> ! {
- init_heap();
- let peripherals = Peripherals::take();
- let mut system = peripherals.DPORT.split();
- let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
- // Disable the RTC and TIMG watchdog timers
- let mut rtc = Rtc::new(peripherals.RTC_CNTL);
- let timer_group0 = TimerGroup::new(
- peripherals.TIMG0,
- &clocks,
- &mut system.peripheral_clock_control,
- );
- let mut wdt0 = timer_group0.wdt;
- let timer_group1 = TimerGroup::new(
- peripherals.TIMG1,
- &clocks,
- &mut system.peripheral_clock_control,
- );
- let mut wdt1 = timer_group1.wdt;
- rtc.rwdt.disable();
- wdt0.disable();
- wdt1.disable();
- let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
- let mut i2c = I2C::new(
- peripherals.I2C0,
- io.pins.gpio21,
- io.pins.gpio22,
- 400u32.kHz(),
- &mut system.peripheral_clock_control,
- &clocks,
- );
- // for addr in 0x00_u8..0x80 {
- // if VALID_ADDR_RANGE.contains(&addr) && i2c.write(addr, &[]).is_ok() {
- // println!("{:02x}", addr)
- // }
- // }
- const buff_size: usize = 4096;
- let mut bytesvailraw: [u8; 2] = [0; 2];
- let mut buf: [u8; 4096] = [0; buff_size];
- let mut wait = Delay::new(&clocks);
- // Init
- while i2c.write(0x42_u8, &[0xFD]).is_err() {
- println!("Waiting for init call to GPS...");
- wait.delay_ms(1000_u32);
- }
- println!("Sent init call to GPS...");
- wait.delay_ms(40_u32);
- // Get number of bytes available (low byte)
- while i2c.read(0x42_u8, &mut bytesvailraw).is_err() {
- println!("Failed to read low byte of bytes avail...");
- wait.delay_ms(500_u32);
- }
- println!("Got high byte of bytes avail: {:b}", bytesvailraw[0]);
- wait.delay_ms(40_u32);
- // Get number of bytes available (high byte)
- while i2c.read(0x42_u8, &mut bytesvailraw).is_err() {
- println!("Failed to read high byte of bytes avail...");
- wait.delay_ms(500_u32);
- }
- println!("God high byte of bytes avail: {:b}", bytesvailraw[1]);
- let mut bytesavail = u16::from_le_bytes(bytesvailraw);
- if bytesavail & (1u16 << 15) != 0 {
- bytesavail &= !(1u16 << 15)
- }
- println!("Bytes available: {:}", bytesavail);
- let mut buf_index: usize = 0;
- wait.delay_ms(100_u32);
- i2c.write(0x42_u8, &[0xFF])
- .expect("Failed to set register...");
- println!("Selected register...");
- wait.delay_ms(40_u32);
- println!("Reading data...");
- let mut local_buff: [u8; 1] = [0];
- while bytesavail > 0 && buf_index < buff_size {
- match i2c.read(0x42_u8, &mut local_buff) {
- Ok(_) => {
- println!("Read a byte: {:X}", local_buff[0]);
- bytesavail -= 1;
- println!("{:?} bytes left...", bytesavail);
- if local_buff[0] == 0xFF_u8 {
- println!("Device sent 0xFF...GPS buff is empty. Waiting.");
- }
- buf[buf_index] = local_buff[0];
- buf_index += 1;
- wait.delay_ms(40_u32);
- }
- Err(e) => {
- println!("Error reading byte: {:?}...\nWaiting...", e);
- wait.delay_ms(500_u32);
- continue
- }
- }
- }
- println!("Our buffer: {:?}", buf);
- loop {}
- }
- ```
- Integration guide:
- https://content.u-blox.com/sites/default/files/NEO-M9N_Integrationmanual_UBX-19014286.pdf
- 3.7.2 I2C interface
- An I2C interface is available for communication with an external host CPU or u-blox cellular modules.
- The interface can be operated in slave mode only. The I2C protocol and electrical interface are fully
- compatible with Fast-mode of the I2C industry standard. Since the maximum SCL clock frequency
- is 400 kHz, the maximum transfer rate is 400 kb/s. The SCL and SDA pins have internal pull-up
- resistors which should be sufficient for most applications. However, depending on the speed of the
- host and the load on the I2C lines additional external pull-up resistors may be necessary.
- To use the I2C interface D_SEL pin must be left open.
- In designs where the host uses the same I2C bus to communicate with more than one u-blox
- receiver, the I2C slave address for each receiver must be configured to a different value. Typically
- most u-blox receivers are configured to the same default I2C slave address value. To poll or
- set the I2C slave address, use the CFG-I2C-ADDRESS configuration item (see the applicable
- interface description [2]).
- The CFG-I2C-ADDRESS configuration item is an 8-bit value containing the I2C slave address in
- 7 most significant bits, and the read/write flag in the least significant bit.
- 3.7.2.1 I2C register layout
- The I2C interface allows 256 registers to be addressed. As shown in Figure 11, only three of these
- are currently implemented.
- The data registers 0 to 252 at addresses 0x00 to 0xFC contain reserved information, the result from
- their reading is currently undefined. The data registers 0 to 252 are 1 byte wide.
- At addresses 0xFD and 0xFE it is possible to read the currently available number of bytes.
- The register at address 0xFF allows the data stream to be read. If there is no data awaiting
- transmission from the receiver, then this register delivers value 0xFF, which cannot be the first byte
- of a valid message. If the message data is ready for transmission, the successive reads of register
- 0xFF will deliver the waiting message data.
- UBX-19014286 - R08 3 Receiver functionality Page 26 of 94
- C1-Public
- NEO-M9N - Integration manual
- Do not use registers 0x00 to 0xFC. They are reserved for future use and they do not currently
- provide any meaningful data.
- Figure 11: I2C register layout
- 3.7.2.2 Read access types
- There are two I2C read transfer forms:
- • The "random access" form: includes a slave register address and allows any register to be read.
- • The "current address" form: omits the register address.
- Figure 12 shows the format of the first one, the "random access" form of the request. Following
- the start condition from the master, the 7-bit device address and the RW bit (which is a logic low
- for write access) are clocked onto the bus by the master transmitter. The receiver answers with an
- acknowledge (logic low) to indicate that it recognizes the address.
- Next, the 8-bit address of the register to be read must be written to the bus. Following the receiver's
- acknowledgment, the master again triggers a start condition and writes the device address, but this
- time the RW bit is a logic high to initiate the read access. Now, the master can read 1 to N bytes
- from the receiver, generating a not-acknowledge and a stop condition after the last byte being read.
- UBX-19014286 - R08 3 Receiver functionality Page 27 of 94
- C1-Public
- NEO-M9N - Integration manual
- Figure 12: I2C random read access
- If the second form, "current address" is used, an address pointer in the receiver is used to determine
- which register to read. This address pointer will increment after each read unless it is already
- pointing at register 0xFF, the highest addressable register, in which case it remains unaltered.
- The initial value of this address pointer at startup is 0xFF, so by default all current address reads
- will repeatedly read register 0xFF and receive the next byte of message data (or 0xFF if no message
- data is waiting).
- Figure 13: I2C current address read access
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement