STM32/STM8技术论坛
直播中

donatello1996

8年用户 687经验值
擅长:处理器/DSP 控制/MCU RF/无线
私信 关注

【STM32MP157A-DK1开发板试用连载】工程环境搭建&简单的GPIO通用输入输出功能

` 本帖最后由 donatello1996 于 2020-4-12 15:57 编辑

收到MP157开发板已经过去将近两个星期了,由于工作太累一直没抽出时间发布帖子,现在发布第一帖。

ST厂商把板子寄过来的时候还附送了一张SD卡,里面是烧录好系统的,省去了自己烧写系统的麻烦,我只需要搭建开发板主控的交叉编译链即可使用板子运行我自己的用户程序。搭建交叉编译链的过程不算太难,但是遇到了两处细节性的地方浪费了不必要的时间,第一就是交叉编译链的sysroot目录被官方预设为/opt下的子目录,因此官方推荐的做法是将交叉编译链安装在/opt下,不然会出现莫名BUG导致编译路径出错,如找不到crt1.o等奇怪错误,如图就是官方安装完交叉编译链的效果,sysroots文件夹在/opt/st/STM32mp1/2.6-openstlinux-20-02-19/路径下:
1.JPG
然后再回过头来看下交叉编译链的下载地址和安装过程,方便发烧友论坛里面想玩MP157板子的萌新,下载地址如下:
https://www.st.com/content/ccc/r ... nux-20-02-19.tar.xz

非常长的一条地址,可以直接用迅雷打开下载。

在虚拟机里面解压这个SDK包,可以看到其中有一个.sh脚本文件,为了执行方便,我将它改名了为1.sh,脚本文件的路径为/home/donatello/STM32MP157SDK,萌新们如果放到别的路径也一样的操作,运行脚本文件:
2.JPG
  1. cd /home/donatello/STM32MP157SDK
  2. ./1.sh
或者直接
  1. /home/donatello/STM32MP157SDK/1.sh

这时安装脚本会问你将SDK安装到哪个目录下,使用默认目录/opt下就可以,直接回车跳过:
3.JPG

安装好的交叉编译环境如图1,这时要使用环境目录里面自带的environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi环境变量配置文件,以让系统可以识别到交叉编译链:
  1. source environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi

这里就有我上文说的第二个问题:一般我以前习惯了交叉编译链开发,都是用arm-xxx-linux-xxx-gcc这样的一条字段来操作编译的,但实际上MP157的交叉编译链字段还有别的组成部分,有一段路径关键字,一段关联库关键字,他们给出的环境变量配置文件里面必须用$CC来指代他们的交叉编译链arm-ostl-linux-gnueabi-gcc,即编译一个main.cc文件,需要使用

  1. $CC main.cc -o main
而不是像以前那样用
  1. arm-ostl-linux-gnueabi-gcc main.cc -o main
不然,就会有报错:
5.JPG
其实他们这样做自然有他们的道理,很简单,使用
echo $CC
就知道他们他们为啥要这样设计了:
6.JPG
$CC是指定了路径关键字和库关键字的。

那么,既然知道编译链的使用,就可以创建代码工程以及MakeFile文件了,MakeFile是方便进行编译的一个工具,不管引入啥样的源文件,头文件,编译库等,只需要往MakeFile文件里面修改相应的配置,编译的时候只需要一个make命令即可搞定,这边我为了方便开发还是使用Windows的代码编辑工具Source Insight,毕竟现在在公司里面用习惯了,超级好用,创建一个main.cc主程序文件,以及两个我自己写的,用于驱动GPIO的源文件和头文件my_gpio.cc和my_gpio.h:
7.JPG
MakeFile文件我摘抄网上例程:

  1. PROG = main
  2. SRCS = main.cc my_gpio.cc

  3. CLEANFILES = $(PROG)

  4. CFLAGS += -Wall $(shell pkg-config --cflags gtk+-3.0)
  5. LDFLAGS += $(shell pkg-config --libs gtk+-3.0)

  6. all: $(PROG)

  7. $(PROG): $(SRCS)
  8.     $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)

  9. clean:
  10.     rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
PROG关键字指定生成的可执行程序名称,我指定为main,SRCS关键字指定源文件,CFLAGS关键字指示编译用的C源码库,LDFLAGS指示编译用的LIB静态库,这里用到一个名为gtk的图形UI库,后面的帖子会提到,clear关键字为编译清理选项,通常是清理.o文件和旧的可执行程序。

关于操作GPIO的方式,目前我看网上的例程,一个是盘古STM32MP157开发板的例程,一个是ST官方维基百科,都是使用struct gpiohandle_request结构体和ioctl即IO操作函数,暂时没发现使用mmap直接操作寄存器的例程,也就只能先用着,后期我会尝试将gpiohandle_request结构体丢弃掉,直接使用内存变量来结合ioctl函数使用,减少资源开销,以下是我操作GPIO的函数:

  1. struct gpiohandle_request GPIO_Init(int port,int pin,int dir)
  2. {
  3.     int fd;
  4.     struct gpiohandle_request req;
  5.     char dev_port_name[9][20]=
  6.     {
  7.         "/dev/gpiochip0",
  8.         "/dev/gpiochip1",
  9.         "/dev/gpiochip2",
  10.         "/dev/gpiochip3",
  11.         "/dev/gpiochip4",
  12.         "/dev/gpiochip5",
  13.         "/dev/gpiochip6",
  14.         "/dev/gpiochip7",
  15.         "/dev/gpiochip8",
  16.     };
  17.         
  18.     fd=open(dev_port_name[port],0);
  19.     if (fd == -1)
  20.     {
  21.         fprintf(stderr, "打开设备%s失败
  22. ",dev_port_name[port]);
  23.     }
  24.     req.lineoffsets[0] = pin;
  25.     if(dir==0)
  26.         req.flags = GPIOHANDLE_REQUEST_INPUT;
  27.     else req.flags = GPIOHANDLE_REQUEST_OUTPUT;
  28.     memset(req.default_values,0,sizeof(req.default_values));
  29.     req.lines  = 1;
  30.     ioctl(fd,GPIO_GET_LINEHANDLE_IOCTL,&req);
  31.     if (close(fd) == -1)
  32.         perror("关闭设备失败
  33. ");
  34.     return req;
  35. }

  36. void GPIO_Set_Output_Value(struct gpiohandle_request req,int val)
  37. {
  38.     struct gpiohandle_data data={0};
  39.     if(val==1)
  40.     {
  41.         data.values[0]=1;
  42.     }
  43.     else if(val==0)
  44.     {
  45.         data.values[0]=0;
  46.     }
  47.     ioctl(req.fd,GPIOHANDLE_SET_LINE_VALUES_IOCTL,&data);
  48. }

  49. int GPIO_Get_Input_Value(struct gpiohandle_request req)
  50. {
  51.     struct gpiohandle_data data={0};
  52.     ioctl(req.fd,GPIOHANDLE_GET_LINE_VALUES_IOCTL,&data);
  53.     return data.values[0];
  54. }
对于官方开发板,上面提供了很多可供操作的GPIO,今天我就先用几个能看到明显效果的LD6 LD5 LD7,分别是绿灯,红灯,黄灯,对应GPIO引脚为PA13 PA14 PH7,然后我再使用一块开源的Arduino外设板插到开发板的底部Arduino排针上,就可以用开发板来操作Arduino外设,本帖我操作的Arduino外设是两个按键以及一个用GPIO高低电平驱动的电机,查阅外设板原理图得出两个按键分别为Arduino排针的D4和D5,电机则是D9,对应开发板的GPIO,D4-》PE10,D5-》PD15,D9-》PH6,有了这些引脚,我可以设计一个简单的操作程序,检测D4 D5按键的电平,分别控制黄灯PH7以及电机PH6,绿灯PA13和红灯PA14则做成流水灯,于是一个简单的程序就写好了:
8.JPG 12.JPG 13.JPG

  1. int main(int argc, char **argv)
  2. {
  3.     struct gpiohandle_request req_pa13,req_pa14,req_ph7;
  4.     struct gpiohandle_request req_pd15,req_pe10;
  5.     struct gpiohandle_request req_ph6;
  6.     int ret;
  7.    
  8.     req_pa13=GPIO_Init(0,13,1);
  9.     req_pa14=GPIO_Init(0,14,1);
  10.     req_ph7=GPIO_Init(7,7,1);

  11.     req_ph6=GPIO_Init(7,6,1);
  12.    
  13.     req_pd15=GPIO_Init(3,15,0);
  14.     req_pe10=GPIO_Init(4,10,0);

  15.     while(1)
  16.     {

  17.         GPIO_Set_Output_Value(req_pa13,1);
  18.         GPIO_Set_Output_Value(req_pa14,1);

  19.         usleep(50*1000);

  20.         GPIO_Set_Output_Value(req_pa13,0);
  21.         GPIO_Set_Output_Value(req_pa14,0);
  22.         
  23.         usleep(50*1000);

  24.         GPIO_Set_Output_Value(req_ph7,!GPIO_Get_Input_Value(req_pd15));
  25.             
  26.         GPIO_Set_Output_Value(req_ph6,!GPIO_Get_Input_Value(req_pe10));

  27.     }

  28.     ret = close(req_pa13.fd);
  29.     if (ret == -1)
  30.     {
  31.         perror("Failed to close GPIO LINEHANDLE device file");
  32.         ret = -errno;
  33.     }
  34.     return ret;
  35. }
使用make编译代码:
14.JPG
使用TFTP工具将可执行文件上传到开发板并运行:
15.JPG 16.JPG IMG_20200412_151404_1.jpg 1.gif
在本文结尾,我再看下开发板的基本信息,如uname -a查看内核版本, cat /proc/meminfo查看内存大小,cat /proc/cpuinfo查看CPU核数,分别是512MB内存,双核A7:
9.JPG 10.JPG 11.JPG

` IMG_20200412_151356.jpg 4.JPG

更多回帖

发帖
×
20
完善资料,
赚取积分