Blackrose's Blog Blackrose's Blog

Freescale i.MX28 AUART应用RS485

in technologyread (169) 文章转载请注明来源!

0x0

最近有客户使用i.MX28的SOM模块开发产品,其中用到了RS485通讯,发现发送时延时在百毫秒级,由于上层应用协议要求是微秒级,客户要求减少发送的延时。问题看起来很简单,解决起来也是小波折。总归还是自己对kernel知识理解不够深入。

0x1

了解问题背景后,就去看AUART的实现代码,之前开发imx28的同事已经在mxs_auart_tx_chars()的前后加入了gpio的操作,

static inline void mxs_auart_tx_chars(struct mxc_auart_port *s)
{
    if(s->port.line == 1){
        gpio_set_value(MXS_AUART_RS485_EN, 1);
    }

    // ignore more send code

    if (s->port.line == 1) {
        do {
            status = __raw_readl(s->port.membase + HW_UARTAPP_STAT);
        } while (!(status & BM_UARTAPP_STAT_TXFE) || (
            status & BM_UARTAPP_STAT_BUSY));
        gpio_set_value(MXS_AUART_RS485_EN, 0); // Add by JBO, Disable send
    }
}

细看之后觉得do while用法在这里可能是问题的根源。看了下有mxs_auart_stop_tx(),应该放在里面做符合tty规范么,结果一测,发现stop_tx就没有执行。然后翻datasheet和代码,才知道auart没有FIFO Empty的中断,所以TX中断后要polling去查FIFO Empty flag再拉gpio。然后在网上看到有网友的解决相同问题的记录,依样画瓢改成tasklet处理了。其中也是小状况,就这位网友说的那样,"很多事情都是想得简单,做起来的时候各种意外"。

这里把gpio的操作放在了start_tx()和stop_tx()里面了,mxs_auart_tx_chars()里的检查xmit buf为空后,执行tasklet_hi_schedule(&my_task0);启动tasklet任务,然后由rs485_mode_func()来检查FIFO是否为空,再操作gpio。

void rs485_mode_func(unsigned long data)
{
     struct uart_port *u = data;
     struct mxs_auart_port *s = to_auart_port(u);
     int status;
 
     dev_dbg(s->dev, "%s: control RS485 line\n", __FUNCTION__);
     if (s == NULL)
         return;
     if (s->port.line == 1){
         if(!(readl(s->port.membase + HW_UARTAPP_STAT) & BM_UARTAPP_STAT_TXFE)){
             udelay(10);
             tasklet_hi_schedule(&my_task0);
         }else{
             mxs_auart_stop_tx(&s->port);
         }
     }
}

Reference

linux rs485 GPIO 方向控制问题

文章二维码

扫描二维码,在手机上阅读!

发表新评论
博客已萌萌哒运行
© 2018 由 Typecho 强力驱动.Theme by Yodu
前篇 后篇
雷姆
拉姆