Hongmeng OpenHarmony hi3516 development board, standard system button switch light

background

From HarmonyOS application development to OpenHarmony application development, it has been more than half a year. The northbound HelloWorld application has been written from JAVA to JS, and then to eTS. The development of northbound applications is not only proficient, but at least half-baked. Check the documentation and refer to the development samples, and you can still write an application slowly. However, the development of southbound equipment has been delayed and I don't know how to get started. So, recently, I finally made up my mind: starting from the HelloWorld of equipment development --- lighting, first on the OpenHarmony standard equipment, use the GPIO that comes with linux to light a light, take the first step, and then use HDF, NAPI and other capabilities , continue to explore southbound equipment development.

So, what I want to do this time is to use the standard system of the OpenHarmony3.0 LTS version to develop an application program, and realize the turning on and off of the light by clicking the button by calling the general GPIO driver that comes with linux. The development board I used this time is Runhe hi3516 dv300. The final effect is as follows:

What are GPIOs?

This problem, for students who are engaged in single-chip microcomputers and embedded systems, it is estimated that it will be solved on the first day. For our students who are engaged in software, they have rarely heard of it. In fact, I have never heard of it before. . .

GPIO, the English full name is General-Purpose IO ports, that is, general-purpose IO ports. Embedded systems often have a large number of external devices/circuits with relatively simple structures. Some of these devices/circuits require the CPU to provide control means, and some need to be used as input signals by the CPU. Also, many of these devices/circuits only require one bit, that is, only two states of on/off are sufficient, such as light on and off. For the control of these devices/circuits, it is not suitable to use traditional serial ports or parallel ports. Therefore, a "general programmable IO interface", namely GPIO, is generally provided on the microcontroller chip.

My personal understanding is that devices such as single-chip microcomputers can control GPIO by directly operating registers or functions provided by the manufacturer, while Linux embedded devices can use Linux's own general GPIO driver to control GPIO, or self-written driver . On top of this, OpenHarmony encapsulates a layer of HDF. Through the encapsulation of HDF, it can adapt to different operating systems to control GPIO.

GPIO port of Runhe hi3516dv300 buttons and lights

This information can be obtained from the schematic :

  • You can see that the GPIO ports of the two custom buttons are: GPIO0_1, GPIO0_2

  • The GPIO ports of the three LEDs are: the red LED of the core board is connected to GPIO3_4, the green LED indicator is connected to GPIO2_3, and the red LED of the uppermost board is connected to GPIO5_1

Use linux's built-in general GPIO driver to turn on and off the lights

From the document , I learned that Hi3516DV300 has a controller to manage 12 groups of GPIO pins, each group has 8 pins.

GPIO number = GPIO group index (0~11) * number of GPIO pins per group (8) + offset within the group

Example: GPIO number of GPIO10_3 = 10 * 8 + 3 = 83

So, button

GPIO0_1 = 0 * 8 + 1 = 1

GPIO0_2 = 0 * 8 + 2 = 2

three lights

GPIO5_1 = 5 * 8 + 1;

GPIO2_3 = 2 * 8 + 3;

GPIO3_4 = 3 * 8 + 4;

So by learning how to operate GPIO in Linux , I learned that you can use the form of echo to control GPIO through the general GPIO driver that comes with linux. So, we can directly connect to the development board through the serial port of hiTools, and use the following command to turn on the red light:

/sys/class/gpio# echo 41 > export      # 设置红灯GPIO口为导出
/sys/class/gpio/gpio41# echo out > direction  # 设置红灯GPIO口为输出
/sys/class/gpio/gpio41# echo 1 > value  # 设置红灯GPIO口为1

by code

It is implemented through code, which is to call the general GPIO driver that comes with linux in the form of a file.

In addition, for buttons, you need to use poll to monitor file changes and respond to GPIO interrupts

​
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<poll.h>
​
​
#define MSG(args...) printf(args) 
 
//函数声明
static int gpio_export(int pin);
static int gpio_unexport(int pin);
static int gpio_direction(int pin, int dir);
static int gpio_write(int pin, int value);
static int gpio_read(int pin);
static int gpio_edge(int pin, int edge);
​
​
​
static int gpio_export(int pin)  
{  
    char buffer[64];  
    int len;  
    int fd;  
  
    fd = open("/sys/class/gpio/export", O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open export for writing!\n");  
        return(-1);  
    }  
  
    len = snprintf(buffer, sizeof(buffer), "%d", pin);  
    printf("%s,%d,%d\n",buffer,sizeof(buffer),len);
    if (write(fd, buffer, len) < 0) 
    {  
        MSG("Failed to export gpio!");  
        return -1;  
    }  
     
    close(fd);  
    return 0;  
}  
static int gpio_unexport(int pin)  
{  
    char buffer[64];  
    int len;  
    int fd;  
  
    fd = open("/sys/class/gpio/unexport", O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open unexport for writing!\n");  
        return -1;  
    }  
  
    len = snprintf(buffer, sizeof(buffer), "%d", pin);  
    if (write(fd, buffer, len) < 0) 
    {  
        MSG("Failed to unexport gpio!");  
        return -1;  
    }  
     
    close(fd);  
    return 0;  
} 
//dir: 0-->IN, 1-->OUT
static int gpio_direction(int pin, int dir)  
{  
    static const char dir_str[] = "in\0out";  
    char path[64];  
    int fd;  
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin);  
    fd = open(path, O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio direction for writing!\n");  
        return -1;  
    }  
  
    if (write(fd, &dir_str[dir == 0 ? 0 : 3], dir == 0 ? 2 : 3) < 0) 
    {  
        MSG("Failed to set direction!\n");  
        return -1;  
    }  
  
    close(fd);  
    return 0;  
}  
//value: 0-->LOW, 1-->HIGH
static int gpio_write(int pin, int value)  
{  
    static const char values_str[] = "01";  
    char path[64];  
    int fd;  
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);  
    fd = open(path, O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio value for writing!\n");  
        return -1;  
    }  
  
    if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0) 
    {  
        MSG("Failed to write value!\n");  
        return -1;  
    }  
  
    close(fd);  
    return 0;  
}
static int gpio_read(int pin)  
{  
    char path[64];  
    char value_str[3];  
    int fd;  
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);  
    fd = open(path, O_RDONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio value for reading!\n");  
        return -1;  
    }  
  
    if (read(fd, value_str, 3) < 0)
    {  
        MSG("Failed to read value!\n");  
        return -1;  
    }  
  
    close(fd);  
    return (atoi(value_str));
}  
// none表示引脚为输入,不是中断引脚
// rising表示引脚为中断输入,上升沿触发
// falling表示引脚为中断输入,下降沿触发
// both表示引脚为中断输入,边沿触发
// 0-->none, 1-->rising, 2-->falling, 3-->both
static int gpio_edge(int pin, int edge)
{
const char dir_str[] = "none\0rising\0falling\0both"; 
int ptr;
char path[64];  
    int fd; 
switch(edge)
{
    case 0:
        ptr = 0;
        break;
    case 1:
        ptr = 5;
        break;
    case 2:
        ptr = 12;
        break;
    case 3:
        ptr = 20;
        break;
    default:
        ptr = 0;
} 
  
    snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", pin);  
    fd = open(path, O_WRONLY);  
    if (fd < 0) 
    {  
        MSG("Failed to open gpio edge for writing!\n");  
        return -1;  
    }  
  
    if (write(fd, &dir_str[ptr], strlen(&dir_str[ptr])) < 0) 
    {  
        MSG("Failed to set edge!\n");  
        return -1;  
    }  
  
    close(fd);  
    return 0;  
}
​
​
int main()  
{  
    int gpio_fd, ret;
    struct pollfd fds[1];
    char buff[10];
    //41为红灯, 1为1号按键
 
    gpio_unexport(41);
    gpio_unexport(1);
 
    
    //41红灯亮起
    gpio_export(41);
    gpio_direction(41, 1);//output out
    gpio_write(41, 1);
    
    //1按钮初始化
    gpio_export(1);
    gpio_direction(1, 0);//input in
    gpio_edge(1,2);
    gpio_fd = open("/sys/class/gpio/gpio1/value",O_RDONLY);
    if(gpio_fd < 0)
    {
        MSG("Failed to open value!\n");  
        return -1;  
    }
    fds[0].fd = gpio_fd;
    fds[0].events  = POLLPRI;
    
    while(1)
    {
​
        ret = poll(fds,1,5000);
        if( ret == -1 )
        MSG("poll\n");
        if( fds[0].revents & POLLPRI)
        {
            ret = lseek(gpio_fd,0,SEEK_SET);
            if( ret == -1 )
            MSG("lseek\n");
​
             ret = read(gpio_fd,buff,10);//读取按钮值,但这里没使用
            if( ret == -1 )
            MSG("read\n");
​
            //切换红灯
            int status = gpio_read(41);
            printf("41 = %d\n",status);
            gpio_write(41, 1 - status);
    
        
            //gpio_write(44, cnt++%2);
            printf("**********************************\n");
        }
        printf("one loop\n");
        //usleep(5);
    }
    return 0;
}
​

Burn the above program into the standard system image

Step 1: Download the OpenHarmony 3.0LTS version, compile and burn the standard image

You can refer to my previous article

Step 2: Write the above program

Create a new one and save it in applications/standard/app/hello.c

Step 3: Create BUILD.gn in the same directory as hello.c

import("//build/ohos.gni")
import("//drivers/adapter/uhdf2/uhdf.gni")

ohos_executable("hello") {
  sources = [
    "hello.c"
  ]
  subsystem_name = "applications"
  part_name = "prebuilt_hap"
}

Step 4: Modify applications\standard\hap\ohos.build

Add "//applications/standard/app:hello" in module_list

Step 5: Recompile and burn, please refer to step 1

./build.sh --product-name Hi3516DV300 --ccache

Step 6: Use the serial port connection to execute hello in the bin directory

cd bin
./hello

Then you can click button 1 to turn on and off the led red light

Quick debugging method

When writing and modifying hello.c, I don’t want to re-burn the image every time. At present, I only find the following methods to quickly compile and burn

Step 1: Add --ccache parameter incremental compilation (it is not necessary to make a separate makefile)

./build.sh --product-name Hi3516DV300 --ccache

Step 2: In the out directory, find the hello file through find and copy it to the local (windows)

Step 3: Update the hello program separately using hdc_std

hdc_std file send 本地路径\hello /data/

Note: By default, files can only be uploaded in the data directory. If you need to put them in other directories like bin, you can use

hdc_std smode # 授予后台服务进程root权限

or

mount -oremount,rw  /       # 更改文件系统的读写权限

There are still many things to be verified in the near future, one step at a time

  • Try small system to control GPIO

  • Try to control GPIO with HDF

  • Try to extend NAPI to control GPIO from the application side

source code

https://gitee.com/42690727/my-open-harmony-sample/tree/master/%E6%A0%87%E5%87%86%E8%AE%BE%E5%A4%87/3.1%20Beta/gpio%E7%82%B9%E7%81%AF

Guess you like

Origin blog.csdn.net/sd2131512/article/details/122114540