MS1003时间测量芯片驱动配置(内附完整代码及注释)
MS1003是一款高精度时间测量芯片(TDC),具有ps级的时间分辨率(1ps时间内光飞行0.3mm),是MS1002的升级版,有更高的精度和更小的封装,配置方式也更丰富,适用于激光雷达、激光测距和脉冲间隔测量。◼自动测量START到STOP之间的时间间隔,无需再配置寄存器◼在非校准模式下,可以测量(小于配置的预期脉冲数)内的任意数量的脉冲◼双通道单精度模式测量最小时间分辨率46ps(光在1ps时
目录
六、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~
一、MS1003时间测量芯片简介
MS1003是一款高精度时间测量芯片(TDC),具有ps级的时间分辨率(1ps时间内光飞行0.3mm),是MS1002的升级版,有更高的精度和更小的封装,配置方式也更丰富,适用于激光雷达、激光测距和脉冲间隔测量。
MS1003主要特点:
◼ 自动测量START到STOP之间的时间间隔,无需再配置寄存器
◼ 在非校准模式下,可以测量(小于配置的预期脉冲数)内的任意数量的脉冲
◼ 双通道单精度模式测量最小时间分辨率46ps (光在1ps时间飞行0.3毫米)
◼ 单通道双精度模式测量最小时间分辨率23ps
◼ 非校准单精度测量范围 14ns(0ns)至 16μs
◼ 非校准双精度测量范围 16ns(0ns)至 16μs
◼ 校准单精度测量范围 14ns(0ns)至 4μs
◼ 校准双精度测量范围 16ns(0ns)至 2μs
◼ 10ns 最小脉冲间隔,双通道最多可接收 20 个脉冲
◼ 4 线 SPI 通信接口
二、MS1003管脚及说明


三、驱动配置及说明
本例程使用MS1003时间测量芯片来进行激光飞行时间的测量,进而实现激光测距的功能,根据数据手册可知,根据最大测量距离的不同,有两种配置思路。
第一种测量思路是开启ALU单元校准功能,当MS1003开启ALU校准输出后,从START信号到STOP信号之间最大的测量时间会被限制在4us(单精度测量),1us时间内激光飞行距离约为300M,4us就是1200M,考虑到激光反射是来回的路程,所以最大测量距离就被限制在了600M。
另一种配置思路是不开启内部ALU单元校准,读出数据之后进行手动校准,这样可以将测量时间延长到16us,理想状态下,测量距离能达到2400米,本例程将展示第二种方式的驱动配置。
四、MS1003寄存器配置图
此图示配置MS1003为双精度测量,非校准模式,生成CAL校准值,每次测量接收10个STOP通道1的激光脉冲回波,开启中断,测量溢出时间为最大测量时间(16μs),溢出时间到后就会将状态寄存器溢出标志位置1,此时可以正常读取输出寄存器中的数据。

MS1003的官方文档中流程图有些问题,在发送校准指令之后不需要等待中断,可以直接读取MS1003产生的校准值,在配置的时候要注意。以下是MS1003的配置流程图:

五、驱动代码及注释
把MS1003配置为非校准模式双精度测量,开启测量结束后自动产生校准值,同时开启高速时钟和中断产生,但是关闭ALU校准值计算。在开始测量之前,向MS1003发送开始校准指令,等待1ms之后,读取MS1003中产生的CAL校准值,然后使用这个校准值来进行测量数据校准,这个校准值存储在特定的结果寄存器中,套用对应的测量时间计算公式,可以进行手动校准测量值,最大测量距离2400M,仅STOP通道1可用。这些内容在代码中都有体现。
非校准模式测量时间计算参数说明:
RES_X:Stop通道结果寄存器读取到的24位整数;
RES_Tref:在初始化后,向MS1003发送校准指令,读取到的24位校准值;
Tref:外挂时钟周期;(以ps为时间单位);
N:配置的时钟分频系数 DIV_CLKHS;

MS1003宏定义代码及注释:
#include "main.h"
#include "MS1003.h"
#include "spi.h"
#define bit32 uint32_t
#define bit16 uint16_t
#define bit8 uint8_t
//MS1003_NSS片选操作宏定义
#define MS1003_NSS_SET GP21_NSS_GPIO_Port->BSRR = (uint32_t)GP21_NSS_Pin
#define MS1003_NSS_CLR GP21_NSS_GPIO_Port->BRR = (uint32_t)GP21_NSS_Pin
//MS1003_RST复位操作宏定义
#define MS1003_RST_SET HAL_GPIO_WritePin(RSTN_TDC_GPIO_Port, RSTN_TDC_Pin, GPIO_PIN_SET)
#define MS1003_RST_CLR HAL_GPIO_WritePin(RSTN_TDC_GPIO_Port, RSTN_TDC_Pin, GPIO_PIN_RESET)
//MS1003_EN_STOP1通道操作宏定义
#define MS1003_EN_STOP1_SET HAL_GPIO_WritePin(EN_STOP1_GPIO_Port, EN_STOP1_Pin, GPIO_PIN_SET)
#define MS1003_EN_STOP1_CLR HAL_GPIO_WritePin(EN_STOP1_GPIO_Port, EN_STOP1_Pin, GPIO_PIN_RESET)
//MS1003_EN_STOP2通道操作宏定义
#define MS1003_EN_STOP2_SET HAL_GPIO_WritePin(EN_STOP2_GPIO_Port, EN_STOP2_Pin, GPIO_PIN_SET)
#define MS1003_EN_STOP2_CLR HAL_GPIO_WritePin(EN_STOP2_GPIO_Port, EN_STOP2_Pin, GPIO_PIN_RESET)
MS1003初始化代码及注释:
/*****************************************************************************
[函数名称]Init_MS1003
[函数功能]MS1003初始化函数
[参 数]
[备 注]
*****************************************************************************/
void Init_MS1003(void)
{
uint8_t cmd = 0; //命令缓存
MS1003_RST_CLR; //MS1003芯片硬件复位
HAL_Delay(2);
MS1003_RST_SET;
HAL_Delay(2);
cmd = RESET_CMD_MS1003; //复位指令0x50
MS1003_NSS_CLR; //开启SPI通讯使能
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); //发送复位指令
MS1003_NSS_SET; //关闭SPI通讯使能
HAL_Delay(1);
uint32_t RegBuffer = 0x0B1C0060; //配置寄存器,详见MS1003寄存器配置
uint8_t u8RegConfig[5] = {0};
u8RegConfig[0] = WriteReg_CMD_MS1003; //写寄存器指令
u8RegConfig[1] = (uint8_t)(RegBuffer >> 24);
u8RegConfig[2] = (uint8_t)(RegBuffer >> 16);
u8RegConfig[3] = (uint8_t)(RegBuffer >> 8);
u8RegConfig[4] = (uint8_t)(RegBuffer);
MS1003_NSS_CLR; //开启SPI通讯使能
HAL_SPI_Transmit(&hspi1, u8RegConfig, 5, 400);//发送32位寄存器配置指令
MS1003_NSS_SET; //关闭SPI通讯使能
//检查主机和MS1003的通信是否正确建立
cmd = 0xBC; //读取配置寄存器的低8位
MS1003_NSS_CLR; //开启SPI通讯使能
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); //发送校验指令
HAL_SPI_Receive(&hspi1, &cmd, 1, 100); //接收返回值
MS1003_NSS_SET; //关闭SPI通讯使能
if(cmd == 0x60) //返回值对比,如果初始化成功
{
//校准前进行初始化操作
cmd = INIT_CMD_MS1003;
MS1003_NSS_CLR;
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); //发送初始化指令
MS1003_NSS_SET;
//手动获取校准值
cmd = CAL_CMD_MS1003; //获取开始校准命令
MS1003_NSS_CLR;
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); //发送开始校准指令
MS1003_NSS_SET;
HAL_Delay(1);
uint32_t u32CAL = 1; //赋一个默认值
Read24BitsData_MS1003(u32CAL, CAL_VALUE_ADDR); //获取CAL原始校准值
//250000指的是Tref*N的值,Tref指的是时钟周期,如果外挂时钟为4Mhz,那么Tref就是250ns
//N指的是控制寄存器配置的时钟分频系数,此例程配置为2
//门延时时间 = 250000ps * 2(时钟分频系数) / u32CAL
m_f32CAL = 500000.0 / u32CAL; //获取校准值,门延时时间
}
}
MS1003开始/停止测量函数代码及注释:
/*****************************************************************************
[函数名称]Start_Test_MS1003
[函数功能]开始测量函数
[参 数]
[备 注]
*****************************************************************************/
void Start_Test_MS1003(void)
{
m_timer4.bStartMCUON(); //发射PWM信号驱动MS1003的START端口,开始测量
MS1003_EN_STOP1_SET; //开启STOP1通道的接收使能
uint8_t cmd = INIT_CMD_MS1003; //MS1003初始化指令
MS1003_NSS_CLR;
HAL_SPI_Transmit(&hspi1, &cmd, 1, 200);
MS1003_NSS_SET;
}
/*****************************************************************************
[函数名称]Stop_Test_MS1003
[函数功能]停止测量函数
[参 数]
[备 注]
*****************************************************************************/
void MS1003::Stop_Test_MS1003(void)
{
m_timer4.bStopMCUON(); //停止发射激光的PWM输出
m_timer2.bStop_R_PWM(); //关闭R_PWM接收PWM输出
MS1003_EN_STOP1_CLR; //关闭STOP通道接收使能
}
MS1003读数据函数代码及注释:
ps:MS1003读取状态寄存器中的STOP回波数时,会比实际回波个数多一个,所以需要在读取回波个数的基础上-1。
/*****************************************************************************
[函数名称]Run_MS1003
[函数功能]轮询是否有数值更新,调用中断处理函数
[参 数]
[备 注]在这里检查是否有MS1003中断触发,如果有,就回调处理函数
*****************************************************************************/
void Run_MS1003(void)
{
if(m_DataIsReady == true) //数据就绪,开始处理数据
{
m_DataIsReady = false; //清空中断数据就绪标志位
Irq_Server_MS1003(); //调用处理函数
}
//如果测量结束,开始数据处理算法
}
/*****************************************************************************
[函数名称]Irq_Server_MS1003
[函数功能]数据处理函数
[参 数]
[备 注]在这个处理函数中读取传感器数据
*****************************************************************************/
void Irq_Server_MS1003(void)
{
uint8_t cmd = 0;
int8_t i8Stop1Nums = 0; //STOP通道1回波个数
float f32Dist = 0; //测量距离值
uint32_t u32TimeValue = 0; //MS1003原始传感器数据
uint32_t u32StatusREG = 0; //状态寄存器值
MS1003_EN_STOP1_CLR; //STOP1通道关闭使能
Read24BitsData_MS1003(u32StatusREG, STATE_REG); //读取状态寄存器的值
//寄存器读取到的回波个数比实际个数多1,所以要 -1
i8Stop1Nums = ((uint8_t)(u32StatusREG>>5) & 0x0F) - 1; //获取STOP1回波数
//如果STOP通道1的脉冲个数不为0,说明接收到有效数据
if( i8Stop1Nums > 0 )
{
uint8_t reg = 0;
for(uint8_t i=0; i<i8Stop1Nums; i++) //读取有效数据
{
reg = STOP1_REG+i;
Read24BitsData_MS1003(u32TimeValue, reg);//获取u32TimeValue时间数据
//将时间转换为距离,66667是光飞行1m对应的ps数
m_f32Dist = u32TimeValue * m_f32CAL / 66667;
//然后对校准后的数据存入设置的数据缓存中
if(m_f32Dist > 0 && m_f32Dist < 2400) //如果数据在有效范围内
{
//调用数据更新API进行更新
m_pListener->bOnDistUpdate(m_f32Dist, true);
}
}
}
else //如果没有接收到回波,说明当前配置有问题,需要切换模式
{
m_pListener->bOnDistUpdate(0, false); //返回异常信息
}
cmd = INIT_CMD_MS1003;
MS1003_NSS_CLR;
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); //初始化MS1003
MS1003_NSS_SET;
MS1003_EN_STOP1_SET; //开启MS1003的STOP1通道
}
/*****************************************************************************
[函数名称]Read24BitsData_MS1003
[函数功能]读寄存器24位
[参 数]
[备 注]
*****************************************************************************/
void Read24BitsData_MS1003(uint32_t &value, uint8_t reg)
{
uint8_t u8RecBuf[3] = {0};
MS1003_NSS_CLR;
HAL_SPI_Transmit(&hspi1, ®, 1, 200); //发送读24bits数据指令
HAL_SPI_Receive(&hspi1, u8RecBuf, 3, 400); //接收24bits三字节数据
MS1003_NSS_SET;
value = (uint32_t)(u8RecBuf[0]<<16) | (uint32_t)(u8RecBuf[1]<<8) | (uint32_t)u8RecBuf[2];
}
/*****************************************************************************
[函数名称]HAL_GPIO_EXTI_Falling_Callback
[函数功能]中断服务程序
[参 数]无
[备 注]HAL_GPIO_EXTI_Falling_Callback中断回调函数包含在C库中
*****************************************************************************/
extern "C"
{
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case GPIO_PIN_2:
{
m_DataIsReady = TRUE; //更新数据就绪标志位
} break;
default:
break;
}
}
}
六、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)