This shows you the differences between two versions of the page.
eap:laboratoare:02 [2024/07/17 16:55] jan.vaduva [UART] |
eap:laboratoare:02 [2024/07/18 10:08] (current) jan.vaduva |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== RP2040 internals ===== | + | ===== RP2040 internals: UART, interrupts & timers ===== |
==== UART ==== | ==== UART ==== | ||
Line 118: | Line 118: | ||
* Rising Edge: Interrupt occurs when a pin transitions from a LOW to HIGH. | * 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. | * Falling Edge: Interrupt occurs when a pin transitions from HIGH to LOW. | ||
+ | |||
+ | Here's a basic introduction to using interrupts on RP2040 with Pico-SDK, including setup, trigger sources, and handler functions. | ||
+ | * Include necessary libraries: In your C/C++ code, include the hardware/irq.h header from Pico-SDK: | ||
+ | |||
+ | <code> | ||
+ | #include <hardware/irq.h> | ||
+ | </code> | ||
+ | * Globally enable interrupts using the **irq_set_enabled(true)** function. This allows the RP2040 to recognize and respond to interrupt requests. Various hardware events can trigger interrupts, like changes on GPIO pins, timers expiring, or DMA transfers completing. | ||
+ | <code> | ||
+ | // Set up a RX interrupt | ||
+ | int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ; | ||
+ | |||
+ | // And set up and enable the interrupt handlers | ||
+ | irq_set_exclusive_handler(UART_IRQ, on_uart_rx); | ||
+ | irq_set_enabled(UART_IRQ, true); | ||
+ | </code> | ||
+ | * Define a function to handle the interrupt. This function is called whenever the configured trigger source (e.g., the GPIO pin change) occurs. The handler function can perform actions like reading the GPIO pin state, triggering other events, or notifying other parts of your program about the interrupt. | ||
+ | <code> | ||
+ | // RX interrupt handler | ||
+ | void on_uart_rx() { | ||
+ | // Perform action based on the interrupt | ||
+ | | ||
+ | // Clear the interrupt flag (important) | ||
+ | } | ||
+ | </code> | ||
==== Timers ==== | ==== Timers ==== | ||
+ | Timers are hardware components that generate periodic interrupts or control signals at defined intervals. Timers offer a wide range of functionalities, including: | ||
+ | * **Generating delays**: Create precise timing delays in your program without busy waiting. | ||
+ | * **Implementing periodic tasks**: Execute code sections at regular intervals (e.g., blinking an LED, reading sensor data). | ||
+ | * **Pulse Width Modulation (PWM)**: Generate square waves with varying pulse widths for controlling motors, LEDs with adjustable brightness, etc. | ||
+ | The system timer is intended to provide a global timebase for software. RP2040 has a number of other programmable counter resources which can provide regular interrupts, or trigger DMA transfers. | ||
+ | * The PWM contains 8× 16-bit programmable counters, which run at up to system speed, can generate interrupts, and can be continuously reprogrammed via the DMA, or trigger DMA transfers to other peripherals. | ||
+ | * 8× PIO state machines can count 32-bit values at system speed, and generate interrupts. | ||
+ | * The DMA has four internal pacing timers, which trigger transfers at regular intervals. | ||
+ | * Each Cortex-M0+ core has a standard 24-bit SysTick timer, counting either the microsecond tick or the system clock. | ||
+ | |||
+ | The timer has a 64-bit counter, but RP2040 only has a 32-bit data bus. This means that the TIME value is accessed | ||
+ | through a pair of registers. These are: | ||
+ | * **TIMEHW** and **TIMELW** to write the time | ||
+ | * **TIMEHR** and **TIMELR** to read the time | ||
+ | These pairs are used by accessing the lower register, L, followed by the higher register, H. In the read case, reading the L register latches the value in the H register so that an accurate time can be read. Alternatively, **TIMERAWH** and **TIMERAWL** can be used to read the raw time without any latching. | ||
+ | |||
+ | The timer has 4 alarms, and outputs a separate interrupt for each alarm. The alarms match on the lower 32 bits of the | ||
+ | 64-bit counter which means they can be fired at a maximum of 232 microseconds into the future. This is equivalent to: | ||
+ | * 232 ÷ 106: ~4295 seconds | ||
+ | * 4295 ÷ 60: ~72 minutes | ||
+ | |||
+ | To enable an alarm: | ||
+ | * Enable the interrupt at the timer with a write to the appropriate alarm bit in INTE: i.e. (1 << 0) for ALARM0 | ||
+ | * Enable the appropriate timer interrupt at the processor (see Section 2.3.2) | ||
+ | * Write the time you would like the interrupt to fire to ALARM0 (i.e. the current value in TIMERAWL plus your desired alarm time in microseconds). Writing the time to the ALARM register sets the ARMED bit as a side effect. | ||
+ | Once the alarm has fired, the ARMED bit will be set to 0. To clear the latched interrupt, write a 1 to the appropriate bit in | ||
+ | INTR. | ||
+ | |||
+ | For using timers on RP2040 with Pico-SDK include the hardware/timer.h header from Pico-SDK: | ||
+ | |||
+ | <code> | ||
+ | #include <hardware/timer.h> | ||
+ | </code> | ||
==== Exercises ==== | ==== Exercises ==== | ||
- 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). | - 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). |