几天前,我毫不客气地蒙着面纱,承诺削减有关Milander的职位。好吧,让我们尝试一下。
您可能已经知道,有一家俄罗斯公司Milander,除其他外,该公司生产基于ARM Cortex-M内核的微控制器。 凭着命运的意志,我被迫充分了解他们,我
知道了痛苦 。
下面介绍了因使用RS-485而引起的一小部分痛苦。 如果我在基本概念上花了太多时间,我先向您道歉,但我想让更多的读者理解这篇文章。
我还要提前预约,我只处理198691和19861,我不能自信地谈论其他人。
TL 博士Milandrovsk UART缺少“发送完成”中断,拐杖是“环回测试模式”,即 回声模式。 但是有细微差别。
参赛作品
RS-485接口(虽然我在日常生活中从未听说过,但也称为EIA-485)是具有总线拓扑结构的异步半双工接口。 该标准仅规定物理学-即 电压电平和时序图-但未指定交换协议,针对传输错误的保护,仲裁等。
实际上,RS-485只是具有更高差分电压电平的半双工UART。 正是这种简单性确保了RS-485的普及。
要将UART转换为RS-485,需要使用特殊的转换器微电路,例如MAX485或5559IN10AU(来自同一Milander)。 对于程序员来说,它们几乎是“透明地”工作的,他们只能选择芯片的正确操作模式-接收或发送。 这是通过支路nRE(不是接收器输出使能)和DE(驱动器输出使能)来完成的,通常,它们由微控制器的一个支路进行组合和控制。
抬高此支脚会将芯片切换为发送,将其降低为接收。
因此,程序员所需要做的就是提高这个RE-DE支路,传输所需的字节数,降低支路并等待答案。 听起来很简单,对吧?
呵呵
问题
当所有传输的字节完全传输到该行时,应降低该支路。 如何抓住这一刻? 为此,您需要捕获事件“ Transmit complete”(传输完成),该事件会在微控制器中生成一个UART模块。 在大多数情况下,事件会将某些寄存器或中断请求中的位置1。 为了捕捉寄存器中的位设置,必须对寄存器进行轮询,即 使用如下代码:
while( MDR_UART1->FR & UART_FR_BUSY ) {;}
这是如果我们有能力完全停止程序,直到所有字节传输完毕。 通常,我们负担不起。
在这方面,中断要方便得多,因为它是异步异步到达的。 中断时,我们可以快速省略RE-DE和整个业务。
当然,如果我们能够做到这一点,那就没有痛苦了,这个职位也将不存在。
事实是,在Milander将其放入Cortex-M上所有微控制器的UART模块中(据我所知),“ Transfer Complete”事件不会中断。 只有一个标志。 并且有一个中断“发送器的缓冲区为空”。 当然,还有字节中断。
还有我认为还有很多其他中断和FIFO模式完全没有用。 如果有人知道为什么需要他,请告诉我们!
问题在于“传输缓冲区为空”-这与“传输完成”完全不同。 据我了解内部UART器件,“缓冲区空”事件意味着发送器缓冲区中至少有一个可用空间。 即使此位置只有一个(即一个字节大小的缓冲区),也仅意味着最后发送的字节已复制到内部移位寄存器,该字节将从此字节逐位爬出到行中。
简而言之,“发送器缓冲区为空”事件并不意味着所有字节都已被完全发送。 如果我们此时忽略RE-DE,我们将“削减”我们的包装。
怎么办
汇流
当然,这种解决方案不是很好。 如果我们无法阻止此标志,则必须定期检查它。 要定期检查它,您必须围起来整个花园(特别是如果您想编写一个便携式模块,而不仅仅是一次性解决此问题)。
如果您使用某种RTOS,则为了除草,您必须启动一个单独的任务,在中断时将其唤醒,将其设置为不是最低优先级的麻烦。
但是,好吧,一次折磨,然后我们使用并感到高兴。 但是没有
不幸的是,仅仅将所有字节发送到末尾后,仅严格地忽略RE-DE是不够的。 我们需要
不晚降低它。 因为我们不是一个人坐公交车。 很可能,其他订户的某种回答应该出现在我们的消息中。 如果我们太晚省略RE-DE,我们将不会切换到接收模式,也不会丢失一些响应位。
我们能够承受“过度曝光” RE-DE支路的时间主要取决于传输速度(波特率)以及我们在总线上与之通信的设备的速度。
在我的情况下,速度相对较低(57600波特),并且该设备相当轻巧。 有时碰巧答案丢失了一两点。
总体而言,不是一个好的解决方案。
计时器
想到的第二个选项是使用硬件计时器。 然后,在“发送缓冲区空”中断中,我们启动一个计时器,该超时等于一个字节的发送时间(此时间很容易根据波特率计算),而在计时器中断中,放低脚。
好,可靠的方法。 只有计时器是可惜的。 传统上,米兰德拉(Milandra)中没有很多东西-两到三块。
循环模式
如果您仔细阅读这些内容。 关于UART的描述-
例如,对于1986 BE91T-您会注意到这段很短的段落:
( ) 1 LBE UARTCR.
如果那些。 如果您不阅读说明,则可以通过缩短RX和TX硬件的支脚来获得几乎相同的效果。
大声念头有趣的是,这种循环在哪里? 通常将此模式称为“回声”,但是很好。
想法如下-在传输包中的最后一个字节之前,您需要激活“环回”模式。 然后,当它完全爬到总线上时,您会收到一个中断以接收我们自己的最后一个字节! 好吧,差不多。
实际上,事实证明,接收中断的触发时间比应触发的时间要早一些,大约是位间隔的三分之一。 我不知道这与什么有关; 在环路测试模式下,可能没有实际的线路采样发生,也许环路模式没有考虑最后的停止位。 我不知道 即便如此,我们也无法在进入此中断后立即忽略RE-DE,因为这是我们从最后一个字节“切断”停止位或部分停止位的方式。
严格来说,我们可以或不能取决于接口速度(即一个比特间隔的持续时间)与微控制器的频率之比,但是我无法达到波特率为57600的80 MHz频率。
其他选项是可能的。
如果您有能力轮询标志UART_FR_BUSY一个位的时间间隔-实际上,甚至要少一些,因为进入中断和初步检查也需要时间-那么可以找到解决方案。 对于57600的速度,实际上,最大轮询时间约为18微秒(一个比特间隔),约为5微秒。
对于那些感兴趣的人,我引用了整个中断处理程序代码。 void Handle :: irqHandler(void) { UMBA_ASSERT( m_isInited ); m_irqCounter++;
如果您能负担得起RX和TX支脚之间的跳线(理想情况下可以控制),那么一切都很好。
不幸的是,今天我无法提供其他选择。
这就是我的全部。 如果有人知道解决此问题的其他方法,请在评论中分享。
另外,借此机会并更改Habr规则,我想推广StartMilandr网站,该网站包含有关Milander微控制器的文章。 出于不清楚的原因,您只能偶然使用Google进行搜索。
而且,当然,还记得
标准外围设备库的一个
分支的存在,与官方库不同,该库中的错误已修复,并且有gcc支持。