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.

[参考译文] RM44L520:SPI 从 DMA 中断卡滞

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1004287/rm44l520-spi-slave-dma-interrupt-stuck

器件型号:RM44L520
主题中讨论的其他器件: HALCOGEN

你(们)好

希望你们做得好。

我有一个非常奇怪的问题,我无法解决。 如果您能帮助我快速解决这一问题、我将不胜感激、因为这对于该项目而言非常紧迫。

我在 RM44L520上实现了 SPI 从 DMA 中断。  

每次主器件发送数据时、都会触发中断、这正是我所期望的。  

问题是... 当主器件未发送任何数据时、从器件会停留在以下语句 中、并且从不会从此处退出。 我不明白为什么会发生这种情况。

(*pf_irqFunc)();   /* Execute interrupt routine */

此语句是以下函数的一部分

void irqHandler(uint32_t u32VectorIrqIndex)
{
    t_isrFuncPTR pf_irqFunc = NULL; /* Assign Null address */
    /* Check IrqVector Range */
    if ((u32VectorIrqIndex > (uint32_t)0U) && (u32VectorIrqIndex <= U32_VIM_CHAN_MAX) /* index is valid */)
	{
        pf_irqFunc = vimRAM->ISR[u32VectorIrqIndex]; /* Read IRQ Interrupt Vector */

        /* Save VIM REQENASET[0,1,2,3] Registers for later restore */
        uint32 u32BckupREQMASKSET0 = vimREG->REQMASKSET0;
        uint32 u32BckupREQMASKSET1 = vimREG->REQMASKSET1;
        uint32 u32BckupREQMASKSET2 = vimREG->REQMASKSET2;
        uint32 u32BckupREQMASKSET3 = vimREG->REQMASKSET3;

        /* Mask out lower priority IRQs depending on IRQ index */
        if(U32_VIM_CHAN3_OFFSET < u32VectorIrqIndex) /* Channel 97-127*/
        {
            vimREG->REQMASKCLR3 = ((U32_REG_CLRMASK << (u32VectorIrqIndex - 97U)) & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
        }
        else if (U32_VIM_CHAN2_OFFSET < u32VectorIrqIndex) /* Channel 64-96 */
        {
            vimREG->REQMASKCLR2 = ((U32_REG_CLRMASK << (U32_CHAN_REG2_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR2));
            vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                                               & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
        }
        else if (U32_VIM_CHAN1_OFFSET < u32VectorIrqIndex) /* Channel 32-63 */
        {
            vimREG->REQMASKCLR1 = ((U32_REG_CLRMASK << (U32_CHAN_REG1_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR1));
            vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR2));
            vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
        }
        else if (U32_VIM_CHAN0_OFFSET < u32VectorIrqIndex) /* Channel 2-31 */
        {
            vimREG->REQMASKCLR0 = ((U32_REG_CLRMASK << (U32_CHAN_REG0_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR0));
            vimREG->REQMASKCLR1 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR1));
            vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR2));
            vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR3));
            /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
            vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;

        }
        else    /* FIQ is not executed in this context*/
        {
        	ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
        }


        _enable_IRQ();     /* Enable IRQ, to allow preemption of IRQ routine */

        (*pf_irqFunc)();   /* Execute interrupt routine */

        _disable_IRQ();    /* Disable IRQ, to protect the remainder of the dispatcher from preemption */

        /* Restore VIM REQENASET[0,1,2,3] Registers */
        vimREG->REQMASKSET0 = u32BckupREQMASKSET0;
        vimREG->REQMASKSET1 = u32BckupREQMASKSET1;
        vimREG->REQMASKSET2 = u32BckupREQMASKSET2;
        vimREG->REQMASKSET3 = u32BckupREQMASKSET3;

	}
	else /*index is not valid */
	{
		ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
	}
}

函数指针本身指向..

/* SourceId : DMA_SourceId_019 */
/* DesignId : DMA_DesignId_016 */
/* Requirements: HL_SR181, HL_SR182 */
void dmaBTCAInterrupt(void)
{
    uint32 offset = dmaREG->BTCAOFFSET;

/* USER CODE BEGIN (6) */
/* USER CODE END */

    if (offset != 0U)
    {
        dmaGroupANotification(BTC, offset - 1U);
    }

/* USER CODE BEGIN (7) */
/* USER CODE END */

}

请告诉我您是否需要有关此方面的任何其他信息。

谢谢、祝您愉快。

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

    您好!

    强烈建议不要将嵌套中断用于安全应用。 在 ARM Cortex-R 器件中、CPU 将在进入 IRQ 模式后立即自动禁用 IRQ、以避免嵌套 IRQ。  

    在大多数情况下、不需要嵌套中断。 中断服务例程(ISR)应该很短、并且只执行时间关键型任务。 广泛的计算应该留给主例程、也许 ISR 中会设置一个标志、以通知主循环要处理的新数据。

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

    你(们)好

    感谢您的回复

    我没有任何嵌套中断。 当主器件未发送任何数据时、不会再次触发中断

    请以红色查看以下图像和注释、我使用断点逐步执行代码以将其清除。 我希望能够澄清我的问题。 如果您有任何疑问、请告诉我。  

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

    在之前的代码中、IRQ 在 IRQ 中断服务例程中被重新启用和禁用:

    空 irqHandler (uint32_t u32VectorIrqIndex)

      …………

       _enable_IRQ ();/*启用 IRQ、以允许 IRQ 例程的抢占*

      (*pf_irqFunc)();//执行中断例程*/

      _disable_IRQ ();/*禁用 IRQ、以保护发送程序的其余部分免遭抢占*/

      …

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

    irqHandler (uint32_t u32VectorIrqIndex)是 spna219应用手册中的示例代码。 ARM Cortex-R4/5 (TMS570、RX4x/5x)内核不支持一次获取多个 IRQ。 此示例用于实现具有 SW 的可重入 IRQ 处理程序。

    请为您的应用使用通过 HALCOGen 生成的 SPI 中断服务例程。

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

    非常感谢您的意见。

    此时只有一个中断被启用,并且由于主器件只发送一个数据包,因此也只触发一次,您能否告诉我我们为什么不退出  irqHandler()函数? 为什么我们 总是停留在 (*pf_irqFunc)();

    我通过在 irqHandler()函数的入口放置一个断点来验证中断只触发一次。  

    再次感谢大家。

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

    您好!

    该器件支持 硬件矢量中断(仅限 IRQ)。 如果启用此功能、CPU 接收到一个 IRQ 后、CPU 直接从 带有 VIC 端口的接口读取 ISR 的地址、而不是分支到0x18 (在您的情况下为 irqHandler)。 CPU 将直接分支到 ISR。

    您的代码中是否启用了 VIC? 通过调用 HAL 生成的 API 来启用 VIC:  

     /*通过 Vic 控制器启用 IRQ 偏移*/
    _coreEnableIrqVicOffset_();

    使用 irqHandler 可能需要更多的堆栈大小。 您可以尝试更大的堆栈尺寸吗?

    您的代码中使用了哪个 SPI?  

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

    感谢您的意见、很抱歉我在尝试查看实际原因时迟到的回复

    以下是您的问题的答案

    1) _coreEnableIrqVicOffset_()不会从任何位置调用

    2) 2)如 上一帖子中的图所示、 时间函数为空、因此不是栈问题。

    我要确定的是:

    发送器发送的数据

    void irqHandler(uint32_t u32VectorIrqIndex)
    {
        t_isrFuncPTR pf_irqFunc = NULL; /* Assign Null address */
        /* Check IrqVector Range */
        if ((u32VectorIrqIndex > (uint32_t)0U) && (u32VectorIrqIndex <= U32_VIM_CHAN_MAX) /* index is valid */)
    	{
            pf_irqFunc = vimRAM->ISR[u32VectorIrqIndex]; /* Read IRQ Interrupt Vector */
    
            /* Save VIM REQENASET[0,1,2,3] Registers for later restore */
            uint32 u32BckupREQMASKSET0 = vimREG->REQMASKSET0;
            uint32 u32BckupREQMASKSET1 = vimREG->REQMASKSET1;
            uint32 u32BckupREQMASKSET2 = vimREG->REQMASKSET2;
            uint32 u32BckupREQMASKSET3 = vimREG->REQMASKSET3;
    
            /* Mask out lower priority IRQs depending on IRQ index */
            if(U32_VIM_CHAN3_OFFSET < u32VectorIrqIndex) /* Channel 97-127*/
            {
                vimREG->REQMASKCLR3 = ((U32_REG_CLRMASK << (u32VectorIrqIndex - 97U)) & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
            }
            else if (U32_VIM_CHAN2_OFFSET < u32VectorIrqIndex) /* Channel 64-96 */
            {
                vimREG->REQMASKCLR2 = ((U32_REG_CLRMASK << (U32_CHAN_REG2_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR2));
                vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                                               & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
                vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
            }
            else if (U32_VIM_CHAN1_OFFSET < u32VectorIrqIndex) /* Channel 32-63 */
            {
                vimREG->REQMASKCLR1 = ((U32_REG_CLRMASK << (U32_CHAN_REG1_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR1));
                vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR2));
                vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                          & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
                vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
            }
            else if (U32_VIM_CHAN0_OFFSET < u32VectorIrqIndex) /* Channel 2-31 */
            {
                vimREG->REQMASKCLR0 = ((U32_REG_CLRMASK << (U32_CHAN_REG0_OFFSET(u32VectorIrqIndex))) & (~vimREG->FIRQPR0));
                vimREG->REQMASKCLR1 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR1));
                vimREG->REQMASKCLR2 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR2));
                vimREG->REQMASKCLR3 = ( U32_REG_CLRMASK                         & (~vimREG->FIRQPR3));
                /* Readback Mask to ensure that the previous write was finished before enabling interrupts again */
                vimREG->REQMASKCLR3 = vimREG->REQMASKCLR3;
                vimREG->REQMASKCLR2 = vimREG->REQMASKCLR2;
    
            }
            else    /* FIQ is not executed in this context*/
            {
            	ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
            }
    
    
            _enable_IRQ();     /* Enable IRQ, to allow preemption of IRQ routine */
    
            (*pf_irqFunc)();   /* Execute interrupt routine */
    
            _disable_IRQ();    /* Disable IRQ, to protect the remainder of the dispatcher from preemption */
    
            /* Restore VIM REQENASET[0,1,2,3] Registers */
            vimREG->REQMASKSET0 = u32BckupREQMASKSET0;
            vimREG->REQMASKSET1 = u32BckupREQMASKSET1;
            vimREG->REQMASKSET2 = u32BckupREQMASKSET2;
            vimREG->REQMASKSET3 = u32BckupREQMASKSET3;
    
    	}
    	else /*index is not valid */
    	{
    		ErrHdl_vSetErrCodeDummy; /* Reaction Safe Mode */
    	}
    }

    执行该操作

    (*pf_irqFunc)();   /* Execute interrupt routine */

    调用以下函数

    #pragma CODE_STATE(dmaBTCAInterrupt, 32)
    #pragma INTERRUPT(dmaBTCAInterrupt, IRQ)
    
    /* SourceId : DMA_SourceId_019 */
    /* DesignId : DMA_DesignId_016 */
    /* Requirements: HL_SR181, HL_SR182 */
    void dmaBTCAInterrupt(void)
    {
        uint32 offset = dmaREG->BTCAOFFSET;
    
    /* USER CODE BEGIN (6) */
    /* USER CODE END */
    
        if (offset != 0U)
        {
            dmaGroupANotification(BTC, offset - 1U);
        }
    
    /* USER CODE BEGIN (7) */
    /* USER CODE END */
    
    }

     由于 dmaBTCAInterrupt 函数是一个中断函数、因此编译器会在函数末尾添加以下指令

    SUB     lr, lr, #4

    由于这条指令不是进入  _disable_IRQ ()的下一条指令; 在以下代码中,它再次进入 (*pf_irqFunc)();

     _enable_IRQ();     /* Enable IRQ, to allow preemption of IRQ routine */
    
            (*pf_irqFunc)();   /* Execute interrupt routine */
    
            _disable_IRQ();    /* Disable IRQ, to protect the remainder of the dispatcher from preemption */
     

    所以我所做的是,我 在函数的顶部注释如下,使 dmaBTCAInterrupt()函数成为正常函数。

    //#pragma CODE_STATE(dmaBTCAInterrupt, 32)
    //#pragma INTERRUPT(dmaBTCAInterrupt, IRQ)

    它似乎在工作、但我不确定它是否是正确的方式、您能不能指导我。

    再次感谢您的宝贵时间和支持。

    祝你度过美好的一天!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="467197" URL"~/support/microcontrollers/other-microcontrollers-group/other/f/other-microcontrollers-forum/1004287/rm44l520-spi-slave-dma-interrupt-stuck/3715563 #3715563"]它似乎正常工作,但我不确定它是否是正确的工作方式,您能否为我提供指导。

    如果 要从不同的函数而不是 IRQ 调用 dmaBTCAInterrupt(),则正确的做法是将其定义为"正常"函数,即不使用 INTERRUPT pragma。

    查看 HALCoGen 04.07.01生成的 dmaBTCAInterrupt()函数,它对中断配置的状态很敏感。 在 IRQ 被设定为"矢量模式"时:

    然后、生成的代码具有 IRQ 处理程序的 pragma:

    /** @fn void dmaBTCAInterrupt(void)
    *   @brief DMA Interrupt Handler
    *
    *   Frame transfer complete Interrupt handler for DMA channel routed to Group A
    *
    */
    #pragma CODE_STATE(dmaBTCAInterrupt, 32)
    #pragma INTERRUPT(dmaBTCAInterrupt, IRQ)
    
    /* SourceId : DMA_SourceId_019 */
    /* DesignId : DMA_DesignId_016 */
    /* Requirements: HL_SR181, HL_SR182 */
    void dmaBTCAInterrupt(void)
    {
        uint32 offset = dmaREG->BTCAOFFSET;
    

    如果 IRQ 被更改为"Dispatch Mode"(派单模式)、那么生成的代码是一个正常的函数:

    /** @fn void dmaBTCAInterrupt(void)
    *   @brief DMA Interrupt Handler
    *
    *   Frame transfer complete Interrupt handler for DMA channel routed to Group A
    *
    */
    
    /* SourceId : DMA_SourceId_019 */
    /* DesignId : DMA_DesignId_016 */
    /* Requirements: HL_SR181, HL_SR182 */
    void dmaBTCAInterrupt(void)
    {
        uint32 offset = dmaREG->BTCAOFFSET;