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:使用 SSI 通信从器件到主器件的通信错误

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/598181/tm4c123gh6pm-communication-error-from-slave-to-master-using-ssi-communication

器件型号:TM4C123GH6PM

您好!

对于两个端口之间的 SSI 通信、我将面临从器件端到主器件端的通信问题 我正在使用 ssi0和 SSI2、其中 ssi0是主设备、而 SSI2是从设备。从主设备到从设备的通信正常、但从设备到主设备的发送字节未被接收。 在调试模式下、我看到它显示的是0x0000、而不是正确的数据。 请帮助。

此致、

//
//
// ti_master.c -演示如何在 TI 主控模式下配置 SSI0的示例。
//
//版权所有(c) 2010-2015 Texas Instruments Incorporated。 保留所有权利。
//软件许可协议
//
//以源代码和二进制形式重新分发和使用,有无
//如果满足以下条件,则允许进行修改
//满足:
//
//重新分发源代码必须保留上述版权
//注意、此条件列表和以下免责声明。
//
//二进制形式的重新分发必须复制上述版权
//注意、中的条件列表和以下免责声明
//随提供的文档和/或其他材料
//分布。
//
//德州仪器公司的名称和的名称都不是
//其贡献者可用于认可或推广衍生产品
//未经特定的事先书面许可,从该软件下载。
//
//本软件由版权所有者和作者提供
//“原样”以及任何明示或暗示的保证,包括但不包括
//限于对适销性和适用性的暗示保证
//一个特定的目的是免责的。 在任何情况下、版权均不得
//所有者或贡献者应对任何直接、间接、偶然、
//特殊、典型或必然的损害(包括但不包括)
//仅限于采购替代货物或服务;
//数据或利润;或业务中断)
//责任理论,无论是合同责任、严格责任还是侵权行为
//(包括疏忽或其他)以任何方式因使用而产生
//此软件,即使已被告知可能会发生此类损坏。
//
//这是 Tiva 固件开发包的修订版本2.1.2.111的一部分。
//
//

#include
#include
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "driverlib/rom.h"

//
//
//! 添加到组 SSI_Examples_list
//!

TI 主器件(ti_master)


//!
//! 此示例展示了如何将 SSI0配置为 TI 主器件。 代码将会
//! 在主器件 Tx 上发送三个字符、然后轮询接收 FIFO、直至
//! 在主 Rx 上接收3个字符。
//!
//! 此示例使用以下外设和 I/O 信号。 您必须执行的操作
//! 查看这些内容并根据您自己的董事会的需要进行更改:
//! SSI0外设
//! - GPIO 端口 A 外设(用于 SSI0引脚)
//! SSI0Clk - PA2
//! SSI0Fss - PA3
//! SSI0Rx - PA4
//! SSI0Tx - PA5
//!
//! 以下 UART 信号仅配置为显示控制台
//! 消息。 I2C0运行时不需要这些寄存器。
//! UART0外设
//! - GPIO 端口 A 外设(用于 UART0引脚)
//! - UART0RX - PA0
//! - UART0TX - PA1
//!
//! 此示例使用以下中断处理程序。 来使用该示例
//! 在您自己的应用程序中、您必须将这些中断处理程序添加到
//! 矢量表。
//! -无。
//
//

//
//
//要发送和接收的字节数。
//
//
#define NUM_SSI_DATA 3.
uint32_t pui32DataTx[NUM_SSI_DATA];
uint32_t pui32DataRx[NUM_SSI_DATA];
uint32_t ui32Index;

//
//
//此函数将 UART0设置为用于控制台显示信息
//因为示例正在运行。
//
//

//
//
//在主 TI 模式下配置 SSI0。 此示例将发出3个字节的
//数据,然后等待3个字节的数据进入。 这一切都将通过来完成
//轮询方法。
//
//


无效
CONFIG_UART0 ()

ROM_SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);

ROM_GPIOPinConfigure (GPIO_PA0_U0RX);
ROM_GPIOPinConfigure (GPIO_PA1_U0TX);

ROM_GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);
UARTStdioConfig (0、115200、16000000);

// ROM_UARTConfigSetExpClk (UART0_BASE、ROM_SysCtlClockGet ()、115200、
//(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
// UART_CONFIG_PAR_NONE));
//UARTEnable (UART0_BASE);

//********* //
内部
main (空)

ROM_FPULazyStackingEnable();

SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHz);

CONFIG_UART0();

//
//在控制台上显示设置。
//
UARTprintf ("SSI ->\n");
UARTprintf ("模式:TI\n");
UARTprintf ("数据:8位\n");

//
//必须启用 SSI0外设才能使用。
//
SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
SysCtlPeripheralEnable (SYSCTL_Periph_SSI2);

//
//对于本示例,SSI0与 Porta[5:2]一起使用。 实际端口和
//使用的引脚可能与您的器件不同、请参阅的数据表
//更多信息。 GPIO 端口 A 需要启用、以便这些引脚可以
//使用。
// TODO:将其更改为您正在使用的 GPIO 端口。
//
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);

//
//为端口 A2、A3、A4和 A5上的 SSI0功能配置引脚复用。
//如果您的器件不支持引脚复用、则无需执行此步骤。
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinConfigure (GPIO_PA2_SSI0CLK);
GPIOPinConfigure (GPIO_PA3_SSI0FSS);
GPIOPinConfigure (GPIO_PA4_SSI0RX);
GPIOPinConfigure (GPIO_PA5_SSI0TX);


//******** //

/***** 新添加的 SSI2
GPIOPinConfigure (GPIO_PB4_SSI2CLK);
GPIOPinConfigure (GPIO_PB5_SSI2FSS);
GPIOPinConfigure (GPIO_PB6_SSI2RX);
GPIOPinConfigure (GPIO_PB7_SSI2TX);

//
//配置 SSI 引脚的 GPIO 设置。 该函数也会提供
将这些引脚的//控制到 SSI 硬件。 请参阅中的数据表
//查看每个引脚分配的函数。
//引脚分配如下:
// PA5 - SSI0Tx
// PA4 - SSI0Rx
// PA3 - SSI0Fss
// PA2 - SSI0CLK
// TODO:更改此选项以选择您正在使用的端口/引脚。
//
GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 |
GPIO_PIN_2);


GPIOPinTypeSSI (GPIO_PORTB_BASE、GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 |
GPIO_PIN_4);//为 SSI2新增了

SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MOTO_0、SSI_MODE_MASTER、2000000、 8);

SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MOTO_0、SSI_MODE_SLAVE、2000000、 8);
//
//为 TI 主控模式配置和启用 SSI 端口。 使用 SSI0系统
//时钟电源、主控模式、1MHz SSI 频率和8位数据。
//

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

//
//从 SSI 端口读取任何残留数据。 这将确保接收
// FIFO 为空,因此我们不会读取任何不需要的垃圾。 这在这里完成
//因为 TI SSI 模式为全双工模式,允许您发送和
//同时接收。 SSIDataGetNonBlocking 函数返回
//返回数据时为"true",未返回数据时为"false"。
//“非阻塞”函数检查接收中是否有数据
// FIFO、如果没有、则不会"挂起"。
//
while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataRx[0]))

//
//初始化要发送的数据。
//
pui32DataTx[0]='t';
pui32DataTx[1]='I';
pui32DataTx[2]='!';

//
//显示 SSI 正在发送数据的指示。
//
UARTprintf ("sent:\n ");

//
//发送3个字节的数据。
//
for (ui32Index = 0;ui32Index < NUM_SSI_DATA;ui32Index++)

//
//显示 SSI 正在传输的数据。
//
UARTprintf ("'%c'"、pui32DataTx[ui32Index]);

//
//使用“阻塞”Put 函数发送数据。 此函数
//将等待发送 FIFO 中有空间后再返回。
//这使您可以确保发送的所有数据都将其输入
//发送 FIFO。
//
SSIDataPut (SSI0_BASE、pui32DataTx[ui32Index]);

//
//等待 SSI0完成传输发送 FIFO 中的所有数据。
//
while (SSIBusy (SSI2_base))

//
//显示 SSI 正在接收数据的指示。
//
UARTprintf ("\n 接收:\n ");

while (SSIDataGetNonBlocking (SSI2_base、&pui32DataTx[0]))

//
//接收3个字节的数据。
//
for (ui32Index = 0;ui32Index < NUM_SSI_DATA;ui32Index++)

//
//使用“阻塞”GET 函数接收数据。 此函数
//将等待接收 FIFO 中有数据后再返回。
//
SSIDataGetNonBlocking (SSI2_base、&pui32DataTx[ui32Index]);

//
//由于我们使用的是8位数据,所以屏蔽 MSB。
//
pui32DataRx[ui32Index]&= 0x00FF;

//
//显示 SSI0接收到的数据。
//
UARTprintf ("'%c'"、pui32DataTx[ui32Index]);




UARTprintf ("\n 从器件发送:\n ");
while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataTx[0]))


SSIDataPut (SSI2_base、pui32DataTx[1]);
UARTprintf ("'%c'"、pui32DataTx[1]);

while (SSIBusy (SSI2_base))





pui32DataTx[1]='f';
UARTprintf ("\n 在主控器件收到:\n ");
if (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataTx[1]))

UARTprintf ("'%c'"、pui32DataTx[1]);

其他

UARTprintf ("失败");

//
//返回无错误
//
返回(0);

//******* 输出如下所示。*** //

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    在第263行中、您是否应该等待 SSI0完成、而不是 SSI2? 那么、我认为您不希望在 while 循环的272到274行中调用 SSIDataGetNonBlocking。 这将清空 SSI2的接收 FIFO。 (也许您应该将该代码放在第225-226行、以确保在 SSI0上开始传输前 SSI2的接收 FIFO 为空。) 如果要在 for 循环(第279-298行)中读取 SSI2接收 FIFO,请使用 SSIDataGet ()而不是 SSIDataGetNonBlocking。

    在第295行中、您将打印发送的数据、而不是您接收的数据、即使您将其命名为"已接收:"。 实际上、您从未加载 SSI2 TX FIFO、因此 SSI0将不会接收有效数据。 在 SSI 模块上、主机和从机同时发送和接收数据(全双工)。 首先加载从器件 FIFO (SSIDataPut (SSI2_base、data)、然后加载主器件数据(SSIDataPut (SSI0_BASE、data)。 加载主器件 TX FIFO 即可开始发送。 当主器件完成发送时、您可以从主器件和从器件 FIFO 中读取数据。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    另一个建议是、当您想要发布 C 代码时、请使用"丰富的文本格式"并使用"<>"图标发布它。 然后、它会保留格式并更易于阅读:

    //发送3个字节的数据。
    //
    for (ui32Index = 0;ui32Index < NUM_SSI_DATA;ui32Index++)
    {
    //
    显示 SSI 正在传输的数据。
    //
    UARTprintf ("'%c'"、pui32DataTx[ui32Index]);
    
    //
    使用"blocking" Put 函数发送数据。 此函数
    //将等待发送 FIFO 中有空间后再返回。
    //这使您可以确保发送的所有数据都将其放入
    //发送 FIFO 中。
    //
    SSIDataPut (SSI0_BASE、pui32DataTx[ui32Index]);
    }