From 9b7d34fa65933a08ddd9c7d4d2a1aa0dcd12d494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 May 2023 14:33:38 +0200 Subject: [PATCH] [realtek-ambz2] Fix C++ support, implement SerialClass --- builder/family/realtek-ambz2.py | 2 +- .../arduino/libraries/Serial/Serial.cpp | 94 +++++++++++++++++++ .../arduino/libraries/Serial/SerialPrivate.h | 18 ++++ cores/realtek-ambz2/arduino/src/lt_defs.h | 7 ++ cores/realtek-ambz2/base/lt_family.h | 4 + cores/realtek-ambz2/base/port/printf.c | 2 +- cores/realtek-ambz2/base/sdk_extern.h | 1 + cores/realtek-ambz2/misc/rtl8710c_ram.ld | 67 +++++-------- docs/contrib/porting.md | 7 ++ docs/flashing/tools/adr.md | 4 + 10 files changed, 161 insertions(+), 45 deletions(-) create mode 100644 cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp create mode 100644 cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h create mode 100644 cores/realtek-ambz2/arduino/src/lt_defs.h diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index c6b2bbe..1b8a617 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -53,7 +53,7 @@ queue.AppendPublic( "-mthumb", "-mcmse", "-mfloat-abi=soft", - "--specs=nosys.specs", + "--specs=nano.specs", "-Wl,--use-blx", "-Wl,--undefined=gRamStartFun", "-Wl,-wrap,aesccmp_construct_mic_iv", diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp new file mode 100644 index 0000000..eb1e462 --- /dev/null +++ b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp @@ -0,0 +1,94 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2023-05-24. */ + +#include "SerialPrivate.h" + +#if HAS_SERIAL0 +SerialClass Serial0(0, PIN_SERIAL0_RX, PIN_SERIAL0_TX); +#endif +#if HAS_SERIAL1 +SerialClass Serial1(1, PIN_SERIAL1_RX, PIN_SERIAL1_TX); +#endif +#if HAS_SERIAL2 +SerialClass Serial2(2, PIN_SERIAL2_RX, PIN_SERIAL2_TX); +#endif + +static void callback(uint32_t param, uint32_t event) { + if (event != RxIrq) + return; + hal_uart_adapter_t *uart = &pdUART; + + uint8_t c; + while (hal_uart_rgetc(uart, (char *)&c)) { +#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && PIN_SERIAL2_RX != PIN_INVALID + // parse UART protocol commands on UART2 + if (uart->base_addr == UART2) + SerialClass::adrParse(c); +#endif + pdBUF.store_char(c); + } +} + +void SerialClass::begin(unsigned long baudrate, uint16_t config) { + if (!this->data) { + this->data = new SerialData(); + this->buf = &BUF; + + if (this->port == 2) { + hal_uart_deinit(&log_uart); + } + + // TODO handle PIN_INVALID + hal_uart_init(&UART, this->tx, this->rx, NULL); + + if (this->rx != PIN_INVALID) { + hal_uart_enter_critical(); + hal_uart_rxind_hook(&UART, callback, (uint32_t)this->data, RxIrq); + UART.base_addr->ier_b.erbi = 1; + UART.base_addr->ier_b.etbei = 0; + hal_uart_exit_critical(); + } + } + + if (this->baudrate != baudrate || this->config != config) + this->configure(baudrate, config); +} + +void SerialClass::configure(unsigned long baudrate, uint16_t config) { + if (!this->data) + return; + + uint8_t dataWidth = (config & SERIAL_DATA_MASK) == SERIAL_DATA_7 ? 7 : 8; + uint8_t parity = (config & SERIAL_PARITY_MASK) ^ 0b11; + uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2 ? 2 : 1; + + hal_uart_set_baudrate(&UART, baudrate); + hal_uart_set_format(&UART, dataWidth, parity, stopBits); + + this->baudrate = baudrate; + this->config = config; +} + +void SerialClass::end() { + if (!this->data) + return; + + hal_uart_deinit(&UART); + + this->buf = NULL; + this->baudrate = 0; + delete DATA; +} + +void SerialClass::flush() { + if (!this->data) + return; + while (UART.base_addr->tflvr_b.tx_fifo_lv != 0) {} +} + +size_t SerialClass::write(uint8_t c) { + if (!this->data) + return 0; + while (!hal_uart_writeable(&UART)) {} + hal_uart_putc(&UART, c); + return 1; +} diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h b/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h new file mode 100644 index 0000000..48c4d04 --- /dev/null +++ b/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h @@ -0,0 +1,18 @@ +/* Copyright (c) Kuba SzczodrzyƄski 2023-05-24. */ + +#pragma once + +#include +#include + +typedef struct { + hal_uart_adapter_t uart; + RingBuffer buf; +} SerialData; + +#define DATA ((SerialData *)data) +#define pDATA ((SerialData *)param) +#define BUF (DATA->buf) +#define pdBUF (pDATA->buf) +#define UART (DATA->uart) +#define pdUART (pDATA->uart) diff --git a/cores/realtek-ambz2/arduino/src/lt_defs.h b/cores/realtek-ambz2/arduino/src/lt_defs.h new file mode 100644 index 0000000..b79eb88 --- /dev/null +++ b/cores/realtek-ambz2/arduino/src/lt_defs.h @@ -0,0 +1,7 @@ +#pragma once + +#error "Don't include this file directly" + +#define LT_ARD_HAS_SERIAL 1 + +#define LT_ARD_MD5_MBEDTLS 1 diff --git a/cores/realtek-ambz2/base/lt_family.h b/cores/realtek-ambz2/base/lt_family.h index 9723ffb..d9c9f41 100644 --- a/cores/realtek-ambz2/base/lt_family.h +++ b/cores/realtek-ambz2/base/lt_family.h @@ -16,3 +16,7 @@ #error "No serial port is available" #endif #endif + +// Auto-download-reboot detection pattern +// "ping" command for BootROM +#define LT_UART_ADR_PATTERN 'p', 'i', 'n', 'g', '\n' diff --git a/cores/realtek-ambz2/base/port/printf.c b/cores/realtek-ambz2/base/port/printf.c index f3aa09b..d151780 100644 --- a/cores/realtek-ambz2/base/port/printf.c +++ b/cores/realtek-ambz2/base/port/printf.c @@ -19,7 +19,7 @@ void putchar_(char c) { } void putchar_p(char c, unsigned long port) { - while ((uart_dev[port]->tflvr & 0x1F) > 15) {} + while (uart_dev[port]->tflvr_b.tx_fifo_lv >= Uart_Tx_FIFO_Size) {} uart_dev[port]->thr = c; } diff --git a/cores/realtek-ambz2/base/sdk_extern.h b/cores/realtek-ambz2/base/sdk_extern.h index 476e0ee..e5d5c1a 100644 --- a/cores/realtek-ambz2/base/sdk_extern.h +++ b/cores/realtek-ambz2/base/sdk_extern.h @@ -10,6 +10,7 @@ extern "C" { #endif // __cplusplus // SDK +extern hal_uart_adapter_t log_uart; void software_reset(); void sys_swd_off(); void sys_uart_download_mode(); diff --git a/cores/realtek-ambz2/misc/rtl8710c_ram.ld b/cores/realtek-ambz2/misc/rtl8710c_ram.ld index cc6a48d..221819e 100644 --- a/cores/realtek-ambz2/misc/rtl8710c_ram.ld +++ b/cores/realtek-ambz2/misc/rtl8710c_ram.ld @@ -134,26 +134,6 @@ SECTIONS *(.sram.data*) *(.data*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP(*(SORT(.fini_array.*))) - KEEP(*(.fini_array)) - PROVIDE_HIDDEN (__fini_array_end = .); - KEEP(*(.jcr*)) . = ALIGN(4); /* All data end */ @@ -282,29 +262,6 @@ SECTIONS /* put RO data sections need to be encrypted here */ *(.xip.sec_rodata*) - /* Add This for C++ support */ - /* ambd_arduino/Arduino_package/hardware/variants/rtl8720dn_bw16/linker_scripts/gcc/rlx8721d_img2_is_arduino.ld */ - . = ALIGN(4); - __preinit_array_start = .; - KEEP(*(.preinit_array)) - __preinit_array_end = .; - . = ALIGN(4); - __init_array_start = .; - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - __init_array_end = .; - . = ALIGN(4); - __fini_array_start = .; - KEEP(*(SORT(.fini_array.*))) - KEEP(*(.fini_array)) - __fini_array_end = .; - /*-----------------*/ - /* https://community.silabs.com/s/article/understand-the-gnu-linker-script-of-cortex-m4?language=en_US */ - KEEP(*(.init)) - KEEP(*(.fini)) - *(.init) - *(.fini) - __xip_code_text_end__ = .; } > XIP_FLASH_C @@ -330,6 +287,30 @@ SECTIONS KEEP(*crtend.o(.dtors)) *(.rodata .rodata.* .gnu.linkonce.r.*) + /* Add This for C++ support */ + /* ambd_arduino/Arduino_package/hardware/variants/rtl8720dn_bw16/linker_scripts/gcc/rlx8721d_img2_is_arduino.ld */ + . = ALIGN(4); + __preinit_array_start = .; + KEEP(*(.preinit_array)) + __preinit_array_end = .; + . = ALIGN(4); + __init_array_start = .; + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + __init_array_end = .; + . = ALIGN(4); + __fini_array_start = .; + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + __fini_array_end = .; + /*-----------------*/ + + /* https://community.silabs.com/s/article/understand-the-gnu-linker-script-of-cortex-m4?language=en_US */ + KEEP(*(.init)) + KEEP(*(.fini)) + *(.init) + *(.fini) + . = ALIGN(4); __xip_code_rodata_end__ = .; } > XIP_FLASH_P diff --git a/docs/contrib/porting.md b/docs/contrib/porting.md index 48f7275..61cc4d8 100644 --- a/docs/contrib/porting.md +++ b/docs/contrib/porting.md @@ -50,6 +50,7 @@ Here's what has to be done to make that work: - Make sure not to make a mess in the `CCFLAGS`/`CPPDEFINES`, and only include what's needed there. Some flags are project-wide (family-independent) in `builder/frameworks/base.py`. - Use a **pure PlatformIO** project - **not ESPHome!**. Pass one of the generic boards you created before, and `framework = base` in `platformio.ini`. Generally, try to get the thing to compile. - Use a simple Hello World program - C, not C++. Only add `main()` function with a `printf()` and a `while(1)` loop. + - I've noticed that using `nano.specs` instead of `nosys.specs` produces smaller binaries. 9. When you get it to link successfully, build a UF2 file. @@ -91,3 +92,9 @@ Here's what has to be done to make that work: 5. Write LibreTiny C APIs - in `lt_api.c`. 6. At this point, your Hello World code should work fine. + +## Porting Arduino Core - C++ support + +1. Add main.cpp and write wiring_*.c ports. GPIOs and stuff should work even without proper C++ support. + +2. Port Serial library first. This should already show whether C++ works fine or if it doesn't. For example, calling `Serial.println()` refers to the virtual function `Print::write`, which will probably crash the chip if C++ is not being linked properly. diff --git a/docs/flashing/tools/adr.md b/docs/flashing/tools/adr.md index a976b67..3c41299 100644 --- a/docs/flashing/tools/adr.md +++ b/docs/flashing/tools/adr.md @@ -16,3 +16,7 @@ The code listens on UART1 for a link-check command (`01 E0 FC 01 00`). The baudr ## Realtek AmebaZ This only works when using [ltchiptool](ltchiptool.md) for flashing. Upon starting UART communication, the tool sends `55 AA 22 E0 D6 FC` (0x55AA followed by the `realtek-ambz` family ID). After detecting that pattern, the chip proceeds to reboot into UART download mode (using [`lt_reboot_download_mode()`](../../../ltapi/lt__device_8h.md)) + +## Realtek AmebaZ2 + +The code listens on UART2 for a `ping\n` command, that is sent by [ltchiptool](ltchiptool.md) (and possibly by the vendor flasher, too). The device is then rebooted to download mode.