mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
Merge branch 'feature/dedicated_gpios_xtensa' into 'master'
Dedicated GPIO: add software UART implementation for Xtensa targets See merge request espressif/esp-idf!21918
This commit is contained in:
commit
74d87aef0c
@ -20,6 +20,3 @@ examples/peripherals/dedicated_gpio/soft_uart:
|
||||
- if: SOC_DEDICATED_GPIO_SUPPORTED != 1
|
||||
temporary: false
|
||||
reason: Target doesn't support dedicated GPIO
|
||||
- if: IDF_TARGET in ["esp32s2", "esp32s3"]
|
||||
temporary: true
|
||||
reason: Xtensa targets not supported yet
|
||||
|
@ -1,5 +1,5 @@
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- |
|
||||
| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# Example: UART software emulation using dedicated/fast GPIOs
|
||||
|
||||
@ -22,7 +22,7 @@ Due to the tight timing requirements of SW bit banging, the `asm_emulate_uart` f
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with a RISC-V Espressif SoC (e.g., ESP32-C3 or ESP32-C2)
|
||||
* A development board with one of the supported chips (see the list above.)
|
||||
* A USB cable for Power supply and programming
|
||||
* Some jumper wires to connect the UART to an external UART-to-USB adapter.
|
||||
|
||||
@ -34,7 +34,7 @@ Due to the strict timing requirements of the UART emulation, the UART emulation
|
||||
|
||||
### Build and flash the project
|
||||
|
||||
* Set the target of the project to a RISC-V-based one. For example:
|
||||
* Set the target of the project to a compatible one. For example:
|
||||
```
|
||||
idf.py set-target esp32c3
|
||||
```
|
||||
|
@ -1,9 +1,15 @@
|
||||
set(srcs "soft_uart.c")
|
||||
|
||||
# During CMake early expansion, Kconfig constants are not defined yet, thus, to
|
||||
# avoid having CMake falsely fail on all targets, do not send FATAL_ERROR at that moment
|
||||
if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED)
|
||||
if(CONFIG_IDF_TARGET_ARCH_RISCV)
|
||||
list(APPEND srcs "riscv/soft_uart.S")
|
||||
elseif(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||
message(FATAL_ERROR "Xtensa targets not supported yet")
|
||||
else()
|
||||
list(APPEND srcs "xtensa/soft_uart.S")
|
||||
endif()
|
||||
elseif(NOT CMAKE_BUILD_EARLY_EXPANSION)
|
||||
message(FATAL_ERROR "Target doesn't support dedicated gpios")
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
|
||||
.macro WRITE_GPIO_OUT mask value
|
||||
wr_mask_gpio_out \value, \mask
|
||||
.endm
|
||||
|
||||
.macro READ_GPIO_IN reg
|
||||
get_gpio_in \reg
|
||||
.endm
|
||||
|
||||
#else // CONFIG_IDF_TARGET_ESP32S3
|
||||
|
||||
.macro WRITE_GPIO_OUT mask value
|
||||
ee.wr_mask_gpio_out \value, \mask
|
||||
.endm
|
||||
|
||||
.macro READ_GPIO_IN reg
|
||||
ee.get_gpio_in \reg
|
||||
.endm
|
||||
|
||||
#endif
|
||||
|
||||
.section .text
|
||||
|
||||
/**
|
||||
* @brief Send bytes on the emulated UART.
|
||||
*
|
||||
* @param tx_buffer (a2) Buffer to send on the TX line. Guaranteed not NULL by the caller.
|
||||
* @param tx_size (a3) Size of tx_buffer. Guaranteed not 0 by the caller.
|
||||
* @param tx_bit (a4) Offset of TX I/O in the dedicated GPIO register.
|
||||
* @param baudrate (a5) CPU clock cycles taken by each bit.
|
||||
*
|
||||
* The C signature of this routine would be:
|
||||
* void emulate_uart_send(const uint8_t* tx, uint32_t tx_size, uint32_t tx_bit, uint32_t baudrate_delay);
|
||||
*/
|
||||
.global emulate_uart_send
|
||||
.type emulate_uart_send, @function
|
||||
emulate_uart_send:
|
||||
entry a1, 16
|
||||
/* Convert tx_bit into a bitmask */
|
||||
ssl a4
|
||||
movi a4, 1
|
||||
sll a4, a4
|
||||
/* Set the line to high */
|
||||
movi a7, 0xff
|
||||
WRITE_GPIO_OUT a4, a7
|
||||
mov a10, a5
|
||||
/* By calling delay here, we guarantee that in the following code, the next register window will
|
||||
* be free, as such, there won't be any window overflow */
|
||||
call8 uart_delay
|
||||
uart_send_loop:
|
||||
/* Start bit, clear/reset TX bit */
|
||||
movi a7, 0
|
||||
WRITE_GPIO_OUT a4, a7
|
||||
/* Wait for the given amount of CPU cycles */
|
||||
mov a10, a5
|
||||
call8 uart_delay
|
||||
/* Load the next byte and send it on the line */
|
||||
l8ui a6, a2, 0
|
||||
/* Use the upper bits of a6 to keep track of the remaining bits to send */
|
||||
movi a7, 0xff00
|
||||
or a6, a6, a7
|
||||
uart_send_next_bit:
|
||||
/* Take the LSB of a6 */
|
||||
mov a7, a4
|
||||
bbci a6, 0, uart_send_bit_0
|
||||
j uart_send_bit_end
|
||||
uart_send_bit_0:
|
||||
movi a7, 0
|
||||
uart_send_bit_end:
|
||||
WRITE_GPIO_OUT a4, a7
|
||||
srli a6, a6, 1
|
||||
/* Check if we still have bits to send */
|
||||
movi a7, 0x100
|
||||
/* Wait for the given amount of CPU cycles */
|
||||
mov a10, a5
|
||||
call8 uart_delay
|
||||
bge a6, a7, uart_send_next_bit
|
||||
/* Increment the tx_buffer and continue */
|
||||
addi a2, a2, 1
|
||||
addi a3, a3, -1
|
||||
/* Stop bit, set TX bit */
|
||||
WRITE_GPIO_OUT a4, a4
|
||||
mov a10, a5
|
||||
call8 uart_delay
|
||||
bnez a3, uart_send_loop
|
||||
retw
|
||||
|
||||
/* Register a2 contains the number of cycles to wait */
|
||||
.align 4
|
||||
uart_delay:
|
||||
entry a1, 16
|
||||
rsr.ccount a3
|
||||
add a2, a2, a3
|
||||
uart_delay_loop:
|
||||
rsr.ccount a3
|
||||
blt a3, a2, uart_delay_loop
|
||||
retw
|
||||
|
||||
/**
|
||||
* @brief Receive bytes from the emulated UART.
|
||||
*
|
||||
* @param rx_buffer (a2) Buffer to store the received bytes in. Guaranteed not NULL by the caller.
|
||||
* @param rx_size (a3) Size of rx_buffer. Guaranteed not 0 by the caller.
|
||||
* @param rx_bit (a4) Offset of RX I/O in the dedicated GPIO register.
|
||||
* @param baudrate (a5) CPU clock cycles taken by each bit.
|
||||
*
|
||||
* The C signature of this routine would be:
|
||||
* void emulate_uart_receive(uint8_t *rx_buffer, uint32_t tx_size, uint32_t rx_bit, uint32_t baudrate_delay);
|
||||
*/
|
||||
.global emulate_uart_receive
|
||||
.type emulate_uart_receive, @function
|
||||
emulate_uart_receive:
|
||||
entry a1, 16
|
||||
|
||||
read_next_byte:
|
||||
/* a6 contains the current bit being received */
|
||||
movi a6, 0x1
|
||||
/* Wait for the start bit (0) */
|
||||
wait_start_bit:
|
||||
READ_GPIO_IN a7
|
||||
bbs a7, a4, wait_start_bit
|
||||
/* a7 will now store the final byte */
|
||||
movi a7, 0
|
||||
/* Wait 1.5 baudrate cycle, this will let us read the next bit in the middle on its period */
|
||||
srli a10, a5, 1
|
||||
call8 uart_delay
|
||||
read_next_bit:
|
||||
mov a10, a5
|
||||
call8 uart_delay
|
||||
/* Read the RX line and store the bit */
|
||||
READ_GPIO_IN a8
|
||||
bbc a8, a4, read_not_set_bit
|
||||
/* Write the bit 1 in the final byte */
|
||||
or a7, a7, a6
|
||||
read_not_set_bit:
|
||||
slli a6, a6, 1
|
||||
movi a8, 0x100
|
||||
bne a6, a8, read_next_bit
|
||||
/* Save the received bit in the buffer */
|
||||
s8i a7, a2, 0
|
||||
addi a2, a2, 1
|
||||
/* Wait a baudrate period to make sure stop bit is being sent */
|
||||
mov a10, a5
|
||||
call8 uart_delay
|
||||
/* Check if we have received all the characters */
|
||||
addi a3, a3, -1
|
||||
bnez a3, read_next_byte
|
||||
retw
|
Loading…
x
Reference in New Issue
Block a user