• 【Luckfox pico入门记录(一)】开发环境与工具链


    写在前面

      最近刷bilibili发现微雪电子关于luckyfox pico的介绍视频,感叹linux开发板居然可以把价格缩到100RMB以内,也正巧结束了复旦微比赛,受够了FM33LC046N的低性能,来玩点便宜又高性能的板子。
      开发板型号:luckfox pico max
      开发环境:Ubuntu 22.04
      参考:luckyfox pico官方WIKI微雪bilibili视频
      我的luckfox-pico的github仓库在这里,这边简单记录一下git的使用教程。

    首先在github官网新建一个repository,
    在这里插入图片描述
    然后git clone注意用ssh的,因为http的话虚拟机代理会有问题,经常连不上,但是使用ssh需要添加一个ssh key,否则会clone失败,教程在这里[git初始化与ssh秘钥生成]
    添加完毕秘钥之后我们就可以git clone,git add, git commit, git push愉快4连了。


    一、环境搭建,输出hello world

      开发环境的搭建主要是根据官方WIKI的上手教程来进行,
    在这里插入图片描述

      因为max是新出的,这里暂时只有标准版和plus的教程,我们按照plus的来就可以。虽然SPI NAND FLASH中已经有出厂镜像了,但是实测发现出厂烧录的镜像可能有问题,因此需要手动进行镜像烧录。

    这里踩了一些坑,出厂自带的sys/class/pwm下是空的,于是我打算要要么再烧录一遍官方的文件,要么自己编译。由于烧录官方文件更加省时,所以优先考虑。

    当然,我其实也尝试编译过镜像,并浅浅记一下踩坑.
    问题1】编译镜像的过程中出现了python找不到的情况,为其添加了软连接.在这里插入图片描述
    问题2】编译完毕需要通过共享文件夹传输文件,发现共享文件系统又坏了
    这篇文章修好了vmware的共享文件夹问题
    问题3】编译完的镜像传输到windows平台下会导致软链接失效,需要手动重命名一下。

    镜像烧录(使用官方提供的镜像)

      首先,下载官方的镜像和烧录工具,如下图所示
    在这里插入图片描述
      按照官方教程来就可以了

    问题】下载过程中可能因为连接问题导致固件下载失败,反复尝试多次下载即可。
    在这里插入图片描述

    搭建虚拟机开发环境

      我们直接接上type-c USB进行ADB连接。WIKI中已经介绍过windows系统下ADB的使用了,因为开发都是在linux中的,所以这里直接介绍linux下的adb连接。
      初学者可以按照教程用他给的镜像,但是这里我们头铁,我们要学会嵌入式的通用开发方式。打开我的虚拟机VMware,系统是ubuntu22.04,这里不一样都没关系,下面我们开始!

       安装相关依赖

    sudo apt-get install repo git ssh make gcc gcc-multilib g++-multilib module-assistant expect g++ gawk texinfo libssl-dev bison flex fakeroot cmake unzip gperf autoconf device-tree-compiler libncurses5-dev pkg-config
    
    • 1

       安装adb工具:

    sudo apt install adb
    
    • 1

       克隆官方git

    git clone https://github.com/LuckfoxTECH/luckfox-pico.git
    
    • 1

    在这里插入图片描述
      激活交叉工具链环境变量,第一次执行如果报错,再重新执行一遍source即可

    cd tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/
    source env_install_toolchain.sh
    
    • 1
    • 2

      激活之后我们就可以写一个简单的C程序,

    #include
    int main(){
        printf("hello world\n");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

      对其进行编译

    arm-rockchip830-linux-uclibcgnueabihf-gcc aaa.c aaa.o
    
    • 1

      编译好后的文件我们使用adb发送到开发板上,首先输入

    adb connect 172.32.0.93 
    
    • 1

    完成adb连接,这里需要注意,在windows下adb工具可以不指定端口号,这里需要指定端口号,这和具体的adb工具有关。
    除此之外,需要注意启动后过一阵子再连接,这和树莓派是一个道理,机子需要启动时间,否则会连不上。
    在这里插入图片描述

      然后登陆到开发板。
    在这里插入图片描述

      接着另外启动一个窗口,通过adb把交叉编译好的文件发送过去,语法如下
    在这里插入图片描述
    在这里插入图片描述

      然后我们再查看开发板上的文件,发现多了一个aaa.o,并运行它
    在这里插入图片描述
    注意:从知乎老哥那里学来的,传来的可执行文件要chmod 777 ./yourfile,这样添加权限避免一些隐形故障

      为了方便开发,我添加了这些alias,因为没有系统学过shell,所以这个搞了我一晚上,比较笨哈哈,将这个存成bootenv在根目录下,source bootenv就可以直接使用里面的alias了,比如打开luckfox就可以直接用luckfox_openshell命令了,多方便!

    alias g='gvim'
    export LUCKFOX_IP=172.32.0.93:5555
    alias luckfox_connect='adb connect $LUCKFOX_IP'
    alias luckfox_openshell='adb -s $LUCKFOX_IP shell'
    alias luckfox_push='push_func'
    push_func(){
    adb -s $LUCKFOX_IP push $1 /
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    二、GPIO使用

      使用gpio之前需要提一下gpio的编号,因为在开发板的linux系统中,gpio通过编号进行索引

    GPIO有5个bank,每个bank32个pin;
    每个bank又可以分为ABCD四组,每组8个pin

      因此,对于GPIO1_C7_d,编号=1*32+8*2+7=55. 后面那个小d是后缀
      根据引脚示意图,我们可以查到gpio55的位置,我们接上LED灯和电阻
    在这里插入图片描述
    在这里插入图片描述

    2.1 shell控制GPIO

      我们首先尝试使用在shell内直接更改GPIO设备文件的方法
      导出gpio55到用户空间

    echo 55 > /sys/class/gpio/export
    
    • 1

      读取 GPIO1_C7_d 引脚电平

    echo 55 > /sys/class/gpio/export         
    echo in > /sys/class/gpio/gpio55/direction 
    cat /sys/class/gpio/gpio55/value       
    
    • 1
    • 2
    • 3

      输出 GPIO1_C7_d 引脚电平,可以观测到led的变化

    echo out > /sys/class/gpio/gpio55/direction 
    echo 1 > /sys/class/gpio/gpio55/value       
    echo 0 > /sys/class/gpio/gpio55/value    
    
    • 1
    • 2
    • 3

    2.2 C语言系统调用控制GPIO

      当然,更常用的办法是使用C语言通过系统调用的方式修改设备文件,实现对GPIO的控制。

    #include 
    #include 
    #include 
    
    int main(){
        int gpio_pin;
    
        printf("Enter GPIO pin number:");
        scanf("%d",&gpio_pin);
        //export gpio to user
        FILE *export_file = fopen("/sys/class/gpio/export","w");
        if(export_file == NULL){
        	perror("Failed to open GPIO export file");
    	return -1;
        }
        fprintf(export_file,"%d",gpio_pin);
        fclose(export_file);
        
        //get the direction_path
        char direction_path[50];
        snprintf(direction_path,sizeof(direction_path),"sys/class/gpio/gpio%d/direction",gpio_pin);//get the format char
        //specify the pin direction
        FILE *direction_file = fopen(direction_path,"w");
        if (direction_file == NULL){
            perror("Failed to open GPUI direction file");
    	return -1;
        }
        fprintf(direction_file,"out");
        fclose(direction_file);
    
        char value_path[50];
        snprintf(value_path,sizeof(value_path),"sys/class/gpio/gpio%d/value",gpio_pin);
        FILE *value_file = fopen(value_path,"w");
        if(value_file == NULL){
            perror("Failed to open GPIO value file");
    	return -1;
        }
        
        for(int i=0; i<300; i++){
            fprintf(value_file,"1");
            fflush(value_file);
    	sleep(1);
    
            fprintf(value_file,"0");
            fflush(value_file);
    	sleep(1);
    
        }
    
        fclose(value_file);
        return 0;
    }
    
    
    • 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

      使用交叉编译工具链进行编译,然后通过adb传输到开发板上运行即可,过程跟上一节一样这里就不赘述了,可以观察到LED的闪烁。
      用到的重要的函数需要解释一下:

    fflush(File_ptr)//这个函数用来刷新缓冲区
    snprintf()//这个函数用来把带格式控制的字符串转变成普通字符串
    
    • 1
    • 2

    三、PWM的使用

    这里也是按照教程的方法进行操作就可以了,不再过多赘述,用示波器可以抓到波形
    在这里插入图片描述

    关于PWM的一些问题

    本来买这个rockchipRV1106是看中它性能更高更好地驱动FOC的,但是一来Linux系统不是实时系统,二来虽然我观察源码也暂时不能知道如何调节中央对齐PWM输出,我也不好修改设备树和源码,这样太麻烦。如果使用裸机编程的话,没有寄存器和详细的datasheet,只能根据linux kernel源码来判断地址寄存器功能。所以用RV1106直接驱动FOC PWM的想法暂时搁置。但是看源码中确实是有PWM中央对齐的选项的,应当有机会修改源码。
    在这里插入图片描述
    因此,对于FOC控制,我准备把计算部分放在rockchip上,下级MCU(例如复旦微开发板)上仅仅执行简单的定时、uart中断和pwm更新输出,两者用Uart通讯

    四、UART的使用

    shell命令控制UART

    主要就是配置串口波特率,然后给/dev/ttyS3 echo内容就能通讯了。参考WIKI上的教程即可
    在这里插入图片描述

    C语言系统调用控制UART

      继续照抄wiki参考即可,但需要注意,wiki中scanf的书写有误,需要改一下

    五、ADC的使用

      照抄WIKI即可

    六、I2C的使用(结合AS5600)

      血的教训,我把GND和VCC接错了,导致AS5600烧了,幸好我AS5600多嘻嘻,并且RV1106没被烧,万幸。
      有关AS5600的I2C协议和时序图介绍见这篇

    shell命令控制i2c

      将luckfox-pico的I2C 3接口接到AS5600或者其他设备上,并输入

    i2cdetect -y -a 3
    
    • 1

    在这里插入图片描述
    发现可以detect到0x36地址的设备AS5600
    有关i2c tool的使用可以见这篇

    C语言控制i2c

    这里是参考官方WIKI和对AS5600的特性自己写的

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define I2C_DEVICE_PATH "/dev/i2c-3"
    #define AS5600_ADDR 0x36
    #define LOW_DATA_ADDR 0x0D
    #define HIGH_DATA_ADDR 0x0C
    
    #define _2PI 6.28318530718
    int main() {
        uint8_t data = 0x00;
    	uint8_t * data_p=&data;
        uint8_t result =0x00;
    	uint16_t result16=0x0000;
    	int     result16_int=0;
    	uint8_t * result_p = &result;
        const char *i2c_device = I2C_DEVICE_PATH;  
        int i2c_file;
    	float rad;
    
        if ((i2c_file = open(i2c_device, O_RDWR)) < 0) {
            perror("Failed to open I2C device");
            return -1;
        }
        
        ioctl(i2c_file, I2C_TENBIT, 0);
        ioctl(i2c_file, I2C_RETRIES, 5);//retry times
        	
    	ioctl(i2c_file,I2C_SLAVE,AS5600_ADDR);
    	while(1){
    	data = LOW_DATA_ADDR;
    	write(i2c_file,data_p,1);
    	read(i2c_file,result_p,1);
    	result16=result;
    	printf("%x,",result);
    
    	data = HIGH_DATA_ADDR;
    	write(i2c_file,data_p,1);
    	read(i2c_file,result_p,1);
    	result16=result16 | (result << 8);
    	
    	result16_int=result16;
    	rad=((float)result16_int/(float)4096)*_2PI;
    
    	printf("%x,",result);
    	printf("%x,",result16);
    	printf("%d,",result16);
    	printf("%f\n",rad);
    
    	}
        close(i2c_file);
    
    
        return 0;
    }
    
    
    • 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
    • 58
    • 59
    • 60
    • 61

    运行结果如下所示
    在这里插入图片描述
    最后输出一个介于0-6.28之间的值

  • 相关阅读:
    Rust的模式匹配
    Java计算机毕业设计电商后台管理系统源码+系统+数据库+lw文档
    400电话申请办理:为企业提供高效沟通的必备工具
    Linux 同步管理(上)
    云原生之Kubernetes:16、详解Operator控制器
    学习Java框架的重要性及步骤
    unity Newtonsoft.Json通过字段名直接读取字段值
    数据结构——二叉搜索树的实现、删除(最大值和最小值、最大值和最小值)
    Day61 数据结构(线性表、链表)
    字节面试遇到的一个超级复杂的输出题,前端人必看系列,搞定之后再也没有输出题可以难倒你
  • 原文地址:https://blog.csdn.net/SuperiorEE/article/details/133611634