boards: cc1352p1_launchxl: new board, support antenna switching
Added new CC1352P1 LaunchXL board supporting 20dBm TX for its sub-GHz radio. Note that the board has a multiplexer circuit to switch between 2.4GHz, High-Power TX and Sub1GHz states, for which a custom board module was implemented, together with board-specific device-tree bindings and pinctrl definitions for each of the RF states. Signed-off-by: Stancu Florin <niflostancu@gmail.com>
This commit is contained in:
parent
e41de9235a
commit
817e41f965
15 changed files with 768 additions and 36 deletions
6
boards/arm/cc1352p1_launchxl/CMakeLists.txt
Normal file
6
boards/arm/cc1352p1_launchxl/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_sources(
|
||||
board_antenna.c
|
||||
)
|
20
boards/arm/cc1352p1_launchxl/Kconfig.board
Normal file
20
boards/arm/cc1352p1_launchxl/Kconfig.board
Normal file
|
@ -0,0 +1,20 @@
|
|||
# TI CC1352R LaunchXL board
|
||||
|
||||
# Copyright (c) 2021 Florin Stancu
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config BOARD_CC1352P1_LAUNCHXL
|
||||
bool "TI CC1352P1 LaunchXL"
|
||||
depends on SOC_CC1352P
|
||||
|
||||
if BOARD_CC1352P1_LAUNCHXL
|
||||
|
||||
config BOARD_ANTENNA_INIT_PRIO
|
||||
int "Board antenna switch initialization priority"
|
||||
default 70
|
||||
help
|
||||
Set the priority for board init, must be greater than
|
||||
KERNEL_INIT_PRIORITY_DEVICE but smaller than
|
||||
IEEE802154_CC13XX_CC26XX_SUB_GHZ_INIT_PRIO.
|
||||
|
||||
endif # BOARD_CC1352P1_LAUNCHXL
|
11
boards/arm/cc1352p1_launchxl/Kconfig.defconfig
Normal file
11
boards/arm/cc1352p1_launchxl/Kconfig.defconfig
Normal file
|
@ -0,0 +1,11 @@
|
|||
# TI CC1352P1 LaunchXL board
|
||||
|
||||
# Copyright (c) 2021 Florin Stancu
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if BOARD_CC1352P1_LAUNCHXL
|
||||
|
||||
config BOARD
|
||||
default "cc1352p1_launchxl"
|
||||
|
||||
endif # BOARD_CC1352P1_LAUNCHXL
|
5
boards/arm/cc1352p1_launchxl/board.cmake
Normal file
5
boards/arm/cc1352p1_launchxl/board.cmake
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Copyright (c) 2021 Florin Stancu
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
|
135
boards/arm/cc1352p1_launchxl/board_antenna.c
Normal file
135
boards/arm/cc1352p1_launchxl/board_antenna.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Florin Stancu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implements the RF driver callback to configure the on-board antenna
|
||||
* switch.
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT skyworks_sky13317
|
||||
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
|
||||
#include <ti/drivers/rf/RF.h>
|
||||
#include <driverlib/rom.h>
|
||||
#include <driverlib/interrupt.h>
|
||||
|
||||
/* custom pinctrl states for the antenna mux */
|
||||
#define PINCTRL_STATE_ANT_24G 1
|
||||
#define PINCTRL_STATE_ANT_24G_PA 2
|
||||
#define PINCTRL_STATE_ANT_SUBG 3
|
||||
#define PINCTRL_STATE_ANT_SUBG_PA 4
|
||||
|
||||
#define BOARD_ANT_GPIO_24G 0
|
||||
#define BOARD_ANT_GPIO_PA 1
|
||||
#define BOARD_ANT_GPIO_SUBG 2
|
||||
|
||||
#define ANTENNA_MUX DT_NODELABEL(antenna_mux0)
|
||||
|
||||
static int board_antenna_init(const struct device *dev);
|
||||
static void board_cc13xx_rf_callback(RF_Handle client, RF_GlobalEvent events,
|
||||
void *arg);
|
||||
|
||||
const RFCC26XX_HWAttrsV2 RFCC26XX_hwAttrs = {
|
||||
.hwiPriority = INT_PRI_LEVEL7,
|
||||
.swiPriority = 0,
|
||||
.xoscHfAlwaysNeeded = true,
|
||||
/* RF driver callback for custom antenna switching */
|
||||
.globalCallback = board_cc13xx_rf_callback,
|
||||
/* Subscribe to events */
|
||||
.globalEventMask = (RF_GlobalEventRadioSetup |
|
||||
RF_GlobalEventRadioPowerDown),
|
||||
};
|
||||
|
||||
PINCTRL_DT_INST_DEFINE(0);
|
||||
DEVICE_DT_INST_DEFINE(0, board_antenna_init, NULL, NULL, NULL,
|
||||
POST_KERNEL, CONFIG_BOARD_ANTENNA_INIT_PRIO, NULL);
|
||||
|
||||
static const struct pinctrl_dev_config *ant_pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0);
|
||||
static const struct gpio_dt_spec ant_gpios[] = {
|
||||
GPIO_DT_SPEC_GET_BY_IDX_OR(ANTENNA_MUX, gpios, BOARD_ANT_GPIO_24G, {0}),
|
||||
GPIO_DT_SPEC_GET_BY_IDX_OR(ANTENNA_MUX, gpios, BOARD_ANT_GPIO_PA, {0}),
|
||||
GPIO_DT_SPEC_GET_BY_IDX_OR(ANTENNA_MUX, gpios, BOARD_ANT_GPIO_SUBG, {0}),
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Antenna switch GPIO init routine.
|
||||
*/
|
||||
int board_antenna_init(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
int i;
|
||||
|
||||
/* default pinctrl configuration: set all antenna mux control pins as GPIOs */
|
||||
pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_DEFAULT);
|
||||
/* set all GPIOs to 0 (all RF paths disabled) */
|
||||
for (i = 0; i < ARRAY_SIZE(ant_gpios); i++) {
|
||||
gpio_pin_configure_dt(&ant_gpios[i], 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom TI RFCC26XX callback for switching the on-board antenna mux on radio setup.
|
||||
*/
|
||||
void board_cc13xx_rf_callback(RF_Handle client, RF_GlobalEvent events, void *arg)
|
||||
{
|
||||
bool sub1GHz = false;
|
||||
uint8_t loDivider = 0;
|
||||
int i;
|
||||
|
||||
/* Clear all antenna switch GPIOs (for all cases). */
|
||||
for (i = 0; i < ARRAY_SIZE(ant_gpios); i++) {
|
||||
gpio_pin_configure_dt(&ant_gpios[i], 0);
|
||||
}
|
||||
|
||||
if (events & RF_GlobalEventRadioSetup) {
|
||||
/* Decode the current PA configuration. */
|
||||
RF_TxPowerTable_PAType paType = (RF_TxPowerTable_PAType)
|
||||
RF_getTxPower(client).paType;
|
||||
/* Decode the generic argument as a setup command. */
|
||||
RF_RadioSetup *setupCommand = (RF_RadioSetup *)arg;
|
||||
|
||||
switch (setupCommand->common.commandNo) {
|
||||
case CMD_RADIO_SETUP:
|
||||
case CMD_BLE5_RADIO_SETUP:
|
||||
loDivider = RF_LODIVIDER_MASK & setupCommand->common.loDivider;
|
||||
break;
|
||||
case CMD_PROP_RADIO_DIV_SETUP:
|
||||
loDivider = RF_LODIVIDER_MASK & setupCommand->prop_div.loDivider;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sub1GHz = (loDivider != 0);
|
||||
|
||||
if (sub1GHz) {
|
||||
if (paType == RF_TxPowerTable_HighPA) {
|
||||
/* Note: RFC_GPO3 is a work-around because the RFC_GPO1 */
|
||||
/* is sometimes not de-asserted on CC1352 Rev A. */
|
||||
pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_SUBG_PA);
|
||||
} else {
|
||||
pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_SUBG);
|
||||
/* Manually set the sub-GHZ antenna switch DIO */
|
||||
gpio_pin_configure_dt(&ant_gpios[BOARD_ANT_GPIO_SUBG], 1);
|
||||
}
|
||||
} else /* 2.4 GHz */ {
|
||||
if (paType == RF_TxPowerTable_HighPA) {
|
||||
pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_24G_PA);
|
||||
} else {
|
||||
pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_ANT_24G);
|
||||
/* Manually set the 2.4GHZ antenna switch DIO */
|
||||
gpio_pin_configure_dt(&ant_gpios[BOARD_ANT_GPIO_24G], 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pinctrl_apply_state(ant_pcfg, PINCTRL_STATE_DEFAULT);
|
||||
}
|
||||
}
|
81
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl-pinctrl.dtsi
Normal file
81
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl-pinctrl.dtsi
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Vaishnav Achath
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/dt-bindings/pinctrl/cc13xx_cc26xx-pinctrl.h>
|
||||
|
||||
&pinctrl {
|
||||
/* UART0 */
|
||||
uart0_tx_default: uart0_tx_default {
|
||||
pinmux = <13 IOC_PORT_MCU_UART0_TX>;
|
||||
bias-disable;
|
||||
};
|
||||
uart0_rx_default: uart0_rx_default {
|
||||
pinmux = <12 IOC_PORT_MCU_UART0_RX>;
|
||||
bias-disable;
|
||||
input-enable;
|
||||
};
|
||||
|
||||
/* I2C0 */
|
||||
i2c0_scl_default: i2c0_scl_default {
|
||||
pinmux = <4 IOC_PORT_MCU_I2C_MSSCL>;
|
||||
bias-pull-up;
|
||||
drive-open-drain;
|
||||
input-enable;
|
||||
};
|
||||
i2c0_sda_default: i2c0_sda_default {
|
||||
pinmux = <5 IOC_PORT_MCU_I2C_MSSDA>;
|
||||
bias-pull-up;
|
||||
drive-open-drain;
|
||||
input-enable;
|
||||
};
|
||||
i2c0_scl_sleep: i2c0_scl_sleep {
|
||||
pinmux = <4 IOC_PORT_GPIO>;
|
||||
bias-disable;
|
||||
};
|
||||
i2c0_sda_sleep: i2c0_sda_sleep {
|
||||
pinmux = <5 IOC_PORT_GPIO>;
|
||||
bias-disable;
|
||||
};
|
||||
|
||||
/* SPI0 */
|
||||
spi0_sck_default: spi0_sck_default {
|
||||
pinmux = <10 IOC_PORT_MCU_SSI0_CLK>;
|
||||
bias-disable;
|
||||
};
|
||||
spi0_mosi_default: spi0_mosi_default {
|
||||
pinmux = <9 IOC_PORT_MCU_SSI0_TX>;
|
||||
bias-disable;
|
||||
};
|
||||
spi0_miso_default: spi0_miso_default {
|
||||
pinmux = <8 IOC_PORT_MCU_SSI0_RX>;
|
||||
bias-disable;
|
||||
input-enable;
|
||||
};
|
||||
spi0_cs_default: spi0_cs_default {
|
||||
pinmux = <11 IOC_PORT_MCU_SSI0_FSS>;
|
||||
bias-disable;
|
||||
};
|
||||
|
||||
/* On-board antenna pinmux states */
|
||||
board_ant_24g_off: board_ant_24g_off {
|
||||
pinmux = <28 IOC_PORT_GPIO>;
|
||||
};
|
||||
board_ant_24g_on: board_ant_24g_on {
|
||||
pinmux = <28 IOC_PORT_RFC_GPO0>;
|
||||
};
|
||||
board_ant_tx_pa_off: board_ant_tx_pa_off {
|
||||
pinmux = <29 IOC_PORT_GPIO>;
|
||||
};
|
||||
board_ant_tx_pa_on: board_ant_tx_pa_on {
|
||||
pinmux = <29 IOC_PORT_RFC_GPO3>;
|
||||
};
|
||||
board_ant_subg_off: board_ant_subg_off {
|
||||
pinmux = <30 IOC_PORT_GPIO>;
|
||||
};
|
||||
board_ant_subg_on: board_ant_subg_on {
|
||||
pinmux = <30 IOC_PORT_RFC_GPO0>;
|
||||
};
|
||||
};
|
147
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts
Normal file
147
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.dts
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Florin Stancu
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <ti/cc1352r.dtsi>
|
||||
#include "../cc1352r1_launchxl/boosterpack_connector.dtsi"
|
||||
#include "cc1352p1_launchxl-pinctrl.dtsi"
|
||||
|
||||
/ {
|
||||
model = "TI CC1352P1 LaunchXL";
|
||||
compatible = "ti,launchxl-cc1352p1";
|
||||
|
||||
aliases {
|
||||
led0 = &led0;
|
||||
led1 = &led1;
|
||||
sw0 = &btn0;
|
||||
sw1 = &btn1;
|
||||
};
|
||||
|
||||
chosen {
|
||||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &uart0;
|
||||
zephyr,shell-uart = &uart0;
|
||||
zephyr,ieee802154 = &ieee802154;
|
||||
};
|
||||
|
||||
/**
|
||||
* The CC1352P LAUNCHXL has an on-board antenna switch (SKY13317-373LF) used to select the
|
||||
* appropriate RF signal port based on the currently-used PHY.
|
||||
*
|
||||
* Truth table:
|
||||
*
|
||||
* Path DIO28 DIO29 DIO30
|
||||
* =========== ===== ===== =====
|
||||
* Off 0 0 0
|
||||
* Sub-1 GHz 0 0 1 // DIO30 mux to IOC_PORT_RFC_GPO0 for auto
|
||||
* 2.4 GHz 1 0 0 // DIO28 mux to IOC_PORT_RFC_GPO0 for auto
|
||||
* 20 dBm TX 0 1 0 // DIO29 mux to IOC_PORT_RFC_GPO3 for auto
|
||||
*/
|
||||
antenna_mux0: antenna_mux0 {
|
||||
compatible = "skyworks,sky13317";
|
||||
status = "okay";
|
||||
gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>, <&gpio0 29 GPIO_ACTIVE_HIGH>, \
|
||||
<&gpio0 30 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-0 = <&board_ant_24g_off &board_ant_tx_pa_off &board_ant_subg_off>;
|
||||
pinctrl-1 = <&board_ant_24g_on &board_ant_tx_pa_off &board_ant_subg_off>;
|
||||
pinctrl-2 = <&board_ant_24g_on &board_ant_tx_pa_on &board_ant_subg_off>;
|
||||
pinctrl-3 = <&board_ant_24g_off &board_ant_tx_pa_off &board_ant_subg_on>;
|
||||
pinctrl-4 = <&board_ant_24g_off &board_ant_tx_pa_on &board_ant_subg_on>;
|
||||
pinctrl-names = "default", "ant_24g", "ant_24g_pa", "ant_subg", "ant_subg_pa";
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led0: led_0 {
|
||||
gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
|
||||
label = "Green LED";
|
||||
};
|
||||
led1: led_1 {
|
||||
gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
|
||||
label = "Red LED";
|
||||
};
|
||||
};
|
||||
|
||||
keys {
|
||||
compatible = "gpio-keys";
|
||||
btn0: btn_0 {
|
||||
gpios = <&gpio0 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
|
||||
label = "Push button 1";
|
||||
};
|
||||
btn1: btn_1 {
|
||||
gpios = <&gpio0 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
|
||||
label = "Push button 2";
|
||||
};
|
||||
};
|
||||
|
||||
power-states {
|
||||
idle: idle {
|
||||
compatible = "zephyr,power-state";
|
||||
power-state-name = "suspend-to-idle";
|
||||
min-residency-us = <1000>;
|
||||
};
|
||||
|
||||
standby: standby {
|
||||
compatible = "zephyr,power-state";
|
||||
power-state-name = "standby";
|
||||
min-residency-us = <5000>;
|
||||
exit-latency-us = <240>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&cpu0 {
|
||||
clock-frequency = <48000000>;
|
||||
cpu-power-states = <&idle &standby>;
|
||||
};
|
||||
|
||||
&trng {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_rx_default &uart0_tx_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&i2c0_scl_default &i2c0_sda_default>;
|
||||
pinctrl-1 = <&i2c0_scl_sleep &i2c0_sda_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spi0_sck_default &spi0_mosi_default
|
||||
&spi0_miso_default &spi0_cs_default>;
|
||||
pinctrl-names = "default";
|
||||
cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
&rtc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&ieee802154 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&ieee802154g {
|
||||
status = "disabled";
|
||||
};
|
14
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.yaml
Normal file
14
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl.yaml
Normal file
|
@ -0,0 +1,14 @@
|
|||
identifier: cc1352p1_launchxl
|
||||
name: TI SimpleLink CC1352P LaunchPad
|
||||
type: mcu
|
||||
arch: arm
|
||||
ram: 80
|
||||
flash: 352
|
||||
toolchain:
|
||||
- zephyr
|
||||
- gnuarmemb
|
||||
- xtools
|
||||
supported:
|
||||
- gpio
|
||||
- i2c
|
||||
- spi
|
27
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl_defconfig
Normal file
27
boards/arm/cc1352p1_launchxl/cc1352p1_launchxl_defconfig
Normal file
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# Copyright (c) 2021 Florin Stancu
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
CONFIG_SOC_SERIES_CC13X2_CC26X2=y
|
||||
CONFIG_SOC_CC1352P=y
|
||||
CONFIG_BOARD_CC1352P1_LAUNCHXL=y
|
||||
CONFIG_BUILD_OUTPUT_HEX=y
|
||||
# custom callback for the antenna switch
|
||||
CONFIG_CC13X2_CC26X2_HAS_CUSTOM_RF_HWATTRS=y
|
||||
|
||||
CONFIG_CC13X2_CC26X2_BOOTLOADER_ENABLE=y
|
||||
CONFIG_CC13X2_CC26X2_BOOTLOADER_BACKDOOR_ENABLE=y
|
||||
CONFIG_CC13X2_CC26X2_BOOTLOADER_BACKDOOR_PIN=15
|
||||
|
||||
# Enable MPU and hardware stack protection
|
||||
CONFIG_ARM_MPU=y
|
||||
CONFIG_HW_STACK_PROTECTION=y
|
||||
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_SERIAL=y
|
||||
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_UART_CONSOLE=y
|
BIN
boards/arm/cc1352p1_launchxl/doc/img/cc1352p1_launchxl.jpg
Normal file
BIN
boards/arm/cc1352p1_launchxl/doc/img/cc1352p1_launchxl.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
244
boards/arm/cc1352p1_launchxl/doc/index.rst
Normal file
244
boards/arm/cc1352p1_launchxl/doc/index.rst
Normal file
|
@ -0,0 +1,244 @@
|
|||
.. _cc1352p1_launchxl:
|
||||
|
||||
CC1352P1 LaunchXL
|
||||
#################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
The Texas Instruments CC1352P LaunchPad |trade| (LAUNCHXL-CC1352P1) is a
|
||||
development kit for the SimpleLink |trade| multi-Standard CC1352P wireless MCU.
|
||||
|
||||
See the `TI CC1352P LaunchPad Product Page`_ for details.
|
||||
|
||||
.. figure:: img/cc1352p1_launchxl.jpg
|
||||
:width: 400px
|
||||
:align: center
|
||||
:alt: TI CC1352P1 LaunchPad
|
||||
|
||||
Texas Instruments CC1352P1 LaunchPad |trade|
|
||||
|
||||
Hardware
|
||||
********
|
||||
|
||||
The CC1352P LaunchPad |trade| development kit features the CC1352P wireless MCU.
|
||||
The board is equipped with two LEDs, two push buttons, antenna switch and
|
||||
BoosterPack connectors for expansion. It also includes an integrated (XDS110)
|
||||
debugger.
|
||||
|
||||
The CC1352P wireless MCU has a 48 MHz Arm |reg| Cortex |reg|-M4F SoC and an
|
||||
integrated sub-1GHz and 2.4 GHz transceiver with integrated 20dBm power amplifier
|
||||
(PA) supporting multiple protocols including Bluetooth |reg| Low Energy and IEEE
|
||||
|reg| 802.15.4.
|
||||
|
||||
See the `TI CC1352P Product Page`_ for additional details.
|
||||
|
||||
Supported Features
|
||||
==================
|
||||
|
||||
The CC1352P LaunchPad board configuration supports the following hardware
|
||||
features:
|
||||
|
||||
+-----------+------------+----------------------+
|
||||
| Interface | Controller | Driver/Component |
|
||||
+===========+============+======================+
|
||||
| GPIO | on-chip | gpio |
|
||||
+-----------+------------+----------------------+
|
||||
| MPU | on-chip | arch/arm |
|
||||
+-----------+------------+----------------------+
|
||||
| NVIC | on-chip | arch/arm |
|
||||
+-----------+------------+----------------------+
|
||||
| PINMUX | on-chip | pinmux |
|
||||
+-----------+------------+----------------------+
|
||||
| UART | on-chip | serial |
|
||||
+-----------+------------+----------------------+
|
||||
| I2C | on-chip | i2c |
|
||||
+-----------+------------+----------------------+
|
||||
| SPI | on-chip | spi |
|
||||
+-----------+------------+----------------------+
|
||||
|
||||
Other hardware features have not been enabled yet for this board.
|
||||
|
||||
Connections and IOs
|
||||
===================
|
||||
|
||||
All I/O signals are accessible from the BoosterPack connectors. Pin function
|
||||
aligns with the LaunchPad standard.
|
||||
|
||||
+-------+-----------+---------------------+
|
||||
| Pin | Function | Usage |
|
||||
+=======+===========+=====================+
|
||||
| DIO3 | GPIO | |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO4 | I2C_MSSCL | I2C SCL |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO5 | I2C_MSSDA | I2C SDA |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO6 | GPIO | Red LED |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO7 | GPIO | Green LED |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO8 | SSI0_RX | SPI MISO |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO9 | SSI0_TX | SPI MOSI |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO10 | SSI0_CLK | SPI CLK |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO11 | SSIO_CS | SPI CS |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO12 | UART0_RX | UART RXD |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO13 | UART0_TX | UART TXD |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO14 | GPIO | Button 2 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO15 | GPIO | Button 1 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO16 | | JTAG TDO |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO17 | | JTAG TDI |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO18 | UART0_RTS | UART RTS / JTAG SWO |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO19 | UART0_CTS | UART CTS |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO20 | GPIO | Flash CS |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO21 | GPIO | |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO22 | GPIO | |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO23 | AUX_IO | A0 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO24 | AUX_IO | A1 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO25 | AUX_IO | A2 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO26 | AUX_IO | A3 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO27 | AUX_IO | A4 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO28 | AUX_IO | A5 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO29 | AUX_IO | A6 |
|
||||
+-------+-----------+---------------------+
|
||||
| DIO30 | AUX_IO | A7 |
|
||||
+-------+-----------+---------------------+
|
||||
|
||||
Programming and Debugging
|
||||
*************************
|
||||
|
||||
Before flashing or debugging ensure the RESET, TMS, TCK, TDO, and TDI jumpers
|
||||
are in place. Also place jumpers on the the TXD and RXD signals for a serial
|
||||
console using the XDS110 application serial port.
|
||||
|
||||
Prerequisites:
|
||||
==============
|
||||
|
||||
#. Ensure the XDS-110 emulation firmware on the board is updated.
|
||||
|
||||
Download and install the latest `XDS-110 emulation package`_.
|
||||
|
||||
Follow these `xds110 firmware update directions
|
||||
<http://software-dl.ti.com/ccs/esd/documents/xdsdebugprobes/emu_xds110.html#updating-the-xds110-firmware>`_
|
||||
|
||||
Note that the emulation package install may place the xdsdfu utility
|
||||
in ``<install_dir>/ccs_base/common/uscif/xds110/``.
|
||||
|
||||
#. Install OpenOCD
|
||||
|
||||
You can obtain OpenOCD by following these
|
||||
:ref:`installing the latest Zephyr SDK instructions <toolchain_zephyr_sdk>`.
|
||||
|
||||
After the installation, add the directory containing the OpenOCD executable
|
||||
to your environment's PATH variable. For example, use this command in Linux:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
export PATH=$ZEPHYR_SDK_INSTALL_DIR/sysroots/x86_64-pokysdk-linux/usr/bin/openocd:$PATH
|
||||
|
||||
Flashing
|
||||
========
|
||||
|
||||
Applications for the ``CC1352P LaunchPad`` board configuration can be built and
|
||||
flashed in the usual way (see :ref:`build_an_application` and
|
||||
:ref:`application_run` for more details).
|
||||
|
||||
Here is an example for the :ref:`hello_world` application.
|
||||
|
||||
First, run your favorite terminal program to listen for output.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ screen <tty_device> 115200
|
||||
|
||||
Replace :code:`<tty_device>` with the port where the XDS110 application
|
||||
serial device can be found. For example, :code:`/dev/ttyACM0`.
|
||||
|
||||
Then build and flash the application in the usual way.
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/hello_world
|
||||
:board: cc1352p1_launchxl
|
||||
:goals: build flash
|
||||
|
||||
Debugging
|
||||
=========
|
||||
|
||||
You can debug an application in the usual way. Here is an example for the
|
||||
:ref:`hello_world` application.
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/hello_world
|
||||
:board: cc1352p1_launchxl
|
||||
:maybe-skip-config:
|
||||
:goals: debug
|
||||
|
||||
Bootloader
|
||||
==========
|
||||
|
||||
The ROM bootloader on CC13x2 and CC26x2 devices is enabled by default. The
|
||||
bootloader will start if there is no valid application image in flash or the
|
||||
so-called backdoor is enabled (via option
|
||||
:kconfig:option:`CONFIG_CC13X2_CC26X2_BOOTLOADER_BACKDOOR_ENABLE`) and BTN-1 is held
|
||||
down during reset. See the bootloader documentation in chapter 10 of the `TI
|
||||
CC13x2 / CC26x2 Technical Reference Manual`_ for additional information.
|
||||
|
||||
Power Management and UART
|
||||
=========================
|
||||
|
||||
System and device power management are supported on this platform, and
|
||||
can be enabled via the standard Kconfig options in Zephyr, such as
|
||||
:kconfig:option:`CONFIG_PM`, :kconfig:option:`CONFIG_PM_DEVICE`.
|
||||
|
||||
When system power management is turned on (CONFIG_PM=y),
|
||||
sleep state 2 (standby mode) is allowed, and polling is used to retrieve input
|
||||
by calling uart_poll_in(), it is possible for characters to be missed if the
|
||||
system enters standby mode between calls to uart_poll_in(). This is because
|
||||
the UART is inactive while the system is in standby mode. The workaround is to
|
||||
disable sleep state 2 while polling:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
<code that calls uart_poll_in() and expects input at any point in time>
|
||||
pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES);
|
||||
|
||||
|
||||
References
|
||||
**********
|
||||
|
||||
CC1352P1 LaunchPad Quick Start Guide:
|
||||
http://www.ti.com/lit/pdf/swru525
|
||||
|
||||
.. _TI CC1352P LaunchPad Product Page:
|
||||
https://www.ti.com/tool/LAUNCHXL-CC1352P
|
||||
|
||||
.. _TI CC1352P Product Page:
|
||||
https://www.ti.com/product/CC1352P
|
||||
|
||||
.. _TI CC13x2 / CC26x2 Technical Reference Manual:
|
||||
http://www.ti.com/lit/pdf/swcu185
|
||||
|
||||
.. _XDS-110 emulation package:
|
||||
http://processors.wiki.ti.com/index.php/XDS_Emulation_Software_Package#XDS_Emulation_Software_.28emupack.29_Download
|
|
@ -0,0 +1,14 @@
|
|||
# Copyright (c) 2022 Stancu Florin
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Skyworks SKY13317 pHEMT GaAs SP3T Antenna Switch
|
||||
|
||||
compatible: "skyworks,sky13317"
|
||||
|
||||
include: [pinctrl-device.yaml, base.yaml]
|
||||
|
||||
properties:
|
||||
gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: Antenna mux control pins
|
1
boards/arm/cc1352p1_launchxl/support/openocd.cfg
Normal file
1
boards/arm/cc1352p1_launchxl/support/openocd.cfg
Normal file
|
@ -0,0 +1 @@
|
|||
source [find board/ti_cc13x2_launchpad.cfg]
|
|
@ -92,4 +92,19 @@ config IEEE802154_CC13XX_CC26XX_SUB_GHZ_RADIO_TX_RETRIES
|
|||
Number of transmission attempts radio driver should do, before
|
||||
replying it could not send the packet.
|
||||
|
||||
config IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_RADIO_SETUP
|
||||
bool "Use custom radio setup structures (advanced)"
|
||||
default n
|
||||
help
|
||||
Imports the radio setup structure from an external module instead of using
|
||||
the default one.
|
||||
Allows overriding the RF modulation / protocol settings.
|
||||
|
||||
config IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_POWER_TABLE
|
||||
bool "Use custom power table structure (advanced)"
|
||||
default n
|
||||
help
|
||||
Imports the radio power table from an external module.
|
||||
Allows overriding the RF modulation settings.
|
||||
|
||||
endif # IEEE802154_CC13XX_CC26XX_SUB_GHZ
|
||||
|
|
|
@ -50,9 +50,17 @@ static void ieee802154_cc13xx_cc26xx_subg_setup_rx_buffers(
|
|||
#define CMD_PROP_RADIO_DIV_SETUP_PA CMD_PROP_RADIO_DIV_SETUP
|
||||
#endif
|
||||
|
||||
/* Radio values for CC13x2R (note: CC26x2 does not support sub-GHz radio) */
|
||||
#if defined(CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_RADIO_SETUP)
|
||||
/* User-defined CMD_PROP_RADIO_DIV_SETUP structures */
|
||||
#if defined(CONFIG_SOC_CC1352R)
|
||||
/* R overrides from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */
|
||||
extern volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup;
|
||||
#elif defined(CONFIG_SOC_CC1352P)
|
||||
extern volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup;
|
||||
#endif /* CONFIG_SOC_CC1352x, extern RADIO_DIV_SETUP */
|
||||
|
||||
#elif defined(CONFIG_SOC_CC1352R)
|
||||
/* Radio values for CC13x2R (note: CC26x2 does not support sub-GHz radio) */
|
||||
/* From SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */
|
||||
static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = {
|
||||
/* DC/DC regulator: In Tx, use DCDCCTL5[3:0]=0x7 (DITHER_EN=0 and IPEAK=7). */
|
||||
(uint32_t)0x00F788D3,
|
||||
|
@ -78,7 +86,7 @@ static uint32_t ieee802154_cc13xx_overrides_sub_ghz[] = {
|
|||
};
|
||||
|
||||
/* Radio setup command for CC1312R / CC1352R */
|
||||
static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_radio_div_setup = {
|
||||
static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_subg_radio_div_setup = {
|
||||
.commandNo = CMD_PROP_RADIO_DIV_SETUP,
|
||||
.condition.rule = COND_NEVER,
|
||||
.modulation.modType = 1, /* FSK */
|
||||
|
@ -99,32 +107,6 @@ static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_t ieee802154_cc13xx_radio_div_setup
|
|||
.pRegOverride = ieee802154_cc13xx_overrides_sub_ghz,
|
||||
};
|
||||
|
||||
/* Sub GHz power table */
|
||||
static const RF_TxPowerTable_Entry txPowerTable_sub_ghz[] = {
|
||||
{ -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) },
|
||||
{ -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 3) },
|
||||
{ -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 5) },
|
||||
{ -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) },
|
||||
{ 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 8) },
|
||||
{ 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 9) },
|
||||
{ 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) },
|
||||
{ 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 10) },
|
||||
{ 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 11) },
|
||||
{ 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) },
|
||||
{ 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 3, 0, 16) },
|
||||
{ 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 0, 19) },
|
||||
{ 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 22) },
|
||||
{ 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 3, 0, 31) },
|
||||
{ 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 2, 0, 31) },
|
||||
{ 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 2, 0, 51) },
|
||||
{ 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 0, 0, 82) },
|
||||
{ 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 0, 89) },
|
||||
#ifdef CC13X2_CC26X2_BOOST_MODE
|
||||
{ 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) },
|
||||
#endif
|
||||
RF_TxPowerTable_TERMINATION_ENTRY
|
||||
};
|
||||
|
||||
/* Radio values for CC13X2P */
|
||||
#elif defined(CONFIG_SOC_CC1352P)
|
||||
/* CC1352P overrides from SmartRF Studio (200kbps, 50kHz deviation, 2-GFSK, 311.8kHz Rx BW) */
|
||||
|
@ -175,8 +157,8 @@ static uint32_t rf_prop_overrides_tx_20[] = {
|
|||
(uint32_t)0xFFFFFFFF
|
||||
};
|
||||
|
||||
/* Radio setup command for CC1312R / CC1352R */
|
||||
static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_radio_div_setup = {
|
||||
/* Radio setup command for CC1312P / CC1352P */
|
||||
static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_subg_radio_div_setup = {
|
||||
.commandNo = CMD_PROP_RADIO_DIV_SETUP_PA,
|
||||
.condition.rule = COND_NEVER,
|
||||
.modulation.modType = 1, /* FSK */
|
||||
|
@ -198,9 +180,40 @@ static volatile rfc_CMD_PROP_RADIO_DIV_SETUP_PA_t ieee802154_cc13xx_radio_div_se
|
|||
.pRegOverrideTxStd = rf_prop_overrides_tx_std,
|
||||
.pRegOverrideTx20 = rf_prop_overrides_tx_20,
|
||||
};
|
||||
#endif /* CONFIG_SOC_CC1352x, default CMD_PROP_RADIO_DIV_SETUP structures */
|
||||
|
||||
/* Sub GHz power tables */
|
||||
#if defined(CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ_CUSTOM_POWER_TABLE)
|
||||
extern RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[];
|
||||
|
||||
#elif defined(CONFIG_SOC_CC1352R)
|
||||
static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = {
|
||||
{ -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) },
|
||||
{ -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 3) },
|
||||
{ -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 5) },
|
||||
{ -5, RF_TxPowerTable_DEFAULT_PA_ENTRY(4, 3, 0, 5) },
|
||||
{ 0, RF_TxPowerTable_DEFAULT_PA_ENTRY(8, 3, 0, 8) },
|
||||
{ 1, RF_TxPowerTable_DEFAULT_PA_ENTRY(9, 3, 0, 9) },
|
||||
{ 2, RF_TxPowerTable_DEFAULT_PA_ENTRY(10, 3, 0, 9) },
|
||||
{ 3, RF_TxPowerTable_DEFAULT_PA_ENTRY(11, 3, 0, 10) },
|
||||
{ 4, RF_TxPowerTable_DEFAULT_PA_ENTRY(13, 3, 0, 11) },
|
||||
{ 5, RF_TxPowerTable_DEFAULT_PA_ENTRY(14, 3, 0, 14) },
|
||||
{ 6, RF_TxPowerTable_DEFAULT_PA_ENTRY(17, 3, 0, 16) },
|
||||
{ 7, RF_TxPowerTable_DEFAULT_PA_ENTRY(20, 3, 0, 19) },
|
||||
{ 8, RF_TxPowerTable_DEFAULT_PA_ENTRY(24, 3, 0, 22) },
|
||||
{ 9, RF_TxPowerTable_DEFAULT_PA_ENTRY(28, 3, 0, 31) },
|
||||
{ 10, RF_TxPowerTable_DEFAULT_PA_ENTRY(18, 2, 0, 31) },
|
||||
{ 11, RF_TxPowerTable_DEFAULT_PA_ENTRY(26, 2, 0, 51) },
|
||||
{ 12, RF_TxPowerTable_DEFAULT_PA_ENTRY(16, 0, 0, 82) },
|
||||
{ 13, RF_TxPowerTable_DEFAULT_PA_ENTRY(36, 0, 0, 89) },
|
||||
#ifdef CC13X2_CC26X2_BOOST_MODE
|
||||
{ 14, RF_TxPowerTable_DEFAULT_PA_ENTRY(63, 0, 1, 0) },
|
||||
#endif
|
||||
RF_TxPowerTable_TERMINATION_ENTRY
|
||||
};
|
||||
#elif defined(CONFIG_SOC_CC1352P)
|
||||
/* Sub GHz power table */
|
||||
static const RF_TxPowerTable_Entry txPowerTable_sub_ghz[] = {
|
||||
static const RF_TxPowerTable_Entry ieee802154_cc13xx_subg_power_table[] = {
|
||||
{ -20, RF_TxPowerTable_DEFAULT_PA_ENTRY(0, 3, 0, 2) },
|
||||
{ -15, RF_TxPowerTable_DEFAULT_PA_ENTRY(1, 3, 0, 3) },
|
||||
{ -10, RF_TxPowerTable_DEFAULT_PA_ENTRY(2, 3, 0, 5) },
|
||||
|
@ -230,8 +243,7 @@ static const RF_TxPowerTable_Entry txPowerTable_sub_ghz[] = {
|
|||
{ 20, RF_TxPowerTable_HIGH_PA_ENTRY(18, 3, 0, 71, 27) },
|
||||
RF_TxPowerTable_TERMINATION_ENTRY
|
||||
};
|
||||
|
||||
#endif /* CONFIG_SOC_CC1352* */
|
||||
#endif /* CONFIG_SOC_CC1352x power table */
|
||||
|
||||
/** RF patches to use (note: RF core keeps a pointer to this, so no stack). */
|
||||
static RF_Mode rf_mode = {
|
||||
|
@ -442,7 +454,7 @@ static int ieee802154_cc13xx_cc26xx_subg_set_txpower(
|
|||
RF_Stat status;
|
||||
|
||||
RF_TxPowerTable_Value power_table_value = RF_TxPowerTable_findValue(
|
||||
(RF_TxPowerTable_Entry *)txPowerTable_sub_ghz, dbm);
|
||||
(RF_TxPowerTable_Entry *)ieee802154_cc13xx_subg_power_table, dbm);
|
||||
|
||||
if (power_table_value.rawValue == RF_TxPowerTable_INVALID_VALUE) {
|
||||
LOG_DBG("RF_TxPowerTable_findValue() failed");
|
||||
|
@ -780,7 +792,7 @@ static int ieee802154_cc13xx_cc26xx_subg_init(const struct device *dev)
|
|||
rf_params.pClientEventCb = client_event_callback;
|
||||
|
||||
drv_data->rf_handle = RF_open(&drv_data->rf_object,
|
||||
&rf_mode, (RF_RadioSetup *)&ieee802154_cc13xx_radio_div_setup,
|
||||
&rf_mode, (RF_RadioSetup *)&ieee802154_cc13xx_subg_radio_div_setup,
|
||||
&rf_params);
|
||||
if (drv_data->rf_handle == NULL) {
|
||||
LOG_ERR("RF_open() failed");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue