乐鑫技术交流
直播中

HCPcry

8年用户 1195经验值
擅长:处理器/DSP
私信 关注
[问答]

将ESP8266的HSPI配置为从机,,MISO信号相位不对怎么解决?

我将ESP8266的HSPI配置为从机,然后连接到我的STM32单片机上,写入与读取数据都没有问题,但是,通过逻辑分析仪的观察,发现MISO信号是在上升沿变化的,且逻辑分析仪分析出的数据是错误的。

STM32上运行的是RT_Thread操作系统,不停的发送与读取数据。代码如下:

void WriteTest(void)
{
   int i;
   esp8266_writeBuf[0] = 0x02;//0x02 写数据  0x03读数据
   esp8266_writeBuf[1] = 0x00;
   
   esp8266_writeBuf[2] = counter++;
   for (i = 0; i < 30; i++)
   {
      esp8266_writeBuf[i + 3] = 2;
   }
   esp8266_writeBuf[33] = esp8266_writeBuf[2];
      
   rt_memset(esp8266_readBuf,0,sizeof(esp8266_readBuf));
   esp8266_message.send_buf = esp8266_writeBuf;
   esp8266_message.recv_buf = esp8266_readBuf;   //设置读写缓存
   esp8266_message.length = 34;         //设置读写长度
   esp8266_message.cs_take = 1;         //开始通信时拉低CS
   esp8266_message.cs_release = 1;      //结束通信时拉高CS
   esp8266_message.next = RT_NULL;
   rt_spi_transfer_message(rt_spi_esp8266_device, &esp8266_message);//进行一次数据传输
   
   rt_kprintf("rnesp8266 write Buf is rn");
   for (i = 0; i < 34; i++)
   {
      rt_kprintf("%02X ", esp8266_writeBuf);
   }
}

void ReadTest(void)
{
   int i;
   esp8266_writeBuf[0] = 0x03;//0x02 写数据  0x03读数据
   esp8266_writeBuf[1] = 0x00;
   
   rt_memset(esp8266_writeBuf + 2, 0, 32);
   
   rt_memset(esp8266_readBuf,0,sizeof(esp8266_readBuf));
   esp8266_message.send_buf = esp8266_writeBuf;
   esp8266_message.recv_buf = esp8266_readBuf;   //设置读写缓存
   esp8266_message.length = 34;         //设置读写长度
   esp8266_message.cs_take = 1;         //开始通信时拉低CS
   esp8266_message.cs_release = 1;      //结束通信时拉高CS
   esp8266_message.next = RT_NULL;
   rt_spi_transfer_message(rt_spi_esp8266_device, &esp8266_message);//进行一次数据传输
   
   rt_kprintf("rnesp8266 read Buf is rn");
   for (i = 0; i < 34; i++)
   {
      rt_kprintf("%02X ", esp8266_readBuf);
   }
}
/*******************************************************************************
* 函数名    : wifi_thread_entry
* 描述      : 通信相关线程
* 输入        : - parameter: 线程入口参数
* 输出        : None
* 返回值    : None
*******************************************************************************/
void wifi_thread_entry(void* parameter)
{
   init_esp8266();
   while(1)
   {
      WriteTest();
      rt_thread_delayMs(10);
      ReadTest();
      rt_thread_delayMs(10);
   }   
}



ESP8266上使用的是esp8266_nonos_sdk_v2.0.0_16_07_19,并参照ESP8266_技术参考.pdf上41-44页的程序,只是增加了在中断中将接收到的数据通过串口输出的代码,代码如下
Code: Select all
uint32 intCounter = 0;
static uint8 spi_data[32] = {0};
static uint8 idx = 0;

// SPI interrupt callback function.
void spi_slave_isr_sta(void *para)
{
   uint32 regvalue;
   uint32 statusW, statusR, counter;
   uint32 recv_data,i;
   
   if (READ_PERI_REG(0x3ff00020)&BIT4)
   {
      //following 3 lines is to clear isr signal
      CLEAR_PERI_REG_MASK(SPI_SLAVE(SpiNum_SPI), 0x3ff);
   }
   else if (READ_PERI_REG(0x3ff00020)&BIT7)
   { //bit7 is for hspi isr,
   
/*      regvalue = READ_PERI_REG(SPI_USER(SpiNum_HSPI));
      os_printf("rnspi_slave_isr_sta SPI_USER[0x%08x]nr",regvalue);
   
      regvalue = READ_PERI_REG(SPI_ADDR(SpiNum_HSPI));
      os_printf("spi_slave_isr_sta SPI_ADDR[0x%08x]nr",regvalue);
   
      regvalue = READ_PERI_REG(SPI_CTRL(SpiNum_HSPI));
      os_printf("spi_slave_isr_sta SPI_CTRL[0x%08x]nr",regvalue);
   
      regvalue = READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI));
      os_printf("spi_slave_isr_sta SPI_RD_STATUS[0x%08x]nr",regvalue);
   
      regvalue = READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI));
      os_printf("spi_slave_isr_sta SPI_WR_STATUS[0x%08x]nr",regvalue);
*/
      regvalue = READ_PERI_REG(SPI_SLAVE(SpiNum_HSPI));
      os_printf("rnspi_slave_isr_sta SPI_SLAVE[0x%08x]   count is %dnr",regvalue, ++intCounter);
      SPIIntClear(SpiNum_HSPI);
      SET_PERI_REG_MASK(SPI_SLAVE(SpiNum_HSPI), SPI_SYNC_RESET);
      SPIIntClear(SpiNum_HSPI);
      SPIIntEnable(SpiNum_HSPI,    SpiIntSrc_WrStaDone
                           | SpiIntSrc_RdStaDone
                           | SpiIntSrc_WrBufDone
                           | SpiIntSrc_RdBufDone);
      if (regvalue & SPI_SLV_WR_BUF_DONE)
      {
         // User can get data from the W0~W7
         os_printf("spi_slave_isr_sta : SPI_SLV_WR_BUF_DONEnr");

         idx=0;
         while(idx<8)   //取8次,每次取出一个32位数,共取出32*8=256位,也即32个字节
         {
            recv_data=READ_PERI_REG(SPI_W0(HSPI)+(idx<<2));
            spi_data[idx<<2] = recv_data&0xff;
            spi_data[(idx<<2)+1] = (recv_data>>8)&0xff;
            spi_data[(idx<<2)+2] = (recv_data>>16)&0xff;
            spi_data[(idx<<2)+3] = (recv_data>>24)&0xff;
            idx++;
         }
         os_printf("data: nr");
         for(i=0;i<32;i++)
         {
            os_printf("%02X ",spi_data);
         }
         os_printf("rn");
      }
      else if (regvalue & SPI_SLV_RD_BUF_DONE)
      {
         // TO DO
         os_printf("spi_slave_isr_sta : SPI_SLV_RD_BUF_DONEnr");
      }
      if (regvalue & SPI_SLV_RD_STA_DONE)
      {
         statusR = READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI));
         statusW = READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI));
         os_printf("spi_slave_isr_sta : SPI_SLV_RD_STA_DONE[R=0x%08x,W=0x%08x]nr", statusR,statusW);
      }
      if (regvalue & SPI_SLV_WR_STA_DONE)
      {
         statusR = READ_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI));
         statusW = READ_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI));
         os_printf("spi_slave_isr_sta : SPI_SLV_WR_STA_DONE[R=0x%08x,W=0x%08x]nr", statusR,statusW);
      }
      if ((regvalue & SPI_TRANS_DONE) && ((regvalue & 0xf) == 0))
      {
         os_printf("spi_slave_isr_sta : SPI_TRANS_DONEnr");
      }
         //SHOWSPIREG(SpiNum_HSPI);
   }
}

void ICACHE_FLASH_ATTR spi_slave_test()
{
   // SPI initialization configuration, speed = 0 in slave mode
   SpiAttr hSpiAttr;
   hSpiAttr.bitOrder = SpiBitOrder_MSBFirst;
   hSpiAttr.speed = 0;
   hSpiAttr.mode = SpiMode_Slave;
   hSpiAttr.subMode = SpiSubMode_0;
   // Init HSPI GPIO
   // Configure MUX to allow HSPI
   WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105);
   PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode
   PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode
   PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode
   PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode
   os_printf("rn ============= spi init slave =============rn");
   SPIInit(SpiNum_HSPI, &hSpiAttr);
   // Set spi interrupt information.
   SpiIntInfo spiInt;
   spiInt.src = (SpiIntSrc_TransDone
   | SpiIntSrc_WrStaDone
   |SpiIntSrc_RdStaDone
   |SpiIntSrc_WrBufDone
   |SpiIntSrc_RdBufDone);
   spiInt.isrFunc = spi_slave_isr_sta;
   SPIIntCfg(SpiNum_HSPI, &spiInt);
   // SHOWSPIREG(SpiNum_HSPI);
   SPISlaveRecvData(SpiNum_HSPI);
   uint32_t sndData[8] = { 0 };
   sndData[0] = 0x35343332;
   sndData[1] = 0x39383736;
   sndData[2] = 0x3d3c3b3a;
   sndData[3] = 0x11103f3e;
   sndData[4] = 0x15141312;
   sndData[5] = 0x19181716;
   sndData[6] = 0x1d1c1b1a;
   sndData[7] = 0x21201f1e;
   // write 8 word (32 byte) data to SPI buffer W8~W15
   SPISlaveSendData(SpiNum_HSPI, sndData, 8);
   // set the value of status register
   WRITE_PERI_REG(SPI_RD_STATUS(SpiNum_HSPI), 0x8A);
   WRITE_PERI_REG(SPI_WR_STATUS(SpiNum_HSPI), 0x83);
}

/******************************************************************************
* FunctionName : user_init
* Description  : entry of user application, init user function here
* Parameters   : none
* Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
    os_printf("SDK version:%sn", system_get_sdk_version());

   //spi_test_init();
   //spi_master_test();
   spi_slave_test();
}



上半部分是STM32打印的调试信息,可以看到数据读取是没有问题的,下半部分是ESP8266打印的调试信息,可以发现数据写入也是没有问题的


但是,通过逻辑分析仪可以看到,ESP8266通过miso传送到STM32的数据出问题了,是在上升沿变化,且数据不正确



请问有朋友能帮我解答一下吗,谢谢
                                                                                                                                                

回帖(1)

李华

2024-7-12 18:01:27
从您的描述来看,问题可能出在MISO信号的相位上。在SPI通信中,有两种数据传输模式:CPHA=0(数据在时钟的上升沿采样)和CPHA=1(数据在时钟的下降沿采样)。根据您的描述,MISO信号在上升沿变化,这可能是由于STM32和ESP8266之间的CPHA设置不一致导致的。

要解决这个问题,您可以尝试以下步骤:

1. 检查STM32和ESP8266的SPI配置。确保它们的CPHA设置相同。在STM32上,您可以在初始化SPI时设置CPHA:

```c
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1;
```

在ESP8266上,您需要查找相应的SPI配置选项并进行设置。

2. 如果您已经确保了CPHA设置相同,但问题仍然存在,请检查SPI时钟极性(CPOL)。CPOL设置为0表示时钟空闲状态为低电平,设置为1表示时钟空闲状态为高电平。同样,确保STM32和ESP8266的CPOL设置相同。

3. 检查SPI速率(波特率)。确保STM32和ESP8266的SPI速率设置相同,以避免通信错误。

4. 如果以上步骤都无法解决问题,请尝试使用逻辑分析仪检查STM32和ESP8266之间的SPI信号,以确定问题出在哪个环节。

5. 如果问题仍然存在,您可以尝试在STM32上使用软件SPI,而不是硬件SPI,以获得更多的灵活性和控制。

希望这些建议能帮助您解决问题。如果问题仍然存在,请随时提供更多信息,以便我们能够更好地帮助您。
举报

更多回帖

×
20
完善资料,
赚取积分