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.
您好!
我正在体验在 SPI 总线上似乎是"17"位的传输。
我有8个 UCS 连接在一起、它们使用菊花链中的 SPI 总线(SPI-b)进行通信。 UC1与 uC2谈判,uC2与 uC3谈判...... UC8返回 UC1。
UC1是主器件。
数据长度为16位(SpibRegs.SPICCR.bit.SPICHAR = 0x1F;)
SPI 时钟速度非常慢、示波器迹线显示出出色的 SPI 时钟任一侧的设置和保持。
问题:
当我简单地通过主虚拟字路由时、它会通过完美的精细纹波、并且每个 uC (以及主器件)接收的内容是正确的。
但是、当我尝试在流中"注入"数据(即我"覆盖 uC 中的内容)时、返回到主设备(UC1)的数据会损坏。
花了一段时间、但我最终意识到数据正在向左移动1位-这表明 UC 正在计时17位!
例如、我注入8345 (1000-0011-0100-0101)、然后返回068B (0000-0110-1000-1011)-左移1位。 我使用了许多不同的数据模式、结果是相同的。
我已经阅读了 SPI 手册封面到封面上的十几次、我尝试了不同的速度(我认为这不可能是因为"虚拟"数据在所有速度下都能完美运行)。
我已经检查以确保没有杂散边沿(时钟"恢复状态"为低电平)
我已检查"勘误表"数据、但与 SPI 无关。
请任何人帮忙-我被骗了
我包括一些与 SPI 设置相关的代码部分
SPI_SET_UP { EALLOW; //将所选引脚的限定条件设置为仅异步*/ //这将为所选引脚选择异步(无限定条件)。 GpioCtrlRegs.GPAQSEL1.bit.GPIO12 = 3;//异步输入 GPIO12 (SPISIMOB) GpioCtrlRegs.GPAQSEL1.bit.GPIO13 = 3;//异步输入 GPIO13 (SPISOMIB) GpioCtrlRegs.GPAQSEL1.bit.GPIO14 = 3;//异步输入 GPIO14 = GPIO14.KB = GPIO3KB;GPIOL.GPIO3/ GPIO1.GPIO1.GPIO1.GPIO3KB = GPIO1.GPIO1.GPIO3KB //异步输入 GPIO14 (!SPISTEB) //使用 GPIO 寄存器配置 SPI-B 引脚*// 这指定哪些可能的 GPIO 引脚将是 SPI 功能引脚。 GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 3;//将 GPIO12配置为 SPISIMOB GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 3;//将 GPIO13配置为 SPISOMIB GpioCtrlRegs.GPAMUX1.bit.GPIO14 = 3;/ GPICl14 = 3;GPICOL = 3;GPICOL = 3;GPICOL = GPO14 = GPICOL = 3;GPICOL = 3 //将 GPIO115配置为 SPISTEB //为所选引脚启用内部上拉 //用户可以启用或禁用上拉。 //这将启用指定引脚的上拉电阻。 GpioCtrlRegs.GPAPUD.bit.GPIO12 = 0;//启用 GPIO12上的上拉(SPISIMOB) GpioCtrlRegs.GPAPUD.bit.GPIO13 = 0;//启用 GPIO13上的上拉(SPISOMIB) GpioCtrlRegs.GPAPUD.bit.GPIO13上拉 ;//启用 GPIO14上拉(SPIC.SPIC.0KB)/SPICOL = 0KB;GPIO14位/SPIC.GPIO14 = 0KB;GPIO14 = SPIC.SPICR.GPIO14;SPIC.GPIO14 =所有引脚 环回关闭 SpibRegs.SPIBRR = 0x19;//SPI 时钟速度-慢 SpibRegs.SPICTL.ALL = 0x02;//CLK_PHASE = 0、启用数据传输、禁用 SPI 中断(轮询)、// 0 =从器件; SpibRegs.SPICCR.ALL = 0x8F;//清除 SPI 复位 }
我的代码转至 tranmsit (Master)
void read_spi_Data (void) { receive_Count = 0; dmummy = 0x0F0F; SpibRegs.SPITXBUF = dmummy;//加载带有第一个字节的 Tx 缓冲区- dmummy -在 (SpibRegs.SPISTS.bit.INT_flag!= 1)//未在缓冲区中接收到字符时启动时钟 ;SpibRegs.SpibRegs.spirt.pummy = //清除标志(读取 Rx 缓冲器) SpibRegs.SPITXBUF = Command_Message;//使用下一个字加载 TxBuffer (即命令字 )// Command_Message 启用/禁用 O/PS 并设置覆盖等 ,而(SpibRegs.SPISTS.bit.INT_flag!=1)//没有收到字符时 ,SpibRegs.SpibUrl 缓冲区中的字符 = SpibUrummy 缓冲区 //清除标志(读取 Rx 缓冲器) 虚拟= 0x6789;// while (Receive_Count < 35) //receive_Count 是预期字数= { SpibRegs.SPITXBUF =虚拟; //使用下一个字加载 TxBuffer //后续行检查是否设置 Rx 标志-表示 SPI 总线已接收到一个字 ,同时(SpibRegs.SPISTS.bit.INT_flag !=1)//在缓冲区中没有接收到字符-轮询标志 {} test = SpibRegs.SPIRXBUF; //清除标志(读取 Rx 缓冲区) SPI_RxArray[Receive_Count]= test;//将接收到的数据放入 RxArray Receive_Count++中;//递增到下一个接收到的字 } Receive_Count = 0;//读取完成 后重置计数器 test = 0; }
从机读取
void transmit _SPI_Data (void) { receive_Count = 0; //后续注释应用于'first' uC。 //后续 UC 也会收到类似的信息,但有差距! //第一个接收到的字是虚拟字,用于启动传输 //第二个接收到的字是命令字-当调用此函数 时收到该字(Receive_Count < 37)//Receive_Count 是预期字的数量 { local_buffer = SpibRegs.SPIRXBUF local_buffer = 0x8345; // 'this'="" device="" -="" route="" it="" through="" receive_count++;="" while="" (spibregs.spists.bit.int_flag="" !="1)" received="" character="" in="" buffer="" poll="" flag="" {="" }="" function="" resets="" timer="" reset="" everything!="" receive_count="0;" counter="" transmit_count="0;" transmit="" count=""
您好!
已将这一问题通知有关专家。
请注意、这是美国的感恩节周、大多数 TI 工程师都不在。
请预计下周初收到延迟的回复。
此致、
Sudhakar
------------------------------------------------------
如果帖子回答了您的问题、请使用 "验证答案" 按钮进行标记。
其他有用链接:
我已附上您请求的图片
为清楚起见、我没有在从器件上使用!SPISTEB 信号、并且我将它们一直绑定到低电平(我认为这不会导致我看到的效果、因为这不会影响 SPICLK 位计数)、并且直接路由时的虚拟数据也不受影响。 只有当我覆盖时、它才会出现问题。
硬件设计包含8个 uC "菊花链"、其中 uC 1作为主设备。 数据流由两个"控制"字(每个16字节长)组成、后跟虚拟数据、这些虚拟数据使用以下7 uC (uC2 - uC 8)中的真实数据进行覆盖。
为了实现波形的目的、进入 uC2的所有数据都使用8345进行覆盖。 但是、产生的结果是左舍入的-068B- (建议17位计数)
在图1中、我尝试显示设置并保持 SPICLK 的任一侧、并显示通过 UC2路由的前16位。
通道1是时钟(16个"边沿")
通道2是从 uC 2传输的数据。 该数据应为8345,但会左移1位,因此为068B。
通道3是 uC2的输入、是"虚拟"数据后的两个控制字(6789 -尽管我尝试了不同的数据模式)
在图2中、我显示的是相同的东西、但时间更长。
感谢您(或其他团队成员)在这方面的帮助。
此致
j
您好、Veena、
不确定如果已经移出了什么内容、如何查看本地缓冲器?
您能告诉我如何看待它吗?
j
John、
几个问题:
很抱歉、我真的不认为有任何位移发生、这可能是您构建软件的方式。 如果您从未在时钟线上看到时钟位、我看不到这种情况会发生。 如果我遗漏了您之前提到的任何内容、请原谅我。
侧注-请避免将代码粘贴到文本正文中富文本编辑器中有一个带有 此图标的代码格式器工具: 。 默认情况下、您可以折叠代码。 由于代码格式正确、它使线程更易于跟踪和读取。 我继续编辑了您的原始帖子、以显示其外观。
当然、在我键入所有这些内容之后、我更难查看您的从器件发送代码、并发现可能是问题的东西。 进入 while 循环后、您将立即读取 SPIRXBUF。 该循环中的第一个可能是对 INT_FLAG 的轮询。 尤其是在没有芯片选择引脚提供的 SPI 传输门和 SPI 状态机复位的情况下、您可能会被单个位关闭、并且无法恢复。
此外、我不确定为什么您在 INT_Flag 上使用外部 while 环路来使用主控方 READ_SPI_Data 函数。 该函数的整个结构看起来有点偏。 考虑将第11行操作为:while (int_flag!= 1){}//其余代码。
Mark、您好!
感谢您回来。
答案如下:
1是的、全部为28035
2主器件运行 S/W_Master、7个从器件运行 S/W_Slave。
3我回到了信号质量的第一原则。 时钟非常干净(我在发送端包含了一个22R 电阻器以提高信号完整性)、数据也非常干净、示波器显示设置和保持时间非常出色。
4 S/W 或 H/W 中没有发生其他事件 该设计只需使用从器件的 A/D 启动一系列电压、并通过 SPI 总线将结果传输到主器件。 我正在为每个从器件使用隔离式 SPI 收发器(测量的传播延迟小于5ns、信号质量出色)。 没有可能产生噪声的大电流开关。 在测试中、我目前尚未连接任何要测量的电压、并且正在"模拟"A/D 读数以使 SPI 正常工作。
5此设计包括重复的"同步"过程、可满足此类需求。
6个会的
7我目前正在查看第一个从器件的输出。 这将从主控方接收虚拟和控制字(每个字16 btis)。 在完成的应用程序中,虚拟字和控制字被传送到第二个从器件(然后是第三个....) 以下虚拟数据与 A/D 结果一起被改写。 为了进行测试、我将"尝试"以使用"已饱和"A/D 数据覆盖所有数据。 所发生的情况是、第一个从器件(和其余从器件)输出的仿真数据按照所述的方式(向左移位1位)被损坏。 由于所有从器件代码都是相同的(读取硬件的简单3位代码可使从器件软件确定其在序列中的位置并预加载一系列数据计数器)、因此事实证明这非常简单。
8我可以减少从器件的数量、但这需要削减和连接-我宁愿避免这样做。 由于我能够监控第一个从器件的输出、因此我有效地对链进行了编辑。 此外、正如我之前的亚发射中提到的、如果我允许虚拟和控制字不受阻碍地通过、数据就不会损坏(这是一个奇怪的位、因为它表明我已经正确设置了所有内容)。
9我读过 FIFO 使用情况、但看不出有什么理由使用它、因为设计简单且"低"。 我会更好地为任何未来的示波器跟踪做注释、遗憾的是、示波器不是我通常使用的示波器、我仍在学习如何驱动它!
我正在查看您有关 while 循环的后续电子邮件。 将于今天上午晚些时候提供建议
感谢您迄今提供的支持
j
回复:代码提交-我将使用 对于将来提交的代码、我的 BAD!
您好、Mark。
嗯、我有一种解决方案。
SPI 总线出现为17位时钟(左移1位)的问题似乎是围绕着 I 对进入 SPI 输入的数据进行写操作、还是直接传输进入的数据。
如果我执行以下操作:
虚拟= SpibRegs.SPIRXBUF;
虚拟= 0xAFAF; //覆盖出现的内容
SpibRegs.SPITXBUF =虚拟;
数据损坏、SPI 输出结果为0x5F5F (左移1位)
执行以下操作
虚拟= SpibRegs.SPIRXBUF;
SpibRegs.SPITXBUF =虚拟;
数据从 SPI 输出中输出、不会损坏。
显然、我希望有选择性地覆盖传入的数据、以便 在写入数据后立即引入短延迟。
虚拟= SpibRegs.SPIRXBUF;
虚拟= 0xAFAF; //覆盖出现的内容
延迟 //延迟几个时钟周期
SpibRegs.SPITXBUF =虚拟;
新数据从 SPI 输出中输出、但不会损坏。
当写入发送给 SPI Txbuffer 的新数据时、似乎需要几个时钟周期。 这很奇怪–TI SPI 手册中没有任何内容表明需要延迟或要检查的任何其他标志。
必须使用任意延迟似乎并不正确,必须有一个寄存器或标志来指示新数据已准备好传输.....
您能不能对这种奇怪的情况下做出任何说明?
j
void transmit _spi_Data (void) { Transmit _Count = 0; Receive_Count = 0; while (Receive_Count < 37) //receive_Count 是预期字数(37) { while (SpibRegs.SPISTS.bit.INT_flag!= 1) //等待 SPI 标志指示新消息已到达-轮询该标志! {} if ((Receive_Count >(Data_Location - 1))和(Receive_Count <(Data_Location + 4)))//简单地确定从数据的放置位置 { Slave_Dummy = SpibRegs.SPIRXBUF; //简单读取以清除标志 Slave_Data = SPI_TxArray[Transmit _Count];//从 TxArray 获取数据 非常短的延迟(); //需要这个短暂的延迟!!!!!!!!!!!! SpibRegs.SPITXBUF = Slave_Data;//将数据放置在 TxBuffer 中 Transmit _Count++;//goto the next TxArray location } 否则、如果(Receive_Count = Geographic _Location) //在流中标识'this'位置的'command'字 { Command_Message = SpibRegs.SPIRXBUF; //存储“命令”字。 //非常短接延迟(); SpibRegs.SPITXBUF = Command_Message; //将命令 Word 路由到下一个 UC (7个从设备,1个主设备) } 其他 { Slave_Data = SpibRegs.SPIRXBUF; //非常短接延迟(); SpibRegs.SPITXBUF = Slave_Data; //如果数据不适用于“此”设备,则只需将其路由 到}即可 Receive_Count++; } Receive_Count = 0; //重置计数器 Transmit _Count = 0; //重置发送计数 } void SPI_Setup (void) //SPI 端口 B { SpibRegs.SPICCR.bit.SPISWRESET = 0;//强制 SPI 复位 SpibRegs.SPICCR.bit.SPICHAR = 15;// SpibRegs.SPICCR.bit.CLKPOLARITY = 0;// SpibRegs.SPICCR.bit.SPILBK = 0;//强制 SPI 复位,16位,时钟极性,环回关闭 SpibRegs.SPIBRR = 0x0A;//SPI 时钟速度-慢速0x02 SpibRegs.SPICTL.ALL = 0x02;//CLK_PHASE = 0、启用数据传输、禁用 SPI 中断(轮询)、// 0 =从器件;(0x0A / 0x02) EALLOW; //仅将所选引脚的限定条件设置为异步 //这将为所选引脚选择异步(无限定条件)。 GpioCtrlRegs.GPAQSEL1.bit.GPIO12 = 3;//异步输入 GPIO12 (SPISIMOB) GpioCtrlRegs.GPAQSEL1.bit.GPIO13 = 3;//异步输入 GPIO13 (SPISOMIB) GpioCtrlRegs.GPAQSEL1.bit.GPIO14 = 3;//异步输入 GPIO14 (SPICLKB) GpioCtrlRegs.GPAQSEL1.bit.GPIO15 = 3;//异步输入 GPIO14 (!SPISTEB)这在 PCB 上连接低电平。 //使用 GPIO 寄存器配置 SPI-B 引脚 //这指定哪些可能的 GPIO 引脚将是 SPI 功能引脚。 GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 3;//将 GPIO12配置为 SPISIMOB GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 3;//将 GPIO13配置为 SPISOMIB GpioCtrlRegs.GPAMUX1.bit.GPIO14 = 3;//将 GPIO14配置为 SPICLKB GpioCtrlRegs.GPAMUX1.bit.GPIO15=3;//将 GPIO115配置为 SPISTEB 在 PCB 上绑定为低 电平// GpioCtrlRegs.GPAPUD.bit.GPIO14=1;//禁用 GPIO14上的上拉电阻器(SPICLKB).................................. >>><<< EDIS; SpibRegs.SPICCR.bit.SPISWRESET = 1; //清除 SPI 复位 GpioDataRegs.GPASET.bit.GPIO6 = 1; //启用 SPI 缓冲 器} void set_up_Clock (void) { EALLOW; // LOSPCP 预分频寄存器设置,通常它将设置为默认值 GpioCtrlRegs.GPAMUX2.bit.GPIO18=0;//关闭 X法规 判例法 // SysCtrlRegs.LOSPCP。all = 0x0002; // XCLKOUT 与 SYSCLKOUT 之比。 LSPCLK = SYSCLKOUT/4 SysCtrlRegs.LOSPCP。all = 0x0004; // XCLKOUT 与 SYSCLKOUT 之比。 LSPCLK = SYSCLKOUT/8 SysCtrlRegs.XCLK.bit.XCLKOUTDIV = 3; //外设时钟启用针对所选外设的设置。 = XCLKOUT 3 =关闭 SysCtrlRegs.CLKCTL.bit.XTALSCOFF = 1;// Crystal OSC 关闭(内部时钟) SysCtrlRegs.CLKCTL.bit.XCLKINOFF = 1;//外部时钟输入关闭(内部时钟) SysCtrlRegs.CLKCTL.bit.INTOSC1OFF = 0;//(内部时钟) SysCtrlRegs.CLKCTL.bit.OSCCLKSRCSEL = 0;//内部 OSC1选择的 OSCCLK //关闭不需要的时钟 SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1; // ADC -- SysCtrlRegs.PCLKCR3.bit.COMP1ENCLK = 0;// COMP1 SysCtrlRegs.PCLKCR3.bit.COMP2ENCLK = 0;// Comp2 SysCtrlRegs.PCLKCR3.bit.COMP3ENCLK = 0;// Comp3 SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 0;// eCAP1 SysCtrlRegs.PCLKCR0.bit.ECANAENCLK = 0;// eCAN-A SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 0;// eQEP1 SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 0;// ePWM1 SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 0;// ePWM2 SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 0;// ePWM3 SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 0;// ePWM4 SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 0;// ePWM5 SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 0;// ePWM6 SysCtrlRegs.PCLKCR1.bit.EPWM7ENCLK = 0;// ePWM7 SysCtrlRegs.PCLKCR0.bit.HRPWMENCLK = 0;// HRPWM SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 0; // I2C SysCtrlRegs.PCLKCR0.bit.LINAENCLK = 0; // LIN-A SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK = 0; // CLA1 SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 0; // SCI-A SysCtrlRegs.PCLKCR0.bit.SPIANCLK = 0; // SPI-A SysCtrlRegs.PCLKCR0.bit.SPIBENCLK = 1; // SPI-B --- SysCtrlRegs.PCLKCR2.bit.HRCAP1ENCLK = 0; SysCtrlRegs.PCLKCR2.bit.HRCAP2ENCLK = 0; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC=0; //在 ePWM 内启用 TBCLK EDIS; }
Mark、您好!
SPI 总线的问题仍然存在。
我同意、轮询 INT_FLAG 是检查 RXBUF 是否已满并准备好读取的正确方法。 我之前提交的代码没有强调我已经执行了这项操作、因此我现在已经包含了代码。
您将注意到、我包含了一个可防止数据损坏的短延迟例程。 但是、在确定 RXBUF 已满(轮询 INT_FLAG)时、应该不需要、我应该能够简单地将我喜欢的任何值写入 TXBUF。 如果我删除延迟例程、则数据会损坏。
我认为 UC 或代码结构没有任何问题(其他一切都正常),但我真的很损失。
我还包括了 SPI 总线程序的设置和时钟的设置–我认为问题可能在于其中的一个。
如果您能提供任何帮助、我将不胜感激
j
Mark、您好!
感谢您的再次光临。
‘芯片选择引脚可能是问题,因为只有当我覆盖从器件接收到的“进入”时,才会出现问题。 ‘我不覆盖(我只需将接收到的数据放在 Tx 缓冲区中),则数据不会损坏–因此使能引脚不会影响接收到的数据的“我要做什么”。 此外、当我路由数据时不覆盖数据、它将完全通过所有7 uC。
我已经减慢了主器件的速度–认为可能存在 SPICLK 速度问题、但这没有影响、并且仍然需要非常短的延迟(延迟例程在从器件中–这与直觉相反)。 我已经尝试了许多较慢的主速度、但它无法解决问题。 此外、损坏的性质表明数据在一个位之前(向左移位)随时钟输出。 这使我认为器件会将我写入 Tx 缓冲器的数据保持在移动状态。 如果我在从器件中花费太长的时间将数据放入 TxBuffer、则它将被右移(例如、一个或多个时钟延迟)。
‘芯片选择需要相当多的“剪切和链接”(有7个从器件和1个主器件 UC)。 除非我能清楚地看到这是问题,我认为这不是问题,否则我会这样做。 我对时钟和数据有很好的‘re、并且有清晰和独特的时钟边沿(16个关闭)、并且 Δ I sting‘state 很低、可防止任何杂散边沿。
添加 GPIO 切换以查看事件发生的位置是个好主意(只是希望执行一些 GPIO 切换不会导致问题消失!)。 将在之前提供。
我们是否有办法加快有关这一问题的信函往来,因为我面临着一些进展的压力?
j
Mark、您好!
我想我已经解决了!
简而言之、在主微控制器的配置过程中会产生一个杂散 SPICLK 边沿。 我‘s地认为,如果我进行 SPI 复位(SPICCR.7=0 ),它将清除 SPI 计数器,从而允许我通过执行 SPI 复位随时“同步”所有从器件。
‘的情况是,复位不会重置 SPI 位计数(请确认这种情况,因为我找不到任何显示“将”重置位计数的内容),因此数据始终为1位输出(向左移位)。
为了解决这一问题、我现在介绍了一个简单的同步过程、该过程将信号切换至从器件、并且仅在接收到信号后配置了从器件 SPI。 当主器件被配置且时钟已稳定至休眠状态(低电平)后,会‘切换’。 这可防止一个寄生边沿(从高电平到低电平的转换–这是将数据时钟移入从器件的边沿)。
我已经阅读了无数次应用手册、但在任何地方都找不到真正复位 SPI 位计数器的内容。 是否需要对 SPI 模块执行完整的重新配置以复位计数器?
j