-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feature/dedicated_gpios_xtensa' into 'master'
Dedicated GPIO: add software UART implementation for Xtensa targets See merge request espressif/esp-idf!21918
- Loading branch information
Showing
4 changed files
with
170 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 10 additions & 4 deletions
14
examples/peripherals/dedicated_gpio/soft_uart/components/soft_uart/CMakeLists.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
examples/peripherals/dedicated_gpio/soft_uart/components/soft_uart/xtensa/soft_uart.S
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |