Skip to main content

UART

The UART (Universal Asynchronous Receiver/Transmitter) interface provides asynchronous serial communication. Supports configurable baud rates from 300 to 12,000,000 bps with various data formats and voltage levels from 1.8 V to 3.3 V.

Multiplexing

Some interfaces share the same GPIO pins, so only one can be used at a time. Check out the pin alternate functions page for more details.

The PWM pins use the same channels: enabling UART fails with 409 CONFIGURATION_CONFLICT while PWM is enabled on a pin of the same channel (DA17/DA18 for UART 0, DA21/DA22 for UART 1).

Pin-voltage check

Enabling UART, or changing vcc while it is enabled, first measures its RX and TX pins. If any of them reads below −0.5 V or above vcc + 0.5 V, the request fails with 409 UNSAFE_PIN_VOLTAGE and the interface stays disabled. The error message names the pin and the voltage measured. Reconfiguring with an unchanged vcc does not repeat the check.

Quick Start​

The example code below shows how to enable the UART interface, configure it, and transmit/receive data.

import { AT1000 } from '@ikalogic/at1000';
let devices = await AT1000.findDevices(); // Find devices (returns host strings)
let tester = await AT1000.open(devices[0]); // Open the first detected device
await tester.reset(); // Reset the device to a known state
let uart = tester.com.uart(0); // Select the first UART interface

await uart.enable({
vcc: 3.3,
baud_rate: 115200,
data_bits: 8,
parity: 'none',
stop_bits: '1'
}); // Enable UART with standard 115200 8N1 configuration

// Transmit data
await uart.tx("Hello, World!\r\n");

// Start continuous receive
await uart.start_rx();

// Wait for some data
await new Promise(resolve => setTimeout(resolve, 100));

// Read received data
let data = await uart.rx();
console.log("Received:", data);

// Stop reception
await uart.stop_rx();

// Disable UART interface
await uart.disable();

API Reference​

Accessing UART​

const uart = tester.com.uart(id);

Parameters:

  • id (number / int / u32): The UART interface identifier (0-based index)

Returns: Uart instance / Result<Uart, At1000Error> in Rust


Methods​

configure(config)​

Configures the UART interface parameters without changing the enabled state.

await uart.configure({
baud_rate: 9600,
data_bits: 8,
parity: 'none',
stop_bits: '1',
vcc: 3.3
});

Parameters:

  • config (UartConfigPatch / &UartConfigPatch in Rust): Configuration object with optional properties:
    • enabled (boolean / bool / Option<bool>, optional): Enable or disable the interface
    • baud_rate (number / int / Option<u32>, optional): Baud rate (300 to 12,000,000)
    • data_bits (number / int / Option<u8>, optional): Data bits per character (7 or 8)
    • parity (string / str / Option<SerialParity>, optional): Parity mode - 'none', 'odd', 'even', 'mark', or 'space'
    • stop_bits (string / str / Option<SerialStopBits>, optional): Stop bits - '1', '1.5', or '2'
    • vcc (number / float / Option<f64>, optional): Logic level voltage (1.8 to 3.3)

Returns: Promise<UartConfig> / UartConfig / Result<UartConfig, At1000Error> - The updated configuration

Exceptions:

  • Throws validation error if baud_rate is outside [300, 12000000]
  • Throws validation error if data_bits is not 7 or 8
  • Throws validation error if parity is not 'none', 'odd', 'even', 'mark', or 'space'
  • Throws validation error if stop_bits is not '1', '1.5', or '2'
  • Throws validation error if vcc is outside [1.8, 3.3]

enable([config])​

Enables the UART interface and optionally applies configuration.

await uart.enable({
baud_rate: 115200,
data_bits: 8,
parity: 'none',
stop_bits: '1',
vcc: 3.3
});

Parameters:

  • config (UartEnableConfig, optional / &UartEnableConfig in Rust): Optional configuration to apply

Returns: Promise<UartConfig> / UartConfig / Result<UartConfig, At1000Error> - The updated configuration with enabled: true


disable()​

Disables the UART interface.

await uart.disable();

Returns: Promise<UartConfig> / UartConfig / Result<UartConfig, At1000Error> - The updated configuration with enabled: false


tx(data)​

Transmits data over the UART interface.

// Transmit string data
await uart.tx("Hello\r\n");

// Transmit raw bytes
await uart.tx([0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0D, 0x0A]);

Parameters:

  • data (SerialDataInput / &[u8] in Rust): Data to transmit, either a string or a number[] byte array (up to 65536 bytes). Rust accepts bytes only - write text as b"..." or text.as_bytes()

Returns: Promise<SerialData> / SerialData / Result<SerialData, At1000Error> - The transmitted data as a byte array (number[], Vec<u8> in Rust)

Exceptions:

  • Throws validation error if data exceeds 65536 bytes

start_rx()​

Starts continuous reception. Data is buffered internally until read with rx().

await uart.start_rx();

Returns: Promise<void> / None / Result<(), At1000Error>


stop_rx()​

Stops continuous reception.

await uart.stop_rx();

Returns: Promise<void> / None / Result<(), At1000Error>


rx()​

Reads received data from the internal buffer.

// Read all available data
const data = await uart.rx();
console.log("Received:", data);

Returns: Promise<SerialData> / SerialData / Result<SerialData, At1000Error> - Received data as byte array (number[], Vec<u8> in Rust)

Notes:

  • Returns immediately with available data (non-blocking)
  • Clears the receive buffer after reading
  • Must call start_rx() before receiving data

Types​

UartConfig​

Complete configuration object returned by configuration methods.

{
enabled: boolean,
baud_rate: number, // 300 to 12,000,000
data_bits: number, // 7 or 8
parity: 'none' | 'odd' | 'even' | 'mark' | 'space',
stop_bits: '1' | '1.5' | '2',
vcc: number // 1.8 to 3.3
}

Rust: ikalogic_at1000::UartConfig

pub struct UartConfig {
pub enabled: bool,
pub baud_rate: u32,
pub vcc: f64,
pub data_bits: u8,
pub stop_bits: SerialStopBits,
pub parity: SerialParity,
}

pub enum SerialStopBits { One, OnePointFive, Two }
pub enum SerialParity { None, Odd, Even, Mark, Space }

UartConfigPatch​

Partial configuration for the configure() method. All properties are optional.

{
enabled?: boolean,
baud_rate?: number,
data_bits?: number,
parity?: 'none' | 'odd' | 'even' | 'mark' | 'space',
stop_bits?: '1' | '1.5' | '2',
vcc?: number
}

Rust: ikalogic_at1000::UartConfigPatch (derives Default, so unset fields stay None)

pub struct UartConfigPatch {
pub enabled: Option<bool>,
pub baud_rate: Option<u32>,
pub vcc: Option<f64>,
pub data_bits: Option<u8>,
pub stop_bits: Option<SerialStopBits>,
pub parity: Option<SerialParity>,
}

UartEnableConfig​

Optional configuration for the enable() method.

{
baud_rate?: number,
data_bits?: number,
parity?: 'none' | 'odd' | 'even' | 'mark' | 'space',
stop_bits?: '1' | '1.5' | '2',
vcc?: number
}

Rust: ikalogic_at1000::UartEnableConfig (derives Default, so unset fields stay None)

pub struct UartEnableConfig {
pub baud_rate: Option<u32>,
pub vcc: Option<f64>,
pub data_bits: Option<u8>,
pub stop_bits: Option<SerialStopBits>,
pub parity: Option<SerialParity>,
}

SerialData​

Output data type, always returned as a byte array.

number[] // Array of bytes (0-255)

Rust: ikalogic_at1000::SerialData

pub type SerialData = Vec<u8>;

Common Baud Rates​

Baud RateDescription
300Low-speed legacy
1200Legacy modems
2400Legacy modems
4800Legacy devices
9600Common default
19200Common
38400Common
57600Common
115200Most common high-speed
230400High-speed
460800High-speed
921600Very high-speed
10000001 Mbps
20000002 Mbps
1200000012 Mbps (maximum)

Usage Example​

import { AT1000 } from '@ikalogic/at1000';

// Find and connect to device
const devices = await AT1000.findDevices();
const tester = await AT1000.open(devices[0]);
await tester.reset(); // Reset the device to a known state

// Access UART interface 0
const uart = tester.com.uart(0);

// Enable with standard 115200 8N1 configuration
await uart.enable({
baud_rate: 115200,
data_bits: 8,
parity: 'none',
stop_bits: '1',
vcc: 3.3
});

// Start continuous reception
await uart.start_rx();

// Send a command
await uart.tx("AT\r\n");

// Wait for response
await new Promise(resolve => setTimeout(resolve, 100));

// Read response
const response = await uart.rx();
console.log("Response:", Buffer.from(response).toString());

// Stop reception and disable
await uart.stop_rx();
await uart.disable();

Common Patterns​

AT Command Interface​

async function sendATCommand(uart, command, timeout = 1000) {
// Clear any pending data
await uart.rx();

// Send command
await uart.tx(command + "\r\n");

// Wait for response
await new Promise(resolve => setTimeout(resolve, timeout));

// Read response
const response = await uart.rx();
return Buffer.from(response).toString().trim();
}

// Usage
await uart.start_rx();

const info = await sendATCommand(uart, "ATI");
console.log("Device info:", info);

const signal = await sendATCommand(uart, "AT+CSQ");
console.log("Signal quality:", signal);

GPS NMEA Receiver​

// Configure for GPS module (9600 baud typical)
await uart.enable({
baud_rate: 9600,
data_bits: 8,
parity: 'none',
stop_bits: '1',
vcc: 3.3
});

await uart.start_rx();

// Read NMEA sentences
let buffer = '';

while (true) {
const data = await uart.rx();
if (data.length > 0) {
buffer += Buffer.from(data).toString();

// Process complete sentences
const lines = buffer.split('\r\n');
buffer = lines.pop(); // Keep incomplete sentence

for (const line of lines) {
if (line.startsWith('$GPGGA')) {
console.log("Position:", line);
} else if (line.startsWith('$GPRMC')) {
console.log("Navigation:", line);
}
}
}
await new Promise(resolve => setTimeout(resolve, 100));
}

Binary Protocol​

// Send binary command with header and checksum
function buildPacket(command, data) {
const packet = [0xAA, 0x55, command, data.length, ...data];
const checksum = packet.reduce((a, b) => a ^ b, 0);
return [...packet, checksum];
}

// Read binary response
async function readPacket(uart, timeout = 1000) {
const startTime = Date.now();
let buffer = [];

while (Date.now() - startTime < timeout) {
const data = await uart.rx();
buffer.push(...data);

// Check for complete packet
if (buffer.length >= 4 && buffer[0] === 0xAA && buffer[1] === 0x55) {
const length = buffer[3];
if (buffer.length >= 5 + length) {
return buffer.slice(0, 5 + length);
}
}

await new Promise(resolve => setTimeout(resolve, 10));
}

throw new Error("Timeout waiting for packet");
}

// Usage
const packet = buildPacket(0x01, [0x10, 0x20]);
await uart.tx(packet);
const response = await readPacket(uart);

Line-Based Protocol​

class LineReader {
constructor(uart) {
this.uart = uart;
this.buffer = '';
}

async readLine(timeout = 5000) {
const startTime = Date.now();

while (Date.now() - startTime < timeout) {
const data = await this.uart.rx();
this.buffer += Buffer.from(data).toString();

const newlineIndex = this.buffer.indexOf('\n');
if (newlineIndex !== -1) {
const line = this.buffer.substring(0, newlineIndex).replace('\r', '');
this.buffer = this.buffer.substring(newlineIndex + 1);
return line;
}

await new Promise(resolve => setTimeout(resolve, 10));
}

throw new Error("Timeout waiting for line");
}

async writeLine(text) {
await this.uart.tx(text + '\r\n');
}
}

// Usage
const reader = new LineReader(uart);
await reader.writeLine("GET STATUS");
const status = await reader.readLine();
console.log("Status:", status);

Echo Test​

// Loop TX to RX for echo test
async function echoTest(uart, testData) {
await uart.start_rx();

// Send test data
await uart.tx(testData);

// Wait for echo
await new Promise(resolve => setTimeout(resolve, 100));

// Read response
const received = await uart.rx();

// Compare
const sent = typeof testData === 'string'
? Array.from(Buffer.from(testData))
: testData;

const match = sent.length === received.length &&
sent.every((v, i) => v === received[i]);

console.log(`Echo test: ${match ? 'PASS' : 'FAIL'}`);
return match;
}

await echoTest(uart, "Hello, World!");

Notes​

  • The UART interface supports TTL-level signals only (not RS-232 voltage levels)
  • Use appropriate level shifters for 5V logic when vcc is set higher
  • Flow control (RTS/CTS) is not supported
  • The receive buffer has limited capacity; read frequently to avoid overflow
  • For very high baud rates (> 1 Mbps), ensure signal integrity and short cable lengths
  • Always call start_rx() before expecting to receive data
  • The maximum single transmission is 65536 bytes