]> granicus.if.org Git - esp-idf/commitdiff
ulp: use timer to start ULP, fix I_ANDI bug, add tests
authorIvan Grokhotkov <ivan@espressif.com>
Fri, 16 Dec 2016 12:25:38 +0000 (20:25 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Fri, 16 Dec 2016 12:25:38 +0000 (20:25 +0800)
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.

components/ulp/include/esp32/ulp.h
components/ulp/test/test_ulp.c
components/ulp/ulp.c

index 18ad41ca6df8a0799ff07ea71720d2c0386c524e..a0903824c0de2eaf91d93511d79797c7df7d6f05 100644 (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 = { \
     .dreg = reg_dest, \
     .sreg = reg_src, \
-    .imm = reg_imm_, \
+    .imm = imm_, \
     .unused = 0, \
     .sel = ALU_SEL_AND, \
     .sub_opcode = SUB_OPCODE_ALU_IMM, \
index f0000e1aa29db69c41ffa952463a46a4e3672058..854eb3ee2055ec03172b6b5c76d067c7eb4813db 100644 (file)
 #include "esp_attr.h"
 #include "esp_err.h"
 #include "esp_log.h"
+#include "esp_deep_sleep.h"
 
 #include "esp32/ulp.h"
 
 #include "soc/soc.h"
 #include "soc/rtc_cntl_reg.h"
 #include "soc/sens_reg.h"
+#include "driver/rtc_io.h"
 
 #include "sdkconfig.h"
 
@@ -92,3 +94,77 @@ TEST_CASE("ulp branch test", "[ulp]")
     }
     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();
+}
+
index 228e3ff16d7173c84d6f52ba422a23a2aa5a22b5..60fa292f7c15e1789d3fda4247859da19c08e961 100644 (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)
 {
-    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_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;
 }