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.

[参考译文] TM4C123GH6PM:对半满或半满 TX FIFO 以及其他 SSI 中断的说明

Guru**** 2523080 points
Other Parts Discussed in Thread: TM4C123GH6PM

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1285826/tm4c123gh6pm-clarity-on-tx-fifo-half-full-or-less-and-other-ssi-interrupts

器件型号:TM4C123GH6PM

大家好!

我正在为 TM4C123GH6PM MCU 开发一种中断驱动 SSI (SPI)驱动程序、我看到了一些有关中断生成的奇怪行为。 首先、我想在传输完成时触发一个中断、该标志为 SSI_TXEOT (值为0x40)。 TM4C123的数据表指出此中断应该可用、但仔细查看屏蔽的中断状态寄存器(SSIMIS)时、我们只能访问前3位、 根据 EOT 位、似乎第三位与 FIFO 半空或少于半空或 TX 完成共享一个中断条件。 在这种情况下、EOT 位是什么? 我不知道该怎么说。"

其次、当我为 FIFO 半满或少于半满条件启用中断(值为0x08的 SSI_TXFF)时、我的中断处理程序会立即触发、而主 while 循环从未运行。 可能语言尚不清楚、但对我来说、如果中断在半空或更少的传输 FIFO 上触发、 然后、我们启用该中断后、它将持续触发、因为 TX FIFO 始终为半空或更少、因为我们还没有机会在其中放置任何东西。 这是正确的假设吗?  

概括地说、如果我使用标志 SSI_TXEOT 启用中断、那么就不会触发中断、我想这是有道理的、因为 SSIMIS 只允许屏蔽到第3位。 但是、如果我用标志 SSI_TXFF 启用中断、中断处理程序会立即触发、而主函数无法运行、因为中断处理程序不断触发、所以主任务基本上无法运行。

感谢您的任何澄清、谢谢!

加兰·凯尔

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

    我想跟进此事。 我在 SSICR1寄存器中找到了 EOT 标志、并创建了一个函数来检查该位是否已被置位。 我一启用 SSI_TXFF 标志设置的中断、就会立即触发中断处理程序、但始终不发送任何数据、因为我们位于中断处理程序内部、主函数永远不会执行。 我可以在触发中断后发送数据、看看它是否起作用、但我担心一个应用程序会立即跳进中断处理程序、让主函数无法运行、因为中断处理程序会不断触发。 我在下面附上了一些代码、想看看这些代码是否有用、但我想知道我的做法是否正确。

    数据表表明、当 SSI_TXFF 中断触发时、我需要检查 EOT 标志以查看我们是半空还是事务已完成、但我甚至无法发送任何字节、因为我们一直处于 ISR 状态。  

    void TivaSPI::Initialize() {
      kBaseAddress = SSI0_BASE;
      IntEnable(INT_SSI0);
      SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
      while (!SysCtlPeripheralReady(SYSCTL_PERIPH_SSI0)) {
      }
      SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
      while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)) {
      }
    
      GPIOPinConfigure(GPIO_PA2_SSI0CLK);
      // GPIOPinConfigure(GPIO_PA3_SSI0FSS);
      GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);
      GPIOPinConfigure(GPIO_PA4_SSI0RX);
      GPIOPinConfigure(GPIO_PA5_SSI0TX);
    
      GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);
      // SSIIntEnable(SSI0_BASE, SSI_TXEOT);
      // SSIIntEnable(SSI0_BASE, SSI_RXFF | SSI_TXFF);
      SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
                         SSI_MODE_MASTER, 1000000, 8);
    
      SSIEnable(SSI0_BASE);
      SSIIntEnable(SSI0_BASE, SSI_TXFF);
    }
    
    
    void SSI0Handler() {
      uint32_t int_status = SSIIntStatus(SSI0_BASE, true);
    
      if (int_status & SSI_TXFF) {
        SSIIntClear(SSI0_BASE, SSI_TXFF);
        if (SSIIsEndOfTransmissionFlagSet(SSI0_BASE)) {
          GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
        }
      }
      /* toggling to capture on logic analyzer */
      GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
      GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
    }
    
    void TivaSPI::BlockingWrite(uint32_t *data_out, uint8_t num_bytes) {
      uint8_t bytes_processed = 0;
      ClearReceiveBuffer(&data_out[0]);
      AssertCS();
      while (bytes_processed < num_bytes) {
        SSIDataPut(kBaseAddress, data_out[bytes_processed]);
    
        bytes_processed++;
      }
      // Wait until bus is no longer busy before returning
      while (SSIBusy(kBaseAddress))
        ;  // look into this
      DeAssertCS();
      // check to see if all bytes have been sent and return false if not
      if (bytes_processed != num_bytes) {
        return;
      }
    }

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

    我只想添加一个来自逻辑分析仪的图像、该图像显示了中断触发情况、然后我必须在 ISR 中手动启动事务。 对我来说、这似乎很奇怪、TXFF 中断基本上被立即触发、然后我们在中断处理程序中无限停留。 当调用 ISR 时、紫色线在切换 GPIO、黄色表示时钟、橙色表示 CS、红色表示 MISO、底部修饰的橙色外观颜色表示图案。

      

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [报价 userid="578908" url="~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1285826/tm4c123gh6pm-clarity-on-tx-fifo-half-full-or-less-and-other-ssi-interrupts ]在这种情况下 EOT 位是什么? 我似乎在任何地方都找不到这个。

    EOT 表示传输完成。 假设您只将一个16位字的数据加载到 FIFO、直到整个16位完全移出移位寄存器后才会生成 EOT 中断。  

    Unknown 说:
    第二、当我为半空或少于半空的 FIFO 条件启用中断(值为0x08的 SSI_TXFF)时、我的中断处理程序立即触发、并且 main while 循环从未运行。 可能语言尚不清楚、但对我来说、如果中断在半空或更少的传输 FIFO 上触发、 然后、我们启用该中断后、它将持续触发、因为 TX FIFO 始终为半空或更少、因为我们还没有机会在其中放置任何东西。 这是正确的假设吗?

    您的理解是正确的。 由于 FIFO 中还没有数据、一旦您启用 TXFF 中断、就会立即生成中断。 中断允许处理器填充 FIFO、以启动传输。  

    如果我用标志 SSI_TXFF 启用中断,中断处理程序会立即触发,并且主函数不会因为中断处理程序不断触发而有机会运行,因此主任务基本上无法运行。

    在 SSI0Handler 中、我没有看到您正在将数据加载到 FIFO 中。 只要退出中断、FIFO 保持为半空或更少、因此再次生成中断。  

    我只想从逻辑分析仪添加一个图像,该图像显示中断触发情况,然后我必须在 ISR 中手动启动事务。

    您还可以在启用 SPI 和中断之前加载 FIFO。  

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

    嗨、Charles、

    感谢您的答复和澄清,这是我要寻找的信息。 我喜欢在将数据加载到 FIFO 中后启用中断的想法、但我想我还需要在每个事务结束后禁用中断、以便不会持续触发中断。  

    我将为此设计修改我的应用、并返回一些结果。 再次感谢!

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

    所以我在做一些改变后会有一些跟进问题。 我看到 SSI_TXFF 中断持续触发、直到 FIFO 达到半空或更少、但我没有得到 EOT 中断。 我谈到了何时将数据加载到 FIFO 中、目前屏蔽了中断状态寄存器。 我想知道如何将我的传输回调配置为仅在一个字节完成后发送下一个字节、但由于中断触发如此快、我将所有数据发送得太快、它无法正常运行。 目前我正在尝试写入4个字节。 我已经附上了更新后的代码和逻辑分析仪跟踪供您回顾、感谢您提供任何见解。

    bool TivaSPI::StartNonBlockingWrite(uint8_t *data, uint8_t num_bytes) {
      if (state == SPI_Internal_State::kIdle) {
        state = SPI_Internal_State::kWriting;
    
        std::memcpy(tx_data_buffer, data, num_bytes);
        spi_control.write_index = 0;
        spi_control.num_write_bytes = num_bytes;
    
        AssertCS();
    
        SSIIntEnable(SSI0_BASE, SSI_TXFF);
    
        return true;
      } else {
        return false;
      }
    }
    
    void TivaSPI::TransmitCallback() {
    
      if (!SSIBusy(SSI0_BASE)) {
        SSIDataPutNonBlocking(SSI0_BASE, tx_data_buffer[spi_control.write_index]);
        spi_control.write_index++;
      } else {
        return;
      }
    
      if (spi_control.write_index == spi_control.num_write_bytes - 1) {
        SSIIntDisable(SSI0_BASE, SSI_TXFF);
        state = SPI_Internal_State::kIdle;
        DeAssertCS();
      }
    }
    
    void SSI0Handler() {
      uint32_t int_status = SSIIntStatus(SSI0_BASE, true);
      SSIIntClear(SSI0_BASE, SSI_TXFF);
      /* toggling to capture on logic analyzer */
      GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
      GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0);
    
      if (int_status & SSI_TXFF) {
        spi_bus_0.TransmitCallback();
    
      }
    }

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

    您好!

     您是否可以尝试 SSIDataPut 而不是 SSIDataPutNonBlocking? 您觉得有什么区别吗?

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

    尊敬的 Charles:

    感谢您的答复。 更改为 SSIDataPut 的结果与 SSIDataPutNonBlocking 相同。  

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

    您好、Kyle、

     很抱歉回复延迟。 在启用 SSI 模块之前、是否可以尝试预填充整个 TXFIFO? 它会产生什么影响吗? 我希望这样做会在 FIFO 半空之前发送4个字。 每次收到中断时、您将一次填4个字。  

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

    不用担心、我很感激您的帮助。 我首先加载了 FIFO、然后启用了芯片选择和中断、我认为我们的工作越来越接近。 但正如您从逻辑分析仪跟踪中看到的、中断以每2.1us 快速持续触发一次、因此在回调中、我不确定何时向 FIFO 添加另外4个字节、甚至何时取消置位芯片选择线路。 我想知道我采用的方法是否错误、但我不确定还可以检查哪些其他中断。 我想知道如何仅在所有字节都完成后才触发回调。 也许可以检查总线是否繁忙、如果不是、我可以取消置位 CS 并启动另一个事务?

     

    bool TivaSPI::StartNonBlockingWrite(uint8_t *data, uint8_t num_bytes) {
      if (state == SPI_Internal_State::kIdle) {
        state = SPI_Internal_State::kWriting;
    
        std::memcpy(tx_data_buffer, data, num_bytes);
        spi_control.write_index = 0;
        spi_control.num_write_bytes = num_bytes;
    
        AssertCS();
    
        for (uint8_t index = 0; index < num_bytes; index++) {
          SSIDataPutNonBlocking(SSI0_BASE, tx_data_buffer[index]);
        }
    
        SSIIntEnable(SSI0_BASE, SSI_TXFF);
    
        return true;
      } else {
        return false;
      }
    }

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

    您好!

     您的 LA 捕获确实显示在只发送一个字的情况下多次进入和退出中断 ISR。 我知道您曾尝试等待 EOT、但看不到它、因为 TXFF 中断过快。 您是否可以尝试首先预填充 FIFO 并等待仅 EOT 中断? 换句话说、不要启用 TXFF 中断。 同时、我将进行一些搜索、看看是否过去报告过此问题、以及有什么建议。  

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

    尊敬的 Charles:

    感谢您的回复、并抱歉一开始有误解。 我禁用了 TXFF 中断、然后制作了一个辅助函数、用于设置 SSI_CR1寄存器中的 EOT 位、并生成 EOT 中断! (请参阅逻辑分析仪轨迹、这很完美)。

    出于某种原因、我认为我需要检查 SSI_CR1寄存器中 EOT 位的状态、但实际上我在启动时设置了该位、然后我可以在回调中取消 CS 置位、否则会取消置位。

    我非常感谢在这方面提供的协助。 保重!

    编辑:我回头看了看我的代码、仍然启用了 TXFF 中断、鉴于我看到的捕获和响应、这很有意思。 仅供参考。 这两者似乎都是必要的。