[doc] add emac Chapter

This commit is contained in:
jzlv 2021-09-30 15:10:02 +08:00
parent 6c5470d8de
commit 908102c0de
252 changed files with 5693 additions and 72 deletions

View file

@ -0,0 +1,93 @@
emac basic -- 发送 ARP 数据包
===============================
本 demo 基于 BL706 emac 实现通过以太网发送一个 ARP 裸数据包的例程,通过本例程可以确认 emac 以及 PHY 芯片的配置是否正确。
以太网 PHY 芯片这里使用的是 PHY8720
硬件准备
----------------
- 一块 BL706 ETH 开发板
- 一块 PHY 8720 模块
- 一个串口线
- 一根标准 5/6 类网线
硬件连接
----------------
本 demo 基于 BL706 ETH 开发板,将对应的功能引脚连接到 PHY8720 模块上,连接方式如下:
::
GPIO function GPIO pin
----------------------------------
RMII_CLK <--> GPIO0
RMII_TXD0 <--> GPIO1
RMII_TXD1 <--> GPIO2
RMII_RXD0 <--> GPIO7
RMII_RXD1 <--> GPIO8
RMII_MDC <--> GPIO18
RMII_MDIO <--> GPIO19
RMII_RXERR <--> GPIO20
RMII_TX_EN <--> GPIO21
RMII_RX_DV <--> GPIO22
接下来需要将 PHY8720 模块的 RJ-45 接口通过标准 5/6 类网线连接到与测试 PC 在同一局域网中的路由器或者交换机上。
构造 ARP 数据包
-------------------
通过查阅 ARP 协议可以知道 ARP 包的数据报文组织结构如下:
::
|dst mac|src mac|frame type|Hardware type|Protocol type|Hardware size|Protocol size|Opcode|src mac|src ip|dst mac|dst ip|
|6 Byte |6 Byte |2 Byte | 2 Byte | 2 Byte | 1 Byte | 1 Byte |2 Byte|6 Byte |4 Byte|6 Byte |4 Byte|
|<---------------------------------------------------- 42 Byte -------------------------------------------------------->|
因此按照上图所示数据结构,构造一个 ARP 数据包,交由 EMAC通过 MAC 层将数据发送出去即可,下面的数据报文中的 IP 和 MAC 地址是本机当前的测试环境下的信息,
如在不同网络环境下测试则需要自行修改下列数据帧结构,使其符合当前的测试环境网络,方可正确完成测试。
.. code-block:: c
:linenos:
static const uint8_t test_frame[42] = {
/* ARP reply to 192.168.1.3(b0:7b:25:00:89:53): 192.168.1.221 is at 18:b9:05:12:34:56 */
0xB0, 0x7B, 0x25, 0x00, 0x89, 0x53, // dst mac
0x18, 0xB9, 0x05, 0x12, 0x34, 0x56, // src mac
0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02, // arp reply
0x18, 0xB9, 0x05, 0x12, 0x34, 0x56, // src mac
0xc0, 0xa8, 0x01, 0xDD, // src ip
0xB0, 0x7B, 0x25, 0x00, 0x89, 0x53, // dst mac
0xc0, 0xa8, 0x01, 0x03 // dst ip
};
编译和下载
-----------------
- **命令行编译**
.. code-block:: bash
:linenos:
$ cd bl_mcu_sdk
$ make APP=emac_basic
- **烧录**
详见 :ref:`bl_dev_cube`
实验现象
-----------------
串口 log 信息:
.. figure:: img/emac_basic_arp_2.png
:alt:
以太网状态:
.. figure:: img/emac_basic_arp_1.png
:alt:

View file

@ -0,0 +1,90 @@
http server -- 网页服务器
============================
HTTP 协议是 Hypertext Transfer Protocol超文本传输协议的缩写是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP 是万维网的数据通信的基础。
本 demo 主要是在 BL706 上基于 LwIP 协议栈,实现一个 HTTP 服务器,在 BL706 上部署了一个简单的网页,然后我们可以通过浏览器去访问 BL706 上的网页。
硬件准备
----------------
- 一块 BL706 ETH 开发板
- 一块 PHY 8720 模块
- 一个串口线
- 一根标准 5/6 类网线
硬件连接
----------------
本 demo 基于 BL706 ETH 开发板,将对应的功能引脚连接到 PHY8720 模块上,连接方式如下:
::
GPIO function GPIO pin
----------------------------------
RMII_CLK <--> GPIO0
RMII_TXD0 <--> GPIO1
RMII_TXD1 <--> GPIO2
RMII_RXD0 <--> GPIO7
RMII_RXD1 <--> GPIO8
RMII_MDC <--> GPIO18
RMII_MDIO <--> GPIO19
RMII_RXERR <--> GPIO20
RMII_TX_EN <--> GPIO21
RMII_RX_DV <--> GPIO22
接下来需要将 PHY8720 模块的 RJ-45 接口通过标准 5/6 类网线连接到与测试 PC 在同一局域网中的路由器或者交换机上。
生成 Web 网页及 LwIP 协议栈配置
---------------------------------
Web demo 的源码存放在 ``examples\emac\lwip_http_server\web_demo\pages`` 目录下,网页设计好后,可以使用 ``web_demo`` 目录下的 ``makefsdata.exe`` 工具将网页翻译成 LwIP 协议栈能够解析的文件格式,
在该目录下还有一个 ``makefsdata.bat`` 脚本,该脚本执行后会将 ``pages`` 目录下的 web 网页生成一个 ``fsdata_custom.c`` 文件;
将输出的 ``fsdata_custom.c`` 文件,放到 ``components\lwip\src\apps\http`` 目录下,然后在 ``components/lwip/lwipopts.h`` 文件中,使能 ``HTTPD_USE_CUSTOM_FSDATA`` 宏定义。
注:由于当前测试例程 local ip 地址采用静态 IP 配置进行的测试,如需修改可在 main.c 中进行相应的修改,也可直接使能 LWIP 的 DHCP 功能自动获取 IP 配置。
.. code-block:: c
:linenos:
#define LWIP_TCP 1
#define TCP_TTL 255
#define HTTPD_USE_CUSTOM_FSDATA 1
编译和下载
-------------------
- **命令行编译**
.. code-block:: bash
:linenos:
$ cd bl_mcu_sdk
$ make APP=lwip_http_server
- **烧录**
详见 :ref:`bl_dev_cube`
实验现象
-----------
编译完成后,烧写到芯片正确运行后,打开浏览器访问 BL706 相应的 IP 地址,即可看到一个测试网页。
串口 log 信息:
.. figure:: img/emac_http_1.png
:alt:
.. figure:: img/emac_http_2.png
:alt:
使用 Wireshark 抓取网络数据包,我们可以看到 TCP 协议的 “握手” 过程,以及 HTTP 协议的请求和数据传输:
.. figure:: img/emac_http_3.png
:alt:

View file

@ -0,0 +1,248 @@
lwip iperf 网络性能测试
=============================
iPerf 是一个跨平台的网络性能测试工具iPerf 可以测试 TCP 和 UDP 网络带宽性能和质量,但是 iPerf 是一个命令行形式的,对于使用者来说还不够直观,
这里我们使用 iPerf 的一个图形化版本测试程序 —— JPerfJPerf 简化了复杂的测试命令,并且测试结果可以图形化的实时显示出来。
JPerf 软件直接从互联网上搜索一个下载即可,本文主要介绍如何在 BL706 上实现一个 iPerf 测试线程BL706 作为服务端实时监听客户端PC Jperf 上位机)的连接和发送的数据。
这里主要测试 BL706 TCP 的最大接收速度,其他测试同理。
硬件准备
----------------
- 一块 BL706 ETH 开发板
- 一块 PHY 8720 模块
- 一个串口线
- 一根标准 5/6 类网线
硬件连接
----------------
本 demo 基于 BL706 ETH 开发板,将对应的功能引脚连接到 PHY8720 模块上,连接方式如下:
::
GPIO function GPIO pin
----------------------------------
RMII_CLK <--> GPIO0
RMII_TXD0 <--> GPIO1
RMII_TXD1 <--> GPIO2
RMII_RXD0 <--> GPIO7
RMII_RXD1 <--> GPIO8
RMII_MDC <--> GPIO18
RMII_MDIO <--> GPIO19
RMII_RXERR <--> GPIO20
RMII_TX_EN <--> GPIO21
RMII_RX_DV <--> GPIO22
接下来需要将 PHY8720 模块的 RJ-45 接口通过标准 5/6 类网线连接到与测试 PC 在同一局域网中的路由器或者交换机上。
EMAC 和 LwIP 协议栈的配置
---------------------------
LwIP 协议栈的相关配置文件在 ``components/lwip/lwipopts.h`` 中,详细配置请阅读代码源文件
要测试 TCP 性能,那么必须要在改文件中使能 ``LWIP_TCP`` 宏定义,否则将会使用 LwIP 默认的配置,同时为了获得更好的 TCP 测试性能,还需要加大 ``TCP_SND_BUF````TCP_WND`` 以及 EMAC RX buf 深度等参数。
本 demo 测试时修改参数如下:
.. code-block:: c
:linenos:
#define MEMP_NUM_TCP_PCB_LISTEN 8
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_WND (8 * TCP_MSS)
#define LWIP_TCP 1
#define TCP_TTL 255
// emac tx 和 rx buf 的大小
#define ETH_RXBUFNB 10
#define ETH_TXBUFNB 2
iPerf 测试本地端口设置
-----------------------------
``examples\emac\lwip_iperf\iperf_server.h`` 文件中,通过修改宏定义即可修改测试端口号
注:由于当前测试例程 local ip 地址采用静态 IP 配置进行的测试,如需修改可在 main.c 中进行相应的修改,也可直接使能 LWIP 的 DHCP 功能自动获取 IP 配置。
.. code-block:: c
:linenos:
#define IPERF_SERVER_PORT (3365)
编译和下载
-------------------
- **命令行编译**
.. code-block:: bash
:linenos:
$ cd bl_mcu_sdk
$ make APP=lwip_iperf
- **烧录**
详见 :ref:`bl_dev_cube`
实验现象
-----------
编译完成后,烧写到芯片正确运行后,可以通过配置的测试端口访问芯片。
打开 JPerf 软件开始进行 TCP 性能测试,具体配置如下图,设置好后点击 ``Run IPerf`` 即可。
串口 log 信息:
.. figure:: img/emac_iperf_2.png
:alt:
JPerf 窗口状态:
.. figure:: img/emac_iperf_1.png
:alt:
以太网状态:
.. figure:: img/emac_iperf_3.png
:alt:
UDP 性能测试
--------------
UDP 性能测试,需要使用 ``bl_mcu_sdk/examples/emac/lwip_udp`` 的例程,使用例程的默认代码即可测试 UDP 收发全双工的性能,编译测试请参考 :ref:`eth_udp_echo` 部分教程;
将代码正确编译下载到芯片后,即可通过 JPerf 软件测试 UDP 性能,具体测试配置及性能如下图,设置好后点击 ``Run IPerf`` 即可。
串口 log 信息:
.. figure:: img/emac_udp_3.png
:alt:
JPerf 窗口状态:
.. figure:: img/emac_iperf_4.png
:alt:
以太网状态:
.. figure:: img/emac_iperf_5.png
:alt:
Wireshark 抓包数据:
.. figure:: img/emac_iperf_6.png
:alt:
IPerf 测试结果
------------------
下表是在实验环境下测试的 BL706 运行 FreeRTOS + Lwip 网络协议栈的以太网性能
.. list-table::
:widths: 30 30 30 30 30 30 30
:header-rows: 1
* - 协议类型
- API 接口
- TX(发送速度)
- RX(接收速度)
- TX num
- RX num
- 备注
* - ARP send
- emac tx API
- 69 Mbps
- ——
- 5
- 5
- NO lwip,NO OS
* - UDP send
- lwip raw API
- 50 Mbps
- ——
- 3
- 3
- lwip,FreeRTOS,TX only
* - UDP Full-duplex
- lwip raw API
- 34 Mbps
- 40 Mbps
- 3
- 3
- lwip,FreeRTOS,Full-duplex
* - UDP send
- lwip netconn API
- 48 Mpbs
- ——
- 3
- 3
- lwip,FreeRTOS,TX only
* - UDP Full-duplex
- lwip netconn API
- 23 Mpbs
- 28 Mpbs
- 5
- 5
- lwip,FreeRTOS,Full-duplex
* - UDP send
- lwip socket API
- 47 Mpbs
- ——
- 3
- 3
- lwip,FreeRTOS,TX only
* - UDP Full-duplex
- lwip socket API
- 14.5 Mpbs
- 25 Mbps
- 5
- 5
- lwip,FreeRTOS,Full-duplex
* - TCP send
- lwip raw API
- 24 Mbps
- ——
- 5
- 5
- lwip,FreeRTOS,TX only,modify TCP_WND、TCP_SEND_BUF eg.
* - TCP recv
- lwip raw API
- ——
- 38 Mbps
- 2
- 10
- lwip,FreeRTOS,RX only,modify TCP_WND、TCP_SEND_BUF eg.
* - TCP send
- lwip netconn API
- 22 Mpbs
- ——
- 5
- 5
- lwip,FreeRTOS,TX only,modify TCP_WND、TCP_SEND_BUF eg.
* - TCP recv
- lwip netconn API
- ——
- 32 Mbps
- 2
- 10
- lwip,FreeRTOS,RX only,modify TCP_WND、TCP_SEND_BUF eg.
* - TCP send
- lwip socket API
- 20 Mbps
- ——
- 5
- 5
- lwip,FreeRTOS,TX only,modify TCP_WND、TCP_SEND_BUF eg.
* - TCP recv
- lwip socket API
- ——
- 15 Mbps
- 2
- 10
- lwip,FreeRTOS,RX only,modify TCP_WND、TCP_SEND_BUF eg.

View file

@ -0,0 +1,104 @@
TCP echo
===================
本 demo 基于 BL706 ETH 开发板,并基于 LwIP 轻量级网络协议栈,实现了一个 TCP 协议通信的例程。
以太网 PHY 芯片这里使用的是 PHY8720
硬件准备
----------------
- 一块 BL706 ETH 开发板
- 一块 PHY 8720 模块
- 一个串口线
- 一根标准 5/6 类网线
硬件连接
----------------
本 demo 基于 BL706 ETH 开发板,将对应的功能引脚连接到 PHY8720 模块上,连接方式如下:
::
GPIO function GPIO pin
----------------------------------
RMII_CLK <--> GPIO0
RMII_TXD0 <--> GPIO1
RMII_TXD1 <--> GPIO2
RMII_RXD0 <--> GPIO7
RMII_RXD1 <--> GPIO8
RMII_MDC <--> GPIO18
RMII_MDIO <--> GPIO19
RMII_RXERR <--> GPIO20
RMII_TX_EN <--> GPIO21
RMII_RX_DV <--> GPIO22
接下来需要将 PHY8720 模块的 RJ-45 接口通过标准 5/6 类网线连接到与测试 PC 在同一局域网中的路由器或者交换机上。
LwIP 协议栈的配置
-----------------------
LwIP 协议栈的相关配置文件在 ``components/lwip/lwipopts.h`` 中,详细配置请阅读代码源文件
如果要使用 TCP 相关功能,需要在文件中使能 LWIP_TCP 宏定义,否则将会使用 LwIP 默认的配置
.. code-block:: c
:linenos:
/* ---------- TCP options ---------- */
#define LWIP_TCP 1
#define TCP_TTL 255
TCP 测试本地端口设置
-----------------------------
``examples\emac\lwip_tcp\tcp_server.h`` 文件中,通过修改宏定义即可修改测试端口号
注:由于当前测试例程使用静态 IP 配置进行的测试,如需修改可在 main.c 中进行相应的修改,也可直接使能 LWIP 的 DHCP 功能自动获取 IP 配置。
.. code-block:: c
:linenos:
#define TCP_SERVER_TEST_PORT (3365)
编译和下载
-------------------
- **命令行编译**
.. code-block:: bash
:linenos:
$ cd bl_mcu_sdk
$ make APP=lwip_tcp
- **烧录**
详见 :ref:`bl_dev_cube`
实验现象
-----------
编译完成后,烧写到芯片正确运行后,可以通过配置的测试端口访问芯片。
串口 log 信息:
.. figure:: img/emac_tcp_2.png
:alt:
.. figure:: img/emac_tcp_1.png
:alt:
使用 Wireshark 抓取网络数据包,可以看到 TCP 协议连接的三次 “握手” 过程,以及传输的数据:
.. figure:: img/emac_tcp_3.png
:alt:
断开连接后,通过 Wireshark 抓取网络数据包,也可以观察到 TCP 协议断开连接的四次 “挥手” 过程,以及传输的数据:
.. figure:: img/emac_tcp_4.png
:alt:

View file

@ -0,0 +1,105 @@
.. _eth_udp_echo:
UDP echo
==================
本 demo 基于 BL706 ETH 开发板,并基于 LwIP 轻量级网络协议栈,实现了一个 UDP 协议通信的例程。
以太网 PHY 芯片这里使用的是 PHY8720
硬件准备
----------------
- 一块 BL706 ETH 开发板
- 一块 PHY 8720 模块
- 一个串口线
- 一根标准 5/6 类网线
硬件连接
----------------
本 demo 基于 BL706 ETH 开发板,将对应的功能引脚连接到 PHY8720 模块上,连接方式如下:
::
GPIO function GPIO pin
----------------------------------
RMII_CLK <--> GPIO0
RMII_TXD0 <--> GPIO1
RMII_TXD1 <--> GPIO2
RMII_RXD0 <--> GPIO7
RMII_RXD1 <--> GPIO8
RMII_MDC <--> GPIO18
RMII_MDIO <--> GPIO19
RMII_RXERR <--> GPIO20
RMII_TX_EN <--> GPIO21
RMII_RX_DV <--> GPIO22
接下来需要将 PHY8720 模块的 RJ-45 接口通过标准 5/6 类网线连接到与测试 PC 在同一局域网中的路由器或者交换机上。
LwIP 协议栈的配置
-----------------------
LwIP 协议栈的相关配置文件在 ``components/lwip/lwipopts.h`` 中,详细配置请阅读代码源文件
如果要使用 UDP 相关功能,需要在文件中使能 LWIP_UDP 宏定义,否则将会使用 LwIP 默认的配置
.. code-block:: c
:linenos:
/* ---------- UDP options ---------- */
#define LWIP_UDP 1
#define UDP_TTL 255
UDP 测试目标 IP 及端口设置
----------------------------
``examples\emac\lwip_udp\udp_echo.h`` 文件中,通过修改宏定义即可修改不同测试主机 IP 及端口信息
注:由于当前测试例程 local ip 地址采用静态 IP 配置进行的测试,如需修改可在 main.c 中进行相应的修改,也可直接使能 LWIP 的 DHCP 功能自动获取 IP 配置。
.. code-block:: c
:linenos:
#define UDP_DST_IP0 (192)
#define UDP_DST_IP1 (168)
#define UDP_DST_IP2 (1)
#define UDP_DST_IP3 (3)
#define UDP_TEST_PORT (3365)
编译和下载
-------------------
- **命令行编译**
.. code-block:: bash
:linenos:
$ cd bl_mcu_sdk
$ make APP=lwip_udp
- **烧录**
详见 :ref:`bl_dev_cube`
实验现象
-----------
编译完成后,烧写到芯片正确运行后,可以通过配置的测试端口访问芯片。
串口 log 信息:
.. figure:: img/emac_udp_3.png
:alt:
.. figure:: img/emac_udp_2.png
:alt:
使用 Wireshark 抓包看到的数据包:
.. figure:: img/emac_udp_1.png
:alt:

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,21 @@
=================
EMAC 以太网应用
=================
BL70x 系列芯片拥有一个 EMAC 模块,该模块是一个兼容 `IEEE 802.3 <https://en.wikipedia.org/wiki/Ethernet_flow_control>`_ 的 10/100 Mbps 以太网 MAC。
EMAC 主要通过 RMII 接口连接到 PHY 芯片,以进行以太网通信。
在 BL706 上移植了 `LwIP <https://en.wikipedia.org/wiki/LwIP>`_ 网络协议栈, LwIP 是一个专为嵌入式系统设计的被广泛使用的开源的轻量级 TCP/IP 协议栈。
LwIP 协议栈可以在裸机中或在 RTOS 操作系统中运行,目前下列例程中使用 LwIP 时都是运行在 FreeRTOS 实时操作系统上的。
以下例程都是通过 RMII 接口连接到 PHY 8720 芯片进行通信的。
.. toctree::
:maxdepth: 1
ARP - 发送 ARP 裸包<eth_basic>
UDP - LwIP UDP echo<eth_udp_echo>
TCP - LwIP TCP echo<eth_tcp_echo>
HTTP - LwIP HTTP server<eth_http_server>
IPERF - LwIP iperf<eth_lwip_iperf>

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View file

@ -1,2 +1,279 @@
AUDIO - 麦克风
AUDIO - 声卡
====================
本 demo 将演示 USB Device AUDIO 类实现的一个声卡设备。
通过 usb 外设将其枚举为 AUDIO 类录音播音复合设备,从而可以播放与录制声音,支持双通道录音与播音, 无需专用软件即可播放与录制,如微信电话、播放音乐等。
在 USB 官方手册中,我们可以找到 USB 设备枚举符与端口描述符的定义, 根据定义配置正确的枚举符。
采集声音与播放声音需要用到音频子板模块,这里使用的是 ESP8388 模块
准备工具
-----------------------
BL706 AVB + ES8388音频模块 + windows 录音(任意用到音频的软件,如微信电话)
硬件连接
-----------------------------
本 demo 基于 BL706_AVB 开发板,连接方式如下
.. list-table::
:widths: 30 30
:header-rows: 1
* - GPIO function
- GPIO pin
* - CLK_OUT(MCLK)
- GPIO6
* - I2S_BCLK
- GPIO4
* - I2S_FS
- GPIO29
* - I2S_DO
- GPIO30
* - I2S_DI
- GPIO3
* - I2C_SCL
- GPIO16
* - I2C_SDA
- GPIO11
* - USB_DP
- GPIO7
* - USB_DM
- GPIO8
软件实现
-----------------------------
- USB 相关枚举符在 ``example/usb/usb_audio_mic_speaker/main.c`` 中定义
- 音频 I2S 配置与使用也在 ``example/usb/usb_audio_mic_speaker/main.c`` 中实现
- USB 协议栈 在 ``component/usb_stack/`` 中实现, 其中 ``component/usb_stack/class/audio/`` 中有对于 AUDIO 特定类设备的回调函数。
- E38388 子板的相关驱动在 bsp/bsp_common/es8388/中。
- 使用到的外设时钟源见 ``bsp/board/bl706_avb/clock_config.h``,如有改动,请自行修改:
.. code-block:: C
:linenos:
#define BSP_AUDIO_PLL_CLOCK_SOURCE ROOT_CLOCK_SOURCE_AUPLL_12288000_HZ
#define BSP_I2S_CLOCK_SOURCE ROOT_CLOCK_SOURCE_XCLK
#define BSP_I2S_CLOCK_DIV 0
#define BSP_I2C_CLOCK_SOURCE ROOT_CLOCK_SOURCE_BCLK
#define BSP_I2C_CLOCK_DIV 9
- 使用到的 GPIO 配置见 ``bsp/board/bl706_avb/pinmux_config.h``,如有改动,请自行修改:
.. code-block:: C
:linenos:
#define CONFIG_GPIO6_FUNC GPIO_FUN_CLK_OUT
#define CONFIG_GPIO3_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO4_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO29_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO30_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO11_FUNC GPIO_FUN_I2C
#define CONFIG_GPIO16_FUNC GPIO_FUN_I2C
#define CONFIG_GPIO7_FUNC GPIO_FUN_USB
#define CONFIG_GPIO8_FUNC GPIO_FUN_USB
- 使能外设宏定义,见 ``bsp/board/bl706_avb/peripheral_config.h`` ,外设配置可以保持默认,在程序中已经重新配置:
.. code-block:: C
:linenos:
#define BSP_USING_I2C0
#define BSP_USING_I2S0
#define BSP_USING_USB
#define BSP_USING_DMA0_CH2
#define BSP_USING_DMA0_CH3
#define BSP_USING_DMA0_CH4
``example/usb/usb_audio_mic_speaker/main.c`` 中, 前部分都是 USB 相关宏定义与 USB 枚举符定义, 包括设备枚举符与端口枚举符,
这些枚举符都根据 usb 官方文档而定义, 包含了usb硬件信息、设备类型、audio 参数、端口信息等关键信息,让主机得以正确识别与使用设备,例如:
例1官方文档规定的设备描述符
.. figure:: img/usb_audio_1.png
:alt:
程序中定义的设备描述符:
.. code-block:: C
:linenos:
* ------------------ AudioControl Interface ------------------ */
/* USB Microphone Standard AC Interface Descriptor */
0x09, /* bLength */
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
/* 09 byte*/
例2官方文档规定的麦克风端口描述符
.. figure:: img/usb_audio_2.png
:alt:
程序中定义的端口描述符, 其中一个描述符是控制端口, 一个是数据端口, 由其他描述符所定义的:
.. code-block:: C
:linenos:
/* --------------- AudioStreaming Interface --------------- */
/* USB Microphone Standard AS Interface Descriptor - Audio Streaming Zero Bandwith */
/* Interface 1, Alternate Setting 0 */
0x09, /* bLength */
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
/* 09 byte*/
/* USB Microphone Standard AS Interface Descriptor - Audio Streaming Operational */
/* Interface 1, Alternate Setting 1 */
0x09, /* bLength */
USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x01, /* bAlternateSetting */
0x01, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
/* 09 byte*/
还有其他多个端口枚举符, 其作用可以查阅 usb 官方文档, 其中有详细介绍含义。
USB 的协议流程控制程序在 ``component/usb_stack`` 中, 这是一个由博流开发的极为轻量级的 usb 协议栈。
协议栈使用描述符完成枚举过程, 向主机表达了设备类型与传输端口, 并根据 usb 协议规则控制后续的数据交互流程。
USB 协议栈可以参考 API 手册下的 USB Stack 章节的说明。
``example/usb/usb_audio_mic_speaker/main.c````audio_init()`` 函数,完成了对音频部分的初始化,
包括 ES8388 音频模块的初始化(I2C配置接口), I2S 接口的配置,使用了 DMA 来提高效率降低 cpu 负载。
具体作用请查看 ``基础外设例程`` 下的 ``I2S`` 示例,这里不再详细描述。
``main()`` 函数中,首先是调用了音频初始化函数,然后配置注册了 USB 相关端口,由于使用了 USB 同步传输,
还使用了一路 DMA 来发送数据, 进一步提升效率:
.. code-block:: C
:linenos:
bflb_platform_init(0);
audio_init();
usbd_desc_register(audio_descriptor);
usbd_audio_add_interface(&audio_class, &audio_control_intf);
usbd_audio_add_interface(&audio_class, &audio_stream_intf);
usbd_audio_add_interface(&audio_class, &audio_stream_intf2);
usbd_interface_add_endpoint(&audio_stream_intf, &audio_out_ep);
usb_fs = usb_dc_init();
if (usb_fs) {
device_control(usb_fs, DEVICE_CTRL_SET_INT, (void *)(USB_EP2_DATA_OUT_IT));
}
dma_register(DMA0_CH4_INDEX, "dma_ch4_usb_tx");
dma_ch4_usb_tx = device_find("dma_ch4_usb_tx");
if (dma_ch4_usb_tx) {
DMA_DEV(dma_ch4_usb_tx)->direction = DMA_MEMORY_TO_PERIPH;
DMA_DEV(dma_ch4_usb_tx)->transfer_mode = DMA_LLI_ONCE_MODE;
DMA_DEV(dma_ch4_usb_tx)->src_req = DMA_REQUEST_NONE;
DMA_DEV(dma_ch4_usb_tx)->dst_req = DMA_REQUEST_USB_EP1;
DMA_DEV(dma_ch4_usb_tx)->src_width = DMA_TRANSFER_WIDTH_8BIT;
DMA_DEV(dma_ch4_usb_tx)->dst_width = DMA_TRANSFER_WIDTH_8BIT;
DMA_DEV(dma_ch4_usb_tx)->src_burst_size = DMA_BURST_16BYTE;
DMA_DEV(dma_ch4_usb_tx)->dst_burst_size = DMA_BURST_1BYTE;
device_open(dma_ch4_usb_tx, 0);
// device_set_callback(dma_ch4_usb_tx, dma2_irq_callback);
// device_control(dma_ch4_usb_tx, DEVICE_CTRL_SET_INT, NULL);
device_control(usb_fs, DEVICE_CTRL_ATTACH_TX_DMA, dma_ch4_usb_tx);
device_control(usb_fs, DEVICE_CTRL_USB_DC_SET_TX_DMA, (void *)AUDIO_IN_EP);
}
之后启动 I2S 录音, 并根据 USB 状态来判断是否需要上传录制的音频数据; 同时判断是否有下传的需要播放的数据,如果有就使用 I2S 播放:
.. code-block:: C
:linenos:
/* i2s record start */
device_read(i2s, 0, record_data_buff[0], BUFF_SIZE);
while (1) {
/* Waiting for record data update */
if (record_updata_flag) {
if (!device_control(dma_ch4_usb_tx, DMA_CHANNEL_GET_STATUS, NULL)) {
device_write(usb_fs, AUDIO_IN_EP, record_data_buff[!record_buff_using_num], BUFF_SIZE);
record_updata_flag = 0;
record_buff_using_num = !record_buff_using_num;
device_read(i2s, 0, record_data_buff[record_buff_using_num], BUFF_SIZE);
}
}
if (play_updata_flag) {
device_control(dma_ch2_i2s_tx, DMA_CHANNEL_STOP, NULL);
play_buff_using_num = !play_buff_using_num;
device_write(i2s, 0, play_data_buff[play_buff_using_num], BUFF_SIZE);
play_updata_flag = 0;
usb_data_offset = 0;
}
}
编译和烧录
-----------------------------
- **CDK 编译**
打开项目中提供的工程文件usb_video.cdkproj
参照 :ref:`windows_cdk_quick_start` 的步骤编译下载即可
- **命令行编译**
.. code-block:: bash
:linenos:
$ cd <sdk_path>/bl_mcu_sdk
$ make BOARD=bl706_avb APP=usb_audio_mic_speaker
- **烧录**
详见 :ref:`bl_dev_cube`
实验现象
-----------------------------
如图, 将 ES8388 子板插入 BL706_AVB 板上, 并烧录程序后, 用 USB 线连接电脑:
.. figure:: img/usb_audio_3.png
:alt:
打开电脑声音设置窗口, 在输入与输入的设备中找到并选择 Bouffalo AUDIO DEMO 设备, 如下图:
.. figure:: img/usb_audio_4.png
:alt:
发出声音, 如敲击麦克风,可看见麦克风进度条跳动, 拖动输出的主音量,音量进度条也有跳动,
并且喇叭会发出提示音。如果找到设备但无法输入输出音频, 请检查 board 引脚与外设配置,和硬件连接。
打开任意音频软件, 如音乐播放器, 即可使用设备播放音乐。

View file

@ -47,6 +47,8 @@ BL706 AVB + GC0308摄像头模块 + windows 相机
CAM <--> GPIO30
CAM <--> GPIO31
.. note:: 注意 706 AVB FUN1 的跳冒不要接,默认连接到摄像头引脚,如果接了则连接到了 i2s codec
软件实现
-----------------------------

View file

@ -0,0 +1,120 @@
I2S - 使用DMIC配合audio cube实现在线录音
========================================
本 demo 演示 I2S 外设 驱动板载 DMIC 的音频电路板,通过Audio Cube在线播放的功能。
准备工具
-----------------------
- 一块 bl702 开发板 +DMIC音频子板 + PC端 Audio_Cube 工具
硬件连接
-----------------------------
本 demo 基于 BL706_AVB 开发板,需要用到 DMIC 音频子板,连接方式如下:
.. list-table::
:widths: 30 30
:header-rows: 1
* - GPIO function
- GPIO pin
* - CLK_OUT(MCLK)
- GPIO6
* - I2S_BCLK
- GPIO4
* - I2S_FS
- GPIO29
* - I2S_DI
- GPIO3
* - UART0_TX
- GPIO15
* - UART0_RX
- GPIO14
本 demo 用到的内部外设资源如下:
.. list-table::
:widths: 10 40
:header-rows: 1
* - peripheral
- role
* - I2S
- 标准音频数据接口用于接受DMIC音频子板传送来的音频数据
* - UART
- 串口,用于与上位机 Audio_cube 软件通讯
* - DMA-CH2/CH3
- 直接存储访问技术,用于配合 I2S 高效发送音频数据,减少对 CPU 的负载
* - CLK_OUT
- 引脚复用对外输出指定时钟信号用作提供MCLK时钟
软件实现
-----------------------
软件代码见 ``examples/audio_cube`` 文件夹, 其中 ``data_protocol.c`` 数据协议控制,用以与 Audio_Cube 工具交互通讯,获取控制信息、传输音频数据,
``data_protocol.c`` 是音频驱动相关程序,配置相关外设与音频数据解析, 播放与录制音频。main.c 使用以上程序,完成本 demo 的功能实现。
本文档不再详细功能实现的细节,仅概述功能过程,可以参考 I2S 与 UART 相关文档。
配置 ``I2S, I2C, CLK_OUT(MCLK)`` 相关复用引脚,见 ``bsp/board/bl706_avb/pinmux_config.h`` 中的宏定义选项:
.. code-block:: C
:linenos:
#define CONFIG_GPIO6_FUNC GPIO_FUN_CLK_OUT
#define CONFIG_GPIO3_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO4_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO29_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO30_FUNC GPIO_FUN_I2S
#define CONFIG_GPIO11_FUNC GPIO_FUN_I2C
#define CONFIG_GPIO16_FUNC GPIO_FUN_I2C
#define CONFIG_GPIO14_FUNC GPIO_FUN_UART0_TX
#define CONFIG_GPIO15_FUNC GPIO_FUN_UART0_RX
编译和烧录
-----------------------------
- **CDK 编译**
打开项目中提供的工程文件audio_cube.cdkproj
参照 :ref:`windows_cdk_quick_start` 的步骤编译下载即可
- **命令行编译**
.. code-block:: bash
:linenos:
$ cd <sdk_path>/bl_mcu_sdk
$ make BOARD=bl706_avb APP=audio_cube
- **烧录**
详见 :ref:`bl_dev_cube`
Audio Cube 上位机的使用
-----------------------------
正确编译烧录程序后,复位启动,通过串口连接 PC,打开 Audio Cube 软件,界面如图:
.. figure:: img/audio_cube_1.png
:alt:
选择对应的串口号(Data Port 与 command Port 相同),设置与已烧录的程序里相同的波特率(默认为3M,在 ``data_protocol.c`` 中修改),
Refresh Port 按键用于刷新串口信息,Clear Display 用于清除显示的信息,Advanced 按键展开关于录音的设置,包括采样率、声道数、采样位宽(固定为16bit)
录制音频
^^^^^^^^^^^^^^^^
录制音频前若正在播放音乐,需要点击 Stop 停止播放。点击 Start Record 录制音频,再次点击停止录制,会将录制的音频保存在 record 文件夹下,
录制的音频会以时间作为文件名。如果需要播放录制的音频,点击 Browse 选择录制的音频,再点击 Play 即可。
实验现象
-----------------------------
见视频展示:

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View file

@ -7,4 +7,5 @@ I2S 示例
:maxdepth: 2
I2S - 播放flash内置音乐 <i2s_play_from_flash_demo>
I2S - 回环播放 <i2s_play_from_record_demo>
I2S - 回环播放 <i2s_play_from_record_demo>
I2S - 使用DMIC配合audio cube实现在线录音 <i2s_audio_cube_demo>