Держи, но написано на esp-idf, третьей версии, если память не изменяет.
main.cpp - основная логика. Библиотеки не прикладываю - их много и ничего интересного там нет - вайфай и отправка по http.
#include "freertos/FreeRTOS.h"
#include "esp_system.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "string.h"
#include "esp_log.h"
#include "wifi.h"
#include "esp_sleep.h"
#include "driver/adc_common.h"
#include "driver/adc.h"
#include "driver/rtc_io.h"
#include "driver/i2c.h"
#include <tmp1075.hpp>
#include "http_communication.hpp"
#include <vector>
#include "esp_pm.h"
#include "esp_sntp.h"
#include "esp32/ulp.h"
#include "ulp_main.h"
#include "ulp/ulp_config.h"
#include "esp32/clk.h"
#include "esp_system.h"
#include "soc/adc_channel.h"
// Отправка лога
// Прочистка основного цикла
extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
static constexpr auto TAG = "main";
//RTC_SLOW_ATTR time_t last_time_sync = 1606641588;
//time_t time_sync_interval = 1000 * 60 * 60 * 24 * 3;
static constexpr int b1 = 25;
static constexpr int b2 = 26;
static constexpr int temp_alert = 14;
struct ulp_temp_log_entry {
uint32_t time;
uint32_t temp;
float f() const {
return tmp1075::tmp1075::raw_to_float((uint16_t)temp);
}
uint32_t t() const {
return time << 16;
}
uint16_t temp_raw() const {
return (uint16_t)temp;
}
};
static void nvs_init() {
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
}
/*static void i2c_master_init() {
int i2c_master_port = I2C_NUM_0;
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = 15;
conf.sda_pullup_en = GPIO_PULLUP_DISABLE;
conf.scl_io_num = 13;
conf.scl_pullup_en = GPIO_PULLUP_DISABLE;
conf.master.clk_speed = 400000;
ESP_ERROR_CHECK(i2c_param_config(i2c_master_port, &conf));
ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0));
}*/
static int read_battery() {
constexpr auto channel = ADC2_CHANNEL_8;// ADC2_GPIO25_CHANNEL;
gpio_num_t adc_gpio_num;
int result;
int sum = 0;
ESP_ERROR_CHECK(adc2_pad_get_io_num(channel, &adc_gpio_num));
ESP_ERROR_CHECK(adc_vref_to_gpio(ADC_UNIT_2, adc_gpio_num));
ESP_ERROR_CHECK(adc2_config_channel_atten(channel, ADC_ATTEN_DB_6));
for (int i = 0; i < 10; i++) {
ESP_ERROR_CHECK(adc2_get_raw(channel, ADC_WIDTH_12Bit, &result));
sum += result;
}
return sum / 10;
}
static void power_config() {
esp_pm_config_esp32_t cfg = {};
cfg.max_freq_mhz = 240;
cfg.min_freq_mhz = 40;
cfg.light_sleep_enable = true;
esp_pm_configure(&cfg);
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); // ULP
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF); // нужно для fast boot
//esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF); // нужно для работы ULP
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_OFF);
}
// static void time_sync() {
// auto t = time(nullptr);
// if (esp_sleep_get_wakeup_cause() == 0 || t < last_time_sync || t - time_sync_interval > last_time_sync) {
// setenv("TZ", "Europe/Moscow", true);
// tzset();
// sntp_setoperatingmode(SNTP_OPMODE_POLL);
// sntp_setservername(0, "pool.ntp.org");
// sntp_init();
// int retry = 0;
// const int retry_count = 200;
// while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
// vTaskDelay(100 / portTICK_PERIOD_MS);
// }
// if (retry < retry_count) {
// ESP_LOGI(TAG, "Time sync success (%d/%d)", retry, retry_count);
// last_time_sync = time(nullptr);
// } else {
// ESP_LOGI(TAG, "Time sync fail");
// }
// }
// }
static void init_ulp_program(void) {
esp_err_t err = ulp_load_binary(0, ulp_main_bin_start,
(ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
ESP_ERROR_CHECK(err);
rtc_gpio_init((gpio_num_t)SDA_GPIO);
rtc_gpio_init((gpio_num_t)SCL_GPIO);
rtc_gpio_set_direction((gpio_num_t)SDA_GPIO, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_set_direction((gpio_num_t)SCL_GPIO, RTC_GPIO_MODE_INPUT_ONLY);
#ifdef ULP_GPIO_TRACE
rtc_gpio_init((gpio_num_t)RUN_GPIO);
rtc_gpio_set_level((gpio_num_t)RUN_GPIO, 0);
rtc_gpio_set_direction((gpio_num_t)RUN_GPIO, RTC_GPIO_MODE_OUTPUT_ONLY);
#endif
ulp_set_wakeup_period(0, 1000 * 1000 * 30);
}
gpio_num_t disabled_gpio[] = {
GPIO_NUM_12, GPIO_NUM_32, GPIO_NUM_33, GPIO_NUM_34, GPIO_NUM_15, GPIO_NUM_13
};
extern "C" void app_main() {
esp_log_level_set("*", ESP_LOG_WARN);
esp_log_level_set(TAG, ESP_LOG_INFO);
power_config();
auto slowclk_period = esp_clk_slowclk_cal_get();
ESP_LOGI(TAG, "slow clock period %d.%06dus", slowclk_period >> 19, slowclk_period & ((1 << 19) - 1));
std::vector<Variable_for_post> vars;
auto cause = esp_sleep_get_wakeup_cause();
if (cause == 0) {
init_ulp_program();
ulp_low_thr = tmp1075::tmp1075::float_to_raw(120);
ulp_high_thr = tmp1075::tmp1075::float_to_raw(-50);
}
ESP_LOGI(TAG, "wakeup cause: %d; error_cnt: %d",
cause,
(int16_t)ulp_error_cnt
);
if (cause == 6) {
ESP_LOGI(TAG, "ulp wakeup cause is %d", (int16_t)ulp_wakeup_cause);
if ((int16_t)ulp_wakeup_cause == 2 || (int16_t)ulp_wakeup_cause == 1 || (int16_t)ulp_wakeup_cause == 3) {
ulp_temp_log_entry* log = reinterpret_cast<ulp_temp_log_entry*>(&ulp_temp_log);
uint16_t temp_log_start = ((&ulp_temp_log) - RTC_SLOW_MEM);
uint16_t temp_log_count = ((uint16_t)ulp_temp_log_pos - temp_log_start) / 2;
//ESP_LOGI(TAG, "start: %d; pos: %d; count: %d ", temp_log_start, (uint16_t)ulp_temp_log_pos, temp_log_count);
uint32_t time = RTCCNTL.time0;
for (size_t i = 0; i < temp_log_count; i ++) {
auto time_passed_us = ((uint64_t)((time - log[i].t())) * (uint64_t)slowclk_period) >> RTC_CLK_CAL_FRACT;
int32_t time_passed_s = (int64_t)time_passed_us / -1000000ll;
ESP_LOGI(TAG, "%d %f", time_passed_s, log[i].f());
vars.emplace_back("temp", log[i].f(), time_passed_s);
}
if (temp_log_count > 0) {
auto temp = log[temp_log_count - 1].temp_raw();
constexpr auto step = tmp1075::tmp1075::float_to_raw(1);
ulp_low_thr = temp - step;
ulp_high_thr = temp + step;
} else {
ulp_low_thr = tmp1075::tmp1075::float_to_raw(120);
ulp_high_thr = tmp1075::tmp1075::float_to_raw(-50);
}
ulp_temp_log_pos = 0;
}
adc_power_acquire();
vars.emplace_back("battery", read_battery());
adc_power_release();
nvs_init();
wifi_init();
// time_sync();
HTTP_communication::post_variables(vars, 1000);
wifi_stop();
nvs_flash_deinit();
}
ESP_LOGI(TAG, "going to sleep");
for (auto g: disabled_gpio) {
rtc_gpio_isolate(g);
}
//esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());
esp_deep_sleep_disable_rom_logging();
if (cause == 0) ESP_ERROR_CHECK(ulp_run(&ulp_entry - RTC_SLOW_MEM));
esp_deep_sleep_start();
//esp_deep_sleep(1000ull * 1000 * 60);
//esp_deep_sleep(1000ull * 1000 * 60 * 60);
}
main.S - основная программа ULP проца
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"
#include "stack.S"
#include "rtc.S"
#include "ulp_config.h"
#include "util.S"
.macro my_halt continuation
move r3, startup_addr
move r2, \continuation
st r2, r3, 0
#ifdef ULP_GPIO_TRACE
clear_gpio(RUN_RTC_GPIO)
#endif
halt
.endm
.data
.global error_cnt
error_cnt: .long 0
.global wakeup_cause
wakeup_cause: .long 9999
.bss
stack:
.skip 200
.global stackEnd
stackEnd:
.long 0
.global low_thr
low_thr: .long 0
.global high_thr
high_thr: .long 0
.global temp_log
temp_log: .space TEMP_LOG_SIZE * 8 // значение + таймстамп
.global temp_log_pos
temp_log_pos: .long 0
startup_addr: .long 0
.text
.global entry
entry:
#ifdef ULP_GPIO_TRACE
set_gpio(RUN_RTC_GPIO)
#endif
move r3, startup_addr
ld r0, r3, 0
jumpr first_run, 1, lt
jump r0
first_run:
move r3, temp_log_pos
move r2, temp_log
st r2, r3, 0
start_conversion_stage:
move r3,stackEnd // Инициируем стек вызовов
psr
jump tmp1075_trigger_OC // Запускаем датчик температуры
move r0,r2 // test for error
jumpr tmp_fail, 1, ge
my_halt read_temp_stage
read_temp_stage:
update_rtc_time
move r3,stackEnd // Инициируем стек вызовов
psr
jump tmp1075_read_temp_reg // Запускаем датчик температуры
move r0,r2 // test for error
jumpr tmp_fail, 1, ge
move r3, tmp1075_temp
ld r1, r3, 0 // Температура в r1
move r3, temp_log_pos
ld r2, r3, 0
st r1, r2, 4 // Пишем температуру
check_rtc_time_valid
read_rtc_reg1 // Читаем время в r0
st r0, r2, 0 // Пишем время
add r2, r2, 2 // temp_log_pos += 2
st r2, r3, 0
sub r0, r3, r2 // В r3 адрес temp_log_pos, следующей строго за temp_log - конец лога
move r3, 3
jumpr wakeup_tagged, 1, lt // По заполнению лога просыпаемся
move r3, low_thr
ld r0, r3, 0 // Нижний порог в r0
sub r0, r1, r0 // r0 = r1 - r0
rsh r0, r0, 15 // r0 >>= 15
move r3, 1
jumpr wakeup_tagged, 0, gt
move r3, high_thr
ld r0, r3, 0 // Верхний порог в r0
sub r0, r1, r0 // r0 = r1 - r0
rsh r0, r0, 15 // r0 >>= 15
move r3, 2
jumpr wakeup_tagged, 0, le
my_halt start_conversion_stage
tmp_fail:
move r1, error_cnt // Загружаемся и рапортуем фейл?
ld r0, r1, 0
add r0, r0, 1
st r0, r1, 0
move r3, 99
//jump wakeup_tagged
wakeup_tagged:
move r2, wakeup_cause
st r3, r2, 0
wakeup: // Read RTC_CNTL_RDY_FOR_WAKEUP bit
READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP)
AND r0, r0, 1
JUMP wakeup, eq // Retry until the bit is set
WAKE // Trigger wake up
//REG_WR 0x006, 24, 24, 0 // Stop ULP timer (clear RTC_CNTL_ULP_CP_SLP_TIMER_EN)
my_halt first_run
.global waitMs
waitMs:
wait 8000
sub r2,r2,1
jump doneWaitMs,eq
jump waitMs
doneWaitMs:
ret
i2c.S
/*
* Demo of I2C ULP routines
*/
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"
#include "stack.S"
#include "ulp_config.h"
/*
* =============================== I2C code ==========================================
* Implementation of pseudo code from
* https://en.wikipedia.org/wiki/I%C2%B2C#Example_of_bit-banging_the_I.C2.B2C_master_protocol
*/
.bss
i2c_started:
.long 0
i2c_didInit:
.long 0
.text
.global i2c_start_cond
.global i2c_stop_cond
.global i2c_write_bit
.global i2c_read_bit
.global i2c_write_byte
.global i2c_read_byte
.macro I2C_delay
wait 10 // 38 // minimal 4.7us
.endm
.macro read_SCL // Return current level of SCL line, 0 or 1
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + SCL_RTCIO, 1)
.endm
.macro read_SDA // Return current level of SDA line, 0 or 1
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S + SDA_RTCIO, 1)
.endm
.macro set_SCL // Do not drive SCL (set pin high-impedance)
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC_S + SCL_RTCIO, 1, 1)
.endm
.macro clear_SCL // Actively drive SCL signal low
// Output mode
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS_S + SCL_RTCIO, 1, 1)
.endm
.macro set_SDA // Do not drive SDA (set pin high-impedance)
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TC_REG, RTC_GPIO_ENABLE_W1TC_S + SDA_RTCIO, 1, 1)
.endm
.macro clear_SDA // Actively drive SDA signal low
// Output mode
WRITE_RTC_REG(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS_S + SDA_RTCIO, 1, 1)
.endm
i2c_start_cond:
move r1,i2c_didInit
ld r0,r1,0
jumpr didInit,1,ge
move r0,1
st r0,r1,0
// set GPIO to pull low when activated
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + SCL_RTCIO, 1, 0)
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S + SDA_RTCIO, 1, 0)
didInit:
move r2,i2c_started
ld r0,r2,0
jumpr not_started,1,lt
// if started, do a restart condition
// set SDA to 1
set_SDA
I2C_delay
set_SCL
clock_stretch: // TODO: Add timeout?
read_SCL
jumpr clock_stretch,1,lt
// Repeated start setup time, minimum 4.7us
I2C_delay
not_started:
// if (read_SDA() == 0) {
// arbitration_lost();
// }
// SCL is high, set SDA from 1 to 0.
clear_SDA
I2C_delay
clear_SCL
move r0,1
st r0,r2,0
ret
i2c_stop_cond:
// set SDA to 0
clear_SDA
I2C_delay
set_SCL
clock_stretch_stop:
read_SCL
jumpr clock_stretch_stop,1,lt
// Stop bit setup time, minimum 4us
I2C_delay
// SCL is high, set SDA from 0 to 1
set_SDA
I2C_delay
// if (read_SDA() == 0) {
// arbitration_lost();
// }
move r2,i2c_started
move r0,0
st r0,r2,0
ret
// Write a bit to I2C bus
i2c_write_bit:
jumpr bit0,1,lt
set_SDA
jump bit1
bit0:
clear_SDA
bit1:
// SDA change propagation delay
I2C_delay
// Set SCL high to indicate a new valid SDA value is available
set_SCL
// Wait for SDA value to be read by slave, minimum of 4us for standard mode
I2C_delay
clock_stretch_write:
read_SCL
jumpr clock_stretch_write,1,lt
// SCL is high, now data is valid
// If SDA is high, check that nobody else is driving SDA
// if (bit && (read_SDA() == 0)) {
// arbitration_lost();
// }
// Clear the SCL to low in preparation for next change
clear_SCL
ret
// Read a bit from I2C bus
i2c_read_bit:
// Let the slave drive data
set_SDA
// Wait for SDA value to be written by slave, minimum of 4us for standard mode
I2C_delay
// Set SCL high to indicate a new valid SDA value is available
set_SCL
clock_stretch_read:
read_SCL
jumpr clock_stretch_read,1,lt
// Wait for SDA value to be written by slave, minimum of 4us for standard mode
I2C_delay
// SCL is high, read out bit
read_SDA
// Set SCL low in preparation for next operation
clear_SCL
ret // bit in r0
// Write a byte to I2C bus. Return 0 if ack by the slave.
i2c_write_byte:
stage_rst
next_bit:
and r0,r2,0x80
psr
jump i2c_write_bit
lsh r2,r2,1
stage_inc 1
jumps next_bit,8,lt
psr
jump i2c_read_bit
ret // nack
// Read a byte from I2C bus
i2c_read_byte:
push r2
move r2,0
stage_rst
next_bit_read:
psr
jump i2c_read_bit
lsh r2,r2,1
or r2,r2,r0
stage_inc 1
jumps next_bit_read,8,lt
pop r0
psr
jump i2c_write_bit
move r0,r2
ret
i2c-util.S
/*
* I2C ULP utility routines
*/
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"
#include "stack.S"
.text
write_intro:
psr
jump i2c_start_cond
ld r2,r3,20 // Address
lsh r2,r2,1
psr
jump i2c_write_byte
jumpr popfail,1,ge
ld r2,r3,16 // Register
psr
jump i2c_write_byte
jumpr popfail,1,ge
ret
.global write8
write8:
psr
jump write_intro
write_b:
ld r2,r3,8 // data byte
psr
jump i2c_write_byte
jumpr fail,1,ge
psr
jump i2c_stop_cond
move r2,0 // Ok
ret
.global write16
write16:
psr
jump write_intro
ld r2,r3,8 // data byte 1
rsh r2,r2,8
psr
jump i2c_write_byte
jumpr fail,1,ge
jump write_b
read_intro:
psr
jump i2c_start_cond
ld r2,r3,16 // Address
lsh r2,r2,1
psr
jump i2c_write_byte
jumpr popfail,1,ge
ld r2,r3,12 // Register
psr
jump i2c_write_byte
jumpr popfail,1,ge
psr
jump i2c_start_cond
ld r2,r3,16
lsh r2,r2,1
or r2,r2,1 // Address Read
psr
jump i2c_write_byte
jumpr popfail,1,ge
ret
popfail:
pop r1 // pop caller return address
move r2,1
ret
.global read8
read8:
psr
jump read_intro
move r2,1 // last byte
psr
jump i2c_read_byte
push r0
psr
jump i2c_stop_cond
pop r0
move r2,0 // OK
ret
fail:
move r2,1
ret
.global read16
read16:
psr
jump read_intro
move r2,0
psr
jump i2c_read_byte
push r0
move r2,1 // last byte
psr
jump i2c_read_byte
push r0
psr
jump i2c_stop_cond
pop r0
pop r2 // first byte
lsh r2,r2,8
or r2,r2,r0
move r0,r2
move r2,0 // OK
ret
rtc.S
#include "soc/rtc_cntl_reg.h"
#include "soc/soc_ulp.h"
.macro update_rtc_time
WRITE_RTC_REG(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_S, 1, 1)
.endm
.macro check_rtc_time_valid
loop:
READ_RTC_REG(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID_S, 1)
AND R0, R0, 1
JUMP loop, EQ
.endm
.macro read_rtc_reg0
READ_RTC_REG(RTC_CNTL_TIME0_REG, 0, 16)
.endm
.macro read_rtc_reg1
READ_RTC_REG(RTC_CNTL_TIME0_REG, 16, 16)
.endm
.macro read_rtc_reg2
READ_RTC_REG(RTC_CNTL_TIME1_REG, 0, 16)
.endm
/*
.bss
.global time_reg_1
time_reg_1:
.long 0
.global time_reg_2
time_reg_2:
.long 0
.global time_reg_3
time_reg_3:
.long 0
.text
.global entry
read_time:
//Trigger update of register
WRITE_RTC_REG(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_S, 1, 1)
check_time_valid:
// Check if RTC_CNTL_TIME_VALID bit is 1, otherwise repeat
READ_RTC_REG(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID_S, 1)
AND R0, R0, 1
JUMP check_time_valid, EQ
// Read timer registers
READ_RTC_REG(RTC_CNTL_TIME0_REG, 0, 16)
MOVE R2, time_reg_1
ST R0, R2, 0
READ_RTC_REG(RTC_CNTL_TIME0_REG, 32, 16) ;REG_RD 0x3FF48010, 31, 16
MOVE R2, time_reg_2
ST R0, R2, 0
READ_RTC_REG(RTC_CNTL_TIME1_REG, 0, 16) ;REG_RD 0x3FF48014, 15, 0
MOVE R2, time_reg_3
ST R0, R2, 0*/
stack.S
/*
* ULP stack and subroutine macros
*/
.macro push rx
st \rx,r3,0
sub r3,r3,1
.endm
.macro pop rx
add r3,r3,1
ld \rx,r3,0
.endm
// Prepare subroutine jump, uses scratch register sr
.macro psr sr=r1 pos=.
.set _next2,(\pos+16)
move \sr,_next2
push \sr
.endm
// Return from subroutine
.macro ret sr=r1
pop \sr
jump \sr
.endm
tmp1075.S
#include "stack.S"
.set tmp1075_addr,0b1001000
.set tmp1075_reg_temp,0
.set tmp1075_reg_CFG,1
.set cmd_OC,0b10000001
.bss
.global tmp1075_temp
tmp1075_temp: .long 0
.text
.global tmp1075_trigger_OC
tmp1075_trigger_OC:
move r1, tmp1075_addr
push r1
move r1, tmp1075_reg_CFG
push r1
move r1, cmd_OC
push r1
psr
jump write8
add r3,r3,3
move r0,r2 // test for error
jumpr fail,1,ge
ret
.global tmp1075_read_temp_reg
tmp1075_read_temp_reg:
move r1, tmp1075_addr
push r1
move r1, tmp1075_reg_temp
push r1
psr
jump read16
add r3,r3,2 // remove call parameters from stack
move r1,r0 // save result
move r0,r2 // test for error
jumpr fail,1,ge
move r2,tmp1075_temp // store result
st r1,r2,0
move r2, 0 // ok
ret
fail:
ret
ulp_config.h
//#define ULP_GPIO_TRACE
#define SCL_GPIO 4
#define SDA_GPIO 0
#define SCL_RTCIO 10
#define SDA_RTCIO 11
#define TEMP_LOG_SIZE 180
#define UPDATE_INTERVAL // Посчитать
#define RUN_RTC_GPIO 10
#define RUN_GPIO 4
util.S
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"
.macro set_gpio num
WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + \num, 1, 1)
.endm
.macro clear_gpio num
WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S + \num, 1, 1)
.endm
На плате esp32S от ai-thinker (низкий минимальный порог напряжения питания), tmp1075(дешевый на тот момент, простой в программировании), и батарейки.