lp-i2c: Added support for LP I2C peripheral to LP core

This commit adds support for the LP I2C peripheral driver to be used by
the LP core. An example is also added to demonstrate the usage of the LP
I2C peripheral from the LP core.
This commit is contained in:
Sudeep Mohanty
2023-03-20 16:08:38 +01:00
parent 224430f6b4
commit ec742abb25
27 changed files with 1246 additions and 198 deletions

View File

@@ -90,6 +90,10 @@ examples/system/light_sleep:
temporary: true
reason: target(s) not supported yet
examples/system/lp_core/lp_i2c:
enable:
- if: SOC_LP_I2C_SUPPORTED == 1
examples/system/ota/advanced_https_ota:
disable:
- if: IDF_TARGET == "esp32h2"

View File

@@ -0,0 +1,7 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
list(APPEND SDKCONFIG_DEFAULTS "sdkconfig.defaults")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(lp_i2c_example)

View File

@@ -0,0 +1,63 @@
| Supported Targets | ESP32-C6 |
| ----------------- | -------- |
# LP I2C Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview
This example demonstrates basic usage of the LP I2C driver from the LP core by reading to and writing from a sensor connected over I2C.
## How to use example
### Hardware Required
To run this example, you should have a ESP32-C6 based development board as well as a BH1750 sensor. BH1750 is an ambient light sensor. More information about it can be found in the [BH1750 datasheet](https://www.mouser.com/datasheet/2/348/bh1750fvi-e-186247.pdf).
#### Pin Assignment:
**Note:** The following pin assignments are used by default.
| | SDA | SCL |
| ----------------------- | ------| ------|
| ESP32-C6 LP I2C Master | GPIO6 | GPIO7 |
| BH1750 Sensor | SDA | SCL |
**Note:** There's no need to add an external pull-up resistors for SDA/SCL pin, because the driver enables the internal pull-up resistors.
### Build and Flash
Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project.
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
The log output should indicate that the LP core and the LP I2C peripheral have been successfully initialized. The main CPU would then enter deep sleep mode. The LP Core should wakeup the main CPU if the Light Intensity Value breaches the set thresholds.
```bash
Not an LP core wakeup. Cause = 0
Initializing...
LP core loaded with firmware successfully
LP I2C initialized successfully
Entering deep sleep...
(When the BH1750 sensor is shielded from a light source, the Lux value should be smaller and the LP core should wakeup the main CPU)
LP core woke up the main CPU
Lux = 3
Entering deep sleep...
(When the BH1750 sensor is exposed to a direct light source, the Lux value should be larger and the LP core should wakup the main CPU)
LP core woke up the main CPU
Lux = 1222
Entering deep sleep...
```
## Troubleshooting
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)

View File

@@ -0,0 +1,25 @@
# Register the component
idf_component_register(SRCS "lp_i2c_main.c"
INCLUDE_DIRS ""
REQUIRES ulp)
#
# ULP support additions to component CMakeLists.txt.
#
# 1. The LP Core app name must be unique (if multiple components use LP Core).
set(ulp_app_name lp_core_${COMPONENT_NAME})
#
# 2. Specify all C files.
# Files should be placed into a separate directory (in this case, lp_core/),
# which should not be added to COMPONENT_SRCS.
set(ulp_lp_core_sources "lp_core/main.c")
#
# 3. List all the component source files which include automatically
# generated LP Core export file, ${ulp_app_name}.h:
set(ulp_exp_dep_srcs "lp_i2c_main.c")
#
# 4. Call function to build ULP binary and embed in project using the argument
# values above.
ulp_embed_binary(${ulp_app_name} "${ulp_lp_core_sources}" "${ulp_exp_dep_srcs}")

View File

@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/***************************************************
* BH1750 Register Addresses
***************************************************/
#define BH1750_I2C_ADDR 0x23
#define BH1750_POWER_ON 0x01
#define BH1750_CONTINUOUS_H_RES_MODE 0x10
#define BH1750_CONTINUOUS_H_RES_MODE2 0x11
#define BH1750_CONTINUOUS_L_RES_MODE 0x13
#define BH1750_ONE_TIME_H_RES_MODE 0x20
#define BH1750_ONE_TIME_H_RES_MODE2 0x21
#define BH1750_ONE_TIME_L_RES_MODE 0x23
/***************************************************
* Example configurations
***************************************************/
#define EXAMPLE_RES_MODE BH1750_CONTINUOUS_H_RES_MODE

View File

@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "ulp_lp_core_i2c.h"
#include "ulp_lp_core_utils.h"
#include "../bh1750_defs.h"
#define LP_I2C_TRANS_TIMEOUT_CYCLES 5000
#define LP_I2C_TRANS_WAIT_FOREVER -1
#define LUX_THRESHOLD_LOW 5
#define LUX_THRESHOLD_HIGH 1000
static uint32_t sensor_on = 0;
static uint32_t res_update_done = 0;
volatile uint32_t lux = 0;
static void bh1750_read()
{
uint8_t data_rd[2];
esp_err_t ret = lp_core_i2c_master_read_from_device(LP_I2C_NUM_0, BH1750_I2C_ADDR, data_rd, sizeof(data_rd), LP_I2C_TRANS_TIMEOUT_CYCLES);
if (ret != ESP_OK) {
// Skip this round of calculation and return
return;
}
/* Calculate light intensity value */
uint16_t level = ((data_rd[0] << 8) | data_rd[1]);
lux = (level * 10) / 12;
/* Wakeup main CPU if the Lux breaches the thresholds */
if (lux < LUX_THRESHOLD_LOW || lux > LUX_THRESHOLD_HIGH) {
ulp_lp_core_wakeup_main_processor();
}
}
int main (void)
{
uint8_t data_wr = 0;
esp_err_t ret = ESP_OK;
while (1) {
if (!sensor_on) {
/* Power ON the sensor */
data_wr = BH1750_POWER_ON;
ret = lp_core_i2c_master_write_to_device(LP_I2C_NUM_0, BH1750_I2C_ADDR, &data_wr, sizeof(data_wr), LP_I2C_TRANS_WAIT_FOREVER);
if (ret != ESP_OK) {
// Bail and try again
continue;
}
sensor_on = 1;
}
if (!res_update_done) {
data_wr = EXAMPLE_RES_MODE;
ret = lp_core_i2c_master_write_to_device(LP_I2C_NUM_0, BH1750_I2C_ADDR, &data_wr, sizeof(data_wr), LP_I2C_TRANS_WAIT_FOREVER);
if (ret != ESP_OK) {
// Bail and try again
continue;
}
res_update_done = 1;
}
/* Read BH1750 sensor data */
bh1750_read();
}
return 0;
}

View File

@@ -0,0 +1,77 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "esp_sleep.h"
#include "lp_core_main.h"
#include "ulp_lp_core.h"
#include "lp_core_i2c.h"
extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_main_bin_start");
extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_main_bin_end");
static void lp_core_init(void)
{
esp_err_t ret = ESP_OK;
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
};
ret = ulp_lp_core_load_binary(lp_core_main_bin_start, (lp_core_main_bin_end - lp_core_main_bin_start));
if (ret != ESP_OK) {
printf("LP Core load failed\n");
abort();
}
ret = ulp_lp_core_run(&cfg);
if (ret != ESP_OK) {
printf("LP Core run failed\n");
abort();
}
printf("LP core loaded with firmware successfully\n");
}
static void lp_i2c_init(void)
{
esp_err_t ret = ESP_OK;
/* Initialize LP I2C with default configuration */
const lp_core_i2c_cfg_t i2c_cfg = LP_CORE_I2C_DEFAULT_CONFIG();
ret = lp_core_i2c_master_init(LP_I2C_NUM_0, &i2c_cfg);
if (ret != ESP_OK) {
printf("LP I2C init failed\n");
abort();
}
printf("LP I2C initialized successfully\n");
}
void app_main(void)
{
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
if (cause != ESP_SLEEP_WAKEUP_ULP) {
printf("Not an LP core wakeup. Cause = %d\n", cause);
printf("Initializing...\n");
/* Initialize LP_I2C from the main processor */
lp_i2c_init();
/* Load LP Core binary and start the coprocessor */
lp_core_init();
} else if (cause == ESP_SLEEP_WAKEUP_ULP) {
printf("LP core woke up the main CPU\n");
printf("Lux = %ld\n", ulp_lux);
}
/* Setup wakeup triggers */
ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());
/* Enter Deep Sleep */
printf("Entering deep sleep...\n");
esp_deep_sleep_start();
}

View File

@@ -0,0 +1,10 @@
# Enable LP Core
CONFIG_ULP_COPROC_ENABLED=y
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
CONFIG_ULP_COPROC_RESERVE_MEM=4096
# Set log level to Warning to produce clean output
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
CONFIG_BOOTLOADER_LOG_LEVEL=2
CONFIG_LOG_DEFAULT_LEVEL_WARN=y
CONFIG_LOG_DEFAULT_LEVEL=2