A switch between esp32 and esp32s2betta added to the ULP build process.

The new bin utils will have extension esp32s2ulp-elf, and they have to be placed to the bin directory.
This commit is contained in:
Dmitry 2019-06-28 15:36:32 +03:00 committed by Dmitry
parent f64ee5aba3
commit 1518c410bc
12 changed files with 552 additions and 26 deletions

View file

@ -1,8 +1,13 @@
ifdef CONFIG_IDF_TARGET_ESP32S2BETA
ULP_BINUTILS_PREFIX ?= esp32s2ulp-elf-
else
ULP_BINUTILS_PREFIX ?= esp32ulp-elf-
endif
#
export ULP_AS := $(ULP_BINUTILS_PREFIX)as
export ULP_LD := $(ULP_BINUTILS_PREFIX)ld
export ULP_OBJCOPY := $(ULP_BINUTILS_PREFIX)objcopy
export ULP_OBJDUMP := $(ULP_BINUTILS_PREFIX)objdump
export ULP_NM := $(ULP_BINUTILS_PREFIX)nm
export ULP_LD_TEMPLATE := $(IDF_PATH)/components/ulp/ld/esp32.ulp.ld
export ULP_NM := $(ULP_BINUTILS_PREFIX)nm
export ULP_MAP_GEN := $(IDF_PATH)/components/ulp/esp32ulp_mapgen.py

View file

@ -0,0 +1,15 @@
# CMake toolchain file for ULP
set(CMAKE_SYSTEM_NAME Generic)
# Compiler is only used for preprocessing
set(CMAKE_C_COMPILER "xtensa-esp32s2-elf-gcc")
set(CMAKE_ASM_COMPILER "esp32s2ulp-elf-as")
set(CMAKE_LINKER "esp32s2ulp-elf-ld")
set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "${CMAKE_ASM${ASM_DIALECT}_COMPILER} \
<DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
set(CMAKE_EXE_LINKER_FLAGS "-A elf32-esp32s2ulp -nostdlib" CACHE STRING "ULP Linker Base Flags")
set(CMAKE_ASM_LINK_EXECUTABLE "${CMAKE_LINKER} <FLAGS> <CMAKE_ASM_LINK_FLAGS> \
<LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")

View file

@ -16,6 +16,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "soc/soc.h"
#include "ulp_common.h"
@ -76,15 +77,29 @@ extern "C" {
#define ALU_SEL_MOV 4 /*!< Copy value (immediate to destination register or source register to destination register */
#define ALU_SEL_LSH 5 /*!< Shift left by given number of bits */
#define ALU_SEL_RSH 6 /*!< Shift right by given number of bits */
#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
#define ALU_SEL_INC 0 /*!< Stage_cnt = Stage_cnt + Imm */
#define ALU_SEL_DEC 1 /*!< Stage_cnt = Stage_cnt - Imm */
#define ALU_SEL_RST 2 /*!< Stage_cnt = 0 */
#endif
#define OPCODE_BRANCH 8 /*!< Branch instructions */
#define SUB_OPCODE_BX 0 /*!< Branch to absolute PC (immediate or in register) */
#define BX_JUMP_TYPE_DIRECT 0 /*!< Unconditional jump */
#define BX_JUMP_TYPE_ZERO 1 /*!< Branch if last ALU result is zero */
#define BX_JUMP_TYPE_OVF 2 /*!< Branch if last ALU operation caused and overflow */
#define SUB_OPCODE_B 1 /*!< Branch to a relative offset */
#ifdef CONFIG_IDF_TARGET_ESP32
#define B_CMP_L 0 /*!< Branch if R0 is less than an immediate */
#define B_CMP_GE 1 /*!< Branch if R0 is greater than or equal to an immediate */
#define SUB_OPCODE_BX 0 /*!< Branch to absolute PC (immediate or in register) */
#define SUB_OPCODE_B 1 /*!< Branch to a relative offset */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
#define B_CMP_L 1 /*!< Branch if R0 is less than an immediate */
#define B_CMP_GE 2 /*!< Branch if R0 is greater than an immediate */
#define B_CMP_EQ 4 /*!< Branch if R0 is equal to an immediate */
#define SUB_OPCODE_BX 1 /*!< Branch to absolute PC (immediate or in register) */
#define SUB_OPCODE_B 0 /*!< Branch to a relative offset base on R0 */
#define SUB_OPCODE_B_STAGE 2 /*!< Branch to a relative offset base on stage reg */
#endif
#define OPCODE_END 9 /*!< Stop executing the program */
#define SUB_OPCODE_END 0 /*!< Stop executing the program and optionally wake up the chip */
@ -99,6 +114,10 @@ extern "C" {
#define OPCODE_MACRO 15 /*!< Not a real opcode. Used to identify labels and branches in the program */
#define SUB_OPCODE_MACRO_LABEL 0 /*!< Label macro */
#define SUB_OPCODE_MACRO_BRANCH 1 /*!< Branch macro */
#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
#define OPCODE_SLEEP_WAIT 4
#endif
/**@}*/
/**
@ -123,6 +142,7 @@ union ulp_insn {
uint32_t opcode : 4; /*!< Opcode (OPCODE_DELAY) */
} delay; /*!< Format of DELAY instruction */
#ifdef CONFIG_IDF_TARGET_ESP32
struct {
uint32_t dreg : 2; /*!< Register which contains data to store */
uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
@ -132,7 +152,24 @@ union ulp_insn {
uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ST) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_ST) */
} st; /*!< Format of ST instruction */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
struct {
uint32_t dreg : 2; /*!< Data address register number */
uint32_t sreg : 2; /*!< Base address register number */
uint32_t data_label : 2; /*!< Data label */
uint32_t upper : 1; /*!< High and low half-word Select 1: Write high half-word; 0 : write low half-word; */
uint32_t write_way : 2; /*!< Write number Mode 0 : full word write; 1: with data_label; 3: without label; */
uint32_t unused1 : 1; /*!< Unused */
uint32_t offset : 11; /*!< When you select automatic storage, you need to configure the base address offset*/
uint32_t unused2 : 4; /*!< Unused */
uint32_t wr_auto : 1; /*!< Automatic storage selection enabled (burst mode)*/
uint32_t offset_set : 1; /*!< Configure OFFSET enable */
uint32_t manul_en : 1; /*!< Manual storage selection enabled */
uint32_t opcode : 4; /*!< Opcode (OPCODE_ST) */
} st; /*!< Format of ST instruction */
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
struct {
uint32_t dreg : 2; /*!< Register where the data should be loaded to */
uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
@ -141,12 +178,24 @@ union ulp_insn {
uint32_t unused2 : 7; /*!< Unused */
uint32_t opcode : 4; /*!< Opcode (OPCODE_LD) */
} ld; /*!< Format of LD instruction */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
struct {
uint32_t dreg : 2; /*!< Register where the data should be loaded to */
uint32_t sreg : 2; /*!< Register which contains address in RTC memory (expressed in words) */
uint32_t unused1 : 6; /*!< Unused */
uint32_t offset : 11; /*!< Offset to add to sreg */
uint32_t unused2 : 6; /*!< Unused */
uint32_t rd_upper: 1;
uint32_t opcode : 4; /*!< Opcode (OPCODE_LD) */
} ld; /*!< Format of LD instruction */
#endif
struct {
uint32_t unused : 28; /*!< Unused */
uint32_t opcode : 4; /*!< Opcode (OPCODE_HALT) */
} halt; /*!< Format of HALT instruction */
#ifdef CONFIG_IDF_TARGET_ESP32
struct {
uint32_t dreg : 2; /*!< Register which contains target PC, expressed in words (used if .reg == 1) */
uint32_t addr : 11; /*!< Target PC, expressed in words (used if .reg == 0) */
@ -165,7 +214,29 @@ union ulp_insn {
uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_B) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
} b; /*!< Format of BRANCH instruction (relative address) */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
struct {
uint32_t dreg : 2; /*!< Register which contains target PC, expressed in words (used if .reg == 1) */
uint32_t addr : 11; /*!< Target PC, expressed in words (used if .reg == 0) */
uint32_t unused : 8; /*!< Unused */
uint32_t reg : 1; /*!< Target PC in register (1) or immediate (0) */
uint32_t type : 3; /*!< Jump condition (BX_JUMP_TYPE_xxx) */
uint32_t unused1 : 1; /*!< Unused */
uint32_t sub_opcode : 2; /*!< Sub opcode (SUB_OPCODE_BX) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
} bx; /*!< Format of BRANCH instruction (absolute address) */
struct {
uint32_t imm : 15; /*!< Immediate value to compare against */
uint32_t cmp : 3; /*!< Comparison to perform: B_CMP_L or B_CMP_GE */
uint32_t offset : 7; /*!< Absolute value of target PC offset w.r.t. current PC, expressed in words */
uint32_t sign : 1; /*!< Sign of target PC offset: 0: positive, 1: negative */
uint32_t sub_opcode : 2; /*!< Sub opcode (SUB_OPCODE_B) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_BRANCH) */
} b;
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
struct {
uint32_t dreg : 2; /*!< Destination register */
uint32_t sreg : 2; /*!< Register with operand A */
@ -175,7 +246,20 @@ union ulp_insn {
uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_REG) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
} alu_reg; /*!< Format of ALU instruction (both sources are registers) */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
struct {
uint32_t dreg : 2; /*!< Destination register */
uint32_t sreg : 2; /*!< Register with operand A */
uint32_t treg : 2; /*!< Register with operand B */
uint32_t unused : 15; /*!< Unused */
uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
uint32_t unused1 : 1; /*!< Unused */
uint32_t sub_opcode : 2; /*!< Sub opcode (SUB_OPCODE_ALU_REG) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
} alu_reg; /*!< Format of ALU instruction (both sources are registers) */
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
struct {
uint32_t dreg : 2; /*!< Destination register */
uint32_t sreg : 2; /*!< Register with operand A */
@ -185,6 +269,27 @@ union ulp_insn {
uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_ALU_IMM) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
} alu_imm; /*!< Format of ALU instruction (one source is an immediate) */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
struct {
uint32_t dreg : 2; /*!< Destination register */
uint32_t sreg : 2; /*!< Register with operand A */
uint32_t imm : 16; /*!< Immediate value of operand B */
uint32_t unused : 1; /*!< Unused */
uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
uint32_t unused1 : 1; /*!< Unused */
uint32_t sub_opcode : 2; /*!< Sub opcode (SUB_OPCODE_ALU_IMM) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
} alu_imm; /*!< Format of ALU instruction (one source is an immediate) */
struct {
uint32_t unused : 4; /*!< Unused */
uint32_t imm : 16; /*!< Immediate value of operand B */
uint32_t unused1 : 1; /*!< Unused */
uint32_t sel : 4; /*!< Operation to perform, one of ALU_SEL_xxx */
uint32_t unused2 : 1; /*!< Unused */
uint32_t sub_opcode : 2; /*!< Sub opcode (SUB_OPCODE_ALU_IMM) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_ALU) */
} alu_cnt; /*!< Format of ALU instruction (one source is an immediate) */
#endif
struct {
uint32_t addr : 8; /*!< Address within either RTC_CNTL, RTC_IO, or SARADC */
@ -203,7 +308,7 @@ union ulp_insn {
uint32_t high : 5; /*!< High bit */
uint32_t opcode : 4; /*!< Opcode (OPCODE_WR_REG) */
} rd_reg; /*!< Format of RD_REG instruction */
#ifdef CONFIG_IDF_TARGET_ESP32
struct {
uint32_t dreg : 2; /*!< Register where to store ADC result */
uint32_t mux : 4; /*!< Select SARADC pad (mux + 1) */
@ -213,7 +318,17 @@ union ulp_insn {
uint32_t unused2 : 4; /*!< Unused */
uint32_t opcode: 4; /*!< Opcode (OPCODE_ADC) */
} adc; /*!< Format of ADC instruction */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
struct {
uint32_t dreg : 2; /*!< Register where to store ADC result */
uint32_t mux : 4; /*!< Select SARADC pad (mux + 1) */
uint32_t sar_sel : 1; /*!< Select SARADC0 (0) or SARADC1 (1) */
uint32_t hall_phase : 1; /*!< Unused */
uint32_t xpd_hall : 1; /*!< Unused */
uint32_t unused1 : 19; /*!< Unused */
uint32_t opcode: 4; /*!< Opcode (OPCODE_ADC) */
} adc;
#endif
struct {
uint32_t dreg : 2; /*!< Register where to store temperature measurement result */
uint32_t wait_delay: 14; /*!< Cycles to wait after measurement is done */
@ -231,7 +346,7 @@ union ulp_insn {
uint32_t rw : 1; /*!< Write (1) or read (0) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_I2C) */
} i2c; /*!< Format of I2C instruction */
#ifdef CONFIG_IDF_TARGET_ESP32
struct {
uint32_t wakeup : 1; /*!< Set to 1 to wake up chip */
uint32_t unused : 24; /*!< Unused */
@ -245,7 +360,20 @@ union ulp_insn {
uint32_t sub_opcode : 3; /*!< Sub opcode (SUB_OPCODE_SLEEP) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
} sleep; /*!< Format of END instruction with sleep */
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
struct {
uint32_t wakeup : 1; /*!< Set to 1 to wake up chip */
uint32_t unused : 25; /*!< Unused */
uint32_t sub_opcode : 2; /*!< Sub opcode (SUB_OPCODE_WAKEUP) */
uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
} end;
struct {
uint32_t cycle_sel : 16; /*!< Select which one of SARADC_ULP_CP_SLEEP_CYCx_REG to get the sleep duration from */
uint32_t unused : 12; /*!< Unused */
uint32_t opcode : 4; /*!< Opcode (OPCODE_END) */
} sleep;
#endif
struct {
uint32_t label : 16; /*!< Label number */
uint32_t unused : 8; /*!< Unused */
@ -373,8 +501,13 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
* ULP program will continue running after this instruction. To stop
* the currently running program, use I_HALT().
*/
#ifdef CONFIG_IDF_TARGET_ESP32
#define I_END() \
I_WR_REG_BIT(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0)
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
#define I_END() \
I_WR_REG_BIT(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN_S, 0)
#endif
/**
* Select the time interval used to run ULP program.
*
@ -390,12 +523,18 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
* By default, SENS_SLEEP_CYCLES_S0 register is used by the ULP
* program timer.
*/
#ifdef CONFIG_IDF_TARGET_ESP32
#define I_SLEEP_CYCLE_SEL(timer_idx) { .sleep = { \
.cycle_sel = timer_idx, \
.unused = 0, \
.sub_opcode = SUB_OPCODE_SLEEP, \
.opcode = OPCODE_END } }
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
#define I_SLEEP_CYCLE_SEL(timer_idx) { .sleep = { \
.cycle_sel = timer_idx, \
.unused = 0, \
.opcode = OPCODE_SLEEP_WAIT } }
#endif
/**
* Perform temperature sensor measurement and store it into reg_dest.
*
@ -414,6 +553,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
* adc_idx selects ADC (0 or 1).
* pad_idx selects ADC pad (0 - 7).
*/
#ifdef CONFIG_IDF_TARGET_ESP32
#define I_ADC(reg_dest, adc_idx, pad_idx) { .adc = {\
.dreg = reg_dest, \
.mux = pad_idx + 1, \
@ -422,6 +562,16 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.cycles = 0, \
.unused2 = 0, \
.opcode = OPCODE_ADC } }
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
#define I_ADC(reg_dest, adc_idx, pad_idx) { .adc = {\
.dreg = reg_dest, \
.mux = pad_idx + 1, \
.sar_sel = adc_idx, \
.hall_phase = 0, \
.xpd_hall = 0, \
.unused1 = 0, \
.opcode = OPCODE_ADC } }
#endif
/**
* Store value from register reg_val into RTC memory.
@ -435,6 +585,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
*
* RTC_SLOW_MEM[addr + offset_] = { 5'b0, insn_PC[10:0], val[15:0] }
*/
#ifdef CONFIG_IDF_TARGET_ESP32
#define I_ST(reg_val, reg_addr, offset_) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
@ -443,7 +594,138 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.unused2 = 0, \
.sub_opcode = SUB_OPCODE_ST, \
.opcode = OPCODE_ST } }
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
/**
* burst Mode: write to consecutive address spaces.
* STW, STC instructions for the Class burst storage instructions for continuous address space write operation;
* Need to be used with the SET_OFFSET instruction, you first need to set the start address offset by SET_OFFSET, SREG is the base address,
* Where STW instruction WORD instruction, each execution time, address offset+1;STC for the half-word operation
* (First write high 16bit current address, the Second Write low 16bit current address), each performed twice, the address offset+1.
* Note: when using STC, you must write a word, that is, a burst operation instruction must be an even number.
*/
#define I_STO(offset_) { .st = { \
.dreg = 0, \
.sreg = 0, \
.data_label = 0, \
.upper = 0, \
.write_way = 0, \
.unused1 = 0, \
.offset = offset_, \
.unused2 = 0, \
.wr_auto = 0, \
.offset_set = 0, \
.manul_en = 1, \
.opcode = OPCODE_ST } }
#define I_STW(reg_val, reg_addr) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
.data_label = 0, \
.upper = 0, \
.write_way = 0, \
.unused1 = 0, \
.offset = 0, \
.unused2 = 0, \
.wr_auto = 1, \
.offset_set = 0, \
.manul_en = 0, \
.opcode = OPCODE_ST } }
#define I_STC(reg_val, reg_addr) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
.data_label = 0, \
.upper = 0, \
.write_way = 3, \
.unused1 = 0, \
.offset = 0, \
.unused2 = 0, \
.wr_auto = 1, \
.offset_set = 0, \
.manul_en = 0, \
.opcode = OPCODE_ST } }
/**
* Single mode of operation: write to a single address space.
*
* Loads 16 LSBs from RTC memory word given by the sum of value in reg_addr and
* value of offset_.
*/
/* Mem [ Rsrc1 + offset ]{31:0} = {PC[10:0], 5<>d0,Rdst[15:0]} */
#define I_ST(reg_val, reg_addr, offset_) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
.data_label = 0, \
.upper = 0, \
.write_way = 0, \
.unused1 = 0, \
.offset = offset_, \
.unused2 = 0, \
.wr_auto = 0, \
.offset_set = 0, \
.manul_en = 1, \
.opcode = OPCODE_ST } }
/* Mem [ Rsrc1 + offset ]{31:16} = {Rdst[15:0]} */
#define I_STM32U(reg_val, reg_addr, offset_) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
.data_label = 0, \
.upper = 1, \
.write_way = 3, \
.unused1 = 0, \
.offset = offset_, \
.unused1 = 0, \
.wr_auto = 0, \
.offset_set = 0, \
.manul_en = 1, \
.opcode = OPCODE_ST } }
/* Mem [ Rsrc1 + offset ]{15:0} = {Rdst[15:0]} */
#define I_STM32L(reg_val, reg_addr, offset_) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
.data_label = 0, \
.upper = 0, \
.write_way = 3, \
.unused1 = 0, \
.offset = offset_, \
.unused2 = 0, \
.wr_auto = 0, \
.offset_set = 0, \
.manul_en = 1, \
.opcode = OPCODE_ST } }
/* Mem [ Rsrc1 + offset ]{31:0} = {data_label[1:0],Rdst[13:0]} */
#define I_STMLBU(reg_val, reg_addr, label, offset_) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
.data_label = label, \
.upper = 1, \
.write_way = 1, \
.unused1 = 0, \
.offset = offset_, \
.unused1 = 0, \
.wr_auto = 0, \
.offset_set = 0, \
.manul_en = 1, \
.opcode = OPCODE_ST } }
/* Mem [ Rsrc1 + offset ]{15:0} = {data_label[1:0],Rdst[13:0]} */
#define I_STMLBL(reg_val, reg_addr, label, offset_) { .st = { \
.dreg = reg_val, \
.sreg = reg_addr, \
.data_label = label, \
.upper = 0, \
.write_way = 1, \
.unused1 = 0, \
.offset = offset_, \
.unused2 = 0, \
.wr_auto = 0, \
.offset_set = 0, \
.manul_en = 1, \
.opcode = OPCODE_ST } }
#endif
/**
* Load value from RTC memory into reg_dest register.
@ -451,6 +733,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
* Loads 16 LSBs from RTC memory word given by the sum of value in reg_addr and
* value of offset_.
*/
#ifdef CONFIG_IDF_TARGET_ESP32
#define I_LD(reg_dest, reg_addr, offset_) { .ld = { \
.dreg = reg_dest, \
.sreg = reg_addr, \
@ -458,7 +741,16 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.offset = offset_, \
.unused2 = 0, \
.opcode = OPCODE_LD } }
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
#define I_LD(reg_dest, reg_addr, offset_) { .ld = { \
.dreg = reg_dest, \
.sreg = reg_addr, \
.unused1 = 0, \
.offset = offset_, \
.unused2 = 0, \
.rd_upper = 0, \
.opcode = OPCODE_LD } }
#endif
/**
* Branch relative if R0 less than immediate value.
@ -474,6 +766,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.sub_opcode = SUB_OPCODE_B, \
.opcode = OPCODE_BRANCH } }
#ifdef CONFIG_IDF_TARGET_ESP32
/**
* Branch relative if R0 greater or equal than immediate value.
*
@ -487,7 +780,75 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.sign = (pc_offset >= 0) ? 0 : 1, \
.sub_opcode = SUB_OPCODE_B, \
.opcode = OPCODE_BRANCH } }
#endif
#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
/**
* Branch relative if R0 greater than immediate value.
*
* pc_offset is expressed in words, and can be from -127 to 127
* imm_value is a 16-bit value to compare R0 against
*/
#define I_BG(pc_offset, imm_value) { .b = { \
.imm = imm_value, \
.cmp = B_CMP_GE, \
.offset = abs(pc_offset), \
.sign = (pc_offset >= 0) ? 0 : 1, \
.sub_opcode = SUB_OPCODE_B, \
.opcode = OPCODE_BRANCH } }
/**
* Branch relative if R0 equal to immediate value.
*
* pc_offset is expressed in words, and can be from -127 to 127
* imm_value is a 16-bit value to compare R0 against
*/
#define I_BE(pc_offset, imm_value) { .b = { \
.imm = imm_value, \
.cmp = B_CMP_EQ, \
.offset = abs(pc_offset), \
.sign = (pc_offset >= 0) ? 0 : 1, \
.sub_opcode = SUB_OPCODE_B, \
.opcode = OPCODE_BRANCH } }
/*
* Branch to a relative offset base on stage reg
* If stage reg less imm_value, PC will jump pc_offset.
*/
#define I_BRLS(pc_offset, imm_value) { .b = { \
.imm = imm_value, \
.cmp = B_CMP_L, \
.offset = abs(pc_offset), \
.sign = (pc_offset >= 0) ? 0 : 1, \
.sub_opcode = SUB_OPCODE_B_STAGE, \
.opcode = OPCODE_BRANCH } }
/*
* Branch to a relative offset base on stage reg
* If stage reg greater imm_value, PC will jump pc_offset.
*/
#define I_BRGS(pc_offset, imm_value) { .b = { \
.imm = imm_value, \
.cmp = B_CMP_GE, \
.offset = abs(pc_offset), \
.sign = (pc_offset >= 0) ? 0 : 1, \
.sub_opcode = SUB_OPCODE_B_STAGE, \
.opcode = OPCODE_BRANCH } }
/*
* Branch to a relative offset base on stage reg
* If stage reg equal to imm_value, PC will jump pc_offset.
*/
#define I_BRES(pc_offset, imm_value) { .b = { \
.imm = imm_value, \
.cmp = B_CMP_EQ, \
.offset = abs(pc_offset), \
.sign = (pc_offset >= 0) ? 0 : 1, \
.sub_opcode = SUB_OPCODE_B_STAGE, \
.opcode = OPCODE_BRANCH } }
#endif
/**
* Unconditional branch to absolute PC, address in register.
*
@ -500,6 +861,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.unused = 0, \
.reg = 1, \
.type = BX_JUMP_TYPE_DIRECT, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_BX, \
.opcode = OPCODE_BRANCH } }
@ -514,6 +876,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.unused = 0, \
.reg = 0, \
.type = BX_JUMP_TYPE_DIRECT, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_BX, \
.opcode = OPCODE_BRANCH } }
@ -529,6 +892,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.unused = 0, \
.reg = 1, \
.type = BX_JUMP_TYPE_ZERO, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_BX, \
.opcode = OPCODE_BRANCH } }
@ -543,6 +907,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.unused = 0, \
.reg = 0, \
.type = BX_JUMP_TYPE_ZERO, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_BX, \
.opcode = OPCODE_BRANCH } }
@ -558,6 +923,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.unused = 0, \
.reg = 1, \
.type = BX_JUMP_TYPE_OVF, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_BX, \
.opcode = OPCODE_BRANCH } }
@ -572,6 +938,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.unused = 0, \
.reg = 0, \
.type = BX_JUMP_TYPE_OVF, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_BX, \
.opcode = OPCODE_BRANCH } }
@ -585,6 +952,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.treg = reg_src2, \
.unused = 0, \
.sel = ALU_SEL_ADD, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_REG, \
.opcode = OPCODE_ALU } }
@ -597,6 +965,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.treg = reg_src2, \
.unused = 0, \
.sel = ALU_SEL_SUB, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_REG, \
.opcode = OPCODE_ALU } }
@ -609,6 +978,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.treg = reg_src2, \
.unused = 0, \
.sel = ALU_SEL_AND, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_REG, \
.opcode = OPCODE_ALU } }
@ -621,6 +991,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.treg = reg_src2, \
.unused = 0, \
.sel = ALU_SEL_OR, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_REG, \
.opcode = OPCODE_ALU } }
@ -633,6 +1004,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.treg = 0, \
.unused = 0, \
.sel = ALU_SEL_MOV, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_REG, \
.opcode = OPCODE_ALU } }
@ -645,6 +1017,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.treg = reg_shift, \
.unused = 0, \
.sel = ALU_SEL_LSH, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_REG, \
.opcode = OPCODE_ALU } }
@ -658,6 +1031,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.treg = reg_shift, \
.unused = 0, \
.sel = ALU_SEL_RSH, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_REG, \
.opcode = OPCODE_ALU } }
@ -670,6 +1044,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_ADD, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \
.opcode = OPCODE_ALU } }
@ -683,6 +1058,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_SUB, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \
.opcode = OPCODE_ALU } }
@ -695,6 +1071,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_AND, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \
.opcode = OPCODE_ALU } }
@ -707,6 +1084,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_OR, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \
.opcode = OPCODE_ALU } }
@ -719,6 +1097,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_MOV, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \
.opcode = OPCODE_ALU } }
@ -731,6 +1110,7 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_LSH, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \
.opcode = OPCODE_ALU } }
@ -744,9 +1124,49 @@ static inline uint32_t SOC_REG_TO_ULP_PERIPH_SEL(uint32_t reg) {
.imm = imm_, \
.unused = 0, \
.sel = ALU_SEL_RSH, \
.unused1 = 0, \
.sub_opcode = SUB_OPCODE_ALU_IMM, \
.opcode = OPCODE_ALU } }
#ifdef CONFIG_IDF_TARGET_ESP32S2BETA
/**
* Increments the stage counter for the subscript of the cycle count, Stage_cnt = Stage_cnt + Imm
*/
#define I_SINC(imm_) { .alu_cnt = { \
.unused = 0, \
.imm = imm_, \
.unused1 = 0, \
.sel = ALU_SEL_INC, \
.unused2 = 0, \
.sub_opcode = SUB_OPCODE_ALU_CNT, \
.opcode = OPCODE_ALU } }
/**
* Decrements the stage counter for the subscript of the cycle count, Stage_cnt = Stage_cnt - Imm
*/
#define I_SDEC(imm_) { .alu_cnt = { \
.unused = 0, \
.imm = imm_, \
.unused1 = 0, \
.sel = ALU_SEL_DEC, \
.unused2 = 0, \
.sub_opcode = SUB_OPCODE_ALU_CNT, \
.opcode = OPCODE_ALU } }
/**
* Phase counter is reset for the cycle count subscript, Stage_cnt = 0
*/
#define I_SRST() { .alu_cnt = { \
.unused = 0, \
.imm = 0, \
.unused1 = 0, \
.sel = ALU_SEL_RST, \
.unused2 = 0, \
.sub_opcode = SUB_OPCODE_ALU_CNT, \
.opcode = OPCODE_ALU } }
#endif
/**
* Define a label with number label_num.
*

View file

@ -1,10 +1,16 @@
#include "sdkconfig.h"
#if CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM
#define LOCAL_ULP_COPROC_RESERVE_MEM CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM
#else
#define LOCAL_ULP_COPROC_RESERVE_MEM CONFIG_ESP32_ULP_COPROC_RESERVE_MEM
#endif
#define ULP_BIN_MAGIC 0x00706c75
#define HEADER_SIZE 12
MEMORY
{
ram(RW) : ORIGIN = 0, LENGTH = CONFIG_ESP32_ULP_COPROC_RESERVE_MEM
ram(RW) : ORIGIN = 0, LENGTH = LOCAL_ULP_COPROC_RESERVE_MEM
}
SECTIONS

View file

@ -34,12 +34,19 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs)
idf_build_get_property(python PYTHON)
idf_build_get_property(extra_cmake_args EXTRA_CMAKE_ARGS)
if(IDF_TARGET STREQUAL "esp32")
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-esp32-ulp.cmake)
endif()
if(IDF_TARGET STREQUAL "esp32s2beta")
set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-esp32s2beta-ulp.cmake)
endif()
externalproject_add(${app_name}
SOURCE_DIR ${idf_path}/components/ulp/cmake
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${app_name}
INSTALL_COMMAND ""
CMAKE_ARGS -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
-DCMAKE_TOOLCHAIN_FILE=${idf_path}/components/ulp/cmake/toolchain-ulp.cmake
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FLAG}
-DULP_S_SOURCES=${sources} -DULP_APP_NAME=${app_name}
-DCOMPONENT_DIR=${COMPONENT_DIR}
# Even though this resolves to a ';' separated list, this is fine. This must be special behavior

View file

@ -1 +1 @@
SUPPORTED_ULP_ASSEMBLER_VERSION = 2.28.51.20170517
SUPPORTED_ULP_ASSEMBLER_VERSION = 2.28.51-esp-20190801

View file

@ -65,6 +65,25 @@ esp_err_t ulp_run(uint32_t entry_point)
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M);
// enable ULP timer
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
// disable ULP timer
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
// wait for at least 1 RTC_SLOW_CLK cycle
ets_delay_us(10);
// set entry point
REG_SET_FIELD(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_PC_INIT, entry_point);
SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SEL); // Select ULP_TIMER trigger target for ULP.
CLEAR_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE_FORCE); // Select the value for ULP_TIMER sleep. 1: REG_COCPU_DONE;0: ULP END value.
/* Set the number of cycles of ULP_TIMER sleep, the wait time required to start ULP */
REG_SET_FIELD(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_TIMER_SLP_CYCLE, 100);
/* Clear interrupt COCPU status */
REG_WRITE(RTC_CNTL_INT_CLR_REG, RTC_CNTL_COCPU_INT_CLR | RTC_CNTL_COCPU_TRAP_INT_CLR | RTC_CNTL_ULP_CP_INT_CLR);
// start ULP clock gate.
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_CTRL_REG ,RTC_CNTL_ULP_CP_CLK_FO);
// 1: start with timer. wait ULP_TIMER cnt timer.
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_CTRL_REG, RTC_CNTL_ULP_CP_FORCE_START_TOP); // Select ULP_TIMER timer as COCPU trigger source
SET_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); // Software to turn on the ULP_TIMER timer
#endif
return ESP_OK;
}
@ -131,6 +150,13 @@ esp_err_t ulp_set_wakeup_period(size_t period_index, uint32_t period_us)
}
REG_SET_FIELD(SENS_ULP_CP_SLEEP_CYC0_REG + period_index * sizeof(uint32_t),
SENS_SLEEP_CYCLES_S0, (uint32_t) period_cycles);
#elif defined CONFIG_IDF_TARGET_ESP32S2BETA
if (period_index > 4) {
return ESP_ERR_INVALID_ARG;
}
uint64_t period_us_64 = period_us;
uint64_t period_cycles = (period_us_64 * 1000) / 90; //COCPU sleep clock is 90KHZ.
REG_SET_FIELD(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_TIMER_SLP_CYCLE, period_cycles);
#endif
return ESP_OK;
}

View file

@ -75,7 +75,7 @@ entry:
* Check which IO this is.
*/
move r0, r3
jumpr read_io_high, 16, ge
jumps read_io_high, 16, ge
/* Read the value of lower 16 RTC IOs into R0 */
READ_RTC_REG(RTC_GPIO_IN_REG, RTC_GPIO_IN_NEXT_S, 16)

View file

@ -80,7 +80,9 @@ static void init_ulp_program(void)
*/
rtc_gpio_isolate(GPIO_NUM_12);
rtc_gpio_isolate(GPIO_NUM_15);
#if CONFIG_IDF_TARGET_ESP32
esp_deep_sleep_disable_rom_logging(); // suppress boot messages
#endif
}
static void start_ulp_program(void)

View file

@ -73,7 +73,7 @@ class TestUsage(unittest.TestCase):
output = output_stream.getvalue()
xtensa_esp32_elf_version = 'esp-2019r2-8.2.0'
esp32ulp_version = '2.28.51.20170517'
esp32ulp_version = '2.28.51-esp-20190801'
self.assertIn('* xtensa-esp32-elf:', output)
self.assertIn('- %s (recommended)' % xtensa_esp32_elf_version, output)

View file

@ -142,26 +142,71 @@
"versions": [
{
"linux-amd64": {
"sha256": "c1bbcd65e1e30c7312a50344c8dbc70c2941580a79aa8f8abbce8e0e90c79566",
"size": 8246604,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-linux64-2.28.51-esp32ulp-20180809.tar.gz"
"sha256": "f036ef1907ee19c8705f7076ef8c2e3b6dd9ffff654d35c264e7036c14aa5230",
"size": 8249059,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32ulp-linux-amd64-2.28.51-esp-20190801.tar.gz"
},
"macos": {
"sha256": "c92937d85cc9a90eb6c6099ce767ca021108c18c94e34bd7b1fa0cde168f94a0",
"size": 5726662,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-macos-2.28.51-esp32ulp-20180809.tar.gz"
"sha256": "04f812bf410ae6bef438c53ff4f4a33f34884d9072ae5815814b208ab408a9a4",
"size": 8871878,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32ulp-macos-2.28.51-esp-20190801.tar.gz"
},
"name": "2.28.51.20170517",
"name": "2.28.51-esp-20190801",
"status": "recommended",
"win32": {
"sha256": "92dc83e69e534c9f73d7b939088f2e84f757d2478483415d17fe9dd1c236f2fd",
"size": 12231559,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-win32-2.28.51-esp32ulp-20180809.zip"
"sha256": "44626cc2348686e9c57587142ca49cdab26fec742468942b8679f22b6661a7ec",
"size": 12232098,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32ulp-win32-2.28.51-esp-20190801.zip"
},
"win64": {
"sha256": "92dc83e69e534c9f73d7b939088f2e84f757d2478483415d17fe9dd1c236f2fd",
"size": 12231559,
"url": "https://dl.espressif.com/dl/binutils-esp32ulp-win32-2.28.51-esp32ulp-20180809.zip"
"sha256": "44626cc2348686e9c57587142ca49cdab26fec742468942b8679f22b6661a7ec",
"size": 12232098,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32ulp-win32-2.28.51-esp-20190801.zip"
}
}
]
},
{
"description": "Toolchain for ESP32-S2 ULP coprocessor",
"export_paths": [
[
"esp32s2ulp-elf-binutils",
"bin"
]
],
"export_vars": {},
"info_url": "https://github.com/espressif/binutils-esp32ulp",
"install": "always",
"license": "GPL-2.0-or-later",
"name": "esp32s2ulp-elf",
"version_cmd": [
"esp32s2ulp-elf-as",
"--version"
],
"version_regex": "\\(GNU Binutils\\)\\s+([0-9a-z\\.\\-]+)",
"versions": [
{
"linux-amd64": {
"sha256": "0085852b0de25a2186c874a184385c1dde107414248ec6a726b48d6616da6274",
"size": 8253802,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32s2ulp-linux-amd64-2.28.51-esp-20190801.tar.gz"
},
"macos": {
"sha256": "b180a5ed3b7b5aa4503f26e5bd562d8b0f4b55f24a2ca04942804fd88b4d91b5",
"size": 8877256,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32s2ulp-macos-2.28.51-esp-20190801.tar.gz"
},
"name": "2.28.51-esp-20190801",
"status": "recommended",
"win32": {
"sha256": "dbd0f050273a95a82b3e506aba999c8e4d4b22c69e5f3f3efc712c8eb59355e2",
"size": 12238724,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32s2ulp-win32-2.28.51-esp-20190801.zip"
},
"win64": {
"sha256": "dbd0f050273a95a82b3e506aba999c8e4d4b22c69e5f3f3efc712c8eb59355e2",
"size": 12238724,
"url": "https://github.com/espressif/binutils-esp32ulp/releases/download/v2.28.51-esp-20190801/binutils-esp32s2ulp-win32-2.28.51-esp-20190801.zip"
}
}
]