440 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "gd32e23x.h"
 | |
| #include "systick.h"
 | |
| #include <stdio.h>
 | |
| #include "main.h"
 | |
| // #include "gd32e230c_eval.h"
 | |
| #include "timer.h"
 | |
| #include "board_init.h"
 | |
| #include "chirp_board_config.h"
 | |
| #include "chirp_bsp.h"
 | |
| #include "chirp_smartsonic.h"
 | |
| #include "app_version.h"
 | |
| #include "app_config.h"
 | |
| #include "ultrasound_display_config_info.h"
 | |
| 
 | |
| /* Bit flags used in main loop to check for completion of sensor I/O.  */
 | |
| #define DATA_READY_FLAG		(1 << 0)
 | |
| #define IQ_READY_FLAG		(1 << 1)
 | |
| 
 | |
| #define TestDelayTime 200
 | |
| 
 | |
| /* chirp_data_t - Structure to hold measurement data for one sensor
 | |
|  *   This structure is used to hold the data from one measurement cycle from 
 | |
|  *   a sensor.  The data values include the measured range, the ultrasonic 
 | |
|  *   signal amplitude, the number of valid samples (I/Q data pairs) in the 
 | |
|  *   measurement, and (optionally) the full amplitude data and/or raw I/Q data 
 | |
|  *   from the measurement.
 | |
|  *
 | |
|  *  The format of this data structure is specific to this application, so 
 | |
|  *  you may change it as desired.
 | |
|  *
 | |
|  *  A "chirp_data[]" array of these structures, one for each possible sensor, 
 | |
|  *  is declared in the main.c file.  The sensor's device number is 
 | |
|  *  used to index the array.
 | |
|  */
 | |
| typedef struct {
 | |
| 	uint32_t		range;						// from ch_get_range()
 | |
| 	uint16_t		amplitude;					// from ch_get_amplitude()
 | |
| 	uint16_t		num_samples;				// from ch_get_num_samples()
 | |
| #ifdef READ_AMPLITUDE_DATA
 | |
| 	uint16_t		amp_data[DATA_MAX_NUM_SAMPLES];	 // from ch_get_amplitude_data()
 | |
| #endif
 | |
| #ifdef READ_IQ_DATA
 | |
| 	ch_iq_sample_t	iq_data[DATA_MAX_NUM_SAMPLES];	 // from ch_get_iq_data()
 | |
| #endif
 | |
| } chirp_data_t;
 | |
| 
 | |
| 
 | |
| /* Array of structs to hold measurement data, one for each possible device */
 | |
| chirp_data_t	chirp_data[CHIRP_MAX_NUM_SENSORS];		
 | |
| 
 | |
| /* Array of ch_dev_t device descriptors, one for each possible device */
 | |
| ch_dev_t	chirp_devices[CHIRP_MAX_NUM_SENSORS];		
 | |
| 
 | |
| /* Configuration structure for group of sensors */
 | |
| ch_group_t 	chirp_group;
 | |
| 
 | |
| 
 | |
| 
 | |
| /* Task flag word
 | |
|  *   This variable contains the DATA_READY_FLAG and IQ_READY_FLAG bit flags 
 | |
|  *   that are set in I/O processing routines.  The flags are checked in the 
 | |
|  *   main() loop and, if set, will cause an appropriate handler function to 
 | |
|  *   be called to process sensor data.  
 | |
|  */
 | |
| volatile uint32_t taskflags = 0;
 | |
| 
 | |
| /* Device tracking variables
 | |
|  *   These are bit-field variables which contain a separate bit assigned to
 | |
|  *   each (possible) sensor, indexed by the device number.  The active_devices
 | |
|  *   variable contains the bit pattern describing which ports have active
 | |
|  *   sensors connected.  The data_ready_devices variable is set bit-by-bit
 | |
|  *   as sensors interrupt, indicating they have completed a measurement
 | |
|  *   cycle.  The two variables are compared to determine when all active
 | |
|  *   devices have interrupted.
 | |
|  */
 | |
| static uint32_t active_devices;
 | |
| static uint32_t data_ready_devices;
 | |
| 
 | |
| /* Number of connected sensors */
 | |
| static uint8_t	num_connected_sensors = 0;
 | |
| 
 | |
| /* Number of sensors that use h/w triggering to start measurement */
 | |
| static uint8_t	num_triggered_devices = 0;
 | |
| 
 | |
| 
 | |
| /* Forward declarations */
 | |
| static void    sensor_int_callback(ch_group_t *grp_ptr, uint8_t dev_num);
 | |
| static void    io_complete_callback(ch_group_t *grp_ptr);
 | |
| static uint8_t handle_data_ready(ch_group_t *grp_ptr);
 | |
| 
 | |
| /*!
 | |
|     \brief      main function
 | |
|     \param[in]  none
 | |
|     \param[out] none
 | |
|     \retval     none
 | |
| */
 | |
| int main(void)
 | |
| {
 | |
|     ch_group_t	*grp_ptr = &chirp_group;
 | |
| 	uint8_t chirp_error = 0;
 | |
| 	uint8_t num_ports;
 | |
| 	uint8_t dev_num;
 | |
| 
 | |
| 
 | |
|     /* configure systick */
 | |
|     systick_config();
 | |
|     
 | |
|     chbsp_board_init(grp_ptr);
 | |
| 
 | |
|     printf("\n\nXLSW UltraSonic Example Application\n");
 | |
| 	printf("    Compile time:  %s %s\n", __DATE__, __TIME__);
 | |
| 	printf("    Version: %u.%u.%u", APP_VERSION_MAJOR, APP_VERSION_MINOR, APP_VERSION_REV);
 | |
| 	printf("    SonicLib version: %u.%u.%u\n", SONICLIB_VER_MAJOR, SONICLIB_VER_MINOR, SONICLIB_VER_REV);
 | |
| 	printf("\n");
 | |
| 
 | |
| 	#ifdef DEBUG_VERBOES
 | |
| 	/* print out the clock frequency of system, AHB, APB1 and APB2 */
 | |
| 	printf("[DebugVerboes] System CLK Info!!!");
 | |
|     printf("\r\nCK_SYS is %d", rcu_clock_freq_get(CK_SYS));
 | |
|     printf("\r\nCK_AHB is %d", rcu_clock_freq_get(CK_AHB));
 | |
|     printf("\r\nCK_APB1 is %d", rcu_clock_freq_get(CK_APB1));
 | |
|     printf("\r\nCK_APB2 is %d", rcu_clock_freq_get(CK_APB2));
 | |
| 	printf("[DebugVerboes] System CLK Info Done!!!");
 | |
|     printf("\r\n");
 | |
| 	printf("\r\n");
 | |
| 	printf("\r\n");
 | |
| 	#endif
 | |
| 
 | |
|     /* Get the number of sensor devices on the board*/
 | |
|     num_ports = ch_get_num_ports(grp_ptr);
 | |
| 
 | |
|     /* Initialize sensor descriptors. */
 | |
|     printf("Initializing sensor(s)... ");
 | |
|     for (dev_num = 0; dev_num < num_ports; dev_num++) {
 | |
| 		ch_dev_t *dev_ptr = &(chirp_devices[dev_num]);
 | |
|         chirp_error |= ch_init(dev_ptr, grp_ptr, dev_num, CHIRP_SENSOR_FW_INIT_FUNC);
 | |
| 	}
 | |
| 
 | |
| 	if (chirp_error == 0) {
 | |
| 		printf("starting group... ");
 | |
| 		chirp_error = ch_group_start(grp_ptr);
 | |
| 	}
 | |
| 
 | |
| 	if (chirp_error == 0) {
 | |
| 		printf("OK\n");
 | |
| 	} else {
 | |
| 		printf("FAILED: %d\n", chirp_error);
 | |
| 	}
 | |
| 	printf("\n");
 | |
| 
 | |
| 	printf("Sensor\tType \t   Freq\t\t RTC Cal \tFirmware\n");
 | |
| 	for (dev_num = 0; dev_num < num_ports; dev_num++) {
 | |
| 		ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, dev_num);
 | |
| 
 | |
| 		if (ch_sensor_is_connected(dev_ptr)) {
 | |
| 			printf("%d\tCH%d\t %u Hz\t%u@%ums\t%s\n", dev_num,ch_get_part_number(dev_ptr), (unsigned int) ch_get_frequency(dev_ptr), ch_get_rtc_cal_result(dev_ptr), ch_get_rtc_cal_pulselength(dev_ptr), ch_get_fw_version_string(dev_ptr));
 | |
| 		}
 | |
| 	}
 | |
| 	printf("\n");
 | |
| 
 | |
|     /* Register callback function to be called when Chirp sensor interrupts */
 | |
| 	// ch_io_int_callback_set(grp_ptr, sensor_int_callback);
 | |
| 
 | |
| 	/* Register callback function called when non-blocking I/Q readout completes
 | |
|  	 *   Note, this callback will only be used if READ_IQ_DATA_NONBLOCK is 
 | |
| 	 *   defined to enable non-blocking I/Q readout in this application.
 | |
| 	 */
 | |
| 	// ch_io_complete_callback_set(grp_ptr, io_complete_callback);
 | |
| 
 | |
|     /* Configure each sensor with its operating parameters 
 | |
| 	 *   Initialize a ch_config_t structure with values defined in the
 | |
| 	 *   app_config.h header file, then write the configuration to the 
 | |
| 	 *   sensor using ch_set_config().
 | |
| 	 */
 | |
| 	printf ("Configuring sensor(s)...\n");
 | |
| 	for (dev_num = 0; dev_num < num_ports; dev_num++) {
 | |
| 		ch_config_t dev_config;
 | |
| 		ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, dev_num);
 | |
| 
 | |
| 		if (ch_sensor_is_connected(dev_ptr)) {
 | |
| 
 | |
| 			num_connected_sensors++;		// count one more connected
 | |
| 			active_devices |= (1 << dev_num);	// add to active device bit mask
 | |
| 			
 | |
| 			if (num_connected_sensors == 1) {	// if this is the first sensor
 | |
|                 dev_config.mode = CH_MODE_FREERUN;
 | |
|             }
 | |
| 
 | |
| 			/* Init config structure with values from app_config.h */
 | |
| 			dev_config.max_range       = CHIRP_SENSOR_MAX_RANGE_MM;
 | |
| 			dev_config.static_range    = CHIRP_SENSOR_STATIC_RANGE;
 | |
| 
 | |
| 			/* If sensor will be free-running, set internal sample interval */
 | |
| 			if (dev_config.mode == CH_MODE_FREERUN) {
 | |
| 				dev_config.sample_interval = MEASUREMENT_INTERVAL_MS;
 | |
| 			}
 | |
| 
 | |
| 			/* Apply sensor configuration */
 | |
| 			chirp_error = ch_set_config(dev_ptr, &dev_config);
 | |
| 
 | |
| 			/* Enable sensor interrupt if using free-running mode 
 | |
| 			 *   Note that interrupt is automatically enabled if using 
 | |
| 			 *   triggered modes.
 | |
| 			 */
 | |
| 			if ((!chirp_error) && (dev_config.mode == CH_MODE_FREERUN)) {
 | |
| 				chbsp_set_io_dir_in(dev_ptr);
 | |
| 				chbsp_io_interrupt_enable(dev_ptr);
 | |
| 			}
 | |
| 
 | |
| 			/* Read back and display config settings */
 | |
| 			if (!chirp_error) {
 | |
| 				ultrasound_display_config_info(dev_ptr);
 | |
| 			} else {
 | |
| 				printf("Device %d: Error during ch_set_config()\n", dev_num);
 | |
| 			}
 | |
| 
 | |
| 			/* Turn on an LED to indicate device connected */
 | |
| 			if (!chirp_error) {
 | |
| 				chbsp_led_on(dev_num);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	printf("\n");
 | |
| 
 | |
|     // /* Enable receive sensor pre-triggering, if specified */
 | |
| 	// ch_set_rx_pretrigger(grp_ptr, RX_PRETRIGGER_ENABLE);
 | |
| 
 | |
| 	// /* Initialize the periodic timer we'll use to trigger the measurements.
 | |
|  	//  *   This function initializes a timer that will interrupt every time it 
 | |
| 	//  *   expires, after the specified measurement interval.  The function also 
 | |
| 	//  *   registers a callback function that will be called from the timer 
 | |
| 	//  *   handler when the interrupt occurs.  The callback function will be 
 | |
| 	//  *   used to trigger a measurement cycle on the group of sensors.
 | |
| 	//  */
 | |
| 	if (num_triggered_devices > 0) {
 | |
| 		printf("Initializing sample timer for %dms interval... ", MEASUREMENT_INTERVAL_MS);
 | |
| 
 | |
| 		// chbsp_periodic_timer_init(MEASUREMENT_INTERVAL_MS, periodic_timer_callback);
 | |
| 		/* Enable interrupt and start timer to trigger sensor sampling */
 | |
| 		// chbsp_periodic_timer_irq_enable();
 | |
| 		// chbsp_periodic_timer_start();
 | |
| 		printf("OK\n");
 | |
| 	}
 | |
| 	printf("Starting measurements\n");
 | |
| 
 | |
| 	timer_config();
 | |
| 
 | |
|     while (1)
 | |
|     {
 | |
|         handle_data_ready(grp_ptr);
 | |
| 		// chbsp_led_toggle(dev_num);
 | |
|         delay_ms(MEASUREMENT_INTERVAL_MS);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * periodic_timer_callback() - periodic timer callback routine
 | |
|  *
 | |
|  * This function is called by the periodic timer interrupt when the timer 
 | |
|  * expires.  Because the periodic timer is used to initiate a new measurement 
 | |
|  * cycle on a group of sensors, this function calls ch_group_trigger() during 
 | |
|  * each execution.
 | |
|  *
 | |
|  * This function is registered by the call to chbsp_periodic_timer_init() 
 | |
|  * in main().
 | |
|  */
 | |
| void periodic_timer_callback(void) {
 | |
| 
 | |
| 	if (num_triggered_devices > 0) {
 | |
| 		ch_group_trigger(&chirp_group);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * sensor_int_callback() - sensor interrupt callback routine
 | |
|  *
 | |
|  * This function is called by the board support package's interrupt handler for 
 | |
|  * the sensor's INT line every time that the sensor interrupts.  The device 
 | |
|  * number parameter, dev_num, is used to identify the interrupting device
 | |
|  * within the sensor group.  (Generally the device number is same as the port 
 | |
|  * number used in the BSP to manage I/O pins, etc.)
 | |
|  *
 | |
|  * Each time this function is called, a bit is set in the data_ready_devices
 | |
|  * variable to identify the interrupting device.  When all active sensors have
 | |
|  * interrupted (found by comparing with the active_devices variable), the
 | |
|  * DATA_READY_FLAG is set.  That flag will be detected in the main() loop.
 | |
|  *
 | |
|  * This callback function is registered by the call to ch_io_int_callback_set() 
 | |
|  * in main().
 | |
|  */
 | |
| static void sensor_int_callback(ch_group_t *grp_ptr, uint8_t dev_num) {
 | |
| 	ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, dev_num);
 | |
| 
 | |
| 	data_ready_devices |= (1 << dev_num);		// add to data-ready bit mask
 | |
| 
 | |
| 	if (data_ready_devices == active_devices) {
 | |
| 		/* All active sensors have interrupted after performing a measurement */
 | |
| 		data_ready_devices = 0;
 | |
| 
 | |
| 		/* Set data-ready flag - it will be checked in main() loop */
 | |
| 		taskflags |= DATA_READY_FLAG;
 | |
| 
 | |
| 		/* Disable interrupt unless in free-running mode
 | |
| 		 *   It will automatically be re-enabled by the next ch_group_trigger() 
 | |
| 		 */
 | |
| 		if (ch_get_mode(dev_ptr) == CH_MODE_FREERUN) {
 | |
| 			chbsp_set_io_dir_in(dev_ptr);				// set INT line as input
 | |
| 			chbsp_group_io_interrupt_enable(grp_ptr);
 | |
| 		} else {
 | |
| 			chbsp_group_io_interrupt_disable(grp_ptr);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * io_complete_callback() - non-blocking I/O complete callback routine
 | |
|  *
 | |
|  * This function is called by SonicLib's I2C DMA handling function when all 
 | |
|  * outstanding non-blocking I/Q readouts have completed.  It simply sets a flag 
 | |
|  * that will be detected and handled in the main() loop.
 | |
|  *
 | |
|  * This callback function is registered by the call to 
 | |
|  * ch_io_complete_callback_set() in main().
 | |
|  *
 | |
|  *  Note: This callback is only used if READ_IQ_NONBLOCKING is defined to 
 | |
|  *  select non-blocking I/Q readout in this application.
 | |
|  */
 | |
| static void io_complete_callback(ch_group_t __attribute__((unused)) *grp_ptr) {
 | |
| 
 | |
| 	taskflags |= IQ_READY_FLAG;
 | |
| }
 | |
| 
 | |
| /* retarget the C library printf function to the USART */
 | |
| int fputc(int ch, FILE *f)
 | |
| {
 | |
|     usart_data_transmit(USART0, (uint8_t)ch);
 | |
|     while (RESET == usart_flag_get(USART0, USART_FLAG_TBE));
 | |
| 
 | |
|     return ch;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * handle_data_ready() - get and display data from all sensors
 | |
|  *
 | |
|  * This routine is called from the main() loop after all sensors have 
 | |
|  * interrupted. It shows how to read the sensor data once a measurement is 
 | |
|  * complete.  This routine always reads out the range and amplitude, and 
 | |
|  * optionally will read out the amplitude data or raw I/Q for all samples
 | |
|  * in the measurement.
 | |
|  *
 | |
|  * See the comments in app_config.h for information about the amplitude data
 | |
|  * and I/Q readout build options.
 | |
|  *
 | |
|  */
 | |
| static uint8_t handle_data_ready(ch_group_t *grp_ptr) {
 | |
| 	uint8_t 	dev_num;
 | |
| 	int 		num_samples = 0;
 | |
| 	uint8_t 	ret_val = 0;
 | |
| 
 | |
| 	/* Read and display data from each connected sensor 
 | |
| 	 *   This loop will write the sensor data to this application's "chirp_data"
 | |
| 	 *   array.  Each sensor has a separate chirp_data_t structure in that 
 | |
| 	 *   array, so the device number is used as an index.
 | |
| 	 */
 | |
| 
 | |
| 	for (dev_num = 0; dev_num < ch_get_num_ports(grp_ptr); dev_num++) {
 | |
| 		ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, dev_num);
 | |
| 
 | |
| 		if (ch_sensor_is_connected(dev_ptr)) {
 | |
| 
 | |
| 			/* Get measurement results from each connected sensor 
 | |
| 			 *   For sensor in transmit/receive mode, report one-way echo 
 | |
| 			 *   distance,  For sensor(s) in receive-only mode, report direct 
 | |
| 			 *   one-way distance from transmitting sensor 
 | |
| 			 */
 | |
| 			
 | |
| 			if (ch_get_mode(dev_ptr) == CH_MODE_TRIGGERED_RX_ONLY) {
 | |
| 				chirp_data[dev_num].range = ch_get_range(dev_ptr, 
 | |
| 														CH_RANGE_DIRECT);
 | |
| 			} else {
 | |
| 				chirp_data[dev_num].range = ch_get_range(dev_ptr, 
 | |
| 														CH_RANGE_ECHO_ONE_WAY);
 | |
| 			}
 | |
| 
 | |
| 			if (chirp_data[dev_num].range == CH_NO_TARGET) {
 | |
| 				/* No target object was detected - no range value */
 | |
| 
 | |
| 				chirp_data[dev_num].amplitude = 0;  /* no updated amplitude */
 | |
| 
 | |
| 				// printf("Port %d:          no target found        ", dev_num);
 | |
| 				printf("UltraSnoic0:%0.1f, %u\n", 0.0, 0);
 | |
| 
 | |
| 			} else {
 | |
| 				/* Target object was successfully detected (range available) */
 | |
| 				 /* Get the new amplitude value - it's only updated if range 
 | |
| 				  * was successfully measured.  */
 | |
| 				chirp_data[dev_num].amplitude = ch_get_amplitude(dev_ptr);
 | |
| 
 | |
| 				// printf("Port %d:  Range: %0.1f mm  Amp: %u  ", dev_num, 
 | |
| 				// 		(float) chirp_data[dev_num].range/32.0f,
 | |
| 				// 	   	chirp_data[dev_num].amplitude);
 | |
| 				printf("UltraSnoic0:%0.1f, %u\n", (float) chirp_data[dev_num].range/32.0f, chirp_data[dev_num].amplitude);
 | |
| 			}
 | |
| 
 | |
| 			/* Store number of active samples in this measurement */
 | |
| 			num_samples = ch_get_num_samples(dev_ptr);
 | |
| 			chirp_data[dev_num].num_samples = num_samples;
 | |
| 
 | |
| 			/* Optionally read amplitude values for all samples */
 | |
| #ifdef READ_AMPLITUDE_DATA
 | |
| 			uint16_t 	start_sample = 0;
 | |
| 			ch_get_amplitude_data(dev_ptr, chirp_data[dev_num].amp_data, 
 | |
| 								  start_sample, num_samples, CH_IO_MODE_BLOCK);
 | |
| 
 | |
| #ifdef OUTPUT_AMPLITUDE_DATA
 | |
| 			printf("\n");
 | |
| 			for (uint8_t count = 0; count < num_samples; count++) {
 | |
| 
 | |
| 				printf("%d\n",  chirp_data[dev_num].amp_data[count]);
 | |
| 			}
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| 			/* Optionally read raw I/Q values for all samples */
 | |
| #ifdef READ_IQ_DATA
 | |
| 			display_iq_data(dev_ptr);
 | |
| #endif
 | |
| 			/* If more than 2 sensors, put each on its own line */
 | |
| 			if (num_connected_sensors > 2) {
 | |
| 				printf("\n");
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	printf("\n");
 | |
| 	
 | |
| 	return ret_val;
 | |
| }
 | 
