由把dwm1000模块从STM32单片机移植到N32单片机(国民技术)问题整理(UWB-八)

6 篇文章 2 订阅
1 篇文章 0 订阅

概述:为了减小硬件板子体积,也为了节约成本,现在需要把DWM1000模块从STM32单片机换到N32单片机上(国民技术),但是出现了很多问题,现在已经可以正常驱动了。把问题整理一下,看是否有朋友也遇到相同的问题。

单片机和DWM1000的SPI引脚连接

单片机和DWM1000是通过SPI进行通信的,单片机做主机。DWM1000做从机,支持SPI四种工作模式,默认模式0(SCK空闲低,第一个沿采样)
我把DW1000初始化配置完成写好后,运行代码提示初始化失败。于是我看了MCU从dw1000芯片读取的数据是0xff,也就是没有读到,没有通信。于是我就用逻辑分析仪抓了SPI的时序看。
在这里插入图片描述
紫色的是SCK,蓝色的是MOSI。数据本来是应该是正常脉冲翻转,但是有时候会突然被拉低或者被抬高一下然后马上恢复回去,这样就相当于有了杂波,数据也不对了。造成这种情况无非就是两种,一种就是电路有杂波(EMI),所有导致数据有问题。另外一直就是dw1000接到MCU的MOSI线的也是输出线,两边都发数据抢线操作。
看了一下DWM1000引脚图,MCU的MOSI接到DWM1000的MISO,MCU的MISO接到DWM1000的MOSI,SPI引脚就是这么接的没问题啊。
在这里插入图片描述

然后把板子给硬件工程师帮忙分析一下电路有没有问题。后面确实找到问题了,DWM1000这个模块跟别的器件引脚标的不一样。

别的器件需要把SPI输出对输入这样接,DWM10000的SPI接法是输出对输出,输入对输入,也就是MCU的MOSI接DWM1000MOSI,MCU的MISO接DWM1000的MISO。

应该是模块上面引脚图标的就是MCU的引脚,这里要注意,不要接错了。

引脚换完后又抓了一下波形,这次波形正常了
在这里插入图片描述
于是我又重新初始化DW1000芯片,奇怪的是这次还是失败了。

有些单片机的SPI在高速和低速传的数据会不一样,需要注意

明明波形数据都对了,怎么还是有问题呢。我又分析了一下。因为DW1000芯片初始化的时候需要把SPI速率降到3M以下,初始化完成再把速率升起来。是不是因为速率降低了,导致数据传输又错误了。然后我把低速率SPI的数据抓了一下,果然,明明传的0x55变成了0xaa 。这个就很奇怪。
经过反复抓取数据发现了问题。这个应该是单片机的问题。

while(1)
{
   GPIO_ResetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉低片选
  for(i=0;i<Size;i++)
 {
  while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_TE_FLAG) == RESET);
  SPI_I2S_TransmitData(SPI1, 0x55);
 }
  GPIO_SetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉高片选
}

while 等待发送缓冲区为空,当满足这个条件时,其实数据还没有完全发完,然后我就把CS拉高了。所以0x55—01010101 ,最后一位1还没发完CS就拉高了,然后拉低CS开始发送下一次的导致剩下的1当成下一次的头 本来01010101 ,前面多了个1 变成 10101010 ,挤出末尾的1也是去到下一次的头。所有就变成0xaa。高速的时候发的快,所以虽然拉高之后,while结束之后还没发完。但是在片选拉高之后也发完了。低速的时候很慢,所有while接收之后到片选拉高还有一位没发完。

所以低速的时候需要在while等待结束后面加一个延时,确保数据发完。

下面是官方和STM32单片机驱动DW1000的代码

//MCU通过SPI写入dw1000数据
int writetospi_serial
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       bodylength,
    const uint8 *bodyBuffer
)
{

    int i=0;

    decaIrqStatus_t  stat ;

    stat = decamutexon() ; //关闭DW1000的中断,可以不写

    SPIx_CS_GPIO->BRR = SPIx_CS; //拉低片选

    for(i=0; i<headerLength; i++)
    {
        SPIx->DR = headerBuffer[i];

        while ((SPIx->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);

        SPIx->DR ;
    }

    for(i=0; i<bodylength; i++)
    {
        SPIx->DR = bodyBuffer[i];

        while((SPIx->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);

        SPIx->DR ;
    }

    SPIx_CS_GPIO->BSRR = SPIx_CS;

    decamutexoff(stat) ;//开启DW1000的中断,可以不写

    return 0;
} // end writetospi()

//MCU通过SPI读取dw1000数据
int readfromspi_serial
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       readlength,
    uint8       *readBuffer
)
{

    int i=0;

    decaIrqStatus_t  stat ;

    stat = decamutexon() ;

    /* Wait for SPIx Tx buffer empty */
    //while (port_SPIx_busy_sending());

    SPIx_CS_GPIO->BRR = SPIx_CS;

    for(i=0; i<headerLength; i++)
    {
        SPIx->DR = headerBuffer[i];

        //while((SPIx->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);
        while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

        readBuffer[0] = SPIx->DR ; // Dummy read as we write the header
    }

    for(i=0; i<readlength; i++)
    {
        SPIx->DR = 0;  // Dummy write as we read the message body

        while((SPIx->SR & SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);

        readBuffer[i] = SPIx->DR ;//port_SPIx_receive_data(); //this clears RXNE bit
    }

    SPIx_CS_GPIO->BSRR = SPIx_CS;

    decamutexoff(stat) ;

    return 0;
} // end readfromspi()


下面是我写的N32(国民技术)驱动DW1000的代码

//MCU通过SPI写入dw1000数据
int writetospi_serial
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       bodylength,
    const uint8 *bodyBuffer
)
{

	  int i=0;

    int  stat ;

   // stat = UWB_Interrupt_off();

   // SPIx_CS_GPIO->BRR = SPIx_CS;
   	GPIO_ResetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉低CS
	
    for(i=0; i<headerLength; i++)
    {
    	SPIx_INIT->DAT = headerBuffer[i];
     //while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_TE_FLAG) == RESET); //换成这个初始化失败
    	while ((SPIx_INIT->DAT & SPI_I2S_RNE_FLAG) == (uint16_t)RESET);
	    Delay_ms(1); //延时必须加,不然失败
          
    	SPIx_INIT->DAT ;
    }

    for(i=0; i<bodylength; i++)
    {
     	SPIx_INIT->DAT = bodyBuffer[i];
     //while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_TE_FLAG) == RESET);//换成这个初始化失败
    	while((SPIx_INIT->DAT & SPI_I2S_RNE_FLAG) == (uint16_t)RESET);
			Delay_ms(1);//延时必须加,不然失败

		  SPIx_INIT->DAT ;
	 }

  // SPIx_CS_GPIO->BSRR = SPIx_CS;
	GPIO_SetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉高CS

    //UWB_Interrupt_on(stat) ;

    return 0;
} 


//MCU通过SPI读取dw1000数据
int readfromspi_serial
(
    uint16_t       headerLength,
    const uint8_t *headerBuffer,
    uint32_t       readlength,
    uint8_t       *readBuffer
)
{

	  int i=0;

    int  stat ;

    //stat = UWB_Interrupt_off() ;
	
   // UWB_DISABLE_IRQ;
    /* Wait for SPIx Tx buffer empty */
    //while (port_SPIx_busy_sending());

    //SPIx_CS_GPIO->BRR = SPIx_CS;
	
	  GPIO_ResetBits(SPIx_GPIO_INIT,SPIx_CS_INIT);  //拉低CS
	
    for(i=0; i<headerLength; i++)
    {
			//while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);
    	SPIx_INIT->DAT = headerBuffer[i];
			//while((SPIx_INIT->DAT & SPI_I2S_TE_FLAG) == (uint16_t)RESET);
			//while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_TE_FLAG) == RESET);
     //	while((SPIx_INIT->DAT & SPI_I2S_RNE_FLAG) == (uint16_t)RESET);
				
			while((SPIx_INIT->DAT & SPI_I2S_RNE_FLAG) == (uint16_t)RESET);
		 //while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);//换成这个失败
			Delay_ms(1);//延时必须加,不然失败
        
     	readBuffer[0] = SPIx_INIT->DAT ; // Dummy read as we write the header
			//while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);
			//Delay_ms(10);
    }


    for(i=0; i<readlength; i++)
    {
			
			//while((SPIx_INIT->DAT & SPI_I2S_RNE_FLAG) == (uint16_t)RESET);
    	SPIx_INIT->DAT = 0;  // Dummy write as we read the message body
      while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_TE_FLAG) == RESET); 
    	//while((SPIx_INIT->DAT & SPI_I2S_RNE_FLAG) == (uint16_t)RESET);
			
			while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);//这里可以多加一个代替延时
			//Delay_ms(1);
			/*	{
			   printf("readtospi_2\r\n");
			  }*/
 
	   	readBuffer[i] = SPIx_INIT->DAT ;//port_SPIx_receive_data(); //this clears RXNE bit
			
    }

    //SPIx_CS_GPIO->BSRR = SPIx_CS;*/

	GPIO_SetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉高CS
	//UWB_ENABLE_IRQ;
//	UWB_Interrupt_on(stat) ;
	/*	for(i=0;i<readlength; i++)
    printf("readBuffer[%d] = %d\r\n",i,readBuffer[i]);*/
    return 0;
} // end readfromspi()


总结

遇到DWM1000初始化失败的时候,不一定是硬件或者自己写的代码有问题。也可能是官方的代码写法不适合自己使用的单片机。因为不同的单片机特性和情况不一样。找问题时候不能只看上层,也需要去底层寻找问题。先看看MCU的SPI数据有没有问题,然后看能不能读取DW1000的数据,两者是否能够正常通信。如果MCU那边数据正常但是不能正常读取DW1000数据,可以修改官方底层代码来进行调试。

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值