深入了解Raspberry Pi RP2040可编程IO

2021-02-17 18:18:25

由RP2040微控制器提供支持的Raspberry Pico电路板的普及使每个读者都想了解有关该电路板和芯片的更多信息。因此,今天我们将讨论RP2040的可编程IO,该功能使其不同于大多数其他微控制器板。

RP2040中的两个PIO块或我们称之为硬件接口的每个都有四个状态机。这两个PIO模块可以同时执行程序来操纵GPIO和传输原始数据。现在,这些状态机做什么?好吧,PIO状态机执行从各种来源获取的程序。有时,这些程序来自PIO库(UART,SPI或I2C)或用户软件。

通常,所有板卡都对数字通信协议(例如I2C,SPI和UART)提供硬件支持。但是,如果计划使用的这些接口多于板上可用的接口,则可以使用RP2040微控制器中提供的可编程IO。

嗯,它具有的功能超出人们的想象。假设您现在想通过可编程I / O来输出DPI视频或“与AliExpress上的串行设备通信”。顾名思义,“可编程” IO使其可以直接编程以支持多种接口,包括SD卡接口,VGA输出和更高速度的数据传输。不挂断!我们在文章中最激动人心的部分是“如何对这些可编程I / O进行编程以使您的工作变得轻松”。

Pico SDK(软件开发工具包)提供了必要的头文件,库和构建系统,这些文件为使用C,C ++或Arm汇编语言为基于RP2040的设备(例如Raspberry Pi Pico)编写程序编写程序所必需。

如果您打算使用Python进行编码,则只需在开发板上安装合适的编辑器(例如Thonny)和MicroPython。但是对于C / C ++,您需要使用CMake文件,该文件可以告诉Pico SDK如何将C文件转换为基于RP2040的微控制器板的二进制应用程序,如我们最近针对Raspberry Pi Pico的MicroPython和C教程所述。

PIO汇编器解析一个PIO源文件并输出准备好包含在RP2040应用程序中的汇编版本。这包括针对Pico SDK构建的C和C ++应用程序,以及在RP2040 MicroPython端口上运行的Python程序。

要开始为您的PIO应用程序编程状态机,基于C / C ++的程序包含三个组件。

一个CMake文件,描述了如何将二者组合成程序映像以加载到基于RP2040的开发板上。

现在,在对这些IO接口进行编程时,有9条汇编指令“ JMP,WAIT,IN,OUT,PUSH,PULL,MOV,IRQ和SET”。尽管大多数人可能对使用C / C ++或Python语言对PIO接口进行编程感兴趣,但让我们研究一下用于IO接口的一些汇编语言指令。

JMP:此“跳转”指令可以是条件语句,也可以是非条件语句。在这种情况下,它通过更改指令指针寄存器来传输执行流程。简而言之,使用“ jmp”语句,执行流程进入代码的另一部分。

等待:该指令使代码的执行停止。除非被暂停(使用WAIT指令),否则每条指令需要一个周期。

OUT:该指令将数据从输出移位寄存器一次移至其他目的地,每次1…32位。

为了简化操作,我们将研究hello_world程序,该程序使用可编程IO和TX FIFO的32位数据(PULL指令)使板载LED闪烁。

#include" pico / stdlib.h" #include" hardware / pio.h" //我们的汇编程序:#include" hello.pio.h" int main (){//选择要使用的PIO实例(有两个实例)PIO pio = pio0; //我们的汇编程序需要加载到此PIO指令存储器中。此SDK函数将在//指令存储器中找到一个位置(偏移),在该位置有足够的空间供我们的程序使用。我们需要//记住这个位置! uint偏移量= pio_add_program(pio,& hello_program); //在我们选择的PIO上找到一个空闲状态机(如果没有//则出错)。配置它以运行我们的程序,并使用我们包含在.pio文件中的// helper函数启动它。 uint sm = pio_claim_unused_sm(pio,true); hello_program_init(pio,sm,偏移量,PICO_DEFAULT_LED_PIN); //状态机正在运行。我们推送到其TX FIFO的任何值都将//出现在LED引脚上。 while(true){//闪烁pio_sm_put_blocking(pio,sm,1); sleep_ms(500); //布隆克pio_sm_put_blocking(pio,sm,0); sleep_ms(500); }}

//状态机正在运行。我们推送到其TX FIFO的任何值都会

上面的C / C ++代码以1秒钟的完整周期闪烁LED。对LED进行编程的方式是:先点亮500毫秒,然后熄灭500毫秒。但是,在状态机可以运行程序之前,我们需要将程序加载到该指令存储器中。 “函数pio_add_program()在给定的PIO指令存储器中查找程序的可用空间,并将其加载。”这样,我们将状态机配置为将其数据输出到板载LED。

如下所示的.pio文件的汇编代码具有所有C助手功能来设置C / C ++代码。

.program helloloop:拉出引脚,1个jmp循环%c-sdk {静态内联void hello_program_init(PIO pio,uint sm,uint offset,uint pin){pio_sm_config c = hello_program_get_default_config(offset); //将状态机的OUT引脚组映射到一个引脚,即此函数的“ pin”参数。 sm_config_set_out_pins(& c,pin,1); //设置此引脚的GPIO功能(将PIO连接到焊盘)pio_gpio_init(pio,pin); //将引脚方向设置为在PIO上输出pio_sm_set_consecutive_pindirs(pio,sm,pin,1,true); //加载我们的配置,然后跳转到程序的开头pio_sm_init(pio,sm,offset,& c); //设置运行pio_sm_set_enabled(pio,sm,true);}%}的状态机

除此之外,您还需要CMake文件,该文件描述如何将.pio和.c文件构建到适合加载到Raspberry Pi Pico开发板上的二进制文件中。

没有使用MicroPython编写的等效示例,但是我们可以看到一个更简单的PIO MicroPython代码,用于使板载LED闪烁:

从rp2导入时间,从PIO导入PIO,从机器导入,asm_pio导入Pin#定义闪烁程序。它有一个GPIO绑定到set指令上,该指令是一个输出引脚。#使用大量延迟以使眨眼可见。@ 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()#使用闪烁程序以1000Hz实例化状态机,并将其绑定到Pin(25)(rp2板上的LED)(sm = rp2) .StateMachine(0,闪烁,freq = 1000,set_base = Pin(25))#运行状态机3秒钟。 LED应该闪烁.sm.active(1)时间.sleep(3)sm.active(0)

#定义闪烁程序。它在set指令上有一个绑定到的GPIO,它是一个输出引脚。

#使用闪烁程序以1000Hz实例化状态机,并将其绑定到Pin(25)(rp2板上的LED)

在这种情况下,没有单独的.pio文件,并且MicroPython和汇编代码都放置在.py文件中。

请注意,即使可以使用MicroPython对PIO进行编程,但Python SDK文档指出该PIO当前不稳定/正在进行中,因此建议使用C / C ++。

通过在RGB十六进制格式的帮助下添加要显示的颜色,可以对代码进行许多修改。但是,有许多现实生活中的示例,例如PWM,UART甚至是NeoPixels接口。对于那些感兴趣的人,您可以在GitHub存储库中的C和MicroPython示例中找到许多PIO编程示例。

RP2040可编程IO具有同时执行程序以支持VGA输出和高速数据传输等接口的能力。您可以查看C / C ++和Python的SDK文档中的第3章,以了解有关RP2040可编程IO的更多信息。

Abhishek Jadhav是一名工程专业的学生,RISC-V大使,自由技术作家,开放硬件开发人员社区的负责人。