Web TippsUse custom web fonts in Google Sheets charts(08.09.2026 um 17:05 Uhr)
Web TippsIntroducing the new 1Password App for Google Chat(08.09.2026 um 18:02 Uhr)
Web TippsUse custom web fonts in Google Sheets charts(08.09.2026 um 17:05 Uhr)
Web TippsIntroducing the new 1Password App for Google Chat(08.09.2026 um 18:02 Uhr)

🔧 Programmierung 🕛 vor 1 Jahr 11 Min Lesezeit
0

Self-Aligning Satellite Dish in Rust: Compass

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

In our project we'll need to know the magnetic heading at any given position to help in precise alignment of the kit. For this we'll use a HMC5883L magnetometer module which communicates with other devices via I2c.






Table of Contents




  • Requirements

  • Connections

  • I2C Configuration


  • HMC5883L Configuration



    • Identification

    • Mode

    • Out Rate and Gain






  • Final Code









Requirements




  • 1 x Raspberry Pico board

  • 1 x USB Cable type 2.0

  • 1 x HC-05 Bluetooth module

  • 1 x HMC5833L Compass Module

  • 15 x M-M jumper wires

  • 2 x Mini Breadboards








Connections








CODE
i2c0.ic_enable().modify(|_, w| w.enable().clear_bit());// disable i2c
// select controller mode & speed
i2c0.ic_con().modify(|_, w| {
w.speed().fast();
w.master_mode().enabled();
w.ic_slave_disable().slave_disabled();
w.ic_restart_en().enabled();
w.tx_empty_ctrl().enabled()
});
// Clear FIFO threshold
i2c0.ic_tx_tl().write(|w| unsafe { w.tx_tl().bits(0) });
i2c0.ic_rx_tl().write(|w| unsafe { w.rx_tl().bits(0) });






We have to set up the COUNT registers before using the I2C. From the RP2040's manual we learn that the minimum SCL high and low values are 600ns and 1300ns respectively.



These are used to find the high and low count periods which are used to program the respective counters.




CODE
// IC_xCNT = (ROUNDUP(MIN_SCL_HIGH_LOWtime*OSCFREQ,0))
// IC_HCNT = (600ns * 125MHz) + 1
// IC_LCNT = (1300ns * 125MHz) + 1
i2c0.ic_fs_scl_hcnt().write(|w| unsafe { w.ic_fs_scl_hcnt().bits(76) });
i2c0.ic_fs_scl_lcnt().write(|w| unsafe { w.ic_fs_scl_lcnt().bits(163) });






We finally have to perform spike suppression and program the data hold time during transmission.




CODE
// spkln = lcnt/16;
i2c0.ic_fs_spklen().write(|w| unsafe { w.ic_fs_spklen().bits(163/16) });
// sda_tx_hold_count = freq_in [cycles/s] * 300ns for scl < 1MHz
let sda_tx_hold_count = ((125_000_000 * 3) / 10000000) + 1;
i2c0.ic_sda_hold().modify(|_r, w| unsafe { w.ic_sda_tx_hold().bits(sda_tx_hold_count as u16) });






I2C0 is now set up. We equally have to configure the HMC5883L.








HMC5883L configuration



First we'll write helper functions for reading and writing the I2C lines.



Configuring the magnetometer requires writing to specific registers. The below functions are light tweaks from the rp2040-hal crate. Overall we follow three steps:




  1. Disable the I2C

  2. Write the slave address

  3. Enable the I2C




CODE
fn i2c_read(
i2c0: &mut I2C0,
addr: u16,
bytes: &mut [u8],
) -> Result<(), u32> {
i2c0.ic_enable().modify(|_, w| w.enable().clear_bit());// disable i2c
i2c0.ic_tar().modify(|_, w| unsafe { w.ic_tar().bits(addr) });// slave address
i2c0.ic_enable().modify(|_, w| w.enable().set_bit());// enable i2c

let last_index = bytes.len() - 1;
for (i, byte) in bytes.iter_mut().enumerate() {
let first = i == 0;
let last = i == last_index;

// wait until there is space in the FIFO to write the next byte
while TX_FIFO_SIZE - i2c0.ic_txflr().read().txflr().bits() == 0 {}

i2c0.ic_data_cmd().modify(|_, w| {
if first {
w.restart().enable();
} else {
w.restart().disable();
}

if last {
w.stop().enable();
} else {
w.stop().disable();
}

w.cmd().read()
});

//Wait until address tx'ed
while i2c0.ic_raw_intr_stat().read().tx_empty().is_inactive() {}
//Clear ABORT interrupt
//self.i2c0.ic_clr_tx_abrt.read();

while i2c0.ic_rxflr().read().bits() == 0 {
//Wait while receive FIFO empty
//If attempt aborts : not valid address; return error with
//abort reason.
let abort_reason = i2c0.ic_tx_abrt_source().read().bits();
//Clear ABORT interrupt
i2c0.ic_clr_tx_abrt().read();
if abort_reason != 0 {
return Err(abort_reason)
}
}

*byte = i2c0.ic_data_cmd().read().dat().bits();
}

Ok(())
}

fn i2c_write(
i2c0: &mut I2C0,
addr: u16,
bytes: &[u8],
) -> Result<(), u32> {
i2c0.ic_enable().modify(|_, w| w.enable().clear_bit());// disable i2c
i2c0.ic_tar().modify(|_, w| unsafe { w.ic_tar().bits(addr) });// slave address
i2c0.ic_enable().modify(|_, w| w.enable().set_bit());// enable i2c

let last_index = bytes.len() - 1;
for (i, byte) in bytes.iter().enumerate() {
let last = i == last_index;

i2c0.ic_data_cmd().modify(|_, w| {
if last {
w.stop().enable();
} else {
w.stop().disable();
}
unsafe { w.dat().bits(*byte)}
});

// Wait until address and data tx'ed
while i2c0.ic_raw_intr_stat().read().tx_empty().is_inactive() {}
// Clear ABORT interrupt
// self.i2c0.ic_clr_tx_abrt.read();

// If attempt aborts : not valid address; return error with
// abort reason.
let abort_reason = i2c0.ic_tx_abrt_source().read().bits();
// Clear ABORT interrupt
i2c0.ic_clr_tx_abrt().read();
if abort_reason != 0 {
// Wait until the STOP condition has occured
while i2c0.ic_raw_intr_stat().read().stop_det().is_inactive() {}
// Clear STOP interrupt
i2c0.ic_clr_stop_det().read().clr_stop_det();
return Err(abort_reason)
}

if last {
// Wait until the STOP condition has occured
while i2c0.ic_raw_intr_stat().read().stop_det().is_inactive() {}
// Clear STOP interrupt
i2c0.ic_clr_stop_det().read().clr_stop_det();
}
}

Ok(())
}






Import I2C0.




CODE
use rp2040_pac::I2C0;






Add the TX_FIFO_SIZE constant.




CODE
// Global constants
const TX_FIFO_SIZE: u8 = 16;// I2C FIFO size






Create buffer to hold data to be sent and received via I2C.




CODE
// Buffers
let mut writebuf: [u8; 1];// buffer to hold 1 byte
let mut readbuf: [u8; 1] = [0; 1];











Identification



We can begin by confirming the identification of the HMC5883L. The chip has three Identification registers, A, B and C, holding the values 48, 34 and 33 respectively.



To read a register in the compass we first have to send the slave address with the command bit set to read followed by a pointer to the address whose contents we want to read.



Reading ID Reg. A for example we have to send 0x3D 0x10.



Before proceeding further we should create the magnetometer's addresses constants to help write cleanly.



Add the following to our global constant section




CODE
// Slave Address
const HMC5883L_ADDR: u16 = 30;

// ID
const IDENTIFICATION_REG_A: u8 = 0xA;// HMC5883L
const IDENTIFICATION_REG_B: u8 = 0xB;// HMC5883L
const IDENTIFICATION_REG_C: u8 = 0xC;// HMC5883L






Continuing the configuration...




CODE
// Configure and confirm HMC5833L
// ID the compass
// Read ID REG A
writebuf = [IDENTIFICATION_REG_A];
i2c_write(&mut i2c0, HMC5883L_ADDR, &mut writebuf).unwrap();
i2c_read(&mut i2c0, HMC5883L_ADDR, &mut readbuf).unwrap();
let id_a = readbuf[0];
writeln!(serialbuf, "Id reg a: 0x{:02X}", id_a).unwrap();
transmit_uart_data(&uart_data, serialbuf);

// Read ID REG B
writebuf = [IDENTIFICATION_REG_B];
i2c_write(&mut i2c0, HMC5883L_ADDR, &mut writebuf).unwrap();
i2c_read(&mut i2c0, HMC5883L_ADDR, &mut readbuf).unwrap();
let id_b = readbuf[0];
writeln!(serialbuf, "Id reg b: 0x{:02X}", id_b).unwrap();
transmit_uart_data(&uart_data, serialbuf);

// Read ID REG C
writebuf = [IDENTIFICATION_REG_C];
i2c_write(&mut i2c0, HMC5883L_ADDR, &mut writebuf).unwrap();
i2c_read(&mut i2c0, HMC5883L_ADDR, &mut readbuf).unwrap();
let id_c = readbuf[0];
writeln!(serialbuf, "Id reg c: 0x{:02X}", id_c).unwrap();
transmit_uart_data(&uart_data, serialbuf);

if id_a == 0x48 && id_b == 0x34 && id_c == 0x33 {
writeln!(serialbuf, "Magnetometer ID confirmed!").unwrap();
transmit_uart_data(&uart_data, serialbuf);
}






Flash the program thus far into the Pico. The compass should be positively identified.










Final Code



The updated and rearranged code will be as so.



In the next part we'll run a simple example to demonstrate the working of the HMC5833L.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
Use custom web fonts in Google Sheets charts
2 Quellen
Introducing the new 1Password App for Google Chat
1 Quelle
Context-aware access controls are available for Gemini Enterprise in the Admin console
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Self-Aligning Satellite Dish in Rust: Compass

Thematisch verwandte Begriffe: SelfAligning, Satellite, Dish, Rust · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...