您的位置:首页 > 运维架构 > Linux

在210上做io口模拟串口

2014-03-25 11:03 393 查看
内核版本:linux3.0.8

CPU:s5pv210

在driver/char/ 目录下添加驱动IO_URAT.c

/*************************************

NAME:IO-UART.c

*************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/uaccess.h>//copy_from_user();

#include <linux/hrtimer.h>

#define DEVICE_NAME "GPIO_UART"

/*定时器设备结构体*/
static struct hrtimer  vibe_timer ;
static int value = 55 ,test =1 , io_cnt=0 ,test1; /* Time out setting,104 us */

/* 用来指定UART所用的GPIO引脚 */
static int GPIO_UART_gpios[] = {
S5PV210_GPH2(0),
S5PV210_GPH2(1),
};
#define LED_NUM        ARRAY_SIZE(GPIO_UART_gpios)

static enum hrtimer_restart timer_func(struct hrtimer *timer)
{
//    if(io_cnt < 9)
//hrtimer_start(&vibe_timer, ktime_set(0, 49000),HRTIMER_MODE_REL);
//   printk("start \n");
for(;;)
{
if(io_cnt++ < 1)
{gpio_set_value(GPIO_UART_gpios[0], 0);//起始位
}
else if(io_cnt < 10)
{
if(test&0x01)
{gpio_set_value(GPIO_UART_gpios[0], 1);
}
else
{gpio_set_value(GPIO_UART_gpios[0], 0);
}
test = test >> 1;
}
else
{    gpio_set_value(GPIO_UART_gpios[0], 1);
io_cnt = 0;test1=1;
break;
}/**/
udelay(100);
}
return HRTIMER_NORESTART;
}

static long GPIO_UART_write(struct file *filp, const char *buf, size_t count , loff_t *offset)
{        char kbuf[10];
//    printk("-----------start------------ \r\n");
io_cnt = 0;
copy_from_user(kbuf,buf,count);
//    printk("kbuf  is %c \n",kbuf[0]);
udelay(500)//这里要加个延时,不然会死机
if( test1 == 1)
hrtimer_cancel(&vibe_timer);  //取消定时器
hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
vibe_timer.function =  timer_func ;
gpio_set_value(GPIO_UART_gpios[0], 1);// 设置指定引脚的输出电平为1
hrtimer_start(&vibe_timer,ktime_set(0, 100*1000),HRTIMER_MODE_REL);
test = kbuf[0];
return count;
}

static struct file_operations GPIO_UART_dev_fops = {
.owner            = THIS_MODULE,
// .unlocked_ioctl        = GPIO_UART_ioctl,
.write            = GPIO_UART_write,
};

static struct miscdevice GPIO_UART_dev = {
.minor            = MISC_DYNAMIC_MINOR,
.name            = DEVICE_NAME,
.fops            = &GPIO_UART_dev_fops,
};

static int __init GPIO_UART_dev_init(void) {
int ret;
int i;
ret = gpio_request(GPIO_UART_gpios[0], "LED");
if (ret) {
printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,
GPIO_UART_gpios[0], ret);
return ret;
}
s3c_gpio_cfgpin(GPIO_UART_gpios[0], S3C_GPIO_OUTPUT);
s3c_gpio_setpull(S5PV210_GPB(0), S3C_GPIO_PULL_UP);
gpio_set_value(GPIO_UART_gpios[0], 1);// 设置指定引脚的输出电平为1

ret = misc_register(&GPIO_UART_dev);

printk(DEVICE_NAME"\t------initialized------\n");

return ret;
}

static void __exit GPIO_UART_dev_exit(void) {
int i;
hrtimer_cancel(&vibe_timer);  //取消定时器
for (i = 0; i < LED_NUM; i++) {
gpio_free(GPIO_UART_gpios[i]);
}
printk(DEVICE_NAME"\texit\n");
misc_deregister(&GPIO_UART_dev);
}

module_init(GPIO_UART_dev_init);
module_exit(GPIO_UART_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ljf");
MODULE_DESCRIPTION("GPIO control for IO to uart");


这个驱动要说明一下::刚开始打算开个定时器来当做波特率,查资料得知,linux下的定时器基数都很高,只能用高精度的定时器“hrtimer”,我也试了下,发现定时时间在us级别下很难定准(这里不知道是否是配置问题,不知道有谁知道的说下)。没办法,就采用延时的方式来设置波特率了。但是这边又出现问题了,直接用延时来发一个字节,误码率非常高,十有九错,最右肯能的原因是在发一个个位时有别的进程或中断打断了我们发送程序。。到这里就想到开个进程给他来发送一个字节,这边对进程不太熟悉,然后看到之前的定时器的中断,于是就用定时器的中断函数来发送数据。。这里有谁知道怎么开进程的指导下哈。

这边有个问题是:当你发完一个字节后,再发第二个字节时会把定时器重新开并初始化,这会导致系统出问题。所以在定时器初始化之前把定时器取消掉了“

hrtimer_cancel(&vibe_timer);  //取消定时器


当你发完最后一个字节后,定时器没有取消掉。。这也是个大问题。。。。。

然后在写个应用程序就可以对这个驱动进行测试:

/*************************************

NAME:io-uart.c

*************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int on_off;
int fd;
char buf[2] ;
if (argc != 2 ) {
fprintf(stderr, "Usage: io-uart 0|1\n");
exit(1);
}
fd = open("/dev/GPIO_UART", O_RDWR);//O_RDWR ,因为我们驱动是写函数,所以要填这个参数
if (fd < 0) {
perror("open device GPIO faile");
exit(1);
}
//    sscanf(argv[1], "%d", &on_off);
sscanf(argv[1], "%d", &buf);
printf("on_off: %d", buf[0]);
printf("ioctl+++++++++++++++++++++++++++1\n");
//    ioctl(fd, on_off, 0);
write(fd,buf,2);
printf("write+++++++++++++++++++++++++++2\n");
close(fd);
return 0;
}

然后写个android.mk文件来编译该应用

#
# Makefile for calibrate
#

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= io-uart.c

LOCAL_MODULE := io-uart
LOCAL_MODULE_TAGS := eng
include $(BUILD_EXECUTABLE)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  io模拟uart linux