-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #108 from SJSURoboticsTeam/scd40-driver-libhal-2.0
Scd40 driver libhal-science-2.0
- Loading branch information
Showing
5 changed files
with
274 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#pragma once | ||
|
||
#include <libhal-util/i2c.hpp> | ||
#include <libhal-util/serial.hpp> | ||
#include "scd40.hpp" | ||
|
||
scd40::create(hal::i2c& p_i2c, hal::steady_clock& clock){ | ||
scd40 scd40 = scd40(p_i2c, clock); | ||
HAL_CHECK(scd40.start()) | ||
|
||
} | ||
|
||
scd40::start(){} | ||
|
||
scd40::get_CO2{} | ||
|
||
scd40::get_RH(){} | ||
|
||
scd40::get_temp(){} |
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,51 @@ | ||
#include <libhal-armcortex/dwt_counter.hpp> | ||
#include <libhal-armcortex/startup.hpp> | ||
#include <libhal-armcortex/system_control.hpp> | ||
#include <libhal-util/serial.hpp> | ||
#include <libhal-util/steady_clock.hpp> | ||
#include <libhal/units.hpp> | ||
|
||
#include "../../platform-implementations/scd40.hpp" | ||
#include "../hardware_map.hpp" | ||
|
||
using namespace hal::literals; | ||
using namespace std::chrono_literals; | ||
namespace sjsu::science { | ||
|
||
hal::status application(application_framework& p_framework) | ||
{ | ||
// configure drivers | ||
auto& i2c2 = *p_framework.i2c; | ||
auto& clock = *p_framework.steady_clock; | ||
auto& terminal = *p_framework.terminal; | ||
|
||
auto scd40_sensor = HAL_CHECK(scd40::create(i2c2, clock)); | ||
|
||
while(true){ | ||
//get settings test | ||
// scd40_sensor.stop(); | ||
// auto get = HAL_CHECK(scd40_sensor.get_settings()); | ||
// auto temp = get.temp_offset; | ||
// auto alt = get.altitude; | ||
// hal::print<64>(terminal, "%-5.2f\t%-5.2f\n", temp, alt); | ||
|
||
// periodic readings are only updated every 5000ms (temperature) | ||
hal::delay(clock, 5000ms); | ||
auto rd = HAL_CHECK(scd40_sensor.read()); | ||
auto co2_levels = rd.co2; | ||
auto temp = rd.temp; | ||
auto RH_levels = rd.rh; | ||
|
||
|
||
// hal::print<64>(terminal, "%-5.2f\t%-5.2f\t%-5.2f\n", co2_levels, temp, RH_levels); | ||
// hal::delay(clock, 500ms); | ||
|
||
hal::print<64>(terminal, "CO2 Levels: %f\n", co2_levels); | ||
hal::print<64>(terminal, "Temperature %f\n", temp); | ||
hal::print<64>(terminal, "RH Levels: %f\n", RH_levels); | ||
|
||
} | ||
|
||
return hal::success(); | ||
} | ||
} // namespace sjsu::science |
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,129 @@ | ||
// #pragma once | ||
|
||
#include "scd40.hpp" | ||
|
||
using namespace std::chrono_literals; | ||
using scd40_nm = sjsu::science::scd40; | ||
|
||
|
||
scd40_nm::scd40(hal::i2c& p_i2c, hal::steady_clock& p_clock) : m_i2c(p_i2c), m_clock(p_clock) {} | ||
|
||
hal::result<scd40_nm> scd40_nm::create(hal::i2c& p_i2c, hal::steady_clock& clock){ | ||
scd40 scd40(p_i2c, clock); | ||
HAL_CHECK(scd40.start()); | ||
return scd40; | ||
|
||
} | ||
|
||
hal::status scd40_nm::start(){ | ||
std::array<hal::byte, 2> start_address = { start_periodic_measurement_first_half, start_periodic_measurement_second_half }; | ||
HAL_CHECK(hal::write(m_i2c, addresses::device_address, start_address, hal::never_timeout())); | ||
return hal::success(); | ||
} | ||
|
||
hal::result<scd40_nm::scd40_read_data> scd40_nm::read() { | ||
std::array<hal::byte, 2> read_address = {read_measurement_first_half, read_measurement_second_half }; | ||
std::array<hal::byte, 9> buffer; | ||
|
||
HAL_CHECK(hal::write(m_i2c,addresses::device_address, read_address)); | ||
hal::delay(m_clock, 1ms); | ||
HAL_CHECK(hal::read(m_i2c, addresses::device_address, buffer, hal::never_timeout())); | ||
|
||
scd40_nm::scd40_read_data rd; | ||
rd.co2 = buffer[0] << 8 | buffer[1]; | ||
rd.temp = (-45 + 175.0*(buffer[3] << 8 | buffer[4])/ (1 << 16)); | ||
rd.rh = 100.0 * (buffer[6] << 8 | buffer[7]) / (1 << 16); | ||
|
||
return rd; | ||
} | ||
|
||
hal::status scd40_nm::stop() { | ||
std::array<hal::byte, 2> stop_address = { stop_periodic_measurement_first_half, stop_periodic_measurement_second_half }; | ||
HAL_CHECK(hal::write(m_i2c, addresses::device_address, stop_address, hal::never_timeout())); | ||
return hal::success(); | ||
} | ||
|
||
hal::result<scd40_nm::scd40_settings> scd40_nm::get_settings() { | ||
std::array<hal::byte, 2> read_address_temp = {get_temperature_offset_first_half, get_temperature_offset_second_half }; | ||
std::array<hal::byte, 2> read_address_alt = { get_sensor_altitude_first_half, get_sensor_altitude_second_half }; | ||
std::array<hal::byte, 6> buffer; | ||
|
||
HAL_CHECK(hal::write(m_i2c,addresses::device_address, read_address_temp)); | ||
hal::delay(m_clock, 1ms); | ||
HAL_CHECK(hal::read(m_i2c, addresses::device_address, buffer, hal::never_timeout())); | ||
|
||
scd40_nm::scd40_settings get; | ||
|
||
get.temp_offset = 175 *(buffer[0] << 8 | buffer[1])/(1 << 16); | ||
|
||
HAL_CHECK(hal::write(m_i2c,addresses::device_address, read_address_alt)); | ||
hal::delay(m_clock, 1ms); | ||
HAL_CHECK(hal::read(m_i2c, addresses::device_address, buffer, hal::never_timeout())); | ||
get.altitude = buffer[0]<<8 | buffer[1]; | ||
|
||
return get; | ||
} | ||
|
||
hal::status scd40_nm::set_settings( struct settings setting) { | ||
if(setting.set_temp != 0){ | ||
int temp = int(((setting.set_temp*(1<<16)) / 175)) ; | ||
hal::byte temp_first_half = (temp) >> 8; | ||
hal::byte temp_second_half = temp & 0xff; | ||
std::array<hal::byte, 4> set_temp_address = {set_temperature_offset_first_half, set_temperature_offset_second_half, temp_first_half, temp_second_half}; | ||
HAL_CHECK(hal::write(m_i2c,addresses::device_address,set_temp_address)); | ||
hal::delay(m_clock, 1ms); | ||
} | ||
if(setting.set_pressure != -1){ | ||
int pressure = int(setting.set_pressure/100); | ||
hal::byte pressure_first_half = (pressure) >> 8; | ||
hal::byte pressure_second_half = pressure & 0xff; | ||
std::array<hal::byte, 4> set_pressure_address = {set_ambient_pressure_first_half, set_ambient_pressure_second_half, pressure_first_half, pressure_second_half}; | ||
HAL_CHECK(hal::write(m_i2c,addresses::device_address,set_pressure_address)); | ||
hal::delay(m_clock, 1ms); | ||
} else if(setting.set_alt != 0){ | ||
int alt = int(setting.set_alt); | ||
hal::byte alt_first_half = (alt) >> 8; | ||
hal::byte alt_second_half = alt & 0xff; | ||
std::array<hal::byte, 4> set_alt_address = {set_sensor_altitude_first_half, set_sensor_altitude_second_half, alt_first_half, alt_second_half}; | ||
HAL_CHECK(hal::write(m_i2c,addresses::device_address,set_alt_address)); | ||
hal::delay(m_clock, 1ms); | ||
} | ||
|
||
return hal::success(); | ||
} | ||
|
||
hal::byte scd40_nm::generate_crc(std::array<hal::byte, 2> data){ | ||
uint16_t current_byte; | ||
uint8_t crc_bit; | ||
uint8_t crc = 0xFF; | ||
uint8_t CRC8_POLYNOMIAL = 0x31; | ||
|
||
for (current_byte = 0; current_byte < 2 ; ++current_byte) { | ||
crc ^= (data[current_byte]); | ||
for (crc_bit = 8; crc_bit > 0; --crc_bit) { | ||
if (crc & 0x80) | ||
crc = (crc << 1) ^ CRC8_POLYNOMIAL; | ||
else | ||
crc = (crc << 1); | ||
} | ||
} | ||
return crc; | ||
} | ||
|
||
bool scd40_nm::validate_crc(std::array<hal::byte, 3> data) { | ||
uint16_t current_byte; | ||
uint8_t crc_bit; | ||
uint8_t crc = 0xFF; | ||
uint8_t CRC8_POLYNOMIAL = 0x31; | ||
|
||
for (current_byte = 0; current_byte < 3 ; ++current_byte) { | ||
crc ^= (data[current_byte]); | ||
for (crc_bit = 8; crc_bit > 0; --crc_bit) { | ||
if (crc & 0x80) | ||
crc = (crc << 1) ^ CRC8_POLYNOMIAL; | ||
else | ||
crc = (crc << 1); | ||
} | ||
} | ||
return crc == 0; | ||
} |
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,72 @@ | ||
#pragma once | ||
#include <libhal-util/i2c.hpp> | ||
#include <libhal-util/serial.hpp> | ||
#include <libhal-util/steady_clock.hpp> | ||
#include <libhal/units.hpp> | ||
|
||
|
||
//TODO: maybe later add CRC and config for altitude, ambient pressure, temperature offset (or look at setting persistent values) | ||
|
||
namespace sjsu::science { | ||
class scd40 | ||
{ | ||
private: | ||
|
||
scd40(hal::i2c& p_i2c, hal::steady_clock& p_clock); | ||
hal::i2c& m_i2c; | ||
hal::steady_clock& m_clock; | ||
hal::byte generate_crc(std::array<hal::byte, 2> data); | ||
bool validate_crc(std::array<hal::byte, 3> data); | ||
|
||
|
||
//TODO: revise output type | ||
enum addresses {// deal with hal::byte later | ||
device_address = 0x62, | ||
start_periodic_measurement_first_half = 0x21, | ||
start_periodic_measurement_second_half = 0xb1, | ||
read_measurement_first_half = 0xec, | ||
read_measurement_second_half = 0x05, | ||
stop_periodic_measurement_first_half = 0x3f, | ||
stop_periodic_measurement_second_half = 0x86, | ||
set_temperature_offset_first_half = 0x24, | ||
set_temperature_offset_second_half = 0x1d, | ||
get_temperature_offset_first_half = 0x23, | ||
get_temperature_offset_second_half = 0x18, | ||
set_sensor_altitude_first_half = 0x24, | ||
set_sensor_altitude_second_half = 0x27, | ||
get_sensor_altitude_first_half = 0x23, | ||
get_sensor_altitude_second_half = 0x22, | ||
set_ambient_pressure_first_half = 0xe0, | ||
set_ambient_pressure_second_half = 0x00 | ||
}; | ||
|
||
public: | ||
struct scd40_read_data | ||
{ | ||
double co2; | ||
double temp; | ||
double rh; | ||
}; | ||
|
||
struct settings | ||
{ | ||
float set_temp = 4; | ||
float set_alt = 0; | ||
float set_pressure = -1; | ||
}; | ||
|
||
struct scd40_settings | ||
{ | ||
float temp_offset; | ||
float altitude; | ||
}; | ||
|
||
static hal::result<scd40> create(hal::i2c& p_i2c,hal::steady_clock& p_clock); | ||
hal::status start(); | ||
hal::result<scd40_read_data> read(); | ||
hal::status stop(); | ||
hal::result<scd40_settings> get_settings(); | ||
hal::status set_settings( settings setting); | ||
}; | ||
|
||
} // namespace science |