Merge branch 'feature/ulp_uart' into 'master'

ulp-riscv: uart print

See merge request espressif/esp-idf!19229
This commit is contained in:
Marius Vikhammer
2022-08-02 09:14:48 +08:00
17 changed files with 478 additions and 10 deletions

View File

@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* Underlying driver function for printing a char, e.g. over UART */
typedef void (*putc_fn_t)(const void *ctx, const char c);
/**
* @brief Installs a print driver that will be used for ulp_riscv_print calls
*
* @param putc Underlying driver function for printing a char, e.g. over UART
* @param putc_ctx Context that will be passed when calling the putc function
*/
void ulp_riscv_print_install(putc_fn_t putc, void *putc_ctx);
/**
* @brief Prints a null-terminated string
*
* @param str String to print
*/
void ulp_riscv_print_str(const char *str);
/**
* @brief Prints a hex number. Does not print 0x, only the digits
*
* @param Hex number to print
*/
void ulp_riscv_print_hex(int h);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "ulp_riscv_gpio.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct {
gpio_num_t tx_pin; // TX pin number
} ulp_riscv_uart_cfg_t; // Config for the driver
typedef struct {
uint32_t bit_duration_cycles; // Number of cycles to hold the line for each bit
gpio_num_t tx_pin; // TX pin number
} ulp_riscv_uart_t; // Context for the driver, initialized by ulp_riscv_uart_init
/**
* @brief Initialize the bit-banged UART driver
*
* @note Will also initialize the underlying HW, i.e. the RTC GPIO used.
*
* @param uart Pointer to the struct that will contain the initialized context
* @param cfg Pointer to the config struct which will be used to initialize the driver
*/
void ulp_riscv_uart_init(ulp_riscv_uart_t *uart, const ulp_riscv_uart_cfg_t *cfg);
/**
* @brief Outputs a single byte on the tx pin
*
* @param uart Pointer to the initialized driver context
* @param c Byte to output
*/
void ulp_riscv_uart_putc(const ulp_riscv_uart_t *uart, const char c);
#ifdef __cplusplus
}
#endif

View File

@@ -94,7 +94,16 @@ void ulp_riscv_timer_resume(void);
*
* @param cycles Number of cycles to busy wait
*/
void ulp_riscv_delay_cycles(uint32_t cycles);
void static inline ulp_riscv_delay_cycles(uint32_t cycles)
{
uint32_t start = ULP_RISCV_GET_CCOUNT();
/* Off with an estimate of cycles in this function to improve accuracy */
uint32_t end = start + cycles - 20;
while (ULP_RISCV_GET_CCOUNT() < end) {
/* Wait */
}
}
/**
* @brief Clears the GPIO wakeup interrupt bit

View File

@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ulp_riscv_print.h"
typedef struct {
putc_fn_t putc; // Putc function of the underlying driver, e.g. UART
void *putc_ctx; // Context passed to the putc function
} ulp_riscv_print_ctx_t;
static ulp_riscv_print_ctx_t s_print_ctx;
void ulp_riscv_print_install(putc_fn_t putc, void * putc_ctx)
{
s_print_ctx.putc_ctx = putc_ctx;
s_print_ctx.putc = putc;
}
void ulp_riscv_print_str(const char *str)
{
if (!s_print_ctx.putc) {
return;
}
for (int i = 0; str[i] != 0; i++) {
s_print_ctx.putc(s_print_ctx.putc_ctx ,str[i]);
}
}
void ulp_riscv_print_hex(int h)
{
int x;
int c;
if (!s_print_ctx.putc) {
return;
}
// Does not print '0x', only the digits (8 digits to print)
for (x = 0; x < 8; x++) {
c = (h >> 28) & 0xf; // extract the leftmost byte
if (c < 10) {
s_print_ctx.putc(s_print_ctx.putc_ctx ,'0' + c);
} else {
s_print_ctx.putc(s_print_ctx.putc_ctx ,'a' + c - 10);
}
h <<= 4; // move the 2nd leftmost byte to the left, to be extracted next
}
}

View File

@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "ulp_riscv.h"
#include "ulp_riscv_utils.h"
#include "ulp_riscv_gpio.h"
#include "ulp_riscv_uart_ulp_core.h"
/* We calculate the bit duration at compile time to speed up and avoid pulling in soft-float libs */
#define BIT_DURATION_CYCLES ( ULP_RISCV_CYCLES_PER_US * ((1000*1000) / CONFIG_ULP_RISCV_UART_BAUDRATE) )
void ulp_riscv_uart_init(ulp_riscv_uart_t *uart, const ulp_riscv_uart_cfg_t *cfg)
{
uart->tx_pin = cfg->tx_pin;
/* 1 bit duration with length given in clock cycles */
uart->bit_duration_cycles = BIT_DURATION_CYCLES;
/* Setup GPIO used for uart TX */
ulp_riscv_gpio_init(cfg->tx_pin);
ulp_riscv_gpio_output_enable(cfg->tx_pin);
ulp_riscv_gpio_set_output_mode(cfg->tx_pin, RTCIO_MODE_OUTPUT_OD);
ulp_riscv_gpio_pullup(cfg->tx_pin);
ulp_riscv_gpio_pulldown_disable(cfg->tx_pin);
ulp_riscv_gpio_output_level(cfg->tx_pin, 1);
}
void ulp_riscv_uart_putc(const ulp_riscv_uart_t *uart, const char c)
{
ulp_riscv_gpio_output_level(uart->tx_pin, 0);
for (int i = 0; i<8; i++) {
/* Offset the delay to account for cycles spent setting the bit */
ulp_riscv_delay_cycles(uart->bit_duration_cycles - 100);
if ( (1 << i) & c) {
ulp_riscv_gpio_output_level(uart->tx_pin, 1);
} else {
ulp_riscv_gpio_output_level(uart->tx_pin, 0);
}
}
ulp_riscv_delay_cycles(uart->bit_duration_cycles - 20);
ulp_riscv_gpio_output_level(uart->tx_pin, 1);
ulp_riscv_delay_cycles(uart->bit_duration_cycles);
}

View File

@@ -35,15 +35,6 @@ void ulp_riscv_halt(void)
while(1);
}
void ulp_riscv_delay_cycles(uint32_t cycles)
{
uint32_t start = ULP_RISCV_GET_CCOUNT();
while ((ULP_RISCV_GET_CCOUNT() - start) < cycles) {
/* Wait */
}
}
void ulp_riscv_timer_stop(void)
{
CLEAR_PERI_REG_MASK(RTC_CNTL_ULP_CP_TIMER_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);