-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
27 add battery sensor to the bsc (#54)
* Add mightybuga_bsc/examples/no_bsc_batt_sensor.rs * Update apps/hello_world with light sensor reading * Add battery sensor and example to the hello world app * Fix unused import warning
- Loading branch information
Showing
8 changed files
with
235 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[package] | ||
name = "battery_sensor_controller" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#![no_std] | ||
|
||
/// The trait implemented by the battery sensor to get the battery voltage in millivolts. | ||
pub trait BatterySensorController { | ||
fn get_battery_millivolts(&mut self) -> u16; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
//! battery sensor example without using the BSC | ||
//! The battery sensor is a voltage divider with a 47k resistor and a 20k resistor. | ||
//! The voltage is read from the middle of the two resistors. | ||
//! The voltage is then converted to millivolts and printed to the serial port. | ||
//! | ||
//! Hardware connections: | ||
//! - VBATT to the 47k resistor. The battery has 2 cells in series, so the maximum voltage is 8.4V | ||
//! - GND to the 20k resistor | ||
//! - The middle of the two resistors to PB0 (ADC1) | ||
//! - Led to PC13 | ||
//! - Serial port to PA9 (tx) and PA10 (rx) | ||
//! | ||
//! Run with: | ||
//! cargo xtask mightybuga_bsc example no_bsc_batt_sensor | ||
//! or | ||
//! cd mightybuga-bsc; cargo run --example no_bsc_batt_sensor | ||
#![no_std] | ||
#![cfg_attr(not(doc), no_main)] | ||
use panic_halt as _; | ||
|
||
use mightybuga_bsc as board; | ||
|
||
use board::hal::adc::*; | ||
use board::hal::serial::*; | ||
use board::hal::{pac, prelude::*}; | ||
use cortex_m_rt::entry; | ||
use nb::block; | ||
|
||
#[entry] | ||
fn main() -> ! { | ||
// Get access to the core peripherals from the cortex-m crate | ||
let cp = cortex_m::Peripherals::take().unwrap(); | ||
// Get access to the device specific peripherals from the peripheral access crate | ||
let dp = pac::Peripherals::take().unwrap(); | ||
|
||
// Take ownership over the raw flash and rcc devices and convert them into the corresponding | ||
// HAL structs | ||
let mut flash = dp.FLASH.constrain(); | ||
let rcc = dp.RCC.constrain(); | ||
|
||
let mut afio = dp.AFIO.constrain(); | ||
|
||
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in | ||
// `clocks` | ||
let clocks = rcc.cfgr.freeze(&mut flash.acr); | ||
|
||
// create a delay abstraction based on SysTick | ||
let mut delay = cp.SYST.delay(&clocks); | ||
|
||
// Acquire the GPIOC peripheral | ||
let mut gpioc = dp.GPIOC.split(); | ||
|
||
// Configure gpio C pin 13 as a push-pull output. The `crh` register is passed to the function | ||
// in order to configure the port. For pins 0-7, crl should be passed instead. | ||
let mut led = gpioc.pc13.into_push_pull_output(&mut gpioc.crh); | ||
|
||
// turn on the led | ||
led.set_high(); | ||
|
||
// Acquire the GPIOA peripheral | ||
let mut gpioa = dp.GPIOA.split(); | ||
|
||
// Configure gpio A pins 9 and 10 as a push-pull output. The `crh` register is passed to the | ||
// function in order to configure the port. For pins 0-7, crl should be passed instead. | ||
let tx = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh); | ||
let rx = gpioa.pa10; | ||
|
||
// Configure the serial peripheral | ||
let serial = Serial::new( | ||
dp.USART1, | ||
(tx, rx), | ||
&mut afio.mapr, | ||
Config::default() | ||
.baudrate(115_200.bps()) | ||
.wordlength_8bits() | ||
.parity_none(), | ||
&clocks, | ||
); | ||
|
||
// Split the serial struct into a receiving and a transmitting part | ||
let (mut tx, _rx) = serial.split(); | ||
|
||
let s = b"\r\nBattery readings:\r\n"; | ||
let _ = s.iter().map(|c| block!(tx.write(*c))).last(); | ||
|
||
// Acquire the ADC1 peripheral | ||
let mut adc1 = Adc::adc1(dp.ADC1, clocks); | ||
|
||
// Get the GPIOB port | ||
let mut gpiob = dp.GPIOB.split(); | ||
|
||
// Configure PB0 as an analog input | ||
let mut pb0 = gpiob.pb0.into_analog(&mut gpiob.crl); | ||
|
||
loop { | ||
// Read the battery voltage, take 100 samples and average them (later, so we don't lose precision): | ||
let mut battery_voltage_by_100: u32 = 0; | ||
for _ in 0..100 { | ||
let sample: u16 = adc1.read(&mut pb0).unwrap(); | ||
battery_voltage_by_100 += sample as u32; | ||
} | ||
|
||
// Convert the voltage to millivolts. We multiply the raw value by the battery voltage and | ||
// divide by the resister divider. The maximum value is 8.4V and the resister divider is | ||
// 47k and 20k. The raw value is 12 bits, so the maximum value is 4096 that corresponds to | ||
// 2.5 volts in the ADC. The formula is: | ||
let raw_to_millivolts_multiplier_by_1000 = 2857; | ||
let battery_voltage_mv = | ||
(battery_voltage_by_100 * raw_to_millivolts_multiplier_by_1000 / 100000) as u16; | ||
|
||
// Print the raw value and the battery voltage to the serial port | ||
let mut buf = [0; 5]; | ||
u16_to_str((battery_voltage_by_100 / 100) as u16, &mut buf); | ||
let _ = buf.iter().map(|c| block!(tx.write(*c))).last(); | ||
|
||
let s = b" - "; | ||
let _ = s.iter().map(|c| block!(tx.write(*c))).last(); | ||
|
||
let mut buf = [0; 5]; | ||
u16_to_str(battery_voltage_mv as u16, &mut buf); | ||
let _ = buf.iter().map(|c| block!(tx.write(*c))).last(); | ||
|
||
let s = b" mVolts\r\n"; | ||
let _ = s.iter().map(|c| block!(tx.write(*c))).last(); | ||
|
||
delay.delay_ms(500_u16); | ||
led.toggle(); | ||
} | ||
} | ||
|
||
// function that fills a buffer with the string representation of a number | ||
fn u16_to_str(n: u16, buf: &mut [u8; 5]) { | ||
let mut n = n; | ||
for i in (0..5).rev() { | ||
buf[i] = b'0' + (n % 10) as u8; | ||
n /= 10; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use crate::{ | ||
hal::{ | ||
gpio::{Analog, Pin}, | ||
prelude::_embedded_hal_adc_OneShot, | ||
}, | ||
ADC_POOL, | ||
}; | ||
use battery_sensor_controller::BatterySensorController; | ||
use heapless::pool::arc::Arc; | ||
|
||
/// The battery sensor used to detect the battery level. | ||
/// It uses 1 analog pin connected to the resistor divider and the ADC1 to read the voltage. | ||
pub struct BatterySensor { | ||
/// The pin for the battery sensor | ||
pub sensor_0: Pin<'B', 0, Analog>, | ||
|
||
pub adc: Arc<ADC_POOL>, | ||
} | ||
|
||
impl BatterySensorController for BatterySensor { | ||
fn get_battery_millivolts(&mut self) -> u16 { | ||
let mut adc = self.adc.borrow_mut(); | ||
|
||
// Read the battery voltage, take 10 samples and average them (later, so we don't lose precision): | ||
let mut battery_voltage_by_10: u32 = 0; | ||
for _ in 0..10 { | ||
let sample: u16 = adc.read(&mut self.sensor_0).unwrap(); | ||
battery_voltage_by_10 += sample as u32; | ||
} | ||
|
||
// Convert the voltage to millivolts. We multiply the raw value by the battery voltage and | ||
// divide by the resister divider. The maximum value is 8.4V and the resister divider is | ||
// 47k and 20k. The raw value is 12 bits, so the maximum value is 4096 that corresponds to | ||
// 2.5 volts in the ADC. The formula is: | ||
let raw_to_millivolts_multiplier_by_1000 = 2857; | ||
let battery_voltage_mv = | ||
(battery_voltage_by_10 * raw_to_millivolts_multiplier_by_1000 / 10000) as u16; | ||
|
||
battery_voltage_mv | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters