ulp: use timer to start ULP, fix I_ANDI bug, add tests

Starting the ULP using SENS_SAR_START_FORCE_REG doesn’t disable clock gating of RTC fast clock.
When SoC goes into deep sleep mode, RTC fast clock gets gated, so ULP can no longer run.
Instead, it has to be started using the timer (RTC_CNTL_ULP_CP_SLP_TIMER_EN bit).
When ULP is enabled by the timer, clock also gets enabled.
This commit is contained in:
Ivan Grokhotkov 2016-12-16 20:25:38 +08:00
parent 7b02eae9e6
commit 7a527896dc
3 changed files with 86 additions and 3 deletions

View File

@ -600,7 +600,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
#define I_ANDI(reg_dest, reg_src, imm_) { .alu_imm = { \ #define I_ANDI(reg_dest, reg_src, imm_) { .alu_imm = { \
.dreg = reg_dest, \ .dreg = reg_dest, \
.sreg = reg_src, \ .sreg = reg_src, \
.imm = reg_imm_, \ .imm = imm_, \
.unused = 0, \ .unused = 0, \
.sel = ALU_SEL_AND, \ .sel = ALU_SEL_AND, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \ .sub_opcode = SUB_OPCODE_ALU_IMM, \

View File

@ -22,12 +22,14 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_deep_sleep.h"
#include "esp32/ulp.h" #include "esp32/ulp.h"
#include "soc/soc.h" #include "soc/soc.h"
#include "soc/rtc_cntl_reg.h" #include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h" #include "soc/sens_reg.h"
#include "driver/rtc_io.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@ -92,3 +94,77 @@ TEST_CASE("ulp branch test", "[ulp]")
} }
TEST_ASSERT_EQUAL(0, RTC_SLOW_MEM[64]); TEST_ASSERT_EQUAL(0, RTC_SLOW_MEM[64]);
} }
TEST_CASE("ulp wakeup test", "[ulp]")
{
assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig");
memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM);
const ulp_insn_t program[] = {
I_MOVI(R1, 1024),
M_LABEL(1),
I_DELAY(32000),
I_SUBI(R1, R1, 1),
M_BXZ(3),
I_RSHI(R3, R1, 5), // R3 = R1 / 32
I_ST(R1, R3, 16),
M_BX(1),
M_LABEL(3),
I_MOVI(R2, 42),
I_MOVI(R3, 15),
I_ST(R2, R3, 0),
I_END(1)
};
size_t size = sizeof(program)/sizeof(ulp_insn_t);
ulp_process_macros_and_load(0, program, &size);
ulp_run(0);
esp_deep_sleep_enable_ulp_wakeup();
esp_deep_sleep_start();
}
TEST_CASE("ulp controls RTC_IO", "[ulp]")
{
assert(CONFIG_ULP_COPROC_RESERVE_MEM >= 260 && "this test needs ULP_COPROC_RESERVE_MEM option set in menuconfig");
memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM);
const ulp_insn_t program[] = {
I_MOVI(R0, 0), // R0 is LED state
I_MOVI(R2, 16), // loop R2 from 16 down to 0
M_LABEL(4),
I_SUBI(R2, R2, 1),
M_BXZ(6),
I_ADDI(R0, R0, 1), // R0 = (R0 + 1) % 2
I_ANDI(R0, R0, 0x1),
M_BL(0, 1), // if R0 < 1 goto 0
M_LABEL(1),
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1), // RTC_GPIO12 = 1
M_BX(2), // goto 2
M_LABEL(0), // 0:
I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0), // RTC_GPIO12 = 0
M_LABEL(2), // 2:
I_MOVI(R1, 100), // loop R1 from 100 down to 0
M_LABEL(3),
I_SUBI(R1, R1, 1),
M_BXZ(5),
I_DELAY(32000), // delay for a while
M_BX(3),
M_LABEL(5),
M_BX(4),
M_LABEL(6),
I_END(1) // wake up the SoC
};
const gpio_num_t led_gpios[] = {
GPIO_NUM_2,
GPIO_NUM_0,
GPIO_NUM_4
};
for (size_t i = 0; i < sizeof(led_gpios)/sizeof(led_gpios[0]); ++i) {
rtc_gpio_init(led_gpios[i]);
rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_set_level(led_gpios[i], 0);
}
size_t size = sizeof(program)/sizeof(ulp_insn_t);
ulp_process_macros_and_load(0, program, &size);
ulp_run(0);
esp_deep_sleep_enable_ulp_wakeup();
esp_deep_sleep_start();
}

View File

@ -263,8 +263,15 @@ esp_err_t ulp_process_macros_and_load(uint32_t load_addr, const ulp_insn_t* prog
esp_err_t ulp_run(uint32_t entry_point) esp_err_t ulp_run(uint32_t entry_point)
{ {
SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP_M); // disable ULP timer
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
// set entry point
SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_PC_INIT_V, entry_point, SENS_PC_INIT_S); SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_PC_INIT_V, entry_point, SENS_PC_INIT_S);
SET_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_START_TOP_M); // disable force start
CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP_M);
// make sure voltage is raised when RTC 8MCLK is enabled
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M);
// enable ULP timer
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
return ESP_OK; return ESP_OK;
} }