Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions BoardSupport.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,24 @@ static inline void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callb
#define PIN_TO_SERVO(p) (p)
```

## Arduino UNO Q

The Arduino UNO Q is a Zephyr RTOS-based board built on the STMicroelectronics STM32U585AI (Cortex-M33). It uses the [arduino/ArduinoCore-zephyr](https://github.com/arduino/ArduinoCore-zephyr) core (FQBN `arduino:zephyr:unoq`), which is installed through the Arduino IDE Boards Manager after adding the package index `https://downloads.arduino.cc/packages/package_zephyr_index.json`.

Unlike the classic Uno, sketches on the UNO Q are compiled to a freestanding ELF that is loaded dynamically by a precompiled Zephyr firmware. Any pin that does not appear in the variant's `pwm-pin-gpios`, `adc-pin-gpios`, `i2cs`, or `spis` devicetree properties will not be driven by the corresponding peripheral, so Firmata only exposes the Arduino R3 header pins plus the onboard RGB LED.

| Property | Value |
| ----------- | ------------------------------------ |
| Number of Pins | 22 user-addressable (14 digital D0-D13 + 6 analog A0-A5 as D14-D19 + 2 dedicated I2C D20/D21), plus the onboard RGB LED at `LED_BUILTIN` (pin 51) |
| Number of analog inputs | 6 (14-bit ADC) |
| Flash Memory | 2 MB |
| RAM | 786 KB |
| PWM capable pins | D2, D3, D5-D13, D20, D21, `LED_BUILTIN` (D0/D1 are reserved for USART1 and not PWM-enabled in the default variant) |
| Built-in LED | Yes, the `led3_green` RGB channel exposed as `LED_BUILTIN`; no LED is wired to D13 |
| I2C, Bus 0 | D20 SDA (PB11), D21 SCL (PB10) on I2C2 |
| SPI, Bus 0 | D10 SS (PB9), D11 MOSI (PB15), D12 MISO (PB14), D13 SCK (PB13) on SPI2 |
| Serial1 | D0 RX (PB7), D1 TX (PB6) on USART1 |

### I2C

The Raspberry Pi Pico [datasheet](https://datasheets.raspberrypi.org/pico/Pico-R3-A4-Pinout.pdf) states that the
Expand Down
14 changes: 10 additions & 4 deletions examples/ConfigurableFirmata/ConfigurableFirmata.ino
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ const int NETWORK_PORT = 27016;

// #define ENABLE_ONE_WIRE

// Note that the SERVO module currently is not supported on ESP32. So either disable this or patch the library
#ifndef ESP32
#define ENABLE_SERVO
// Note that the SERVO module currently is not supported on ESP32 or on the Zephyr-based Arduino cores
// (e.g. Arduino UNO Q), which do not ship a Servo library. So either disable this or patch the library.
#if !defined(ESP32) && !defined(ARDUINO_ARCH_ZEPHYR)
#define ENABLE_SERVO
#endif

// #define ENABLE_ACCELSTEPPER
Expand Down Expand Up @@ -166,7 +167,12 @@ void initTransport()
}
Firmata.begin(serverStream);
Firmata.blinkVersion(); // Because the above doesn't do it.
#else
#elif defined(ARDUINO_UNO_Q)
// On the Arduino UNO Q, the STM32's Serial1 is bridged to /dev/ttyHS1 on the
// Linux side. The default `Serial` is USB-CDC and is not reachable from Linux.
Serial1.begin(115200);
Firmata.begin(Serial1);
#else
Firmata.begin(115200);
#endif
}
Expand Down
34 changes: 34 additions & 0 deletions src/ConfigurableFirmata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,40 @@ extern "C" {
#include <stdlib.h>
}

#if defined(ARDUINO_ARCH_ZEPHYR)
// The Zephyr Arduino core builds sketches as LLEXTs against picolibc. libc's vsnprintf
// is not reliably resolvable by the LLEXT loader, but Zephyr's cbvprintf is exported
// (see ArduinoCore-zephyr loader/llext_exports.c). Wrap it to provide a drop-in
// vsnprintf with matching semantics.
#include <zephyr/sys/cbprintf.h>

static int firmata_zephyr_vsnprintf_cb(int c, void *ctx_raw)
{
struct { char *buf; size_t size; size_t pos; } *ctx =
(decltype(ctx))ctx_raw;
if (ctx->pos + 1 < ctx->size) {
ctx->buf[ctx->pos] = (char)c;
}
ctx->pos++;
return c;
}

static int firmata_zephyr_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
{
struct { char *buf; size_t size; size_t pos; } ctx = { str, size, 0 };
// Older Zephyr headers shipped with the Arduino core declare cbprintf_cb as a
// K&R-style (untyped) function pointer, so cast explicitly to satisfy C++.
int written = cbvprintf((cbprintf_cb)firmata_zephyr_vsnprintf_cb, &ctx, fmt, ap);
if (size > 0) {
size_t term = ctx.pos < size ? ctx.pos : size - 1;
str[term] = '\0';
}
return written;
}

#define vsnprintf firmata_zephyr_vsnprintf
#endif

//******************************************************************************
//* Support Functions
//******************************************************************************
Expand Down
31 changes: 31 additions & 0 deletions src/utility/Boards.h
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,37 @@ static inline void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callb
#define PIN_TO_PWM(p) (p)
#define PIN_TO_SERVO(p) (p)

// Arduino UNO Q (Zephyr-based, STM32U585AI, Arduino R3 pinout)
// FQBN: arduino:zephyr:unoq (arduino/ArduinoCore-zephyr)
#elif defined(ARDUINO_UNO_Q)
#define TOTAL_ANALOG_PINS 6
// LED_BUILTIN (led3_green on PH11) is index 51 in the variant's digital-pin-gpios list,
// so TOTAL_PINS is sized to cover it even though only a subset are user-addressable.
#define TOTAL_PINS 52
#define TOTAL_DEFAULT_PINS 22 // 14 digital (D0-D13) + 6 analog (A0-A5 as D14-D19) + 2 I2C (D20 SDA, D21 SCL)
#define VERSION_BLINK_PIN LED_BUILTIN
#define PIN_SERIAL1_RX 0
#define PIN_SERIAL1_TX 1
#define IS_PIN_DIGITAL(p) (((p) >= 2 && (p) < TOTAL_DEFAULT_PINS) || (p) == LED_BUILTIN)
#define FIRMATA_IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
// PWM-capable pins per the variant overlay's pwm-pin-gpios; D0/D1 are disabled due to the USART1 conflict.
#define FIRMATA_IS_PIN_PWM(p) ((p) == 2 || (p) == 3 || ((p) >= 5 && (p) <= 13) || (p) == 20 || (p) == 21 || (p) == LED_BUILTIN)
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // SDA = D20 (PB11), SCL = D21 (PB10) on I2C2
// The Zephyr Arduino core does not expose the standard PIN_SPI_* / SS / MOSI / MISO / SCK symbols,
// so provide them here pointing at SPI2 (the bus exposed on the R3 header).
#define PIN_SPI_SS 10
#define PIN_SPI_MOSI 11
#define PIN_SPI_MISO 12
#define PIN_SPI_SCK 13
#define IS_PIN_SPI(p) ((p) == PIN_SPI_SS || (p) == PIN_SPI_MOSI || (p) == PIN_SPI_MISO || (p) == PIN_SPI_SCK)
#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1) // USART1 on D0 (RX) / D1 (TX)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) ((p) - 14)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) ((p) - 2)
#define DEFAULT_ADC_RESOLUTION 14 // STM32U5 ADC runs at 14 bits per the variant devicetree

// Arduino UNO R4 Minima and Wifi
// The pinout is the same as for the classical UNO R3
#elif defined(ARDUINO_UNOR4_MINIMA) || defined(ARDUINO_UNOR4_WIFI)
Expand Down