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.
unsigned char trans[6] = {0xAA,0xC3,0x00,0xA2,0x00,0x24}; //所要发送的信息 void spi_xmit(Uint16 a); //发送一个数据 void Ready_Config(); //从机芯片ready标志位,此位读到1表明从机已经准备好,才可以与从机进行通信 void SPI_RXbuff(unsigned char *buff,unsigned int len); void SPI_TXbuff(unsigned char *buff,unsigned int len); unsigned char cmd_result[2] = {0x00}; //所要接收的返回信息存放数组,目前为0 void main(void) { Ready_Config(); //TI官方spi loopback例程,给出的初始化 // Step 1. Initialize System Control: // PLL, WatchDog, enable Peripheral Clocks // This example function is found in the F2837xS_SysCtrl.c file. InitSysCtrl(); // Step 2. Initialize GPIO: // This example function is found in the F2837xS_Gpio.c file and // illustrates how to set the GPIO to it's default state. InitGpio(); // Skipped for this example // Setup only the GP I/O only for SPI-A functionality // This function is found in F2837xS_Spi.c InitSpiaGpio(); // Step 3. Clear all __interrupts and initialize PIE vector table: // Disable CPU __interrupts DINT; // Initialize PIE control registers to their default state. // The default state is all PIE __interrupts disabled and flags // are cleared. // This function is found in the F2837xS_PieCtrl.c file. InitPieCtrl(); // Disable CPU __interrupts and clear all CPU __interrupt flags: IER = 0x0000; IFR = 0x0000; // Initialize the PIE vector table with pointers to the shell Interrupt // Service Routines (ISR). // This will populate the entire table, even if the __interrupt // is not used in this example. This is useful for debug purposes. // The shell ISR routines are found in F2837xS_DefaultIsr.c. // This function is found in F2837xS_PieVect.c. InitPieVectTable(); // Step 4. Initialize the Device Peripherals: InitSpi(); // init SPI //发送接收 SPI_TXbuff(trans,6); DELAY_US(10); SPI_RXbuff(cmd_result,2); } //各函数定义 void spi_xmit(Uint16 a) { //while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG); SpiaRegs.SPITXBUF=a; // SPI Serial Output Buffer Register //while(SpiaRegs.SPISTS.bit.INT_FLAG != 1); } //Ready信号接收引脚设置为GPIO10 void Ready_Config() { EALLOW; GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 0; //i/o // GpioCtrlRegs.GPAPUD.bit.GPIO10 = 0; //内部上拉 GpioCtrlRegs.GPADIR.bit.GPIO10 = 0; //input EDIS; } //接收缓冲区数据函数 void SPI_RXbuff(unsigned char *buff,unsigned int len) //uint8_t uint32_t { unsigned int i = 0; if(len==0) return; while(GpioDataRegs.GPADAT.bit.GPIO10 == 0);//等待从机就绪 GpioDataRegs.GPACLEAR.bit.GPIO11 = 1; //拉低片选信号 DELAY_US(10); for(i=0;i<len;i++) { buff[i] = (SpiaRegs.SPIRXBUF>>8); DELAY_US(10); } GpioDataRegs.GPASET.bit.GPIO11 = 1;//拉高片选信号 } //发送缓冲区数据函数 void SPI_TXbuff(unsigned char *buff,unsigned int len) //uint8_t uint32_t { unsigned int i = 0; if(len==0) return; while(GpioDataRegs.GPADAT.bit.GPIO10 == 0);//等待从机就绪 GpioDataRegs.GPACLEAR.bit.GPIO11 = 1; //拉低片选信号 DELAY_US(10); for(i=0;i<len;i++) { spi_xmit(buff[i]); //左移8位,适应MSB的要求 DELAY_US(10); } GpioDataRegs.GPASET.bit.GPIO11 = 1;//拉高片选信号 } //spi.c文件里spi配置 #include "F2837xD_device.h" #include "F2837xD_Examples.h" // // Calculate BRR: 7-bit baud rate register value // SPI CLK freq = 115200 Hz // LSPCLK freq = CPU freq / 4 (by default) // BRR = (LSPCLK freq / SPI CLK freq) - 1 // #if CPU_FRQ_200MHZ #define SPI_BRR ((200E6 / 4) / 115200) - 1 #endif #if CPU_FRQ_150MHZ #define SPI_BRR ((150E6 / 4) / 115200) - 1 #endif #if CPU_FRQ_120MHZ #define SPI_BRR ((120E6 / 4) / 115200) - 1 #endif // // InitSPI - This function initializes the SPI to a known state // void InitSpi(void) { // Initialize SPI-A // Set reset low before configuration changes // Clock polarity (0 == rising, 1 == falling) // 8-bit character // disable loop-back SpiaRegs.SPICCR.bit.SPISWRESET = 0; SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; SpiaRegs.SPICCR.bit.SPICHAR = (8-1); SpiaRegs.SPICCR.bit.SPILBK = 0; // Enable master (0 == slave, 1 == master) // Enable transmission (Talk) // Clock phase (0 == normal, 1 == delayed) // SPI interrupts are disabled SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1; SpiaRegs.SPICTL.bit.TALK = 1; SpiaRegs.SPICTL.bit.CLK_PHASE = 0; SpiaRegs.SPICTL.bit.SPIINTENA = 0; // Set the baud rate SpiaRegs.SPIBRR.bit.SPI_BIT_RATE = SPI_BRR; // Set FREE bit // Halting on a breakpoint will not halt the SPI SpiaRegs.SPIPRI.bit.FREE = 1; // Release the SPI from reset SpiaRegs.SPICCR.bit.SPISWRESET = 1; } // // InitSpiGpio - This function initializes GPIO pins to function as SPI pins. // Each GPIO pin can be configured as a GPIO pin or up to 3 // different peripheral functional pins. By default all pins come // up as GPIO inputs after reset. // // Caution: // For each SPI peripheral // Only one GPIO pin should be enabled for SPISOMO operation. // Only one GPIO pin should be enabled for SPISOMI operation. // Only one GPIO pin should be enabled for SPICLK operation. // Only one GPIO pin should be enabled for SPISTE operation. // Comment out other unwanted lines. // void InitSpiGpio() { InitSpiaGpio(); } // // InitSpiaGpio - Initialize SPIA GPIOs // void InitSpiaGpio() { EALLOW; // // Enable internal pull-up for the selected pins // // Pull-ups can be enabled or disabled by the user. // This will enable the pullups for the specified pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPAPUD.bit.GPIO16 = 0; // Enable pull-up on GPIO16 (SPISIMOA) // GpioCtrlRegs.GPAPUD.bit.GPIO5 = 0; // Enable pull-up on GPIO5 (SPISIMOA) GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pull-up on GPIO17 (SPISOMIA) // GpioCtrlRegs.GPAPUD.bit.GPIO3 = 0; // Enable pull-up on GPIO3 (SPISOMIA) GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0; // Enable pull-up on GPIO18 (SPICLKA) GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0; // Enable pull-up on GPIO19 (SPISTEA) // // Set qualification for selected pins to asynch only // // This will select asynch (no qualification) for the selected pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPAQSEL2.bit.GPIO16 = 3; // Asynch input GPIO16 (SPISIMOA) // GpioCtrlRegs.GPAQSEL1.bit.GPIO5 = 3; // Asynch input GPIO5 (SPISIMOA) GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch input GPIO17 (SPISOMIA) // GpioCtrlRegs.GPAQSEL1.bit.GPIO3 = 3; // Asynch input GPIO3 (SPISOMIA) GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch input GPIO18 (SPICLKA) GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3; // Asynch input GPIO19 (SPISTEA) // //Configure SPI-A pins using GPIO regs // // This specifies which of the possible GPIO pins will be SPI functional // pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA // GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 2; // Configure GPIO5 as SPISIMOA GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA // GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 2; // Configure GPIO3 as SPISOMIA GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1; // Configure GPIO19 as SPISTEA //使能软件片选信号 GPIO11 GpioCtrlRegs.GPAMUX1.bit.GPIO11 = 0; // 设置为普通的GPIO模式 GpioCtrlRegs.GPADIR.bit.GPIO11 = 1; //设置为输出i/o EDIS; } // // End of file //
debug结果为:
可以看出RXBUF的值就是TXBUF的值左移8位(用16进制可以很明显观察到,比如TXBUF是0x24,RXBUF就是0x2400)。loopback模式已经禁用,可是还是感觉数据传输处于loopback模式里,没有真正接收到从机返回值。
以上问题无论是否启用中断模式都是一样存在。
RXBUF数据与TXBUF数据左移八位的问题参考论坛内其他问题的讨论,将发送函数改为:
void SPI_TXbuff(unsigned char *buff,unsigned int len) { unsigned int i = 0; if(len==0) return; while(GpioDataRegs.GPADAT.bit.GPIO10 == 0);//等待从机就绪 GpioDataRegs.GPACLEAR.bit.GPIO11 = 1; //拉低片选信号 DELAY_US(10); for(i=0;i<len;i++) { spi_xmit((Uint16)buff[i]<<8); //左移8位,适应MSB的要求 //delay_loop(); DELAY_US(10); } GpioDataRegs.GPASET.bit.GPIO11 = 1;//拉高片选信号 }
即强制移位8位再送入缓冲区。但这样以来出现了新的问题,就是SPIDAT寄存器的值一直为0,好像没有在发送了,RXBUF的值也一直为0,怀疑是没有发送出去,从机也没有返回值进来。
不知道这样是什么原因呢?难道是spi设置上出了什么问题?
可以的,以下是我调试的结果,事实上,程序流程进行的还算顺利,我先附上我程序的完整版,我在上面的问题里附上的实际上只是一次发送接收的过程的代码,事实上我完整的程序需要几次发送和接收。
我在测试第一次发送和接收时就出现了问题SPIDAT始终为0的问题,调试程序时,我运行至SPI_TXbuff(cmd_loadkey,6)函数,函数成功进行至spi_xmit(Uint16 a)函数,并将要发送的数据发送给SPITXBUF,但遗憾的是,SPITXBUF里的值并没有出现在SPIDAT里面,SPIDAT的值始终保持为0。
在用SPI_TXbuff(cmd_loadkey,6)发送完一个长度为6的数组数据后,SPITXBUF的值为cmd_loadkey数组数据的最后一个值0x24(值得注意的是由于spi_xmit(Uint16 a)需要的参数长度为16位,而我所要发送的数组元素均为长度8位的数据,且dsp的spi发送默认采取MSB方式,所以根据网上资料的建议,将数据左移8位并进行强制类型转换进行发送(spi_xmit((Uint16)buff[i]<<8);),所以SPITXBUF数据显示为9216(0x2400))。但是SPIDAT寄存器始终为0,当然SPIRXBUF也没有接收的返回值,始终为0。
附上调试的图片和完整代码
你这里的配置看起来是没有什么问题的,你的从机是什么?相关的接线是否正确?
RXBUF数据与TXBUF数据左移八位的问题参考论坛内其他问题的讨论
这里你参考的是哪篇帖子?
能否分享下你的工程?
您好,我的从机是一款加密芯片,相关接线目前排查正确的,而且我个人感觉如果是SPIDAT寄存器始终为0的话,可能是28377d这边的问题,因为从spitxbuf传送至spidat的过程按理来说应该是28377d芯片内部自行进行的过程。
我的工程要怎样分享给您呢?好像论坛上只能发布代码?
您看这个工程文件您能否打开?
我这边打开后这些文件都缺失了:
我这边一般也是采取和您一样的方法接收数组。
我怀疑可能是您工程中的配置问题或是代码中有些细节问题我没有注意到,所以想直接看看您的工程。
您在loopback模式下调试有问题吗?您可以先在loopback模式中调试一下。
你好,我这边出了点问题,所以暂时无法测试您的程序。
我咨询了一下资深工程师,这边建议您使用示波器观察下SPI的4个引脚的信号看看是否有什么缺失,以及这边认为您的spi初始化可能有些问题,建议按照TRM第18.4.2章节来初始化spi。
好的,但是我这个SPI的设置是在TI官网例程下改的。而且也是按照这个文档里进行设置的,刚刚我又检查了一遍,好像是与这个18章里面的流程一致的
唯一的问题是,咱们官网28377d的SPI例程是否是我上面所发的那样?我看您给的链接中,TRM 18.5.1里面给出了一个例程位置,但是我并没有找到这里的这个路径,可以看到这里例程的命名与我所下载的例程命名不同,他这里是spi_ex1_loopback.c,我那个是spi_loopback_cpu1
以下是我spi.c文件的设置,好像流程上与18.4.2设置的是一样的。唯一的区别是OVERRUNFLAG和INTFLAG没有单独置0,但是根据手册,这两个标志位会在SPISWRESET置0时被清除,所以也是被置0过的了,而且即使加上这两个标志位置0的语句,SPIDAT内数据为0的问题也并未消失。
您看我这个spi.c的设置中存在问题吗?如果没有的话还可能有什么地方的设置会影响SPI呢?(事实上其他地方的设置我也并没有动过,全部都是例程的设置)
//########################################################################### // // FILE: F2837xD_Spi.c // // TITLE: F2837xD SPI Initialization & Support Functions. // //########################################################################### // $TI Release: F2837xD Support Library v210 $ // $Release Date: Tue Nov 1 14:46:15 CDT 2016 $ // $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated - // http://www.ti.com/ ALL RIGHTS RESERVED $ //########################################################################### // // Included Files // #include "F2837xD_device.h" #include "F2837xD_Examples.h" // // Calculate BRR: 7-bit baud rate register value // SPI CLK freq = 500 kHz // LSPCLK freq = CPU freq / 4 (by default) // BRR = (LSPCLK freq / SPI CLK freq) - 1 // #if CPU_FRQ_200MHZ #define SPI_BRR ((200E6 / 4) / 500000) - 1 #endif #if CPU_FRQ_150MHZ #define SPI_BRR ((150E6 / 4) / 500000) - 1 #endif #if CPU_FRQ_120MHZ #define SPI_BRR ((120E6 / 4) / 500000) - 1 #endif // // InitSPI - This function initializes the SPI to a known state // void InitSpi(void) { // Initialize SPI-A SpiaRegs.SPISTS.bit.BUFFULL_FLAG = 0; SpiaRegs.SPISTS.bit.INT_FLAG = 0; // Set reset low before configuration changes // Clock polarity (0 == rising, 1 == falling) // 16-bit character // Enable loop-back SpiaRegs.SPICCR.bit.SPISWRESET = 0; SpiaRegs.SPICCR.bit.CLKPOLARITY = 0; SpiaRegs.SPICCR.bit.SPICHAR = (8-1); SpiaRegs.SPICCR.bit.SPILBK = 0; // Enable master (0 == slave, 1 == master) // Enable transmission (Talk) // Clock phase (0 == normal, 1 == delayed) // SPI interrupts are disabled SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1; SpiaRegs.SPICTL.bit.TALK = 1; SpiaRegs.SPICTL.bit.CLK_PHASE = 0; SpiaRegs.SPICTL.bit.SPIINTENA = 0; // Set the baud rate SpiaRegs.SPIBRR.bit.SPI_BIT_RATE = SPI_BRR; // Set FREE bit // Halting on a breakpoint will not halt the SPI SpiaRegs.SPIPRI.bit.FREE = 1; // Release the SPI from reset SpiaRegs.SPICCR.bit.SPISWRESET = 1; } // // InitSpiGpio - This function initializes GPIO pins to function as SPI pins. // Each GPIO pin can be configured as a GPIO pin or up to 3 // different peripheral functional pins. By default all pins come // up as GPIO inputs after reset. // // Caution: // For each SPI peripheral // Only one GPIO pin should be enabled for SPISOMO operation. // Only one GPIO pin should be enabled for SPISOMI operation. // Only one GPIO pin should be enabled for SPICLK operation. // Only one GPIO pin should be enabled for SPISTE operation. // Comment out other unwanted lines. // void InitSpiGpio() { InitSpiaGpio(); } // // InitSpiaGpio - Initialize SPIA GPIOs // void InitSpiaGpio() { EALLOW; // // Enable internal pull-up for the selected pins // // Pull-ups can be enabled or disabled by the user. // This will enable the pullups for the specified pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPAPUD.bit.GPIO16 = 0; // Enable pull-up on GPIO16 (SPISIMOA) // GpioCtrlRegs.GPAPUD.bit.GPIO5 = 0; // Enable pull-up on GPIO5 (SPISIMOA) GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pull-up on GPIO17 (SPISOMIA) // GpioCtrlRegs.GPAPUD.bit.GPIO3 = 0; // Enable pull-up on GPIO3 (SPISOMIA) GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0; // Enable pull-up on GPIO18 (SPICLKA) GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0; // Enable pull-up on GPIO19 (SPISTEA) // // Set qualification for selected pins to asynch only // // This will select asynch (no qualification) for the selected pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPAQSEL2.bit.GPIO16 = 3; // Asynch input GPIO16 (SPISIMOA) // GpioCtrlRegs.GPAQSEL1.bit.GPIO5 = 3; // Asynch input GPIO5 (SPISIMOA) GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch input GPIO17 (SPISOMIA) // GpioCtrlRegs.GPAQSEL1.bit.GPIO3 = 3; // Asynch input GPIO3 (SPISOMIA) GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch input GPIO18 (SPICLKA) GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3; // Asynch input GPIO19 (SPISTEA) // //Configure SPI-A pins using GPIO regs // // This specifies which of the possible GPIO pins will be SPI functional // pins. // Comment out other unwanted lines. // GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA // GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 2; // Configure GPIO5 as SPISIMOA GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA // GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 2; // Configure GPIO3 as SPISOMIA GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1; // Configure GPIO19 as SPISTEA EDIS; } // // End of file //
对了,我想可能要向您说明我们这边目前已经排除的一些错误,之前的波特率设置可能有些问题,SPI时钟频率应该设为1MHZ及以下,但是在我们采用了正确波特率设置后也并未解决该通信问题。在这里我们分别尝试了1E6和0.5E6两个值,对应SPI时钟频率为标准的1MHZ和更低的0.5MHZ,均未解决问题,改动如图:
另外,我们这边也检查了CPOL和CPHA的设置,两者均为0,是没有问题的。如下图所示:
目前的现象是:从机芯片接上后和没有连接从机芯片的情况下,均是SPIDAT始终为0。只有loopback自测,或者将dsp的MOSI和MISO短接时,才能正常将SPITXBUF中数据送入SPIDAT,并接收到相同的数据。
期待您这边工程师的回复。
你好,参考下工程师的回复:
感谢您到目前为止的回复和有关您发现的信息。所以重申一下(如果我的理解是错误的,请纠正):
如果您在执行外部环回(MISO/MOSI 短路)时看到发送了正确的数据,则说明您的代码运行正常,并且您有正确的 SPI 通信成功。在主机模式下,当您向TXBUF写入数据时,数据将转移到SPIDAT并立即在MOSI线路上发送出去,因此您将不会在SPIDAT中看到传输的数据。相反,SPIDAT将显示从MISO线移入的接收数据。因此,如果从设备发送零,这就是您在 SPIDAT 中看到的内容。
因此,为了帮助调试,请使用示波器/分析仪查看 4 条 SPI 线路上的活动。具体来说,我们需要检查 SPICLK 是否显示脉冲,并检查 MISO 线路,以查看从设备是否正在向主设备发送数据或发送零。
你好,
之前的问题可能是由于spi是一个全双工通讯协议,要接收必须先发送,要发送也会接收,所以我修改了一下程序,把发送和接收合并了一下。程序改动如下:
好的,我跟进下
这样的延时在dsp 28377d的spi通讯中是可以被允许的吗?会不会造成接收数据的丢失呢?
没有必要使用延时,但是如果你使用了FIFO模式,则最好在写入 TXBUF 之前检查发送 FIFO 中是否有空间,并在读RXBUFF之前检查 FIFO 中是否有预期数量的完整/有效数据。这可以通过一个简单的“while”循环来完成,该循环在写入/读取之前检查 FIFO (TXFFST 和 RXFFST 位)。
通过今天下午的测试,我发现这个发送函数会在它实际开始运行之前(我使用了单步调试)发送出一个2048给从机,这并非我计划内的发送,不知道为什么会出现这一数据。
没有必要使用延时,但是如果你使用了FIFO模式,则最好在写入 TXBUF 之前检查发送 FIFO 中是否有空间,并在读RXBUFF之前检查 FIFO 中是否有预期数量的完整/有效数据。这可以通过一个简单的“while”循环来完成,该循环在写入/读取之前检查 FIFO (TXFFST 和 RXFFST 位)。
嗯嗯,我在新增的数据发送接收函数的接收数据之前进行了RXFFST的检查,至于您说的TXFFST的检查我似乎不太理解是什么意思?您能详细讲讲吗?