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


    概述:为了减小硬件板子体积,也为了节约成本,现在需要把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); //拉高片选
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    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()
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    下面是我写的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
        return 0;
    } // end readfromspi()
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    总结

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

  • 相关阅读:
    抽象之美——万物皆可设计
    【RuoYi-Vue-Plus】扩展笔记 05 - CentOS 8 配置 Jenkins + Docker 自动发布
    (九)RabbitMQ交换机(Exchange)
    录制线上课程,有哪些形式,到底使用什么软件好?
    mysql索引一些思考
    美创科技荣升国家信息安全漏洞库(CNNVD)二级技术支撑单位
    太赞了!别再说 不能用Python开发美观的GUI程序了!
    多线程新手村3--多线程代码案例
    k8s--基础--12.2--pod--生命周期,状态,重启策略
    pytorch快速上手(8)-----pytorch优化器简介
  • 原文地址:https://blog.csdn.net/weixin_46107106/article/details/138178919