cruelfox 发表于 2021-2-23 00:26

【ESP32-Korvo测评】(3)ESP-Skainet工程的编译

<p>  既然 ESP-Korvo 具有语音处理的硬件,自然少不了官方的软件支持了。这次评测的重点是乐鑫提供的 ESP-Skainet 这个开放软件包,它提供了若干音频和语音识别的API支持,也包含了这个开发板的硬件驱动库。<br />
  我是从 github 上把 esp-skainet 克隆到本地电脑上的。(也许还有其它更便捷的下载方式)因为 ESP-Skainet 自带了某一个版本的 ESP-IDF, 所以就不用单独下载 IDF 了。什么是 ESP-IDF? 这是 ESP32 的软件开发框架,包括了很多部件,并不是一个单纯的硬件支持库。比如说,IDF 提供了 bootloader, 做了比 STM32 MCU 启动代码多很多的工作;比如说,IDF 底层有 FreeRTOS, 编写一个应用的入口函数是 app_main() 而不是 main(). IDF给我的感觉是更接近操作系统的一个东西,把ESP32启动过程隐藏了,能想得到的BLE、网络支持、文件系统支持它都有。如果不用 IDF 的话对 ESP32 开发就很难下手(乐鑫说:我们把框架都给你搭好了,你就用吧&hellip;&hellip;)<br />
  有了 ESP-IDF 就可以开发 ESP32 了,那么用什么编译呢?自然需要 Xtensa 处理器的 gcc 编译工具,可以从乐鑫的网站上下载到。想折腾,自己用 GCC 的源代码编译也是可以的。但只有编译器还不够,因为 IDF 每个工程也需要配置,就绕不开使用使用乐鑫的 Python 脚本和辅助程序。这跟开发 STM32/LPC/ATSAM...都很不一样是不是?也难怪,因为 IDF 实在复杂太多了。如果是 Linux 系统,软件工具的问题就看系统上装的够不够使,如果是 Windows 系统呢?需要一个类似 Linux 下的操作环境,比如 cygwin, msys 然后使用经过移植的软件。乐鑫又给了金点子:不好装吗?我给你准备了一套,下载去就能用咯!<br />
  我这次使用的是直接下过来的 esp32_win32_msys2_environment_and_esp2020r2_toolchain-20200601.zip 这个压缩包,里面有 msys2 环境下的软件,和 Xtensa 编译工具。直接解压缩就可以使用了,缺点嘛,就是对 windows xp 不友好,这是 msys2 版本的问题。</p>

<p>  启动 msys2 终端程序(mingw32.exe),试着编译一下 esp-skainet 里面 examples/get_started 这个工程。因为已存在 Makefile, 就直接 make 好啦。</p>

<pre>
<code class="language-makefile">#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#

PROJECT_NAME := get_started
EXTRA_COMPONENT_DIRS += ../../components/

include $(IDF_PATH)/make/project.mk</code></pre>

<p>  这个 Makefile 包含了 IDF 里面实际用的编译指令,所以要设置一下 IDF 的路径:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="font-family:Courier;"><strong>export IDF_PATH=../../esp-idf</strong></span><br />
  然后再 make 就一路编译下去了&hellip;&hellip;居然编译了很久,可不像一个MCU的工程。结束后在生成的 build 目录下可以发现有超过百兆字节的文件。我还没有配置 IDF 组件, 用的 esp-skainet 原先默认的了。如果想配置,那么执行 <strong><span style="font-family:Courier;">make menuconfig</span></strong>, 出现跟配置 linux 内核相仿的字符界面:<br />
</p>

<p>  在编译完成后有如下的提示,说明怎么下载到板子:<br />
<span style="color:#8e44ad;"><em>To flash all build output, run &#39;make flash&#39; or:<br />
python /d/esp-skainet/esp-idf/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0x1000 /d/esp-skainet/examples/get_started/build/bootloader/bootloader.bin 0x10000 /d/esp-skainet/examples/get_started/build/get_started.bin 0x8000 /d/esp-skainet/examples/get_started/build/partitions.bin</em></span><br />
  要烧写的文件有三个:bootloader.bin, get_started.bin, partitions.bin<br />
  我使用连着板子的另一台机器来进行下载:<br />
</p>

<p>  复位之后运行正常,串口打印的内容和以前不同了。看来get_started例子启动了语音检测,那么就唤醒试试&mdash;&mdash;可以工作。<br />
</p>

<p>  看看 main.c 里面写了什么。主函数是 app_main()</p>

<pre>
<code class="language-cpp">void app_main()
{
    codec_init();
    rec_rb = rb_init(BUFFER_PROCESS, 8 * 1024, 1, NULL);
#ifdef CONFIG_ESP32_KORVO_V1_1_BOARD
    mase_rb = rb_init(BUFFER_PROCESS, 8 * 1024, 1, NULL);
#else
    ns_rb = rb_init(BUFFER_PROCESS, 8 * 1024, 1, NULL);
#endif
    agc_rb = rb_init(BUFFER_PROCESS, 8 * 1024, 1, NULL);

    model_iface_data_t *model_data = wakenet-&gt;create(model_coeff_getter, DET_MODE_90);
    model_data_mn = multinet-&gt;create(&amp;MULTINET_COEFF, 4000);

    xTaskCreatePinnedToCore(&amp;recsrcTask, "rec", 2 * 1024, NULL, 8, NULL, 1);
#ifdef CONFIG_ESP32_KORVO_V1_1_BOARD
    xTaskCreatePinnedToCore(&amp;maseTask, "mase", 2 * 1024, NULL, 8, NULL, 1);
#else
    xTaskCreatePinnedToCore(&amp;nsTask, "ns", 2 * 1024, NULL, 8, NULL, 1);
#endif
    xTaskCreatePinnedToCore(&amp;agcTask, "agc", 2 * 1024, NULL, 8, NULL, 1);
    xTaskCreatePinnedToCore(&amp;wakenetTask, "wakenet", 2 * 1024, (void*)model_data, 5, NULL, 0);

    printf("-----------awaits to be waken up-----------\n");
}</code></pre>

<p>  app_main() 做的是初始化和创建语音处理、识别有关的几个任务,然后就结束了。 在 wakenetTask 任务当中,接收语音并处理:</p>

<pre>
<code class="language-cpp">void wakenetTask(void *arg)
{
    model_iface_data_t *model_data = arg;
    int frequency = wakenet-&gt;get_samp_rate(model_data);
    int audio_chunksize = wakenet-&gt;get_samp_chunksize(model_data);
    int chunk_num = multinet-&gt;get_samp_chunknum(model_data_mn);
    printf("chunk_num = %d\n", chunk_num);
    int16_t *buffer = malloc(audio_chunksize * sizeof(int16_t));
    assert(buffer);
    int chunks = 0;
    int mn_chunks = 0;
    bool detect_flag = 0;

    while (1) {
      rb_read(agc_rb, (uint8_t *)buffer, audio_chunksize * sizeof(int16_t), portMAX_DELAY);
      if (detect_flag == 0) {
            int r = wakenet-&gt;detect(model_data, buffer);
            if (r) {
                float ms = (chunks * audio_chunksize * 1000.0) / frequency;
                printf("%.2f: %s DETECTED.\n", (float)ms / 1000.0, wakenet-&gt;get_word_name(model_data, r));
                detect_flag = 1;
                printf("-----------------LISTENING-----------------\n\n");
                rb_reset(rec_rb);
                rb_reset(ns_rb);
                rb_reset(agc_rb);
            }
      } else {
            int command_id = multinet-&gt;detect(model_data_mn, buffer);
            mn_chunks++;
            if (mn_chunks == chunk_num || command_id &gt; -1) {
                mn_chunks = 0;
                detect_flag = 0;
                if (command_id &gt; -1) {
                  speech_commands_action(command_id);
                } else {
                  printf("can not recognize any speech commands\n");
                }

                printf("\n-----------awaits to be waken up-----------\n");
                rb_reset(rec_rb);
                rb_reset(ns_rb);
                rb_reset(agc_rb);
            }
      }
      chunks++;
    }
    vTaskDelete(NULL);
}</code></pre>

<p><br />
  代码和串口打印的内容的确能对应上。后面就可以尝试改代码了。</p>

freebsder 发表于 2021-2-25 22:27

<p>谢谢分享!</p>

Jacktang 发表于 2021-3-4 21:34

<p>测试工具软件都可以从乐鑫的网站上下载,乐鑫的生态系统好</p>
页: [1]
查看完整版本: 【ESP32-Korvo测评】(3)ESP-Skainet工程的编译