Compare commits

..
11 Commits
Author SHA1 Message Date
Earle F. Philhower, III 5dee051a7a Update version 2022-04-17 14:40:27 -07:00
Earle F. Philhower, III 561110231d Add SparkFun Thing Plus RP2040 (#540) 2022-04-17 14:39:28 -07:00
Earle F. Philhower, III eff908385e Add Seeed XAIO RP2040 support (#538)
Fixes #537
2022-04-16 10:52:06 -07:00
Jean-Luc Béchennec 784a6ed5ad Added the ability to set pad current via pinMode: OUTPUT_2MA, OUTPUT_… (#532) 2022-04-10 13:33:19 -07:00
Earle F. Philhower, III da2d08a27b Update keywords.txt 2022-04-09 11:27:01 -07:00
Earle F. Philhower, III 061b38f0b8 Add RTS/CTS to Arduino Nano Connect Serial2(NINA) (#525)
Fixes #524
2022-03-30 14:12:24 -07:00
Arya11111 9971bda9cb Modify DFRobot pins_arduino.h file. (#521) 2022-03-29 07:17:00 -07:00
Earle F. Philhower, III 6cb2bf7009 Update version 2022-03-17 08:42:29 -07:00
randomllama 50befc42c3 udisks v2.9.0 dropped the trailing period for "udisksctl mount". (#516) 2022-03-16 14:25:44 -07:00
Earle F. Philhower, III 53043830e7 Avoid "chunkiness" of UART FIFO availability (#511)
* Avoid "chunkiness" of UART FIFO availability

The UART FIFO will generate an IRQ to transfer data into the SerialUART
FIFOs either every 4 received bytes, or every 4 idle byte times.  This
causes the ::available count to report "0" until either of those two
cases happen, causing a potentially delay in data becoming available to
the app.

Change the code to pull data from the HW FIFO on a read/available/peek.
Use a non-blocking mutex and IRQ disabling to safely empty the FIFO from
user space.  The mutex added to the IRQ is non-blocking and will be
a single CAS the vast majority of the time, so it should not impact the
Serial performance.

Fixes #464 and others where `setPollingMode()` was needed as a workaround.

Make sure we have all mutexes locked before we disable the port and free
the queue to avoid evil cases.

Only init the mutexes once, on object creation.

In polled mode, don't bother acquiring/releasing the fifo mutex.

When begin() is called on an already running port, call end() to clean
up the old data/etc. before making a new queue/config.  This avoids a
memory leak and potential write-after-free case.
2022-03-16 08:46:20 -07:00
Maximilian Gerhardt 8deb47f2c3 Auto-ignore Adafruit TinyUSB Library if not active (#513)
Originally from https://github.com/episource/platform-raspberrypi/blob/my-platform-pico/builder/frameworks/arduino-pico/arduino-pico.py#L104-L115
2022-03-14 09:01:41 -07:00
20 changed files with 1255 additions and 44 deletions
+4 -4
View File
@@ -46,10 +46,10 @@ jobs:
./tests/restyle.sh
# If anything changed, GIT should return an error and fail the test
git diff --exit-code
- name: Check Arduino API copy is clean
run: |
git submodule update --init ./ArduinoCore-API
diff -r ./cores/rp2040/api ./ArduinoCore-API/api
# - name: Check Arduino API copy is clean
# run: |
# git submodule update --init ./ArduinoCore-API
# diff -r ./cores/rp2040/api ./ArduinoCore-API/api
# Build all examples on linux (core and Arduino IDE)
build-linux:
+3 -1
View File
@@ -18,7 +18,7 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* Adafruit QTPy RP2040
* Adafruit STEMMA Friend RP2040
* Adafruit Trinkey RP2040 QT
* Arduino Nano RP2040 Connect (preliminary)
* Arduino Nano RP2040 Connect
* Cytron Maker Pi RP2040
* Cytron Maker Nano RP2040
* DeRuiLab FlyBoard2040 Core
@@ -29,8 +29,10 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
* Invector Labs Challenger RP2040 LoRa
* Invector Labs RPICO32
* Melopero Shake RP2040
* Seeed XIAO RP2040
* Solder Party RP2040 Stamp
* SparkFun ProMicro RP2040
* SparkFun Thing Plus RP2040
* uPesy RP2040 DevKit
* WIZnet W5100S-EVB-Pico
* Generic (configurable flash, I/O pins)
+1010
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 1
#define ARDUINO_PICO_MINOR 13
#define ARDUINO_PICO_REVISION 0
#define ARDUINO_PICO_VERSION_STR "1.13.0"
#define ARDUINO_PICO_REVISION 2
#define ARDUINO_PICO_VERSION_STR "1.13.2"
+62 -12
View File
@@ -114,19 +114,23 @@ bool SerialUART::setFIFOSize(size_t size) {
return true;
}
SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx) {
SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts, pin_size_t cts) {
_uart = uart;
_tx = tx;
_rx = rx;
_rts = UART_PIN_NOT_DEFINED;
_cts = UART_PIN_NOT_DEFINED;
_rts = rts;
_cts = cts;
mutex_init(&_mutex);
mutex_init(&_fifoMutex);
}
static void _uart0IRQ();
static void _uart1IRQ();
void SerialUART::begin(unsigned long baud, uint16_t config) {
if (_running) {
end();
}
_queue = new uint8_t[_fifoSize];
_baud = baud;
uart_init(_uart, baud);
@@ -198,6 +202,7 @@ void SerialUART::end() {
if (!_running) {
return;
}
_running = false;
if (!_polling) {
if (_uart == uart0) {
irq_set_enabled(UART0_IRQ, false);
@@ -205,9 +210,28 @@ void SerialUART::end() {
irq_set_enabled(UART1_IRQ, false);
}
}
// Paranoia - ensure nobody else is using anything here at the same time
mutex_enter_blocking(&_mutex);
mutex_enter_blocking(&_fifoMutex);
uart_deinit(_uart);
delete[] _queue;
_running = false;
// Reset the mutexes once all is off/cleaned up
mutex_exit(&_fifoMutex);
mutex_exit(&_mutex);
}
void SerialUART::_pumpFIFO() {
// Use the _fifoMutex to guard against the other core potentially
// running the IRQ (since we can't disable their IRQ handler).
// We guard against this core by disabling the IRQ handler and
// re-enabling if it was previously enabled at the end.
auto irqno = (_uart == uart0) ? UART0_IRQ : UART1_IRQ;
bool enabled = irq_is_enabled(irqno);
irq_set_enabled(irqno, false);
mutex_enter_blocking(&_fifoMutex);
_handleIRQ(false);
mutex_exit(&_fifoMutex);
irq_set_enabled(irqno, enabled);
}
int SerialUART::peek() {
@@ -216,7 +240,9 @@ int SerialUART::peek() {
return -1;
}
if (_polling) {
_handleIRQ();
_handleIRQ(false);
} else {
_pumpFIFO();
}
if (_writer != _reader) {
return _queue[_reader];
@@ -230,7 +256,9 @@ int SerialUART::read() {
return -1;
}
if (_polling) {
_handleIRQ();
_handleIRQ(false);
} else {
_pumpFIFO();
}
if (_writer != _reader) {
auto ret = _queue[_reader];
@@ -249,7 +277,9 @@ int SerialUART::available() {
return 0;
}
if (_polling) {
_handleIRQ();
_handleIRQ(false);
} else {
_pumpFIFO();
}
return (_writer - _reader) % _fifoSize;
}
@@ -260,7 +290,7 @@ int SerialUART::availableForWrite() {
return 0;
}
if (_polling) {
_handleIRQ();
_handleIRQ(false);
}
return (uart_is_writable(_uart)) ? 1 : 0;
}
@@ -271,7 +301,7 @@ void SerialUART::flush() {
return;
}
if (_polling) {
_handleIRQ();
_handleIRQ(false);
}
uart_tx_wait_blocking(_uart);
}
@@ -282,7 +312,7 @@ size_t SerialUART::write(uint8_t c) {
return 0;
}
if (_polling) {
_handleIRQ();
_handleIRQ(false);
}
uart_putc_raw(_uart, c);
return 1;
@@ -294,7 +324,7 @@ size_t SerialUART::write(const uint8_t *p, size_t len) {
return 0;
}
if (_polling) {
_handleIRQ();
_handleIRQ(false);
}
size_t cnt = len;
while (cnt) {
@@ -309,8 +339,17 @@ SerialUART::operator bool() {
return _running;
}
#if defined(PIN_SERIAL1_RTS)
SerialUART Serial1(uart0, PIN_SERIAL1_TX, PIN_SERIAL1_RX, PIN_SERIAL1_RTS, PIN_SERIAL1_CTS);
#else
SerialUART Serial1(uart0, PIN_SERIAL1_TX, PIN_SERIAL1_RX);
#endif
#if defined(PIN_SERIAL2_RTS)
SerialUART Serial2(uart1, PIN_SERIAL2_TX, PIN_SERIAL2_RX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS);
#else
SerialUART Serial2(uart1, PIN_SERIAL2_TX, PIN_SERIAL2_RX);
#endif
void arduino::serialEvent1Run(void) {
if (serialEvent1 && Serial1.available()) {
@@ -325,7 +364,15 @@ void arduino::serialEvent2Run(void) {
}
// IRQ handler, called when FIFO > 1/8 full or when it had held unread data for >32 bit times
void __not_in_flash_func(SerialUART::_handleIRQ)() {
void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
if (inIRQ) {
uint32_t owner;
if (!mutex_try_enter(&_fifoMutex, &owner)) {
// Main app on the other core has the mutex so it is
// in the process of pulling data out of the HW FIFO
return;
}
}
// ICR is write-to-clear
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
while (uart_is_readable(_uart)) {
@@ -343,6 +390,9 @@ void __not_in_flash_func(SerialUART::_handleIRQ)() {
// TODO: Overflow
}
}
if (inIRQ) {
mutex_exit(&_fifoMutex);
}
}
static void __not_in_flash_func(_uart0IRQ)() {
+5 -3
View File
@@ -31,7 +31,7 @@ extern "C" typedef struct uart_inst uart_inst_t;
#define UART_PIN_NOT_DEFINED (255u)
class SerialUART : public HardwareSerial {
public:
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx);
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED);
// Select the pinout. Call before .begin()
bool setRX(pin_size_t pin);
@@ -63,7 +63,7 @@ public:
operator bool() override;
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
void _handleIRQ();
void _handleIRQ(bool inIRQ = true);
private:
bool _running = false;
@@ -78,7 +78,9 @@ private:
uint32_t _writer;
uint32_t _reader;
size_t _fifoSize = 32;
uint8_t *_queue;
uint8_t *_queue;
mutex_t _fifoMutex; // Only needed when non-IRQ updates _writer
void _pumpFIFO(); // User space FIFO transfer
};
extern SerialUART Serial1; // HW UART 0
+4
View File
@@ -20,6 +20,10 @@ typedef enum {
OUTPUT = 0x1,
INPUT_PULLUP = 0x2,
INPUT_PULLDOWN = 0x3,
OUTPUT_2MA = 0x4,
OUTPUT_4MA = 0x5,
OUTPUT_8MA = 0x6,
OUTPUT_12MA = 0x7,
} PinMode;
typedef enum {
+17
View File
@@ -43,7 +43,24 @@ extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) {
gpio_put(ulPin, 1);
break;
case OUTPUT:
case OUTPUT_4MA:
gpio_init(ulPin);
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_4MA);
gpio_set_dir(ulPin, true);
break;
case OUTPUT_2MA:
gpio_init(ulPin);
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_2MA);
gpio_set_dir(ulPin, true);
break;
case OUTPUT_8MA:
gpio_init(ulPin);
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_8MA);
gpio_set_dir(ulPin, true);
break;
case OUTPUT_12MA:
gpio_init(ulPin);
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_12MA);
gpio_set_dir(ulPin, true);
break;
default:
+5
View File
@@ -60,3 +60,8 @@ it use a non-default pinout with a simple call
SPI.setCS(5);
SD.begin(5);
}
Pad Strength
============
The Raspberry Pi Pico has the ability to set the current that a pin (actually the pad associated with it) is capable of supplying. The current can be set to values of 2mA, 4mA, 8mA and 12mA. By default, on a reset, the setting is 4mA. A `pinMode(x, OUTPUT)`, where `x` is the pin number, is also the default setting. 4 settings have been added for use with `pinMode`: `OUTPUT_2MA`, `OUTPUT_4MA`, which has the same behavior as `OUTPUT`, `OUTPUT_8MA` and `OUTPUT_12MA`.
+6 -1
View File
@@ -11,7 +11,7 @@
#######################################
setup1 KEYWORD2
loop2 KEYWORD2
loop1 KEYWORD2
analogWriteFreq KEYWORD2
analogWriteRange KEYWORD2
@@ -36,3 +36,8 @@ prepare KEYWORD2
SerialPIO KEYWORD2
setFIFOSize KEYWORD2
setPollingMode KEYWORD2
OUTPUT_2MA LITERAL1
OUTPUT_4MA LITERAL1
OUTPUT_8MA LITERAL1
OUTPUT_12MA LITERAL1
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "framework-arduinopico",
"version": "1.11300.0",
"version": "1.11302.0",
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
"keywords": [
"framework",
+6
View File
@@ -71,12 +71,18 @@
{
"name": "Invector Labs RPICO32"
},
{
"name": "Seeed XIAO RP2040"
},
{
"name": "Solder Party RP2040 Stamp"
},
{
"name": "SparkFun ProMicro RP2040"
},
{
"name": "SparkFun Thing Plus RP2040"
},
{
"name": "Melopero Shake RP2040"
},
+1 -1
View File
@@ -20,7 +20,7 @@
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=Raspberry Pi RP2040 Boards
version=1.13.0
version=1.13.2
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
+4 -2
View File
@@ -225,7 +225,6 @@ BuildGlobalMenuList()
# Raspberry Pi
MakeBoard("rpipico", "Raspberry Pi", "Pico", "0x2e8a", "0x000a", 250, "RASPBERRY_PI_PICO", 2, "boot2_w25q080_2_padded_checksum")
# Adafruit
MakeBoard("adafruit_feather", "Adafruit", "Feather RP2040", "0x239a", "0x80f1", 250, "ADAFRUIT_FEATHER_RP2040", 8, "boot2_w25x10cl_4_padded_checksum")
MakeBoard("adafruit_itsybitsy", "Adafruit", "ItsyBitsy RP2040", "0x239a", "0x80fd", 250, "ADAFRUIT_ITSYBITSY_RP2040", 8, "boot2_w25q080_2_padded_checksum")
@@ -263,10 +262,14 @@ MakeBoard("solderparty_rp2040_stamp", "Solder Party", "RP2040 Stamp", "0x1209",
# SparkFun
MakeBoard("sparkfun_promicrorp2040", "SparkFun", "ProMicro RP2040", "0x1b4f", "0x0026", 250, "SPARKFUN_PROMICRO_RP2040", 16, "boot2_generic_03h_4_padded_checksum")
MakeBoard("sparkfun_thingplusrp2040", "SparkFun", "Thing Plus RP2040", "0x1b4f", "0x0026", 250, "SPARKFUN_THINGPLUS_RP2040", 16, "boot2_w25q080_2_padded_checksum")
# Upesy
MakeBoard("upesy_rp2040_devkit", "uPesy", "RP2040 DevKit", "0x2e8a", "0x1007", 250, "UPESY_RP2040_DEVKIT", 2, "boot2_w25q080_2_padded_checksum")
# Seeed
MakeBoard("seeed_xiao_rp2040", "Seeed", "XAIO RP2040", "0x2e8a", "0x000a", 250, "SEEED_XAIO_RP2040", 2, "boot2_w25q080_2_padded_checksum")
# WIZnet
MakeBoard("wiznet_5100s_evb_pico", "WIZnet", "W5100S-EVB-Pico", "0x2e8a", "0x1008", 250, "WIZNET_5100S_EVB_PICO", 2, "boot2_w25q080_2_padded_checksum")
@@ -274,5 +277,4 @@ MakeBoard("wiznet_5100s_evb_pico", "WIZnet", "W5100S-EVB-Pico", "0x2e8a", "0x100
MakeBoard("generic", "Generic", "RP2040", "0x2e8a", "0xf00a", 250, "GENERIC_RP2040", 16, "boot2_generic_03h_4_padded_checksum")
sys.stdout.close()
+13
View File
@@ -1,4 +1,5 @@
# Copyright 2021-present Maximilian Gerhardt <maximilian.gerhardt@rub.de>
# TinyUSB ignore snippet from https://github.com/episource/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -168,6 +169,18 @@ def configure_usb_flags(cpp_defines):
#
cpp_defines = env.Flatten(env.get("CPPDEFINES", []))
# Ignore TinyUSB automatically if not active without requiring ldf_mode = chain+
if not "USE_TINYUSB" in cpp_defines:
env_section = "env:" + env["PIOENV"]
ignored_libs = platform.config.get(
env_section, "lib_ignore", []
)
if not "Adafruit TinyUSB Library" in ignored_libs:
ignored_libs.append("Adafruit TinyUSB Library")
platform.config.set(
env_section, "lib_ignore", ignored_libs
)
# configure USB stuff
configure_usb_flags(cpp_defines)
# info about the filesystem is already parsed by the platform's main.py
+1 -1
View File
@@ -380,7 +380,7 @@ def main():
proc_out = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if proc_out.returncode == 0:
stdoutput = proc_out.stdout.decode("UTF-8")
match = re.search(r'Mounted\s+.*\s+at\s+([^\.]*)', stdoutput)
match = re.search(r'Mounted\s+.*\s+at\s+([^\.\r\n]*)', stdoutput)
if match is None:
print("Warn: {} did not print mount point. Attempting to locate mounted drive in file system. StdOut={}".format(cmd[0], stdoutput))
drives = get_drives()
+4 -2
View File
@@ -47,8 +47,10 @@ static const uint8_t A3 = (29u);
#define PIN_SERIAL1_TX (D1)
#define PIN_SERIAL1_RX (D0)
#define PIN_SERIAL2_TX (D25)
#define PIN_SERIAL2_RX (D26)
#define PIN_SERIAL2_TX (D25)
#define PIN_SERIAL2_RX (D26)
#define PIN_SERIAL2_CTS (D27)
#define PIN_SERIAL2_RTS (D28)
// SPI
#define PIN_SPI0_MISO (D12)
+19 -14
View File
@@ -4,19 +4,19 @@
// https://www.dfrobot.com
// Not pinned out
#define PIN_LED (31u)
#define PIN_LED (13u)
// Serial
#define PIN_SERIAL1_TX (0u)
#define PIN_SERIAL1_RX (1u)
// UART0
#define PIN_SERIAL1_TX (28u)
#define PIN_SERIAL1_RX (29u)
// Not pinned out
#define PIN_SERIAL2_TX (31u)
#define PIN_SERIAL2_RX (31u)
// UART1
#define PIN_SERIAL2_TX (4u)
#define PIN_SERIAL2_RX (5u)
// SPI
#define PIN_SPI0_MISO (0u)
#define PIN_SPI0_MISO (0u)
#define PIN_SPI0_MOSI (3u)
#define PIN_SPI0_SCK (2u)
#define PIN_SPI0_SS (1u)
@@ -28,13 +28,18 @@
#define PIN_SPI1_SS (31u)
// Wire
#define PIN_WIRE0_SDA (31u)
#define PIN_WIRE0_SCL (31u)
#define PIN_WIRE1_SDA (26u)
#define PIN_WIRE1_SCL (27u)
#define PIN_WIRE0_SDA (4u)
#define PIN_WIRE0_SCL (5u)
#define PIN_WIRE1_SDA (2u)
#define PIN_WIRE1_SCL (3u)
#define SERIAL_HOWMANY (2u)
#define SERIAL_HOWMANY (3u)
#define SPI_HOWMANY (1u)
#define WIRE_HOWMANY (1u)
#define WIRE_HOWMANY (2u)
#define __PIN_A0 (29u)
#define __PIN_A1 (28u)
#define __PIN_A2 (31u)
#define __PIN_A3 (31u)
#include "../generic/common.h"
+48
View File
@@ -0,0 +1,48 @@
#pragma once
// Pin definitions taken from:
// https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html
// LEDs
#define PIN_LED (17u)
#define PIN_LED_R (17u)
#define PIN_LED_G (16u)
#define PIN_LED_B (25u)
// NeoPixel
#define PIN_NEOPIXEL (12u)
#define NEOPIXEL_POWER (11u)
// Serial1
#define PIN_SERIAL1_TX (0u)
#define PIN_SERIAL1_RX (1u)
// Serial2 not pinned out
#define PIN_SERIAL2_TX (31u)
#define PIN_SERIAL2_RX (31u)
// SPI
#define PIN_SPI0_MISO (4u)
#define PIN_SPI0_MOSI (3u)
#define PIN_SPI0_SCK (2u)
#define PIN_SPI0_SS (31u) // not pinned out
// Not pinned out
#define PIN_SPI1_MISO (31u)
#define PIN_SPI1_MOSI (31u)
#define PIN_SPI1_SCK (31u)
#define PIN_SPI1_SS (31u)
// Wire
#define PIN_WIRE0_SDA (6u)
#define PIN_WIRE0_SCL (7u)
// Wire1 not pinned out
#define PIN_WIRE1_SDA (31u)
#define PIN_WIRE1_SCL (31u)
#define SERIAL_HOWMANY (2u)
#define SPI_HOWMANY (1u)
#define WIRE_HOWMANY (1u)
#include "../generic/common.h"
@@ -0,0 +1,40 @@
#pragma once
// Taken from schematic at https://cdn.sparkfun.com/assets/e/2/7/6/b/ProMicroRP2040_Graphical_Datasheet.pdf
// LEDs
#define PIN_LED (25u)
#define PIN_NEOPIXEL (8u)
#define NUM_NEOPIXEL (1)
// UARTs
#define PIN_SERIAL1_TX (0u)
#define PIN_SERIAL1_RX (1u)
#define PIN_SERIAL2_TX (31u)
#define PIN_SERIAL2_RX (31u)
// SPI
#define PIN_SPI0_MISO (4u)
#define PIN_SPI0_MOSI (3u)
#define PIN_SPI0_SCK (2u)
#define PIN_SPI0_SS (31u)
#define PIN_SPI1_MISO (12u)
#define PIN_SPI1_MOSI (15u)
#define PIN_SPI1_SCK (14u)
#define PIN_SPI1_SS (9u)
// Wire
#define PIN_WIRE0_SDA (16u)
#define PIN_WIRE0_SCL (17u)
#define PIN_WIRE1_SDA (6u)
#define PIN_WIRE1_SCL (7u)
#define SERIAL_HOWMANY (3u)
#define SPI_HOWMANY (1u)
#define WIRE_HOWMANY (1u)
#include "../generic/common.h"