This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP432E411Y-BGEVM:我的 UART 6 RX EOT 中断太慢

Guru**** 1555290 points
Other Parts Discussed in Thread: MSP432E401Y, MSP432E411Y
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1078283/msp432e411y-bgaevm-my-uart6-rx-eot-interrupt-is-too-slow

部件号:MSP432E411Y-BGAEVM
线程中讨论的其他部件:MSP432E401YMSP432E411Y测试

嘿,伙计们,
我正在进行一个项目,我应该在该项目中通过使用 Modbus-RTU 连接到 UART 的 RS-485与传感器进行通信。 我已经实施了将数据发送到传感器的部分,但在切换连接到 GPIO PH4引脚的 DE/NRE 时遇到问题。 我正在尝试使用 UART_TXINT_MODE_EOT 中断(根据文档,该中断应在发送最后一个字节的最后一位后立即升高)来更改发送数据和中断升高后的通信方向, 但速度太慢,所以我错过了传感器的响应。 我用计时器做了一些粗略的测量,似乎中断时间晚了大约30毫秒。

这是代码的一部分,它应该发生在哪里。 有人能帮我弄清楚为什么它不像我想象的那样工作?

https://pastebin.com/gXpHHrZf

谢谢

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我在 MSP432E401Y Launchpad 上运行了此代码,我的范围在启用引脚上显示了大约9.2毫秒的高脉冲。 这就是我所期待的——8 UART 字节为8.3毫秒,加上一些 slop。

    您是如何衡量的?

    移植注释:

    1)将启用引脚移至 PH0 (无 PH4)

    2)已启用 PORTP (SystlPeripheralEnable)

    3)删除了 msp432e411y.h 的显式包含

    [编辑:固定排版。]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,感谢您对此进行调查,并对延迟回复表示抱歉。 我用计时器和 TimerValueSet()函数测量了它,该过程看起来有点像这样:

    1.启动计时器
    2.将定时器值保存到 TIMER 之前
    3.发送数据
    4.将定时器值保存到 TIMER 之后

    以“将计时器值保存到 TIMER 值”的代码行作为中断处理程序的第一行。

    无论如何,我的目标是:
    Timer_Before = 808
    Timer_After = 1238
    Timer_int = 6,628,182

    这让我相信中断需要600多万个周期。 但我仍在学习,所以很有可能我的方法不是最好的。

    但是,我还使用连接到 TX,RX 和 DE/NRE 导线的示波器进行了检查,该示波器显示从电路板到传感器的数据已发送,然后暂停片刻,传感器将返回响应, 但启用引脚在此后会变低,因此我错过了传入数据。 但我没有确切的数字。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我做了我认为同样的事情,我得到了 timer_before = 119999972,timer_after = 118899120,相差1100852。 我离开计时器预校准器=1,所以它的计数为120MHz。  我的计算器显示1100852/120MHz = 0.009174秒,即约9.2毫秒。

    [编辑:重新阅读时,我意识到我所称的 timer_after 与您的 case 中的 timer_int 对应。]

    我的范围表示最终 Tx 上升边缘(停止位)和使能器下降边缘之间的延迟约为100us。 (我不知道 EOT 是定义为在最终数据位之后触发还是在停止位之后触发。)

    为了清晰起见,我正在与之合作。 也许您可以看到不同之处。

    ///
    #define BMC     1
    #define TIMERS  1
    #include <stdio.h>
    #include <stdlib.h>
    #include "ti/devices/msp432e4/driverlib/driverlib.h"
    #include <ti/devices/msp432e4/driverlib/interrupt.h>
    #include <ti/devices/msp432e4/driverlib/uart.h>
    #include <ti/drivers/uart/UARTMSP432E4.h>
    #include <ti/devices/msp432e4/driverlib/gpio.h>
    #include <ti/devices/msp432e4/driverlib/sysctl.h>
    #include <ti/devices/msp432e4/driverlib/pin_map.h>
    #if !BMC
    #include <ti/devices/msp432e4/inc/msp432e411y.h>
    #endif
    
    volatile unsigned char buffer[256] = { { 0 } };
    volatile unsigned int buffer_position = 0;
    #if BMC // BMC
    #define ENBIT GPIO_PIN_0    // No PH4 on E401Y
    #else
    #define ENBIT GPIO_PIN_4
    #endif
    #if TIMERS
    volatile uint32_t time_before, time_after;
    #endif
    /* Incoming byte at UART6 interrupt handler. */
    void UART6_IRQHandler(void) {
        uint32_t ui32Status;
    #if TIMERS
        time_after = TimerValueGet(TIMER0_BASE, TIMER_A);
    #endif // TIMERS
        // Get the interrupt status.
        ui32Status = UARTIntStatus(UART6_BASE, true);
    
        // Clear the asserted interrupts.
        UARTIntClear(UART6_BASE, ui32Status);
    
        if (ui32Status & UART_INT_TX) { // end-of-transmission interrupt
            GPIOPinWrite(GPIO_PORTH_BASE, ENBIT, 0x00);
        }
        while (UARTCharsAvail(UART6_BASE)) {
            buffer[buffer_position++] = UARTCharGet(UART6_BASE);
        }
    }
    
    int main(void) {
        uint32_t ui32SysClock;
        volatile uint32_t ui32Loop;
    
        // Run from the PLL at 120 MHz.
        ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480),
                                          120000000);
    
    #if BMC // BMC
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
        while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOP)) {
        }
    #endif // BMC
        // Initialise UART 6.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART6);
        IntMasterEnable();
    
        GPIOPinConfigure(GPIO_PP0_U6RX);
        GPIOPinConfigure(GPIO_PP1_U6TX);
        GPIOPinTypeUART(GPIO_PORTP_BASE, GPIO_PIN_0 | GPIO_PIN_1);
        UARTConfigSetExpClk(UART6_BASE, ui32SysClock, 9600,
                            (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_EVEN));
        IntEnable(INT_UART6);
        UARTIntEnable(UART6_BASE, UART_INT_RX | UART_INT_TX);
        UARTTxIntModeSet(UART6_BASE, UART_TXINT_MODE_EOT);
    
        // Initialise GPIO pin.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH);
        while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOH)) {
        }
        GPIOPinTypeGPIOOutput(GPIO_PORTH_BASE, ENBIT);
        // Send message.
        uint8_t data[8] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x05, 0x30, 0x09 };
    #if TIMERS
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
        MAP_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
        MAP_TimerLoadSet(TIMER0_BASE, TIMER_A, ui32SysClock); // 1 second for no good reason
        MAP_TimerEnable(TIMER0_BASE, TIMER_A);
        time_before = TimerValueGet(TIMER0_BASE, TIMER_A);
    #endif // TIMERS
        GPIOPinWrite(GPIO_PORTH_BASE, ENBIT, 0xFF);
        int i;
        for (i = 0; i < 8; ++i) {
            UARTCharPutNonBlocking(UART6_BASE, data[i]);
        }
    
        while (1) {
        }
    }
    

    [编辑:固定排版。]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,很抱歉回复太晚了……再次。 不幸的是,除了移植到您的主板外,我没有看到任何区别。 我认为这可能是一个硬件问题,因为它在您的案例中是按预期工作的。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我认为您可以在您的主板上尝试此代码(重新定义 BMC=0),以查看您是否获得相同的结果。 如果你这样做,那就指向一个方向,如果你不指向另一个方向。

    如果不启用端口 P (sysctl_Periph_GPIOP),我仍然无法确定原始代码如何成功。 当我尝试它时,程序在随后的 GPIOPinConfigure()中立即崩溃。 (这不是您描述的症状,但可能有线索。)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    所以,我想我已经弄清楚了。

    你说得对,我的代码不应该在没有启用端口 P 的情况下工作,而是没有。 我最初发布的代码不是很完整,而是整个过程的清理版本,因为我没有意识到问题可能出在中断设置之外的任何地方。 我在发布之前确实测试了我发布的内容,但我只关注它是否有效,而没有意识到它可能因其他原因而不起作用。 但实际上,我使用 的是 Kentec K350QVG 显示屏,并且将其连接到主板上。 作为显示屏初始化的一部分,端口 P 已启用,因此,即使我没有明确启用它,它也能按预期工作。

    我最初在代码中遇到的另一件事是包含一些文本和换行字符的 printf()语句,我在发送数据后直接使用了该语句。 我不太确定它对 UART 通信的影响到底有多大,但一旦我删除了换行符,问题就消失了。 但是,字符串不会出现在控制台中,所以我猜刷新只会出现在换行字符上,这会以某种方式干扰 UART 通信。

    现在它可以正确地发送数据,我得到一些数据作为回报。  下次我将手拿一个范围,我将对其进行更多测试,但现在它似乎工作正常。 除了一件事,那就是我应该接收15字节的数据,但我只得到前8个字节,但这是实实在在的进步。

    无论如何,很抱歉你花了这么长时间,我应该先公布所有内容。 尽管如此,谢谢,你真的帮助了我。

    顺便说一句,如果你有任何想法,为什么我只收到15个字节中的8个字节,我希望得到一个提示。 我还没有仔细研究过它,但我是一个初学者,所以任何建议都值得赞赏。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我很高兴你能让它发挥作用。

    您发布的代码仅发送8个字节。 其他7个是如何发送的?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的,我要发送8,但传感器应该发回15。 如果不清楚,很抱歉。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    除非您另有设置,否则 Rx 中断将触发为4/8=8字节,因此我怀疑其他7个字节在 FIFO 中滞留。 [参考 TRM (SLAU723A)表26-12 (RXIFLSEL)。]

    尝试将 Rx FIFO 触发器级别设置为更低,可能如下所示:

    >UARTFIFOLevelSet(UART6_BASE ,UART_FIFO,TX4_8, UART_FIFO,RX1_8);// Tx 触发器4/8=8字节,Rx 触发器1/8=2字节

    您可能仍需要轮询最后一个(奇数)字节,但这应该表明这是否是您正在争夺的 FIFO。

    [编辑:您可能还会从接收超时功能中获得一些使用。 我没有使用它,但它似乎在闲置时间~3字节后触发。 [参考 TRM 第26.3.9节]。]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好,我更改了 FIFO 触发器级别,它的工作方式与你所说的完全一致。 最后一个字节仍停留在 FIFO 中,但幸运的是,接收超时中断为我解决了这个问题。

     但是,在继续我的项目时,我意识到我没有认为接收中断不会在每个单字节上触发,这对我来说是个问题,因为我需要检查每个传入字节之间的延迟以进行错误检查(最多可以是1.5个字符的时间)。 我想使用设置了1.5个字符的计时器来完成此操作,并在每次收到一个字节时重置计时器。

    我通过完全禁用 FIFO 解决了这个问题,因为 TRM 第26.3.8节指出,禁用 FIFO 后,它只是一个1字节的暂存寄存器,基本上是一个长度为1字节的 FIFO。 现在,我得到了每个传入字节的中断。

    因此,我认为这条线程可以闭合。 感谢你的所有帮助。