Files
apress/deploy/uno-q/skills/arduino-uno-q/references/05-io-and-peripherals.md
T
Omar SobhandClaude Opus 4.8 d2135a1938 feat(uno-q): ship the arduino-uno-q expert skill on every node by default
Vendors the comprehensive UNO Q skill (SKILL.md + 7 references/*.md) and installs
it into EVERY agent's workspace on each board, so agents know this board's
specifics (dual-brain arch, Bridge/RPC, pin tables, LED matrix + the
ArduinoGraphics-not-installed gotcha) instead of guessing generic Arduino.

Why per-agent workspace: ZeroClaw's read_skill returns only SKILL.md; the agent
reads references/*.md via the workspace-sandboxed file_read tool, so references
are only reachable under ~/.zeroclaw/agents/<alias>/workspace/skills/. A
shared/skills bundle surfaces the skill but its references get sandbox-blocked.

- push-skill.sh installs a SKILL.md+references skill into every agent workspace
  (discovers aliases from the board); provision-fleet runs it per board.
- config.template risk profile now allows + auto-approves read_skill + file_read
  so agents load skills without a human approver (webhook path is non-interactive).
- Flattened the folded 'description: >-' to single-line (ZeroClaw's frontmatter
  parser is a flat scanner, not full YAML).

Verified on board 65301572 with cloud/Sonnet-5: discovered arduino-uno-q →
read_skill(SKILL.md) → file_read references/04-bridge-rpc.md → correct
board-specific answer citing the file.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-07-16 09:14:00 -07:00

144 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UNO Q — Pins, Buses & Controlling Attached Components
**All physical I/O belongs to the MCU (STM32).** You control attached components by writing an Arduino sketch that owns the pin/bus. If Linux/Python needs to be involved, expose the control as a Bridge function and call it from Python (see the Bridge reference). MCU I/O is **3.3 V logic**.
## Digital pins
47 digital pins total (22 on the UNO-style header, 25 on the JMISC connector). UNO-style header mapping:
| MCU pin | Arduino | Function |
|---|---|---|
| PB7 | D0 / RX | GPIO / UART RX |
| PB6 | D1 / TX | GPIO / UART TX |
| PB3 | D2 | GPIO |
| PB0 | D3 | GPIO / OPAMP OUT / **PWM** |
| PA12 | D4 / FDCAN1_TX | GPIO / CAN TX |
| PA11 | D5 / FDCAN1_RX | GPIO / CAN RX / **PWM** |
| PB1 | D6 | GPIO / **PWM** |
| PB2 | D7 | GPIO |
| PB4 | D8 | GPIO |
| PB8 | D9 | GPIO / **PWM** |
| PB9 | D10 / SS | GPIO / SPI SS / **PWM** |
| PB15 | D11 / MOSI | GPIO / SPI MOSI / **PWM** |
| PB14 | D12 / MISO | GPIO / SPI MISO |
| PB13 | D13 / SCK | GPIO / SPI SCK |
| PA4 | D14 / DAC0 | GPIO / ADC / DAC |
| PA5 | D15 / DAC1 | GPIO / ADC / DAC |
| PA6 | D16 | GPIO / ADC / OPAMP IN+ |
| PA7 | D17 | GPIO / ADC / OPAMP IN- |
| PC1 | D18 / SDA2 | GPIO / ADC / I2C SDA |
| PC0 | D19 / SCL2 | GPIO / ADC / I2C SCL |
| PB11 | D20 / SDA | GPIO / I2C SDA |
| PB10 | D21 / SCL | GPIO / I2C SCL |
Usage:
```cpp
pinMode(pin, INPUT | OUTPUT | INPUT_PULLUP);
state = digitalRead(pin);
digitalWrite(pin, HIGH | LOW);
```
Button-reads-input, LED-follows example: `pinMode(btn, INPUT_PULLUP); if (digitalRead(btn)==LOW) digitalWrite(led,HIGH);`
## Analog input (ADC) — JANALOG connector
6 channels, **14-bit** ADC.
| MCU pin | Arduino | Function |
|---|---|---|
| PA4 | A0 | ADC / DAC |
| PA5 | A1 | ADC / DAC |
| PA6 | A2 | ADC / OPAMP IN+ |
| PA7 | A3 | ADC / OPAMP IN- |
| PC1 | A4 | ADC / I2C SDA |
| PC0 | A5 | ADC / I2C SCL |
```cpp
analogReadResolution(14); // 016383
analogReference(AR_INTERNAL2V5); // set V_REF+ (see table)
int v = analogRead(A0);
```
Voltage-reference options: `AR_INTERNAL1V5` (1.5 V), `AR_INTERNAL1V8` (1.8 V), `AR_INTERNAL2V05` (2.048 V), `AR_INTERNAL2V5` (2.5 V), `AR_EXTERNAL` (2 V…VDD, external).
## Analog output (DAC)
Two true DAC outputs.
| MCU pin | Arduino |
|---|---|
| PA4 | DAC0 |
| PA5 | DAC1 |
```cpp
analogWriteResolution(12); // 04095
analogWrite(DAC0, value);
```
(Good for generating waveforms — the docs include a 60 Hz sine via a 256-point LUT clocked with `micros()`.)
## PWM
6 PWM-capable pins: **D3, D5, D6, D9, D10, D11**. Default resolution **8-bit (0255)**; change with `analogWriteResolution(bits)`. **PWM frequency is fixed at 500 Hz.**
```cpp
analogWriteResolution(10); // 01023
analogWrite(D3, dutyValue);
```
## SPI
| MCU pin | Arduino |
|---|---|
| PB9 | SS / D10 |
| PB15 | MOSI / D11 |
| PB14 | MISO / D12 |
| PB13 | SCK / D13 |
```cpp
#include <SPI.h>
#define SS D10
void setup(){ pinMode(SS,OUTPUT); digitalWrite(SS,HIGH); SPI.begin(); }
void loop(){
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(SS, LOW);
SPI.transfer(0x35); SPI.transfer(0xFA);
digitalWrite(SS, HIGH);
SPI.endTransaction();
}
```
## I2C — two buses
| Bus / object | SCL | SDA | Where |
|---|---|---|---|
| `Wire` | D21 (PB10) | D20 (PB11) | UNO-style headers |
| `Wire1` | I2C4_SCL (PD12) | I2C4_SDA (PD13) | **Qwiic** connector |
```cpp
#include <Wire.h>
void setup(){ Wire.begin(); } // or Wire1.begin() for Qwiic
// Wire.beginTransmission(addr); Wire.write(...); Wire.endTransmission();
```
### Qwiic connector
Plug-and-play I²C: polarized connector, daisy-chainable, built-in pull-ups, **3.3 V only** — no breadboard/soldering. Use `Wire1`. Works directly with Arduino's **Modulino** sensor/actuator family for solder-free prototyping.
## UART (hardware serial on the header)
| MCU pin | Arduino |
|---|---|
| PB6 | USART1_TX / D1 |
| PB7 | USART1_RX / D0 |
Use the **`Serial1`** object for the physical D0/D1 pins on the JDIGITAL connector:
```cpp
Serial1.begin(115200);
Serial1.println("Hello UNO Q");
while (Serial1.available()) { char c = Serial1.read(); /* ... */ }
```
> Note: `Serial1` here is the *header UART*. It is **not** the reserved router link — that reserved `Serial1` warning in the Bridge doc refers to the internal MPU↔MCU port; on the exposed headers `Serial1` drives D0/D1. Don't confuse the two: use `Serial1` for external UART devices, and never touch the internal router transport.
## `Serial` for debugging → App Lab console
Since platform **0.55.0**, plain `Serial` prints stream to the **Arduino App Lab Console** — use it like normal:
```cpp
void setup(){ Serial.begin(9600); }
void loop(){ Serial.println("Hello UNO Q"); delay(1000); }
```
The legacy `Monitor` object (`#include <Arduino_RouterBridge.h>``Monitor.begin()/println()`) still works for backward compatibility, but **use `Serial` for new projects.**
## How to actually control "our node's" attached hardware — recipe
1. Identify the interface the component uses (GPIO / ADC / PWM / SPI / I2C / UART) and the matching pins above. Mind **3.3 V** levels.
2. Write the **sketch** that drives it (the standard Arduino libraries work: `Servo`, `Wire`-based sensor libs, etc.).
3. If Python/AI/networking must control or read it, wrap each action in a `Bridge.provide_safe("name", fn)` on the MCU and `Bridge.call("name", ...)` from Python (see Bridge reference).
4. For quick prototyping of sensors/actuators, reach for **Qwiic + Modulino** modules to skip wiring.