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.

[参考译文] TMS320F28075:启用中断时 SPI 发生故障

Guru**** 2867060 points

Other Parts Discussed in Thread: TMS320F28075

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1038241/tms320f28075-spi-failing-when-interrupt-enabled

器件型号:TMS320F28075

大家好、

我正在使用  TMS320F28075控制器并尝试通过 SPI 与外部闪存器件通信。 在 我启用一个20kHz 中断"appTask"前、一切都正常、代码如下。  这个中断内的代码是关键的、所以我不能将其禁用或缩小。

启用此20kHz 中断后、并非所有数据都能正确写入外部闪存或从外部闪存中正确读取。 只有小块数据被成功写入/读取、且数量是随机的。

看起来中断会干扰 SPI 通信。 我本来以为 SPI 的外设是外部的、并且可以独立于主线程或中断工作。

 是否可以启用以下中断并 使 SPI 通信正常工作? 或者我是否做了一些错误的事情?

如果有任何帮助,将不胜感激。  

// -------------------------- interrupt code --------------------------------------------------

/* Set the interrupt vector */
EALLOW;
{
PieVectTable.TIMER0_INT = &appTask;
}
EDIS;

/* Configure CPU-Timer 0: */
ConfigCpuTimer( &CpuTimer0,
( SYSCLK / 1000000 ),
MAINTENANCE_PERIOD_uS );

CpuTimer0Regs.TCR.all = 0x4000; // Use write-only instruction to set TSS bit = 0

/* Enable CPU int1 which is connected to CPU-Timer 0 */
IER |= M_INT1;

/* Enable TINT0 in the PIE: Group 1 interrupt 7 */
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;

/* Enable global Interrupts and higher priority real-time debug events: */
EINT;
ERTM;

// -------------------------- interrupt code --------------------------------------------------



// ------------------------- SPI port init -----------------------------------------------------

/* Control Register (SPICCR).... 'normal' values
* Clock polarity normal
* Loopback off
* SPI Character length (see SPRUHM9B Table 17-9) 0xF => 16-bits
* SPI High Speed mode disabled (not allowed with selected GPIO - see SPRUHM9B section 17.2.2)
*/
SPI_PORT.SPICCR.bit.CLKPOLARITY = 1;
SPI_PORT.SPICCR.bit.SPILBK = 0;
SPI_PORT.SPICCR.bit.SPICHAR = 0x0F;
SPI_PORT.SPICCR.bit.HS_MODE = 0; //sww12jan16

/* SPI Operation Control Register (SPICTL)....
* Disable rx overrun interrupt
* Clock phase normal
* Master mode
* Transmit enabled
* Enable SPI interrupt
*/
SPI_PORT.SPICTL.bit.OVERRUNINTENA = 0;
SPI_PORT.SPICTL.bit.CLK_PHASE = 1;
SPI_PORT.SPICTL.bit.MASTER_SLAVE = 1;
SPI_PORT.SPICTL.bit.TALK = 1;
SPI_PORT.SPICTL.bit.SPIINTENA = 1;

/* SPI Status Register (SPISTS).... 'normal' values
* Clear any outstanding flags
*/
SPI_PORT.SPISTS.all = 0;

/* SPI Baud Rate Register (SPIBRR)
* max baud rate must be less than the max gpio toggle frequency = 25MHz (See SPRUHM9B section 17.3.5 and SPRS902B section 5.7.6.1)
* and less than the slowest device - TC77 max frequency = 7MHz (could select different rates for different devices)
* For SPIBRR > 2, SPI Baud Rate LSPCLK/(SPIBRR+1), where LSPCLK = SYSCLK/4 = 30Mhz
* For SPIBRR = 0, 1, or 2, baud = LSPCLK/4 = 7.5MHz
*/
SPI_PORT.SPIBRR.bit.SPI_BIT_RATE = 4; /* 30/(4+1) = 6MHz jan16 */

/* SPI FIFO Transmit Register (SPIFFTX)
* 0xE0 => fifo enable; enhancements enable; tx enable
* 0x63 => clear outstanding INT; interrupt on FiFo <=3
* !!DAVEC!! set FiFo for best latency at 5MHz
*/
/* Reset all to default */
SPI_PORT.SPIFFTX.all = 0;
SPI_PORT.SPIFFTX.all = 0xE063;

/* SPI FIFO Receive Register (SPIFFRX)
* 0x60 => clear overflow; rx enable;
* 0x61 => clear outstanding INT; interrupt on FiFo >= 1
*/
/* Reset all to default */
SPI_PORT.SPIFFRX.all = 0;
SPI_PORT.SPIFFRX.all = 0x6061;

SPI_PORT.SPICCR.bit.SPILBK = 0;

/* SPI FIFO Control Register (SPIFFCT)
* Delay between FiFo and transmit Shift Reg.
*/
SPI_PORT.SPIFFCT.bit.TXDLY = 0x00;

/* SPI Priority Control Register (SPIPRI)
* Free-run on emulation suspend
* SPISTE non-inverted (not used here anyway)
* Normal 4-wire SPI mode
*/
SPI_PORT.SPIPRI.bit.FREE = 1;
SPI_PORT.SPIPRI.bit.STEINV = 0;
SPI_PORT.SPIPRI.bit.TRIWIRE = 0;



// --------------------------------------------------------------
感谢你能抽出时间。

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

    Warrick、您好!

    您能否进一步说明您在 SPI 上看到了什么故障? SPI 与什么通信? 如果 SPI 通信延迟、它是否有一些实时要求会中断?

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

    您好、Gus、

    感谢您的快速响应。

    我尝试每秒将大约20字节的数据记录到 IS25LQ512B 闪存器件(随附数据表)。 从数据表中、我看不到有关实时要求或成功交易的最大延时时间的任何信息、但 我可以问制造商您认为问题可能出在哪里?

    启用中断后、我无法始终如一地可靠地将全部20个字节的数据写入外部闪存。 例如、如果我写入20个字节的数据、有时会将10个字节加载到闪存中、有时只会将5个字节加载到闪存中、有时根本不会写入任何字节、有时所有字节都会成功写入闪存。 成功写入的字节数是随机的。 从闪存读取时也会出现类似的问题、即无法从闪存读取所有数据、成功读取的字节数是随机的。 我可以通过示波器图像和其他诊断进行发送、如果这样做有帮助吗?

    如果我启用中断、但注释掉该中断中的所有代码、则读取/写入闪存工作正常。 如果我从该中断中删除所有代码并在中断中添加一个小延迟(仅用于循环)、则再次读取/写入将失败。 因此、它肯定与启用中断和执行中断的时间有关。 遗憾的是、此中断中的代码对我们至关重要、我们无法缩小或禁用该函数。 我还尝试在使用"DINT 和 EINT"读取/写入外部闪存之前禁用中断、但这不起作用。  

    e2e.ti.com/.../IS25LQ512B-Datasheet.pdf

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

    我在闪存器件中看到、一些操作可能需要16个时钟、其他32个时钟、其他操作甚至更多。 整个操作封装在一个 CE#低电平脉冲内。 您如何控制闪存器件的 CE#引脚?  我们通常建议通过 MCU 上的 GPIO 引脚来控制芯片启用。 客户代码会在发送命令之前将芯片选择设置为低电平、然后在完成后将其设置为高电平。 但是、使用 FIFO 将其绑定到 SPISTE 引脚也可以正常工作。 后一种方法更复杂、因为只要 FIFO 中有数据、SPI 只会将 SPISTE 保持在低电平。 如果 CPU 在 SPI FIFO 写入期间中断且 FIFO 变为空、则 SPISTE 引脚可以变为高电平。 对于闪存器件、这将发出命令结束的信号、序列将中断。

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

    您好、Gus、

    我们使用两个 GPIO 引脚、一个用于锁存 A 可级联移位寄存器中、以便我们可以在不同的从器件和另一个从器件之间进行选择、从而使用 CE 引脚启用所选的从器件。 我们不使用 它的自动 SPISTE 从器件芯片选择引脚、而是在正确的位置启用和禁用 CE 引脚。 我认为如果这是错误的、即使禁用了中断、我们也会遇到问题。

    SPI 还使用 “__interrupt void spiTxFifoIsr (void); __interrupt void spiRxFifoIsr (void);”来处理通过 SPI 网络发送和接收数据的问题。  TMS320F28075能够 在 不 影响 SPI 外设的情况下处理这些不同的中断吗?

    感谢你能抽出时间。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="499245" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1038241/tms320f28075-spi-failing-when-interrupt-enabled/3842791 #3842791)]我们使用两个 GPIO 引脚、一个用于锁存 A 可级联移位寄存器中、以便我们可以在不同的从器件和另一个从器件之间进行选择、从而使用 CE 引脚启用所选的从器件。 我们不使用 它的自动 SPISTE 从器件芯片选择引脚、而是在正确的位置启用和禁用 CE 引脚。 我认为如果这是错误的、即使禁用了中断、我们也会遇到问题。

    我只是在使用 SPISTE 的情况下进行推测、但您不使用 SPISTE、这一点很重要。

    [引用 userid="499245" URL"~/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1038241/tms320f28075-spi-failing-when-interrupt-enabled/3842791 #3842791"] SPI 还使用 "__interrupt void spitTxFifoIsr ( void ); __interrupt void spiRxFifoIsr ( void );"来处理通过 SPI 网络发送和接收数据的问题。  TMS320F28075能否 在  不影响 SPI 外设的情况下处理这些不同的中断?

    这完全取决于您构建代码的方式。 我不可能这么说。

    如果您有任何其他调试信息、请告诉我。

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

    您好、Gus、

    感谢您的回复。 即使启用了中断、闪存的读取看起来也能正常工作、因此只有写入在启用20KHz 中断的情况下失败。 这是设置20KHz  appTask  中断的代码。 如果我注释掉"IER |= M_INT1;"行、则写入外部闪存将正常工作。 但是、当这个中断被启用时、写入失败。 上面的帖子中显示了 SPI 初始化。  

    这就是 中断的设置方式、您在这里看到了任何潜在的中断问题吗?

    // ----------------------- 20 KHz interrupt setup -----------------------------
    
    voltageSoftStart.presentLimit = sCConfParam.voltage.softstart.presentLimit;
    voltageSoftStart.slewRate = 0;
    voltageSoftStart.targetLimit = 0;
    
    currentSoftStart.presentLimit = sCConfParam.current.softstart.presentLimit;
    currentSoftStart.slewRate = 0;
    currentSoftStart.targetLimit = 0;
    
    indexMinTresh = 0;
    
    /* Take the current 50Hz AC comparator states and log them.*/
    
    /* Set the interrupt vector */
    EALLOW;
    {
    PieVectTable.TIMER0_INT = &appTask;
    }
    EDIS;
    
    InitCpuTimers();
    
    /* Configure CPU-Timer 0: */
    ConfigCpuTimer( &CpuTimer0,
    ( SYSCLK / 1000000 ),
    MAINTENANCE_PERIOD_uS );
    
    // To ensure precise timing, use write-only instructions to write to the entire register. Therefore, if any
    // of the configuration bits are changed in ConfigCpuTimer and InitCpuTimers (in DSP2803x_CpuTimers.h), the
    // below settings must also be updated.
    
    CpuTimer0Regs.TCR.all = 0x4000; // Use write-only instruction to set TSS bit = 0
    
    /* Enable CPU int1 which is connected to CPU-Timer 0 */
    IER |= M_INT1;
    
    /* Enable TINT0 in the PIE: Group 1 interrupt 7 */
    PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
    
    /* Enable global Interrupts and higher priority real-time debug events: */
    EINT;
    ERTM;
    
    // ---------------------- SPI Tx init -----------------------------------------------
    
    static void spiTxIntInitialise( void )
    {
    /* Set Interrupt service address */
    EALLOW;
    {
    PieVectTable.SPI_TX_VECTOR = &spiTxFifoIsr; /* sww25nov15 was PieVectTable.TX_VECTOR = &spiTxFifoIsr; */
    }
    EDIS;
    
    /* Acknowledge any outstanding interrupt */
    spiTxIntAcknowledge();
    
    /* Enable interrupt group in CPU */
    IER |= SPI_INTGRP; //sww25nov15 was IER |= M_INT6; */  // M_INT6  0x0020
    
    /* Start with interrupts disabled. (nothing going on yet) */
    SPI_RXDIS; /* sww25nov15 was RXDIS; */  // (PieCtrlRegs.PIEIER6.bit.INTx9 = 0)
    SPI_TXDIS; /* sww25nov15 was TXDIS; */  // (PieCtrlRegs.PIEIER6.bit.INTx10 = 0)
    
    /* Enable global Interrupts and higher priority real-time debug events: */
    EINT;
    ERTM;
    }
    
    // ------------------------- SPI Rx init  -------------------------------
    
    static void spiRxIntInitialise( void )
    {
    /* Set Interrupt service address */
    EALLOW;
    {
    PieVectTable.SPI_RX_VECTOR = &spiRxFifoIsr; /* sww25nov15 was PieVectTable.RX_VECTOR = &spiRxFifoIsr; */
    }
    EDIS;
    
    /* Acknowledge any outstanding interrupt */
    spiRxIntAcknowledge();
    
    /* Enable interrupt group in CPU */
    IER |= SPI_INTGRP; //sww25nov15 was IER |= M_INT6; */  // M_INT6  0x0020
    
    /* Start with Rx interrupt disabled. (nothing going on yet) */
    SPI_RXDIS; /* sww25nov15 was RXDIS; */  // (PieCtrlRegs.PIEIER6.bit.INTx9 = 0)
    
    /* Enable global Interrupts and higher priority real-time debug events: */
    EINT;
    ERTM;
    }
    
    // --------------------------SPI Tx ISR -------------------------------------------
    
    __interrupt void spiTxFifoIsr( void )
    {
    #if PERF_PROFILE_GPIO
    /* Profile Mark */
    uP_DIAGNOSTIC4_SET();
    #endif
    
    /* Service Tx buffer */
    while( ( SPI_PORT.SPIFFTX.bit.TXFFST < 2 ) &&
    ( isrTxCount != 0 ) )
    {
    SPI_PORT.SPITXBUF = isrTxBuffer[ isrTxIndex++ ];
    isrTxCount--;
    
    }
    
    /* Finished sending? Disable Tx interrupts */
    if( 0 == isrTxCount )
    {
    SPI_TXDIS; /* sww25nov15 was TXDIS; */
    }
    
    /* Acknowledge Device and CPU interrupt */
    
    /* Clear interrupt flag */
    SPI_PORT.SPIFFTX.bit.TXFFINTCLR = 1;
    
    /* Pie */
    SPI_PIEACK = 1; /* sww25nov15 was PieCtrlRegs.PIEACK.bit.ACK6 = 1; */
    
    #if PERF_PROFILE_GPIO
    /* Profile Mark */
    uP_DIAGNOSTIC4_CLEAR();
    #endif
    
    }
    
    // --------------------------- SPI Rx ISR ------------------------------------------
    
    
    
    __interrupt void spiRxFifoIsr( void )
    {
    uint16_t temp;
    
    #if PERF_PROFILE_GPIO
    /* Profile Mark */
    uP_DIAGNOSTIC4_SET();
    #endif
    
    /* Service Rx buffer */
    /* FiFo Status 0 => empty */
    while( SPI_PORT.SPIFFRX.bit.RXFFST != 0 )
    {
    temp = SPI_PORT.SPIRXBUF;
    
    /* Transfer to client buffer if it is valid */
    if( isrRxBuffer != NULL )
    {
    isrRxBuffer[ isrRxIndex++ ] = temp;
    }
    }
    
    /* Service Rx overrun (prev character lost) */
    if( 1 == SPI_PORT.SPIFFRX.bit.RXFFOVF )
    {
    /* Clear hardware
    * (!! Should really abort txn. as we can't rely on char count
    * if overflow)
    * Indicate overflow status to caller
    * */
    SPI_PORT.SPIFFRX.bit.RXFFOVFCLR = 1;
    //DAVEC: isrRxIndex = isrRxCount;
    isrTxnStatus = SPI_DV_RXOVF;
    }
    
    /* Set Rx FiFo for any remaining characters (max 4 characters) */
    temp = isrRxCount - isrRxIndex;
    if( temp > 1 )
    {
    temp = 1;
    }
    if( temp > 0 )
    {
    SPI_PORT.SPIFFRX.bit.RXFFIL = temp;
    }
    
    /* Finished? (Expected nChars received) */
    else
    {
    /* sww19jan16 if new mux data has just been sent then generate active edge to latch data */
    if( SPI_MUX == isrSpiTarget )
    {
    uP_SPI_MUX_CS_ACTIVE();
    }
    
    /* Flag device ready unless error (=> API transaction complete) */
    if( SPI_DV_BUSY == isrTxnStatus )
    {
    isrTxnStatus = SPI_OK;
    }
    
    /* Disable Rx Interrupts */
    SPI_RXDIS; /* sww25nov15 was RXDIS; */
    
    }
    
    /* Acknowledge device and CPU interrupt */
    spiRxIntAcknowledge();
    
    #if PERF_PROFILE_GPIO
    /* Profile Mark */
    uP_DIAGNOSTIC4_CLEAR();
    #endif
    
    }
    
    static void spiRxIntAcknowledge( void )
    {
    /* Clear port overflow and interrupt flags */
    SPI_PORT.SPIFFRX.bit.RXFFOVFCLR = 1;
    SPI_PORT.SPIFFRX.bit.RXFFINTCLR = 1;
    
    /* Pie */
    SPI_PIEACK = 1; /* sww25nov15 was PieCtrlRegs.PIEACK.bit.ACK6 = 1; */
    }
    static void spiTxIntAcknowledge( void )
    {
    /* Clear interrupt flag */
    SPI_PORT.SPIFFTX.bit.TXFFINTCLR = 1;
    
    /* Pie */
    SPI_PIEACK = 1; /* sww25nov15 was PieCtrlRegs.PIEACK.bit.ACK6 = 1; */
    }
    
    // ---------------------------------------------------------------------

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

    我没有立即看到任何明显的东西。 我在 SPI TX ISR 中看不到用于芯片选择的 GPIO 控制、但我假设这是在其他地方。 这是合理的、我想:其他一些代码负责闪存命令队列、SPITX ISR 仅在 isrTxBuffer 中传输数据。  

    您是否曾尝试将故障隔离为特定或可重复的故障? 也许可以尝试在闪存写入命令期间捕获 SPI 总线信号、看看这些信号是否看起来奇怪或错误?  

    既然您提到添加 ISR 代码(或 ISR 内部的延迟)会中断 SPI 通信、那么您是否已配置此 ISR 代码? 换言之、它为包括 SPI 通信在内的其他任务留出了多少 MIPS? ISR 是否会完全占用所有 CPU 带宽? 我想再次提醒大家、闪存将忽略任何被中断或延迟的写入命令。   

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

    供参考、粘贴代码时可以使用"插入代码"命令。 它使我们能够以1000%的时间更轻松地查看代码。  

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

    Gus、您好、感谢您仔细检查代码、是的、GPIO 控制在其他地方完成-认为 需要发布的代码行太多。

    很抱歉、我没有意识到有一种更简单的方法可以在这里发布代码、我下次会这样做。  

    我确实检查了 ISR 使用的 CPU 时间、它的使用时间低于我的预期。 因此、我认为还有足够的时钟周期用于其他任务。 不过、我将再次检查、并尝试使用示波器捕获故障数据包、希望这将为我提供有关故障发生方式的更多信息。

    感谢您抽出宝贵时间参加本次活动。

    此致、

    Warrick