1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 // Apollo3 EVB specific features compile options:
17 // USE AM_BSP_NUM_LEDS : LED initialization and management per EVB target (# of
18 // LEDs defined in EVB BSP) USE_TIME_STAMP : Enable timers and time stamping for
19 // debug and performance profiling (customize per application) USE_DEBUG_GPIO :
20 // Enable GPIO flag polling for debug and performance profiling (customize per
21 // application) USE_MAYA : Enable specific pin configuration and features for
22 // AP3B "quarter" sized board
23
24 #include "tensorflow/lite/micro/examples/micro_speech/audio_provider.h"
25
26 #include <limits>
27
28 // These are headers from Ambiq's Apollo3 SDK.
29 #include "am_bsp.h" // NOLINT
30 #include "am_mcu_apollo.h" // NOLINT
31 #include "am_util.h" // NOLINT
32 #include "tensorflow/lite/micro/examples/micro_speech/micro_features/micro_model_settings.h"
33
34 namespace {
35
36 // These are the raw buffers that are filled by the PDM during DMA
37 constexpr int kPdmNumSlots = 1;
38 constexpr int kPdmSamplesPerSlot = 256;
39 constexpr int kPdmSampleBufferSize = (kPdmNumSlots * kPdmSamplesPerSlot);
40 uint32_t g_ui32PDMSampleBuffer0[kPdmSampleBufferSize];
41 uint32_t g_ui32PDMSampleBuffer1[kPdmSampleBufferSize];
42 uint32_t g_PowerOff = 0;
43
44 // Controls the double buffering between the two DMA buffers.
45 int g_dma_destination_index = 0;
46 // PDM Device Handle.
47 static void* g_pdm_handle;
48 // PDM DMA error flag.
49 volatile bool g_pdm_dma_error;
50 // So the interrupt can use the passed-in error handler to report issues.
51 tflite::ErrorReporter* g_pdm_dma_error_reporter = nullptr;
52
53 // Holds a longer history of audio samples in a ring buffer.
54 constexpr int kAudioCaptureBufferSize = 16000;
55 int16_t g_audio_capture_buffer[kAudioCaptureBufferSize] = {};
56 int g_audio_capture_buffer_start = 0;
57 int64_t g_total_samples_captured = 0;
58 int32_t g_latest_audio_timestamp = 0;
59
60 // Copy of audio samples returned to the caller.
61 int16_t g_audio_output_buffer[kMaxAudioSampleSize];
62 bool g_is_audio_initialized = false;
63
64 //*****************************************************************************
65 //
66 // Globals
67 //
68 //*****************************************************************************
69 #if USE_TIME_STAMP
70 // Select the CTIMER number to use for timing.
71 // The entire 32-bit timer is used.
72 #define SELFTEST_TIMERNUM 0
73
74 // Timer configuration.
75 static am_hal_ctimer_config_t g_sContTimer = {
76 // Create 32-bit timer
77 1,
78
79 // Set up TimerA.
80 (AM_HAL_CTIMER_FN_CONTINUOUS | AM_HAL_CTIMER_HFRC_12MHZ),
81
82 // Set up Timer0B.
83 0};
84
85 #endif // USE_TIME_STAMP
86
87 // ARPIT TODO : Implement low power configuration
custom_am_bsp_low_power_init(void)88 void custom_am_bsp_low_power_init(void) {
89 #if USE_MAYA
90 // Make sure SWO/ITM/TPIU is disabled.
91 // SBL may not get it completely shut down.
92 am_bsp_itm_printf_disable();
93 #else
94 // Initialize the printf interface for AP3B ITM/SWO output.
95 am_bsp_itm_printf_enable();
96 #endif
97
98 // Initialize for low power in the power control block
99 // am_hal_pwrctrl_low_power_init();
100
101 // Run the RTC off the LFRC.
102 // am_hal_rtc_osc_select(AM_HAL_RTC_OSC_LFRC);
103
104 // Stop the XTAL.
105 // am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_XTAL_STOP, 0);
106
107 // Disable the RTC.
108 // am_hal_rtc_osc_disable();
109
110 #ifdef AM_BSP_NUM_LEDS
111 //
112 // Initialize the LEDs.
113 // On the apollo3_evb, when the GPIO outputs are disabled (the default at
114 // power up), the FET gates are floating and
115 // partially illuminating the LEDs.
116 //
117 uint32_t ux, ui32GPIONumber;
118 for (ux = 0; ux < AM_BSP_NUM_LEDS; ux++) {
119 ui32GPIONumber = am_bsp_psLEDs[ux].ui32GPIONumber;
120
121 //
122 // Configure the pin as a push-pull GPIO output
123 // (aka AM_DEVICES_LED_POL_DIRECT_DRIVE_M).
124 //
125 am_hal_gpio_pinconfig(ui32GPIONumber, g_AM_HAL_GPIO_OUTPUT);
126
127 //
128 // Turn off the LED.
129 //
130 am_hal_gpio_state_write(ui32GPIONumber,
131 AM_HAL_GPIO_OUTPUT_TRISTATE_DISABLE);
132 am_hal_gpio_state_write(ui32GPIONumber, AM_HAL_GPIO_OUTPUT_CLEAR);
133 }
134 #endif // AM_BSP_NUM_LEDS
135
136 } // am_bsp_low_power_init()
137
138 // Make sure the CPU is running as fast as possible.
enable_burst_mode(tflite::ErrorReporter * error_reporter)139 void enable_burst_mode(tflite::ErrorReporter* error_reporter) {
140 am_hal_burst_avail_e eBurstModeAvailable;
141 am_hal_burst_mode_e eBurstMode;
142
143 // Check that the Burst Feature is available.
144 if (AM_HAL_STATUS_SUCCESS ==
145 am_hal_burst_mode_initialize(&eBurstModeAvailable)) {
146 if (AM_HAL_BURST_AVAIL == eBurstModeAvailable) {
147 TF_LITE_REPORT_ERROR(error_reporter, "Apollo3 Burst Mode is Available\n");
148 } else {
149 TF_LITE_REPORT_ERROR(error_reporter,
150 "Apollo3 Burst Mode is Not Available\n");
151 }
152 } else {
153 TF_LITE_REPORT_ERROR(error_reporter,
154 "Failed to Initialize for Burst Mode operation\n");
155 }
156
157 // Put the MCU into "Burst" mode.
158 if (AM_HAL_STATUS_SUCCESS == am_hal_burst_mode_enable(&eBurstMode)) {
159 if (AM_HAL_BURST_MODE == eBurstMode) {
160 TF_LITE_REPORT_ERROR(error_reporter,
161 "Apollo3 operating in Burst Mode (96MHz)\n");
162 }
163 } else {
164 TF_LITE_REPORT_ERROR(error_reporter,
165 "Failed to Enable Burst Mode operation\n");
166 }
167 }
168
169 } // namespace
170
171 //*****************************************************************************
172 // PDM configuration information.
173 //*****************************************************************************
174 am_hal_pdm_config_t g_sPdmConfig = {
175 .eClkDivider = AM_HAL_PDM_MCLKDIV_1,
176 .eLeftGain = AM_HAL_PDM_GAIN_P165DB,
177 .eRightGain = AM_HAL_PDM_GAIN_P165DB,
178 .ui32DecimationRate =
179 48, // OSR = 1500/16 = 96 = 2*SINCRATE --> SINC_RATE = 48
180 .bHighPassEnable = 1,
181 .ui32HighPassCutoff = 0x2,
182 .ePDMClkSpeed = AM_HAL_PDM_CLK_1_5MHZ,
183 .bInvertI2SBCLK = 0,
184 .ePDMClkSource = AM_HAL_PDM_INTERNAL_CLK,
185 .bPDMSampleDelay = 0,
186 .bDataPacking = 0,
187 .ePCMChannels = AM_HAL_PDM_CHANNEL_LEFT,
188 .ui32GainChangeDelay = 1,
189 .bI2SEnable = 0,
190 .bSoftMute = 0,
191 .bLRSwap = 0,
192 };
193
194 //*****************************************************************************
195 // PDM initialization.
196 //*****************************************************************************
pdm_init(void)197 extern "C" void pdm_init(void) {
198 //
199 // Initialize, power-up, and configure the PDM.
200 //
201 am_hal_pdm_initialize(0, &g_pdm_handle);
202 am_hal_pdm_power_control(g_pdm_handle, AM_HAL_PDM_POWER_ON, false);
203 am_hal_pdm_configure(g_pdm_handle, &g_sPdmConfig);
204
205 //
206 // Configure the necessary pins.
207 //
208 am_hal_gpio_pincfg_t sPinCfg = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
209
210 //
211 // AP3B EVB w/ PDM MIC in slot3
212 //
213 sPinCfg.uFuncSel = AM_HAL_PIN_12_PDMCLK;
214 am_hal_gpio_pinconfig(12, sPinCfg);
215
216 sPinCfg.uFuncSel = AM_HAL_PIN_11_PDMDATA;
217 am_hal_gpio_pinconfig(11, sPinCfg);
218
219 //
220 // Configure and enable PDM interrupts (set up to trigger on DMA
221 // completion).
222 //
223 am_hal_pdm_interrupt_enable(g_pdm_handle,
224 (AM_HAL_PDM_INT_DERR | AM_HAL_PDM_INT_DCMP |
225 AM_HAL_PDM_INT_UNDFL | AM_HAL_PDM_INT_OVF));
226
227 NVIC_EnableIRQ(PDM_IRQn);
228
229 // Enable PDM
230 am_hal_pdm_enable(g_pdm_handle);
231 }
232
233 // Start the DMA fetch of PDM samples.
pdm_start_dma(tflite::ErrorReporter * error_reporter)234 void pdm_start_dma(tflite::ErrorReporter* error_reporter) {
235 // Configure DMA and target address.
236 am_hal_pdm_transfer_t sTransfer;
237
238 if (g_dma_destination_index == 0) {
239 sTransfer.ui32TargetAddr = (uint32_t)g_ui32PDMSampleBuffer0;
240 } else {
241 sTransfer.ui32TargetAddr = (uint32_t)g_ui32PDMSampleBuffer1;
242 }
243
244 sTransfer.ui32TotalCount = 4 * kPdmSampleBufferSize;
245 // PDM DMA count is in Bytes
246
247 // Start the data transfer.
248 if (AM_HAL_STATUS_SUCCESS != am_hal_pdm_dma_start(g_pdm_handle, &sTransfer)) {
249 TF_LITE_REPORT_ERROR(error_reporter, "Error - configuring PDM DMA failed.");
250 }
251
252 // Reset the PDM DMA flags.
253 g_pdm_dma_error = false;
254 }
255
256 #if USE_MAYA
power_down_sequence(void)257 extern "C" void power_down_sequence(void) {
258 am_hal_gpio_read_type_e eReadType;
259 eReadType = AM_HAL_GPIO_INPUT_READ;
260
261 // Reconfigure PDM Pins for low power
262 // Drive PDMCLK low so Mics go in standby mode of ~ 10 to 20uA each
263 am_hal_gpio_pinconfig(12, g_AM_HAL_GPIO_OUTPUT);
264 am_hal_gpio_state_write(12, AM_HAL_GPIO_OUTPUT_SET);
265
266 // Disable PDMDATA pin so no input buffer leakage current from floating pin
267 am_hal_gpio_pinconfig(11, g_AM_HAL_GPIO_DISABLE);
268
269 // Disable PDM
270 am_hal_pdm_disable(g_pdm_handle);
271 am_hal_pdm_power_control(g_pdm_handle, AM_HAL_PDM_POWER_OFF, false);
272 am_hal_interrupt_master_disable();
273
274 am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(AM_BSP_GPIO_BUTTON0));
275 am_hal_gpio_interrupt_disable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_BUTTON0));
276 am_util_delay_ms(200); // Debounce Delay
277 am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(AM_BSP_GPIO_BUTTON0));
278 am_hal_gpio_interrupt_enable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_BUTTON0));
279
280 for (int ix = 0; ix < AM_BSP_NUM_LEDS; ix++) {
281 am_devices_led_off(am_bsp_psLEDs, ix);
282 }
283
284 am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
285 // Apollo3 will be < 3uA in deep sleep
286
287 am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOR, 0);
288 // Use Reset to perform clean power-on from sleep
289 }
290
291 //*****************************************************************************
292 //
293 // GPIO ISR
294 //
295 //*****************************************************************************
am_gpio_isr(void)296 extern "C" void am_gpio_isr(void) {
297 uint64_t ui64Status;
298 // Read and clear the GPIO interrupt status then service the interrupts.
299 am_hal_gpio_interrupt_status_get(false, &ui64Status);
300 am_hal_gpio_interrupt_clear(ui64Status);
301 am_hal_gpio_interrupt_service(ui64Status);
302 }
303
power_button_handler(void)304 extern "C" void power_button_handler(void) { g_PowerOff = 1; }
305
306 #endif // USE_MAYA
307
308 // Interrupt handler for the PDM.
am_pdm0_isr(void)309 extern "C" void am_pdm0_isr(void) {
310 uint32_t ui32IntMask;
311
312 // Read the interrupt status.
313 if (AM_HAL_STATUS_SUCCESS !=
314 am_hal_pdm_interrupt_status_get(g_pdm_handle, &ui32IntMask, false)) {
315 TF_LITE_REPORT_ERROR(g_pdm_dma_error_reporter,
316 "Error reading PDM0 interrupt status.");
317 }
318
319 // Clear the PDM interrupt.
320 if (AM_HAL_STATUS_SUCCESS !=
321 am_hal_pdm_interrupt_clear(g_pdm_handle, ui32IntMask)) {
322 TF_LITE_REPORT_ERROR(g_pdm_dma_error_reporter,
323 "Error clearing PDM interrupt status.");
324 }
325
326 #if USE_DEBUG_GPIO
327 // DEBUG : GPIO flag polling.
328 am_hal_gpio_state_write(31, AM_HAL_GPIO_OUTPUT_SET); // Slot1 AN pin
329 #endif
330
331 // If we got a DMA complete, set the flag.
332 if (ui32IntMask & AM_HAL_PDM_INT_OVF) {
333 am_util_stdio_printf("\n%s\n", "\nPDM ISR OVF.");
334 }
335 if (ui32IntMask & AM_HAL_PDM_INT_UNDFL) {
336 am_util_stdio_printf("\n%s\n", "\nPDM ISR UNDLF.");
337 }
338 if (ui32IntMask & AM_HAL_PDM_INT_DCMP) {
339 uint32_t* source_buffer;
340 if (g_dma_destination_index == 0) {
341 source_buffer = g_ui32PDMSampleBuffer0;
342 g_dma_destination_index = 1;
343 } else {
344 source_buffer = g_ui32PDMSampleBuffer1;
345 g_dma_destination_index = 0;
346 }
347 pdm_start_dma(g_pdm_dma_error_reporter);
348
349 uint32_t slotCount = 0;
350 for (uint32_t indi = 0; indi < kPdmSampleBufferSize; indi++) {
351 g_audio_capture_buffer[g_audio_capture_buffer_start] =
352 source_buffer[indi];
353 g_audio_capture_buffer_start =
354 (g_audio_capture_buffer_start + 1) % kAudioCaptureBufferSize;
355 slotCount++;
356 }
357
358 g_total_samples_captured += slotCount;
359 g_latest_audio_timestamp =
360 (g_total_samples_captured / (kAudioSampleFrequency / 1000));
361 }
362
363 // If we got a DMA error, set the flag.
364 if (ui32IntMask & AM_HAL_PDM_INT_DERR) {
365 g_pdm_dma_error = true;
366 }
367
368 #if USE_DEBUG_GPIO
369 // DEBUG : GPIO flag polling.
370 am_hal_gpio_state_write(31, AM_HAL_GPIO_OUTPUT_CLEAR); // Slot1 AN pin
371 #endif
372 }
373
InitAudioRecording(tflite::ErrorReporter * error_reporter)374 TfLiteStatus InitAudioRecording(tflite::ErrorReporter* error_reporter) {
375 // Set the clock frequency.
376 if (AM_HAL_STATUS_SUCCESS !=
377 am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0)) {
378 TF_LITE_REPORT_ERROR(error_reporter,
379 "Error - configuring the system clock failed.");
380 return kTfLiteError;
381 }
382
383 // Individually select elements of am_bsp_low_power_init
384 custom_am_bsp_low_power_init();
385
386 // Set the default cache configuration and enable it.
387 if (AM_HAL_STATUS_SUCCESS !=
388 am_hal_cachectrl_config(&am_hal_cachectrl_defaults)) {
389 TF_LITE_REPORT_ERROR(error_reporter,
390 "Error - configuring the system cache failed.");
391 return kTfLiteError;
392 }
393 if (AM_HAL_STATUS_SUCCESS != am_hal_cachectrl_enable()) {
394 TF_LITE_REPORT_ERROR(error_reporter,
395 "Error - enabling the system cache failed.");
396 return kTfLiteError;
397 }
398
399 // Configure Flash wait states.
400 CACHECTRL->FLASHCFG_b.RD_WAIT = 1; // Default is 3
401 CACHECTRL->FLASHCFG_b.SEDELAY = 6; // Default is 7
402 CACHECTRL->FLASHCFG_b.LPM_RD_WAIT = 5; // Default is 8
403
404 // Enable cache sleep states.
405 uint32_t ui32LPMMode = CACHECTRL_FLASHCFG_LPMMODE_STANDBY;
406 if (am_hal_cachectrl_control(AM_HAL_CACHECTRL_CONTROL_LPMMODE_SET,
407 &ui32LPMMode)) {
408 TF_LITE_REPORT_ERROR(error_reporter,
409 "Error - enabling cache sleep state failed.");
410 }
411
412 // Enable Instruction & Data pre-fetching.
413 MCUCTRL->SRAMMODE_b.DPREFETCH = 1;
414 MCUCTRL->SRAMMODE_b.DPREFETCH_CACHE = 1;
415 MCUCTRL->SRAMMODE_b.IPREFETCH = 1;
416 MCUCTRL->SRAMMODE_b.IPREFETCH_CACHE = 1;
417
418 // Enable the floating point module, and configure the core for lazy stacking.
419 am_hal_sysctrl_fpu_enable();
420 am_hal_sysctrl_fpu_stacking_enable(true);
421 TF_LITE_REPORT_ERROR(error_reporter, "FPU Enabled.");
422
423 // Configure the LEDs.
424 am_devices_led_array_init(am_bsp_psLEDs, AM_BSP_NUM_LEDS);
425 // Turn the LEDs off
426 for (int ix = 0; ix < AM_BSP_NUM_LEDS; ix++) {
427 am_devices_led_off(am_bsp_psLEDs, ix);
428 }
429
430 #if USE_MAYA
431 // Configure Power Button
432 am_hal_gpio_pinconfig(AM_BSP_GPIO_BUTTON_POWER, g_AM_BSP_GPIO_BUTTON_POWER);
433
434 // Clear and Enable the GPIO Interrupt (write to clear).
435 am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(AM_BSP_GPIO_BUTTON_POWER));
436 am_hal_gpio_interrupt_register(AM_BSP_GPIO_BUTTON_POWER,
437 power_button_handler);
438 am_hal_gpio_interrupt_enable(AM_HAL_GPIO_BIT(AM_BSP_GPIO_BUTTON_POWER));
439
440 // Enable GPIO interrupts to the NVIC.
441 NVIC_EnableIRQ(GPIO_IRQn);
442 #endif // USE_MAYA
443
444 #if USE_DEBUG_GPIO
445 // DEBUG : GPIO flag polling.
446 // Configure the GPIOs for flag polling.
447 am_hal_gpio_pinconfig(31, g_AM_HAL_GPIO_OUTPUT); // Slot1 AN pin
448 am_hal_gpio_pinconfig(39, g_AM_HAL_GPIO_OUTPUT); // Slot1 RST pin
449 am_hal_gpio_pinconfig(44, g_AM_HAL_GPIO_OUTPUT); // Slot1 CS pin
450 am_hal_gpio_pinconfig(48, g_AM_HAL_GPIO_OUTPUT); // Slot1 PWM pin
451
452 am_hal_gpio_pinconfig(32, g_AM_HAL_GPIO_OUTPUT); // Slot2 AN pin
453 am_hal_gpio_pinconfig(46, g_AM_HAL_GPIO_OUTPUT); // Slot2 RST pin
454 am_hal_gpio_pinconfig(42, g_AM_HAL_GPIO_OUTPUT); // Slot2 CS pin
455 am_hal_gpio_pinconfig(47, g_AM_HAL_GPIO_OUTPUT); // Slot2 PWM pin
456 #endif
457
458 // Ensure the CPU is running as fast as possible.
459 // enable_burst_mode(error_reporter);
460
461 #if USE_TIME_STAMP
462 //
463 // Set up and start the timer.
464 //
465 am_hal_ctimer_stop(SELFTEST_TIMERNUM, AM_HAL_CTIMER_BOTH);
466 am_hal_ctimer_clear(SELFTEST_TIMERNUM, AM_HAL_CTIMER_BOTH);
467 am_hal_ctimer_config(SELFTEST_TIMERNUM, &g_sContTimer);
468 am_hal_ctimer_start(SELFTEST_TIMERNUM, AM_HAL_CTIMER_TIMERA);
469 #endif // USE_TIME_STAMP
470
471 // Configure, turn on PDM
472 g_pdm_dma_error_reporter = error_reporter;
473 pdm_init();
474 am_hal_interrupt_master_enable();
475 am_hal_pdm_fifo_flush(g_pdm_handle);
476 // Trigger the PDM DMA for the first time manually.
477 pdm_start_dma(error_reporter);
478
479 TF_LITE_REPORT_ERROR(error_reporter, "\nPDM DMA Threshold = %d",
480 PDMn(0)->FIFOTHR);
481
482 // Turn on LED 0 to indicate PDM initialized
483 am_devices_led_on(am_bsp_psLEDs, 0);
484
485 return kTfLiteOk;
486 }
487
GetAudioSamples(tflite::ErrorReporter * error_reporter,int start_ms,int duration_ms,int * audio_samples_size,int16_t ** audio_samples)488 TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter,
489 int start_ms, int duration_ms,
490 int* audio_samples_size, int16_t** audio_samples) {
491 #if USE_MAYA
492 if (g_PowerOff) {
493 power_down_sequence();
494 }
495 #endif // USE_MAYA
496
497 if (!g_is_audio_initialized) {
498 TfLiteStatus init_status = InitAudioRecording(error_reporter);
499 if (init_status != kTfLiteOk) {
500 return init_status;
501 }
502 g_is_audio_initialized = true;
503 }
504
505 #if USE_DEBUG_GPIO
506 // DEBUG : GPIO flag polling.
507 am_hal_gpio_state_write(39, AM_HAL_GPIO_OUTPUT_SET); // Slot1 RST pin
508 #endif
509
510 // This should only be called when the main thread notices that the latest
511 // audio sample data timestamp has changed, so that there's new data in the
512 // capture ring buffer. The ring buffer will eventually wrap around and
513 // overwrite the data, but the assumption is that the main thread is checking
514 // often enough and the buffer is large enough that this call will be made
515 // before that happens.
516 const int start_offset =
517 (start_ms < 0) ? 0 : start_ms * (kAudioSampleFrequency / 1000);
518 const int duration_sample_count =
519 duration_ms * (kAudioSampleFrequency / 1000);
520 for (int i = 0; i < duration_sample_count; ++i) {
521 const int capture_index = (start_offset + i) % kAudioCaptureBufferSize;
522 g_audio_output_buffer[i] = g_audio_capture_buffer[capture_index];
523 }
524
525 *audio_samples_size = kMaxAudioSampleSize;
526 *audio_samples = g_audio_output_buffer;
527
528 #if USE_DEBUG_GPIO
529 // DEBUG : GPIO flag polling.
530 am_hal_gpio_state_write(39, AM_HAL_GPIO_OUTPUT_CLEAR); // Slot1 RST pin
531 #endif
532
533 return kTfLiteOk;
534 }
535
LatestAudioTimestamp()536 int32_t LatestAudioTimestamp() { return g_latest_audio_timestamp; }
537