Implementation of Orangepi Zero register access and GPIO control in Python environment

Source: Internet
Author: User
Tags assert

Recently started Orangepi Zero piece, the program needs to use the board's own LED lights, on-line a check, have to say that OPI support and Raspberry Pi can not compare. Oneself groped for a moment, realizes the simple Gpio control method, the author's Zero installs is the Armbian system, uses the python to write a read and write registers the simple module, through this module, can realize to the Gpio control.

The author has previously used STM32 MCU, this kind of MCU, if you want to achieve the control of GPIO, only need to find the corresponding GPIO register according to datasheet and configure, can realize IO control, for example, To set all registers with memory address 0x12345678 to 0xFFFFFFFF, only one C statement is required:

1 (UInt32 *) (0x123456780xFFFFFFFF;

However, this method does not work in Linux, compile run time, will prompt "segmentation fault", this section error should be access to inaccessible memory, this memory area either does not exist, or is protected by the system. So you can only use other methods.

First of all, the implementation of the Orangepi Gpio control two methods, the first is through the Linux memory mapping, the actual CPU hardware memory address map to the user program memory space, and then operate; the second is to control the Gpio by Sysfs Way, in the program, Operation/ The Sys/class/gpio directory implements the control of the IO port.

Both methods have already completed cases, such as the PyH3 library used in the Python environment, and the WIRINGPI Library of the C environment, using the first method, and the second way from the Opi.gpio library that was transplanted from the Raspberry Pi. The second way to feel more simple, because only in the user's program to read and write the system directory files, can achieve the control of Gpio, very convenient, but the author found that this way there is a serious problem is that it can not use those on the board not cited on the IO port, Because the onboard two LEDs (red and green) are using the PA17 and PL10 pins respectively, if you control both pins using the second method, you will be prompted with "Device or resource Busy" error by the following command:

Cat /sys/kernel/debug/gpio

You can see that the system has occupied the following IO ports:

The first GPIO17 is PA17, which is configured as output mode by default and is set to low level. Here need to explain the system in the GPIO port numbering method, the system is in accordance with PA~PL a total of 12 groups, each group of 32 pins to the IO port unified number, such as, GPIO-0~GPIO-31 for PA port io,gpio-32~gpio-63 for PB port Io, And so on So the last line GPIO-362 is actually the PL10 pin, which is the green pin of the power supply.

Return to this article, because the second method cannot manipulate PA17, so only the first method can be used.

The first method already has a ready-made implementation, through in-depth research library source code, the internal actual is through C's mmap function to realize the CPU physical address mapping to the user program memory space. The author is accustomed to use Pyhon in the Linux environment to develop the program, pyH3 the use of the library feel more cumbersome. So it's a deliberate study of the ability to map physical addresses in a python environment. As expected, C has a mmap function, and Python also has a built-in mmap module. Description document here: https://docs.python.org/2/library/mmap.html

The most important of these is the constructor of the Mmap class:

class Mmap.mmap (Fileno, length[, flags[, prot[, access[, offset]])

Fileno: File descriptor, which can be the Fileno () method of the file object, or from Os.open (), open the file before calling Mmap (), and close when the file is no longer needed.

length: The Size (in bytes) of the portion of the file to be mapped, which is 0, the entire file is mapped, and if the size is larger than the file's current size, the file is extended.

flags: map_private: This memory map is available only for this process; mmap. Map_shared: The memory map is shared with other processes, and all processes that map the same file are able to see one of the changes made;
prot: mmap. Prot_read, Mmap. Prot_write and Mmap. Prot_write | Mmap. Prot_read. The last accesses than either meaning is both readable and writable.

Access: There are optional parameters in Mmap the value of access has

Access_read: Read access.

Access_write: Write access, default.

Access_copy: Copy access, do not write changes to file, use flush to write changes to

The Fileno parameter needs to be specified as a file descriptor for the system "/DEV/MEM", which can be obtained through the open () function and the Fileno () method, where the flags, prot, and access parameters are specified as read-write access.

The length and offset parameters are important, first the offset parameter, which indicates which memory address to start mapping, note that this value must be an integer multiple of the page size, in Orangepi zero, the page size is 4096 bytes. According to the memory address of Datasheet,gpio is starting from 0x01c200800, but this value is not an integer multiple of the page size, so can only be intercepted forward, the most recent page size integer times the address is 0x01c200000,offset is to be set to this value.

What about the 0x0800 offset? This is set by the length parameter, the length parameter specifies how many bytes of physical memory are mapped from this offset, and the memory space of the user program, obviously, This length must be long enough to map the entire GPIO module's register address, in order to normally access the GPIO register in the user program, which is set to two page size, that is 8192 bytes (0x01c20000 ~ 0x01c21fff), from Datasheet view, This address space contains all the registers of the CCU, PIO, TIMER, OWA, PWM, KEYADC modules.

After the mapping, we can get an object of the Mmap class, using this object, we can read and write the register as the operation file. In the code of the following modules, two methods are implemented: Read register and write register. Note that during the operation of the Register, it is important to note that each read and write register must be four-byte aligned, that is, read or write 4 bytes at a time (all registers are 32 bits), the Read and write register address must also be a multiple of 4, otherwise the operation will fail, the board will crash.

ImportmmapImportstructclassGPIO:#-------------------------------------------------------------------------------------##defines the offset address of a gpio relative to 0x01c20000Pio_addr_offset = 0x0800#defines the offset address of the GPIOA register relative to the 0x01c20000#The author writes only the GPIOA's register definition, and if you need to use other Io, refer to datasheet to add the definition belowPio_pa_cfg0_reg = Pio_addr_offset + 0x00Pio_pa_cfg1_reg= Pio_addr_offset + 0x04Pio_pa_cfg2_reg= Pio_addr_offset + 0x08Pio_pa_cfg3_reg= Pio_addr_offset + 0x0CPio_pa_data_reg= Pio_addr_offset + 0x10Pio_pa_drv0_reg= Pio_addr_offset + 0x14Pio_pa_drv1_reg= Pio_addr_offset + 0x18Pio_pa_pul0_reg= Pio_addr_offset + 0x1CPio_pa_pul1_reg= Pio_addr_offset + 0x20#-------------------------------------------------------------------------------------#    #the following are constructors and destructors    def __init__(self): Self.m_mmap=None SELF.FD=Nonedef __del__(self):if(Self.m_mmap! =None): Self.m_mmap.close ()if(SELF.FD! =None): Self.fd.close ()#-------------------------------------------------------------------------------------#    #The following are the member functions    defInit (self):"""The Gpio initialization function function opens the/dev/mem file and maps a total of 8192 bytes (2 pages) of memory space to the user's virtual address return value starting from the 0x01c20000 address: none"""start_addr= 0x01c20000SELF.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)assertSelf.m_mmap! = None,"Init fails"    defReadreg (self,reg_addr):"""read the value of a register REG_ADDR: register address to read (must be a multiple of 4), and range within 2 pagesize, i.e. less than 8192 return value: The value of the Register (4 bytes)"""        assertSelf.m_mmap! = None,"Init fails"        assertReg_addr%4 = = 0,"reg_addr must be mutiple of 4"        assert0<=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)        returnStruct.unpack ('L', Readbytes) [0]defWritereg (self,reg_addr,value):"""write the value of a register REG_ADDR: The register address to write (must be a multiple of 4), and within 2 pagesize, that is, less than 8192 value: The value to write, shaping, write a four-byte length integer at a time, i.e. 0xFF FFFFFF return value: None"""             assertSelf.m_mmap! = None,"Init fails"        assertReg_addr%4 = = 0,"reg_addr must be mutiple of 4"        assert0<=reg_addr<=8192,"reg_addr must be less than 8192,which is 2 pagesize"        assert0&LT;=VALUE&LT;=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

To use this module, only need to put the module's py file in the user program in the same directory, direct import can, the following is to make PA17 (red LED) flashing example.

Description

1, Opizero_gpio is the file name of the module defined above, directly import and use.

2, the Pio_pa_cfg2_reg register 4~ 7th bit is Pin17 mode configuration, the configuration is 001 namely the output mode

3, the 17th position of the Pio_pa_data_reg register is Pin17 high-level output control, here is a clever way to read the value of Pio_pa_data_reg and 0x00020000 bitwise XOR can achieve the 17th-bit inversion.

4, do not directly to the register to write data, because PA port has a lot of IO used for the internal use of the board, direct writing can easily lead to other IO port logic output error, causing the board to crash, the author has experienced n times, be sure to use the read-modify-write mode to modify the register value.

Import Opizero_gpio Import  Time # The following are the main programs GPIO = Opizero_gpio. Gpio () Gpio. Init (); # PA17 configured as output mode GPIO. Writereg (GPIO). Pio_pa_cfg2_reg,gpio. Readreg (GPIO). Pio_pa_cfg2_reg) | 0x00000010)while (1):    ^ 0x00020000)    time.sleep (0.3)

The actual results are as follows:

Finally, the source is attached:

Https://files.cnblogs.com/files/qzrzq1/OPiZero_GPIO.zip

Https://pan.baidu.com/s/1yiely1q_4LPZ4Bs8gyKDGg

Implementation of Orangepi Zero register access and GPIO control in Python environment

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.