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

Guru**** 2477705 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/687696/ek-tm4c123gxl-converting-from-polling-to-interrupt-driven-ssi

器件型号:EK-TM4C123GXL

您好!

我编写了一个 SSI 的轮询版本、该版本使用以下函数在 MCU 和 Winbond 闪存之间传输字节。 一切都很好、我能够正常地与闪存交互。

uint8_t byte_transfer (uint8_t data){
SSIDataPut (SSI0_BASE、DATA);
while (SSIBusy (SSI0_BASE));
uint32_t rx_buf;
SSIDataGet (SSI0_BASE、&Rx_Buf);
while (SSIBusy (SSI0_BASE));
返回(uint8_t) rx_Buf;
} 


最近、我决定将 SSI 的轮询版本设为中断驱动版本、但我在这方面遇到了困难。 这是我目前所拥有的。

// SSI 初始化

void init_SPI (void){
SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);

GPIOPinConfigure (GPIO_PA2_SSI0CLK);
GPIOPinConfigure (GPIO_PA4_SSI0RX);
GPIOPinConfigure (GPIO_PA5_SSI0TX);
GPIOPinTypeSSI (GPIO_Porta_base、
GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);

SSIConfigSetExpClk (SSI0_BASE、
SysCtlClockGet ()、
SSI_FRF_MOTO_MODE_0、
SSI_MODE_MASTER、
1000000、
8);

GPIOPinTypeGPIOOutput (GPIO_Porta_base、GPIO_PIN_3);
GPIOPinWrite (GPIO_Porta_base、GPIO_PIN_3、GPIO_PIN_3);

SSIEnable (SSI0_BASE);

//从 SSI 端口读取任何残留数据。
while (SSIDataGetNonBlocking (SSI0_BASE、&g_Rx_Buf));

SSIIntDisable (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR);
SSIIntClear (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR);

//启用 SSI 中断。
IntEnable (INT_SSI0);

//启用处理器中断。
IntMasterEnable();
} 

//全局变量

uint32_t g_rx_buf = 0;//全局 Rx 缓冲
器 uint32_t g_tx_buf = 0;//全局 TX 缓冲
器易失性 uint32_t g_wait_for_int = 0;//标志等待中断发生 

// SSI 数据字节传输

uint8_t byte_transfer (uint8_t data){
G_WAIT_for_int = 1;
G_TX_Buf =(uint32_t)数据;

//启用发送和接收中断。 这将启动实际操作
//传输。
SSIIntEnable (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO);

while (g_wait_for_int);//等待 ISR 触发

// IntTrigger (INT_SSI0);

返回(uint8_t) g_rx_buf;
}

// SSI ISR

void SSI0IntHandler (void){
uint32_t status = SSIIntStatus (SSI0_BASE、TRUE);
G_WAIT_for_int = 0;

SSIIntClear (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO);

SSIDataPutNonBlocking (SSI0_BASE、g_TX_Buf);

SSIDataGetNonBlocking (SSI0_BASE、&g_Rx_Buf);

SSIIntDisable (SSI0_BASE、SSI_TXFF | SSI_RXFF | SSI_RXTO);
} 

//使用传输函数读取闪存 ID

void read_id (void){
uint8_t man_id、dev_id;

UARTprintf ("正在获取闪存信息...\n");

CHIP_SELECT (~GPIO_PIN_3);///芯片选择低电平

byte_transfer (wb_read_ID);
Byte_transfer (0x00);
Byte_transfer (0x00);
Byte_transfer (0x00);
man_id = byte_transfer (0x00);
DEV_id = BYTE_TRANSFRATE (0x00);

CHIP_SELECT (GPIO_PIN_3);///芯片选择高电平

UARTprintf ("制造 ID:\%2x\n"、man_id);
UARTprintf ("设备 ID:\%2x\n"、DEV_id);
} 

因此、我使用了调试器并在 ISR 处设置了一个断点、我一直执行到程序结束、我获得0xFF 表示制造 ID (错误值、应为0x17)、 0xEF 表示器件 ID (正确)。

如果我只是运行程序而不设置任何断点、我将为两个 ID 获得0xFF。

我有点卡、希望有人能提供一些指导。 提前感谢!

此致、

Jacky

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Jacky、
    能否测试 SSIDataPutNonBlocking ()和 SSIDataGetNonBlocking ()的返回值? 这些是与 FIFO 之间发送和接收数据的非阻塞 API。 如果这些调用的返回值为零、则表示 FIFO 中没有数据。 您还可以尝试阻止 API 的版本、如 SSIDataGet 和 SSIDataPut。 还请使用示波器查看总线活动。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Charles、

    感谢您的快速响应。 )

    因此、我能够通过使用以下 ISR 正确地与闪存通信:

    void SSI0IntHandler (void){
    uint32_t status = SSIIntStatus (SSI0_BASE、TRUE);
    
    if (status & SSI_TXFF){
    SSIIntClear (SSI0_BASE、SSI_TXFF);
    // UARTprintf ("SSI_TXFF\n");
    SSIDataPutNonBlocking (SSI0_BASE、g_TX_Buf);
    SSIIntDisable (SSI0_BASE、SSI_TXFF);
    }
    
    if (status & SSI_RXTO){
    G_WAIT_for_int = 0;
    SSIIntClear (SSI0_BASE、SSI_RXTO);
    // UARTprintf ("SSI_RXTO\n");
    SSIDataGetNonBlocking (SSI0_BASE、&g_Rx_Buf);
    SSIIntDisable (SSI0_BASE、SSI_RXTO);
    }
    } 

    我最后只使用 TXFF 和 RXTO 中断。 RXFF 被丢弃、因为我的函数在每个 byte_transfer 调用中仅发送/接收一个数据字节、这将永远不会触发 RXFF、因为 FIFO 永远不会半满或更多。 (问题1)根据代码的运行方式、这是否正确?

    (问题2)我看到一些人对其 SPI 进行了编码、以便填充 TX FIFO /等待 RX FIFO 填充(使用 RXFF 中断)、然后再传输数据字节。 将其与每个函数调用发送/接收一个数据字节进行比较、哪一个更有效? 我知道我的版本将更多地进入/退出 ISR、但我不会长时间停留在 ISR 中。

    我主要将与以下代码进行比较: e2e.ti.com/.../ssi_5F00_atmel.c

    (问题3)尝试阻止 API 版本。 您是说我可以尝试将 SSIDataGet 和 SSIDataPut 放入 ISR 中吗? 如果是这样、这是否不会很糟糕、因为您在 ISR 中循环/轮询的过程中非常多?

    谢谢、

    Jacky

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

    您好、Jacky、

     很高兴它能为您工作。

    [引用用户="Jacky Wang43]]我最后仅使用 TXFF 和 RXTO 中断。 RXFF 被丢弃、因为我的函数在每个 byte_transfer 调用中仅发送/接收一个数据字节、这将永远不会触发 RXFF、因为 FIFO 永远不会半满或更多。 (问题1)根据我的代码的运行方式、这是否正确?

     当 FIFO 中的数据少于或等于 FIFO 中的一半时、它将产生 TXFF 中断。 是否确定您不是处于 FIFO 模式、而是基于 EOT (传输结束)来生成中断?

    [引用用户="Jacky Wang43"](问题2)我看到一些人对其 SPI 进行了编码、使其填充 TX FIFO /等待 RX FIFO 填充(使用 RXFF 中断)、然后传输数据字节。 将其与每个函数调用发送/接收一个数据字节进行比较、哪一个更有效? 我知道我的版本将更多地进入/退出 ISR、但我不会一直停留在 ISR 中。

     如果您处于双工 SPI 操作中、那么当您在 TX 上传输 N 个字节时、您还将在 RX 上接收 N 个字节。 因此、可以根据 RX FIFO 中断开始将下一批数据填充到 TX FIFO 中。 如果使用 SSIDataPutNonBlocking、则需要检查返回的值、以查看在写入 FIFO 之前 FIFO 中是否有可用空间。  

    [引用 USER="Jacky Wang43"](问题3)您提到过尝试阻止 API 版本。 您是说我可以尝试将 SSIDataGet 和 SSIDataPut 放入 ISR 中吗? 如果是这样、这是否不会很糟糕、因为您在 ISR 中循环/轮询的过程中相当多?[/引述]

    如果 FIFO 已满、 则 SSIDataPut 将等待 FIFO 中有空间。 如果使用 SSIDataPutNonBlocking、则需要检查返回的值以确保 TX FIFO 中有空间写入下一个数据。  

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

    [引用用户="Jacky Wang43"]... 填充 TX FIFO /等待 RX FIFO 填充-然后传输数据字节。  将其与每个函数调用的 Tx/Rx 比较一个数据字节-哪一个更有效?

    由于工作负载-效率问题似乎已被忽略。   (至少目前)

    也就是说、"您"有两种方法"经过测试和工作"、创建这样的测试是否"对您来说最简单"-执行并记录结果-然后在此处展示您的发现?   通过这种方式、您可以"回答您自己的问题-并为论坛提供高价值-进行相同的处理...