本帖最后由 sagitattoo 于 2018-12-30 01:04 编辑
再厉害的硬件如果没有软件的加持是发挥不出百分百的能量的。
前面了解了一些关于Distance2Go硬件的信息,现在来学习一下让系统真正活起来的固件。 首先,进入main函数后,系统会先在dma_init()函数中给DMA分配src和dst地址: - pDMA_src_I = (uint32_t*)&ADC_MEASUREMENT_ADV_G1_IF_I_RES;
- pDMA_src_Q = (uint32_t*)&ADC_MEASUREMENT_ADV_G2_IF_Q_RES;
- pDMA_dst_I = (uint32_t *)adc_i;
- pDMA_dst_Q = (uint32_t *)adc_q;
复制代码这是由于涉及到从ADC大量数据的搬运,为了保持系统效率,CPU会把这种“苦力活”交给“好兄弟”DMA来处理。 接着调用DAVE_Init()开始对相关硬件进行初始化。 - //主时钟
- init_status = (DAVE_STATUS_t)CLOCK_XMC4_Init(&CLOCK_XMC4_0);
- //滴答时钟
- init_status = (DAVE_STATUS_t)SYSTIMER_Init(&SYSTIMER_0);
- //获取IQ两路数据的ADC,以及对应DMA的初始化
- init_status = (DAVE_STATUS_t)ADC_MEASUREMENT_ADV_Init(&ADC_MEASUREMENT_ADV_G1);
- init_status = (DAVE_STATUS_t)ADC_MEASUREMENT_ADV_Init(&ADC_MEASUREMENT_ADV_G2);
- init_status = (DAVE_STATUS_t)ADC_MEASUREMENT_ADV_Init(&ADC_MEASUREMENT_SCAN);
- init_status = (DAVE_STATUS_t)DMA_CH_Init(&DMA_CH_I);
- init_status = (DAVE_STATUS_t)DMA_CH_Init(&DMA_CH_Q);
- //雷达芯片使能控制POWER_ENABLE管脚初始化
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_BGT_POWER_ENABLE);
- //PLL使能以及模式选择等管脚初始化
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_PLL_CE);
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_PLL_MOD);
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_PLL_TRIG1);
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_PLL_TRIG2);
- //配置雷达芯片和PLL芯片的SPI管脚初始化,两个芯片共用一组SPI的clk和data
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_SPI_M_CLK);
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_SPI_M_DATA);
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_SPI_M_CS_PLL);
- init_status = (DAVE_STATUS_t)DIGITAL_IO_Init(&DIGITAL_IO_SPI_M_CS_BGT24);
- //存储校准参数的EEPROM初始化
- init_status = (DAVE_STATUS_t)E_EEPROM_XMC4_Init(&E_EEPROM_XMC4_0);
- //USB接口初始化
- init_status = (DAVE_STATUS_t)USBD_VCOM_Init(&USBD_VCOM_0);
- //以及一些定时器
- //ADC循环采样定时器
- init_status = (DAVE_STATUS_t)TIMER_Init(&TIMER_ADC_TRIG);
- //用于延迟的定时器
- init_status = (DAVE_STATUS_t)TIMER_Init(&TIMER_DELAY);
- //一帧数据触发定时器及中断
- init_status = (DAVE_STATUS_t)TIMER_Init(&TIMER_FRAME_TRIG);
- init_status = (DAVE_STATUS_t)INTERRUPT_Init(&INTERRUPT_FRAME);
复制代码以上就是系统会用到的全部硬件资源。
当全部硬件初始化成功后,status会返回DAVE_STATUS_SUCCESS。系统便进入实质性的雷达启动阶段。
首先函数radar_open_device()通过结构体Radar_Driver_Object_t完成驱动挂载和参数配置,并通过mcu_init()完成雷达系统的启动,等待开启发射和接收。 - typedef struct Radar_Driver_Object
- {
- Frame_Format_t current_frame_format_s;
- Adc_Configuration_t current_adc_config_s;
- Doppler_Configuration_t current_doppler_config_s;
- Fmcw_Configuration_t current_fmcw_config_s;
- uint16_t sample_rate_divider;
-
- uint8_t num_rx_antennas;
-
- uint8_t bgt_tx_power_level;
- float32_t bgt_tx_output_power;
- uint32_t current_frame_interval_usec;
- uint32_t current_adc_buffer_size;
- enum
- {
- STATE_READY,
- STATE_AUTO_TRIGGER,
- STATE_TEST_MODE
- } Sensor_State_t;
- } Radar_Driver_Object_t;
复制代码
这个结构体有些复杂,主要说一下几个主要的变量: - current_frame_format_s: 指定每帧数据长度和天线数
- current_adc_config_s: 指定adc分辨率以及采集的频率,采集的频率和信号调制类型有关
- current_doppler_config_s: 当采用多普勒技术,需要配置这参数,包括发射频率和发射功率
- current_fmcw_config_s: 当采用FMCW,需要指定发射的起始频率和最终频率,频率的变化趋势是单调增加还是单调递减, 亦或是三角波的形式;同样还有发射功率
当配置完上面这个结构体变量后调用mcu_init():- 通过SPI配置雷达芯片,并使能雷达芯片;
- 对PLL进行配置上电;
- 配置USB下位机;
- 读取FLASH中的校准参数;
- 配置定时器。
准备完毕后,调用radar_start(),雷达芯片便按照预先设置,以固定时间间隔开启收发信号。
最后通过USB接口usb_init(),按照固定协议protocol_init(endpoint_list, sizeof(endpoint_list)/sizeof(Endpoint_t), SYSTIMER_GetTime, HOST_TIME_OUT)与上位机进行交互protocol_run(),将receive_data()获取的数据传给上位机。
官方提供的这个固件并不包含多普勒或者FMCW算法,只是单纯的将ADC的原始数据上传给上位机用于算法人员进行算法开发。整个代码思路清晰,通过结构体的形式将MAC层和PHY层的功能划分清楚,值得细细品味。
最后奉上这个固件包。 |