openwrt-安装-驱动-应用-lcd2004a实验
2017-06-12 21:33 tlnshuju 阅读(1436) 评论(0) 编辑 收藏 举报1. 板子f403tech的RT5350的板子和
(1)openWRT系统的定义和特点
OpenWrt是一个高度模块化、高度自己主动化的嵌入式Linux系统。拥有强大的网络组件。经常被
用于工控设备、电话、小型机器人、智能家居、路由器以及VOIP设备中。
OpenWrt支持各种处理器架构。不管是对ARM。X86。PowerPC或者MIPS都有非常好的支持。
其多达3000多种软件包。囊括从工具链(toolchain)。到内核(linux kernel),到软件包
(packages)。再到根文件系统(rootfs)整个体系,使得用户仅仅需简单的一个make命令就可以方便快
速地定制一个具有特定功能的嵌入式系统来制作固件。 其模块化设计也能够方便的移植各类功能
到OpenWrt下,加快开发速度。
2 实验mjpeg-streamer、uvc视频监控
3 openwrt的下载安装
<pre name="code" class="cpp">sudo apt-get install subversion sudo apt-get install git-core sudo apt-get install gcc g++ binutils patch bzip2 flex bison make autoconf gettext texinfo unzip sharutils zlib1g-dev libncurses5-dev gawk mkdir openwrt cd openwrt/ svn co svn://svn.openwrt.org/openwrt/trunk cd trunk/ ./scripts/feeds update -a ./scripts/feeds install -a (4) 配置编译openWRT系统 a、选择CPU型号 TargetSystem —> RalinkRT288x/RT3xxx b、选择CPU子型号 Subtarget —> RT3x5x/RT5350basedboards c、选择详细路由器型号 Targetprofile—>HAME-MPR-A2 (5) 编译 make V=99至此,完毕内核和文件系统镜像编译
4 驱动开发流程
进入/home/openwrt/trunk/package/kernel驱动文件夹,仿照參考其它的驱动。
新建example目录,进入example目录。
创建Makefile:
#
# Copyright (C) 2008-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
# modify by 2014-10-23
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=example
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/example
SUBMENU:=Other modules
# DEPENDS:=@!LINUX_3_3
TITLE:=Simple example driver
FILES:=$(PKG_BUILD_DIR)/example.ko
# AUTOLOAD:=$(call AutoLoad,30,gpio-button-hotplug,1)
KCONFIG:=
endef
define KernelPackage/example/description
This is a example for the following in-kernel drivers:
1) example one
2) example two
endef
MAKE_OPTS:= \
ARCH="$(LINUX_KARCH)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
SUBDIRS="$(PKG_BUILD_DIR)"
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
$(MAKE_OPTS) \
modules
endef
$(eval $(call KernelPackage,example))
新建srce目录。进入src目录。 创建Makefile: obj-m += example.o 创建example.c源文件 #include <linux/module.h> #include <linux/version.h> #include <linux/kmod.h> static int __init example_init(void) { printk("hello example openwrt\n"); return 0; } static void __exit example_exit(void) { printk("hello example openwrt exit\n"); } module_init(example_init); module_exit(example_exit); MODULE_AUTHOR("zhaochuang8888@126.com"); MODULE_DESCRIPTION("example driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); c.编译驱动的命令 make package/kernel/example/compile V=99 <pre name="code" class="cpp"><pre name="code" class="cpp">在/home/openwrt/trunk/bin/ramips/packages/base文件夹生成:kmod-example_3.14.18-1_ramips_24kec.ipk5 应用开发流程
进入/home/openwrt/trunk/package应用文件夹。參考其它的应用文件。
创建helloworld目录。并进入。
创建Makefile:
##############################################
# OpenWrt Makefile for helloworld program
#
#
# Most of the variables used here are defined in
# the include directives below. We just need to
# specify a basic description of the package,
# where to build our program, where to find
# the source files, and where to install the
# compiled program on the router.
#
# Be very careful of spacing in this file.
# Indents should be tabs, not spaces, and
# there should be no trailing whitespace in
# lines that are not commented.
#
##############################################
include $(TOPDIR)/rules.mk
# Name and release number of this package
PKG_NAME:=helloworld
PKG_RELEASE:=1
# This specifies the directory where we're going to build the program.
# The root build directory, $(BUILD_DIR), is by default the build_mipsel
# directory in your OpenWrt SDK directory
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
# Specify package information for this program.
# The variables defined here should be self explanatory.
# If you are running Kamikaze, delete the DESCRIPTION
# variable below and uncomment the Kamikaze define
# directive for the description below
define Package/helloworld
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Helloworld -- prints a snarky message
endef
# Uncomment portion below for Kamikaze and delete DESCRIPTION variable above
define Package/helloworld/description
If you can't figure out what this program does, you're probably
brain-dead and need immediate medical attention.
endef
# Specify what needs to be done to prepare for building the package.
# In our case, we need to copy the source files to the build directory.
# This is NOT the default. The default uses the PKG_SOURCE_URL and the
# PKG_SOURCE which is not defined here to download the source from the web.
# In order to just build a simple program that we have just written, it is
# much easier to do it this way.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
# We do not need to define Build/Configure or Build/Compile directives
# The defaults are appropriate for compiling a simple program such as this one
# Specify where and how to install the program. Since we only have one file,
# the helloworld executable, install it by copying it to the /bin directory on
# the router. The $(1) variable represents the root directory on the router running
# OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install
# directory if it does not already exist. Likewise $(INSTALL_BIN) contains the
# command to copy the binary file from its current location (in our case the build
# directory) to the install directory.
define Package/helloworld/install
$(INSTALL_DIR) $(1)/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/
endef
# This line executes the necessary commands to compile our program.
# The above define directives specify all the information needed, but this
# line calls BuildPackage which in turn actually uses this information to
# build a package.
$(eval $(call BuildPackage,helloworld))
创建src目录,并进入。
创建Makefile:
# build helloworld executable when user executes "make"
helloworld: helloworld.o
$(CC) $(LDFLAGS) helloworld.o -o helloworld
helloworld.o: helloworld.c
$(CC) $(CFLAGS) -c helloworld.c
# remove object files and executable when user executes "make clean"
clean:
rm *.o helloworld
创建helloworld.c:
#include<stdio.h>
int main(void)
{
printf("helloworld\n");
return 0;
}
make package/helloworld/motor/compile V=99
在/home/openwrt/trunk/bin/ramips/packages/base文件夹生成:helloworld_1_ramips_24kec.ipk
5 LCD2004实验
lcd_204a_drv.c 驱动源程序:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
static struct class *lcddrv_class;
static struct device *lcddrv_class_dev;
volatile unsigned long *GPIOMODE;
volatile unsigned long *I2C_CONFIG;
volatile unsigned long *I2C_CLKDIV;
volatile unsigned long *I2C_DEVADDR;
volatile unsigned long *I2C_ADDR;
volatile unsigned long *I2C_DATAOUT;
volatile unsigned long *I2C_STATUS;
volatile unsigned long *I2C_STARTXFR;
volatile unsigned long *I2C_BYTECNT;
static int lcd_204a_open(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t lcd_204a_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned char val;
copy_from_user(&val, buf, 1);
*I2C_CONFIG = (0x6<<2)|(1<<1); // 设备地址是7bit、不用发地址
*I2C_DEVADDR = 0x20; // 设备地址为0x20
*I2C_DATAOUT = val;
*I2C_STARTXFR = 0x0;
while(*I2C_STATUS & 0x1);
return 1;
}
static struct file_operations sencod_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自己主动创建的__this_module变量 */
.open = lcd_204a_open,
.write = lcd_204a_write,
};
int major;
static int lcd_204a_init(void)
{
major = register_chrdev(0, "lcd_204a", &sencod_drv_fops);
lcddrv_class = class_create(THIS_MODULE, "lcd");
lcddrv_class_dev = device_create(lcddrv_class, NULL, MKDEV(major, 0), NULL, "lcd"); /* /dev/204a */
/* 映射对应的寄存器的地址 */
GPIOMODE = (volatile unsigned long *)ioremap(0x10000060, 4);
I2C_CONFIG = (volatile unsigned long *)ioremap(0x10000900, 4);
I2C_CLKDIV = (volatile unsigned long *)ioremap(0x10000904, 4);
I2C_DEVADDR = (volatile unsigned long *)ioremap(0x10000908, 4);
I2C_ADDR = (volatile unsigned long *)ioremap(0x1000090C, 4);
I2C_DATAOUT = (volatile unsigned long *)ioremap(0x10000910, 4);
I2C_STATUS = (volatile unsigned long *)ioremap(0x10000918, 4);
I2C_STARTXFR = (volatile unsigned long *)ioremap(0x1000091C, 4);
I2C_BYTECNT = (volatile unsigned long *)ioremap(0x10000920, 4);
/* 開始设置这些寄存器 */
*GPIOMODE &= ~(1<<0); // I2C_GPIO_MODE
*I2C_CLKDIV = 0x200; // IIC总线时钟 = 40MHz / 512 = 79KHz
return 0;
}
static void lcd_204a_exit(void)
{
unregister_chrdev(major, "lcd_204a");
device_unregister(lcddrv_class_dev);
class_destroy(lcddrv_class);
iounmap(GPIOMODE);
iounmap(I2C_CONFIG);
iounmap(I2C_CLKDIV);
iounmap(I2C_DEVADDR);
iounmap(I2C_ADDR);
iounmap(I2C_DATAOUT);
iounmap(I2C_STATUS);
iounmap(I2C_STARTXFR);
iounmap(I2C_BYTECNT);
}
module_init(lcd_204a_init);
module_exit(lcd_204a_exit);
MODULE_LICENSE("GPL");
lcd2004的应用程序:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
//依据LCD2004A和PCF8574T的引脚确定
//RS:指令/数据 寄存器选择 RS = 0 : 指令寄存器 RS = 1 : 数据寄存器 依据原理图得:RS 与 PCF8574T的PO链接
//RW:读/写 选择 R/W = 0 : 写 R/W = 1 : 读 依据原理图得:RW 与 PCF8574T的P1链接
//CS:同意信号 表示从高电平到低电平,
#define DATA(rs, rw, cs, data) (data<<4)|(cs<<2)|(rw<<1)|rs
int fd;
static void lcd_write_command(unsigned char command)
{
unsigned char data;
/* 1.发送命令的高4位 */
data = DATA(0, 0, 1, (command>>4));
printf("h data = %d\n", data);
write(fd, &data, 1);
usleep(20);
data = DATA(0, 0, 0, (command>>4));
printf("h data = %d\n", data);
write(fd, &data, 1);
/* 2.发送命令的低4位 */
data = DATA(0, 0, 1, (command&0x0f));
printf("l data = %d\n", data);
write(fd, &data, 1);
usleep(20);
data = DATA(0, 0, 0, (command&0x0f));
printf("l data = %d\n", data);
write(fd, &data, 1);
}
static void lcd_write_data(unsigned char wdata)
{
unsigned char data;
/* 1.发送命令的高4位 */
data = DATA(1, 0, 1, (wdata>>4));
printf("h data = %d\n", data);
write(fd, &data, 1);
usleep(20);
data = DATA(1, 0, 0, (wdata>>4));
printf("h data = %d\n", data);
write(fd, &data, 1);
/* 2.发送命令的低4位 */
data = DATA(1, 0, 1, (wdata&0x0f));
printf("l data = %d\n", data);
write(fd, &data, 1);
usleep(20);
data = DATA(1, 0, 0, (wdata&0x0f));
printf("l data = %d\n", data);
write(fd, &data, 1);
}
static void lcd_set_xy(unsigned char x, unsigned char y)
{
unsigned char address;
if (y == 0)
address = 0x80 + x;
else
address = 0xc0 + x;
lcd_write_command(address);
}
/*
函数名:
lcd_write_char()
功能:
列x=0~15,行y=0,1
使用方法:
*/
static void lcd_write_char(unsigned char X,unsigned char Y,unsigned char Recdata)
{
lcd_set_xy(X, Y);
lcd_write_data(Recdata);
}
static int lcd_PutStr(unsigned char *DData,int pos)
{
unsigned char i;
if(pos==-1)
{
lcd_write_command(0x01); //清屏
usleep(2);
pos=0;
}
while((*DData)!='\0')
{
switch(*DData)
{
case '\n': //假设是\n,则换行
{
if(pos<21)
{
for(i=pos;i<20;i++)
lcd_write_char(i%20, i/20, ' ');
pos=20;
}
else
{
for(i=pos;i<40;i++)
lcd_write_char(i%20, i/20, ' ');
pos=40;
}
break;
}
case '\b': //假设是\b。则退格
{
if(pos>0)
pos--;
lcd_write_char(pos%20, pos/20, ' ');
break;
}
default:
{
if((*DData)<0x20)
{
*DData=' ';
}
lcd_write_char(pos%20, pos/20,*DData);
pos++;
break;
}
}
DData++;
}
return(pos);
}
//从右边数。保留几位小数
static int lcd_PutNum(unsigned long num,int XS,int pos)
{
unsigned long tmp=0;
unsigned char numbits=0;
if(pos==-1)
{
lcd_write_command(0x01);
usleep(2);
pos=0;
}
if(num==0)
{
lcd_write_char(pos%20, pos/20, '0');
pos++;
}
else
{
if(num<0)
{
lcd_write_char(pos%20, pos/20, '-');
num*=(-1);
pos++;
}
while(num)
{
tmp=tmp*10+(num%10);
num=num/10;
numbits++;
}
while(tmp)
{
lcd_write_char(pos%20, pos/20, (tmp%10)+48);
tmp=tmp/10;
pos++;
numbits--;
if(numbits==XS)
pos=lcd_PutStr(".",pos); //显示小数点
}
while(numbits--)
{
lcd_write_char(pos%20, pos/20, '0');
pos++;
}
}
return(pos);
}
void lcd_put_char(unsigned char ch, unsigned int pos , int flag)
{
if(flag == 0)
{
lcd_write_command(0x80+pos);
}
if(flag == 1)
{
lcd_write_command(0xc0+pos);
}
lcd_write_data(ch);
}
void lcd_put_str(const char *str, int flag)
{
int cnt=0;
while(*str !='\0')
{
lcd_put_char(*str, cnt, flag);
cnt++;
str++;
}
}
/* seconddrvtest
*/
int main(int argc, char **argv)
{
int p;
fd = open("/dev/lcd", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
lcd_write_command(0x28);
usleep(1000);
lcd_write_command(0x28);
usleep(1000);
lcd_write_command(0x28);
usleep(1000);
lcd_write_command(0x0e); // 显示开
usleep(1000);
lcd_write_command(0x01); // 清屏
usleep(1000);
// lcd_write_char(0, 0, "a");
int i = 0;
for(i=0; i<26; i++)
{
lcd_write_command(0x80+i);
lcd_write_data('a'+i);
}
for(i=0; i<30; i++)
{
lcd_write_command(0xc0+i);
lcd_write_data('2'+i);
}
sleep(10);
lcd_write_command(0x01); // 清屏
usleep(1000);
lcd_put_str("Welcome RT5350", 0);
lcd_put_str(" --By Dreeam", 1);
//p = lcd_PutStr("RT5350 By F403tech!\n",0); // 显示一段文字
//usleep(1000);
//p = lcd_PutStr("f403tech.taobao.com\n",p); // 显示一段文字
//lcd_PutNum(1234,2,p); // 显示12.34这个数
return 0;
}
a.软件包管理经常使用命令
opkg install xxx.ipk // 安装指定的软件包
opkg remove xxx.ipk // 卸载已经安装过的指定的软件包
opkg list // 获取软件列表
生成的驱动位于 /lib/modules/3.14.18/文件夹下。
<pre name="code" class="cpp">生成的应用位于 /bin文件夹下。
opkg help