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.

[参考译文] CCS/EK-TM4C123GXL:使用 SSI 发送/接收数据

Guru**** 2466550 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/665776/ccs-ek-tm4c123gxl-send-receive-data-using-ssi

器件型号:EK-TM4C123GXL

工具/软件:Code Composer Studio

大家好、我使用以下代码在主从之间使用 SSI 接口发送和接收数据、我的目标是从主从发送一些值、从返回该值乘以某个数字。

以下代码的问题是从机可以接收值"ui32Message" 、即800、但 Value Master 接收到"ui32MessageX"、但它保持为零。此外、当我在 一个控制器中使用 SSIDataGet (SSI0_BASE、&ui32Message)接收数据而不为另一个控制器供电时、也会出现另一个问题(仅其他控制器未连接)、 程序在下一个状态上卡滞、除非我将其连接到其他控制器(为另一个控制器供电)、否则不会执行该程序。

//从

器件#include 
#include 
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/secl.idio"




#include "drivers.idio.h"#include "drivers/drivers.mdio.ide"#include "#include "#drivers.idio"#include "#include "drivers.idio.idio.h"




*配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 *
* /void
ConfigureUART (void)
{
//启用 UART 使用的 GPIO 外设。
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
//启用 UART0
SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
//为 UART 模式配置 GPIO 引脚。
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
//使用内部16MHz 振荡器作为 UART 时钟源。
UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);
//初始化控制台 I/O 的 UART
UARTStdioConfig (0、115200、16000000);
}

/*********
*主函数、程序入口点。 *
(S)** /
int main (void)
{

uint32_t ui32Message = 0;
uint32_t ui32MessageX = 0;
//将 PLL 的时钟设置为以50MHz 运行。
SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz |
SYSCTL_OSC_MAIN);
SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
GPIOPinConfigure (GPIO_PA2_SSI0CLK);
GPIOPinConfigure (GPIO_PA3_SSI0FSS);
GPIOPinConfigure (GPIO_PA4_SSI0RX);
GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MOTO_0、SSI_MODE_SLAVE、10000、 16);
SSIEnable (SSI0_BASE);

//初始化 UART 并对其进行配置
ConfigureUART();
UARTprintf ("\n ** \n* SSI 从机日志*\n****** \n");

while (1)
{
UARTprintf ("\n ui32Message \n");
SSIDataGet (SSI0_BASE、\ui32Message);
UARTprintf ("%d"、ui32Message);
UARTprintf ("\n 收到的 ui32消息\n");
SysCtlDelay (SysCtlClockGet ()/100);
while (SSIBusy (SSI0_BASE));
ui32MessageX=ui32Message+2;
UARTprintf ("%d"、mx);
SSIDataPut (SSI0_BASE、ui32MessageX);
while (SSIBusy (SSI0_BASE));
UARTprintf ("\---- ui32MessageX 已发送--- \n");

}
}


//主

#include 
#include 
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/secl.idio"




#include "drivers.idio.h"#include "drivers/drivers.mdio.ide"#include "#include "#drivers.idio"#include "#include "drivers.idio.idio.h"





*配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 *
* /void
ConfigureUART (void)
{
//启用 UART 使用的 GPIO 外设。
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);

//启用 UART0
SysCtlPeripheralEnable (SYSCTL_Periph_UART0);

//为 UART 模式配置 GPIO 引脚。
GPIOPinConfigure (GPIO_PA0_U0RX);
GPIOPinConfigure (GPIO_PA1_U0TX);
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);

//使用内部16MHz 振荡器作为 UART 时钟源。
UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);

//初始化控制台 I/O 的 UART
UARTStdioConfig (0、115200、16000000);
}

uint32_t ui32Message = 0;
unit32_t ui32MessageX= 0;
int main (void)
{




//将 PLL 的时钟设置为以50MHz 运行。
SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz |
SYSCTL_OSC_MAIN);


// HWREG (GPIO_PORTF_BASE + GPIO_LOCK)= GPIO_LOCK_KEY;
// HWREG (GPIO_PORTF_BASE + GPIO_O_CR)= 0xFF;
//


SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
GPIOPinConfigure (GPIO_PA2_SSI0CLK);
GPIOPinConfigure (GPIO_PA3_SSI0FSS);
GPIOPinConfigure (GPIO_PA5_SSI0TX);
GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_3 | GPIO_PIN_2);


SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MOTO_0、SSI_MODE_MASTER、10000、 16);
SSIEnable (SSI0_BASE);
//初始化 UART 并对其进行配置
ConfigureUART();
UARTprintf ("\n ** \n* SSI 主日志*\n****** \n");

while (1)
{
ui32Message = 800;
SSIDataPut (SSI0_BASE、ui32Message);
while (SSIBusy (SSI0_BASE));
UARTprintf ("\ui32Message sent \n");
SysCtlDelay (SysCtlClockGet ()/100);
SSIDataGet (SSI0_BASE、\ui32MessageX);
UARTprintf ("%d"、ui32MessageX);
UARTprintf ("\n 接收到的 ui32消息\n"\});
while (SSIBusy (SSI0_BASE));
}
}

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

    每次主器件执行 SSIDataPut ()时、SSI 都会执行全双工传输。 由于您只从主器件执行了一个 SSIDataPut(),主器件发送了800,并将其存储在接收缓冲区0中,因为从器件的发送缓冲区中没有任何内容。 然后从机在其发送缓冲区中加载802,但传输将不会开始,直到主机对 SSIDataPut()执行另一个调用。

    我认为您要做的是:

    SSIDataPut (SSI0_BASE、ui32Message);//发送800
    SSIDataGet (SSI0_BASE、\ui32MessageX);//虚拟读取到空缓冲区
    //从机加载新号码的延迟时间
    SSIDataPut (SSI0_BASE、ui32Message);//虚拟发送以获取读取数据
    SSIDataGet (SSI0_BASE、&ui32MessageX);//现在我们应该得到802
    

    该代码片段将导致第一个片段中的两次全双工传输、从主设备到从设备的数据有效、从设备到主设备的数据无效。 在第二种情况下、从主器件到从器件的数据无关、从器件到主器件的数据是有效的。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    使用此代码 ui32MessageX 值现在为65535。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我刚意识到我犯了一个愚蠢的错误,我没有在主代码中添加 GPIOPinConfigure (GPIO_PA4_SSI0RX),在从代码中添加 GPIOPinConfigure (GPIO_PA5_SSI0TX),所以在添加之后它的工作正常。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Bob、

    我们是否可以注意到并赞扬"细节、清晰和关心"、这"充分"了您的回答?   最棒的!

    我认为、"细分"您的回答是有建设性的:

    • 一个、"介绍性叙述"-详细列出并解释了 MCU 的基本(但必要)、 "SSI 基本规则"。   (非常重要-但这种情况很少出现...)
    • 随后-很好地说明和评论代码  ("开车回家"遵守"基本规则")  (甚至 CB1也能很好地理解)
    • 结尾为"结束语"(结束语)、提供了对 MCU SSI 机制的"不寻常的见解"。

    当然,一个“模型文章”- 我会“按” ** 喜欢 **按钮-但(以某种方式)喜欢的回报-有“离开大楼…”

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的、我完全同意、我感谢所有社区成员、我从你们那里得到了很多帮助。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很高兴听到这样的声音-谢谢!   Bob 在这篇文章中"离开公园"、我觉得这篇文章的"独特性"值得纪念...
    简直太棒了...   (并作为高效 的"模型响应"。)   (更快/更少-"机枪"响应-不是太多!)

    " Bob 选择解决海报问题的"方法"证明 、"高度细节"和"基本规则"可以以紧凑、高效的方式交付!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    对于(i=0;i<3;i++)
    {
    
    SSIDataGet (SSI0_BASE、\ui32Message[i]);
    SSIDataPut (SSI0_BASE、ui32MessageX[i]);
    
    SysCtlDelay (SysCtlClockGet ()/100);
    while (SSIBusy (SSI0_BASE));
    
    SSIDataGet (SSI0_BASE、\ui32Message[i]);
    SSIDataPut (SSI0_BASE、ui32MessageX[i]);
    while (SSIBusy (SSI0_BASE));
    
    }
    

    是否仍有从器件读取多个变量、如电机的位置和速度? 我可以将阵列用于循环、但另一个控制器(主控制器)不会使用哪个值是位置、哪个是速度?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    由于您的从站是 MCU、并且如果您正确安装并启用了适当的"位置传感器"、则"位置和速度"都可能可用。 (速度被定义为"delta P/delta t"。)

    您可以按已知顺序向 SPI 的 FIFO 显示所需的"位置和速度"。 如果您不介意传递较慢的数据速率、您可能会在这2个变量中的任何一个之前显示一个"唯一数据字节"-这将(非常)很好地识别"是哪一个"。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我使用以下代码按顺序获取数据、我最初工作正常、但当我复位发送数据的控制器时、数据序列在接收端发生变化、是否仍然按顺序获取数据。

    #define TM4C123GH6PM
    #include 
    #include 
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/ssctl.h"#include "drivers.mdio.h"#include "drivers.mdio"
    
    
    
    
    #include "#mdio.h"#include "drivers.mdio.md小时#include "#include "#include "drivers.mdio.h"#include "#mdio.md小时#include "#include "#include "drivers.mdio.md小时
    #include "#include "#include "#mdio.htm#include "#include "#include "#def"#def"#mdio.mdio.md小时#include "#include "#include
    
    
    
    
    *配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 *
    * /void
    ConfigureUART (void)
    {
    //启用 UART 使用的 GPIO 外设。
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
    //启用 UART0
    SysCtlPeripheralEnable (SYSCTL_Periph_UART0);
    //为 UART 模式配置 GPIO 引脚。
    GPIOPinConfigure (GPIO_PA0_U0RX);
    GPIOPinConfigure (GPIO_PA1_U0TX);
    GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1);
    //使用内部16MHz 振荡器作为 UART 时钟源。
    UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);
    //初始化控制台 I/O 的 UART
    UARTStdioConfig (0、115200、16000000);
    }
    
    /*********
    *主函数、程序入口点。 *
    (S)** /
    uint32_t ui32消息[4];
    uint32_t ui32MessageX [4];
    
    uint32_t i;
    int main (void)
    {
    
    
    //将 PLL 的时钟设置为以50MHz 运行。
    SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz |
    SYSCTL_OSC_MAIN);
    SysCtlPeripheralReset (SYSCTL_Periph_SSI0);
    SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
    
    SysCtlPeripheralReset (SYSCTL_Periph_GPIOA);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
    
    GPIOPinConfigure (GPIO_PA2_SSI0CLK);
    GPIOPinConfigure (GPIO_PA3_SSI0FSS);
    GPIOPinConfigure (GPIO_PA4_SSI0RX);
    GPIOPinConfigure (GPIO_PA5_SSI0TX);
    GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);
    SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MOTO_0、SSI_MODE_SLAVE、10000、 16);
    SSIEnable (SSI0_BASE);
    SSIIntEnable (SSI0_BASE、SSI_RXFF);
    SSIIntClear (SSI0_BASE、SSI_RXFF);
    SSIIntEnable (SSI0_BASE、SSI_RXOR);
    SSIIntClear (SSI0_BASE、SSI_RXOR);
    IntEnable (INT_SSI0);
    IntMasterEnable();
    
    //初始化 UART 并对其进行配置
    ConfigureUART();
    UARTprintf ("\n ** \n* SSI 从机日志*\n****** \n");
    
    while (1)
    {
    }
    
    
    }
    空 SSI0IntHandler (空)
    {
    ui32MessageX[0]=5;
    ui32MessageX[1]=4;
    ui32MessageX[2]=3;
    unsigned long status=SSIIntStatus (SSI0_BASE、TRUE);
    IF (STATUS & SSI_RXFF & SSI_RXOR)
    {
    对于(i=0;i<4;i++)
    {
    SSIDataGetNonBlocking (SSI0_BASE、\ui32Message[i]);
    }
    
    }
    UARTprintf ("\n 接收到的从机数据\n");
    对于(i=0;i<4;i++)
    {
    UARTprintf ("\n %d \n"、ui32Message[i]);
    SysCtlDelay (SysCtlClockGet ()/1000);
    }
    SSIIntClear (SSI0_BASE、SSI_RXFF);
    } 


    ////////////////////////////       MasterCode   //////////////////////////////////////////////////////////////

    #include
    #include
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "driverlib/flash.h"
    #include "driverlib/adc.h"
    #include "driverlib/ssi.h"
    #include "drivers/buttons.h"
    #include "utils/uartstdio.h"

    /*********
    *配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 *
    秘书长的报告 /


    uint32_t miso_M[4];
    uint32_t MOSI_M[]={6、7、8、9};

    int main (空)

    //将 PLL 的时钟设置为以50MHz 运行。
    SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHz |
    SYSCTL_OSC_MAIN);


    // HWREG (GPIO_PORTF_BASE + GPIO_LOCK)= GPIO_LOCK_KEY;
    // HWREG (GPIO_PORTF_BASE + GPIO_O_CR)= 0xFF;

    SysCtlPeripheralReset (SYSCTL_Periph_SSI0);
    SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);

    SysCtlPeripheralReset (SYSCTL_Periph_GPIOA);
    SysCtlPeripheralEnable (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_3 | GPIO_PIN_2);


    SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MOTO_0、SSI_MODE_MASTER、10000、 16);
    SSIEnable (SSI0_BASE);
    //初始化 UART 并对其进行配置

    while (1)

    uint32_t i;
    对于(i=0;i<4;i++)

    SSIDataPut (SSI0_BASE、MOSI_M[i]);

    SysCtlDelay (SysCtlClockGet ()/100);

    while (SSIBusy (SSI0_BASE));



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

    [报价 USER="Awais Mughal"]当我重置发送数据的控制器时,数据序列在接收端发生变化   是否有顺序获取数据的方法? [/报价]

    如果您仅 选择了"重置"发送控制器"-很难接受您的声明、即 "数据序列在接收端发生变化"。   (它更有可能(也更合理)证明您的发送序列发生了改变-因为只有发送控制器被复位。   您的"接收控制员""无权更改此类顺序-它只是"报告已交付的内容"-您(现在)不同意吗?)

    您可以考虑添加 一个"Sequence Alignment byte"-在任何 MCU 复位后立即发送。   在"接收结束接收"(和确认)时、您规定的"序列订单"的保险效果要好得多。   要添加更多内容-"序列稳健性"-您可以"定期发送 "序列对齐字节" -接收端可以处理该字节-并极大地帮助 您 "保持正确的序列!"   

    请注意、我建议将 "周期序列对齐字节" 设置为"定期发送"、而不仅仅是在任何"发送控制器复位"之后。   并尽最大努力确保"对齐字节最不可能发生-在"正常条件下!"   如果无法保证、则必须考虑"多个这样的对齐字节-已发送(和已接收)"背靠背!"   (操作与之前描述的操作相同。)