前言

本来这篇文章应该在上周就写完的,不过突然被安排出差,一直忙到了现在,终于可以静下心来做些其它事情。

之前和龙芯3A5000主机一起送过来的还有一块龙芯2K500的迷你开发板,整个板子不到巴掌大小。之前只是简单做了上电启动,这次拿到了比较完整的开发资料,可以尝试为开发板编写一些程序了。

由于暂时没有屏幕,只能先试着做一些其它的事情,如通信和IO控制,其中最简单,最基础的就是LED灯的控制。然后我就发现,这个板子居然有一颗可以调节亮度的LED灯!没错,之前做的LED控制都只能进行开关操作,而可以调节亮度,意味着可以做出更多的显示效果,这次我就做了一个呼吸灯的效果。

然后,我也简单了解了一下这种亮度调节的原理,实际上就是通过调节PWM输出的占空比,改变一个周期内输出的高低电平所占的比例,实现控制LED灯亮度的效果。由于引脚输出的电压是固定的,所以不能通过改变电平来控制亮度,而改变高低电平的占空比则是另一种思路,嵌入式设备的屏幕背光亮度调节也是基于同样的原理。

开发板上电启动、连接串口终端

由于暂时没有屏幕,想要和开发板进行交互就只能通过终端的方式,通常开发板都会有调试串口,我们先通过串口终端登录设备,配置好网口IP地址后,再通过网络连接登录设备。

串口的连接方式如下图:

将绿、白、黑三色线以图中方式接好(红线不用接),USB端插入到电脑,应该不需要装驱动,电脑可以直接识别出串口设备。

打开串口终端工具,比如Windows MobaXterm,linux minicom等,我比较喜欢用putty。

配置好端口,设置
波特率:115200
数据位:8位
停止位:1位
校验:无
硬件流控:无

然后给开发板接通电源,就可以看到调试输出信息了。

查看系统信息,可以看到运行的是安装了PREEMPT_RT补丁的实时操作系统。

1
2
3
[root@LS-GD ~]# uname -a
Linux LS-GD 5.10.0.lsgd-g434b00a6badf #1 PREEMPT Wed Sep 14 12:57:58 CST 2022 loongarch64 GNU/Linux
[root@LS-GD ~]# 

配置交叉编译环境

2K500开发板是loongarch64架构的嵌入式板卡。下载好对应的交叉编译工具链后,解压到系统/opt/目录下。按手册来就好~

1
$ sudo tar -xf toolchain-loongarch64-linux-gnu-gcc8-host-x86_64-2022-07-18.tar.xz -C /opt/

然后我们需要将交叉编译器添加到系统路径,方便我们接下来使用。

这里我直接将配置写成脚本,方便下次使用。

1
2
3
4
5
6
7
8
$ cd /opt/toolchain-loongarch64-linux-gnu-gcc8-host-x86_64-2022-07-18
# 创建脚本
$ sudo touch environment-setup-loongarch64-linux-gnu
# 添加可执行权限
$ sudo chmod +x environment-setup-loongarch64-linux-gnu
# 修改脚本内容
$ sudo vi environment-setup-loongarch64-linux-gnu
# 内容如下~
1
2
3
4
5
6
7
8
# environment-setup-loongarch64-linux-gnu
CC_PREFIX=/opt/toolchain-loongarch64-linux-gnu-gcc8-host-x86_64-2022-07-18
export PATH=$CC_PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$CC_PREFIX/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$CC_PREFIX/loongarch64-linux-gnu/lib64:$LD_LIBRARY_PATH

export ARCH=loongarch
export CROSS_COMPILE=loongarch64-linux-gnu-

接下来测试一下交叉编译环境

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ cd ~
$ . /opt/toolchain-loongarch64-linux-gnu-gcc8-host-x86_64-2022-07-18/environment-setup-loongarch64-linux-gnu
$ loongarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=loongarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/opt/toolchain-loongarch64-linux-gnu-gcc8-host-x86_64-2022-07-18/bin/../libexec/gcc/loongarch64-linux-gnu/8.3.0/lto-wrapper
Target: loongarch64-linux-gnu
Configured with: /dev/shm/build_loongarch64_gcc8-host-x86_64_2022-07-18/src/gcc/configure --build=x86_64-redhat-linux --host=x86_64-redhat-linux --target=loongarch64-linux-gnu --program-prefix=loongarch64-linux-gnu- --prefix=/dev/shm/build_loongarch64_gcc8-host-x86_64_2022-07-18/cross --libdir=/dev/shm/build_loongarch64_gcc8-host-x86_64_2022-07-18/cross/lib --with-gxx-include-dir=/dev/shm/build_loongarch64_gcc8-host-x86_64_2022-07-18/cross/sysroot/usr/include/c++ --with-sysroot=/dev/shm/build_loongarch64_gcc8-host-x86_64_2022-07-18/cross/sysroot --with-native-system-header-dir=/usr/include --with-arch=loongarch64 --with-abi=lp64 --with-multilib-list=lp64d,lp64s --with-pkgversion='LoongArch\ GNU\ toolchain\ vec.32-rc2' --disable-linker-build-id --with-newlib --without-headers --disable-shared --enable-threads=posix --enable-tls --enable-languages=c,c++,fortran --enable-__cxa_atexit --enable-libquadmath-support --disable-gcov --disable-libcc1 --enable-initfini-array --disable-nls --disable-bootstrap --with-glibc-version=2.28
Thread model: posix
gcc version 8.3.0 (LoongArch GNU toolchain vec.32-rc2)

可以看到loongarch交叉编译器的版本信息,配置交叉编译环境完成。

编写程序

控制LED灯的亮度,Linux系统已经有驱动实现了,我们要做的操作就是向相应的文件中写入数值即可,剩下的都是系统的事情。

对于一般的LED灯,只有开关两个选项,写入0为关闭,写入非0值打开。

而对于PWM控制的LED灯,需要写入具体数值来控制灯的亮度,同样,0为关闭,写入数值越大LED灯就越亮,当然,这是有上限的。这里经过测试,写入255后,LED灯达到最亮。

而这次写的呼吸灯程序,则是逐渐改变LED灯的亮度,实现LED灯缓慢闪烁的效果。
这里我将亮度分为10个级别,从0255(2^8 - 1),每100ms改变一下LED灯的亮度,一个周期刚好为2秒(从灭到最亮,然后从最亮到灭)。

至于为什么是分为这10个级别,而不是从0~255变化,大家可以自己试试,看一下效果。

以下是完整程序:

 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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
 * file: led-pwm.c
 */

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/**
 * @brief 呼吸灯效果
 * @param fd 设备文件
 */
void breath(int fd);

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        printf("Please input LED device.\n");
        return -1;
    }

    int fd;
    char file[64];
    sprintf(file, "%s/brightness", argv[1]);

    /* 打开设备文件 */
    fd = open(file, O_WRONLY);
    if (fd < 0)
    {
        printf("Error open file: %s\n", file);
        return fd;
    }

    breath(fd);
    /* 关闭设备文件 */
    close(fd);
    return 0;
}

void breath(int fd)
{
    const int values[15] = { 0, 1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 255, 255 };
    char buf[5];

    while (1)
    {
        for (int i = 0; i < 30; i++)
        {
            int j = i < 15 ? i : (29 - i);
            sprintf(buf, "%d", values[j]);
            write(fd, buf, sizeof(buf));
            usleep(100000);  // 休眠100ms
        }
    }
}

然后编译,得到在开发板上运行可执行程序。

1
$ loongarch64-linux-gnu-gcc led-pwm.c -o led-pwm

下载程序到开发板

运行前的最后一步,需要将编译好可执行程序复制到开发板上,我通常是使用scp命令将文件复制到开发板。

需要先在串口终端通过ifconfig设置开发板的网口IP,第一次使用scp前,需要先用ssh登录到开发板。

系统默认账户为root,默认密码为123

由于之前不知道默认密码是什么,所以先用passwd命令改了密码😅。

1
2
3
4
5
6
7
8
# 例:将可执行程序复制到开发板
$ scp ./led-pwm root@192.168.0.10:~/
# 使用 ssh 登录开发板
$ ssh root@192.168.0.10
# 为程序添加可执行权限(在开发板操作)
~ $ chmod +x ./led-pwm
# 运行程序
~ $ ./led-pwm /sys/class/leds/led1-pwm

实际运行效果

由于开发板的LED2默认是心跳模式[heartbeat],所以会一直一闪一闪的,在运行呼吸灯程序前,可以先把LED2改为[none]模式。

1
~ $ echo none > /sys/class/leds/led2/trigger

执行编写的呼吸灯程序

1
~ $ ./led-pwm /sys/class/leds/led1-pwm

实际运行效果如下: