[realtek-ambz2] Fix C++ support, implement SerialClass

This commit is contained in:
Kuba Szczodrzyński
2023-05-25 14:33:38 +02:00
parent c0cc602c9a
commit 9b7d34fa65
10 changed files with 161 additions and 45 deletions

View File

@@ -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",

View File

@@ -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;
}

View File

@@ -0,0 +1,18 @@
/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */
#pragma once
#include <Arduino.h>
#include <sdk_private.h>
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)

View File

@@ -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

View File

@@ -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'

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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.

View File

@@ -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.