Example programs for GR-MANGO

Dependencies:   opencv-lib mbed-http

This is a collection of sample programs that work on RZ/A2M boards. You can try Mbed OS for RZ/A2M with GR-MANGO board.

Overview

Sample program files are located under the sample_programs folder. You can try each sample program by changing the following macro in sample_select.h.

insample_select.h

#define SAMPLE_PROGRAM_NO  0
No.Program fileDescription
0sample_00_led_rtc_analogin.cppDigitalOut, InterruptIn, RTC, Timer and AnalogIn
1sample_01_flash_write.cppFlashAPI sample
2sample_02_ssif_loop_back.cppSSIF loop back sample
4sample_04_ssif_wav_playback.cppSSIF wav playback sample (use USB memory or SD card)
7sample_07_usb_func_serial.cppUSBSerial (CDC) sample
8sample_08_usb_func_mouse.cppUSBMouse sample
9sample_09_usb_func_keyboard.cppUSBKeyboard sample
10sample_10_usb_func_midi.cppUSBMIDI sample
11sample_11_usb_func_audio_1.cppUSBAudio sample
12sample_12_usb_func_audio_2.cppUSBAudio and SSIF sample
13sample_13_ether_http.cppEther HTTP sample
14sample_14_ether_https.cppEther HTTPS sample
16sample_16_usb_func_msd_1.cppUSBMSD and FlashAPI sample
17sample_17_usb_func_msd_2.cppUSBMSD and FlashAPI sample advanced version
18sample_18_mipi_drp_lcd.cppMIPI, DRP and LCD sample
19sample_19_mipi_drp_diplayapp.cppMIPI, DRP and USBSerial (CDC) sample (use "DisplayApp")
20sample_20_drp_dynamic_loading.cppDRP Dynamic Loading Sample
21sample_21_deep_standby_alarm.cppDeep standby and RTC alarm sample
22sample_22_hdmi_disp_ssif.cppHDMI output and SSIF wav playback Sample
23sample_23_mipi_hdmi.cppHDMI output and MIPI Sample
24sample_24_facedetection.cppHDMI output and face detection using OpenCV
25sample_25_hdmi_mouse.cppHDMI output and Mouse Sample

Notice

sample_24_facedetection.cpp only can be compiled with GNU Compiler Collection.

About sample_24_facedetection.cpp, this is a demonstration that can detect the face of a person without a mask. It will surround the face of a person without a mask with a red rectangle and sound alarm at the same time. To use OpenCV for face recognition, you need to prepare the followings:
・USB drive or SD card
・ Raspberry Pi Camera Module V2
・ HDMI monitor

Perform the following steps to complete face recognition sample.
1. Copy the lbpcascade_frontalface.xml to the root folder of USB drive or SD card and save it.
2. Copy the alarm.wav to the root folder of USB drive or SD card and save it.
3. Set "camera-type" value to "CAMERA_RASPBERRY_PI_832X480" in mbed_app.json

About custom boot loaders

This sample uses custom bootloader revision 5, and you can drag & drop the "xxxx_application.bin" file to write the program. Please see here for the detail.

How to write program

When using DAPLink, please use xxxx.bin as following.

  1. Connect the micro USB type B terminal to the PC using a USB cable.
  2. You can find the MBED directory.
  3. Drag & drop xxxx.bin to the MBED directory.
  4. When writing is completed, press the reset button.

When using custom bootloader, please use xxxx_application.bin as following.

  1. Connect the USB type C terminal to the PC using a USB cable.
  2. Hold down USB0 and press the reset button.
  3. You can find the GR-MANG directory.
  4. Drag & drop xxxx_application.bin to the GR-MANGO directory.

When writing is completed, press the reset button.

Attention!

For the first time only, you need to write a custom bootloader using DAPLink.

Terminal setting

If you want to confirm the serial communication the terminal soft on your PC, please specify the below values. You can change the baud rate by platform.stio-baud-rate of mbed_app.json.

Baud rate115,200
Data8bit
Paritynone
Stop1bit
Flow controlnone

sample_programs/sample_20_drp_dynamic_loading.cpp

Committer:
luyao@os.mbed.com
Date:
2021-03-04
Revision:
16:f4798796b4a2
Parent:
4:2da9e0f275a1

File content as of revision 16:f4798796b4a2:

/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
*
* Copyright (C) 2019 Renesas Electronics Corporation. All rights reserved.
*******************************************************************************/
#include "sample_select.h"

#if (SAMPLE_PROGRAM_NO == 20)
// SAMPLE_PROGRAM_NO 20 : DRP Dynamic Loading Sample
//
// Detects the edges of the input image from MIPI camera by Canny method using DRP and outputs to display.
// Please refer to the document for details. (RZ_A2M_Mbed\drp-for-mbed\r_drp\doc)
//
// Please set the value of "camera-type" in "mbed_app.json" to null or "CAMERA_RASPBERRY_PI".
//
//        "camera-type":{
//            "help": "Please see EasyAttach_CameraAndLCD/README.md",
//            "value": null
//        },
//
//        or
//
//        "camera-type":{
//            "help": "Please see EasyAttach_CameraAndLCD/README.md",
//            "value": "CAMERA_RASPBERRY_PI"
//        },
//
// Requirements
//   RZ/A2M Evaluation Board Kit : Display Output Board
//   SBEV-RZ/A2M                 : LVDS To HDMI Board
//   SEMB1402                    : LVDS To HDMI Board

#if !defined(TARGET_RZ_A2XX)
#error "DRP and MIPI are not supported."
#endif
#if MBED_CONF_APP_CAMERA_TYPE != CAMERA_RASPBERRY_PI
#error Please set the value of "camera-type" in "mbed_app.json" to "CAMERA_RASPBERRY_PI" and build.
#endif

#include "mbed.h"
#include "EasyAttach_CameraAndLCD.h"
#include "dcache-control.h"
#include "AsciiFont.h"
#include "r_dk2_if.h"
#include "r_drp_bayer2grayscale.h"
#include "r_drp_median_blur.h"
#include "r_drp_canny_calculate.h"
#include "r_drp_canny_hysterisis.h"

#define RAM_TABLE_DYNAMIC_LOADING   1

/*! Frame buffer stride: Frame buffer stride should be set to a multiple of 32 or 128
    in accordance with the frame buffer burst transfer mode. */
#define VIDEO_PIXEL_HW         (640)
#define VIDEO_PIXEL_VW         (480)

#define DATA_SIZE_PER_PIC      (1u)
#define FRAME_BUFFER_STRIDE    (((VIDEO_PIXEL_HW * DATA_SIZE_PER_PIC) + 31u) & ~31u)
#define FRAME_BUFFER_HEIGHT    (VIDEO_PIXEL_VW)

#define DRP_FLG_TILE_ALL       (R_DK2_TILE_0 | R_DK2_TILE_1 | R_DK2_TILE_2 | R_DK2_TILE_3 | R_DK2_TILE_4 | R_DK2_TILE_5)
#define DRP_FLG_CAMER_IN       (0x00000100)

static DisplayBase Display;
static uint8_t fbuf_bayer[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((aligned(128)));
static uint8_t fbuf_work0[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((aligned(32)));
static uint8_t fbuf_work1[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((aligned(32)));
static uint8_t fbuf_clat8[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((aligned(32)));
static uint8_t fbuf_overlay[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((section("NC_BSS"),aligned(32)));
static uint8_t drp_work_buf[((FRAME_BUFFER_STRIDE * ((FRAME_BUFFER_HEIGHT / 3) + 2)) * 2) * 3]__attribute((section("NC_BSS")));
static uint8_t nc_memory[512] __attribute((section("NC_BSS")));
static uint8_t drp_lib_id[R_DK2_TILE_NUM] = {0};
static Thread drpTask(osPriorityHigh);

#if RAM_TABLE_DYNAMIC_LOADING
static uint8_t ram_drp_lib_bayer2grayscale[sizeof(g_drp_lib_bayer2grayscale)]__attribute((aligned(32)));
static uint8_t ram_drp_lib_median_blur[sizeof(g_drp_lib_median_blur)]__attribute((aligned(32)));
static uint8_t ram_drp_lib_canny_calculate[sizeof(g_drp_lib_canny_calculate)]__attribute((aligned(32)));
static uint8_t ram_drp_lib_canny_hysterisis[sizeof(g_drp_lib_canny_hysterisis)]__attribute((aligned(32)));
#endif

static const uint32_t clut_data_resut[] = {0x00000000, 0xff00ff00};  // ARGB8888

static void IntCallbackFunc_Vfield(DisplayBase::int_type_t int_type) {
    drpTask.flags_set(DRP_FLG_CAMER_IN);
}

static void cb_drp_finish(uint8_t id) {
    uint32_t tile_no;
    uint32_t set_flgs = 0;

    // Change the operation state of the DRP library notified by the argument to finish
    for (tile_no = 0; tile_no < R_DK2_TILE_NUM; tile_no++) {
        if (drp_lib_id[tile_no] == id) {
            set_flgs |= (1 << tile_no);
        }
    }
    drpTask.flags_set(set_flgs);
}

static void Start_Video_Camera(void) {
    // Video capture setting (progressive form fixed)
    Display.Video_Write_Setting(
        DisplayBase::VIDEO_INPUT_CHANNEL_0,
        DisplayBase::COL_SYS_NTSC_358,
        (void *)fbuf_bayer,
        FRAME_BUFFER_STRIDE,
        DisplayBase::VIDEO_FORMAT_RAW8,
        DisplayBase::WR_RD_WRSWA_NON,
        VIDEO_PIXEL_VW,
        VIDEO_PIXEL_HW
    );
    EasyAttach_CameraStart(Display, DisplayBase::VIDEO_INPUT_CHANNEL_0);
}

static void Start_LCD_Display(void) {
    DisplayBase::rect_t rect;
    DisplayBase::clut_t clut_param;

    rect.vs = 0;
    rect.vw = VIDEO_PIXEL_VW;
    rect.hs = 0;
    rect.hw = VIDEO_PIXEL_HW;
    Display.Graphics_Read_Setting(
        DisplayBase::GRAPHICS_LAYER_0,
        (void *)fbuf_clat8,
        FRAME_BUFFER_STRIDE,
        DisplayBase::GRAPHICS_FORMAT_CLUT8,
        DisplayBase::WR_RD_WRSWA_32_16_8BIT,
        &rect
    );
    Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_0);

    memset(fbuf_overlay, 0, sizeof(fbuf_overlay));
    clut_param.color_num = sizeof(clut_data_resut) / sizeof(uint32_t);
    clut_param.clut = clut_data_resut;

    rect.vs = 0;
    rect.vw = VIDEO_PIXEL_VW;
    rect.hs = 0;
    rect.hw = VIDEO_PIXEL_HW;
    Display.Graphics_Read_Setting(
        DisplayBase::GRAPHICS_LAYER_2,
        (void *)fbuf_overlay,
        FRAME_BUFFER_STRIDE,
        DisplayBase::GRAPHICS_FORMAT_CLUT8,
        DisplayBase::WR_RD_WRSWA_32_16_8BIT,
        &rect,
        &clut_param
    );
    Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_2);

    ThisThread::sleep_for(50);
    EasyAttach_LcdBacklight(true);
}

static void drp_task(void) {
    uint32_t idx;
    uint32_t drp_time[8];
    char str[64];
    Timer t;
    AsciiFont ascii_font(fbuf_overlay, VIDEO_PIXEL_HW, VIDEO_PIXEL_VW, FRAME_BUFFER_STRIDE, DATA_SIZE_PER_PIC);

    EasyAttach_Init(Display);
    Start_LCD_Display();
    // Interrupt callback function setting (Field end signal for recording function in scaler 0)
    Display.Graphics_Irq_Handler_Set(DisplayBase::INT_TYPE_S0_VFIELD, 0, IntCallbackFunc_Vfield);
    Start_Video_Camera();

#if RAM_TABLE_DYNAMIC_LOADING
    // Copy to RAM to increase the speed of dynamic loading.
    memcpy(ram_drp_lib_bayer2grayscale, g_drp_lib_bayer2grayscale, sizeof(ram_drp_lib_bayer2grayscale));
    memcpy(ram_drp_lib_median_blur, g_drp_lib_median_blur, sizeof(ram_drp_lib_median_blur));
    memcpy(ram_drp_lib_canny_calculate, g_drp_lib_canny_calculate, sizeof(ram_drp_lib_canny_calculate));
    memcpy(ram_drp_lib_canny_hysterisis, g_drp_lib_canny_hysterisis, sizeof(ram_drp_lib_canny_hysterisis));
#endif

    R_DK2_Initialize();

    t.start();

    while (true) {
        ThisThread::flags_wait_all(DRP_FLG_CAMER_IN);

        /* Load DRP Library            */
        /*        +------------------+ */
        /* tile 0 | Bayer2Grayscale  | */
        /*        +------------------+ */
        /* tile 1 | Bayer2Grayscale  | */
        /*        +------------------+ */
        /* tile 2 | Bayer2Grayscale  | */
        /*        +------------------+ */
        /* tile 3 | Bayer2Grayscale  | */
        /*        +------------------+ */
        /* tile 4 | Bayer2Grayscale  | */
        /*        +------------------+ */
        /* tile 5 | Bayer2Grayscale  | */
        /*        +------------------+ */
        /* fbuf_bayer -> fbuf_work0    */
        t.reset();
        R_DK2_Load(
#if RAM_TABLE_DYNAMIC_LOADING
                   ram_drp_lib_bayer2grayscale,
#else
                   g_drp_lib_bayer2grayscale,
#endif
                   R_DK2_TILE_0 | R_DK2_TILE_1 | R_DK2_TILE_2 | R_DK2_TILE_3 | R_DK2_TILE_4 | R_DK2_TILE_5,
                   R_DK2_TILE_PATTERN_1_1_1_1_1_1, NULL, &cb_drp_finish, drp_lib_id);
        R_DK2_Activate(0, 0);
        drp_time[0] = t.read_us();

        t.reset();
        r_drp_bayer2grayscale_t * param_b2g = (r_drp_bayer2grayscale_t *)nc_memory;
        for (idx = 0; idx < R_DK2_TILE_NUM; idx++) {
            param_b2g[idx].src    = (uint32_t)fbuf_bayer + (VIDEO_PIXEL_HW * (VIDEO_PIXEL_VW / R_DK2_TILE_NUM) * idx);
            param_b2g[idx].dst    = (uint32_t)fbuf_work0 + (VIDEO_PIXEL_HW * (VIDEO_PIXEL_VW / R_DK2_TILE_NUM) * idx);
            param_b2g[idx].width  = VIDEO_PIXEL_HW;
            param_b2g[idx].height = VIDEO_PIXEL_VW / R_DK2_TILE_NUM;
            param_b2g[idx].top    = (idx == 0) ? 1 : 0;
            param_b2g[idx].bottom = (idx == 5) ? 1 : 0;
            R_DK2_Start(drp_lib_id[idx], (void *)&param_b2g[idx], sizeof(r_drp_bayer2grayscale_t));
        }
        ThisThread::flags_wait_all(DRP_FLG_TILE_ALL);
        R_DK2_Unload(0, drp_lib_id);
        drp_time[1] = t.read_us();


        /* Load DRP Library            */
        /*        +------------------+ */
        /* tile 0 | MedianBlur       | */
        /*        +------------------+ */
        /* tile 1 | MedianBlur       | */
        /*        +------------------+ */
        /* tile 2 | MedianBlur       | */
        /*        +------------------+ */
        /* tile 3 | MedianBlur       | */
        /*        +------------------+ */
        /* tile 4 | MedianBlur       | */
        /*        +------------------+ */
        /* tile 5 | MedianBlur       | */
        /*        +------------------+ */
        /* fbuf_work0 -> fbuf_work1    */
        t.reset();
        R_DK2_Load(
#if RAM_TABLE_DYNAMIC_LOADING
                   ram_drp_lib_median_blur,
#else
                   g_drp_lib_median_blur,
#endif
                   R_DK2_TILE_0 | R_DK2_TILE_1 | R_DK2_TILE_2 | R_DK2_TILE_3 | R_DK2_TILE_4 | R_DK2_TILE_5,
                   R_DK2_TILE_PATTERN_1_1_1_1_1_1, NULL, &cb_drp_finish, drp_lib_id);
        R_DK2_Activate(0, 0);
        drp_time[2] = t.read_us();

        t.reset();
        r_drp_median_blur_t * param_median = (r_drp_median_blur_t *)nc_memory;
        for (idx = 0; idx < R_DK2_TILE_NUM; idx++) {
            param_median[idx].src    = (uint32_t)fbuf_work0 + (VIDEO_PIXEL_HW * (VIDEO_PIXEL_VW / R_DK2_TILE_NUM) * idx);
            param_median[idx].dst    = (uint32_t)fbuf_work1 + (VIDEO_PIXEL_HW * (VIDEO_PIXEL_VW / R_DK2_TILE_NUM) * idx);
            param_median[idx].width  = VIDEO_PIXEL_HW;
            param_median[idx].height = VIDEO_PIXEL_VW / R_DK2_TILE_NUM;
            param_median[idx].top    = (idx == 0) ? 1 : 0;
            param_median[idx].bottom = (idx == 5) ? 1 : 0;
            R_DK2_Start(drp_lib_id[idx], (void *)&param_median[idx], sizeof(r_drp_median_blur_t));
        }
        ThisThread::flags_wait_all(DRP_FLG_TILE_ALL);
        R_DK2_Unload(0, drp_lib_id);
        drp_time[3] = t.read_us();


        /* Load DRP Library            */
        /*        +------------------+ */
        /* tile 0 |                  | */
        /*        + CannyCalculate   + */
        /* tile 1 |                  | */
        /*        +------------------+ */
        /* tile 2 |                  | */
        /*        + CannyCalculate   + */
        /* tile 3 |                  | */
        /*        +------------------+ */
        /* tile 4 |                  | */
        /*        + CannyCalculate   + */
        /* tile 5 |                  | */
        /*        +------------------+ */
        /* fbuf_work1 -> fbuf_work0    */
        t.reset();
        R_DK2_Load(
#if RAM_TABLE_DYNAMIC_LOADING
                   ram_drp_lib_canny_calculate,
#else
                   g_drp_lib_canny_calculate,
#endif
                   R_DK2_TILE_0 | R_DK2_TILE_2 | R_DK2_TILE_4,
                   R_DK2_TILE_PATTERN_2_2_2, NULL, &cb_drp_finish, drp_lib_id);
        R_DK2_Activate(0, 0);
        drp_time[4] = t.read_us();

        t.reset();
        r_drp_canny_calculate_t * param_canny_cal = (r_drp_canny_calculate_t *)nc_memory;
        for (idx = 0; idx < 3; idx++) {
            param_canny_cal[idx].src    = (uint32_t)fbuf_work1 + (VIDEO_PIXEL_HW * (VIDEO_PIXEL_VW / 3) * idx);
            param_canny_cal[idx].dst    = (uint32_t)fbuf_work0 + (VIDEO_PIXEL_HW * (VIDEO_PIXEL_VW / 3) * idx);
            param_canny_cal[idx].width  = VIDEO_PIXEL_HW;
            param_canny_cal[idx].height = (VIDEO_PIXEL_VW / 3);
            param_canny_cal[idx].top    = ((idx * 2) == 0) ? 1 : 0;
            param_canny_cal[idx].bottom = ((idx * 2) == 4) ? 1 : 0;
            param_canny_cal[idx].work   = (uint32_t)&drp_work_buf[((VIDEO_PIXEL_HW * ((VIDEO_PIXEL_VW / 3) + 2)) * 2) * idx];
            param_canny_cal[idx].threshold_high = 0x28;
            param_canny_cal[idx].threshold_low  = 0x18;
            R_DK2_Start(drp_lib_id[(idx * 2)], (void *)&param_canny_cal[idx], sizeof(r_drp_canny_calculate_t));
        }
        ThisThread::flags_wait_all(DRP_FLG_TILE_ALL);
        R_DK2_Unload(0, drp_lib_id);
        drp_time[5] = t.read_us();


        /* Load DRP Library            */
        /*        +------------------+ */
        /* tile 0 |                  | */
        /*        +                  + */
        /* tile 1 |                  | */
        /*        +                  + */
        /* tile 2 |                  | */
        /*        + CannyHysterisis  + */
        /* tile 3 |                  | */
        /*        +                  + */
        /* tile 4 |                  | */
        /*        +                  + */
        /* tile 5 |                  | */
        /*        +------------------+ */
        /* fbuf_work0 -> fbuf_clat8    */
        t.reset();
        R_DK2_Load(
#if RAM_TABLE_DYNAMIC_LOADING
                   ram_drp_lib_canny_hysterisis,
#else
                   g_drp_lib_canny_hysterisis,
#endif
                   R_DK2_TILE_0,
                   R_DK2_TILE_PATTERN_6, NULL, &cb_drp_finish, drp_lib_id);
        R_DK2_Activate(0, 0);
        drp_time[6] = t.read_us();

        t.reset();
        r_drp_canny_hysterisis_t * param_canny_hyst = (r_drp_canny_hysterisis_t *)nc_memory;
        param_canny_hyst[0].src    = (uint32_t)fbuf_work0;
        param_canny_hyst[0].dst    = (uint32_t)fbuf_clat8;
        param_canny_hyst[0].width  = VIDEO_PIXEL_HW;
        param_canny_hyst[0].height = VIDEO_PIXEL_VW;
        param_canny_hyst[0].work   = (uint32_t)drp_work_buf;
        param_canny_hyst[0].iterations = 2;
        R_DK2_Start(drp_lib_id[0], (void *)&param_canny_hyst[0], sizeof(r_drp_canny_hysterisis_t));
        ThisThread::flags_wait_all(DRP_FLG_TILE_ALL);
        R_DK2_Unload(0, drp_lib_id);
        drp_time[7] = t.read_us();


        // Display DRP time
        sprintf(str, "Bayer2Grayscale : Load %2.1fms + Run %2.1fms",
                (float_t)drp_time[0] / 1000, (float_t)drp_time[1] / 1000);
        ascii_font.DrawStr(str, 5, 5 + (AsciiFont::CHAR_PIX_HEIGHT + 1) * 0, 1, 2);
        sprintf(str, "MedianBlur      : Load %2.1fms + Run %2.1fms",
                (float_t)drp_time[2] / 1000, (float_t)drp_time[3] / 1000);
        ascii_font.DrawStr(str, 5, 5 + (AsciiFont::CHAR_PIX_HEIGHT + 1) * 2, 1, 2);
        sprintf(str, "CannyCalculate  : Load %2.1fms + Run %2.1fms",
                (float_t)drp_time[4] / 1000, (float_t)drp_time[5] / 1000);
        ascii_font.DrawStr(str, 5, 5 + (AsciiFont::CHAR_PIX_HEIGHT + 1) * 4, 1, 2);
        sprintf(str, "CannyHysterisis : Load %2.1fms + Run %2.1fms",
                (float_t)drp_time[6] / 1000, (float_t)drp_time[7] / 1000);
        ascii_font.DrawStr(str, 5, 5 + (AsciiFont::CHAR_PIX_HEIGHT + 1) * 6, 1, 2);

        uint32_t time_sum = 0;
        for (int i = 0; i < 8; i++) {
            time_sum += drp_time[i];
        }
        sprintf(str, "Total           : %2.1fms", (float_t)time_sum / 1000);
        ascii_font.DrawStr(str, 5, 5 + (AsciiFont::CHAR_PIX_HEIGHT + 1) * 8, 1, 2);
    }
}

int main(void) {
    // Start DRP task
    drpTask.start(callback(drp_task));

    ThisThread::sleep_for(osWaitForever);
}

#endif