S3C2440 RS485驱动

来源:互联网 发布:路由器mac地址过滤 编辑:程序博客网 时间:2024/05/16 17:53

环境arm linux

根据serial/s3c2410.c搭建485驱动整体框架,因为要实现实时响应命令功能,所以将部分数据处理放在驱动程序中做,这样可以保证在1ms内完成数据通信,系统通信可靠。

整体框架如下

static __init int s3c485_init(void)
{
    int res;
    dev_t dev = 0;
    if (s3c485_major) {
        dev = MKDEV(s3c485_major, uart_minor);
        res = register_chrdev_region(dev, s3c485_nr_devs, S3C485_NAME);
    } else {
        // dynamic alloc dev major/minor
        res = alloc_chrdev_region(&dev, uart_minor, s3c485_nr_devs, S3C485_NAME);
        s3c485_major = MAJOR(dev);
    }
    if (res < 0) {
        printk(KERN_INFO "s3c_uart1: can't get major %d/n", s3c485_major);
        return res;
    }
    {
        struct s3c485_dev *dev = &uart_dev;
        s3c485_setup_cdev(dev, 0);
        // 硬件配置,初始化寄存器地址和I/O,此处也可以写在device_driver的probe中
        s3c485_setup_regs(dev, 2);
#ifdef CONFIG_DEVFS_FS
        devfs_mk_cdev(MKDEV(s3c485_major, 0), S_IFCHR | S_IRUSR | S_IWUSR, S3C485_NAME);
#endif
        /*
         * 注册接收中断函数,实时响应命令
         */
        if (request_irq(dev->irq, s3c485_rx_interrupt, /*SA_SHIRQ*/0, S3C485_NAME, dev)) {
            printk("s3c485: uart_setup_base - Can't get irq %d/n", dev->irq);
            return -EBUSY;
        }
    }
    // register over
    printk("S3C-UART2 driver v" S3C485_VER "/n");
    return 0;
}

// exit函数做一些清理工作

static __exit void s3c485_exit(void)
{
    struct s3c485_dev *dev = &uart_dev;
    free_irq(dev->irq, dev);
    cdev_del(&dev->cdev);
#ifdef CONFIG_DEVFS_FS
    devfs_remove("s3c485");
#endif
    unregister_chrdev_region(s3c485_major, s3c485_nr_devs);
}
module_init(s3c485_init);
module_exit(s3c485_exit);

// 打开函数

static int s3c485_open(struct inode *inode, struct file *filp)
{
    struct s3c485_dev *dev;
    int ret;
    // get uart devices...
    dev = container_of(inode->i_cdev, struct s3c485_dev, cdev);
    // save dev data to private data
    filp->private_data = dev;
    // UART只允许独占方式打开
    if (dev->isopened) {
        up(&dev->sem);
        return -EBUSY;
    }
    dev->isopened = 1;

    // 使能接收
    if ((ret = s3c485_setup_base(dev)) < 0) {
        goto err;
    }

    // 数据初始化
    ...
    return nonseekable_open(inode, filp);
err:
    return ret;
}
// 中断函数

static irqreturn_t s3c485_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
    struct s3c485_dev *dev = (struct s3c485_dev *)dev_id;
    unsigned int status = s3c_read_reg(dev->reg_base, S3C2410_UERSTAT);// 读取错误状态寄存器
    u8 data;
    if (status)
        PDEBUG("err status %x/n", status);
    status = s3c_read_reg(dev->reg_base, S3C2410_UTRSTAT);
    if (status & S3C2410_UTRSTAT_RXDR) {
        data = s3c_read_reg(dev->reg_base, S3C2410_URXH) & 0xFF;

        // 收到数据,并做数据处理
        ...

        // 发送数据

        s3c485_en_tx();// enable tx, I/O线置位发送

        send_data();// 查询方式发送数据

        s3c485_disable_tx();// disable tx, I/O线置位发送
    }
out:
    return IRQ_HANDLED;
}

 

调试时应注意通信时序

数据处理要即时

原创粉丝点击