#include "board.h" #include "tdc_tof.h" #define ANZ_FIRE 12u //fire发送脉冲数 #define DIV_FIRE 3u //内部时钟产生脉冲的分频 #define DIV_CLKHS 0u //高速时钟分频 #define START_CLKHS 2u //高速启动后测量前晶振启动间隔时间,2(120us),0 = 晶振关闭;1 = 晶振持续开启;2 = 启振延迟时间 120 μs #define NEG_START 0u //start通道边缘 #define NEG_STOP 0u //stop通道边缘 #define HITIN 9u //stop预期脉冲数 #define SEL_TIMO_MB 3u //测量范围溢出选择时间限制,3 = 512μs,4 = 1024μs #define SEL_TSTO2 3u //TSTO2 管脚状态设置,3 = 32kHz 输出 #define SEL_TSTO1 0u //TSTO1 管脚状态设置,0 = 高速时钟输入 #define DFLT_WREG0 ((ANZ_FIRE<<25) | \ ( DIV_FIRE<<19) | \ ( DIV_CLKHS<<17) | \ ( START_CLKHS<<14) | \ ( NEG_START<<13) | \ ( NEG_STOP<<12) | \ ( HITIN<< 8) | \ ( SEL_TIMO_MB<< 4) | \ ( SEL_TSTO2<< 2) | \ ( SEL_TSTO1<< 0)) #define EN_INT_TO 1 //TIMOUT中断触发位,1=开启中断 #define EN_INT_HIT 0 //END HITS中断触发位,0=关闭中断 #define EN_INT_ALU 1 //alu中断触发位,1=开启中断 #define RFEDGE 0 //stop通道边沿敏感性,0 = 上升或下降沿 #define UP_DELVAL1 200u //当EN_FIST_WAVE=1时,为第一波顺流屏蔽窗口 BIT12~27,200*0.25=50us #define OFFSET 0 //当en_hc=0时, OFFSET电压31~-32mV;0=0mV,1=1mV,...31=31mV,32=-32mV...63=-1mV,60=-4mV #define DFLT_WREG1 ((EN_INT_TO<<31) | \ ( EN_INT_HIT<<30) | \ ( EN_INT_ALU<<29) | \ ( RFEDGE<<28) | \ ( UP_DELVAL1<<12) | \ ( OFFSET<< 0)) #define EN_FIRST_WAVE 1u //BIT31, 为1时后面的定义有效 #define EDGE_FW 0u //第一波边缘敏感性,0 = 上升沿 #define DELREL1 6u //第1个stop接收第几个回波周期 #define DELREL2 8u //第2个stop接收第几个回波周期 #define DELREL3 10u //第3个stop接收第几个回波周期 #define DELREL4 12u //第4个stop接收第几个回波周期 #define DELREL5 14u //第5个stop接收第几个回波周期 #define DFLT_WREG2 ((EN_FIRST_WAVE<<31) | \ (EDGE_FW<<30) | \ (DELREL1<<24) | \ (DELREL2<<18) | \ (DELREL3<<12) | \ (DELREL4<< 6) | \ (DELREL5<< 0)) #define DELREL6 16u //第6个stop接收第几个回波周期 #define DELREL7 18u //第7个stop接收第几个回波周期 #define DELREL8 20u //第8个stop接收第几个回波周期 #define DIS_PW 1u //关闭脉冲宽度测量功能,1=关闭 #define WAVE_OFFS 0u //第一波比较器偏置电压:EN_HC = 0 -64mV~63mV;0=0mV,1=1mV,...63=63mV,64=-64mV,...127=-1mV;16=16mV #define DFLT_WREG3 ((DELREL6<<26) | \ (DELREL7<<20) | \ (DELREL8<<14) | \ (DIS_PW<<13) | \ (WAVE_OFFS<<6)) #define CONF_FIRE 2 //脉冲触发器的输出设置,不可以设置为3, bit 30 = 1: 开启输出 FIRE_UP #define PHASE_FIREUP 0 //FIREUP反向设置,0:同相 #define PHASE_FIREDOWN 0 //FIREDOWN 反向设置,0:同相 #define SEL_START_FIRE 1 //FIRE 脉冲用作触发 TDC START,1 = FIRE 内部触发 START #define EN_ANALOG 1 //模拟测量部分开启控制,1 = 模拟部分开启, STOP1 和 STOP2 模拟信号输入 #define HZ60 0 //顺流测量和逆流测量的时间单位,0 = 50 Hz,20ms #define TCYCLE 1 //设置温度测量的循环时间,1 = 512μs #define ANZ_FAKE 0 //在温度测量前的热身测量次数,1 = 7 次热身测量 #define SEL_ECLK_TMP 1 //选择温度测量内部 cycle参考时钟,1 = CLKHS/128 作为 cycle 时钟 #define TW2 5 //EN_ANALOG = 1,给STOP 端口的电容充电时间,0=60μs,1=120μs,2=180μs,3=240μs,4=300μs #define EN_PEAK 0 //峰值检波使能,0:不使能 #define EN_DISCHARGE 0 //检波放电使能,0:不使能 #define CYCLE_TOF 0 //顺流逆流自动检测模式下,顺流逆流测量间隔时间,0=0.25×HZ60(20ms@50Hz),5ms #define EN_ERR_VAL 1 //溢出时 ALU 写入全 F 到第一个 STOP 结果寄存器与累加和结果寄存器,1=开启 #define EN_DC 1 //stop端口充电模式;0=交流模式,1=直流模式 #define FIRE0_DEF 1 //非工作情况下 FIRE 通道的默认状态; 0=高阻(数字模式),1=低(模拟模式) #define DOUBLE_RES 0 //双精度模式使能,0:不使能 #define QUAD_RES 1 //四精度模式使能,1:使能 #define DFLT_WREG4 ((CONF_FIRE<<29) | \ ( PHASE_FIREUP<<28) | \ ( PHASE_FIREDOWN<<27) | \ ( SEL_START_FIRE<<26) | \ ( EN_ANALOG<<25) | \ ( HZ60<<24) | \ ( TCYCLE<<23) | \ ( ANZ_FAKE<<22) | \ ( SEL_ECLK_TMP<<21) | \ ( TW2<<17) | \ ( EN_PEAK<<16) | \ ( EN_DISCHARGE<<15) | \ ( CYCLE_TOF<<11) | \ ( EN_ERR_VAL<<10) | \ ( EN_DC<<9) | \ ( FIRE0_DEF<<8) | \ ( DOUBLE_RES<<7) | \ ( QUAD_RES<<6)) #define CYCLE_AUTOTOF 0 //自动测量循环时间, 0: 自动循环测量禁止 #define ANZ_AUTOTOF 0 //自动循环测量的次数,0:不开启 #define AUTOTOF_MODE 0 //自动循环测量模式,0:顺-逆-顺-逆 #define PHASE_FIRENUM 0 //定义在第几个脉冲进行相位插入,0 = 关闭 #define ANZ_PHASE 0 //插入的 FIRE 周期个数,0:不进行相位插入 #define DFLT_WREG5 ((CYCLE_AUTOTOF<<20) | \ ( ANZ_AUTOTOF<<16) | \ ( AUTOTOF_MODE<<15) | \ ( PHASE_FIRENUM<<6) | \ ( ANZ_PHASE<<0)) #define DOWN_DELVAL1 200u //当EN_FIST_WAVE=1时,为第一波逆流屏蔽窗口 BIT12~27,200*0.25=50us #define SEL_SRC_CLK 0 //选择高速时钟输入源,0:高速晶振产生时钟 #define EN_HC 0 //比较器调节步长,0:1mV,1:2mV #define CURR32K 0 //32kHz 晶振功耗设置,0:低功耗 #define DIS_Vref 1 //基准电压输出控制,0:开启基准输出, 1:关闭基准输出 #define ADJ_LDO_ROUGH 0 //内部 LDO 输出粗调,0:1.8V 档位, 1:1.5V 档位 #define ADJ_LDO_FINE 0 //内部 LDO 输出细调, 0-7:细调 LDO 输出电压 #define DFLT_WREG6 ((DOWN_DELVAL1<<12) | \ ( SEL_SRC_CLK<<7) | \ ( EN_HC<<6) | \ ( CURR32K<<5) | \ ( DIS_Vref<<4) | \ ( ADJ_LDO_ROUGH<<3) | \ ( ADJ_LDO_FINE<<0)) uint16_t tof_state = TOF_ST_INIT; uint32_t tof_flag; uint16_t TdcStatus; uint16_t TdcUPwFw; uint16_t TdcUPwHw; uint32_t TdcUToF[9]; uint16_t TdcDPwFw; uint16_t TdcDPwHw; uint32_t TdcDToF[9]; uint32_t TdcCal; //float TdcScale = 250.0f/65536; float TdcScale = 0.00381147861f; uint32_t TdcPT[4]; float TdcResist = 5000; // OhmX10 //modified by yuewei 20260520 //float WaterPrmt[2] = {25.0f, 1496.6f}; float WaterPrmt[2] = {25.0f, 1497.1484f}; /** * @brief MS1031初始化函数 * @param 无 * @retval 无 */ void tdc_tof_init(void) { //MUX ADDA : PA08; ADDB : PC09 mux_init(); // MS1030 RSTN : PD02 GpioInit(PD02_AF0, GPIO_DIG_OUT_WEAK_PUSH_NONEUP_NONEDOWN); GpioClrPins(GpioPortD, GpioBitMsk2); // reset active low us_delay(10); // 10us > tPH(30ns) GpioSetPins(GpioPortD, GpioBitMsk2); // reset release us_delay(10); // 10us > tRFS(30ns) tdc_spi_init(); // peripheral init PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); // TDC POR tdc_spi_wr_code(0x50); us_delay(1000); // 1000us > specification(500us) tdc_spi_wr_d32(0x80, DFLT_WREG0); tof_flag = TOF_FLAG_UNALGND_CHOP; if (tdc_spi_rd_d32(0xa0) != DFLT_WREG0) { tof_flag |= TOF_FLAG_TDC_FAULT; } else { tdc_spi_wr_d32(0x80,DFLT_WREG0); tdc_spi_wr_d32(0x81,DFLT_WREG1); tdc_spi_wr_d32(0x82,DFLT_WREG2); tdc_spi_wr_d32(0x83,DFLT_WREG3); tdc_spi_wr_d32(0x84,DFLT_WREG4); tdc_spi_wr_d32(0x85,DFLT_WREG5); tdc_spi_wr_d32(0x86,DFLT_WREG6); //读取时钟校准时,如果不加该项,状态寄存器d0中的TDC_Flood位会一直置位 tdc_spi_wr_d32(0x87,0x20000000);//!!!!!!!!do not delete!!!!!!!!! tdc_spi_wr_code(0x70); //启动一次时钟校准 tdc_spi_wr_code(0x06); //延时等待,时间必须大于时钟校准中断时间,便于后一步正确读取校准时间 us_delay(2000);//!!!!!!!!do not delete!!!!!!!!! //读取一次时钟校准 tdc_read_cal(0); } DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); // MS1030 INTN : PD03 falling edge trigger GpioInit(PD03_AF0, GPIO_DIG_IN_PULLUP_NONEDOWN); GpioEventInit(PD03_AF0, GPIO_EVENT_FALL); // enable interrupt at NVIC side IRQMutEnable(PORTD_F_IRQn, NVIC_PRIO_1); } /** * @brief MS1031开启第一波自动双向测量 * @param uint32_t cfg可选下面参数 * 1、TDC_CFG_DO_CKENA:开启SPI时钟+DMA中断 * 2、TDC_CFG_DO_WREG:调整局部寄存器 * 3、TDC_CFG_DO_CKDIS:关闭SPI时钟+DMA中断 * @retval 无 */ void tdc_start_tof(uint32_t cfg) { uint32_t u32tmp; if (cfg & TDC_CFG_DO_CKENA) { PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); } if (cfg & TDC_CFG_DO_WREG) { // write_reg3 u32tmp = (DFLT_WREG3 & ~((1u << 13) | (0x7F << 6))) | (TdcFwOfst << 6); //6到12位以及13位清0然后写入新数据到6到12位 // measure FW pulse width, 0:on; 1:off // FW wave_offs, 0:0mv; 1~63:2~126mV; 64~127:-128~-2mV; if (tof_state&TOF_ST_VOID) { u32tmp |= (1u << 13); // disable FW pulse width to save power } tdc_spi_wr_d32(0x83, u32tmp); } // Initial TDC status regs tdc_spi_wr_code(0x70); // 开启第一波自动双向测量 tdc_spi_wr_code(0x03); if (cfg & TDC_CFG_DO_CKDIS) { DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); } } /** * @brief MS1031读取第一波自动双向测量结果 * @param uint32_t cfg可选下面参数 * 1、TDC_CFG_DO_CKENA:开启SPI时钟+DMA中断 * 2、TDC_CFG_DO_WREG:调整局部寄存器 * 3、TDC_CFG_DO_CKDIS:关闭SPI时钟+DMA中断 * @retval 无 */ void tdc_read_tof(uint32_t cfg) { if (cfg & TDC_CFG_DO_CKENA) { PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); } TdcStatus = tdc_spi_rd_d16(0xd0); //modified by yuewei 260813 0xd2 -> 0xd0, to match ms1031 if ((TdcStatus&0x0300) == 0x0000u) //modified by yuewei 260813 0x0600 -> 0x0300, to match ms1031 { tof_flag ^= TOF_FLAG_UNALGND_CHOP; //tdc_spi_wr_code(0x70); } if ((TdcStatus&0x03F0) != 0x0090u) //modified by yuewei 260813 0x06F0 -> 0x03F0, to match ms1031 { tof_flag |= TOF_FLAG_BLANK_PIPE; tdc_spi_wr_code(0x70); } else { //modified by yuewei 260813 start TdcUPwFw = tdc_spi_rd_d16(0xd3); // First wave pulse width TdcUPwHw = tdc_spi_rd_d16(0xd4); // 1st Hit wave pulse width TdcDPwFw = TdcUPwFw; TdcDPwHw = TdcUPwHw; // TOF_UP_HITs TdcUToF[0] = tdc_spi_rd_d32(0xb8)*(1.0f/8); // average of all // TOF_DOWN_HITs TdcDToF[0] = tdc_spi_rd_d32(0xc8)*(1.0f/8); // average of all tdc_spi_wr_code(0x70); //modified by yuewei 260813 end } if (cfg & TDC_CFG_DO_CKDIS) { DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); } } /** * @brief MS1031开启高速晶振校准 * @param uint32_t cfg可选下面参数 * 1、TDC_CFG_DO_CKENA:开启SPI时钟+DMA中断 * 2、TDC_CFG_DO_WREG:调整局部寄存器 * 3、TDC_CFG_DO_CKDIS:关闭SPI时钟+DMA中断 * @retval 无 */ void tdc_start_cal(uint32_t cfg) { if (cfg & TDC_CFG_DO_CKENA) { PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); } // 8*T_32k = 244.140625us if (cfg & TDC_CFG_DO_WREG) { // write_reg3 tdc_spi_wr_d32(0x83, DFLT_WREG3 | ( 1u<<13) // measure FW pulse width, 0:on; 1:off ); } tdc_spi_wr_code(0x70); tdc_spi_wr_code(0x06); if (cfg & TDC_CFG_DO_CKDIS) { DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); } } /** * @brief MS1031读取高速晶振校准结果 * @param uint32_t cfg可选下面参数 * 1、TDC_CFG_DO_CKENA:开启SPI时钟+DMA中断 * 2、TDC_CFG_DO_WREG:调整局部寄存器 * 3、TDC_CFG_DO_CKDIS:关闭SPI时钟+DMA中断 * @retval 无 */ void tdc_read_cal(uint32_t cfg) { if (cfg & TDC_CFG_DO_CKENA) { PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); } TdcStatus = tdc_spi_rd_d16(0xd0); //modified by yuewei 260813 0xd2 -> 0xd0, to match ms1031 if ((TdcStatus&0x0300) == 0x0000u) //modified by yuewei 260813 0x0600 -> 0x0300, to match ms1031 { tof_flag ^= TOF_FLAG_UNALGND_CHOP; TdcCal = tdc_spi_rd_d32(0xd5); //TdcScale = 244140.625f/TdcCal; TdcScale += (244140.625f/TdcCal - TdcScale)*(1.0f/2); tdc_spi_wr_code(0x70); } else { tdc_spi_wr_code(0x70); } if (cfg & TDC_CFG_DO_CKDIS) { DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); } } /** * @brief MS1031开启温度采集 * @param uint32_t cfg可选下面参数 * 1、TDC_CFG_DO_CKENA:开启SPI时钟+DMA中断 * 2、TDC_CFG_DO_WREG:调整局部寄存器 * 3、TDC_CFG_DO_CKDIS:关闭SPI时钟+DMA中断 * @retval 无 */ void tdc_start_temp(uint32_t cfg) { if (cfg & TDC_CFG_DO_CKENA) { PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); } if (cfg & TDC_CFG_DO_WREG) { // write_reg3 tdc_spi_wr_d32(0x83, DFLT_WREG3 | ( 1u<<13) // measure FW pulse width, 0:on; 1:off ); } tdc_spi_wr_code(0x70); tdc_spi_wr_code(0x04); if (cfg & TDC_CFG_DO_CKDIS) { DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); } } /** * @brief MS1031读取温度采集结果 * @param uint32_t cfg可选下面参数 * 1、TDC_CFG_DO_CKENA:开启SPI时钟+DMA中断 * 2、TDC_CFG_DO_WREG:调整局部寄存器 * 3、TDC_CFG_DO_CKDIS:关闭SPI时钟+DMA中断 * @retval 无 */ void tdc_read_temp(uint32_t cfg) { if (cfg & TDC_CFG_DO_CKENA) { PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); } //delete by yuewei 260813, ms1031 status reg(d0) bit 11 and bit 10 can only indicate the PT1 is short or open //TdcStatus = tdc_spi_rd_d16(0xd0); //modified by yuewei 260813 0xd2 -> 0xd0, to match ms1031 // REF 25K TdcPT[0] = tdc_spi_rd_d32(0xd1); //modified by yuewei 260813 0xc2 -> 0xd1, to match ms1031 // NTC TdcPT[1] = tdc_spi_rd_d32(0xd2); //modified by yuewei 260813 0xc3 -> 0xd2, to match ms1031 tdc_spi_wr_code(0x70); //add by yuewei 260813 to deal Rref or Rntc is short or open if((TdcPT[0] == 0) || (TdcPT[0] == 0xFFFFFFFF) || (TdcPT[1] == 0) || (TdcPT[1] == 0xFFFFFFFF)) { TdcResist = 0;//when Rref or Rntc is short or open, set TdcResist = 0, to set the Temprature = -3276.8f in Ohm2Dgr2USSpd(TdcResist, WaterPrmt) } else { TdcResist = 2500.0f*TdcPT[1]/TdcPT[0]; // ohmX10 } Ohm2Dgr2USSpd(TdcResist, WaterPrmt); // [0]:Temperature; [1]:ultrasonic speed @Temp if (cfg & TDC_CFG_DO_CKDIS) { DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); } } /** * @brief 打开、关闭MS1031高速时钟(空管时,节约功耗) * @param state:0关闭,1开启 * @retval 无 */ void tdc_turn_on_off_high_clk(uint8_t state) { PeriClk_MutEnable(PeriClk_Spi1); DMA_ReqClkOn(); if(state == 0) { tdc_spi_wr_d32(0x80, DFLT_WREG0 & ~(0x03 << 14));//set bit 14、15、16=0, disable the high clk } else { GpioInit(PD02_AF0, GPIO_DIG_OUT_WEAK_PUSH_NONEUP_NONEDOWN); GpioClrPins(GpioPortD, GpioBitMsk2); // reset active low us_delay(10); // 10us > tPH(30ns) GpioSetPins(GpioPortD, GpioBitMsk2); // reset release us_delay(10); // 10us > tRFS(30ns) tdc_spi_wr_d32(0x80,DFLT_WREG0); tdc_spi_wr_d32(0x81,DFLT_WREG1); tdc_spi_wr_d32(0x82,DFLT_WREG2); tdc_spi_wr_d32(0x83,DFLT_WREG3); tdc_spi_wr_d32(0x84,DFLT_WREG4); tdc_spi_wr_d32(0x85,DFLT_WREG5); tdc_spi_wr_d32(0x86,DFLT_WREG6); //读取时钟校准时,如果不加该项,状态寄存器d0中的TDC_Flood位会一直置位 tdc_spi_wr_d32(0x87,0x20000000);//!!!!!!!!do not delete!!!!!!!!! tdc_spi_wr_code(0x70); } DMA_ReqClkOff(); PeriClk_MutDisable(PeriClk_Spi1); }