Guillermo Perez Guillen
Created January 6, 2020 © CC BY-NC-ND

Protected Area Monitor: RSL10 Sense + Mini Drone

A protected area through effective means, to achieve the long term conservation of nature with services of a RSL10-SENSE and a Mini Drone

AdvancedFull instructions provided17 hours108

Things used in this project

Hardware components

RSL10-SENSE-GEVK
onsemi RSL10-SENSE-GEVK
×1
DJI TELLO RYZE DRONE
×1

Software apps and online services

onsemi On Semiconductor IDE (4.12)
onsemi RSL10 Sense and Control App

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Android Smartphone

Story

Read more

Custom parts and enclosures

Protected Area Monitor

STL, FCStd and JPG files of a Protected Area Monitor

Schematics

Schematic diagram

Block diagram of the proposed system: Protected Area Monitor

Code

main.c

C/C++
Section 3. INTERFACE TO GET THE ALTITUDE
Modified "main.c" code in the example: sense_production_tests
#include <BDK.h>
#include <BSP_Components.h>
#include <BLE_Components.h>
#include <ansi_color.h>
#include <SEGGER_RTT.h>

#include <stdio.h>
#include <math.h>

#define AUDIO_DMIC0_GAIN                0x800
#define AUDIO_DMIC1_GAIN                0x800
#define AUDIO_OD_GAIN                   0x800

#define AUDIO_CONFIG                    (OD_AUDIOSLOWCLK            | \
                                         DMIC_AUDIOCLK              | \
                                         DECIMATE_BY_64             | \
                                         OD_UNDERRUN_PROTECT_ENABLE | \
                                         OD_DATA_MSB_ALIGNED        | \
                                         DMIC0_DATA_LSB_ALIGNED     | \
                                         DMIC1_DATA_LSB_ALIGNED     | \
                                         OD_DMA_REQ_DISABLE         | \
                                         DMIC0_DMA_REQ_DISABLE      | \
                                         DMIC1_DMA_REQ_DISABLE      | \
                                         OD_INT_GEN_DISABLE         | \
                                         DMIC0_INT_GEN_ENABLE       | \
                                         DMIC1_INT_GEN_DISABLE      | \
                                         OD_DISABLE                 | \
                                         DMIC0_ENABLE               | \
                                         DMIC1_DISABLE)

#define EEPROM_I2C_ADDR       (0x50)
#define EEPROM_PAGE_SIZE      (4)

/* All data written to RX characteristic will be echoed back as a notification
 * send from TX characteristic. */
void BLE_CustomServiceEcho(struct BLE_ICS_RxIndData *ind);

/* Prints message into serial terminal when button is pressed / released. */
void PB_TransitionEvent(void *arg);

/* Copies measurement data for printing of status messages. */
void BME680_Callback(struct BME680_ENV_Data *output);

/* Copies measurement data for printing of status messages. */
void BHY_OrientationCallback(bhy_data_generic_t *data, bhy_virtual_sensor_t sensor);


int32_t noa1305_status = -1;

int32_t bme680_status = -1;
struct BME680_ENV_Data bme680_output = { 0 };

int32_t bhy_status = -1;
bhy_data_vector_t bhy_orientation;

int32_t eeprom_status = -1;
I2CEeprom eeprom;
const uint8_t eeprom_ref[]  = "This is just a test";
const uint8_t eeprom_ref_length = sizeof(eeprom_ref);

int32_t dmic_value = 0;
int32_t dmic_max = 0;
int32_t dmic_min = INT32_MAX;

float tmax = 0;
float hmax = 0;
float altitude;
float bar;

int main(void)
{
    int32_t retval = 0;

    /* Initialize BDK library, set system clock (default 8MHz). */
    BDK_InitializeFreq(HAL_CLK_CONF_8MHZ);
    HAL_I2C_SetBusSpeed(HAL_I2C_BUS_SPEED_FAST);

    /* Initialize all LEDs */
    LED_Initialize(LED_RED);
    LED_Initialize(LED_GREEN);
    LED_Initialize(LED_BLUE);

    /* Test LEDs are working */
    LED_On(LED_RED);
    HAL_Delay(500);

    LED_Off(LED_RED);
    LED_On(LED_GREEN);
    HAL_Delay(500);

    LED_Off(LED_GREEN);
    LED_On(LED_BLUE);

    /* Initialize BLE stack */
    BDK_BLE_Initialize();
    BDK_BLE_SetLocalName("RSL10-SENSE-TESTER");
    BLE_ICS_Initialize(NULL);

    /* Initialize Button to call callback function when pressed or released. */
    BTN_Initialize(BTN0);
    BTN_Initialize(BTN1);

    /* AttachScheduled -> Callback will be scheduled and called by Kernel Scheduler. */
    /* AttachInt -> Callback will be called directly from interrupt routine. */
    BTN_AttachScheduled(BTN_EVENT_TRANSITION, &PB_TransitionEvent, (void*)BTN0, BTN0);
    BTN_AttachScheduled(BTN_EVENT_TRANSITION, &PB_TransitionEvent, (void*)BTN1, BTN1);

    /** Initialize NOA1305. */
    retval = NOA1305_ALS_Initialize();
    if (retval == NOA1305_OK)
    {
        retval = NOA1305_ALS_StartContinuous(0, NULL);
        if (retval == NOA1305_OK)
        {
            noa1305_status = 0;
        }
        else
        {
            noa1305_status = 2;
        }
    }
    else
    {
        noa1305_status = 1;
    }

    /** Initialize BME680 */
    retval = BME680_ENV_Initialize();
    if (retval == 0)
    {
        retval = BME680_ENV_StartPeriodic(BME680_Callback, 3000);
        if (retval == 0)
        {
            bme680_status = 0;
        }
        else
        {
            bme680_status = 2;
        }
    }
    else
    {
        bme680_status = 1;
    }

    /** Initialize BHI160 + load BMM150 RAM patch */
    retval = BHI160_NDOF_Initialize();
    if (retval == BHY_SUCCESS)
    {
        retval = BHI160_NDOF_EnableSensor(BHI160_NDOF_S_ORIENTATION, BHY_OrientationCallback, 1);
        if (retval == BHY_SUCCESS)
        {
            bhy_status = 0;
        }
        else
        {
            bhy_status = 2;
        }
    }
    else
    {
        bhy_status = 1;
    }

    /** DO R/W test for N24RF64 EEPROM memory. */
    retval = I2CEeprom_Initialize(EEPROM_I2C_ADDR, EEPROM_PAGE_SIZE, &eeprom);
    if (retval == I2C_EEPROM_OK)
    {
        retval = I2CEeprom_Write(0, (uint8_t*)eeprom_ref, eeprom_ref_length, &eeprom);
        if (retval == I2C_EEPROM_OK)
        {
            uint8_t eeprom_readback[sizeof(eeprom_ref)];

            retval = I2CEeprom_Read(0, eeprom_readback, eeprom_ref_length, &eeprom);
            if (retval == I2C_EEPROM_OK)
            {
                if (memcmp(eeprom_ref, eeprom_readback, eeprom_ref_length) == 0)
                {
                    memset(eeprom_readback, 0, eeprom_ref_length);
                    I2CEeprom_Write(0, eeprom_readback, eeprom_ref_length, &eeprom);

                    eeprom_status = 0;
                }
                else
                {
                    eeprom_status = 4;
                }
            }
            else
            {
                eeprom_status = 3;
            }
        }
        else
        {
            eeprom_status = 2;
        }
    }
    else
    {
        eeprom_status = 1;
    }

    /** Configure DMIC input to test INMP522 microphone. */

    /* Configure AUDIOCLK to 2 MHz and AUDIOSLOWCLK to 1 MHz. */
    CLK->DIV_CFG1 &= ~(AUDIOCLK_PRESCALE_64 | AUDIOSLOWCLK_PRESCALE_4);
    CLK->DIV_CFG1 |= AUDIOCLK_PRESCALE_4 | AUDIOSLOWCLK_PRESCALE_2;

    /* Configure OD, DMIC0 and DMIC1 */
    Sys_Audio_Set_Config(AUDIO_CONFIG);

    Sys_Audio_Set_DMICConfig(DMIC0_DCRM_CUTOFF_20HZ | DMIC1_DCRM_CUTOFF_20HZ |
                             DMIC1_DELAY_DISABLE | DMIC0_FALLING_EDGE |
                             DMIC1_RISING_EDGE, 0);

    Sys_Audio_DMICDIOConfig(DIO_6X_DRIVE | DIO_LPF_DISABLE | DIO_NO_PULL,
                            10, 6, DIO_MODE_AUDIOCLK);

    /* Configure Gains for DMIC0, DMIC1 and OD */
    AUDIO->DMIC0_GAIN = AUDIO_DMIC0_GAIN;
    NVIC_EnableIRQ(DMIC_OUT_OD_IN_IRQn);

    LED_Off(LED_BLUE);
    printf("APP: Entering main loop.\r\n");

    uint32_t timestamp = 0;
    while (1)
    {
        /* Execute any events that have occurred & refresh Watchdog timer. */
        BDK_Schedule();

        /* Print status information every second */
        if (HAL_TIME_ELAPSED_SINCE(timestamp) >= 1000)
        {
            timestamp = HAL_Time();

            printf(RTT_CTRL_CLEAR "Test status:\r\n");

            printf("NOA1305 initialization: %s\r\n", noa1305_status == 0 ? COLORIZE("OK", GREEN) : COLORIZE("ERROR", RED));
            if (noa1305_status == 0)
            {
                uint32_t lux = 0;
                NOA1305_ALS_ReadLux(&lux);
                printf("NOA1305 measured value: " COLORIZE("%lu", YELLOW) " lux\r\n\n", lux);
            }

            printf("BME680 initialization: %s\r\n", bme680_status == 0 ? COLORIZE("OK", GREEN) : COLORIZE("ERROR", RED));
            if (bme680_status == 0)
            {
                printf("BME680 temperature: " COLORIZE("%.2f", YELLOW) " °C\r\n", ((float)bme680_output.temperature) / 100.0f);
                printf("Maximum temperature: " COLORIZE("%.2f", YELLOW) " °C\r\n", tmax / 100.0f);
                printf("BME680 humidity: " COLORIZE("%.2f", YELLOW) " %%\r\n", ((float)bme680_output.humidity) / 1000.0f);
                printf("Maximum humidity: " COLORIZE("%.2f", YELLOW) " %%\r\n", hmax / 1000.0f);
                printf("BME680 pressure: " COLORIZE("%.2f", YELLOW) " Pa\r\n", ((float)bme680_output.pressure));
                bar = bme680_output.pressure * 1e-5;
                altitude = -8005 * log(bar);
                printf("Altitude: " COLORIZE("%.2f", YELLOW) " mts\r\n\n", altitude);
            }

            if (bme680_output.temperature > tmax) {
            	tmax = bme680_output.temperature;
            	//printf("t max: " COLORIZE("%.2f", YELLOW) " °C\r\n", tmax / 100.0f);
            	}

            if (bme680_output.humidity > hmax) {
            	hmax = bme680_output.humidity;
            	//printf("h max: " COLORIZE("%.2f", YELLOW) " %%\r\n", hmax / 1000.0f);
            	}

            printf("BHI160 (+BMM150) initialization: %s\r\n", bhy_status == 0 ? COLORIZE("OK", GREEN) : COLORIZE("ERROR", RED) );
            if (bhy_status == 0)
            {
                float h = bhy_orientation.x / 32768.0f * 360.0f;
                float p = bhy_orientation.y / 32768.0f * 360.0f;
                float y = bhy_orientation.z / 32768.0f * 360.0f;

                printf("BHI160 heading=" COLORIZE("%.2f°", YELLOW) ", ", h);
                printf("pitch=" COLORIZE("%.2f°", YELLOW) ", ", p);
                printf("yaw=" COLORIZE("%.2f°", YELLOW) "\r\n\n", y);
            }

            printf("N24RF64 read back test: %s\r\n\n", eeprom_status == 0 ? COLORIZE("OK", GREEN) : COLORIZE("ERROR", RED));

            printf("INMP522: Use J-Scope to see waveform\r\n");
            printf("INMP522: dmic_min=" COLORIZE("%ld", YELLOW) ", dmic_max=" COLORIZE("%ld", YELLOW) "\r\n", dmic_min, dmic_max);
        }

        SYS_WAIT_FOR_INTERRUPT;
    }

    return 0;
}

void BLE_CustomServiceEcho(struct BLE_ICS_RxIndData *ind)
{
    BLE_ICS_Notify(ind->data, ind->data_len);
}

void PB_TransitionEvent(void *arg)
{
    ButtonName btn = (ButtonName)arg;

    switch (btn)
    {
    case BTN0:
        LED_Toggle(LED_RED);
        break;
    case BTN1:
        LED_Toggle(LED_GREEN);
        break;
    default:
        return;
    }

    /* Read current Push Button state. */
    bool button_pressed = BTN_Read(btn);

    /* Print current button state to serial terminal. */
    printf("PB: Button %s state: %s [%lu ms]\r\n", (btn == BTN0) ? "0" : "1",
            (button_pressed == BTN_PRESSED) ? "PRESSED" : "RELEASED",
            HAL_Time());
}

void BME680_Callback(struct BME680_ENV_Data *output)
{
    memcpy(&bme680_output, output, sizeof(struct BME680_ENV_Data));
}

void BHY_OrientationCallback(bhy_data_generic_t *data, bhy_virtual_sensor_t sensor)
{
    memcpy(&bhy_orientation, &data->data_vector, sizeof(bhy_data_vector_t));
}

void DMIC_OUT_OD_IN_IRQHandler(void)
{
    dmic_value = (int32_t)AUDIO->DMIC0_DATA;

    if (dmic_max < dmic_value)
    {
        dmic_max = dmic_value;
    }
    else
    {
        if (dmic_min > dmic_value)
        {
            dmic_min = dmic_value;
        }
    }
}

bsec_integration.c

C/C++
Section 4. BSEC ENVIRONMENTAL CLUSTER WITH BME680 SENSOR
Modified "bsec_integration.c" code in the example: sense_bm680_bsec
#include <stdio.h>
#include <BDK.h>

#include <BSEC_ENV.h>
#include <timermath.h>
#include <ansi_color.h>
#include <bsec_integration.h>
#include <I2CEeprom.h>
#include <math.h>

//#define APP_USE_ANSI_COLORS


/* Delays program execution for given amount of time. */
void App_BsecSleep(uint32_t t_ms)
{
    HAL_Delay(t_ms);
}

void App_BsecOutputReady(bsec_env_output_struct *output)
{
//    printf(""); // clear screen
    printf("BSEC output:\r\n");

    printf("  timestamp = %lu ms\r\n", (uint32_t)(output->timestamp / 1000000));

#ifdef APP_USE_ANSI_COLORS
    printf("  iaq = " COLORIZE("%.0f", GREEN) " (%d)\r\n", output->iaq,
            output->iaq_accuracy);

    printf("  temperature = " COLORIZE("%.2f °C", RED) " (%d)\r\n",
            output->temperature, output->temperature_accuracy);

    printf("  humidity = " COLORIZE("%.2f %%", CYAN) " (%d)\r\n",
            output->humidity, output->humidity_accuracy);
#else
    printf("  iaq = %.0f (%d)\r\n", output->iaq, output->iaq_accuracy);

    printf("  temperature = %.2f °C (%d)\r\n",
            output->temperature, output->temperature_accuracy);

    printf("  humidity = %.2f %% (%d)\r\n",
            output->humidity, output->humidity_accuracy);

#endif /* APP_USE_ANSI_COLORS */
    printf("  raw_pressure = %f Pa\r\n", output->raw_pressure);

    float bar = (output->raw_pressure) * 1e-5; // ALTITUDE
    float altitude = -8005 * log(bar); // ALTITUDE
    printf("  altitude = %f mts\r\n", altitude); // ALTITUDE

    printf("  co2_equivalent = %.2f ppm (%d)\r\n", output->co2_equivalent,
            output->co2_accuracy);

    printf("  breath_voc_equivalent = %.2f ppm (%d)\r\n",
            output->breath_voc_equivalent,
            output->breath_voc_accuracy);

    printf("\r\n\n");
}

/* Retrieves current system time stamp.
 *
 * The system uses 32-bit counter incremented every ms.
 * Therefore some additional logic was added to handle counter overflow and
 * expands the time stamp into 64-bit value.
 */
int64_t App_BsecGetTimestampUs()
{
    static int64_t timestamp = 0;
    static struct tm_math math;
    static uint32_t last = 0;

    uint32_t now, diff;

    if (timestamp == 0)
    {
        tm_initialize(&math, UINT32_MAX);
        last = 0;
    }

    now = HAL_Time();
    diff = tm_get_diff(&math, now, last);
    last = now;

    timestamp += diff;

    return timestamp * 1000;
}

uint32_t App_BsecStateLoadFromEEPROM(uint8_t *state_buffer, uint32_t buffer_len)
{
    int32_t retval;
    uint8_t magic[APP_BSEC_EEPROM_MAGIC_SIZE] = APP_BSEC_EEPROM_MAGIC;
    uint8_t magic_read[APP_BSEC_EEPROM_MAGIC_SIZE] = APP_BSEC_EEPROM_MAGIC;
    I2CEeprom m24rf64;

    I2CEeprom_Initialize(APP_BSEC_EEPROM_I2C_ADDR, 4, &m24rf64);

    retval = I2CEeprom_Read(APP_BSEC_EEPROM_ADDR, magic_read,
            APP_BSEC_EEPROM_MAGIC_SIZE, &m24rf64);
    if (retval == I2C_EEPROM_OK)
    {
        if (memcmp(magic, magic_read, APP_BSEC_EEPROM_MAGIC_SIZE - 1) == 0)
        {
            uint32_t saved_size = magic_read[APP_BSEC_EEPROM_MAGIC_SIZE - 1];

            if (saved_size != 0 && saved_size <= buffer_len)
            {
                retval = I2CEeprom_Read(
                        APP_BSEC_EEPROM_ADDR + APP_BSEC_EEPROM_MAGIC_SIZE,
                        state_buffer, saved_size, &m24rf64);
                if (retval == I2C_EEPROM_OK)
                {
                    printf("BSEC: Loaded BSEC state from EEPROM memory.\r\n");
                    return saved_size;
                }
            }
        }
    }

    printf("BSEC: Failed to load BSEC state from EEPROM memory.\r\n");
    return 0;
}

void App_BsecStateSaveToEEPROM(uint8_t *state_buffer, uint32_t size)
{
    int32_t retval;
    uint8_t magic[APP_BSEC_EEPROM_MAGIC_SIZE] = APP_BSEC_EEPROM_MAGIC;
    magic[APP_BSEC_EEPROM_MAGIC_SIZE - 1] = size;
    I2CEeprom m24rf64;

    I2CEeprom_Initialize(APP_BSEC_EEPROM_I2C_ADDR, 4, &m24rf64);

    retval = I2CEeprom_Write(APP_BSEC_EEPROM_ADDR, magic,
            APP_BSEC_EEPROM_MAGIC_SIZE, &m24rf64);
    if (retval == I2C_EEPROM_OK)
    {
        retval = I2CEeprom_Write(
                APP_BSEC_EEPROM_ADDR + APP_BSEC_EEPROM_MAGIC_SIZE, state_buffer,
                size, &m24rf64);
    }

    if (retval == I2C_EEPROM_OK)
    {
        printf("Saved BSEC state to EEPROM.\r\n");
    }
    else
    {
        printf(
                "BSEC: Error while saving BSEC state to EEPROM. (errcode=%ld)\r\n",
                retval);
    }
}

Project repository: "Protected Area Monitor: RSL10 Sense + Drone"

Folders: A) sense_ics_firmware (unmodified and used in sections 2 and 5); B) sense_production_tests (modified to calculate the altitude and used in section 3); and C) sense_bme680_bsec (modified to calculate the altitude and used in section 4)

Credits

Guillermo Perez Guillen

Guillermo Perez Guillen

57 projects • 63 followers
Electronics and Communications Engineer (ECE) & Renewable Energy: 14 prizes in Hackster / Hackaday Prize Finalist 2021-22-23

Comments