Orange pi GPIO output control, bare metal lighting Dafa (1)!

Bare metal lighting method

Wouldn't it be incomplete to play with Raspberry Pi or Orange Pi without playing bare metal lighting. The so-called bare metal lighting, that is, a bare board, through the gpio output control, realizes the control of the green power indicator light and the red status indicator light on the board

Two methods of bare metal lighting (GPIO output control)

Firstly, summarize the two methods to control OrangePi GPIO. The first is to map the memory address of the actual CPU hardware to the memory space of the user program through Linux memory mapping, and then operate; the second is to control GPIO through sysfs. In the program, operate the /sys/class/gpio directory to realize the control of the io port.

Both methods have ready-made completed cases. For example, the pyH3 library used in the python environment and the WiringPi library in the C environment use the first method; the OPi.GPIO library ported from the Raspberry Pi uses the second method. The second way is easier for me personally, because you only need to read and write the files in the system directory in the user program to realize the control of GPIO, which is very convenient, but after testing, it is found that this way has a serious problem on the armbian system, that is, it cannot use the IO ports that are not drawn out on the board, because the two LEDs (red and green) on the board use the PA17 and PL10 pins respectively. If you use the second way to control these two pins, it will prompt "Device or resource busy" error, but in or Both the ubuntu image provided by the angpi official website and Debian can be perfectly implemented . Through the following command:

cat /sys/kernel/debug/gpio

It can be seen that the IO ports already occupied by the system are as follows:
insert image description here

The second method

In fact, there is a general GPIO operation interface under Linux, which is the "/sys/class/gpio" method I want to introduce.

Although my system is armbian, I can’t use the second method. Let’s briefly talk about the second operation. If you are on armbian system like me, you can skip to the next section and see another method.

From the picture above, we can see that the gpio number of powerLED is 362, and the number of statusLED is 17. Next, let’s see if there is a "/sys/class/gpio" folder in the system. If not, you need to add Device Drivers when compiling the kernel —> GPIO Support —> /sys/class/gpio/… (sysfs interface
)

I have tried armbian system, ubuntu system and Debian all have this folder, then you can directly operate it. Take a
look at the instructions of /sys/class/gpio:

1、gpio_operation 通过/sys/文件接口操作IO端口 GPIO到文件系统的映射;
2、控制GPIO的目录位于/sys/class/gpio;
3、 /sys/class/gpio/export文件用于通知系统需要导出控制的GPIO引脚编号;
4、/sys/class/gpio/unexport 用于通知系统取消导出;
5、/sys/class/gpio/gpiochipX目录保存系统中GPIO寄存器的信息,包括每个寄存器控制引脚的起始编号base,寄存器名称,引脚总数 导出一个引脚的操作步骤;
6、首先计算此引脚编号,引脚编号 = 控制引脚的寄存器基数 + 控制引脚寄存器位数;
7、向/sys/class/gpio/export写入此编号,比如12号引脚,在shell中可以通过以下命令实现,命令成功后生成/sys/class/gpio/gpio12目录,如果没有出现相应的目录,说明此引脚不可导出:echo 12 > /sys/class/gpio/export;
8、direction文件,定义输入输入方向,可以通过下面命令定义为输出;
9、echo out > direction, direction接受的参数:in, out, high, low。high/low同时设置方向为输出,并将value设置为相应的1/0;
10、value文件是端口的数值,为1或0.echo 1 > value

Type the following command in the terminal

cd /sys/class/gpio/

ls to see if there is a directory of gpio362 or gpio17, normally there is not.
Next, GPIO control test, type the following command in the terminal

通知系统需要导出控制的GPIO引脚编号为17
echo 17 > /sys/class/gpio/export
定义输入输入方向为输出
echo out > /sys/class/gpio/gpio139/direction
设置17号引脚的数值为1,即输出高电平,灯亮
echo 1 > /sys/class/gpio/gpio139/value
设置17号引脚的数值为0,即输出低电平,灯灭
echo 0 > /sys/class/gpio/gpio139/value

The control of powerLED is the same, just change 17 to 362. It should be noted
that if you are an armbian system, you will be prompted that the device is busy when you export pin 17. It is normal under ubuntu and Debian. This has been mentioned before.

insert image description here

the first method

I am referring to the blog of this great god. I don’t know if it is his original work. Attach the link: Realize OrangePi Zero register access and GPIO control in the python environment.
The author speaks in great detail. Post his code here.

root@orangepi:~# vim OPiZero_GPIO.py

import mmap
import struct
class GPIO:   
#-------------------------------------------------------------------------------------#
#定义GPIO相对0x01C20000的偏移地址
    PIO_ADDR_OFFSET = 0x0800    
#定义GPIOA的寄存器相对0x01C20000的偏移地址
#作者只写了GPIOA的寄存器定义,如果需要使用其他IO,请参考datasheet在下面增加定义
    PIO_PA_CFG0_REG = PIO_ADDR_OFFSET + 0x00
    PIO_PA_CFG1_REG = PIO_ADDR_OFFSET + 0x04
    PIO_PA_CFG2_REG = PIO_ADDR_OFFSET + 0x08
    PIO_PA_CFG3_REG = PIO_ADDR_OFFSET + 0x0C
    PIO_PA_DATA_REG = PIO_ADDR_OFFSET + 0x10

    PIO_PA_DRV0_REG = PIO_ADDR_OFFSET + 0x14
    PIO_PA_DRV1_REG = PIO_ADDR_OFFSET + 0x18
    PIO_PA_PUL0_REG = PIO_ADDR_OFFSET + 0x1C
    PIO_PA_PUL1_REG = PIO_ADDR_OFFSET + 0x20

#-------------------------------------------------------------------------------------#
    #以下是构造函数和析构函数
    def __init__(self):
        self.m_mmap = None
        self.fd = None

    def __del__(self):
        if(self.m_mmap != None):
            self.m_mmap.close()
        if(self.fd != None):
            self.fd.close()
    
#-------------------------------------------------------------------------------------#
    #以下是成员函数
    def Init(self):
        """
        GPIO初始化函数
        函数会打开/dev/mem文件,并映射从0x01C20000地址开始,共8192字节长度(2页)的内存空间到用户的虚拟地址
        返回值:无
        """
        START_ADDR = 0x01C20000
        self.fd = open("/dev/mem", "rb+")
        self.m_mmap = mmap.mmap(self.fd.fileno(), 4096 * 2, mmap.MAP_SHARED, mmap.PROT_WRITE | mmap.PROT_READ, mmap.ACCESS_WRITE, START_ADDR)
        assert self.m_mmap != None,"Init Fails"

    def ReadReg(self,reg_addr):
        """
        读取一个寄存器的值
        reg_addr:要读取的寄存器地址(必须为4的倍数),且范围在2个pagesize内,即小于8192
        返回值:寄存器的值(4字节)
        """
        assert self.m_mmap != None,"Init Fails"
        assert reg_addr%4 == 0,"reg_addr must be mutiple of 4"
        assert 0<=reg_addr<=8192,"reg_addr must be less than 8192,which is 2 pagesize"
        
        self.m_mmap.seek(reg_addr)
        ReadBytes = self.m_mmap.read(4)
        return struct.unpack('L',ReadBytes)[0]

    def WriteReg(self,reg_addr,value):
        """
        写一个寄存器的值
        reg_addr:要写入的寄存器地址(必须为4的倍数),且范围在2个pagesize内,即小于8192
        value:要写入的值,整形,一次写入四个字节长度的整数,即0xffffffff
        返回值:无
        """     
        assert self.m_mmap != None,"Init Fails"
        assert reg_addr%4 == 0,"reg_addr must be mutiple of 4"
        assert 0<=reg_addr<=8192,"reg_addr must be less than 8192,which is 2 pagesize"
        assert 0<=value<=0xFFFFFFFF,"value must be less than 0xFFFFFFFF,which is 4 bytes"
        
        self.m_mmap.seek(reg_addr)
        BytesToWrite = struct.pack('L',value)
        self.m_mmap.write(BytesToWrite)
        return
root@orangepi:~# vim LED_Blink.py

import OPiZero_GPIO
import time

#以下为主程序
GPIO = OPiZero_GPIO.GPIO()
GPIO.Init();

#PA17配置为输出模式
GPIO.WriteReg(GPIO.PIO_PA_CFG2_REG,GPIO.ReadReg(GPIO.PIO_PA_CFG2_REG) | 0x00000010)
while(1):
    GPIO.WriteReg(GPIO.PIO_PA_DATA_REG,GPIO.ReadReg(GPIO.PIO_PA_DATA_REG) ^ 0x00020000)
    time.sleep(0.3)

Run the program and you can see that the LED on the board is flashing

root@orangepi:~# python3 LED_Blink.py 

Guess you like

Origin blog.csdn.net/Running_free/article/details/103060934