I2C ULP

Lakeboard
Posts: 2
Joined: Sun Sep 18, 2022 1:08 pm

I2C ULP

Postby Lakeboard » Sun Sep 18, 2022 1:56 pm

Hello, everyone

I'm working on a project to read an I2C sensor with an ESP32 in battery mode.
For this, I want to use the I2C bus with the ULP Coprocessor in the deep sleep mode.

This should be possible and is even advertised:
"The Ultra Low Power (ULP) coprocessor is a simple finite state machine (FSM) which is designed to perform measurements using the ADC, temperature sensor, and external I2C sensors, while the main processors are in deep sleep mode."
From: https://docs.espressif.com/projects/esp ... m/ulp.html

To wirte the ULP (Assembler) Code I use a Library call "HULP" and de macros from ESP.
Macros: https://docs.espressif.com/projects/esp ... acros.html
HULP Library: https://github.com/boarchuz/HULP

In the light sleep mode my code works fine. But in the deep sleep mode it failed.
You can see in the Image (Logic Analyzer), that the I2C works in the two seconds (delay(2000)) before it get into the deep sleep mode. In the deep sleep mode the I2C stops.
I think, something is separately to power on in the deep sleep mode, that the I2C works.
Knows someone what and how? The ESP would be a great application with the ULP. But I haven't been able to find any good examples.

I am grateful for any help. :)

Code: Select all

#include <Arduino.h>
#include <SPI.h>
#include <stdio.h>
#include "soc/rtc.h"
#include "esp_sleep.h"
#include "esp32/ulp.h"
#include "hulp/hulp.h"

#define SCL_PIN GPIO_NUM_4
#define SDA_PIN GPIO_NUM_15

#define SLAVE_ADDR 0x68
#define SLAVE_SUBADDR 0x01

//Prototype
void init_ulp();

void setup()
{
	//ULP
       	init_ulp();
	esp_sleep_enable_ulp_wakeup();
       	ulp_run(0);

	//Delay after running ULP, befor go to sleep
   	delay(2000);

	//Call power settings again to be sure
	esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);

	esp_deep_sleep_start();
	//esp_light_sleep_start();
}

void loop()
{
	//Empty
}

//------------------------ULP Code------------------------//
void init_ulp()
{
	//ULP program
	const ulp_insn_t program[] = 
       	{
		I_DELAY(63000),
		I_I2C_READ(0, SLAVE_SUBADDR),
		I_WAKE(),
		I_HALT(),
	};
	
	//Pin config
        rtc_gpio_init(SCL_PIN);
      	rtc_gpio_set_direction(SCL_PIN, RTC_GPIO_MODE_INPUT_OUTPUT);
       	rtc_gpio_init(SDA_PIN);
       	rtc_gpio_set_direction(SDA_PIN, RTC_GPIO_MODE_INPUT_OUTPUT);

	//Sleep power settings
        esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO);

	//I2C settings
       	hulp_register_i2c_slave(0, 0x68);
	hulp_configure_i2c_pins(SCL_PIN, SDA_PIN, true, true);
	hulp_i2c_controller_config_t config = HULP_I2C_CONTROLLER_CONFIG_DEFAULT();
	hulp_configure_i2c_controller(&config);

	//Load and run ULP 
	size_t size = sizeof(program)/sizeof(ulp_insn_t);
       	ulp_process_macros_and_load(0, program, &size);
}
//--------------------------------------------------------//
Deep Sleep Mode:
Image

Light Sleep Mode:
Image

boarchuz
Posts: 605
Joined: Tue Aug 21, 2018 5:28 am

Re: I2C ULP

Postby boarchuz » Mon Sep 19, 2022 4:10 am

What happens if you remove esp_sleep_enable_ulp_wakeup or I_WAKE? Suspecting the repeated initialisation while running is breaking the I2C or ULP.

Lakeboard
Posts: 2
Joined: Sun Sep 18, 2022 1:08 pm

Re: I2C ULP

Postby Lakeboard » Mon Sep 19, 2022 5:57 pm

Many Thanks! You were right. The repeated initialization makes problems.
I wouldn't have thought of that.

Boarchuz, you are my hero!

For posterity... I solved the problem like this. If there are better solutions, they are very welcome!

Code: Select all

#include <Arduino.h>
#include <SPI.h>
#include <stdio.h>
#include "soc/rtc.h"
#include "esp_sleep.h"
#include "esp32/ulp.h"
#include "hulp/hulp.h"

#define SCL_PIN GPIO_NUM_4
#define SDA_PIN GPIO_NUM_15

#define SLAVE_ADDR 0x68
#define SLAVE_SUBADDR 0x01

#define ULP_WAKEUP_INTERVAL_MS 1000

RTC_DATA_ATTR ulp_var_t ulp_init_state;

//Prototype
void init_ulp();

void setup()
{
	Serial.begin(115200);

	//ULP init
	if(ulp_init_state.val == 0)
	{
		init_ulp();
		ulp_init_state.val = 1;
		Serial.println("ULP init!");
	}

	//Reset wakup reason
	esp_sleep_enable_ulp_wakeup();

	Serial.println("Hello World!");

	//Delay after running ULP, befor go to sleep
   	delay(2000);

	//Call power settings again to be sure
	esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);

	esp_deep_sleep_start();
	//esp_light_sleep_start();
}

void loop()
{
	//Empty
}

//------------------------ULP Code------------------------//
void init_ulp()
{
	//ULP program
	const ulp_insn_t program[] = 
	{
		I_DELAY(63000),
		I_I2C_READ(0, SLAVE_SUBADDR),
		I_WAKE(),
		I_HALT(),
	};
	
	//Pin config
    	rtc_gpio_init(SCL_PIN);
    	rtc_gpio_set_direction(SCL_PIN, RTC_GPIO_MODE_INPUT_OUTPUT);
    	rtc_gpio_init(SDA_PIN);
    	rtc_gpio_set_direction(SDA_PIN, RTC_GPIO_MODE_INPUT_OUTPUT);

	//Sleep power settings
    	esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_AUTO);

	//I2C settings
    	hulp_register_i2c_slave(0, 0x68);
	hulp_configure_i2c_pins(SCL_PIN, SDA_PIN, true, true);
	hulp_i2c_controller_config_t config = HULP_I2C_CONTROLLER_CONFIG_DEFAULT();
	hulp_configure_i2c_controller(&config);

	//Load and run ULP 
	ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), ULP_WAKEUP_INTERVAL_MS * 1000, 0));
	ESP_ERROR_CHECK(hulp_ulp_run(0));
}
//--------------------------------------------------------//

Image

Image

Who is online

Users browsing this forum: No registered users and 62 guests