mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
lp-core-uart: Added support for printf to the LP core
This commit adds a minimal logging driver for the LP core. The logging driver provides a printf function which is built on top of the LP UART driver. The commit also adds an example to demonstrate how to use print statements in an LP core program.
This commit is contained in:
parent
3638082670
commit
38c1759fb4
@ -88,7 +88,8 @@ elseif(ULP_COCPU_IS_LP_CORE)
|
||||
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c"
|
||||
"${IDF_PATH}/components/hal/uart_hal_iram.c"
|
||||
"${IDF_PATH}/components/hal/uart_hal.c"
|
||||
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c")
|
||||
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c"
|
||||
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c")
|
||||
|
||||
target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles")
|
||||
target_link_options(${ULP_APP_NAME} PRIVATE "-Wl,--no-warn-rwx-segments")
|
||||
|
17
components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h
Normal file
17
components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Print from the LP core
|
||||
*
|
||||
* @note This function uses the LP UART peripheral to enable prints.The LP UART must be initialized with lp_core_uart_init() before using this function.
|
||||
* @note This function is not a standard printf function and may not support all format specifiers or special characters.
|
||||
*
|
||||
* @param format string to be printed
|
||||
* @param ... variable argument list
|
||||
*
|
||||
*/
|
||||
void lp_core_printf(const char* format, ...);
|
269
components/ulp/lp_core/lp_core/lp_core_print.c
Normal file
269
components/ulp/lp_core/lp_core/lp_core_print.c
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include "ulp_lp_core_uart.h"
|
||||
|
||||
#define LP_UART_PORT_NUM LP_UART_NUM_0
|
||||
#define BINARY_SUPPORT 1
|
||||
|
||||
#define is_digit(c) ((c >= '0') && (c <= '9'))
|
||||
|
||||
static void lp_uart_send_char(char c)
|
||||
{
|
||||
int tx_len = 0;
|
||||
int loop_cnt = 0;
|
||||
|
||||
/* Write one byte to LP UART. Break after few iterations if we are stuck for any reason. */
|
||||
while (tx_len != 1 && loop_cnt < 1000) {
|
||||
tx_len = lp_core_uart_tx_chars(LP_UART_PORT_NUM, (const void *)&c, 1);
|
||||
loop_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
// Ported over ROM function _cvt()
|
||||
static int lp_core_cvt(unsigned long long val, char *buf, long radix, char *digits)
|
||||
{
|
||||
#ifdef SUPPORT_LITTLE_RADIX
|
||||
char temp[64];
|
||||
#else
|
||||
char temp[32];
|
||||
#endif
|
||||
char *cp = temp;
|
||||
int length = 0;
|
||||
|
||||
if (val == 0) {
|
||||
/* Special case */
|
||||
*cp++ = '0';
|
||||
} else {
|
||||
while (val) {
|
||||
*cp++ = digits[val % radix];
|
||||
val /= radix;
|
||||
}
|
||||
}
|
||||
while (cp != temp) {
|
||||
*buf++ = *--cp;
|
||||
length++;
|
||||
}
|
||||
*buf = '\0';
|
||||
return (length);
|
||||
}
|
||||
|
||||
// Ported over ROM function ets_vprintf()
|
||||
static int lp_core_ets_vprintf(void (*putc)(char c), const char *fmt, va_list ap)
|
||||
{
|
||||
#ifdef BINARY_SUPPORT
|
||||
char buf[sizeof(long long) * 8];
|
||||
#else
|
||||
char buf[32];
|
||||
#endif
|
||||
char c, sign, *cp = buf;
|
||||
int left_prec, right_prec, zero_fill, pad, pad_on_right, islong, islonglong;
|
||||
long long val = 0;
|
||||
int res = 0, length = 0;
|
||||
|
||||
while ((c = *fmt++) != '\0') {
|
||||
if (c == '%') {
|
||||
c = *fmt++;
|
||||
left_prec = right_prec = pad_on_right = islong = islonglong = 0;
|
||||
if (c == '-') {
|
||||
c = *fmt++;
|
||||
pad_on_right++;
|
||||
}
|
||||
if (c == '0') {
|
||||
zero_fill = true;
|
||||
c = *fmt++;
|
||||
} else {
|
||||
zero_fill = false;
|
||||
}
|
||||
while (is_digit(c)) {
|
||||
left_prec = (left_prec * 10) + (c - '0');
|
||||
c = *fmt++;
|
||||
}
|
||||
if (c == '.') {
|
||||
c = *fmt++;
|
||||
zero_fill++;
|
||||
while (is_digit(c)) {
|
||||
right_prec = (right_prec * 10) + (c - '0');
|
||||
c = *fmt++;
|
||||
}
|
||||
} else {
|
||||
right_prec = left_prec;
|
||||
}
|
||||
sign = '\0';
|
||||
if (c == 'l') {
|
||||
c = *fmt++;
|
||||
islong = 1;
|
||||
if (c == 'l') {
|
||||
c = *fmt++;
|
||||
islonglong = 1;
|
||||
islong = 0;
|
||||
}
|
||||
}
|
||||
switch (c) {
|
||||
case 'p':
|
||||
islong = 1;
|
||||
case 'd':
|
||||
case 'D':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'u':
|
||||
case 'U':
|
||||
#ifdef BINARY_SUPPORT
|
||||
case 'b':
|
||||
case 'B':
|
||||
#endif
|
||||
if (islonglong) {
|
||||
val = va_arg(ap, long long);
|
||||
} else if (islong) {
|
||||
val = (long long)va_arg(ap, long);
|
||||
} else {
|
||||
val = (long long)va_arg(ap, int);
|
||||
}
|
||||
|
||||
if ((c == 'd') || (c == 'D')) {
|
||||
if (val < 0) {
|
||||
sign = '-';
|
||||
val = -val;
|
||||
}
|
||||
} else {
|
||||
if (islonglong) {
|
||||
;
|
||||
} else if (islong) {
|
||||
val &= ((long long)1 << (sizeof(long) * 8)) - 1;
|
||||
} else {
|
||||
val &= ((long long)1 << (sizeof(int) * 8)) - 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'p':
|
||||
(*putc)('0');
|
||||
(*putc)('x');
|
||||
zero_fill = true;
|
||||
left_prec = sizeof(unsigned long) * 2;
|
||||
case 'd':
|
||||
case 'D':
|
||||
case 'u':
|
||||
case 'U':
|
||||
case 'x':
|
||||
case 'X':
|
||||
switch (c) {
|
||||
case 'd':
|
||||
case 'D':
|
||||
case 'u':
|
||||
case 'U':
|
||||
length = lp_core_cvt(val, buf, 10, "0123456789");
|
||||
break;
|
||||
case 'p':
|
||||
case 'x':
|
||||
length = lp_core_cvt(val, buf, 16, "0123456789abcdef");
|
||||
break;
|
||||
case 'X':
|
||||
length = lp_core_cvt(val, buf, 16, "0123456789ABCDEF");
|
||||
break;
|
||||
}
|
||||
cp = buf;
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
cp = va_arg(ap, char *);
|
||||
if (cp == NULL) {
|
||||
cp = "<null>";
|
||||
}
|
||||
length = 0;
|
||||
while (cp[length] != '\0')
|
||||
length++;
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
c = va_arg(ap, int /*char*/);
|
||||
(*putc)(c);
|
||||
res++;
|
||||
continue;
|
||||
#ifdef BINARY_SUPPORT
|
||||
case 'b':
|
||||
case 'B':
|
||||
length = left_prec;
|
||||
if (left_prec == 0) {
|
||||
if (islonglong)
|
||||
length = sizeof(long long) * 8;
|
||||
else if (islong)
|
||||
length = sizeof(long) * 8;
|
||||
else
|
||||
length = sizeof(int) * 8;
|
||||
}
|
||||
for (int i = 0; i < length - 1; i++) {
|
||||
buf[i] = ((val & ((long long)1 << i)) ? '1' : '.');
|
||||
}
|
||||
cp = buf;
|
||||
break;
|
||||
#endif
|
||||
case '%':
|
||||
(*putc)('%');
|
||||
break;
|
||||
default:
|
||||
(*putc)('%');
|
||||
(*putc)(c);
|
||||
res += 2;
|
||||
}
|
||||
pad = left_prec - length;
|
||||
if (sign != '\0') {
|
||||
pad--;
|
||||
}
|
||||
if (zero_fill) {
|
||||
c = '0';
|
||||
if (sign != '\0') {
|
||||
(*putc)(sign);
|
||||
res++;
|
||||
sign = '\0';
|
||||
}
|
||||
} else {
|
||||
c = ' ';
|
||||
}
|
||||
if (!pad_on_right) {
|
||||
while (pad-- > 0) {
|
||||
(*putc)(c);
|
||||
res++;
|
||||
}
|
||||
}
|
||||
if (sign != '\0') {
|
||||
(*putc)(sign);
|
||||
res++;
|
||||
}
|
||||
while (length-- > 0) {
|
||||
c = *cp++;
|
||||
(*putc)(c);
|
||||
res++;
|
||||
}
|
||||
if (pad_on_right) {
|
||||
while (pad-- > 0) {
|
||||
(*putc)(' ');
|
||||
res++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(*putc)(c);
|
||||
res++;
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
int lp_core_printf(const char* format, ...)
|
||||
{
|
||||
/* Create a variable argument list */
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
/* Pass the input string and the argument list to ets_vprintf() */
|
||||
int ret = lp_core_ets_vprintf(lp_uart_send_char, format, ap);
|
||||
|
||||
va_end(ap);
|
||||
}
|
@ -78,10 +78,6 @@ 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"
|
||||
@ -181,6 +177,10 @@ examples/system/ulp/lp_core/lp_uart/lp_uart_echo:
|
||||
enable:
|
||||
- if: SOC_UART_LP_NUM > 0
|
||||
|
||||
examples/system/ulp/lp_core/lp_uart/lp_uart_print:
|
||||
enable:
|
||||
- if: SOC_UART_LP_NUM > 0
|
||||
|
||||
examples/system/ulp/ulp_fsm/ulp:
|
||||
disable:
|
||||
- if: SOC_ULP_FSM_SUPPORTED != 1
|
||||
|
@ -33,6 +33,7 @@ Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
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.
|
||||
|
||||
Use another serial monitor program/instance such as idf.py monitor, minicom or miniterm to send and receive data from the LP core.
|
||||
The default baudrate used for the example is 115200. Care must be taken that the configuration matches on both the device and the serial terminal.
|
||||
|
||||
## Example Output
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
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_uart_init()
|
||||
static void lp_uart_init(void)
|
||||
{
|
||||
lp_core_uart_cfg_t cfg = LP_CORE_UART_DEFAULT_CONFIG();
|
||||
|
||||
|
@ -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_uart_print_example)
|
67
examples/system/ulp/lp_core/lp_uart/lp_uart_print/README.md
Normal file
67
examples/system/ulp/lp_core/lp_uart/lp_uart_print/README.md
Normal file
@ -0,0 +1,67 @@
|
||||
| Supported Targets | ESP32-C6 |
|
||||
| ----------------- | -------- |
|
||||
|
||||
# LP UART Print Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates how to use print statements from a program running on the LP core.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
To run this example, you should have an ESP32-C6 based development board and a host machine with a serial input connection.
|
||||
|
||||
#### Pin Assignment:
|
||||
|
||||
**Note:** The following pin assignments are used by default.
|
||||
|
||||
|
||||
| | Tx |
|
||||
| ----------------------- | ------|
|
||||
| ESP32-C6 | GPIO5 |
|
||||
| Host machine | Rx |
|
||||
|
||||
### 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.
|
||||
|
||||
Use another serial monitor program/instance such as idf.py monitor, minicom or miniterm to send and receive data from the LP core.
|
||||
The default baudrate used for the example is 115200. Care must be taken that the configuration matches on both the device and the serial terminal.
|
||||
|
||||
## Example Output
|
||||
|
||||
The log output from the serial monitor connected to the main core should indicate that the LP core and the LP UART peripheral have been successfully initialized. The main CPU would then enter deep sleep mode.
|
||||
|
||||
```bash
|
||||
Not an LP core wakeup. Cause = 0
|
||||
Initializing...
|
||||
LP UART initialized successfully
|
||||
LP core loaded with firmware and running successfully
|
||||
Entering deep sleep...
|
||||
```
|
||||
|
||||
The log output from the serial monitor connected to the LP core should display output as below -
|
||||
|
||||
```bash
|
||||
Hello from the LP core!!
|
||||
This program has run 1 times
|
||||
**************************
|
||||
Hello from the LP core!!
|
||||
This program has run 2 times
|
||||
**************************
|
||||
Hello from the LP core!!
|
||||
This program has run 3 times
|
||||
**************************
|
||||
```
|
||||
|
||||
## 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.)
|
@ -0,0 +1,25 @@
|
||||
# Register the component
|
||||
idf_component_register(SRCS "lp_uart_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_uart_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}")
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ulp_lp_core_print.h"
|
||||
#include "ulp_lp_core_utils.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
static int iteration = 0;
|
||||
const char separator[] = "**************************";
|
||||
|
||||
lp_core_printf("Hello from the LP core!!\r\n");
|
||||
lp_core_printf("This program has run %d times\r\n", ++iteration);
|
||||
lp_core_printf("%s", separator);
|
||||
lp_core_printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_err.h"
|
||||
#include "lp_core_main.h"
|
||||
#include "ulp_lp_core.h"
|
||||
#include "lp_core_uart.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_uart_init(void)
|
||||
{
|
||||
lp_core_uart_cfg_t cfg = LP_CORE_UART_DEFAULT_CONFIG();
|
||||
|
||||
ESP_ERROR_CHECK(lp_core_uart_init(&cfg));
|
||||
|
||||
printf("LP UART initialized successfully\n");
|
||||
}
|
||||
|
||||
static void lp_core_init(void)
|
||||
{
|
||||
/* Set LP core wakeup source as the HP CPU */
|
||||
ulp_lp_core_cfg_t cfg = {
|
||||
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER,
|
||||
.lp_timer_sleep_duration_us = 1000000,
|
||||
};
|
||||
|
||||
/* Load LP core firmware */
|
||||
ESP_ERROR_CHECK(ulp_lp_core_load_binary(lp_core_main_bin_start, (lp_core_main_bin_end - lp_core_main_bin_start)));
|
||||
|
||||
/* Run LP core */
|
||||
ESP_ERROR_CHECK(ulp_lp_core_run(&cfg));
|
||||
|
||||
printf("LP core loaded with firmware and running 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_UART */
|
||||
lp_uart_init();
|
||||
|
||||
/* Load LP Core binary and start the coprocessor */
|
||||
lp_core_init();
|
||||
}
|
||||
|
||||
/* Setup wakeup triggers */
|
||||
ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());
|
||||
|
||||
/* Enter Deep Sleep */
|
||||
printf("Entering deep sleep...\n");
|
||||
esp_deep_sleep_start();
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
# Enable LP Core
|
||||
CONFIG_ULP_COPROC_ENABLED=y
|
||||
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM=8192
|
Loading…
x
Reference in New Issue
Block a user