summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-05-18 18:17:14 +1000
committerjacqueline <me@jacqueline.id.au>2023-05-18 18:17:14 +1000
commitb320a6a863cf1c10dc79254af41f573730935564 (patch)
tree00e0624eb34b5347dcf14bde26d708ffb216f834 /src
parentd71f726c42963d55809605b4dc4144970ca0f230 (diff)
downloadtangara-fw-b320a6a863cf1c10dc79254af41f573730935564.tar.gz
Add basic samd class
Diffstat (limited to 'src')
-rw-r--r--src/drivers/CMakeLists.txt2
-rw-r--r--src/drivers/battery.cpp1
-rw-r--r--src/drivers/include/samd.hpp46
-rw-r--r--src/drivers/samd.cpp109
-rw-r--r--src/main/main.cpp11
5 files changed, 168 insertions, 1 deletions
diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt
index 072a8b68..413e1ea0 100644
--- a/src/drivers/CMakeLists.txt
+++ b/src/drivers/CMakeLists.txt
@@ -1,6 +1,6 @@
idf_component_register(
SRCS "touchwheel.cpp" "dac.cpp" "gpio_expander.cpp" "battery.cpp" "storage.cpp" "i2c.cpp"
- "spi.cpp" "display.cpp" "display_init.cpp" "driver_cache.cpp"
+ "spi.cpp" "display.cpp" "display_init.cpp" "driver_cache.cpp" "samd.cpp"
INCLUDE_DIRS "include"
REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span")
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/drivers/battery.cpp b/src/drivers/battery.cpp
index 8d747c07..92b269de 100644
--- a/src/drivers/battery.cpp
+++ b/src/drivers/battery.cpp
@@ -42,6 +42,7 @@ Battery::Battery() {
Battery::~Battery() {
adc_cali_delete_scheme_line_fitting(adc_calibration_handle_);
+ ESP_ERROR_CHECK(adc_oneshot_del_unit(adc_handle_));
}
auto Battery::Millivolts() -> uint32_t {
diff --git a/src/drivers/include/samd.hpp b/src/drivers/include/samd.hpp
new file mode 100644
index 00000000..4ba5877c
--- /dev/null
+++ b/src/drivers/include/samd.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <optional>
+
+namespace drivers {
+
+class Samd {
+ public:
+ Samd();
+ ~Samd();
+
+ enum class ChargeStatus {
+ // There is no battery plugged into the device.
+ kNoBattery,
+ // The battery is discharging, and the current voltage level is very low.
+ kBatteryCritical,
+ // The battery is discharging.
+ kDischarging,
+ // The battery is charging over a low-current USB connection
+ kChargingRegular,
+ // The battery is charging over a high-current USB connection
+ kChargingFast,
+ // The battery is full charged, and we are still plugged in.
+ kFullCharge,
+ };
+
+ auto ReadChargeStatus() -> std::optional<ChargeStatus>;
+
+ enum class UsbMscStatus {
+ // There is no compatible usb host attached.
+ kDetached,
+ // There is a compatible usb host attached, but USB MSC is not currently
+ // in use by the SAMD.
+ kAttachedIdle,
+ // The SAMD is currently exposing the SD card via USB MSC.
+ kAttachedMounted,
+ };
+
+ auto WriteAllowUsbMsc(bool is_allowed) -> void;
+ auto ReadUsbMscStatus() -> UsbMscStatus;
+
+ auto ReadFlashingEnabled() -> bool;
+ auto WriteFlashingEnabled(bool) -> void;
+};
+
+} // namespace drivers
diff --git a/src/drivers/samd.cpp b/src/drivers/samd.cpp
new file mode 100644
index 00000000..3b275c47
--- /dev/null
+++ b/src/drivers/samd.cpp
@@ -0,0 +1,109 @@
+#include "samd.hpp"
+#include <stdint.h>
+#include <optional>
+
+#include "esp_err.h"
+#include "esp_log.h"
+#include "hal/i2c_types.h"
+#include "i2c.hpp"
+
+enum Registers {
+ kRegisterVersion = 0,
+ kRegisterCharge = 1,
+ kRegisterUsbMsc = 2,
+ kRegisterFlashing = 3,
+};
+
+static const uint8_t kAddress = 0x45;
+static const char kTag[] = "SAMD";
+
+namespace drivers {
+
+Samd::Samd() {
+ // Being able to interface with the SAMD properly is critical. To ensure we
+ // will be able to, we begin by checking the I2C protocol version is
+ // compatible, and throw if it's not.
+ uint8_t raw_res = 0;
+ I2CTransaction transaction;
+ transaction.start()
+ .write_addr(kAddress, I2C_MASTER_WRITE)
+ .write_ack(kRegisterVersion)
+ .write_addr(kAddress, I2C_MASTER_READ)
+ .read(&raw_res, I2C_MASTER_NACK)
+ .stop();
+ ESP_LOGI(kTag, "checking samd firmware rev");
+ ESP_ERROR_CHECK(transaction.Execute());
+ ESP_LOGI(kTag, "samd firmware: %u", raw_res);
+}
+Samd::~Samd() {}
+
+auto Samd::ReadChargeStatus() -> std::optional<ChargeStatus> {
+ uint8_t raw_res;
+ I2CTransaction transaction;
+ transaction.start()
+ .write_addr(kAddress, I2C_MASTER_WRITE)
+ .write_ack(kRegisterCharge)
+ .write_addr(kAddress, I2C_MASTER_READ)
+ .read(&raw_res, I2C_MASTER_NACK)
+ .stop();
+ ESP_LOGI(kTag, "checking charge status");
+ ESP_ERROR_CHECK(transaction.Execute());
+ ESP_LOGI(kTag, "raw charge status: %x", raw_res);
+
+ uint8_t usb_state = raw_res & 0b11;
+ uint8_t charge_state = (raw_res >> 2) & 0b111;
+ switch (charge_state) {
+ case 0:
+ return ChargeStatus::kNoBattery;
+ case 1:
+ return usb_state == 1 ? ChargeStatus::kChargingRegular
+ : ChargeStatus::kChargingFast;
+ case 2:
+ return ChargeStatus::kFullCharge;
+ case 4:
+ return ChargeStatus::kBatteryCritical;
+ case 5:
+ return ChargeStatus::kDischarging;
+ case 3:
+ // Fall-through.
+ default:
+ return {};
+ }
+}
+
+auto Samd::WriteAllowUsbMsc(bool is_allowed) -> void {
+ I2CTransaction transaction;
+ transaction.start()
+ .write_addr(kAddress, I2C_MASTER_WRITE)
+ .write_ack(kRegisterUsbMsc, is_allowed)
+ .stop();
+ ESP_ERROR_CHECK(transaction.Execute());
+}
+
+auto Samd::ReadUsbMscStatus() -> UsbMscStatus {
+ return UsbMscStatus::kDetached;
+}
+
+auto Samd::ReadFlashingEnabled() -> bool {
+ uint8_t raw_res;
+ I2CTransaction transaction;
+ transaction.start()
+ .write_addr(kAddress, I2C_MASTER_WRITE)
+ .write_ack(kRegisterVersion)
+ .write_addr(kAddress, I2C_MASTER_READ)
+ .read(&raw_res, I2C_MASTER_NACK)
+ .stop();
+ ESP_ERROR_CHECK(transaction.Execute());
+ return raw_res;
+}
+
+auto Samd::WriteFlashingEnabled(bool is_enabled) -> void {
+ I2CTransaction transaction;
+ transaction.start()
+ .write_addr(kAddress, I2C_MASTER_WRITE)
+ .write_ack(kRegisterFlashing, is_enabled)
+ .stop();
+ ESP_ERROR_CHECK(transaction.Execute());
+}
+
+} // namespace drivers
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 07547713..29ac2c7f 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -31,6 +31,7 @@
#include "gpio_expander.hpp"
#include "i2c.hpp"
#include "lvgl_task.hpp"
+#include "samd.hpp"
#include "spi.hpp"
#include "storage.hpp"
#include "touchwheel.hpp"
@@ -48,6 +49,16 @@ extern "C" void app_main(void) {
ESP_LOGI(TAG, "Init GPIOs");
drivers::GpioExpander* expander = drivers->AcquireGpios();
+ ESP_LOGI(TAG, "Init SAMD comms");
+ drivers::Samd samd;
+ ESP_LOGI(TAG, "It might have worked? Let's read something!");
+ auto res = samd.ReadChargeStatus();
+ if (res) {
+ ESP_LOGI(TAG, "Charge status is %d", static_cast<uint8_t>(*res));
+ } else {
+ ESP_LOGI(TAG, "no charge status?");
+ }
+
ESP_LOGI(TAG, "Enable power rails for development");
expander->with(
[&](auto& gpio) { gpio.set_pin(drivers::GpioExpander::AMP_EN, 1); });