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.

[参考译文] EK-TM4C123GXL:SSI_TXEOT 中断

Guru**** 2445440 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/630889/ek-tm4c123gxl-ssi_txeot-interrupt

器件型号:EK-TM4C123GXL

有人能不能向我解释一下 TM4C123x 的勘误表 SS#07。 SPMZ849F 文档中对此进行了介绍(链接)。

当 SSI 完成发送(SSI_TXEOT)时、我尝试获取中断。 无论我尝试什么、我都不会获得中断、或者得到无限量的中断。

设置 SSI0的代码:

void
PinoutSet (void)
{
//启用外设时钟。
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);

// PA[5:2]用于 SSI0。
MAP_GPIOPinConfigure (GPIO_PA2_SSI0CLK);
MAP_GPIOPinConfigure (GPIO_PA3_SSI0FSS);
MAP_GPIOPinConfigure (GPIO_PA4_SSI0RX);
MAP_GPIOPinConfigure (GPIO_PA5_SSI0TX);
MAP_GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
GPIO_PIN_2);
} 

初始化 SSI0的代码:

//启用 SSI0
MAP_SysCtlPeripheralDisable (SYSCTL_Periph_SSI0);
MAP_SysCtlPeripheralReset (SYSCTL_Periph_SSI0);
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
while (!MAP_SysCtlPeripheralReady (SYSCTL_SSIP0)

;SYSCTL_SysCtlPeripheralReady (SYSCIPH/ Configure) 1MHz、8位数据、主控模式。
SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_TI、SSI_MODE_MASTER、1000000、 8);

//启用 SSI0模块。
SSIEnable (SSI0_BASE);

//启用中断
SSIIntDisable (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXINT);
SSIIntClear (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXOT | SSI_RXOT | SSI_RXOT | SSIOR_RXINT);SSIOR_0
(SSIREG_RESPONIFn)+ SSIOR_RESPONIFT/ SSIOR= SSIOR_RESPONIFT/ SSIOR_RESPONIFG (SSIOR_RESPONIFG)


和中断处理程序:

void
SSI0IntHandler (void)
{
volatile unsigned long status = 0;

STATUS = SSIIntStatus (SSI0_BASE、TRUE);
SSIIntClear (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR);

// HWREG (SSI0_BASE + SSI_O_IM)&&~SSI_IM_TXIM;
} 

当我确实得到无限量的中断时;状态被设置为8。

有什么提示/技巧可以帮助您解决这个问题? 或者、我是否误解了勘误表、这是不可能的?

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

    在 SSI0IntHandler()中,可以在 SSIIntClear ()之后读回 SSIMIS 寄存器。 基本上如下代码所示。 我怀疑这是一个竞争条件、在你尝试清除中断标志后、你立即退出 ISR。 物理清除这些标志需要一些周期、但您已经退出 ISR。 在这些标志被实际清除之前、中断仍在等待 NVIC、并重新进入 ISR。 通常情况下、您会有一些代码来处理数据、例如在清除中断标志后重新加载 FIFO。 这些指令将需要足够的周期来完成中断标志的清零。 请尝试一下、看看它是否有所不同。 希望这就是问题、如果不是这样、我们将进一步调试。

    STATUS = SSIIntStatus (SSI0_BASE、TRUE);
    SSIIntClear (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR);
    STATUS = SSIIntStatus (SSI0_BASE、TRUE);
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Charles:

    遗憾的是、中断服务例程中花费的时间不足以让处理器清除该标志。 我已扩展代码并将其全部粘贴到下面。

    #include 
    #include 
    include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_NVIC.h"
    #include "Filename/hw_types.h"
    #include "inc/hw_ssi.h"
    #include "driverlib/driverlib#driverlib"
    #driverlib#driverlib_driverlib#driverlib#driver.h"
    
    #include "driverlib#driverlib#driverlib#driverlib_driverlib#driverlib#driverlib#driverlib#driverlib#driver.h"#include "#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driver.h"
    
    
    
    
    
    
    
    
    
    
    #include "#driverlib#driverlib#driverlib#driver.h"#include "#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driverlib#driver.h"#include "#driverlib#driv
    
    
    
    
    
    
    
    
    
    
    //启用外设时钟。
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
    
    // PA[1:0]用于 UART0 (ICDI)。
    MAP_GPIOPinConfigure (GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure (GPIO_PA1_U0TX);
    MAP_GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
    
    // PA[5:2]用于 SSI0。
    MAP_GPIOPinConfigure (GPIO_PA2_SSI0CLK);
    MAP_GPIOPinConfigure (GPIO_PA3_SSI0FSS);
    MAP_GPIOPinConfigure (GPIO_PA4_SSI0RX);
    MAP_GPIOPinConfigure (GPIO_PA5_SSI0TX);
    MAP_GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
    GPIO_PIN_2);
    }
    
    
    void
    SSI0IntHandler (void)
    {
    uint32_t ui32Status;
    
    //读取 SSIMIS (SSI 掩码后中断状态)
    ui32Status = SSIIntStatus (SSI0_BASE、TRUE);
    SSIIntClear (SSI0_BASE、ui32Status);
    
    //清除 SSIIM.TXIM 以停止进一步的中断
    HWREG (SSI0_BASE + SSI_O_IM)&=~(SSI_IM_TXIM);
    
    //小延迟
    ROM_SysCtlDelay (10);
    
    UARTprintf ("ISR:ui32Status =%x\n"、ui32Status);
    }
    
    
    void
    ConsoleInit (void)
    {
    //启用 UART0
    MAP_SysCtlPeripheralDisable (SYSCTL_Periph_UART0);
    MAP_SysCtlPeripheralReset (SYSCTL_Periph_UART0);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
    while (!map_SysCtlPeripheralReady (SYSCTL_Periph_UART0));
    
    //使用内部16MHz 振荡器作为 UART 时钟源。
    MAP_UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);
    
    //初始化控制台 I/O 的 UART
    UARTStdioConfig (0、115200、16000000);
    }
    
    
    int
    main (void)
    {
    uint32_t ui32DataRx;
    
    //将系统时钟设置为以40MHz 的频率从 PLL 运行。
    ROM_SysCtlClockSet (SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz |
    SYSCTL_OSC_MAIN);
    
    //配置器件引脚。
    PinoutSet();
    
    //启用和初始化 UART。
    ConsoleInit();
    
    //调试
    UARTprintf ("\n\n 启用 SSI0\n");
    
    //启用 SSI0
    MAP_SysCtlPeripheralDisable (SYSCTL_Periph_SSI0);
    MAP_SysCtlPeripheralReset (SYSCTL_Periph_SSI0);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
    while (!map_SysCtlPeripheralReady (SYSCTL_Periph_SSI0));
    
    //配置 SSI、1MHz、8位数据、主控模式。
    SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MODE_0、
    SSI_MODE_MASTER、1000000、8);
    
    //启用 SSI0模块。
    SSIEnable (SSI0_BASE);//等式。 更改为 HWREG (SSI0_BASE + SSI_O_CR1)|= SSI_CR1_SSE;
    UARTprintf ("SSI0已启用\n");
    
    //启用 SSI TX EOT 中断
    IntEnable (INT_SSI0);
    SSIIntEnable (SSI0_BASE、SSI_TXFF);//等式。 更改为 HWREG (SSI0_BASE + SSI_O_IM)|= SSI_TXFF;
    HWREG (SSI0_BASE + SSI_O_CR1)|= SSI_CR1_EOT;// TXFF 中断变为 EOT 中断
    IntMasterEnable();
    UARTprintf ("启用的中断\n");
    
    //从 SSI 端口读取任何残留数据。
    while (SSIDataGetNonBlocking (SSI0_BASE、&ui32DataRx);
    UARTprintf ("剩余数据读取\n");
    
    //为下一轮设置 SSIIM.TXIM 位
    HWREG (SSI0_BASE + SSI_O_IM)|= SSI_IM_TXIM;
    UARTprintf ("SSIIM.TXIM set\n");
    
    //将单字节写入 SSI FIFO
    SSIDataPut (SSI0_BASE、0x000000ab);
    UARTprintf ("FIFO 已加载\n");
    
    //忙等待循环;在 UARTprintf 之前等待中断
    while (SSIBusy (SSI0_BASE));
    UARTprintf ("完成写入\n");
    
    //读取一个字节
    SSIDataGet (SSI0_BASE、\ui32DataRx);
    UARTprintf ("SSI 事务已完成\n"\n);
    
    //睡眠1
    ROM_SysCtlDelay (ROM_SysCtlClockGet ()/3);
    UARTprintf ("延迟结束\n");
    
    //禁用处理器的中断;循环永远
    ROM_IntMasterDisable();
    while (1)
    {
    }
    } 

    ISR 中现在有一个 SysCtlDelay 和一个 UARTprintf。 这应该是处理器清除中断标志的足够时间。

    控制台的输出为:

    启用 SSI0
    SSI0使能
    ISR:ui32Status = 8
    中断被启用
    剩余数据读取
    SSIIM.TXIM 置位
    ISR:ui32Status = 0
    FIFO 已加载
    完成写入
    SSI 传输完成
    延迟结束

    我觉得奇怪的是、中断在启用中断后立即触发(在 UARTprintf 能够输出"中断已启用"之前)。 第一次 ui32Status = 8时、看起来是正确的(尽管这里没有 EOT)。 我清除了 ISR 内部的 SSIIM.TXIM 以停止大量中断。 如果我再次置位 TXIM 位、似乎现在中断确实在 EOT 被触发、但是 ui32Status = 0... (即没有中断?)。

    要继续...

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Andrew:
    我可以复制您的结果、并在明天投入更多时间。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Andrew:

     同样、您看到 ui32Status 为零的位置是 条件2的 SSI 勘误表7的结果。  

     

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

    您好、Charles、

    我设法使 EOT 中断工作。 请参阅下面的示例代码;如果有人遇到类似的问题、可能会很有用。 我仍然必须使用示波器通过比较 SPI CS 线路(PA3)和 PF3来确认时序、但我不会想到会出现问题。

    使我脱离保护的原因是、在启用 SSI_TXFF 中断之前、您首先需要设置 SSICR1中的 EOT 位、否则它将立即调用 ISR。 轻松的陷阱:-) 如果在条件2中工作、则无需变通办法(清除 SSIIM.TXIM);只需注意 SSIIntStatus 将返回0。 在这方面,文件可能更加明确。

    感谢您的支持!

    #include 
    #include 
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_NVIC.h"
    #include "inc/hw_types.h"
    #include "driverlib/driverlib"#driverlib/smis.h"
    
    
    #include "driverlib/driverlib#driver.h"#include "driverlib.driverlib#driver.h"#include "driverlib.driverlib#driverlib#driverlib.driver.h"#include "driverlib#driverlib.driverlib#driverlib.driver.h"#include "driverlib#driverlib.driverlib#driverlib.driver.h"#include "driverlib#driverlib.driverlib.driverlib#driverlib.driver.h"#include
    
    
    
    
    
    
    
    
    
    
    "driver.h"#include "driverlib#driverlib.driverlib.driverlib#driverlib.driverlib#driverlib.
    volatile uint32_t g_ui32IntCounter;
    
    void
    PinoutSet (void)
    {
    //启用外设时钟。
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF);
    
    // PA[1:0]用于 UART0 (ICDI)。
    MAP_GPIOPinConfigure (GPIO_PA0_U0RX);
    MAP_GPIOPinConfigure (GPIO_PA1_U0TX);
    MAP_GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
    
    // PA[5:2]用于 SSI0。
    MAP_GPIOPinConfigure (GPIO_PA2_SSI0CLK);
    MAP_GPIOPinConfigure (GPIO_PA3_SSI0FSS);
    MAP_GPIOPinConfigure (GPIO_PA4_SSI0RX);
    MAP_GPIOPinConfigure (GPIO_PA5_SSI0TX);
    MAP_GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
    GPIO_PIN_2);
    
    // PF3用于指示 ISR 退出。
    MAP_GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_3);
    }
    
    void
    SSI0IntHandler (void)
    {
    uint32_t ui32Status;
    
    //读取 SSIMIS (SSI 掩码后中断状态)
    ui32Status = SSIIntStatus (SSI0_BASE、TRUE);
    SSIIntClear (SSI0_BASE、ui32Status);
    
    //递增中断计数器。
    G_ui32IntCounter++;
    
    //切换 PF3以指示中断处理程序退出。
    ROM_GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_3、
    (ROM_GPIOPinRead (GPIO_PORTF_BASE、GPIO_PIN_3)^
    GPIO_PIN_3);
    }
    
    void
    SPIInit (void)
    {
    //启用 SSI0
    MAP_SysCtlPeripheralDisable (SYSCTL_Periph_SSI0);
    MAP_SysCtlPeripheralReset (SYSCTL_Periph_SSI0);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
    while (!map_SysCtlPeripheralReady (SYSCTL_Periph_SSI0));
    
    //配置 SSI、1MHz、8位数据、主控模式。
    SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MODE_0、
    SSI_MODE_MASTER、1000000、8);
    
    //启用 SSI0模块。
    SSIEnable (SSI0_BASE);
    
    //为 TXRIS 中断启用发送结束中断模式。
    HWREG (SSI0_BASE + SSI_O_CR1)|= SSI_CR1_EOT;
    
    //启用 SSI0中断。
    IntEnable (INT_SSI0);
    
    //启用 SSI_TXEOT 中断源。
    SSIIntEnable (SSI0_BASE、SSI_TXFF);
    }
    
    void
    SSIEOTTestCase (void)
    {
    }
    
    void
    ConsoleInit (void)
    {
    //启用 UART0
    MAP_SysCtlPeripheralDisable (SYSCTL_Periph_UART0);
    MAP_SysCtlPeripheralReset (SYSCTL_Periph_UART0);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
    while (!map_SysCtlPeripheralReady (SYSCTL_Periph_UART0));
    
    //使用内部16MHz 振荡器作为 UART 时钟源。
    MAP_UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);
    
    //初始化控制台 I/O 的 UART
    UARTStdioConfig (0、115200、16000000);
    }
    
    
    
    int
    main (void)
    {
    uint32_t ui32长度;
    uint32_t ui32Index;
    
    //将系统时钟设置为以40MHz 的频率从 PLL 运行。
    ROM_SysCtlClockSet (SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz |
    SYSCTL_OSC_MAIN);
    
    //配置器件引脚。
    PinoutSet();
    
    //启用和初始化 UART。
    ConsoleInit();
    
    //启用和初始化 SPI 接口。
    SPIInit();
    
    //启用到处理器的中断。
    ROM_IntMasterEnable();
    
    //编写长度不同的消息。 中断只能在结束时发生
    传输的//。
    for (ui32Length = 1;ui32Length <= 10;ui32Length ++)
    {
    //重置中断计数器。
    G_ui32IntCounter = 0;
    
    ui32Index = ui32Length;
    while (ui32索引)
    {
    SSIDataPut (SSI0_BASE、ui32Index);
    ui32Index--;
    }
    while (SSIBusy (SSI0_BASE));//应在此处发生中断
    
    //验证中断只触发一次。
    if (g_ui32IntCounter!= 1)
    {
    UARTprintf ("ui32Length =%d、g_ui32IntCounter =%d\n"、
    ui32Length、g_ui32IntCounter);
    }
    }
    UARTprintf ("完成了。\n");
    
    //禁用处理器的中断;循环永远
    ROM_IntMasterDisable();
    while (1)
    {
    }
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Andrew:
    很高兴问题得到解决、感谢大家分享技巧、在为条件2启用 TXFF 中断之前先设置 EOT 位。