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.

[参考译文] SSI 读取数据问题

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/566770/ssi-reading-data-issue

器件型号:EK-TM4C1294XL

工具/软件:Code Composer Studio

你好

我在使用 SSIDataGet ()和高级模式 SSI_ADV_MODE_READ_WRITE 时遇到问题,我尝试读取 FT800的制造商 ID,但我不知道为什么它需要多次发送读取函数,因为第一个值不正确。

我尝试使用另一个 GPIO (例如 PORTJ GPIO_PIN_2)作为 CS 而不是 FSS、但情况有所改善、但并非解决方案

FT800 ID 为0x7C、我得到以下值:

*** SSI_0和 UART_0完成***
数据8地址= 0x102400读取= 0x42
Dato8地址= 0x102400读取= 0x4a
数据8地址= 0x102400读取= 0x43
数据8地址= 0x102400读取= 0x42
Dato8地址= 0x102400读取= 0x4a
数据8地址= 0x102400读取= 0x43
数据8地址= 0x102400读取= 0x42
数据8地址= 0x102400读取= 0x7c
Dato8地址= 0x102400读取= 0x4a
数据8地址= 0x102400读取= 0x43
数据8地址= 0x102400读取= 0x7c
数据8地址= 0x102400读取= 0x7c
数据8地址= 0x102400读取= 0x7c
数据8地址= 0x102400读取= 0x7c

请帮助!  

此致、

-Angel Nino

我共享代码。

SSI 配置 功能

void ConfigureSSI (void)
{
MAP_SysCtlPeripheralReset (SYSCTL_Periph_GPIOA);
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
MAP_SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);

MAP_GPIOPinConfigure (GPIO_PA2_SSI0CLK);//SCK
MAP_GPIOPinConfigure (GPIO_PA3_SSI0FSS);/CS
MAP_GPIOPinConfigure (GPIO_PA4_SSI0XDAT0);//Tx (MOSI)
MAP_GPIOPinConfigure (GPIO_PA5_SSI0XDAT1);//RX (MISO)
MAP_GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);

MAP_SSIConfigSetExpClk (SSI0_BASE、120000000、SSI_FRF_MOTO_MOTO_0、SSI_MODE_MASTER、8000000、 8);
MAP_SSIAdvModeSet (SSI0_BASE、SSI_ADV_MODE_READ_WRITE);
MAP_SSIAdvFrameHoldEnable (SSI0_BASE);
MAP_SSIEnable (SSI0_BASE);
} 

写入和读取函数

void ft800cmd_Write (unsigned char ftCommand)
{
// GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、0);//将芯片选择设置为低
电平// while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataRx));

SSIDataPut (SSI0_BASE、ftCommand);//发送命令
SSIDataPut (SSI0_BASE、0x00);//发送第一个填充字节
SSIAdvDataPutFrameEnd (SSI0_BASE、0x00); //发送第二个填充字节

// while (SSIBusy (SSI0_BASE));
// GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、GPIO_PIN_CS);//将芯片选择设置为高
电平}

unsigned char ft800mem_Read8 (unsigned long ftAddress)
{
unsigned char ftData8 = 0;//读取8位的占位符
unsigned char cTempAddr[3];// FT800内存地址
unsigned char cZeroFill =零;

cTempAddr[2]=(char)(ftAddress >> 16)| MEM_READ;//编写要发送的命令和地址
cTempAddr[1]=(字符)(ftAddress >> 8);//中间字节
cTempAddr[0]=(char)(ftAddress);//低字节

// GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、0);//将芯片选择设置为低
电平// while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataRx));

SSIDataPut (SSI0_BASE、cTempAddr[2]);//发送内存写入加高地址字节
SSIDataPut (SSI0_BASE、cTempAddr[1]);
SSIDataPut (SSI0_BASE、cTempAddr[0]);

SSIAdvDataPutFrameEnd (SSI0_BASE、cZeroFill);//发送虚拟字节

SSIDataGet (SSI0_BASE、&ftData8);//接收数据字节

// while (SSIBusy (SSI0_BASE));
// GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、GPIO_PIN_CS);//设置芯片选择高

返回 ftData8;//返回8位
}

unsigned int ft800mem_Read16 (unsigned long ftAddress)
{
unsigned int ftData16=0;// 16位返回
unsigned char cTempAddr[3];// FT800内存地址
unsigned char cTempData[2];//读取16位的占位符
unsigned char cZeroFill =零;

cTempAddr[2]=(char)(ftAddress >> 16)| MEM_READ;//编写要发送的命令和地址
cTempAddr[1]=(字符)(ftAddress >> 8);//中间字节
cTempAddr[0]=(char)(ftAddress);//低字节

// GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、0);//将芯片选择设置为低
电平// while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataRx));

SSIDataPut (SSI0_BASE、cTempAddr[2]);//发送内存写入加高地址字节
SSIDataPut (SSI0_BASE、cTempAddr[1]);
SSIDataPut (SSI0_BASE、cTempAddr[0]);

SSIAdvDataPutFrameEnd (SSI0_BASE、cZeroFill); //发送虚拟字节

SSIDataGet (SSI0_BASE、&cTempData[0]);//接收数据字节
SSIDataGet (SSI0_BASE、&cTempData[1]);

// while (SSIBusy (SSI0_BASE));
// GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、 GPIO_PIN_CS);//将芯片选择设置为高电平

ftData16 =(cTempData[1]<< 8)|//编写要返回的值-高字节
(cTempData[0]);//低字节

返回 ftData16;//返回16位
} 

主函数

int main (void)
{
int value;
unsigned char ft800Gpio;

MAP_SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz |
SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480)、120000000);

SysCtlPeripheralEnable (SYSCTL_Periph_GPIOJ);
GPIOPinTypeGPIOInput (GPIO_PORTJ_BASE、GPIO_PIN_0 | GPIO_PIN_1);
GPIOPadConfigSet (GPIO_PORTJ_BASE、GPIO_PIN_0、GPIO_Strength _2mA、GPIO_PIN_TYPE_STD_WPU); SW_1和 PULL_UP 的//使能引脚
GPIOPadConfigSet (GPIO_PORTJ_BASE、GPIO_PIN_1、GPIO_Strength _2mA、GPIO_PIN_TYPE_STD_WPU); SW_1和 PULL_UP 的//使能引脚

SysCtlPeripheralEnable (SYSCTL_Periph_GPION);
GPIOPinTypeGPIOInput (GPIO_PORTN_BASE、GPIO_PIN_INT);
GPIOPinTypeGPIOOutput (GPIO_PORTN_BASE、GPIO_PIN_PD | GPIO_PIN_CS | GPIO_PIN_1 | GPIO_PIN_0);//为 LED_2和 LED_1启用 ine

ConfigureSSI();
ConfigureUART();
UARTprintf ("*** SSI_0和 UART_0完成***\n"\});

GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_PD、GPIO_PIN_PD); // PD_N 的初始状态-高电平
GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、GPIO_PIN_CS); // SPI CS 的初始状态-高电平
MAP_SysCtlDelay ((120000000 * 0.02)/ 3);//延迟20ms

ft800cmd_Write (FT800_active); //启动 FT800

while (1)
{
if ((GPIOPinRead (GPIO_PORTJ_BASE、GPIO_PIN_0)& GPIO_PIN_0)=0)
{
SysCtlDelay ((120000000 * 0.15)/3);

如果(值==0)
{
unsigned char data8 = ft800mem_Read8 (REG_ID);// REG_GPIO、REG_GPIO_DIR、REG_ID、ROM_CHIPID
UARTprintf ("Dato8 Addr= 0x%x\tetch=0x%x\n"、REG_ID、dato8);
值= 1;
}
}
否则、如果((GPIOPinRead (GPIO_PORTJ_BASE、GPIO_PIN_1)& GPIO_PIN_1)= 0)
{
SysCtlDelay ((120000000 * 0.15)/3);

如果(值==0)
{
unsigned int data16 = ft800mem_Read16 (REG_Rplay_FREQ);// REG_CMD_READ、REG_CMD_WRITE
UARTprintf ("Dato16 Addr= 0x%x\tetch=0x%x\n"、REG_REPLAY_FREQ、dato16);
值= 1;
}
}
其他
{
值= 0;
}
}

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

    使用 PORTJ GPIO_PIN_2作为 CS 时、我得到了以下结果:

    *** SSI_0和 UART_0完成***
    数据8地址= 0x102400读取= 0x42
    数据8地址= 0x102400读取= 0x7c
    数据8地址= 0x102400读取= 0x7c
    数据8地址= 0x102400读取= 0x7c
    数据8地址= 0x102400读取= 0x7c
    数据16地址= 0x1024b0读取= 0x4a7c
    数据16地址= 0x1024b0读取= 0x4a40
    数据16地址= 0x1024b0读取= 0x4a40
    数据16地址= 0x1024b0读取= 0x4a40

    有所改善、但需要发送两次读取函数。  

    我所做的更改:

    SSI 配置功能

    void ConfigureSSI (void)
    {
    MAP_SysCtlPeripheralReset (SYSCTL_Periph_GPIOA);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
    
    MAP_GPIOPinConfigure (GPIO_PA2_SSI0CLK);//SCK
    // MAP_GPIOPinConfigure (GPIO_PA3_SSI0FSS);/CS
    MAP_GPIOPinConfigure (GPIO_PA4_SSI0XDAT0);//Tx (MOSI)
    MAP_GPIOPinConfigure (GPIO_PA5_SSI0XDAT1);//RX (MISO)
    MAP_GPIOPinTypeSSI (GPIO_Porta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2);//| GPIO_PIN_3
    
    MAP_SSIConfigSetExpClk (SSI0_BASE、120000000、SSI_FRF_MOTO_MOTO_0、SSI_MODE_MASTER、8000000、 8);
    // MAP_SSIAdvModeSet (SSI0_BASE、SSI_ADV_MODE_READ_WRITE);
    // MAP_SSIAdvFrameHoldEnable (SSI0_BASE);
    MAP_SSIEnable (SSI0_BASE);
    } 

    读取函数

    unsigned int ft800mem_Read16 (unsigned long ftAddress)
    {
    unsigned int ftData16=0;// 16位返回
    unsigned char cTempAddr[3];// FT800内存地址
    unsigned char cTempData[2];//读取16位的占位符
    unsigned char cZeroFill =零;
    
    cTempAddr[2]=(char)(ftAddress >> 16)| MEM_READ;//编写要发送的命令和地址
    cTempAddr[1]=(字符)(ftAddress >> 8);//中间字节
    cTempAddr[0]=(char)(ftAddress);//低字节
    
    GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、0);//将芯片选择设置为低电平
    while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataRx));
    
    SSIDataPut (SSI0_BASE、cTempAddr[2]);//发送内存写入加高地址字节
    SSIDataPut (SSI0_BASE、cTempAddr[1]);
    SSIDataPut (SSI0_BASE、cTempAddr[0]);
    
    SSIDataPut (SSI0_BASE、cZeroFill);//发送虚拟字节
    // SSIAdvDataPutFrameEnd (SSI0_BASE、cZeroFill);
    
    while (SSIBusy (SSI0_BASE));
    SSIDataGet (SSI0_BASE、&cTempData[0]);//接收数据字节
    SSIDataGet (SSI0_BASE、&cTempData[1]);
    
    GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、GPIO_PIN_CS);//将芯片选择设置为高电平
    
    ftData16 =(cTempData[1]<< 8)|//编写要返回的值-高字节
    (cTempData[0]);//低字节
    
    返回 ftData16;//返回16位
    } 

    示波器信号

    第1读


    第2读

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

    您好!

    从硬件 的角度来看,SPI 接口是一个环形移位寄存器-主设备中的内容传输到从设备,反之亦然。 但是、发送的第一个字节、即命令、在完全保存到内部缓冲区之前不会被处理或知道、因此、在解析(解码)并从 第二个字节开始之后、您可能会得到所需的结果。

    换言之、从软件的角度来看、第一个接收到的字节是虚拟字节、应进行刷写、第二个字节和后续字节可能会产生良好的结果。 器件的数据表指定了良好结果之前要转义/转存的虚拟字节的数量。 (IIRC 该文档是您在上一个主题中指定的应用手册之一)。 请再次阅读文档。

    此外、IIRC、您的器件需要首先发送最后一个地址字节-小端字节序系统-因此、在将地址解析为字节后、您必须开始从索引0而不是2发送它们。 我是对的吗?

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

    您好、Petrei

    感谢您的回答、这对我确实有很大帮助。

    我不理解文档中的那一部分、Amit 说需要执行一个清空操作、因为主器件发送一个字节、而从器件应答。 地址字节和虚拟字节应答数据回收站之后、从器件给出了良好的字节、它是正确的吗?

    文档提到"首先发送 MSB "、但字节顺序是[2]、[1]、[0]、最后。 因此、我对我的功能进行了必要的更改、效果非常好! 使用 FSS 引脚或任何引脚作为 CS 工作正常、现在我可以写入和读取任何寄存器

    非常感谢

    -Angel Nino

    共享我的 SSI 配置

    void ConfigureSSI (void)
    {
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
    MAP_SysCtlPeripheralEnable (SYSCTL_Periph_SSI0);
    
    MAP_GPIOPinConfigure (GPIO_PA2_SSI0CLK);//SCK
    MAP_GPIOPinConfigure (GPIO_PA3_SSI0FSS);/CS
    MAP_GPIOPinConfigure (GPIO_PA4_SSI0XDAT0);//Tx (MOSI)
    MAP_GPIOPinConfigure (GPIO_PA5_SSI0XDAT1);//RX (MISO)
    MAP_GPIOPinTypeSSI (GPIO_PORta_base、GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_3 | GPIO_PIN_2);//
    
    MAP_SSIConfigSetExpClk (SSI0_BASE、120000000、SSI_FRF_MOTO_MOTO_0、SSI_MODE_MASTER、8000000、 8);
    MAP_SSIAdvModeSet (SSI0_BASE、SSI_ADV_MODE_READ_WRITE);
    MAP_SSIAdvFrameHoldEnable (SSI0_BASE);
    MAP_SSIEnable (SSI0_BASE);
    } 

    //读取32位
    void ft800mem_Write32 (unsigned long ftAddress、unsigned long ftData32) { unsigned char cTempAddr[3]; // FT800内存地址 unsigned char cTempData[4]; //要写入的32位数据 cTempAddr[2]=(char)(ftAddress >> 16)| MEM_WRITE; //编写要发送的命令和地址 cTempAddr[1]=(字符)(ftAddress >> 8); //中间字节 cTempAddr[0]=(char)(ftAddress); //低字节 cTempData[3]=(字符)(ftData32 >> 24); //编写要发送的数据-高字节 cTempData[2]=(char)(ftData32 >> 16); // cTempData[1]=(char)(ftData32 >> 8); // cTempData[0]=(char)(ftData32); //低字节 // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、0);//将芯片选择设置为低电平 while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataRx)); SSIDataPut (SSI0_BASE、cTempAddr[2]);//发送内存写入加高地址字节 SSIDataPut (SSI0_BASE、cTempAddr[1]); SSIDataPut (SSI0_BASE、cTempAddr[0]); SSIDataPut (SSI0_BASE、cTempData[0]);//发送数据字节 SSIDataPut (SSI0_BASE、cTempData[1]); SSIDataPut (SSI0_BASE、cTempData[2]); // SSIDataPut (SSI0_BASE、cTempData[3]); SSIAdvDataPutFrameEnd (SSI0_BASE、cTempData[3]); // while (SSIBusy (SSI0_BASE)); // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、 GPIO_PIN_CS);//将芯片选择设置为高 电平}

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

    高级模式的工作方式与 QSPI 外设的传统模式不同。 在高级模式下、CS 控制也由外设处理、根据您使用的是高级写操作还是高级读写操作、可能不需要也可能需要清除 RXFIFO。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Amit

    在这种情况下、如果我理解从高级模式正确使用、我希望是正确的、那么这似乎是必要的。 我将继续制作更多探针。

    (评论:我也在练习英语、如果我有任何不好的表达或错误的单词、请告诉我)

    谢谢你

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

    您可以参阅在以下 TI 设计中使用 QSPI 的模型

    www.ti.com/.../TIDM-TM4C129SDRAMNVM

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

    共享我的读取函数:

    unsigned int ft800mem_Read16 (unsigned long ftAddress)
    {
    unsigned int ftData16=0;// 16位返回
    unsigned char cTempAddr[3];// FT800内存地址
    unsigned char cTempData[2];//读取16位的占位符
    unsigned char cZeroFill =零;
    
    cTempAddr[2]=(char)(ftAddress >> 16)| MEM_READ;//编写要发送的命令和地址
    cTempAddr[1]=(字符)(ftAddress >> 8);//中间字节
    cTempAddr[0]=(char)(ftAddress);//低字节
    
    // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、0);//将芯片选择设置为低电平
    while (SSIDataGetNonBlocking (SSI0_BASE、&pui32DataRx));
    
    SSIDataPut (SSI0_BASE、cTempAddr[2]);//发送内存写入加高地址字节
    SSIDataPut (SSI0_BASE、cTempAddr[1]);
    SSIDataPut (SSI0_BASE、cTempAddr[0]);
    SSIDataPut (SSI0_BASE、cZeroFill);//发送虚拟字节
    SSIDataPut (SSI0_BASE、cZeroFill);
    // SSIDataPut (SSI0_BASE、cZeroFill);
    SSIAdvDataPutFrameEnd (SSI0_BASE、cZeroFill);
    
    SSIDataGet (SSI0_BASE、&pui32DataRx);
    SSIDataGet (SSI0_BASE、&pui32DataRx);
    SSIDataGet (SSI0_BASE、&pui32DataRx);
    SSIDataGet (SSI0_BASE、&pui32DataRx);
    SSIDataGet (SSI0_BASE、&cTempData[0]);//接收数据字节
    SSIDataGet (SSI0_BASE、&cTempData[1]);
    
    // while (SSIBusy (SSI0_BASE));
    // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_CS、 GPIO_PIN_CS);//将芯片选择设置为高电平
    
    ftData16 =(cTempData[1]<< 8)|//编写要返回的值-高字节
    (cTempData[0]);//低字节
    
    返回 ftData16;//返回16位
    } 

    此致

    -Angel Nino

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

    请参阅高级模式使用的参考代码。 上述粘贴的代码不是高级模式的正确模型。