1. 程式人生 > >在210上做io口模擬串列埠

在210上做io口模擬串列埠


核心版本: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)