打印
[应用相关]

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

[复制链接]
34|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;

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

        SPIx->DR ;
    }

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

        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;

        //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 = 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;
     //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;
     //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;
                        //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 = 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);*/
    return 0;
} // end readfromspi()




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

纠正
其实这个是我自己写错了,SPI加了延迟以后。收发数据太慢了,对于定位测距来说是很大的问题。而且SPI传输需要加延时很明显是有问题的,于是我从头开始找问题。
终于找到问题了:

在while等待那里,我把状态寄存器写成了数据寄存器,所以while是没有效果的,加了延时后因为状态寄存器在延时时候置位了。所以可以正常通信了。
while((SPIx_INIT->DAT & SPI_I2S_RNE_FLAG) == (uint16_t)RESET); //DAT是数据寄存器而不是状态寄存器。
正确写法应该是这样:while((SPIx_INIT->STS & SPI_I2S_RNE_FLAG)

所以国民技术SPI和DW1000通信的正确代码如下:

int writetospi_serial
(
    uint16       headerLength,
    const uint8 *headerBuffer,
    uint32       bodylength,
    const uint8 *bodyBuffer
)
{
          int i=0;  
   // stat = UWB_Interrupt_off();

           GPIO_ResetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉低CS
       
    for(i=0; i<headerLength; i++)
    {
            SPIx_INIT->DAT = headerBuffer;
        while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);
           
            SPIx_INIT->DAT ;
    }

    for(i=0; i<bodylength; i++)
    {
             SPIx_INIT->DAT = bodyBuffer;
        while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);

                 SPIx_INIT->DAT ;
         }

        GPIO_SetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉高CS
    //UWB_Interrupt_on(stat) ;
    return 0;
} // end writetospi()


int readfromspi_serial
(
    uint16_t       headerLength,
    const uint8_t *headerBuffer,
    uint32_t       readlength,
    uint8_t       *readBuffer
)
{
          int i=0;
    //stat = UWB_Interrupt_off() ;       
          GPIO_ResetBits(SPIx_GPIO_INIT,SPIx_CS_INIT);  //拉低CS       
    for(i=0; i<headerLength; i++)
    {
                       
             SPIx_INIT->DAT = headerBuffer;
                       
                 while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);

               readBuffer[0] = SPIx_INIT->DAT ; // Dummy read as we write the header
                       
    }
    for(i=0; i<readlength; i++)
    {                       
            SPIx_INIT->DAT = 0;  // Dummy write as we read the message body        
                while(SPI_I2S_GetStatus(SPIx_INIT, SPI_I2S_RNE_FLAG) == RESET);
                   readBuffer = SPIx_INIT->DAT ;//port_SPIx_receive_data(); //this clears RXNE bit                       
    }
        GPIO_SetBits(SPIx_GPIO_INIT,SPIx_CS_INIT); //拉高CS
    return 0;
} // end readfromspi()

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_46107106/article/details/138178919

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

50

帖子

0

粉丝