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 (SSI_FRF_MOTO_MOTO_MODE_0)作为从机无法接收数据

Guru**** 2609285 points
Other Parts Discussed in Thread: EK-TM4C123GXL

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/757399/ccs-ek-tm4c123gxl-unable-to-receive-data-using-ssi-ssi_frf_moto_mode_0-as-slave

器件型号:EK-TM4C123GXL

工具/软件:Code Composer Studio

大家好、我正在尝试将 EK-TM4C123GXL Launch Pad 用作 SSI/SPI 从设备。 我已经尝试了一些基于使用 SSI0中断的在线资源的示例代码。 当我尝试将数据从主设备(基于 Linux 的平台)发送到 launchpad 时、 不会触发 SSI0IntHandler、也不会看到收到的任何数据。

我想知道使用中断来接收数据的代码是否正确。 或者、有一种更简单的方法来查看接收到的数据(我 不介意使用轮询方法)和示例代码。

注意:我的主设备工作正常、因为我能够从它接收数据、而不会因将 aardvark 设备用作 从设备而出现任何问题。 我在 代码中注释了 sendTxSSI()。

#include 
#include 
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_NVIC.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctex.idio"

#include "driverlib/uart/uart.h"



//
//! \addtogroup 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 g_ui32SysClock; uint32_t g_ulDataRX1[4]、g_ulDataRx2; uint8_t g_ulSSI2RXTO; uint8_t 标志=0; uint8_t temp_data =0; uint32_t 计数器=0;uint8_uluint32_t 状态= uint32_t = uint32;uint32_t tuint32 uintuintuintuintuintuintektimert = uint_t = uint32 uint32 uintuintuintuint_t void = uint32;uint32 uintuintuintuintuint_t status_t t/t t/t translator = uint32 uint32 uintuintuintuintu TimerIntClear (TIMER5_base、status); Millis++; } void SSI0IntHandler (void) { // //读取中断状态。 // ulStatus = SSIIntStatus (SSI0_BASE、1); // //检查中断原因。 // //if (ulStatus & SSI_RXFF) UARTprintf ("\n\nullStatus---%x:%x\n"、ulStatus、ulStatus & SSI_RXFF); //if (ulStatus & SSI_RXTO) if (ulStatus & SSI_RXFF) { // 中断是由于 RX 超时所致。 因此、递增计数器可告知 //主循环发生 RX 超时中断。 // // //////从 SSI2 RX FIFO 读取 NUM_SSI_DATA 数据字节。 // // SSIDataGet (SSI0_BASE、&g_ulDataRX1[0]); //SSIDataPut (SSI0_BASE、0x1111);//虚拟写入 // sendTxSSI (); while (!SSIDataGetNonBlocking (SSI0_BASE、 &g_ulDataRX1[0]) { while (!SSIDataGetNonBlocking (SSI0_BASE、&g_ulDataRX1[1]) } {while (!SSIDataGetNonBlocking (SSI0_BASE、&g_ulDataRX1[2])} {while (!SSIDataGetNonBlocking (SSI0_BASE)、&SSI2&SSI2n )/UART20/G/SSI0) // UARTprintf ("\n\nCloar ulStatus %x\n"ulStatus); SSIIntClear (SSI0_BASE、ULStatus); //SSIIntClear (SSI0_BASE、SSI_RXFF); } // // //此函数将 UART0设置为用于控制台,以便 在示例运行时显示信息//。 //// ***************** void InitConsole (void) { // //启用用于 UART0引脚的 GPIO 端口 A。 // TODO:将其更改为您正在使用的 GPIO 端口。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //为端口 A0和 A1上的 UART0功能配置引脚复用。 //如果您的器件不支持引脚复用、则无需执行此步骤。 // TODO:更改此选项以选择您正在使用的端口/引脚。 // GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); // //启用 UART0以便我们可以配置时钟。 // SysCtlPeripheralEnable (SYSCTL_Periph_UART0); // //使用内部16MHz 振荡器作为 UART 时钟源。 // UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC); // //为这些引脚选择替代(UART)功能。 // TODO:更改此选项以选择您正在使用的端口/引脚。 // GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); // //初始化控制台 I/O 的 UART // UARTStdioConfig (0、115200、16000000); } // 计时器设置 */ void TimerBegin (){ //我们设置加载值,以便计时器每1ms 中断一次 UINT32_t 周期; //周期= 80000;//1ms //周期= 833;//10us 周期= 100;//190_2.5us ; * SysCtl= 3;SysCtl/ Deltl 周期= 833;// SysCtl* 将计时器配置为周期、省去它处于递减计数模式。 它从加载值计数到0、然后重置回加载值。 请记住:您需要在设置加载并匹配 * / TimerConfigure (TIMER5_base、TIMER_CFG_PERIODICRAY); TimerLoadSet (TIMER5_base、TIMER_A、PERIOD -1)之前配置计时器; TimerIntRegister (TIMER5_base、TIMER_A、SysTickInt); /* 启用超时中断。 在递减计数模式下、定时器到达 0并复位回加载。 在向上计数模式下、计时器达到负载 并重置为0。 */ TimerIntEnable (TIMER5_base、TIMER_TINA_TIMEOUT); TimerEnable (TIMER5_base、TIMER_A); } // 这是延迟函数。 // 空等待(uint32_t temp){ volatile uint32_t temp = millis; while ((millis-ttemp)< temp); } void sendTxSSI () { uint32_t ulDataTx; uint32_t ulDataRx; uint32_t ulDataTx1 = 0; ulDataTx = 0x8001; ulDataTx1 = 0x7FFC; //if (flag = 0) //( 如果(SSIDataPutNonBlocking (SSI0_BASE、0x1111)!= 0)//将数据放在 SSI 发送 FIFO 中{ UARTprintf ("\NTX:%x\n\r"、ulDataTx); } if (SSIDataPutNonBlocking (SSI0_BASE、ulDataTx)); }UARTx ("\UARTx") //等待 SSI0完成传输发送 FIFO 中的所有数据。 //while (SSIBusy (SSI0_BASE)) //{;} //} ulDataTx++; if (SSIDataPutNonBlocking (SSI0_BASE、ulDataTx)!= 0) { UARTprintf ("TX:%x\n\r"、ulDataTx); } //while (SSIBusy (SSI0_BASE)) //{;} //} if (SSIDataPutNonBlocking (SSI0_BASE、ulDataTx1)!= 0) { UARTprintf ("TX:%x\n\r\n"、ulDataTx1); } //while (SSIBusy (SSI0_BASE)) //{;} //} ulDataTx1+; if (SSIDataPutNonBlocking (SSI0_BASE、ulDataTx1)!= 0) { UARTprintf ("TX:%x\n\r"、ulDataTx1); temp_data ++; UARTprintf ("\ntemp_data1 %d\n"、temp_data); } //while (SSIBusy (SSI0_BASE)) //{;} //********* // //在主 TI 模式下配置 SSI0。 此示例将发出3个字节 的//数据、然后等待3个字节的数据进入。 这一切都将使用 //轮询方法来完成。 //// ***************** int main (void) { // //将时钟设置为直接从外部晶振/振荡器运行。 // TODO:必须更改 SYSCTL_XTAL_VALUE 以匹配的值 板上的//晶体。 // G_ui32SysClock = SysCtlClockFreqSet ((SYSCTL_OSC_INT | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480)、120000000); // //设置用于显示消息的串行控制台。 这是 //仅用于此示例程序,SSI 操作不需要。 // InitConsole(); UARTprintf ("64->g_ui32SysClock %d\n"、g_ui32SysClock); UARTprintf ("g_ui32SysClock %d\n"、g_ui32SysClock); // //在控制台上显示设置。 // UARTprintf ("SSI ->\n"); UARTprintf ("设备:从属设备\n"); UARTprintf ("模式:TI\n"); UARTprintf ("数据:8位\n"); UARTprintf ("速度:25kHz\n\n"); TimerBegin(); SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF); SysCtlDelay(3); //将您的选择的引脚设置为输出 GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_1); // //必须启用 SSI0外设才能使用。 // SysCtlPeripheralEnable (SYSCTL_Periph_SSI0); // //对于本示例,SSI0与 Porta[5:2]一起使用。 实际端口和 //使用的引脚可能与您的器件不同、请参阅的数据表 //更多信息。 GPIO 端口 A 需要启用、以便这些引脚可以 //使用。 // TODO:将其更改为您正在使用的 GPIO 端口。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //为端口 A2、A3、A4和 A5上的 SSI0功能配置引脚复用。 //如果您的器件不支持引脚复用、则无需执行此步骤。 // TODO:更改此选项以选择您正在使用的端口/引脚。 // GPIOPinConfigure (GPIO_PA2_SSI0CLK); GPIOPinConfigure (GPIO_PA3_SSI0FSS); GPIOPinConfigure (GPIO_PA4_SSI0RX); GPIOPinConfigure (GPIO_PA5_SSI0TX); // //配置 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); // //为 SPI 主控模式配置和启用 SSI 端口。 使用 SSI0、 //系统时钟电源,空闲时钟低电平和低电平有效时钟输入 //飞思卡尔 SPI 模式、主控模式、1MHz SSI 频率和8位数据。 //对于 SPI 模式,可以设置 SSI 时钟的极性 //单元空闲。 您还可以配置所需的时钟边沿 //在上捕获数据。 有关的更多信息、请参阅数据表 //不同的 SPI 模式。 // #if defined (target_IS_TM4C129_RA0)|| \ 已定义(TARGET_IS_TM4C129_RA1)|| \ 已定义(TARGET_IS_TM4C129_RA2) SSIConfigSetExpClk (SSI0_BASE、ui32SysClock、SSI_FRF_MOTO_MODE_0、 SSI_MODE_SLAVE、25000、8); #else SSIConfigSetExpClk (SSI0_BASE、SysCtlClockGet ()、SSI_FRF_MOTO_MODE_0、 SSI_MODE_SLAVE、25000、8); #endif // //启用 SSI0模块。 // SSIEnable (SSI0_BASE); SSIIntEnable (SSI0_BASE、SSI_RXFF); // SSIIntDisable (SSI0_BASE、SSI_TXFF); SSIIntDisable (SSI0_BASE、SSI_TXEOT); SSIIntDisable (SSI0_BASE、SSI_RXTO); SSIIntDisable (SSI0_BASE、SSI_RXOR); SSIIntClear (SSI0_BASE、SSI_RXFF); // SSIIntClear (SSI0_BASE、SSI_TXFF); // SSIIntClear (SSI0_BASE、SSI_RXTO); //SSIIntClear (SSI0_BASE、SSI_RXOR); // //从 SSI 端口读取任何残留数据。 这将确保接收 // FIFO 为空,因此我们不会读取任何不需要的垃圾。 这在这里完成 //因为 TI SSI 模式为全双工模式,允许您发送和 //同时接收。 SSIDataGetNonBlocking 函数返回 //返回数据时为"true",未返回数据时为"false"。 //“非阻塞”函数检查接收中是否有数据 // FIFO、如果没有、则不会"挂起"。 // while (SSIDataGetNonBlocking (SSI0_BASE、&g_ulDataRX1[0])) { } // //初始化要发送的数据。 // IntEnable (INT_SSI0); G_uC_TIMER =毫秒; UARTprintf ("\ntemp_data2 %d\n"、temp_data); while (1){ //UARTprintf ("\n1.temp_data %d\n"、temp_data); if (g_ulSSI2RXTO!= 0){ UARTprintf ("\ng_ulSSI2RXTO %d 计数%d\n"、g_ulSSI2RXTO、计数); g_ulSSI2RXTO = 0; Count++; UARTprintf ("\nRX.%x\n\r"、ulARTx0]_ulDataRTO=0) UARTprintf ("RX.%x\n\r"、g_ulDataRx1[1]); UARTprintf ("RX.%x\n\r"、g_ulDataRx1[2]); UARTprintf ("RX%x\n\r"、 G_ulDataRX1[3]); //UARTprintf ("\n 将数据发送回主设备\n"); /sendTxSSI (); } 返回(0); }

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

    您好、Gowtham、

    缺少 SSIIntRegister API 来将 ISR 处理程序与 SSI0中断相关联:

    SSIIntRegister (SSI0_BASE、SSI0IntHandler); 

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

    您好、Ralph、

    感谢您的反馈。 借助 SSIIntRegister (SSI0_BASE、SSI0IntHandler)、我能够在 SSI0IntHandler 内部接收数据。 但是、接收到的数据不准确。 当我从 主器 件传输(十六进制数据:10、11、12、13)时、我的接收数据为(Dec 数据:{6、2、5、6}或{5、6、2、5}或{2、5、6、2})。 有时只接收2或3个数据 、而不是全部4个数据。

    我对原始代码进行了一些修改。 附加了修改后的代码"receive_working_but wrong_data.c"和终端输出。

    e2e.ti.com/.../receive_5F00_working_5F00_but_5F00_wrong_5F00_data.c

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

    我建议在 SPI 引脚上放置一个示波器或逻辑分析仪、并在此时查看波形。 您需要验证时钟信号是否处于预期频率、以及主器件和从器件的极性设置是否正确。