Популярность платы Raspberry Pico на базе микроконтроллера RP2040 велика. Поэтому поговорим о программируемых модулях ввода-вывода RP2040 – функции, которая отличает ее от большинства других плат микроконтроллеров.
Каждый из двух блоков PIO или, скажем так, аппаратных интерфейсов RP2040, имеет четыре конечных автомата. Эти два блока PIO могут одновременно выполнять программы для управления GPIO и передачи необработанных данных. Итак, что делают эти конечные автоматы? Конечные автоматы PIO выполняют программы, полученные из различных источников, к примеру из библиотеки PIO (UART, SPI или I2C) или пользовательского ПО.
Почему программируемый ввод-вывод?
Все платы обычно поставляются с аппаратной поддержкой протоколов цифровой связи, таких как I2C, SPI и UART. Однако, если вы планируете использовать больше этих интерфейсов, чем доступно на плате, вы можете использовать программируемые входы-выходы, предусмотренные в микроконтроллере RP2040.
Это дает больше возможностей, чем можно подумать. Допустим, вы хотите выводить видео с разрешением DPI или «использовать последовательное устройство с AliExpress» и это теперь возможно с помощью программируемого ввода-вывода. Из названия «программируемый» следует, что его можно запрограммировать напрямую для поддержки нескольких интерфейсов, включая интерфейс SD-карты, выход VGA и более высокую скорость передачи данных. И! Самая интересная часть обзора – «Как запрограммировать эти программируемые входы/выходы, чтобы облегчить вашу работу».
Как начать работу с программированием PIO RP2040?
Pico SDK (Software Development Kit) предоставляет разъемы, библиотеки и систему сборки, необходимые для написания программ для устройств на базе RP2040, таких как Raspberry Pi Pico, на языке C, C ++ или Arm.
Если вы планируете использовать Python для кодирования, вам потребуется только подходящий редактор (скажем, Thonny) и MicroPython, установленный на плате разработки. Но, в случае C/C ++ вам потребуется файл CMake, который сообщает Pico SDK, как превратить файл C в двоичное приложение для платы микроконтроллера на базе RP2040, как описано в нашем недавнем руководстве по MicroPython и C для Raspberry Pi Pico.
PIO ассемблер анализирует исходный файл PIO и выводит собранную версию, готовую для включения в приложение RP2040. Сюда входят приложения C и C ++, созданные на основе Pico SDK, и программы Python, работающие на порту MicroPython RP2040.
Чтобы начать программирование конечного автомата для вашего PIO-приложения, есть три компонента для программы на C/C ++.
- Программа PIO
- Программное обеспечение на языке C для запуска демонстрации.
- Файл CMake, описывающий, как эти два элемента объединяются в образ программы для загрузки на плату разработки на базе RP2040.
Инструкции по сборке PIO
Теперь, когда дело доходит до программирования этих интерфейсов ввода-вывода, существует девять инструкций сборки «JMP, WAIT, IN, OUT, PUSH, PULL, MOV, IRQ и SET». Хотя большинство людей могут быть заинтересованы в программировании интерфейсов PIO на языке C / C ++ или Python, давайте рассмотрим некоторые инструкции на языке ассемблера, используемые для интерфейсов ввода-вывода.
- JMP: эта инструкция «перехода» может быть условной или не условной. При этом он передает поток выполнения, изменяя регистр указателя команд. Проще говоря, с оператором «jmp» поток выполнения переходит к другой части кода.
- WAIT: эта инструкция останавливает выполнение кода. Каждая инструкция занимает один цикл, если она не остановлена (с использованием инструкций WAIT).
- OUT: Эта инструкция перемещает данные из выходного регистра сдвига в другие места назначения, по 1… 32 бита за раз.
- PULL: Эта инструкция выталкивает 32-битные слова из TX FIFO в выходной регистр сдвига.
- IN: Эта инструкция сдвигает в регистр 1… 32 бита за раз. I
- PUSH: Эта инструкция для записи содержимого ISR в RX FIFO.
Более подробная информация об инструкциях на ассемблере доступна в спецификациях RP2040.
Пример программирования PIO RP2040 на C / C ++ и MicroPython Чтобы упростить задачу, мы рассмотрим программу hello_world, которая отвечает за мигание встроенного светодиода, используя программируемые входы-выходы и 32-битные данные TX FIFO (инструкции PULL).
Программа на C / C ++ выглядит примерно так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include "pico/stdlib.h" #include "hardware/pio.h" // Our assembled program: #include "hello.pio.h" int main() { // Choose which PIO instance to use (there are two instances) PIO pio = pio0; // Our assembled program needs to be loaded into this PIO's instruction // memory. This SDK function will find a location (offset) in the // instruction memory where there is enough space for our program. We need // to remember this location! uint offset = pio_add_program(pio, &hello_program); // Find a free state machine on our chosen PIO (erroring if there are // none). Configure it to run our program, and start it, using the // helper function we included in our .pio file. uint sm = pio_claim_unused_sm(pio, true); hello_program_init(pio, sm, offset, PICO_DEFAULT_LED_PIN); // The state machine is now running. Any value we push to its TX FIFO will // appear on the LED pin. while (true) { // Blink pio_sm_put_blocking(pio, sm, 1); sleep_ms(500); // Blonk pio_sm_put_blocking(pio, sm, 0); sleep_ms(500); } } |
Приведенный выше код C / C ++ мигает светодиодом с одним полным циклом в 1 секунду. Светодиод запрограммирован таким образом, что он будет гореть 500 мс, а затем выключаться на 500 мс. Но, прежде чем конечный автомат сможет запустить программу, нам нужно загрузить программу в эту память команд. «Функция pio_add_program () находит свободное место для нашей программы в памяти инструкций данного PIO и загружает его». Таким образом, мы настраиваем конечный автомат для вывода данных на встроенный светодиод.
Код сборки для файла .pio, показанный ниже, содержит все вспомогательные функции C для установки кода C / C ++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.program hello loop: pull out pins, 1 jmp loop % c-sdk { static inline void hello_program_init(PIO pio, uint sm, uint offset, uint pin) { pio_sm_config c = hello_program_get_default_config(offset); // Map the state machine's OUT pin group to one pin, namely the `pin` // parameter to this function. sm_config_set_out_pins(&c, pin, 1); // Set this pin's GPIO function (connect PIO to the pad) pio_gpio_init(pio, pin); // Set the pin direction to output at the PIO pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); // Load our configuration, and jump to the start of the program pio_sm_init(pio, sm, offset, &c); // Set the state machine running pio_sm_set_enabled(pio, sm, true); } %} |
Помимо этого, вам также потребуется файл CMake, который описывает, как файлы .pio и .c встраиваются в двоичный файл, подходящий для загрузки на плату разработки Raspberry Pi Pico.
Эквивалентного образца, написанного с помощью MicroPython, не существует, но мы можем увидеть более простой код PIO MicroPython, используемый для мигания встроенного светодиода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import time from rp2 import PIO, asm_pio from machine import Pin # Define the blink program. It has one GPIO to bind to on the set instruction, which is an output pin. # Use lots of delays to make the blinking visible by eye. @asm_pio(set_init=rp2.PIO.OUT_LOW) def blink(): wrap_target() set(pins, 1) [31] nop() [31] nop() [31] nop() [31] nop() [31] set(pins, 0) [31] nop() [31] nop() [31] nop() [31] nop() [31] wrap() # Instantiate a state machine with the blink program, at 1000Hz, with set bound to Pin(25) (LED on the rp2 board) sm = rp2.StateMachine(0, blink, freq=1000, set_base=Pin(25)) # Run the state machine for 3 seconds. The LED should blink. sm.active(1) time.sleep(3) sm.active(0) |
В этом случае нет отдельного файла .pio, и и MicroPython, и код сборки помещаются в файл .py.
Обратите внимание, что хотя PIO можно запрограммировать с помощью MicroPython, в документации Python SDK говорится, что он в настоящее время нестабилен / находится в стадии разработки, поэтому рекомендуется C / C ++.
В код можно внести множество изменений, добавив цвет, который вы хотите отображать, с помощью шестнадцатеричного формата в RGB. Однако есть много примеров из реальной жизни, таких как PWM, UART или даже взаимодействие NeoPixels. Для тех, кто заинтересован, вы можете найти множество примеров программирования PIO в репозиториях GitHub для образцов C и MicroPython.
Заключение
Программируемые модули ввода-вывода RP2040 могут одновременно выполнять программы для поддержки таких интерфейсов, как выход VGA. Вы можете ознакомиться с главой 3 в документации SDK для C/C++ и Python, чтобы узнать больше о программируемых ввода-вывода RP2040.
Выражаем свою благодарность источнику из которого взята и переведена статья, сайту cnx-software.com.
Оригинал статьи вы можете прочитать здесь.