This is an old revision of the document!


RP2040 internals

UART

The RP2040 microcontroller from Raspberry Pi offers two built-in UART peripherals for serial communication. Here's a basic introduction to using UART with Pico-SDK, including configuration, sending, and receiving data:

  • Include necessary libraries: In your C/C++ code, include the hardware/uart.h header from Pico-SDK:
#include <hardware/uart.h>
  • Initialize UART: Use the uart_init function to configure the desired UART peripheral (e.g., uart0 or uart1) and set parameters like baud rate, parity, and stop bits:
// Configure UART0 at 115200 baud, 8N1 format
int baudrate = 115200;
uart_init(uart0, baudrate);
//uart_set_format(uart, 8, 1, UART_PARITY_NONE);

// Set the TX and RX pins by using the function select on the GPIO 0 and 1
gpio_set_function(0, GPIO_FUNC_UART);
gpio_set_function(1, GPIO_FUNC_UART);
  • Sending data:
    • Prepare data: The data you want to send must be an array of characters (char*).
    • Transmit data: Use the uart_puts function for sending a null-terminated string (\0 at the end). Alternatively, uart_write_blocking offers more control over the data buffer and transmission:
const char* message = "Hello from RP2040!\n";

// Sending a string with uart_puts
uart_puts(uart0, message);

// Sending raw data with uart_write_blocking
uint8_t data[] = {0x41, 0x42, 0x43};  // Example data bytes
int written = uart_write_blocking(uart0, data, sizeof(data));
  • Receiving data:
    • Read data: Use the uart_getc function to read a single character from the receive buffer.
    • Check for available data: Before reading, use uart_is_readable to ensure data is present in the buffer to avoid errors.
int received_char;

// Reading a single character
while (uart_is_readable(uart0)) {
  received_char = uart_getc(uart0);
  // Process received character (e.g., print it)
}

// Reading data into a buffer with a timeout
uint8_t buffer[10];
int num_read = uart_read_blocking(uart0, buffer, sizeof(buffer), 100);  // Wait 100ms for data
if (num_read > 0) {
  // Process received data in the buffer
}

Interrupts

A hardware interrupt is a type of exception which is a synchronous or asynchronous signal from a peripheral that signals the occurrence of an event that must be handled by the processor. Interrupt handling has the effect of suspending a program's normal thread of execution and launching an interrupt service routine (ISR).

Generally, to associate an interrupt with a specific routine in the program, the processor uses the interrupt vector table (IVT). In this table, each interrupt is associated with the address to which the program will jump when the interrupt is triggered. These addresses are predefined and are mapped in program memory.

When an interrupt request happens the first thing that the processor does is to memorize its current state. For ARM Cortex-M0 this happens by pushing 8 words or registered data into the main stack to provide the information need to return the processor to what it was doing before before the interrupt request was called. This part is called the stack frame and it includes registers 0 through 3, register 12, the link register, the program counter and the program status register.

 dsa

ARM Cortex-M microcontrollers also use a Nested Vectored Interrupt Controller (NVIC). The NVIC is specifically designed to handle these interrupts more efficiently. Interrupt addresses in the NVIC memory region are set according to their priority: the lower the address, the higher the priority. As suggested by the “Nested” in its name, the NVIC supports nested interrupts. This means that if a higher priority interrupt occurs while another interrupt is being processed, the controller can pause the current interrupt service routine (ISR), handle the higher priority interrupt, and then resume the interrupted ISR. This feature is crucial for responsive and real-time processing.

The RP2040 boots from an internal bootloader that sets the initial interrupt IVT. The before starting the actual code written into Flash, the internal bootloader loads a secondary bootloader that is written in Flash (the first 256 bytes) together with the developer's app. The IVT that the Flash application provides start after the secondary bootloader, at address 0x100.

 dsa

The RP2040 chip has two cores (processors), and each core has its own NVIC. Each core's NVIC is connected to the same set of hardware interrupt lines with one exception: IO Interrupts. In the RP2040, IO interrupts are organized by banks, and each core has its own set of IO interrupts for each bank. The IO interrupts for each core are completely independent. For instance, Processor 0 (Core 0) can be interrupted by an event on GPIO pin 0 in bank 0, while Processor 1 (Core 1) can be interrupted by a separate event on GPIO pin 1 in the same bank. Each processor responds only to its own interrupts, allowing them to operate independently or to handle different tasks simultaneously without interfering with each other.

 dsa

On RP2040, only the lower 26 IRQ signals are connected on the NVIC, as seen in the table below, and IRQs 26 to 31 are tied to zero (never firing). The core can still be forced to enter the relevant interrupt handler by writing bits 26 to 31 in the NVIC ISPR register.

 dsa

The priority order is determined for these signals is determined by :

  • First, the dynamic priority level configured per interrupt by the NVIC_IPR0-7 registers. The Cortex-M0+ implements the two most significant bits of an 8-bit priority field, so four priority levels are available, and the numerically-lowest level (level 0) is the highest priority.
  • Second, for interrupts with the same dynamic priority level, the lower-numbered IRQ has higher priority (using the IRQ numbers given in the table above)

All GPIO pins in Raspberry Pi Pico support interrupts. The interrupts can be classified into three types:

  • Level High: An interrupt occurs while a pin is HIGH or at logic 1.
  • Level Low: An interrupt occurs while a pin is LOW or at logic 0.
  • Rising Edge: Interrupt occurs when a pin transitions from a LOW to HIGH.
  • Falling Edge: Interrupt occurs when a pin transitions from HIGH to LOW.

Timers

Exercises

  1. Write a program for a Raspberry Pi Pico to communicate with another device via UART. The program will set up the UART with desired settings, send a predefined message, receive incoming data, and process it (like printing or storing).
  2. Prepare your setup for Marble Pico interaction with VS Code and pico SDK or use Arduino IDE support according to instructions available here: Ardushop Marble Pico.

References

eap/laboratoare/02.1721223315.txt.gz · Last modified: 2024/07/17 16:35 by jan.vaduva
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0