Skip to Content
DEEPCRAFT™ Studio 5.7 has arrived. Read more →

Model Deployment on Other Development Boards

This topic provides an overview on how to deploy a machine learning model trained in Studio on a development board. In this example, we use model.h and main.c to demonstrate the deployment of a model that processes PCM audio data as input and generates predictions, providing confidence levels for the various classes on which the model was trained.

Step 1: Include the header files

Include all necessary header files along with the model. The header files will vary depending on the selected development board and are not required by the Edge API.

Example including header files

#include <float.h> // Board specific header file #include "cyhal.h" // Board specific header file #include "cybsp.h" // Board specific header file #include "cy_retarget_io.h" // Board specific header file // Model to use #include <models/model.h>

Step 2: Define configuration for board and sensor

Define the configuration for your development board and sensor. These parameters will vary depending on the selected board and sensor and are not related to Edge API.

Example for defining the relevant configuration for sensor and board

// Desired sample rate. Typical values: 8/16/22.05/32/44.1/48 kHz #define SAMPLE_RATE_HZ 16000 // Audio subsystem clock. Typical values depends on the desire sample rate: // - 8/16/48kHz : 24.576 MHz // - 22.05/44.1kHz : 22.579 MHz #define AUDIO_SYS_CLOCK_HZ 24576000 // Decimation rate of the PDM/PCM block. Typical value is 64 #define DECIMATION_RATE 64 // Microphone sensitivity // PGA in 0.5 dB increment, for example a value of 5 would mean +2.5 dB. #define MICROPHONE_GAIN 19 // Multiplication factor of the input signal. // This should be 1. Any higher value will have an negative impact on the sampling dynamic range. // However, it can be used as a last resort when MICROPHONE_GAIN is at maximum. #define DIGITAL_BOOST_FACTOR 10.0f // Specifies the dynamic range in bits. // PCM word length, see the A/D specific documentation for valid ranges. #define AUIDO_BITS_PER_SAMPLE 16 // PDM/PCM Pins #define PDM_DATA P10_5 #define PDM_CLK P10_4 // Size of audio buffer #define AUDIO_BUFFER_SIZE 512

Step 3: Define Imagimob compatibility parameters

Add the compatibility parameters so that the code works regardless of the selected deployment target in DEEPCRAFT™ Studio.

// Imagimob compatibility defines to support all versions of code generation APIs #ifndef IPWIN_RET_SUCCESS #define IPWIN_RET_SUCCESS (0) #endif #ifndef IPWIN_RET_NODATA #define IPWIN_RET_NODATA (-1) #endif #ifndef IPWIN_RET_ERROR #define IPWIN_RET_ERROR (-2) #endif #ifndef IMAI_DATA_OUT_SYMBOLS #define IMAI_DATA_OUT_SYMBOLS IMAI_SYMBOL_MAP #endif

Step 4: Ensure sensor data is of the correct type and range

If the model is trained on 1-channel audio data within the range [-1,1], then we need to map the microphone samples into the same range.

Example for normalizing given audio sample into range [-1,1]

#define SAMPLE_NORMALIZE(sample) (((float) (sample)) / (float) (1 << (AUIDO_BITS_PER_SAMPLE - 1)))

Step 5: Define the halting function

Example for halting execution and flashing LED with the given code. If the code is 0 (for success) this function does nothing.

static void halt_error(int code) { if(code == 0) // Universal success code return; // flash code on LED for(;;){} }

Step 6: Define the inialization functions for board and sensor

These functions would be specific to the development board and sensor. The following example implements the functions for PCM audio.

static void init_board(void) { // Clear watchdog timer so that it doesn't trigger a reset #if defined (CY_DEVICE_SECURE) cyhal_wdt_t wdt_obj; result = cyhal_wdt_init(&wdt_obj, cyhal_wdt_get_max_timeout_ms()); CY_ASSERT(CY_RSLT_SUCCESS == result); cyhal_wdt_free(&wdt_obj); #endif // Initialize the device and board peripherals halt_error(cybsp_init()); // Enable global interrupts __enable_irq(); // Initialize retarget-io to use the debug UART port halt_error(cy_retarget_io_init_fc( CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, CYBSP_DEBUG_UART_CTS, CYBSP_DEBUG_UART_RTS, CY_RETARGET_IO_BAUDRATE)); }
static void init_audio(cyhal_pdm_pcm_t* pdm_pcm) { cyhal_clock_t audio_clock; cyhal_clock_t pll_clock; const cyhal_pdm_pcm_cfg_t pdm_pcm_cfg = { .sample_rate = SAMPLE_RATE_HZ, // Sample rate in Hz .decimation_rate = DECIMATION_RATE, // Decimation Rate of the PDM/PCM block .mode = CYHAL_PDM_PCM_MODE_LEFT, // Microphone to use (Channel) .word_length = AUIDO_BITS_PER_SAMPLE, // Bits per sample .left_gain = MICROPHONE_GAIN, // Left channel gain dB ("volume") .right_gain = MICROPHONE_GAIN, // Right channel gain dB ("volume") }; // Initialize the PLL halt_error(cyhal_clock_reserve(&pll_clock, &CYHAL_CLOCK_PLL[0])); halt_error(cyhal_clock_set_frequency(&pll_clock, AUDIO_SYS_CLOCK_HZ, NULL)); halt_error(cyhal_clock_set_enabled(&pll_clock, true, true)); // Initialize the audio subsystem clock (CLK_HF[1]) // The CLK_HF[1] is the root clock for the I2S and PDM/PCM blocks halt_error(cyhal_clock_reserve(&audio_clock, &CYHAL_CLOCK_HF[1])); // Source the audio subsystem clock from PLL halt_error(cyhal_clock_set_source(&audio_clock, &pll_clock)); halt_error(cyhal_clock_set_enabled(&audio_clock, true, true)); // Initialize the pulse-density modulation to pulse-code modulation (PDM/PCM) converter. halt_error(cyhal_pdm_pcm_init(pdm_pcm, PDM_DATA, PDM_CLK, &audio_clock, &pdm_pcm_cfg)); // Clear PDM/PCM RX FIFO halt_error(cyhal_pdm_pcm_clear(pdm_pcm)); // Start PDM/PCM halt_error(cyhal_pdm_pcm_start(pdm_pcm)); }

Step 7: Bring everything together in main function

int main(void) { int16_t audio_buffer[AUDIO_BUFFER_SIZE] = {0}; float label_scores[IMAI_DATA_OUT_COUNT]; // Array containing the confidence/probablility of each label/class. The sum of probabilities sums up to 1.0. char *label_text[] = IMAI_DATA_OUT_SYMBOLS; // Contains the class labels/symbols from the model. size_t audio_count; cyhal_pdm_pcm_t pdm_pcm; // Basic board setup init_board(); // Initialize model #ifdef IMAI_NATRIX_API IMAI_init(); #else halt_error(IMAI_init()); // new api returns status code from init call #endif // Initialize audio sampling init_audio(&pdm_pcm); // ANSI ESC sequence for clear screen printf("\x1b[2J\x1b[;H"); for (;;) { // Move cursor home printf("\033[H"); printf("Imagimob Audio Model Example\r\n\n"); // Read either audio_in_count samples or the number of samples that are currently // available in the receive buffer, whichever is less audio_count = AUDIO_BUFFER_SIZE; memset(audio_buffer, 0, AUDIO_BUFFER_SIZE * sizeof(uint16_t)); halt_error(cyhal_pdm_pcm_read(&pdm_pcm, (void *) audio_buffer, &audio_count)); float sample_max = 0; for(int i = 0; i < audio_count; i++) { // Convert integer sample to float and pass it to the model float sample = SAMPLE_NORMALIZE(audio_buffer[i]) * DIGITAL_BOOST_FACTOR; halt_error(IMAI_enqueue(&sample)); // Used to tune gain control. sample_max should be near 1.0 when shouting directly into the microphone float sample_abs = fabs(sample); if(sample_abs > sample_max) sample_max = sample_abs; // Check if there is any model output to process int16_t best_label = 0; float max_score = -1000.0f; switch(IMAI_dequeue(label_scores)) { case IMAI_RET_SUCCESS: // We have data, display it for(int i = 0; i < IMAI_DATA_OUT_COUNT; i++) { printf("label: %-10s: score: %f\r\n", label_text[i], label_scores[i]); if (label_scores[i] > max_score) { max_score = label_scores[i]; best_label = i; } } printf("\r\n"); printf("Output: %-30s\r\n", label_text[best_label]); printf("\r\n"); printf("Volume: %.4f\r\n", sample_max); printf("Audio buffer utilization: %.3f\r\n", audio_count / (float)AUDIO_BUFFER_SIZE); break; case IMAI_RET_NODATA: // No new output, continue with sampling break; case IMAI_RET_ERROR: // Abort on error halt_error(IMAI_RET_ERROR); break; } } } }
Last updated on