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.

[参考译文] TMS320F280049:启用和禁用 SCI 中断

Guru**** 2482105 points
Other Parts Discussed in Thread: C2000WARE

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1441339/tms320f280049-sci-interrupts-enable-and-disable

器件型号:TMS320F280049
Thread 中讨论的其他器件:C2000WARE

工具与软件:

您好!

我正在使用 Launchpad F280049电路板、我正在尝试了解如何使用中断来实现 SCI 与主机的通信。 使用和修改的示例是 位于(C:\ti\c2000\C2000Ware_5_01_00_00\driverlib\f28004x\examples\sci)的 sci_ex2_interrupts.c。  

为了直接到达这个点、当我尝试从主机发送一个字符数组时、SCIRX 中断会执行它的工作、接收这些字符并将它们发回。 即使 ISR 例程的作业已完成、也会再次调用 RX 中断。 但在本例中、我不会向 RX 发送任何字符、因此 readCharArray 函数只会一直等待、因此 ISR 绝不会返回。

SCIRX 和 SCITX ISR 例程

__interrupt void
sciaTxISR(void)
{
    //
    // Disable the TXRDY interrupt.
    //
    SCI_disableInterrupt(SCIA_BASE, SCI_INT_TXRDY);

    msg = "\r\nEnter a character: \0";
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 22);

    //
    // Ackowledge the PIE interrupt.
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

__interrupt void
sciaRxISR(void)
{

    //
    // Enable the TXRDY interrupt again.
    //

    SCI_enableInterrupt(SCIA_BASE, SCI_INT_TXRDY);

    //
    // Read a character from the RXBUF.
    // MSG_LENGTH = 10 characters
    SCI_readCharArray(SCIA_BASE, msgreceive, MSG_LENGTH); // HERE IS THE PROBLEM

    //
    // Echo back the character.
    //
    msg = "You sent: ";
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13);
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msgreceive, MSG_LENGTH);


    //recievemsg = (uint16_t)(HWREGH(SCIA_BASE + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
    //
    // Acknowledge the PIE interrupt.
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

    counter++;
}

当我尝试在 ISR 内部禁用 RX 中断并 在 TX ISR 内部启用该中断时、RX ISR 绝不会卡住调用、而去接收字符并正确退出。

__interrupt void
sciaTxISR(void)
{
    //
    // Disable the TXRDY interrupt.
    //

    SCI_disableInterrupt(SCIA_BASE, SCI_INT_TXRDY);
    SCI_enableInterrupt(SCIA_BASE, SCI_INT_RXRDY_BRKDT); //ENABLE RX INTERRUPT

    msg = "\r\nEnter a character: \0";
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 22);

    //
    // Ackowledge the PIE interrupt.
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

}

//
// sciaRxISR - Read the character from the RXBUF and echo it back.
//
__interrupt void
sciaRxISR(void)
{

    //
    // Enable the TXRDY interrupt again.
    //
    SCI_disableInterrupt(SCIA_BASE, SCI_INT_RXRDY_BRKDT); // DISABLE RX INTERRUPT
    SCI_enableInterrupt(SCIA_BASE, SCI_INT_TXRDY);

    //
    // Read a character from the RXBUF.
    //
    SCI_readCharArray(SCIA_BASE, msgreceive, MSG_LENGTH);

    //
    // Echo back the character.
    //
    msg = "You sent: ";
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13);
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msgreceive, MSG_LENGTH);


    //recievemsg = (uint16_t)(HWREGH(SCIA_BASE + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
    //
    // Acknowledge the PIE interrupt.
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

    counter++;
}

我的问题是:为什么以这种方式禁用和启用中断有效? 即使 SCIRXBUF 寄存器中没有字符、程序如何在第一种情况下再次调用 ISR?
我希望我能清楚地介绍所有内容、但如果没有、我很乐意提供更多详细信息。

谢谢你。

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

    您好!

    您是否修改了 SCI 配置? 如果中断被触发、则会被调用、因此要查看的寄存器是 SCI RX 寄存器-这是否为非 FIFO 模式、取决于 RX 状态位? 您是否已逐步执行代码并观察 SCI 寄存器以了解行为是如何的以及/或对 SCI 线路的作用域以确保信号符合预期?

    顺便说一下、如果您使用 FIFO 模式、RX 和 TX 中断将完全取决于 FIFO 中字符的级别、例如、将在接收预配置数量的字符时触发(例如、如果 RXFFIL = 2、则在 RX FIFO 中填充2个完整字符时将触发 RX 中断)。

    如果您在 RX ISR 中禁用 RX 中断、请确保在首先跳转到 TX ISR 之前不能调用 RX 中断。 在这种情况下、当您向缓冲区写入数据以便发送时、这会导致一个到 TX ISR 的跳转、并在接收到 RX ISR 时使能该 ISR。

    此致、

    Allison

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

    我使用的是 C2000WARE 库中的这个示例。  "C:\ti\c2000\C2000Ware_5_01_00_00\driverlib\f28004x\examples\sci\sci_ex2_interrupts.c"

    我修改的只是这组线

    //
    // Read a character from the RXBUF.
    //
    receivedChar = SCI_readCharBlockingNonFIFO(SCIA_BASE);
    
    //
    // Echo back the character.
    //
    msg = "  You sent: \0";
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13);
    SCI_writeCharBlockingNonFIFO(SCIA_BASE, receivedChar);

    解决方案:

    //
    // Read a character from the RXBUF.
    //
    SCI_readCharArray(SCIA_BASE, msgreceive, MSG_LENGTH);
    
    //
    // Echo back the character.
    //
    msg = "  You sent: \0";
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msg, 13);
    SCI_writeCharArray(SCIA_BASE, (uint16_t*)msgreceive, MSG_LENGTH);

    ISR 内的任务。  唯一的区别是,第一个我只是回显一个字符,第二个,我试图回显 MSG_LENGTH 字符数组。

    我在这里使用不基于 FIFO 的通信、配置如下所示:

     //
        // Map the ISR to the wake interrupt.
        //
    Interrupt_register(INT_SCIA_TX, sciaTxISR);
    Interrupt_register(INT_SCIA_RX, sciaRxISR);
    
    SCI_performSoftwareReset(SCIA_BASE);
    
    SCI_disableModule(SCIA_BASE);
    
    HWREGH(SCIA_BASE + SCI_O_HBAUD) = 0;
    HWREGH(SCIA_BASE + SCI_O_LBAUD) = 0;
    HWREGH(SCIA_BASE + SCI_O_CCR) = ((HWREGH(SCIA_BASE + SCI_O_CCR) &
                                     ~(SCI_CONFIG_PAR_MASK |
                                       SCI_CONFIG_STOP_MASK |
                                       SCI_CONFIG_WLEN_MASK)) | (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));
    
    SCI_resetChannels(SCIA_BASE);
    SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_TXRDY | SCI_INT_RXRDY_BRKDT);
    SCI_enableModule(SCIA_BASE);
    SCI_performSoftwareReset(SCIA_BASE);
    
    //
    // Enable the TXRDY and RXRDY interrupts.
    //
    SCI_enableInterrupt(SCIA_BASE, SCI_INT_TXRDY | SCI_INT_RXRDY_BRKDT);

    如果您在 RX ISR 中禁用 RX 中断、请确保在首先跳转到 TX ISR 之前不能调用 RX 中断。 在这种情况下、当您向缓冲区写入数据以便发送时、这会导致一个到 TX ISR 的跳转、并在接收到 RX ISR 时使能该 ISR。

    这就是 具体情况、 这样禁用和启用中断会起作用、我将尝试理解原因。 为何应禁用和启用? 我收到之后字符数组是否应该为空以便它永远不会再次调用 ISR (我指的是第二个代码片段)?

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

    尊敬的 Shriram:

    Allison 目前不在办公室,直到节假日结束。 请预计响应会有延迟。 感谢您的耐心。

    此致、

    Aishwarya.

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

    你好、Shiram、

    对于延迟延长、我们深表歉意。 "你是什么人?

    下面添加了仅针对上下文的 driverlib 说明、二者非常相似(在 NonFIFO 中)、只是增加了数据量。

    SCI_readCharBlockingNonFIFO:

    //*****************************************************************************
    //
    //! Waits for a character from the specified port when the FIFO enhancement
    //! is not enabled.
    //!
    //! \param base is the base address of the SCI port.
    //!
    //! Gets a character from the receive buffer for the specified port.  If there
    //! is no characters available, this function waits until a character is
    //! received before returning.
    //!
    //! \return Returns the character read from the specified port as \e uint16_t.
    //
    //*****************************************************************************
    static inline uint16_t
    SCI_readCharBlockingNonFIFO(uint32_t base)
    {
        //
        // Check the arguments.
        //
        ASSERT(SCI_isBaseValid(base));
    
        //
        // Wait until a character is available in the receive FIFO.
        //
        while(!SCI_isDataAvailableNonFIFO(base))
        {
        }
    
        //
        // Return the character from the receive buffer.
        //
        return((uint16_t)(HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M));
    }

    SCI_readCharArray:

    //*****************************************************************************
    //
    // SCI_readCharArray
    //
    //*****************************************************************************
    void
    SCI_readCharArray(uint32_t base, uint16_t * const array, uint16_t length)
    {
        //
        // Check the arguments.
        //
        ASSERT(SCI_isBaseValid(base));
    
        uint16_t i;
        //
        // Check if FIFO enhancement is enabled.
        //
        if(SCI_isFIFOEnabled(base))
        {
            //
            // FIFO is enabled.
            // For loop to read (Blocking) 'length' number of characters
            //
            for(i = 0U; i < length; i++)
            {
                //
                // Wait until a character is available in the receive FIFO.
                //
                while(SCI_getRxFIFOStatus(base) == SCI_FIFO_RX0)
                {
                }
    
                //
                // Return the character from the receive buffer.
                //
                array[i] = (uint16_t)
                           (HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
            }
        }
        else
        {
            //
            // FIFO is not enabled.
            // For loop to read (Blocking) 'length' number of characters
            //
            for(i = 0U; i < length; i++)
            {
                //
                // Wait until a character is available in the receive buffer.
                //
                while(!SCI_isDataAvailableNonFIFO(base))
                {
                }
    
                //
                // Return the character from the receive buffer.
                //
                array[i] = (uint16_t)
                           (HWREGH(base + SCI_O_RXBUF) & SCI_RXBUF_SAR_M);
            }
        }
    }
    

    在原始未修改的示例中:首先触发器件以进入 TX ISR、禁用 TX 中断、因此不会 重复发送消息到主机 PC。 器件将空闲、直到用户 写入一个要被器件接收的字符时被触发。 接收时、器件将进入 RX ISR、然后该 ISR 会将该字符写回主机、并允许在空闲前出现另一个 TX ISR、再次等待接收。  

    我希望您的情况也能有类似的行为。  您是否逐行逐个检查代码以观察/确认行为? 您是否还审阅了 SCI 波形以了解 RX 线路上是否存在行为?

    此致、

    Allison

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

    您好!

    "禁用 TX 中断、以使其不会 向主机 PC 重复发送消息。 器件将空闲、直到用户 写入一个字符以供器件接收"。

    这正是我所寻找的。 为什么我们需要禁用中断内部的中断? 除非我们发送一个字符、怎么才能再次调用中断?

    在最初的示例中、TX 中断被禁用、而 RX 中断不是被禁用。 我修改了示例、禁用了 RX 中断、以使其正常工作。 为什么会这样呢?

    是的、我确实对代码进行了调试以查看我是否可以捕获异常、但每次都只会在读取字符数组后跳转到下一个 RX ISR 调用。

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

    尊敬的 Shriram:

    让我来回答您的第一个问题:

    为什么需要在中断内部禁用中断?

    这是因为该 示例希望向用户发送一条消息、然后等待用户的响应(等待接收一个字符)、然后再次触发 TX ISR 以(再次)提示用户输入一个字符。 请注意、SCI 发送器通过 SCICTL2寄存器 标志位 TXRDY 指示有效中断状态。 因此、本质上、TXRDY 位决定何时触发 TX 中断-这就是我们要 在本示例中启用/禁用的原因。

    如果您查看 TXRDY 的寄存器描述、您将看到在 SCITXBUF 缓冲区为空(已准备好写入以传输下一个字符)时、TXRDY 位设置为"1"。 该位为1时、只要中断使能位也被置位、该标志就会使发送器中断请求有效。 因此、如果在您完成第一条消息的发送后 TXRDY 中断仍然启用、那么在发送消息后、TXBUF 将变为空、这实际上会立即触发另一个 TX 中断(在中断被确认后)、同时等待用户发回一个字符。

    请注意、有几种不同的方法可以完成此示例的操作。 这只是其中一个在非 FIFO 模式下展示 SCI 中断应用的引脚。

    每次读取字符数组后、它都会跳至下一个 RX ISR 调用

    关于这一点、您是否看到从 RXBUF 读取后 RXRDY 标志正确清零? 此位控制接收器中断线路。

    此致、

    Allison

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    关于这一点、您是否看到从 RXBUF 读取后 RXRDY 标志正确清零? 此位控制接收器中断线路。[/QUOT]

    当我处于调试模式时、RXRDY 标志根本不置位(始终为0)。

    "数据被从 RXSHF 转移到接收器缓冲寄存器(SCIRXBUF);请求中断。 标志位
    RXRDY (SCIRXST、位6)变为高电平以指示已接收到新字符。"

    以上内容摘自技术参考手册。 根据此规范、程序应该只有在我发送下一个字符时才接收中断。 如果我要从主机 PC 发送10个字符并按10个字符调用 readCharArray、则读取最后一个字符后的 RXRDY 应该是0、这符合预期。 但程序被卡在这个部分,在这里,它等待第11个字符(这是不存在的):

    // Wait until a character is available in the receive FIFO.
    //
    while(!SCI_isDataAvailableNonFIFO(base))
    {
    }

    位于 RX ISR 内。 因此、除非再次调用 ISR、否则程序无法发出此无限循环以等待接收下一个字符。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    当我处于调试模式时、根本不设置 RXRDY 标志(始终为0)。

    有时、我可以看到它正在设置、但这取决于我设置断点的位置。 当 ISR 第二次运行时(不应该运行)、它始终为0。

    最新动态:

    因此、我能够在不同的调试点将 RXRDY 设为1、但我必须守门员来准确地获取该签名。 但是、当我从 PC 发送10个字符并期望固件中包含10个字符(第一个帖子中提供的代码)时、为什么 RXRDY 始终显示为1?

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

    尊敬的 Shriram:

    RXRDY 取决于 RXBUF 的状态、因此它应该在每次读取后(并在接收到 RXBUF 的下一个字符之前)清零。 如果连续接收到背靠背数据、且 CCS 刷新无法捕获数据、则可能无法清除 RXRDY 位、具体取决于调试方式。 注意事项:

    1. 我会注意到的另一种调试方法是使用所谓的 硬件观察点 (如果您过去尚未使用该功能)、这样您就可以在对存储器进行读取/写入访问时暂停。  
    2. 我想强调的是、RX 中断线路由 TXRDY 和 BRKDT 触发-您是否看到中断 检测位发生了任何变化?

    我将~我是否可以运行与您类似的代码、并确定我是否在接下来的1 μ s 天内看到类似的行为。  

    此致、

    Allison

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

    尊敬的 Shriram:

    我将从 C2000Ware 运行 SCI 示例2中断的一个版本、并进行类似修改(使用与您相同的 driverlib 函数传输10个字符)。  

    借助于这个设置、当您写入第一个字符时、由于您处于非 FIFO 模式、CPU 将立即跳转到 RX ISR、并且 RX 中断标志将用一个已准备好被读取的字符进行设定。 不过、之后用户需要继续键入字符(发送到 C2000)、以满足 READ_CharArray 函数 MSG 长度要求(消息长度为10)。 只要您在串行终端中输入另一个字符、就会立即出现另一个挂起的 RX 中断标志。 由于我们不会禁用 RX 中断或清除中断路径上的所有标志(从 SCI -> PIE -> CPU 级别)、因此这会导致程序在之后跳回到下一个 RX ISR。 这也是因为 SCIRX 中断的优先级高于 SCITX、因此即使设置了 TX 中断标志、程序也会继续跳转到 RX ISR、这是您可以看到的。

    然后、我通过在 RX ISR 开始时禁用 RX 中断(并在 TX ISR 内重新启用)来修改此示例。 就像您刚才暗示的那样。 这样就不会重复调用 RX ISR。 它将一直等到 TX ISR 被首先执行、然后才允许下一个 RX ISR 发生。

    要重新迭代、还有其他更简洁的方法来实现这一点、例如利用 FIFO 模式+中断、但希望这可以消除您一直困惑的地方:如果您使用数组函数发送多个字符、为什么需要禁用 RX INT。  

    附件是我修改后的示例、可供您进行比较:

    e2e.ti.com/.../sci_5F00_ex2_5F00_interrupts.zip

    此致、

    Allison