diff --git a/esp32/PlantControl.code-workspace b/esp32/PlantControl.code-workspace index 13450eb..fb90e31 100644 --- a/esp32/PlantControl.code-workspace +++ b/esp32/PlantControl.code-workspace @@ -22,7 +22,8 @@ "array": "cpp", "tuple": "cpp", "utility": "cpp", - "fstream": "cpp" + "fstream": "cpp", + "system_error": "cpp" } } } diff --git a/esp32/include/ControllerConfiguration.h b/esp32/include/ControllerConfiguration.h index 1040b78..02aa74b 100644 --- a/esp32/include/ControllerConfiguration.h +++ b/esp32/include/ControllerConfiguration.h @@ -82,9 +82,13 @@ /** \addtogroup Configuration * @{ */ +#define CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE +#define CONFIG_COMPILER_CXX_EXCEPTIONS + + #define FIRMWARE_VERSION "sw 2.0 hw 0.10b" -#define TIMED_LIGHT_PIN CUSTOM1_PIN5 +#define TIMED_LIGHT_PIN CUSTOM1_PIN7 //#define FLOWMETER_PIN CUSTOM1_PIN1 #ifdef FLOWMETER_PIN #define FLOWMETER_FLOWFACTOR 23 /** F = 22 * Q;Q = L/min */ diff --git a/esp32/include/HomieConfiguration.h b/esp32/include/HomieConfiguration.h index 293b4d8..3a0405e 100644 --- a/esp32/include/HomieConfiguration.h +++ b/esp32/include/HomieConfiguration.h @@ -86,6 +86,7 @@ HomieSetting ntpServer("ntpServer", "NTP server (pool.ntp.org as d HomieSetting timedLightStart("LightStart", "hour to start light"); HomieSetting timedLightEnd("LightEnd", "hour to end light"); HomieSetting timedLightOnlyWhenDark("LightOnlyDark", "only enable light, if solar is low"); + HomieSetting timedLightPowerLevel("LightPowerLevel", "0-255 power level"); #endif // TIMED_LIGHT_PIN diff --git a/esp32/include/LogDefines.h b/esp32/include/LogDefines.h index e1fcced..871eef1 100644 --- a/esp32/include/LogDefines.h +++ b/esp32/include/LogDefines.h @@ -31,4 +31,5 @@ #define LOG_SLEEP_NIGHT 100 #define LOG_SLEEP_DAY 101 #define LOG_SLEEP_CYCLE 102 -#define LOG_MISSING_PUMP -4 \ No newline at end of file +#define LOG_MISSING_PUMP -4 +#define LOG_BOOT_ERROR_DETECTION 10000 \ No newline at end of file diff --git a/esp32/include/ulp-pwm.h b/esp32/include/ulp-pwm.h new file mode 100644 index 0000000..778d202 --- /dev/null +++ b/esp32/include/ulp-pwm.h @@ -0,0 +1,188 @@ +#ifndef ULP_PWM_h +#define ILP_PWM_h + +#include +#include "driver/rtc_io.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/rtc.h" +#include "esp32/ulp.h" +#include "ControllerConfiguration.h" + +#define LBL_START 1 +#define LBL_DELAY_ON 2 +#define LBL_DELAY_OFF 3 +#define LBL_SKIP_ON 4 +#define LBL_SKIP_OFF 5 +#define REGISTER_DELAY_LOOP_COUNTER R0 +#define REGISTER_TICKS_ON R1 +#define REGISTER_TICKS_OFF R2 +#define TOTAL_TICKS_DELAY 255 +#define PIN TIMED_LIGHT_PIN + +//support 20 vars +const size_t ulp_var_offset = CONFIG_ULP_COPROC_RESERVE_MEM - 20; +//use the first for dimming +const size_t ulp_dimm_offset = ulp_var_offset + 1; +const size_t ulp_alive_offset = ulp_var_offset + 2; + +//see https://github.com/perseus086/ESP32-notes +const uint32_t rtc_bit[40] = { + 25, //gpio0 + 0, //gpio1 + 26, //gpio2 + 0, //gpio3 + 24, //gpio4 + 0, //gpio5 + 0, //gpio6 + 0, //gpio7 + 0, //gpio8 + 0, //gpio9 + 0, //gpio10 + 0, //gpio11 + 29, //gpio12 + 28, //gpio13 + 30, //gpio14 + 27, //gpio15 + 0, //gpio16 + 31, //gpio17 + 0, //gpio18 + 0, //gpio19 + 0, //gpio20 + 0, //gpio21 + 0, //gpio22 + 0, //gpio23 + 0, //gpio24 + 20, //gpio25 + 21, //gpio26 + 0, //gpio27 + 0, //gpio28 + 0, //gpio29 + 0, //gpio30 + 0, //gpio31 + 23, //gpio32 + 22, //gpio33 + 18, //gpio34 + 19, //gpio35 + 14, //gpio36 + 15, //gpio37 + 16, //gpio38 + 17 //gpio39 +}; + +static inline void ulp_internal_data_write(size_t offset, uint16_t value) +{ + if (offset >= CONFIG_ULP_COPROC_RESERVE_MEM || offset <= ulp_var_offset) + { + Serial.print("Invalid ULP offset detected, refusing write!"); + Serial.print(offset); + Serial.print("-"); + Serial.print(ulp_var_offset); + Serial.print("-"); + Serial.println(CONFIG_ULP_COPROC_RESERVE_MEM); + return; + } + else + { + RTC_SLOW_MEM[offset] = value; + } +} + +static inline uint16_t ulp_internal_data_read(size_t offset) +{ + if (offset >= CONFIG_ULP_COPROC_RESERVE_MEM || offset <= ulp_var_offset) + { + Serial.print("Invalid ULP offset detected"); + Serial.print(offset); + Serial.print("-"); + Serial.print(ulp_var_offset); + Serial.print("-"); + Serial.println(CONFIG_ULP_COPROC_RESERVE_MEM); + } + return RTC_SLOW_MEM[offset] & 0xffff; +} + +static inline uint32_t rtc_io_number_get(gpio_num_t gpio_num) +{ + assert(rtc_gpio_is_valid_gpio(gpio_num) && "Invalid GPIO for RTC"); + uint32_t bit = rtc_bit[gpio_num]; + Serial.print("Resolved GPIO "); + Serial.print(gpio_num); + Serial.print(" to rtc bit "); + Serial.println(bit); + return bit; +} + +void ulp_internal_start(void) +{ + rtc_gpio_init(PIN); + rtc_gpio_set_direction(PIN, RTC_GPIO_MODE_OUTPUT_ONLY); + rtc_gpio_set_level(PIN, 0); + const uint32_t rtc_gpio = rtc_io_number_get(PIN); + + // Define ULP program + const ulp_insn_t ulp_prog[] = { + M_LABEL(LBL_START), + + I_MOVI(REGISTER_DELAY_LOOP_COUNTER, 1), + I_MOVI(REGISTER_TICKS_ON, 0), + I_ST(REGISTER_DELAY_LOOP_COUNTER, REGISTER_TICKS_ON, ulp_alive_offset), //store 1 with 0 offset into alive + + I_LD(REGISTER_TICKS_ON, REGISTER_TICKS_ON, ulp_dimm_offset), //REGISTER_TICKS_ON = RTC_DATA[0+ulp_dimm_offset] + //in total there is always 255 delay loop iterations, but in different duty cycle + I_MOVI(REGISTER_TICKS_OFF, TOTAL_TICKS_DELAY), + I_SUBR(REGISTER_TICKS_OFF, REGISTER_TICKS_OFF, REGISTER_TICKS_ON), + + //on phase + I_MOVR(REGISTER_DELAY_LOOP_COUNTER, REGISTER_TICKS_ON), + M_BL(LBL_SKIP_ON, 1), //if never on, skip on phase + I_WR_REG(RTC_GPIO_OUT_REG, rtc_gpio, rtc_gpio, HIGH), // on + M_LABEL(LBL_DELAY_ON), + I_DELAY(1), //wait 1 clock + I_SUBI(REGISTER_DELAY_LOOP_COUNTER, REGISTER_DELAY_LOOP_COUNTER, 1), // REGISTER_DELAY_LOOP_COUNTER-- + M_BGE(LBL_DELAY_ON, 1), //if time left, goto start of on loop + M_LABEL(LBL_SKIP_ON), + + //off phase + I_MOVR(REGISTER_DELAY_LOOP_COUNTER, REGISTER_TICKS_OFF), + + M_BL(LBL_SKIP_OFF, 1), //if never off, skip on phase + I_WR_REG(RTC_GPIO_OUT_REG, rtc_gpio, rtc_gpio, LOW), // on + M_LABEL(3), + I_DELAY(1), //wait 1 clock + I_SUBI(REGISTER_DELAY_LOOP_COUNTER, REGISTER_DELAY_LOOP_COUNTER, 1), // REGISTER_DELAY_LOOP_COUNTER-- + M_BGE(3, 1), //if time left, goto start of on loop + M_LABEL(LBL_SKIP_OFF), + + M_BX(LBL_START), + }; + // Run ULP program + size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); + assert(size < ulp_var_offset && "ULP_DATA_OFFSET needs to be greater or equal to the program size"); + esp_err_t error = ulp_process_macros_and_load(0, ulp_prog, &size); + Serial.print("ULP bootstrap status "); + Serial.println(error); + + //allow glitchless start + ulp_internal_data_write(ulp_alive_offset, 0); + + error = ulp_run(0); + Serial.print("ULP start status "); + Serial.println(error); +} + +static inline void ulp_pwm_set_level(uint8_t level) +{ + ulp_internal_data_write(ulp_dimm_offset, level); +} + +static inline void ulp_pwm_init() +{ + ulp_internal_data_write(ulp_alive_offset, 0); + delay(10); + if (ulp_internal_data_read(ulp_alive_offset) == 0) + { + ulp_internal_start(); + } +} + +#endif \ No newline at end of file diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index 4d71e09..7100aa9 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -35,12 +35,18 @@ #include #include "driver/pcnt.h" #include "MQTTUtils.h" +#include "esp_ota_ops.h" +#if defined(TIMED_LIGHT_PIN) + #include "ulp-pwm.h" +#endif + /****************************************************************************** * DEFINES ******************************************************************************/ #define AMOUNT_SENOR_QUERYS 8 #define MAX_TANK_DEPTH 2000 +#define REBOOT_LOOP_DETECTION_ERROR 5 /****************************************************************************** * FUNCTION PROTOTYPES @@ -54,9 +60,7 @@ bool determineTimedLightState(bool lowLight); /****************************************************************************** * NON VOLATILE VARIABLES in DEEP SLEEP ******************************************************************************/ - #if defined(TIMED_LIGHT_PIN) -RTC_DATA_ATTR bool timedLightOn = false; /**< allow fast recovery after poweron */ RTC_DATA_ATTR bool timedLightLowVoltageTriggered = false; /**remember if it was shut down due to voltage level */ #endif // TIMED_LIGHT_PIN @@ -104,11 +108,29 @@ Plant mPlants[MAX_PLANTS] = { * LOCAL FUNCTIONS ******************************************************************************/ +void finsihedCycleSucessfully() +{ + const esp_partition_t *running = esp_ota_get_running_partition(); + esp_ota_img_states_t ota_state; + if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) + { + log(LOG_LEVEL_INFO, "Get State Partition was Successfull", LOG_BOOT_ERROR_DETECTION); + if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) + { + log(LOG_LEVEL_INFO, "Diagnostics completed successfully! Marking as valid", LOG_BOOT_ERROR_DETECTION); + esp_ota_mark_app_valid_cancel_rollback(); + } + } +} + void espDeepSleep(bool afterPump = false) { + if (mDownloadMode) { log(LOG_LEVEL_DEBUG, "abort deepsleep, DownloadMode active", LOG_DEBUG_CODE); + //if we manage to get to the download mode, the device can be restored + finsihedCycleSucessfully(); return; } if (aliveWasRead()) @@ -139,10 +161,6 @@ void espDeepSleep(bool afterPump = false) esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON); esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); -#if defined(TIMED_LIGHT_PIN) - gpio_hold_en(TIMED_LIGHT_PIN); -#endif // TIMED_LIGHT_PIN - long secondsToSleep = -1; if (afterPump) @@ -165,6 +183,7 @@ void espDeepSleep(bool afterPump = false) } esp_sleep_enable_timer_wakeup((secondsToSleep * 1000U * 1000U)); + finsihedCycleSucessfully(); if (aliveWasRead()) { delay(1000); @@ -208,7 +227,7 @@ void readOneWireSensors() continue; } - char buf[(sizeof(ds18b20Address) * 2)+1]; /* additional byte for trailing terminator */ + char buf[(sizeof(ds18b20Address) * 2) + 1]; /* additional byte for trailing terminator */ snprintf(buf, sizeof(buf), "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X", ds18b20Address[0], ds18b20Address[1], @@ -639,22 +658,19 @@ void pumpActiveLoop() } } -void safeSetup() +void setup() { - /* reduce power consumption */ setCpuFrequencyMhz(80); Serial.begin(115200); - Serial << "Wifi mode set to " << WIFI_OFF << " to allow analog2 useage " << endl; WiFi.mode(WIFI_OFF); + Serial.flush(); //restore state before releasing pin, to prevent flickering #if defined(TIMED_LIGHT_PIN) - pinMode(TIMED_LIGHT_PIN, OUTPUT); - digitalWrite(TIMED_LIGHT_PIN, timedLightOn); - gpio_hold_dis(TIMED_LIGHT_PIN); + ulp_pwm_init(); #endif // TIMED_LIGHT_PIN /* Intialize Plant */ @@ -733,6 +749,8 @@ void safeSetup() { return (candidate > 0) && (candidate < (20)); }); #if defined(TIMED_LIGHT_PIN) + timedLightPowerLevel.setDefaultValue(25).setValidator([](long candidate) + { return (candidate > 0) && (candidate <= (255)); }); timedLightStart.setDefaultValue(18).setValidator([](long candidate) { return (candidate > 0) && (candidate < (25)); }); timedLightEnd.setDefaultValue(23).setValidator([](long candidate) @@ -825,26 +843,6 @@ void safeSetup() setupFinishedTimestamp = millis(); } -/** - * @brief Startup function - * Is called once, the controller is started - */ -void setup() -{ - try - { - safeSetup(); - } - catch (const std::exception &e) - { - Serial.printf("Exception thrown: \"%s\"", e.what()); - } - catch (...) - { - Serial.println("Other exception thrown."); - } -} - void selfTest() { @@ -974,8 +972,18 @@ void plantcontrol() Serial.println("Skipping MQTT, offline mode"); Serial.flush(); } - bool isLowLight = (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE); + +#if defined(TIMED_LIGHT_PIN) + bool shouldLight = determineTimedLightState(isLowLight); + if(shouldLight){ + ulp_pwm_set_level(timedLightPowerLevel.get()); + }else { + ulp_pwm_set_level(0); + } + +#endif // TIMED_LIGHT_PIN + bool hasWater = true; //FIXME remaining > waterLevelMin.get(); //FIXME no water warning message pumpToRun = determineNextPump(isLowLight); @@ -1002,12 +1010,6 @@ void plantcontrol() { espDeepSleep(); } - -#if defined(TIMED_LIGHT_PIN) - bool shouldLight = determineTimedLightState(isLowLight); - timedLightOn = shouldLight; - digitalWrite(TIMED_LIGHT_PIN, shouldLight); -#endif // TIMED_LIGHT_PIN } /** @}*/ @@ -1032,11 +1034,14 @@ bool determineTimedLightState(bool lowLight) return false; } - if (((hoursStart > hoursEnd) && - (getCurrentHour() >= hoursStart || getCurrentHour() <= hoursEnd)) || - /* Handle e.g. start = 8, end = 21 */ + int curHour = getCurrentHour(); + bool condition1 = ((hoursStart > hoursEnd) && + (curHour >= hoursStart || curHour <= hoursEnd)); + bool condition2 = /* Handle e.g. start = 8, end = 21 */ ((hoursStart < hoursEnd) && - (getCurrentHour() >= hoursStart && getCurrentHour() <= hoursEnd))) + (curHour >= hoursStart && curHour <= hoursEnd)); + timedLightNode.setProperty("debug").send(String(curHour) + " " + String(hoursStart) + " " + String(hoursEnd) + " " + String(condition1) + " " + String(condition2)); + if (condition1 || condition2) { bool voltageOk = !timedLightLowVoltageTriggered && battery.getVoltage(BATTSENSOR_INDEX_BATTERY) >= timedLightVoltageCutoff.get(); if (voltageOk || equalish(timedLightVoltageCutoff.get(), -1)) diff --git a/esp32test/Esp32DeepSleepTest/include/DS2438.h b/esp32test/Esp32DeepSleepTest/include/DS2438.h deleted file mode 100644 index 0809015..0000000 --- a/esp32test/Esp32DeepSleepTest/include/DS2438.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * DS2438.h - * - * by Joe Bechter - * - * (C) 2012, bechter.com - * - * All files, software, schematics and designs are provided as-is with no warranty. - * All files, software, schematics and designs are for experimental/hobby use. - * Under no circumstances should any part be used for critical systems where safety, - * life or property depends upon it. You are responsible for all use. - * You are free to use, modify, derive or otherwise extend for your own non-commercial purposes provided - * 1. No part of this software or design may be used to cause injury or death to humans or animals. - * 2. Use is non-commercial. - * 3. Credit is given to the author (i.e. portions © bechter.com), and provide a link to the original source. - * - */ - -#ifndef DS2438_h -#define DS2438_h - -#include -#include - -#define DS2438_TEMPERATURE_CONVERSION_COMMAND 0x44 -#define DS2438_VOLTAGE_CONVERSION_COMMAND 0xb4 -#define DS2438_WRITE_SCRATCHPAD_COMMAND 0x4e -#define DS2438_COPY_SCRATCHPAD_COMMAND 0x48 -#define DS2438_READ_SCRATCHPAD_COMMAND 0xbe -#define DS2438_RECALL_MEMORY_COMMAND 0xb8 - -#define PAGE_MIN 0 -#define PAGE_MAX 7 - -#define DS2438_CHA 0 -#define DS2438_CHB 1 - -#define DS2438_MODE_CHA 0x01 -#define DS2438_MODE_CHB 0x02 -#define DS2438_MODE_TEMPERATURE 0x04 - -#define DS2438_TEMPERATURE_DELAY 10 -#define DS2438_VOLTAGE_CONVERSION_DELAY 8 - -#define DEFAULT_PAGE0(var) uint8_t var[8] { \ - 0b00001011 /* X, ADB=0, NVB=0, TB=0, AD=1, EE=0, CA=1, IAD=1 */, \ - 0, /* Temperatur */ \ - 0, /* Temperatur */ \ - 0, /* Voltage */ \ - 0, /* Voltage */ \ - 0, /* Current */ \ - 0, /* Current */ \ - 0 /* Threashold */ \ -} - -typedef struct PageOne { - uint8_t eleapsedTimerByte0; /**< LSB of timestamp */ - uint8_t eleapsedTimerByte1; - uint8_t eleapsedTimerByte2; - uint8_t eleapsedTimerByte3; /**< MSB of timestamp */ - uint8_t ICA; /**< Integrated Current Accumulator (current flowing into and out of the battery) */ - uint8_t offsetRegisterByte0; /**< Offset for ADC calibdation */ - uint8_t offsetRegisterByte1; /**< Offset for ADC calibdation */ - uint8_t reserved; -} PageOne_t; - -typedef struct PageSeven { - uint8_t userByte0; - uint8_t userByte1; - uint8_t userByte2; - uint8_t userByte3; - uint8_t CCA0; /**< Charging Current Accumulator (CCA) */ - uint8_t CCA1; /**< Charging Current Accumulator (CCA) */ - uint8_t DCA0; /**< Discharge Current Accumulator (DCA) */ - uint8_t DCA1; /**< Discharge Current Accumulator (DCA) */ -} PageSeven_t; - -typedef uint8_t DeviceAddress[8]; - -class DS2438 { - public: - DS2438(OneWire *ow, float currentShunt); - DS2438(OneWire *ow, uint8_t *address); - - void begin(); - void update(); - double getTemperature(); - float getVoltage(int channel=DS2438_CHA); - float getCurrent(); - boolean isError(); - boolean isFound(); - private: - bool validAddress(const uint8_t*); - bool validFamily(const uint8_t* deviceAddress); - - bool deviceFound = false; - OneWire *_ow; - DeviceAddress _address; - uint8_t _mode; - double _temperature; - float _voltageA; - float _voltageB; - float _current; - float _currentShunt; - boolean _error; - boolean startConversion(int channel, boolean doTemperature); - boolean selectChannel(int channel); - void writePage(int page, uint8_t *data); - boolean readPage(int page, uint8_t *data); -}; - -#endif \ No newline at end of file diff --git a/esp32test/Esp32DeepSleepTest/include/ulp-pwm.h b/esp32test/Esp32DeepSleepTest/include/ulp-pwm.h new file mode 100644 index 0000000..15f5d35 --- /dev/null +++ b/esp32test/Esp32DeepSleepTest/include/ulp-pwm.h @@ -0,0 +1,187 @@ +#ifndef ULP_PWM_h +#define ILP_PWM_h + +#include +#include "driver/rtc_io.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/rtc.h" +#include "esp32/ulp.h" + +#define LBL_START 1 +#define LBL_DELAY_ON 2 +#define LBL_DELAY_OFF 3 +#define LBL_SKIP_ON 4 +#define LBL_SKIP_OFF 5 +#define REGISTER_DELAY_LOOP_COUNTER R0 +#define REGISTER_TICKS_ON R1 +#define REGISTER_TICKS_OFF R2 +#define TOTAL_TICKS_DELAY 255 +#define PIN GPIO_NUM_12 + +//support 20 vars +const size_t ulp_var_offset = CONFIG_ULP_COPROC_RESERVE_MEM - 20; +//use the first for dimming +const size_t ulp_dimm_offset = ulp_var_offset + 1; +const size_t ulp_alive_offset = ulp_var_offset + 2; + +//see https://github.com/perseus086/ESP32-notes +const uint32_t rtc_bit[40] = { + 25, //gpio0 + 0, //gpio1 + 26, //gpio2 + 0, //gpio3 + 24, //gpio4 + 0, //gpio5 + 0, //gpio6 + 0, //gpio7 + 0, //gpio8 + 0, //gpio9 + 0, //gpio10 + 0, //gpio11 + 29, //gpio12 + 28, //gpio13 + 30, //gpio14 + 27, //gpio15 + 0, //gpio16 + 31, //gpio17 + 0, //gpio18 + 0, //gpio19 + 0, //gpio20 + 0, //gpio21 + 0, //gpio22 + 0, //gpio23 + 0, //gpio24 + 20, //gpio25 + 21, //gpio26 + 0, //gpio27 + 0, //gpio28 + 0, //gpio29 + 0, //gpio30 + 0, //gpio31 + 23, //gpio32 + 22, //gpio33 + 18, //gpio34 + 19, //gpio35 + 14, //gpio36 + 15, //gpio37 + 16, //gpio38 + 17 //gpio39 +}; + +static inline void ulp_data_write(size_t offset, uint16_t value) +{ + if (offset >= CONFIG_ULP_COPROC_RESERVE_MEM || offset <= ulp_var_offset) + { + Serial.print("Invalid ULP offset detected, refusing write!"); + Serial.print(offset); + Serial.print("-"); + Serial.print(ulp_var_offset); + Serial.print("-"); + Serial.println(CONFIG_ULP_COPROC_RESERVE_MEM); + return; + } + else + { + RTC_SLOW_MEM[offset] = value; + } +} + +static inline uint16_t ulp_data_read(size_t offset) +{ + if (offset >= CONFIG_ULP_COPROC_RESERVE_MEM || offset <= ulp_var_offset) + { + Serial.print("Invalid ULP offset detected"); + Serial.print(offset); + Serial.print("-"); + Serial.print(ulp_var_offset); + Serial.print("-"); + Serial.println(CONFIG_ULP_COPROC_RESERVE_MEM); + } + return RTC_SLOW_MEM[offset] & 0xffff; +} + +static inline uint32_t rtc_io_number_get(gpio_num_t gpio_num) +{ + assert(rtc_gpio_is_valid_gpio(gpio_num) && "Invalid GPIO for RTC"); + uint32_t bit = rtc_bit[gpio_num]; + Serial.print("Resolved GPIO "); + Serial.print(gpio_num); + Serial.print(" to rtc bit "); + Serial.println(bit); + return bit; +} + +void ulp_pwm_start(void) +{ + rtc_gpio_init(PIN); + rtc_gpio_set_direction(PIN, RTC_GPIO_MODE_OUTPUT_ONLY); + rtc_gpio_set_level(PIN, 0); + const uint32_t rtc_gpio = rtc_io_number_get(PIN); + + // Define ULP program + const ulp_insn_t ulp_prog[] = { + M_LABEL(LBL_START), + + I_MOVI(REGISTER_DELAY_LOOP_COUNTER, 1), + I_MOVI(REGISTER_TICKS_ON, 0), + I_ST(REGISTER_DELAY_LOOP_COUNTER, REGISTER_TICKS_ON, ulp_alive_offset), //store 1 with 0 offset into alive + + I_LD(REGISTER_TICKS_ON, REGISTER_TICKS_ON, ulp_dimm_offset), //REGISTER_TICKS_ON = RTC_DATA[0+ulp_dimm_offset] + //in total there is always 255 delay loop iterations, but in different duty cycle + I_MOVI(REGISTER_TICKS_OFF, TOTAL_TICKS_DELAY), + I_SUBR(REGISTER_TICKS_OFF, REGISTER_TICKS_OFF, REGISTER_TICKS_ON), + + //on phase + I_MOVR(REGISTER_DELAY_LOOP_COUNTER, REGISTER_TICKS_ON), + M_BL(LBL_SKIP_ON, 1), //if never on, skip on phase + I_WR_REG(RTC_GPIO_OUT_REG, rtc_gpio, rtc_gpio, HIGH), // on + M_LABEL(LBL_DELAY_ON), + I_DELAY(1), //wait 1 clock + I_SUBI(REGISTER_DELAY_LOOP_COUNTER, REGISTER_DELAY_LOOP_COUNTER, 1), // REGISTER_DELAY_LOOP_COUNTER-- + M_BGE(LBL_DELAY_ON, 1), //if time left, goto start of on loop + M_LABEL(LBL_SKIP_ON), + + //off phase + I_MOVR(REGISTER_DELAY_LOOP_COUNTER, REGISTER_TICKS_OFF), + + M_BL(LBL_SKIP_OFF, 1), //if never off, skip on phase + I_WR_REG(RTC_GPIO_OUT_REG, rtc_gpio, rtc_gpio, LOW), // on + M_LABEL(3), + I_DELAY(1), //wait 1 clock + I_SUBI(REGISTER_DELAY_LOOP_COUNTER, REGISTER_DELAY_LOOP_COUNTER, 1), // REGISTER_DELAY_LOOP_COUNTER-- + M_BGE(3, 1), //if time left, goto start of on loop + M_LABEL(LBL_SKIP_OFF), + + M_BX(LBL_START), + }; + // Run ULP program + size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); + assert(size < ulp_var_offset && "ULP_DATA_OFFSET needs to be greater or equal to the program size"); + esp_err_t error = ulp_process_macros_and_load(0, ulp_prog, &size); + Serial.print("ULP bootstrap status "); + Serial.println(error); + + //allow glitchless start + ulp_data_write(ulp_alive_offset, 0); + + error = ulp_run(0); + Serial.print("ULP start status "); + Serial.println(error); +} + +static inline void ulp_pwm_set_level(uint8_t level) +{ + ulp_data_write(ulp_dimm_offset, level); +} + +static inline void ulp_pwm_init() +{ + ulp_data_write(ulp_alive_offset, 0); + delay(10); + if (ulp_data_read(ulp_alive_offset) == 0) + { + ulp_pwm_start(); + } +} + +#endif \ No newline at end of file diff --git a/esp32test/Esp32DeepSleepTest/src/main.cpp b/esp32test/Esp32DeepSleepTest/src/main.cpp index 8d05b45..f463918 100644 --- a/esp32test/Esp32DeepSleepTest/src/main.cpp +++ b/esp32test/Esp32DeepSleepTest/src/main.cpp @@ -1,90 +1,30 @@ #include -#include "driver/pcnt.h" -#include "driver/rtc_io.h" -#include "esp32/ulp.h" -#include "soc/rtc_cntl_reg.h" -#include "soc/rtc.h" +#include "driver/pcnt.h" +#include "ulp-pwm.h" -#define ULP_DATA_OFFSET 200 - -#define ULP_START_OFFSET 0 -void ulp_start(void) { - // Slow memory initialization - //memset(RTC_SLOW_MEM, ULP_START_OFFSET, (8192-ULP_START_OFFSET)); - // GPIO32 initialization (set to output and initial value is 0) - rtc_gpio_init(GPIO_NUM_12); - rtc_gpio_set_direction(GPIO_NUM_12, RTC_GPIO_MODE_OUTPUT_ONLY); - rtc_gpio_set_level(GPIO_NUM_12, 0); - // Define ULP program - const ulp_insn_t ulp_prog[] = { - M_LABEL(1), - - I_MOVI(R2, 0), - I_MOVI(R3, 0), - I_LD(R2, R2, ULP_DATA_OFFSET), - I_LD(R3, R3, ULP_DATA_OFFSET+1), - - - I_WR_REG(RTC_GPIO_OUT_REG, 29, 29, 1), // on - - //wait for 100*r2 - I_MOVR(R0,R2), - M_LABEL(2), - I_DELAY(1), - I_SUBI(R0,R0,1), - M_BGE(2,1), - - I_WR_REG(RTC_GPIO_OUT_REG, 29, 29, 0), // off - - //wait for 100*R3 - I_MOVR(R0,R3), - M_LABEL(3), - I_DELAY(1), - I_SUBI(R0,R0,1), - M_BGE(3,1), - - M_BX(1), - }; - // Run ULP program - size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); - ulp_process_macros_and_load(ULP_START_OFFSET, ulp_prog, &size); - assert(size < ULP_DATA_OFFSET && "ULP_DATA_OFFSET needs to be greater or equal to the program size"); - ulp_run(ULP_START_OFFSET); -} - -static inline void ulp_data_write(size_t offset, uint16_t value) +RTC_SLOW_ATTR uint8_t tick = 0; +RTC_SLOW_ATTR bool dir = true; +void setup() { - RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] = value; -} - -static inline uint16_t ulp_data_read(size_t offset) -{ - return RTC_SLOW_MEM[ULP_DATA_OFFSET + offset] & 0xffff; -} - -void setup() { - Serial.begin(115200); - ulp_data_write(0,1000); - ulp_data_write(1,1000); - ulp_start(); + Serial.println(rtc_io_number_get(GPIO_NUM_12)); + ulp_pwm_init(); + + if (dir) { + tick += 10; + } else { + tick -= 10; + } + ulp_pwm_set_level(tick); + if (tick == 250 || tick == 0) { + dir = !dir; + } + esp_sleep_enable_timer_wakeup(1000000); + Serial.println(ulp_data_read(ulp_dimm_offset)); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - //esp_deep_sleep_start(); + esp_deep_sleep_start(); } +void loop(){ -void loop() { - delay(1000); - Serial.println(ulp_data_read(0)); - ulp_data_write(0, 50); - ulp_data_write(1, 150); - //test = 10; - //test2 = 255-test; - delay(1000); - //test = 50; - //test2 = 255 - test; - ulp_data_write(0, 150); - ulp_data_write(1, 50); - //Serial.print(); - Serial.println("loop"); } \ No newline at end of file