int main(void)
{
ch_group_t *grp_ptr = &chirp_group;
uint8_t u8_chirp_error = 0;
uint8_t u8_num_ports;
uint8_t u8_dev_num;
/* Initialize board hardware functions
* This call to the board support package (BSP) performs all necessary
* hardware initialization for the application to run on this board.
* This includes setting up memory regions, initializing clocks and
* peripherals (including I2C and serial port), and any processor-specific
* startup sequences.
*
* The chbsp_board_init() function also initializes fields within the
* sensor group descriptor, including number of supported sensors and
* the RTC clock calibration pulse length.
*/
chbsp_board_init(grp_ptr);
printf("\n\nNuvoton M263 & Chirp SonicLib 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");
/* Get the number of (possible) sensor devices on the board
* Set by the BSP during chbsp_board_init()
*/
u8_num_ports = ch_get_num_ports(grp_ptr);
/* Initialize sensor descriptors.
* This loop initializes each (possible) sensor's ch_dev_t descriptor,
* although we don't yet know if a sensor is actually connected.
*
* The call to ch_init() specifies the sensor descriptor, the sensor group
* it will be added to, the device number within the group, and the sensor
* firmware initialization routine that will be used. (The sensor
* firmware selection effectively specifies whether it is a CH101 or
* CH201 sensor, as well as the exact feature set.)
*/
printf("Initializing sensor(s)... ");
for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
{
ch_dev_t *dev_ptr = &(chirp_devices[u8_dev_num]); // init struct in array
/* Init device descriptor
* Note that this assumes all sensors will use the same sensor
* firmware. The CHIRP_SENSOR_FW_INIT_FUNC symbol is defined in
* app_config.h and is used for all devices.
*
* However, it is possible for different sensors to use different
* firmware images, by specifying different firmware init routines
* when ch_init() is called for each.
*/
u8_chirp_error |= ch_init(dev_ptr, grp_ptr, u8_dev_num,
CHIRP_SENSOR_FW_INIT_FUNC);
}
/* Start all sensors.
* The ch_group_start() function will search each port (that was
* initialized above) for a sensor. If it finds one, it programs it (with
* the firmware specified above during ch_init()) and waits for it to
* perform a self-calibration step. Then, once it has found all the
* sensors, ch_group_start() completes a timing reference calibration by
* applying a pulse of known length to the sensor's INT line.
*/
if (u8_chirp_error == 0)
{
printf("starting group... ");
u8_chirp_error = ch_group_start(grp_ptr);
}
if (u8_chirp_error == 0)
{
printf("OK\n");
}
else
{
printf("FAILED: %d\n", u8_chirp_error);
}
printf("\n");
/* Get and display the initialization results for each connected sensor.
* This loop checks each device number in the sensor group to determine
* if a sensor is actually connected. If so, it makes a series of
* function calls to get different operating values, including the
* operating frequency, clock calibration values, and firmware version.
*/
printf("Sensor\tType \t Freq\t\t RTC Cal \tFirmware\n");
for (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
{
ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);
if (ch_sensor_is_connected(dev_ptr))
{
printf("%d\tCH%d\t %u Hz\t%u@%ums\t%s\n", u8_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);
/* 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 (u8_dev_num = 0; u8_dev_num < u8_num_ports; u8_dev_num++)
{
ch_config_t dev_config;
ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);
if (ch_sensor_is_connected(dev_ptr))
{
/* Select sensor mode
* All connected sensors are placed in hardware triggered mode.
* The first connected (lowest numbered) sensor will transmit and
* receive, all others will only receive.
*/
u8_num_connected_sensors++; // count one more connected
u32_active_devices |= (1 << u8_dev_num); // add to active device bit mask
if (u8_num_connected_sensors == 1) // if this is the first sensor
{
dev_config.mode = CHIRP_FIRST_SENSOR_MODE;
}
else
{
dev_config.mode = CHIRP_OTHER_SENSOR_MODE;
}
if (dev_config.mode != CH_MODE_FREERUN) // unless free-running
{
u8_num_triggered_devices++; // will be triggered
}
/* 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;
}
else
{
dev_config.sample_interval = 0;
}
dev_config.thresh_ptr = 0;
/* Apply sensor configuration */
u8_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 ((!u8_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 (!u8_chirp_error)
{
display_config_info(dev_ptr);
}
else
{
printf("Device %d: Error during ch_set_config()\n", u8_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 (u8_num_triggered_devices > 0)
{
printf("Initializing sample timer for %dms interval... ",
MEASUREMENT_INTERVAL_MS);
chbsp_periodic_timer_init(MEASUREMENT_INTERVAL_MS,
periodic_timer_callback);
printf("OK\n");
}
printf("Starting measurements\n");
/* Enter main loop
* This is an infinite loop that will run for the remainder of the system
* execution. The processor is put in a low-power sleep mode between
* measurement cycles and is awakened by interrupt events.
*
* The interrupt may be the periodic timer (set up above), a data-ready
* interrupt from a sensor, or the completion of a non-blocking I/O
* operation. This loop will check flags that are set during the
* callback functions for the data-ready interrupt and the non-blocking
* I/O complete. Based on the flags that are set, this loop will call
* the appropriate routines to handle and/or display sensor data.
*/
while (1)
{
/* Check for sensor data-ready interrupt(s) */
if (u32_taskflags & DATA_READY_FLAG)
{
/* All sensors have interrupted - handle sensor data */
u32_taskflags &= ~DATA_READY_FLAG; // clear flag
handle_data_ready(grp_ptr); // read and display measurement
}
}
}
/*
* 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 (u8_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, u8_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 u32_data_ready_devices
* variable to identify the interrupting device. When all active sensors have
* interrupted (found by comparing with the u32_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 u8_dev_num)
{
ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_dev_num);
u32_data_ready_devices |= (1 << u8_dev_num); // add to data-ready bit mask
if (u32_data_ready_devices == u32_active_devices)
{
/* All active sensors have interrupted after performing a measurement */
u32_data_ready_devices = 0;
/* Set data-ready flag - it will be checked in main() loop */
u32_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);
}
}
}
/*
* display_config_info() - display the configuration values for a sensor
*
* This function displays the current configuration settings for an individual
* sensor. The operating mode, maximum range, and static target rejection
* range (if used) are displayed.
*
* For CH201 sensors only, the multiple detection threshold values are also
* displayed.
*/
static uint8_t display_config_info(ch_dev_t *dev_ptr)
{
ch_config_t read_config;
uint8_t u8_chirp_error;
uint8_t u8_dev_num = ch_get_dev_num(dev_ptr);
ch_thresholds_t read_thresholds;
/* Read configuration values for the device into ch_config_t structure */
u8_chirp_error = ch_get_config(dev_ptr, &read_config);
if (!u8_chirp_error)
{
const char *mode_string;
switch (read_config.mode)
{
case CH_MODE_IDLE:
mode_string = "IDLE";
break;
case CH_MODE_FREERUN:
mode_string = "FREERUN";
break;
case CH_MODE_TRIGGERED_TX_RX:
mode_string = "TRIGGERED_TX_RX";
break;
case CH_MODE_TRIGGERED_RX_ONLY:
mode_string = "TRIGGERED_RX_ONLY";
break;
default:
mode_string = "UNKNOWN";
}
/* Display sensor number, mode and max range */
printf("Sensor %d:\tmax_range=%dmm \tmode=%s ", u8_dev_num,
read_config.max_range, mode_string);
/* Display static target rejection range, if used */
if (read_config.static_range != 0)
{
printf("static_range=%d samples", read_config.static_range);
}
/* Display detection thresholds (only supported on CH201) */
if (ch_get_part_number(dev_ptr) == CH201_PART_NUMBER)
{
/* Get threshold values in structure */
u8_chirp_error = ch_get_thresholds(dev_ptr, &read_thresholds);
if (!u8_chirp_error)
{
printf("\n Detection thresholds:\n");
for (int i = 0; i < CH_NUM_THRESHOLDS; i++)
{
printf(" %d\tstart: %2d\tlevel: %d\n", i,
read_thresholds.threshold[i].start_sample,
read_thresholds.threshold[i].level);
}
}
else
{
printf(" Device %d: Error during ch_get_thresholds()", u8_dev_num);
}
}
printf("\n");
}
else
{
printf(" Device %d: Error during ch_get_config()\n", u8_dev_num);
}
return u8_chirp_error;
}
/*
* 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 u8_dev_num;
uint8_t u8_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 (u8_dev_num = 0; u8_dev_num < ch_get_num_ports(grp_ptr); u8_dev_num++)
{
ch_dev_t *dev_ptr = ch_get_dev_ptr(grp_ptr, u8_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[u8_dev_num].range = ch_get_range(dev_ptr,
CH_RANGE_DIRECT);
}
else
{
chirp_data[u8_dev_num].range = ch_get_range(dev_ptr,
CH_RANGE_ECHO_ONE_WAY);
}
if (chirp_data[u8_dev_num].range == CH_NO_TARGET)
{
/* No target object was detected - no range value */
chirp_data[u8_dev_num].amplitude = 0; /* no updated amplitude */
printf("Port %d: no target found ", u8_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[u8_dev_num].amplitude = ch_get_amplitude(dev_ptr);
printf("Port %d: Range: %0.1f mm Amp: %u ", u8_dev_num,
(float) chirp_data[u8_dev_num].range / 32.0f,
chirp_data[u8_dev_num].amplitude);
}
/* Store number of active samples in this measurement */
u8_num_samples = ch_get_num_samples(dev_ptr);
chirp_data[u8_dev_num].num_samples = u8_num_samples;
/* If more than 2 sensors, put each on its own line */
if (u8_num_connected_sensors > 2)
{
printf("\n");
}
}
}
printf("\n");
return ret_val;
}
|