#include "gd32e23x.h" #include "systick.h" #include #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); } 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); } /* 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; }