2024-08-28 16:35:08 +08:00

472 lines
16 KiB
C

/*!
\file main.c
\brief led spark with systick, USART print and key example
\version 2023-02-27, V1.2.0, firmware for GD32E23x
*/
/*
Copyright (c) 2023, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#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);
} 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;
}