-
Notifications
You must be signed in to change notification settings - Fork 327
Add variant support: Arduino Nesso N1 #1117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
816d4e2
4e886bf
c8a6bcf
3dc04de
f594f2c
86225cd
6ee0b85
f5f5886
3e3fa5b
da5dbcd
b2dcb06
8b68b5a
9405e8b
5ecfa61
018d338
392a7a3
01cbaa0
ff3b84d
ea65b6f
d8ee0f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| #include "ArduinoNessoN1Board.h" | ||
| #include <Arduino.h> | ||
|
|
||
| void ArduinoNessoN1Board::begin() { | ||
| ESP32Board::begin(); | ||
|
|
||
| #ifdef MESH_DEBUG | ||
| // delay for 2s after boot to ensure early output below makes it to the serial logger | ||
| delay(2000); | ||
| #endif | ||
|
|
||
| #ifdef P_LORA_TX_LED | ||
| MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): setup TX LED mode"); | ||
| pinMode(P_LORA_TX_LED, OUTPUT); | ||
| digitalWrite(P_LORA_TX_LED, HIGH); | ||
| #endif | ||
|
|
||
| battery.begin(); | ||
| battery.enableCharge(); | ||
|
|
||
| MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): set Nesso N1 pin modes and default states..."); | ||
| pinMode(LORA_ENABLE, OUTPUT); // RESET | ||
| pinMode(LORA_ANTENNA_SWITCH, OUTPUT); // ANTENNA_SWITCH | ||
| pinMode(LORA_LNA_ENABLE, OUTPUT); // LNA_ENABLE | ||
| pinMode(LCD_BACKLIGHT, OUTPUT); | ||
| pinMode(BEEP_PIN, OUTPUT); | ||
|
|
||
| // Toggle LoRa reset via expander | ||
| MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Enable LoRa..."); | ||
| digitalWrite(LORA_ENABLE, LOW); | ||
| delay(10); | ||
| digitalWrite(LORA_ENABLE, HIGH); | ||
|
|
||
| // Configure antenna switch and LNA | ||
| digitalWrite(LORA_ANTENNA_SWITCH, HIGH); // enable antenna switch | ||
| digitalWrite(LORA_LNA_ENABLE, HIGH); // enable LNA | ||
|
|
||
| // Configure initial state of further devices on expander | ||
| MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Set LCD_BACKLIGHT and BEEP_PIN to low initial state..."); | ||
| digitalWrite(LCD_BACKLIGHT, LOW); | ||
| digitalWrite(BEEP_PIN, LOW); | ||
|
|
||
| // Toggle LCD backlight to show the device has powered on until we get the screen working | ||
| MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Now high..."); | ||
| digitalWrite(LCD_BACKLIGHT, HIGH); | ||
| digitalWrite(BEEP_PIN, HIGH); | ||
| delay(2000); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this delay need to be this long?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Absolutely not; this was just for testing to ensure that the device was waking - as without the screen on it wasn't clear that it was. It'll be gone before I intend for anything to be merged. |
||
| digitalWrite(LCD_BACKLIGHT, LOW); | ||
| digitalWrite(BEEP_PIN, LOW); | ||
| MESH_DEBUG_PRINTLN("ArduinoNessoN1.begin(): Now low..."); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| #pragma once | ||
|
|
||
| #include <Arduino.h> | ||
| #include <MeshCore.h> | ||
| #include <helpers/ESP32Board.h> | ||
| #include "pins_arduino.h" | ||
|
|
||
| #define P_LORA_TX_LED LED_BUILTIN // defined in pins_arduino.h / expander.cpp through pin handling functions specific to the IO expander | ||
| // #define PIN_TFT_RST LCD_RESET | ||
| // #define PIN_TFT_LEDA_CTL LCD_BACKLIGHT | ||
|
|
||
| class ArduinoNessoN1Board : public ESP32Board { | ||
| private: | ||
| NessoBattery battery; | ||
|
|
||
| public: | ||
| void begin(); // Defined in ArduinoNessoN1Board.cpp | ||
|
|
||
| #ifdef P_LORA_TX_LED | ||
| void onBeforeTransmit() override { | ||
| MESH_DEBUG_PRINTLN("onBeforeTransmit: LOW LED for On"); | ||
| digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on | ||
| } | ||
| void onAfterTransmit() override { | ||
| MESH_DEBUG_PRINTLN("onBeforeTransmit: HIGH LED for Off"); | ||
| digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off | ||
| } | ||
| #endif | ||
|
|
||
| const char* getManufacturerName() const override { | ||
| return "Arduino Nesso N1"; | ||
| } | ||
|
|
||
| uint16_t getBattMilliVolts() override { | ||
| #ifdef MESH_DEBUG | ||
| MESH_DEBUG_PRINTLN("getBattMilliVolts(): isCharging(): %u", battery.isCharging()); | ||
| MESH_DEBUG_PRINTLN("getBattMilliVolts(): Current charge level %u %%", battery.getChargeLevel()); | ||
| MESH_DEBUG_PRINTLN("getBattMilliVolts(): Current voltage %f V", battery.getVoltage()); | ||
| MESH_DEBUG_PRINTLN("getBattMilliVolts(): Current voltage %u mV", battery.getMilliVoltage()); | ||
| #endif | ||
| return battery.getMilliVoltage(); | ||
| } | ||
|
|
||
| void reboot() override { | ||
| MESH_DEBUG_PRINTLN("ArduinoNessoN1.reboot(): noop() instead"); | ||
| // esp_restart(); | ||
| } | ||
| }; | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,233 @@ | ||
| #pragma once | ||
| // Based off here https://github.com/espressif/arduino-esp32/blob/d1eb62d7c6dda16c254c374504aa93188d7c386b/variants/arduino_nesso_n1/expander.cpp | ||
| // Should be OK based on this? https://opensource.stackexchange.com/a/6406 | ||
|
|
||
| #include "pins_arduino.h" | ||
| #include <helpers/ESP32Board.h> | ||
| #include <Wire.h> | ||
|
|
||
| static bool wireInitialized = true; // initialised in ESP32Board.begin() ; ToDo: Remove all these conditions in future | ||
| static bool expanderInitialized = false; | ||
|
|
||
| // From https://www.diodes.com/datasheet/download/PI4IOE5V6408.pdf | ||
| static void writeRegister(uint8_t address, uint8_t reg, uint8_t value) { | ||
| Wire.beginTransmission(address); | ||
| Wire.write(reg); | ||
| Wire.write(value); | ||
| Wire.endTransmission(); | ||
| } | ||
|
|
||
| static uint8_t readRegister(uint8_t address, uint8_t reg) { | ||
| Wire.beginTransmission(address); | ||
| Wire.write(reg); | ||
| Wire.endTransmission(false); | ||
| Wire.requestFrom(address, 1); | ||
| return Wire.read(); | ||
| } | ||
|
|
||
| static void writeBitRegister(uint8_t address, uint8_t reg, uint8_t bit, uint8_t value) { | ||
| MESH_DEBUG_PRINTLN("ExpanderPin writeBitRegister(address=%u, reg=%u, bit=%u, value=%u)", address, reg, bit, value); | ||
| uint8_t val = readRegister(address, reg); | ||
| if (value) { | ||
| writeRegister(address, reg, val | (1 << bit)); | ||
| } else { | ||
| writeRegister(address, reg, val & ~(1 << bit)); | ||
| } | ||
| } | ||
|
|
||
| static bool readBitRegister(uint8_t address, uint8_t reg, uint8_t bit) { | ||
| MESH_DEBUG_PRINTLN("ExpanderPin readBitRegister(address=%u, reg=%u, bit=%u)", address, reg, bit); | ||
| uint8_t val = readRegister(address, reg); | ||
| return ((val & (1 << bit)) > 0); | ||
| } | ||
|
|
||
| void pinMode(ExpanderPin pin, uint8_t mode) { | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| // reset all registers to default state | ||
| } | ||
| if (!expanderInitialized) { | ||
| writeRegister(pin.address, 0x1, 0x1); | ||
| // set all pins as high as default state | ||
| writeRegister(pin.address, 0x9, 0xFF); | ||
| // interrupt mask to all pins | ||
| writeRegister(pin.address, 0x11, 0xFF); | ||
| // all input | ||
| writeRegister(pin.address, 0x3, 0); | ||
| expanderInitialized = true; | ||
| } | ||
| MESH_DEBUG_PRINTLN("ExpanderPin pinMode(pin=%u, mode=%u)", pin.pin, mode); | ||
| writeBitRegister(pin.address, 0x3, pin.pin, mode == OUTPUT); | ||
| if (mode == OUTPUT) { | ||
| // remove high impedance | ||
| writeBitRegister(pin.address, 0x7, pin.pin, false); | ||
| } else if (mode == INPUT_PULLUP) { | ||
| // set pull-up resistor | ||
| writeBitRegister(pin.address, 0xB, pin.pin, true); | ||
| writeBitRegister(pin.address, 0xD, pin.pin, true); | ||
| } else if (mode == INPUT_PULLDOWN) { | ||
| // disable pull-up resistor | ||
| writeBitRegister(pin.address, 0xB, pin.pin, true); | ||
| writeBitRegister(pin.address, 0xD, pin.pin, false); | ||
| } else if (mode == INPUT) { | ||
| // disable pull selector resistor | ||
| writeBitRegister(pin.address, 0xB, pin.pin, false); | ||
| } | ||
| } | ||
|
|
||
| void digitalWrite(ExpanderPin pin, uint8_t val) { | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| } | ||
| MESH_DEBUG_PRINTLN("ExpanderPin digitalWrite(%u)", pin.pin); | ||
| writeBitRegister(pin.address, 0x5, pin.pin, val == HIGH); | ||
| } | ||
|
|
||
| int digitalRead(ExpanderPin pin) { | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| } | ||
| MESH_DEBUG_PRINTLN("ExpanderPin digitalRead(%u)", pin.pin); | ||
| return readBitRegister(pin.address, 0xF, pin.pin); | ||
| } | ||
|
|
||
| void NessoBattery::begin() { | ||
| // AW32001E - address 0x49 | ||
| // Spec: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/products/core/LLM630%20Computer%20Kit/AW32001E.pdf | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| } | ||
|
|
||
| uint8_t val = 0; | ||
| val = readRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_CHIP_ID); | ||
| // coarsely check if chip is actually the right chip | ||
| auto res = (val == AW32001_I2C_CHIP_ADDR); | ||
| if (res) { | ||
| val = readRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_CHR_TMR); | ||
| #ifdef MESH_DEBUG | ||
| // Debug output the WatchDog Timer (wdt) state | ||
| MESH_DEBUG_PRINTLN("NessoBattery.begin(): CHR_TMR full register; bits 5,6 are for WDT = %#02x", val); | ||
| #endif | ||
| // disable WatchDog Timer (wdt) | ||
| // take existing register value AND with 00011111 | ||
| val = val & 0x1f; | ||
| writeRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_CHR_TMR, val); | ||
| } | ||
| #ifdef MESH_DEBUG | ||
| else { | ||
| MESH_DEBUG_PRINTLN("NessoBattery.begin(): Register of chip ADDR = %u != I2C of chip %u", AW32001_REG_CHIP_ID, AW32001_I2C_CHIP_ADDR); | ||
| } | ||
| #endif | ||
|
|
||
| // store if chip is initiated by whether it passed above checks and had watchdog disabled | ||
| _power_mgmt_init = res; | ||
| } | ||
|
|
||
| void NessoBattery::enableCharge() { | ||
| // AW32001E - address 0x49 | ||
| // set CEB (charge enable) bit (3) low (0) in AW32001_REG_PWR_CFG (0x01) | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge()"); | ||
|
|
||
| if (_power_mgmt_init) { | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): _power_mgmt_init = true"); | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| } | ||
|
|
||
| bool charge_enable_bit = readBitRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_PWR_CFG, 3); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current charge setting (low is on): %u", charge_enable_bit); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): isCharging(): %u", NessoBattery::isCharging()); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current charge level %u %%", NessoBattery::getChargeLevel()); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current voltage %f V", NessoBattery::getVoltage()); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): Current voltage %u mV", NessoBattery::getMilliVoltage()); | ||
|
|
||
| writeBitRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_PWR_CFG, 3, false); | ||
| } | ||
| #ifdef MESH_DEBUG | ||
| else { | ||
| MESH_DEBUG_PRINTLN("NessoBattery::enableCharge(): _power_mgmt_init is false, won't enable charge"); | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| NessoBattery::ChargeStatus NessoBattery::getChargeStatus(void) { | ||
| uint8_t reg_value = 0; | ||
| if (_power_mgmt_init) | ||
| { | ||
| reg_value = readRegister(AW32001_I2C_CHIP_ADDR, AW32001_REG_SYS_STA); | ||
| // Extract bits 4 and 3 for charge status | ||
| reg_value = (reg_value >> 3) & 0b00000011; // Get bits 4 and 3 | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getChargeStatus(): bits 4 and 3 from register %#02x = %u", AW32001_REG_SYS_STA, reg_value); | ||
| switch (reg_value) | ||
| { | ||
| case 0b00: return CS_NOT_CHARGING; // Not charging | ||
| case 0b01: return CS_PRE_CHARGE; // Pre-charge | ||
| case 0b10: return CS_CHARGE; // Charging | ||
| case 0b11: return CS_CHARGE_DONE; // Charge done | ||
| default: return CS_UNKNOWN; // Unknown state | ||
| } | ||
| } | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getChargeStatus(): failed, probably chip wasn't init"); | ||
| return CS_UNKNOWN; // Return unknown if read failed | ||
| } | ||
|
|
||
| bool NessoBattery::isCharging(void) | ||
| { | ||
| ChargeStatus status = getChargeStatus(); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::isCharging(): ChargeStatus = %u; is? false0/true1 = %u", status, (status == CS_PRE_CHARGE || status == CS_CHARGE)); | ||
| return (status == CS_PRE_CHARGE || status == CS_CHARGE); | ||
| } | ||
|
|
||
| float NessoBattery::getVoltage() { | ||
| // BQ27220 - address 0x55 | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| } | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getVoltage()"); | ||
| uint16_t voltage = (readRegister(0x55, 0x9) << 8) | readRegister(0x55, 0x8); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getVoltage(): %f", voltage / 1000.0f); | ||
| return (float)voltage / 1000.0f; | ||
| } | ||
|
|
||
| uint16_t NessoBattery::getMilliVoltage() { | ||
| // BQ27220 - address 0x55 | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| } | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getMilliVoltage()"); | ||
| uint16_t voltage = (readRegister(0x55, 0x9) << 8) | readRegister(0x55, 0x8); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getMilliVoltage(): %u", voltage); | ||
| return voltage; | ||
| } | ||
|
|
||
| uint16_t NessoBattery::getChargeLevel() { | ||
| // BQ27220 - address 0x55 | ||
| if (!wireInitialized) { | ||
| Wire.begin(SDA, SCL); | ||
| wireInitialized = true; | ||
| } | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getChargeLevel()"); | ||
| uint16_t current_capacity = readRegister(0x55, 0x11) << 8 | readRegister(0x55, 0x10); | ||
| uint16_t total_capacity = readRegister(0x55, 0x13) << 8 | readRegister(0x55, 0x12); | ||
| MESH_DEBUG_PRINTLN("NessoBattery::getChargeLevel(): curr = %u / total = %u; pct = %u %%", current_capacity, total_capacity, ((current_capacity * 100) / total_capacity)); | ||
| return (current_capacity * 100) / total_capacity; | ||
| } | ||
|
|
||
| ExpanderPin LORA_LNA_ENABLE(5); | ||
| ExpanderPin LORA_ANTENNA_SWITCH(6); | ||
| ExpanderPin LORA_ENABLE(7); | ||
| ExpanderPin KEY1(0); | ||
| ExpanderPin KEY2(1); | ||
| ExpanderPin POWEROFF((1 << 8) | 0); | ||
| ExpanderPin LCD_RESET((1 << 8) | 1); | ||
| ExpanderPin GROVE_POWER_EN((1 << 8) | 2); | ||
| ExpanderPin VIN_DETECT((1 << 8) | 5); | ||
| ExpanderPin LCD_BACKLIGHT((1 << 8) | 6); | ||
| ExpanderPin LED_BUILTIN((1 << 8) | 7); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reset the changes to these .md files. Looks like these diffs were inherited from the main branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah; yeah I forked from the
mainbranch; so will see if I can rebase todev