目录
准备工作:
wifi音视频开发板一块
1.N32905 GPIO简介
N32905共有192个GPIO,分6组分别为GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOG,每组有32个GPIO。
实现流水灯只需两步就可以完成,首先在内核配置中选择支持GPIO,然后编写GPIO用户程序既可。应用程序是通过ioctl系统调用完成对底层硬件的操作。
ioctl是应用程序对设备控制的函数,通常用于设置设备的一些参数,例如串口的传输波特率、马达的转速等等,当然也可以控制GPIO。
函数原型:int ioctl(int fd, ind cmd, …)
输入参数:1.fd:用户程序打开设备时使用open函数返回的文件标示符;
2.cmd:用户程序对设备的控制命令;
返回值:0:成功;
-1:出错;
如果驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数控制设备的I/O通道。
2.硬件设计
底板上的LED1、LED2、LED3、LED4分别与核心板的GPA[0]、GPA[2]、GPA[5]、GPA[6]直接相连,其电路连接如下图1.2.1所示。
图2.1 LED与N32905电路连接图
3.软件设计
3.1内核配置
命令行输入./build spiramfs,按enter键就开始编译内核,内核生成路径在/duckbill/N32905/BSP/image/Kernel.bin。
3.2 GPIO应用程序分析
代码路径:/duckbill/N32905/BSP/applications/gpio/gpio-led/gpio.c。
/*
* LED application Program
引脚对应关系
LED1 ------> GPA0
LED2 ------> GPA2
LED3 ------> GPA5
LED4 ------> GPA6
输出LED高电平灭,低电平亮
*
*/
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#define GPIO_SETOUT_HIGH 1 //GPIO输出高电平
#define GPIO_SETOUT_LOW 0 //GPIO输出低电平
#define GPIO_SETDIR_OUT 1 //设置GPIO输出
#define GPIO_SETDIR_IN 0 //设置GPIO输入
// GPIO ioctl command
#define GPIO_IOCTRL_OPEN 1 //打开IOCTL接口
#define GPIO_IOCTRL_SETDIR 2 //设置GPIO方向
#define GPIO_IOCTRL_SETOUT 3 //设置GPIO输出的值
#define GPIO_IOCTRL_GETIN 4 //获取GPIO输入的值
#define DEF_CTRL_DEVICE "/dev/gpio" //GPIO设备文件名,即文件节点
//N32905共有5组GPIO,分别为GPIOA、GPIOB、GPIOC、GPIOD、GPIOE.
typedef enum
{
eDRVGPIO_GPIOA = 0x00,
eDRVGPIO_GPIOB = 0x10,
eDRVGPIO_GPIOC = 0x20,
eDRVGPIO_GPIOD = 0x30,
eDRVGPIO_GPIOE = 0x40
} E_DRVGPIO_PORT;
//每组GPIO下有16个GPIO引脚,从PIN0到PIN15.
typedef enum
{
eDRVGPIO_PIN0 = 0x0001,
eDRVGPIO_PIN1 = 0x0002,
eDRVGPIO_PIN2 = 0x0004,
eDRVGPIO_PIN3 = 0x0008,
eDRVGPIO_PIN4 = 0x0010,
eDRVGPIO_PIN5 = 0x0020,
eDRVGPIO_PIN6 = 0x0040,
eDRVGPIO_PIN7 = 0x0080,
eDRVGPIO_PIN8 = 0x0100,
eDRVGPIO_PIN9 = 0x0200,
eDRVGPIO_PIN10 = 0x0400,
eDRVGPIO_PIN11 = 0x0800,
eDRVGPIO_PIN12 = 0x1000,
eDRVGPIO_PIN13 = 0x2000,
eDRVGPIO_PIN14 = 0x4000,
eDRVGPIO_PIN15 = 0x8000,
} E_DRVGPIO_BIT;
//结构体S_GPIO_PARAM表示每个GPIO的属性,包含命令、端口、引脚、值。
typedef struct _S_GPIO_PARAM
{
int cmd;
int port;
int pin;
int val;
} S_GPIO_PARAM;
//定义GPIO文件标示符
int s_fdGPIO=0;
//通过ioctl控制GPIO
int CtrlPinsIO(int cmd, int port, int pin, int val)
{
S_GPIO_PARAM param;
param.cmd = cmd;
param.port = port;
param.pin = pin;
param.val = val;
if(ioctl(s_fdGPIO, cmd, (void*)¶m) < 0)
printf("CtrlPinsIO:cmd=%d failed!\n", cmd);
return param.val;
}
int main(void)
{
int rec=0,cnt1=0,cnt2=0;
int key_down=0;
//打开设备文件,若小于0则打开失败。
if((s_fdGPIO = open(DEF_CTRL_DEVICE, O_RDWR)) < 0)
{
printf("Failed to open %s!\n", DEF_CTRL_DEVICE);
return 0;
}
//初始化GPA0、GPA2、GPA5、GPA6为输出高电平,LED1-LED4全灭.
CtrlPinsIO(GPIO_IOCTRL_OPEN, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, 0); //打开GPA0
CtrlPinsIO(GPIO_IOCTRL_SETDIR, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETDIR_OUT); //设置GPA0为输出
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETOUT_HIGH); //设置GPA0输出高电平
CtrlPinsIO(GPIO_IOCTRL_OPEN, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, 0); //打开GPA2
CtrlPinsIO(GPIO_IOCTRL_SETDIR, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETDIR_OUT); //设置GPA2为输出
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETOUT_HIGH); //设置GPA2输出高电平
CtrlPinsIO(GPIO_IOCTRL_OPEN, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, 0); //打开GPA5
CtrlPinsIO(GPIO_IOCTRL_SETDIR, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETDIR_OUT); //设置GPA5为输出
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETOUT_HIGH); //设置GPA5输出高电平
CtrlPinsIO(GPIO_IOCTRL_OPEN, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, 0); //打开GPA6
CtrlPinsIO(GPIO_IOCTRL_SETDIR, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETDIR_OUT); //设置GPA6为输出
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETOUT_HIGH); //设置GPA6输出高电平
while(1)
{
//LED1亮
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETOUT_LOW); //设置GPA0输出低电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETOUT_HIGH);//设置GPA2输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETOUT_HIGH);//设置GPA5输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETOUT_HIGH);//设置GPA6输出高电平
usleep(500000); //延时500ms
//LED2亮
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETOUT_HIGH);//设置GPA0输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETOUT_LOW); //设置GPA2输出低电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETOUT_HIGH);//设置GPA5输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETOUT_HIGH);//设置GPA6输出高电平
usleep(500000); //延时500ms
//LED3亮
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETOUT_HIGH);//设置GPA0输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETOUT_HIGH);//设置GPA2输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETOUT_LOW); //设置GPA5输出低电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETOUT_HIGH);//设置GPA6输出高电平
usleep(500000); //延时500ms
//LED4亮
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETOUT_HIGH);//设置GPA0输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETOUT_HIGH);//设置GPA2输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETOUT_HIGH);//设置GPA5输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETOUT_LOW); //设置GPA6输出低电平
usleep(500000); //延时500ms
//LED3亮
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETOUT_HIGH);//设置GPA0输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETOUT_HIGH);//设置GPA2输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETOUT_LOW); //设置GPA5输出低电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETOUT_HIGH);//设置GPA6输出高电平
usleep(500000); //延时500ms
//LED2亮
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN0, GPIO_SETOUT_HIGH);//设置GPA0输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN2, GPIO_SETOUT_LOW); //设置GPA2输出低电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN5, GPIO_SETOUT_HIGH);//设置GPA5输出高电平
CtrlPinsIO(GPIO_IOCTRL_SETOUT, eDRVGPIO_GPIOA, eDRVGPIO_PIN6, GPIO_SETOUT_HIGH);//设置GPA6输出高电平
usleep(500000); //延时500ms
}
close(s_fdGPIO); //关闭设备文件
}
main函数一开始首先打开设备文件open(DEF_CTRL_DEVICE, O_RDWR),对linux操作系统而言,一切设备即文件,应用程序通过设备文件就可以操作底层驱动了。通过调用系统函数ioctl控制LED,依次循环点亮LED1-LED4,最后关闭设备文件。
4.编译
在ubuntu下切换路径至/duckbill/N32905/applications/gpio/gpio-led。
执行make,编译生成可执行文件led_demo,led_demo将会自动拷贝至例程文件系统目录 /duckbill/N32905/usr/TEST_mini905/mkFilesys下。
执行例程文件系统TEST_mini905/test_mini905/目录下的脚本mkjffs2.sh,生成我们所需的jffs2文件系统。
5.烧录运行
N32905音视频开发板与电脑之间连接好usb电源线(也充当下载线)、usb转串口线,将拨码开关S1拨向Rec位,按下自锁开关K1,开发板通电,N32905进入烧录模式。
①烧录loader:Image Type 选择System Image,Image Name选择SpiLoader_905.bin,点击Burn烧录。
②烧录内核:Image No:设置1,Image Name选择Kernel.bin,Image Type 选择Execute,Image execute address设置0,Image start bank设置4,点击Burn烧录。
③烧录文件系统:Image No:设置2,Image Name选择TEST_mini905.jffs2.summary,Image Type 选择Data,Image execute address设置0,Image start bank设置30,点击Burn烧录。
烧录完成后将拨码开关S1拨向Nor位,板子重新通电,N32905进入正常启动模式,等待系统运行起来。
在串口超级终端输入./led_demo,将会看到LED1-LED4依次循环点亮,流水灯就实现了。