Skip to content

UART API

The UART API provides console I/O functions for serial communication.

Overview

The UART module provides:

  • Character and string I/O
  • Printf-style formatted output
  • Input buffering and line editing
  • Non-blocking input checking
  • Buffer management

The SDK configures UART0 for:

  • 115200 baud rate
  • 8 data bits, no parity, 1 stop bit (8N1)
  • No hardware flow control
#include <embsec/uart.h>

Initialization

embsec_uart_init

void embsec_uart_init(void);

Initialize UART for console I/O. This is automatically called by embsec_init().

Note: You don't need to call this directly unless reinitializing UART.

Character I/O

embsec_putchar

void embsec_putchar(int c);

Send a single character to UART.

Parameters:

  • c: Character to send (0-255)

Example:

embsec_putchar('A');
embsec_putchar('\n');

embsec_getchar

int embsec_getchar(void);

Get a single character from UART. This function blocks until a character is available.

Returns:

  • Character received (0-255)

Example:

embsec_printf("Press any key to continue...");
int c = embsec_getchar();
embsec_printf("\nYou pressed: %c\n", c);

embsec_kbhit

bool embsec_kbhit(void);

Check if a character is available without blocking.

Returns:

  • true if character available
  • false otherwise

Example:

// Non-blocking input check
if (embsec_kbhit()) {
    char c = embsec_getchar();
    process_command(c);
}

String I/O

embsec_puts

void embsec_puts(const char *str);

Send a null-terminated string to UART. Does not append newline.

Parameters:

  • str: Null-terminated string to send

Example:

embsec_puts("Hello, ");
embsec_puts("World!");
embsec_puts("\n");

embsec_gets

char *embsec_gets(char *buffer, size_t size);

Get a line of input from UART. Reads until newline or buffer full.

Parameters:

  • buffer: Buffer to store input
  • size: Maximum size of buffer (including null terminator)

Returns:

  • Pointer to buffer on success
  • NULL on error

Features:

  • Handles backspace for line editing
  • Null-terminates the string
  • Newline is not included in buffer
  • Echoes characters as typed

Example:

char name[32];
embsec_printf("Enter your name: ");
if (embsec_gets(name, sizeof(name))) {
    embsec_printf("Hello, %s!\n", name);
} else {
    embsec_printf("Error reading input\n");
}

Formatted Output

embsec_printf

int embsec_printf(const char *format, ...);

Printf-style formatted output to UART.

Parameters:

  • format: Format string
  • ...: Variable arguments

Returns:

  • Number of characters printed

Supported format specifiers:

  • %c - Character
  • %s - String
  • %d, %i - Signed decimal integer
  • %u - Unsigned decimal integer
  • %x - Unsigned hexadecimal (lowercase)
  • %X - Unsigned hexadecimal (uppercase)
  • %p - Pointer
  • %% - Literal percent sign

Example:

int value = 42;
embsec_printf("The answer is %d (0x%02X)\n", value, value);

// Print table
embsec_printf("%-10s %5s %8s\n", "Name", "Score", "Hex");
embsec_printf("%-10s %5d %8X\n", "Alice", 95, 95);

embsec_vprintf

int embsec_vprintf(const char *format, va_list args);

Vprintf-style formatted output. Useful for creating wrapper functions.

Parameters:

  • format: Format string
  • args: Variable argument list

Returns:

  • Number of characters printed

Example:

void debug_printf(const char *format, ...) {
    embsec_puts("[DEBUG] ");

    va_list args;
    va_start(args, format);
    embsec_vprintf(format, args);
    va_end(args);
}

Buffer Management

embsec_uart_flush

void embsec_uart_flush(void);

Wait until all pending transmit data has been sent. Useful before system reset or power down.

Example:

embsec_printf("System shutting down...\n");
embsec_uart_flush();  // Ensure message is sent
embsec_system_reset();

embsec_uart_clear

void embsec_uart_clear(void);

Clear the UART receive buffer, discarding any pending data.

Example:

// Clear any stale input before prompting
embsec_uart_clear();
embsec_printf("Enter command: ");

Common Patterns

void show_menu(void) {
    embsec_printf("\n=== Main Menu ===\n");
    embsec_printf("1. Option One\n");
    embsec_printf("2. Option Two\n");
    embsec_printf("3. Exit\n");
    embsec_printf("Choice: ");
}

int main(void) {
    embsec_init();

    while (1) {
        show_menu();

        char choice = embsec_getchar();
        embsec_printf("%c\n", choice);  // Echo choice

        switch (choice) {
            case '1':
                embsec_printf("You selected Option One\n");
                break;
            case '2':
                embsec_printf("You selected Option Two\n");
                break;
            case '3':
                embsec_printf("Goodbye!\n");
                embsec_uart_flush();
                return 0;
            default:
                embsec_printf("Invalid choice!\n");
        }
    }
}

Command Parser

void process_command(const char *cmd) {
    if (strcmp(cmd, "help") == 0) {
        embsec_printf("Available commands:\n");
        embsec_printf("  help    - Show this help\n");
        embsec_printf("  status  - Show system status\n");
        embsec_printf("  reset   - Reset system\n");
    } else if (strcmp(cmd, "status") == 0) {
        embsec_printf("System uptime: %u ms\n", embsec_get_tick_ms());
    } else if (strcmp(cmd, "reset") == 0) {
        embsec_system_reset();
    } else {
        embsec_printf("Unknown command: %s\n", cmd);
    }
}

int main(void) {
    embsec_init();
    char buffer[64];

    embsec_printf("Command Line Interface\n");
    embsec_printf("Type 'help' for commands\n");

    while (1) {
        embsec_printf("> ");

        if (embsec_gets(buffer, sizeof(buffer))) {
            if (strlen(buffer) > 0) {
                process_command(buffer);
            }
        }
    }
}

Debug Output

#define DEBUG 1

#if DEBUG
    #define DEBUG_PRINT(...) embsec_printf("[DEBUG] " __VA_ARGS__)
#else
    #define DEBUG_PRINT(...)
#endif

void some_function(int value) {
    DEBUG_PRINT("Entering function with value=%d\n", value);

    // Function implementation

    DEBUG_PRINT("Function completed\n");
}

Progress Indicator

void show_progress(int current, int total) {
    int percent = (current * 100) / total;

    embsec_printf("\rProgress: [");

    // Draw progress bar
    for (int i = 0; i < 20; i++) {
        if (i < (percent / 5)) {
            embsec_putchar('#');
        } else {
            embsec_putchar(' ');
        }
    }

    embsec_printf("] %d%%", percent);

    if (current >= total) {
        embsec_printf("\n");
    }
}

// Usage
for (int i = 0; i <= 100; i++) {
    show_progress(i, 100);
    embsec_delay_ms(50);
}

Terminal Compatibility

The UART functions work with standard terminal emulators:

  • Supports VT100 escape sequences
  • Backspace handling for line editing
  • Carriage return and line feed handling

ANSI Color Codes

// Color code definitions
#define ANSI_RED     "\x1b[31m"
#define ANSI_GREEN   "\x1b[32m"
#define ANSI_YELLOW  "\x1b[33m"
#define ANSI_BLUE    "\x1b[34m"
#define ANSI_RESET   "\x1b[0m"

// Colored output
embsec_printf(ANSI_GREEN "Success!" ANSI_RESET "\n");
embsec_printf(ANSI_RED "Error: " ANSI_RESET "Invalid input\n");

Performance Considerations

Buffering

  • UART transmission is interrupt-driven
  • Small transmit FIFO (16 bytes)
  • No receive buffering beyond hardware FIFO

Throughput

At 115200 baud:

  • ~11,520 characters per second theoretical maximum
  • ~10,000 characters per second practical throughput
  • Printf operations may block if buffer full

Best Practices

  1. Use flush before critical operations:

    embsec_printf("Critical error!\n");
    embsec_uart_flush();
    embsec_system_reset();
    

  2. Clear input buffer before prompts:

    embsec_uart_clear();
    embsec_printf("Enter password: ");
    

  3. Check for input in main loop:

    while (1) {
        // Do work
    
        if (embsec_kbhit()) {
            handle_input();
        }
    }
    

  4. Limit printf in interrupts:

    // BAD - Printf in interrupt
    void timer_isr(void) {
        embsec_printf("Timer fired!\n");  // May cause issues
    }
    
    // GOOD - Set flag in interrupt
    volatile bool timer_fired = false;
    void timer_isr(void) {
        timer_fired = true;
    }
    
    // Print in main loop
    if (timer_fired) {
        timer_fired = false;
        embsec_printf("Timer fired!\n");
    }
    

Troubleshooting

No Output

  1. Check terminal settings: 115200 8N1
  2. Verify embsec_init() was called
  3. Check TX/RX connections

Garbled Characters

  1. Verify baud rate matches terminal
  2. Check for clock configuration issues
  3. Ensure proper grounding

Missing Characters

  1. Add embsec_uart_flush() after output
  2. Check for buffer overruns
  3. Reduce output rate

Example: Interactive Shell

#include <embsec/embsec.h>
#include <embsec/uart.h>
#include <string.h>

#define CMD_BUFFER_SIZE 64
#define HISTORY_SIZE 5

typedef struct {
    char buffer[CMD_BUFFER_SIZE];
} cmd_history_t;

int main(void) {
    embsec_init();

    cmd_history_t history[HISTORY_SIZE] = {0};
    int history_index = 0;
    char cmd_buffer[CMD_BUFFER_SIZE];

    embsec_printf("\n=== EmbSec Interactive Shell ===\n");
    embsec_printf("Type 'help' for commands\n\n");

    while (1) {
        // Show prompt
        embsec_printf("embsec> ");

        // Get command
        if (!embsec_gets(cmd_buffer, sizeof(cmd_buffer))) {
            continue;
        }

        // Skip empty commands
        if (strlen(cmd_buffer) == 0) {
            continue;
        }

        // Save to history
        strcpy(history[history_index].buffer, cmd_buffer);
        history_index = (history_index + 1) % HISTORY_SIZE;

        // Process command
        if (strcmp(cmd_buffer, "help") == 0) {
            embsec_printf("Commands:\n");
            embsec_printf("  help     - Show this help\n");
            embsec_printf("  clear    - Clear screen\n");
            embsec_printf("  echo MSG - Echo message\n");
            embsec_printf("  history  - Show command history\n");
            embsec_printf("  uptime   - Show system uptime\n");
            embsec_printf("  exit     - Exit shell\n");
        }
        else if (strcmp(cmd_buffer, "clear") == 0) {
            embsec_printf("\x1b[2J\x1b[H");  // ANSI clear screen
        }
        else if (strncmp(cmd_buffer, "echo ", 5) == 0) {
            embsec_printf("%s\n", cmd_buffer + 5);
        }
        else if (strcmp(cmd_buffer, "history") == 0) {
            embsec_printf("Command history:\n");
            for (int i = 0; i < HISTORY_SIZE; i++) {
                if (strlen(history[i].buffer) > 0) {
                    embsec_printf("  %s\n", history[i].buffer);
                }
            }
        }
        else if (strcmp(cmd_buffer, "uptime") == 0) {
            uint32_t ms = embsec_get_tick_ms();
            uint32_t sec = ms / 1000;
            embsec_printf("Uptime: %u:%02u:%02u\n", 
                         sec / 3600, (sec / 60) % 60, sec % 60);
        }
        else if (strcmp(cmd_buffer, "exit") == 0) {
            embsec_printf("Goodbye!\n");
            break;
        }
        else {
            embsec_printf("Unknown command: %s\n", cmd_buffer);
        }
    }

    return 0;
}