首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

S3C2440 RS485驱动

S3C2440 RS485驱动

环境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;
}

调试时应注意通信时序
数据处理要即时
继承事业,薪火相传
返回列表