BouffaloSDK 使用指南
欢迎来到 Bouffalo Lab BouffaloSDK 文档中心。
开发环境搭建
BouffaloSDK 提供了以下几种开发环境,包含环境搭建、编译、烧录和调试,选择一种适合你的即可。
Build and Debug with CDK
Build with Windows CMD
本节主要介绍如何在 Windows 下使用 命令行 进行开发。
环境搭建
首先需要安装 git 工具,这里自行百度。
使用 git 下载 RISC-V 工具链, 这里比如安装到 D 盘
1$ cd D:/
2$ git clone https://gitee.com/bouffalolab/toolchain_gcc_t-head_windows.git
将 make、ninja、下载的 risc-v 工具链路径配置到系统环境变量中, 其中 make 和 ninja 工具位于 bouffalo_sdk/tools 目录下。
windows 11 配置完以后需要重启电脑才生效。

完成上述步骤以后,需要检查是否真的安装成功。打开 powershell 或者 cmd,输入下列命令:
1$ make -v
此时应该显示如下内容表示安装成功:
1 GNU Make 4.2.1
2 Built for x86_64-w64-mingw32
3 Copyright (C) 1988-2016 Free Software Foundation, Inc.
4 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
5 This is free software: you are free to change and redistribute it.
6 There is NO WARRANTY, to the extent permitted by law.
1$ riscv64-unknown-elf-gcc -v
此时应该显示如下内容表示安装成功:
1 Using built-in specs.
2 COLLECT_GCC=riscv64-unknown-elf-gcc
3 COLLECT_LTO_WRAPPER=/mnt/d/EmbeddedSoftware/Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/bin/../libexec/gcc/riscv64-unknown-elf/10.2.0/lto-wrapper
4 Target: riscv64-unknown-elf
5 Configured with: /lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/./source/riscv/riscv-gcc/configure --target=riscv64-unknown-elf --with-gmp=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-mpfr=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-mpc=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-libexpat-prefix=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-libmpfr-prefix=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-pkgversion='Xuantie-900 elf newlib gcc Toolchain V2.2.5 B-20220323' CXXFLAGS='-g -O2 -DTHEAD_VERSION_NUMBER=2.2.5' --enable-libgcctf --prefix=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5 --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-sysroot=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/riscv64-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/./source/riscv/riscv-gcc --enable-multilib --with-abi=lp64d --with-arch=rv64gcxthead 'CFLAGS_FOR_TARGET=-Os -mcmodel=medany' 'CXXFLAGS_FOR_TARGET=-Os -mcmodel=medany'
6 Thread model: single
7 Supported LTO compression algorithms: zlib
8 gcc version 10.2.0 (Xuantie-900 elf newlib gcc Toolchain V2.2.5 B-20220323)
编译
打开 powershell 或者 cmd,进入 examples ,选择你想要编译的 case,且该 case 下必须有 Makefile 文件。使用下面命令编译,生成的 bin 文件会输出到 build/build_out 目录下。
使用 make 编译
1 $ cd .\examples\helloworld\
2 $ make CHIP=chip_name BOARD=board_name ## chip_name 为芯片型号,可以填写 bl702、bl616、bl808、bl606p, board_name 为开发板名称,详见 bsp/board 目录
使用 ninja 编译
1 $ cd .\examples\helloworld\
2 $ make ninja CHIP=chip_name BOARD=board_name ## chip_name 为芯片型号,可以填写 bl702、bl616、bl808、bl606p, board_name 为开发板名称,详见 bsp/board 目录
备注
如果使用 BL808 或者 BL606P,需要在上面基础上添加 CPU_ID=id ,id 可以为 m0 或者 d0
烧录
1 $ cd examples/helloworld
2 $ make flash CHIP=chip_name COMX=port_name ## port_name 为串口号名称,比如 COM5
备注
如果使用 BL808 或者 BL606P,需要在上面基础上添加 CPU_ID=id ,id 可以为 m0 或者 d0
调试
推荐使用 eclipse + cklink 调试,参考 Build and Debug with Eclipse,也可以使用命令行调试,这里不做介绍
Build with Linux or WSL
本节主要介绍如何在 Linux 或者 WSL 下使用 命令行 进行开发。Windows 下如何安装 WSL 以及 WSL1/WSL2 下如何使用串口请自行百度。
环境搭建
首先打开 linux 终端,并安装依赖工具
1$ cd ~
2$ sudo apt install git make ninja-build -y
其次使用 git 下载 RISC-V 工具链
1$ cd ~
2$ git clone https://gitee.com/bouffalolab/toolchain_gcc_t-head_linux.git
3$ sudo cp -rf toolchain_gcc_t-head_linux/ /usr/bin
4$ echo "export PATH=\"$PATH:/usr/bin/toolchain_gcc_t-head_linux/bin\"" >> ~/.bashrc
5$ source ~/.bashrc
完成上述步骤以后,需要检查是否真的安装成功,输入下列命令:
1$ make -v
此时应该显示如下内容表示安装成功:
1 GNU Make 4.1
2 Built for x86_64-pc-linux-gnu
3 Copyright (C) 1988-2014 Free Software Foundation, Inc.
4 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
5 This is free software: you are free to change and redistribute it.
6 There is NO WARRANTY, to the extent permitted by law.
1$ riscv64-unknown-elf-gcc -v
此时应该显示如下内容表示安装成功:
1 Using built-in specs.
2 COLLECT_GCC=riscv64-unknown-elf-gcc
3 COLLECT_LTO_WRAPPER=/mnt/d/EmbeddedSoftware/Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/bin/../libexec/gcc/riscv64-unknown-elf/10.2.0/lto-wrapper
4 Target: riscv64-unknown-elf
5 Configured with: /lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/./source/riscv/riscv-gcc/configure --target=riscv64-unknown-elf --with-gmp=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-mpfr=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-mpc=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-libexpat-prefix=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-libmpfr-prefix=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/build-Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/lib-for-gcc-x86_64-linux --with-pkgversion='Xuantie-900 elf newlib gcc Toolchain V2.2.5 B-20220323' CXXFLAGS='-g -O2 -DTHEAD_VERSION_NUMBER=2.2.5' --enable-libgcctf --prefix=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5 --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-sysroot=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/build-riscv-gcc-riscv64-unknown-elf/Xuantie-900-gcc-elf-newlib-x86_64-V2.2.5/riscv64-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --disable-tm-clone-registry --src=/lhome/software/toolsbuild/slave2/workspace/Toolchain/build-gnu-riscv_4/./source/riscv/riscv-gcc --enable-multilib --with-abi=lp64d --with-arch=rv64gcxthead 'CFLAGS_FOR_TARGET=-Os -mcmodel=medany' 'CXXFLAGS_FOR_TARGET=-Os -mcmodel=medany'
6 Thread model: single
7 Supported LTO compression algorithms: zlib
8 gcc version 10.2.0 (Xuantie-900 elf newlib gcc Toolchain V2.2.5 B-20220323)
编译
打开 linux 终端,进入 examples ,选择你想要编译的 case,且该 case 下必须有 Makefile 文件。使用下面命令编译,生成的 bin 文件会输出到 build/build_out 目录下。
使用 make 编译
1 $ cd examples/helloworld
2 $ make CHIP=chip_name BOARD=board_name ## chip_name 为芯片型号,可以填写 bl702、bl616、bl808、bl606p, board_name 为开发板名称,详见 bsp/board 目录
使用 ninja 编译
1 $ cd examples/helloworld
2 $ make ninja CHIP=chip_name BOARD=board_name ## chip_name 为芯片型号,可以填写 bl702、bl616、bl808、bl606p, board_name 为开发板名称,详见 bsp/board 目录
备注
如果使用 BL808 或者 BL606P,需要在上面基础上添加 CPU_ID=id ,id 可以为 m0 或者 d0
烧录
1 $ cd examples/helloworld
2 $ make flash CHIP=chip_name COMX=port_name ## port_name 为串口号名称,比如 linux 中/dev/ttyACMx
备注
如果使用 BL808 或者 BL606P,需要在上面基础上添加 CPU_ID=id ,id 可以为 m0 或者 d0
调试
推荐使用 eclipse + cklink 调试,参考 Build and Debug with Eclipse,也可以使用命令行调试,这里不做介绍
Build and Debug with Eclipse
本节主要介绍如何使用 Eclipse 进行开发。
环境搭建
首先下载 Eclipse , 选择 Eclipse IDE for C/C++ Developers , 并根据你的电脑版本进行下载。

其余步骤参考 Build with Windows CMD
解压 Eclipse 并双击打开 Eclipse.exe

选择工作路径并点击 Launch

点击左上角 File 选择 Import,选择 General > Existing project into workspace 并点击 Next

导入 bl_mcu_sdk

编译
双击 Build Targets 中的 make 即可编译 helloworld。双击 clean 即可清除 helloworld 下的缓存

如果需要更换 demo ,右击 Build Targets 中的 make,修改中间方框里的内容即可,内容为指定 demo 下 Makefile 文件的路径

调试
完成上述步骤以后,如果是在 flash 上调试,需要先将 bin 文件烧录到芯片中 ,然后才能够进行下面的调试环节。
在 Eclipse 中 点击 debug 图标,并点击 Debug Configurations

左侧打开 GDB Hardware Debugging,选择对应芯片的配置按钮,并导入编译生成的 elf, 最后点击 Debug

最终进入调试界面

bouffalo_flash_cube 的使用
BouffaloSDK 采用新的 flash tool ( bouffalo_flash_cube ),并且烧录依赖 Flash prog cfg.ini 文件。
相比于 Bouffalo Lab DevCube 繁琐的功能,bouffalo_flash_cube 只用于下载代码,在用户执行 make flash
时会调用 bouffalo_flash_cube 下的可执行文件,并根据 Flash prog cfg.ini 进行烧录,
本节主要介绍一下 Flash prog cfg.ini 的语法。更详细的介绍参考 tools/bflb_tools/bouffalo_flash_cube/docs/FlashCube_User_Guide.pdf
语法
Flash prog cfg.ini 正常使用只需要创建一个 KEY,例如 [FW],并且填写 filedir 和 address 就可以使用了。
其中 filedir 的填写方式有以下几种:
bin 文件全路径 + bin 文件名称
bin 文件相对路径 + bin 文件名称
bin 文件名称添加 _$(CHIPNAME) 后缀可以自动识别成不同芯片(仅在 bin 文件名称前缀不同的时候使用)
bin 文件名称添加 * 通配符,可以自动补全bin 文件名称(仅在 bin 文件名称前缀不同的时候使用)
常规 MCU 使用(不使用无线功能)
1 [cfg]
2 # 0: no erase, 1:programmed section erase, 2: chip erase
3 erase = 1
4 # skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated
5 skip_mode = 0x0, 0x0
6 # 0: not use isp mode, #1: isp mode
7 boot2_isp_mode = 0
8
9 [FW]
10 filedir = ./build/build_out/xxx*_$(CHIPNAME).bin
11 address = 0x0000
cfg 表示烧录时的一些配置,正常不需要改动
FW 要烧录的应用固件,必须使用 FW 名称。
filedir 表示应用固件所在相对路径,正常来说是编译完后放在 build/build_out 目录。
_$(CHIPNAME).bin
用于自动区分不同芯片。xxx
表示应用固件名称,与 CMakeLists.txt 中 project(xxx) 中名称一致。*
表示正则匹配,可用可不用。address 必须使用 0 地址
常规 IOT 使用(使用无线功能)
1 [cfg]
2 # 0: no erase, 1:programmed section erase, 2: chip erase
3 erase = 1
4 # skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated
5 skip_mode = 0x0, 0x0
6 # 0: not use isp mode, #1: isp mode
7 boot2_isp_mode = 0
8
9 [boot2]
10 filedir = ./build/build_out/boot2_*.bin
11 address = 0x000000
12
13 [partition]
14 filedir = ./build/build_out/partition*.bin
15 address = 0xE000
16
17 [FW]
18 filedir = ./build/build_out/xxx*_$(CHIPNAME).bin
19 address = 0x10000
20
21 [mfg]
22 filedir = ./build/build_out/mfg*.bin
23 address = 0x210000
cfg 表示烧录时的一些配置,正常不需要改动
FW 要烧录的应用固件,必须使用 FW 名称。
filedir 表示应用固件所在相对路径,正常来说是编译完后放在 build/build_out 目录。
_$(CHIPNAME).bin
用于区分不同芯片。xxx
表示应用固件名称,与 CMakeLists.txt 中 project(xxx) 中名称一致。address 由 partition_xxx.toml 指定
boot2 要烧录的 boot2 固件,必须使用 boot2 名称。
filedir 表示 boot2 固件所在相对路径,正常来说是编译完后放在 build/build_out 目录。 自动从 bsp/board/board_name/config 目录拷贝。
address 必须使用 0 地址
partition 要烧录的 partition 固件,必须使用 partition 名称。
filedir 表示 partition 固件所在相对路径,正常来说是编译完后放在 build/build_out 目录。 自动从 bsp/board/board_name/config 目录 partition_xxx.toml 转换成 bin 文件并拷贝。
address 由 partition_xxx.toml 指定
mfg 要烧录的 mfg 固件,必须使用 mfg 名称。 mfg 可选,可以不烧录
filedir 表示 mfg 固件所在相对路径,正常来说是编译完后放在 build/build_out 目录。 自动从 bsp/board/board_name/config 目录拷贝。
address 由 partition_xxx.toml 指定
备注
如果使用了 partition,address 可以使用 @partition 代替绝对地址,@partition 将会自动从 partition_xxx.toml 找到对应的地址
1 [cfg]
2 # 0: no erase, 1:programmed section erase, 2: chip erase
3 erase = 1
4 # skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated
5 skip_mode = 0x0, 0x0
6 # 0: not use isp mode, #1: isp mode
7 boot2_isp_mode = 0
8
9 [boot2]
10 filedir = ./build/build_out/boot2_*.bin
11 address = 0x000000
12
13 [partition]
14 filedir = ./build/build_out/partition*.bin
15 address = 0xE000
16
17 [FW]
18 filedir = ./build/build_out/xxx*_$(CHIPNAME).bin
19 address = 0x10000
20
21 [mfg]
22 filedir = ./build/build_out/mfg*.bin
23 address = 0x210000
多个运行固件烧录
禁止使用通配符 * 以及 _$(CHIPNAME)
前缀,因为 bin 文件名称前缀相同。
1 [cfg]
2 # 0: no erase, 1:programmed section erase, 2: chip erase
3 erase = 1
4 # skip mode set first para is skip addr, second para is skip len, multi-segment region with ; separated
5 skip_mode = 0x0, 0x0
6 # 0: not use isp mode, #1: isp mode
7 boot2_isp_mode = 0
8
9 [FW1]
10 filedir = ./build/build_out/xxx0.bin
11 address = 0x00000
12
13 [FW2]
14 filedir = ./build/build_out/xxx1.bin
15 address = 0x10000
16
17 [FW3]
18 filedir = ./build/build_out/xxx2.bin
19 address = 0x20000
使用调试器调试代码
本节主要介绍如何使用调试器进行代码的调试。
芯片默认 JTAG PIN 列表
CHIP/Pin |
BL602/BL604 |
BL702/BL704/BL706 |
BL616/BL618 |
BL808 |
---|---|---|---|---|
TMS |
GPIO12 |
GPIO0 |
GPIO0 |
GPIO6 |
TCK |
GPIO14 |
GPIO2 |
GPIO1 |
GPIO12 |
TDO |
GPIO11 |
GPIO9 |
GPIO2 |
GPIO7 |
TDI |
GPIO17 |
GPIO1 |
GPIO3 |
GPIO13 |
使用 CKLink + Eclipse 调试代码
从 T-HEAD 官网下载最新版本 CKLink 驱动
安装和配置 CKLink
将下载的 CKLink 安装包解压,并双击 Setup ,一路 next 即可,安装完成以后,桌面会有一个 T-HeadDebugServer 图标


将板子的 JTAG 引脚和 CKLink 调试器连接以后,点击 三角 按钮,如果变成 圆圈,则表示 JTAG 连接成功。如果失败,则需要检查 JTAG 线序是否正确。

使用 Eclipse 调试
CMake 框架的使用
本节主要介绍如何使用 CMake 框架。BouffaloSDK 中为用户封装了以下函数接口,基本满足常用场景的使用。
Function |
Description |
---|---|
sdk_generate_library |
生成库,库名如果函数没有形参则使用当前库所在目录名 |
sdk_library_add_sources |
为库添加源文件 |
sdk_library_add_sources_ifdef |
为库添加源文件(满足 if 条件) |
sdk_add_include_directories |
添加头文件路径 |
sdk_add_include_directories_ifdef |
添加头文件路径(满足 if 条件) |
sdk_add_compile_definitions |
添加宏定义,不要带 -D |
sdk_add_compile_definitions_ifdef |
添加宏定义(满足 if 条件) |
sdk_add_compile_options |
添加编译选项 |
sdk_add_compile_options_ifdef |
添加编译选项(满足 if 条件) |
sdk_add_link_options |
添加链接选项 |
sdk_add_link_options_ifdef |
添加链接选项(满足 if 条件) |
sdk_add_link_libraries |
添加静态库 |
sdk_add_link_libraries_ifdef |
添加静态库(满足 if 条件) |
sdk_add_subdirectory_ifdef |
编译子目录下的 cmakelist(满足 if 条件) |
sdk_add_static_library |
添加外部静态库 |
sdk_set_linker_script |
设置链接脚本 |
sdk_set_main_file |
设置 main 函数所在文件 |
project |
工程编译 |
target_source(app PRIVATE xxx) |
添加源文件到 app 库中,当用户需要自己添加一些源文件又不想创建 cmakelist 单独编译成库,可以使用该项 |
新建工程
用户可以复制一份工程,如 helloworld,并修改 SDK_DEMO_PATH 变量为你使用的路径即可创建一份全新的工程
为工程添加组件
如果需要编译相关组件,如 FATFS、LVGL ,需要在 proj.conf 文件中添加组件的使能,举例如下:
1 set(CONFIG_FATFS 1)
2 set(CONFIG_LVGL 1)
使能条件编译项
用户自定义的 cmake 条件编译项( 使用了 cmake 的 if 语法)、或者使用了 sdk 带 ifdef 结尾的函数, 使能方式同上
Repo 的使用
Repo 是谷歌用 Python 脚本写的调用 git 的一个脚本,可以实现管理多个 git 库,简单的几行命令便可以拉取很多仓库的代码。
安装
下载 repo 。
windows 下将 repo.exe 文件(在 win 目录中)所在的路径配置到系统环境变量。

Linux 下执行以下命令。
1 cd repo/linux
2 chmod +x repo
3 mv repo /usr/bin/repo
下载代码
请联系商务申请账号。
同步代码
后续只需要使用 repo sync
即可同步代码。
Peripherals
简介
BouffaloSDK 中外设驱动分为两类: LHAL 和 SOC ,前者对通用外设进行了统一的封装,不同芯片使用同一套接口,方便用户使用和移植到其他平台。后者则是每个芯片独有且特殊的部分,比如 GLB、HBN、PDS、AON 等等。
下面主要列出 LHAL 相关 API 的使用。
LHAL 中各个外设 API 声明均在 drivers/include 目录下可以查看。在学习 API 使用之前,我们需要了解 struct bflb_device_s 结构体的含义和作用。
1struct bflb_device_s {
2 const char *name;
3 uint32_t reg_base;
4 uint8_t irq_num;
5 uint8_t idx;
6 uint8_t sub_idx;
7 uint8_t dev_type;
8 void *user_data;
9};
parameter |
description |
---|---|
name |
外设名称 |
reg_base |
外设寄存器基地址 |
irq_num |
外设中断号 |
idx |
外设 id |
idx |
外设 id,例如 UART0、UART1 |
sub_idx |
外设子 id,例如 DMA0_CH0、DMA0_CH1 |
dev_type |
外设类型 |
user_data |
用户变量 |
从上我们可以知道 struct bflb_device_s 结构体成员的具体信息,其中比较重要的就是 reg_base 和 irq_num ,有了这两个,我们才能操作外设寄存器和外设中断。那么当我们进行外设配置之前,就需要先获取该结构体句柄,从中获取我们需要的信息,否则不能对外设进行操作。获取结构体句柄有以下两种方式:
bflb_device_get_by_name 通过 name 获取
bflb_device_get_by_id 通过 dev_type 和 idx 获取
那么还有一个问题,结构体句柄保存在哪?
对于每个系列芯片支持的外设,我们将结构体句柄保存在一个 table 表中。详见 lhal/config/xxx/device_table.c 文件。
API 支持情况
了解了上面的基本概念以后,接下来就可以查阅相关 LHAL API 并使用了。当前已经支持的 LHAL API 列表如下:
备注
✔️ 表示已支持; ❌ 表示未支持; ❓ 表示已支持但未测试; ➖ 表示没有该外设。
peripheral |
BL602/BL604 |
BL702/BL704/BL706 |
BL616/BL618 |
BL808 |
---|---|---|---|---|
ADC |
❓ |
✔️ |
✔️ |
❓ |
CAM |
➖ |
❌ |
❌ |
❌ |
CKS |
❓ |
✔️ |
✔️ |
❓ |
DAC |
❓ |
✔️ |
✔️ |
❓ |
DMA |
❓ |
✔️ |
✔️ |
✔️ |
EFUSE |
❓ |
✔️ |
✔️ |
✔️ |
EMAC |
➖ |
✔️ |
✔️ |
✔️ |
FLASH |
✔️ |
✔️ |
✔️ |
✔️ |
GPIO |
❓ |
✔️ |
✔️ |
✔️ |
I2C |
❓ |
✔️ |
✔️ |
❓ |
IR |
❓ |
✔️ |
✔️ |
✔️ |
MJPEG |
❌ |
✔️ |
✔️ |
❌ |
PWM_v1 |
❓ |
✔️ |
➖ |
➖ |
PWM_v2 |
➖ |
➖ |
✔️ |
✔️ |
RTC |
❓ |
✔️ |
✔️ |
✔️ |
SEC_AES |
❓ |
✔️ |
✔️ |
✔️ |
SEC_SHA |
❓ |
✔️ |
✔️ |
✔️ |
SEC_TRNG |
❓ |
✔️ |
✔️ |
✔️ |
SEC_PKA |
❓ |
✔️ |
✔️ |
✔️ |
SPI |
❓ |
✔️ |
✔️ |
❓ |
TIMER |
❓ |
✔️ |
✔️ |
✔️ |
UART |
❓ |
✔️ |
✔️ |
✔️ |
USB_v1 |
➖ |
✔️ |
➖ |
➖ |
USB_v2 |
➖ |
➖ |
✔️ |
✔️ |
WDG |
❓ |
✔️ |
✔️ |
✔️ |
API 列表
除了使用网页版查看 API 以外, 还提供了 LHAL Doxygen 版本,离线生成文档。 Doxyfile 文件在 drivers/lhal
目录下。
使用 Doxywizard 导入并运行即可。

ADC
Macros
adc channel
参考 bflb_adc.h 文件,不详细列出。
adc clock div
对 adc 时钟再一次进行分频。分频后的时钟必须小于等于 500K。ADC CLK = CLK_SOURCE/CLK_DIV/adc_clk_div。
1 #define ADC_CLK_DIV_4 1
2 #define ADC_CLK_DIV_8 2
3 #define ADC_CLK_DIV_12 3
4 #define ADC_CLK_DIV_16 4
5 #define ADC_CLK_DIV_20 5
6 #define ADC_CLK_DIV_24 6
7 #define ADC_CLK_DIV_32 7
adc resolution
adc 位数,可以选择 12B、14B、16B。其中 14B 和 16B 自带过采样处理。
1 #define ADC_RESOLUTION_12B 0
2 #define ADC_RESOLUTION_14B 2
3 #define ADC_RESOLUTION_16B 4
adc vref
adc 内置参考电压选择,可以选择 2.0 V 或者 3.2V。
1 #define ADC_VREF_3P2V 0
2 #define ADC_VREF_2P0V 1
Structs
struct bflb_adc_config_s
adc 初始化配置结构体。
1 struct bflb_adc_config_s {
2 uint8_t clk_div;
3 uint8_t scan_conv_mode;
4 uint8_t continuous_conv_mode;
5 uint8_t differential_mode;
6 uint8_t resolution;
7 uint8_t vref;
8 };
parameter |
description |
---|---|
clk_div |
分频值 |
scan_conv_mode |
是否开启扫描模式 |
continuous_conv_mode |
是否开启连续转换模式 |
differential_mode |
是否开启差分模式 |
resolution |
采样位数 |
vref |
参考电压选择 |
struct bflb_adc_channel_s
配置 adc 通道时使用。
1 struct bflb_adc_channel_s {
2 uint8_t pos_chan;
3 uint8_t neg_chan;
4 };
parameter |
description |
---|---|
pos_chan |
正向通道 |
neg_chan |
反向通道(单端模式下无用) |
struct bflb_adc_result_s
adc 标准转换结果
1 struct bflb_adc_result_s {
2 int8_t pos_chan;
3 int8_t neg_chan;
4 int32_t value;
5 int32_t millivolt;
6 };
parameter |
description |
---|---|
pos_chan |
正向通道 |
neg_chan |
反向通道(单端模式下无用) |
value |
adc 转换结果 |
millivolt |
转换结果转 mv |
Functions
bflb_adc_init
说明: 初始化 adc。adc 使用之前需要开启 adc ip 时钟、设置 adc 时钟源和分频值、选择使用的 gpio 为 analog 模式。
1 void bflb_adc_init(struct bflb_device_s *dev, const struct bflb_adc_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
config |
配置项 |
bflb_adc_deinit
说明: 反初始化 adc。
1 void bflb_adc_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_adc_link_rxdma
说明: adc dma 功能开关。
1 void bflb_adc_link_rxdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否开启 dma 功能 |
bflb_adc_channel_config
说明: 配置 adc 通道。
1 int bflb_adc_channel_config(struct bflb_device_s *dev, struct bflb_adc_channel_s *chan, uint8_t channels);
parameter |
description |
---|---|
dev |
设备句柄 |
chan |
通道(一对) |
channels |
通道对数(单次扫描模式下只能为 1) |
bflb_adc_start_conversion
说明: 启动 adc 转换。连续转换模式下只需要调用一次。
1 void bflb_adc_start_conversion(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_adc_stop_conversion
说明: 停止 adc 转换。
1 void bflb_adc_stop_conversion(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_adc_get_count
说明: 获取 adc 转换个数。
1 uint8_t bflb_adc_get_count(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
转换个数(最大为32) |
bflb_adc_read_raw
说明: 读取一次 adc 转换值。
1 uint32_t bflb_adc_read_raw(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
转换值(注意不是最终采样值) |
bflb_adc_rxint_mask
说明: adc 转换完成中断开关。
1 void bflb_adc_rxint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_adc_errint_mask
说明: adc 错误中断开关。
1 void bflb_adc_errint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_adc_get_intstatus
说明: adc 中断标志。
1uint32_t bflb_adc_get_intstatus(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
中断标志 |
返回值如下:
1 ADC_INTSTS_NEG_SATURATION
2 ADC_INTSTS_NEG_SATURATION
3 ADC_INTSTS_FIFO_UNDERRUN
4 ADC_INTSTS_FIFO_OVERRUN
5 ADC_INTSTS_ADC_READY
bflb_adc_int_clear
说明: 清除 adc 中断标志。
1 void bflb_adc_int_clear(struct bflb_device_s *dev, uint32_t int_clear);
parameter |
description |
---|---|
dev |
设备句柄 |
int_clear |
清除值 |
int_clear 可以填入以下参数:
1 ADC_INTCLR_NEG_SATURATION
2 ADC_INTCLR_POS_SATURATION
3 ADC_INTCLR_FIFO_UNDERRUN
4 ADC_INTCLR_FIFO_OVERRUN
5 ADC_INTCLR_ADC_READY
bflb_adc_parse_result
说明: 对 adc 转换结果进行解析。
1 void bflb_adc_parse_result(struct bflb_device_s *dev, uint32_t *buffer, struct bflb_adc_result_s *result, uint16_t count);
parameter |
description |
---|---|
dev |
设备句柄 |
buffer |
转换值 |
result |
输出结果 |
count |
转换个数 |
bflb_adc_tsen_init
说明: 初始化 adc tsen 模块。
1void bflb_adc_tsen_init(struct bflb_device_s *dev, uint8_t tsen_mod);
parameter |
description |
---|---|
dev |
设备句柄 |
tsen_mod |
模式选择 |
bflb_adc_tsen_get_temp
说明: 初始化 adc tsen 模块。
1float bflb_adc_tsen_get_temp(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
温度 |
bflb_adc_vbat_enable
说明: 开启 vbat 。
1void bflb_adc_vbat_enable(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_adc_vbat_disable
说明: 关闭 vbat。
1void bflb_adc_vbat_disable(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
CKS
Macros
无
Structs
无
Functions
CLOCK
Macros
无
Structs
无
Functions
bflb_clk_get_system_clock
说明: 获取系统时钟频率。
1 uint32_t bflb_clk_get_system_clock(uint8_t type);
parameter |
description |
---|---|
dev |
设备句柄 |
type |
外设类型 |
type 可以填入以下参数:
1#define BFLB_SYSTEM_ROOT_CLOCK 0
2#define BFLB_SYSTEM_CPU_CLK 1
3#define BFLB_SYSTEM_PBCLK 2
4#define BFLB_SYSTEM_XCLK 3
5#define BFLB_SYSTEM_32K_CLK 4
bflb_clk_get_peripheral_clock
说明: 获取外设时钟频率。
1 uint32_t bflb_clk_get_peripheral_clock(uint8_t type, uint8_t idx);
parameter |
description |
---|---|
dev |
设备句柄 |
type |
外设类型 |
idx |
外设 id |
type 可以填入以下参数:
1#define BFLB_DEVICE_TYPE_ADC 0
2#define BFLB_DEVICE_TYPE_DAC 1
3#define BFLB_DEVICE_TYPE_AUDIOADC 2
4#define BFLB_DEVICE_TYPE_AUDIODAC 3
5#define BFLB_DEVICE_TYPE_GPIO 4
6#define BFLB_DEVICE_TYPE_UART 5
7#define BFLB_DEVICE_TYPE_SPI 6
8#define BFLB_DEVICE_TYPE_I2C 7
9#define BFLB_DEVICE_TYPE_DMA 8
10#define BFLB_DEVICE_TYPE_I2S 9
11#define BFLB_DEVICE_TYPE_IR 10
12#define BFLB_DEVICE_TYPE_TIMER 11
13#define BFLB_DEVICE_TYPE_PWM 12
14#define BFLB_DEVICE_TYPE_CAMERA 14
15#define BFLB_DEVICE_TYPE_FLASH 15
16#define BFLB_DEVICE_TYPE_QSPI 16
17#define BFLB_DEVICE_TYPE_SDH 17
18#define BFLB_DEVICE_TYPE_SDU 18
19#define BFLB_DEVICE_TYPE_ETH 19
20#define BFLB_DEVICE_TYPE_RTC 20
21#define BFLB_DEVICE_TYPE_CRC 21
22#define BFLB_DEVICE_TYPE_RNG 22
23#define BFLB_DEVICE_TYPE_MIPI 23
24#define BFLB_DEVICE_TYPE_DPI 24
25#define BFLB_DEVICE_TYPE_DSI 25
26#define BFLB_DEVICE_TYPE_CSI 26
27#define BFLB_DEVICE_TYPE_USB 27
28#define BFLB_DEVICE_TYPE_AES 28
29#define BFLB_DEVICE_TYPE_SHA 29
30#define BFLB_DEVICE_TYPE_MD5 30
31#define BFLB_DEVICE_TYPE_TRNG 31
32#define BFLB_DEVICE_TYPE_PKA 32
33#define BFLB_DEVICE_TYPE_CKS 33
34#define BFLB_DEVICE_TYPE_MJPEG 34
DAC
Macros
dac clock div
dac 分频,只有 DMA 模式下可以使用 1 分频。
1#define DAC_CLK_DIV_16 0
2#define DAC_CLK_DIV_32 1
3#define DAC_CLK_DIV_64 3
4#define DAC_CLK_DIV_1 4
dac channel
博流系列芯片 dac 通道共两组:A 通道和 B 通道。
1 #define DAC_CHANNEL_A (1 << 0)
2 #define DAC_CHANNEL_B (1 << 1)
Structs
无
Functions
bflb_dac_init
说明: 初始化 dac。dac 使用之前需要开启 dac ip 时钟、设置 dac 时钟源和分频值、选择使用的 gpio 为 analog 模式。
1 void bflb_dac_init(struct bflb_device_s *dev, uint8_t clk_div);
parameter |
description |
---|---|
dev |
设备句柄 |
clk_div |
分频值 |
bflb_dac_deinit
说明: 反初始化 dac。
1 void bflb_dac_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_dac_link_txdma
说明: dac dma 开关使能。
1 void bflb_dac_link_txdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否使能 dma |
bflb_dac_channel_enable
说明: dac 通道使能。
1 void bflb_dac_channel_enable(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道,多个通道之间使用 | 连接 |
bflb_dac_channel_disable
说明: dac 通道关闭。
1 void bflb_dac_channel_disable(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道,多个通道之间使用 | 连接 |
bflb_dac_set_value
说明: 更改 dac 通道值。
1 void bflb_dac_set_value(struct bflb_device_s *dev, uint8_t ch, uint16_t value);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道,多个通道之间使用 | 连接 |
value |
通道值 |
DMA
Macros
dma direction
dma 传输方向支持 4 种。
1 #define DMA_MEMORY_TO_MEMORY 0
2 #define DMA_MEMORY_TO_PERIPH 1
3 #define DMA_PERIPH_TO_MEMORY 2
4 #define DMA_PERIPH_TO_PERIPH 3
dma addr increment
dma 地址自增使能。
1 #define DMA_ADDR_INCREMENT_DISABLE 0
2 #define DMA_ADDR_INCREMENT_ENABLE 1
dma data width
dma 传输位宽支持 8BIT 、16BIT、32BIT。
1 #define DMA_TRANSFER_WIDTH_8BIT 0
2 #define DMA_TRANSFER_WIDTH_16BIT 1
3 #define DMA_TRANSFER_WIDTH_32BIT 2
dma burst size
dma 突发传输个数,最多 16 字节突发。
1 #define DMA_BURST_INCR1 0
2 #define DMA_BURST_INCR4 1
3 #define DMA_BURST_INCR8 2
4 #define DMA_BURST_INCR16 3
警告
位宽 * 突发个数 需要小于等于 16 字节
dma addr
参考 bflb_dma.h 文件,不详细列出。
dma request
参考 bflb_dma.h 文件,不详细列出。
Structs
struct bflb_dma_channel_lli_pool_s
由于 dma 支持 lli 模式,所以需要在传输之前分配一块内存池给 lli 使用, 调用 bflb_dma_lli_reload 后会自动消耗内存池和配置相关 lli 信息,无需用户手动配置。
1 struct bflb_dma_channel_lli_pool_s {
2 uint32_t src_addr;
3 uint32_t dst_addr;
4 uint32_t nextlli;
5 union bflb_dma_lli_control_s lli_control;
6 };
struct bflb_dma_channel_lli_transfer_s
用户使用 lli 传输时,需要填充的传输内容:源地址、目标地址和长度,并且如果地址不连续,可以增加多个 transfer。
1 struct bflb_dma_channel_lli_transfer_s {
2 uint32_t src_addr;
3 uint32_t dst_addr;
4 uint32_t nbytes;
5 };
struct bflb_dma_channel_config_s
初始化 dma 通道时需要填充的信息。
1 struct bflb_dma_channel_config_s {
2 uint8_t direction;
3 uint32_t src_req;
4 uint32_t dst_req;
5 uint8_t src_addr_inc;
6 uint8_t dst_addr_inc;
7 uint8_t src_burst_count;
8 uint8_t dst_burst_count;
9 uint8_t src_width;
10 uint8_t dst_width;
11 };
parameter |
description |
---|---|
direction |
传输方向 |
src_req |
源 dma 请求 |
dst_req |
目标 dma 请求 |
src_addr_inc |
源地址是否自增 |
dst_addr_inc |
目标地址是否自增 |
src_burst_count |
源地址突发个数 |
dst_burst_count |
目标地址突发个数 |
src_width |
源地址位宽 |
dst_width |
目标地址位宽 |
Functions
bflb_dma_channel_init
说明: 初始化 dma 通道。
1 void bflb_dma_channel_init(struct bflb_device_s *dev, const struct bflb_dma_channel_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
config |
配置参数 |
bflb_dma_channel_deinit
说明: 反初始化 dma 通道。
1 void bflb_dma_channel_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_dma_channel_start
说明: 启动 dma 通道传输。
1 void bflb_dma_channel_start(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_dma_channel_stop
说明: 关闭 dma 通道传输。
1 void bflb_dma_channel_stop(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_dma_channel_isbusy
说明: 检查 dma 通道是否处于 busy 状态。
1bool bflb_dma_channel_isbusy(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
是否 busy |
bflb_dma_channel_irq_attach
说明: 注册 dma 通道中断完成回调函数并开启通道完成中断。
1void bflb_dma_channel_irq_attach(struct bflb_device_s *dev, void (*callback)(void *arg), void *arg);
parameter |
description |
---|---|
dev |
设备句柄 |
callback |
回调函数 |
arg |
用户参数 |
bflb_dma_channel_irq_detach
说明: 关闭 dma 通道完成中断。
1void bflb_dma_channel_irq_detach(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_dma_channel_lli_reload
说明: 配置 dma 通道的 lli 信息。
1 int bflb_dma_channel_lli_reload(struct bflb_device_s *dev,
2 struct bflb_dma_channel_lli_pool_s *lli_pool, uint32_t max_lli_count,
3 struct bflb_dma_channel_lli_transfer_s *transfer, uint32_t count);
parameter |
description |
---|---|
dev |
设备句柄 |
lli_pool |
lli 内存池 |
max_lli_count |
lli 内存池大小 |
transfer |
传输句柄 |
count |
传输次数 |
return |
返回使用的 lli count个数,小于0表示错误 |
bflb_dma_channel_lli_link_head
说明: 将 lli 最后一个链表与头部连接,表示开启循环模式。
1void bflb_dma_channel_lli_link_head(struct bflb_device_s *dev,
2struct bflb_dma_channel_lli_pool_s *lli_pool, uint32_t used_lli_count);
parameter |
description |
---|---|
dev |
设备句柄 |
lli_pool |
lli 内存池 |
used_lli_count |
已经使用的 lli 个数 |
bflb_dma_feature_control
说明: dma 其他特性相关控制,一般不常用。
1void bflb_dma_feature_control(struct bflb_device_s *dev, int cmd, size_t arg);
parameter |
description |
---|---|
dev |
设备句柄 |
cmd |
控制字 |
arg |
控制参数 |
cmd 可以填入以下参数:
1#define DMA_CMD_SET_SRCADDR_INCREMENT (0x01)
2#define DMA_CMD_SET_DSTADDR_INCREMENT (0x02)
3#define DMA_CMD_SET_ADD_MODE (0x03)
4#define DMA_CMD_SET_REDUCE_MODE (0x04)
FLASH
Macros
flash iomode
1#define FLASH_IOMODE_NIO 0
2#define FLASH_IOMODE_DO 1
3#define FLASH_IOMODE_QO 2
4#define FLASH_IOMODE_DIO 3
5#define FLASH_IOMODE_QIO 4
Structs
无
Functions
bflb_flash_init
说明: flash 初始化,自动识别支持的 flash 并重新配置 flash 的参数。如果返回错误,必须停止运行代码。
1int bflb_flash_init(void);
parameter |
description |
---|---|
return |
返回 0 表示成功,其他表示错误,必须停止运行代码 |
bflb_flash_get_jedec_id
说明: 获取 flash jedec id。
1uint32_t bflb_flash_get_jedec_id(void);
parameter |
description |
---|---|
return |
返回 flash jedec id |
bflb_flash_get_cfg
说明: 获取 flash 配置。
1void bflb_flash_get_cfg(uint8_t **cfg_addr, uint32_t *len);
parameter |
description |
---|---|
cfg_addr |
保存 flash 配置的地址 |
len |
flash 配置的长度 |
bflb_flash_set_iomode
说明: 设置 flash IO 工作模式。
1void bflb_flash_set_iomode(uint8_t iomode);
parameter |
description |
---|---|
iomode |
flash IO 工作模式 |
bflb_flash_get_image_offset
说明: 获取代码 xip 虚拟地址实际所在的 flash 物理地址。
1uint32_t bflb_flash_get_image_offset(void);
parameter |
description |
---|---|
return |
返回 flash xip 物理地址 |
bflb_flash_erase
说明: flash 扇区擦除。 len 为擦除的长度,需要为 4096 倍数,假设 addr 为0 , len 为 4096,则擦除范围为 0 ~ 4095。
1int bflb_flash_erase(uint32_t addr, uint32_t len);
parameter |
description |
---|---|
addr |
擦除的物理地址 |
len |
擦除长度,需要是 4096 的倍数 |
return |
返回 0 表示成功,其他表示错误 |
bflb_flash_write
说明: 获取代码 xip 虚拟地址实际所在的 flash 物理地址。
1int bflb_flash_write(uint32_t addr, uint8_t *data, uint32_t len);
parameter |
description |
---|---|
addr |
写入的物理地址 |
data |
写入的数据缓冲区 |
len |
写入长度 |
return |
返回 0 表示成功,其他表示错误 |
bflb_flash_read
说明: 获取代码 xip 虚拟地址实际所在的 flash 物理地址。
1int bflb_flash_read(uint32_t addr, uint8_t *data, uint32_t len);
parameter |
description |
---|---|
addr |
读取的物理地址 |
data |
读取的数据缓冲区 |
len |
读取长度 |
return |
返回 0 表示成功,其他表示错误 |
bflb_flash_aes_init
说明: 配置某一段 flash 区域进行硬件 aes 解密,能够通过 xip 直接读取解密后的内容。
1void bflb_flash_aes_init(struct bflb_flash_aes_config_s *config);
parameter |
description |
---|---|
config |
flash aes 配置 |
bflb_flash_aes_enable
说明: 使能 flash aes 解密。
1void bflb_flash_aes_enable(void);
bflb_flash_aes_disable
说明: 关闭 flash aes 解密。
1void bflb_flash_aes_disable(void);
GPIO
Macros
gpio pin
参考 bflb_gpio.h 文件,不详细列出。
警告
相同系列芯片引脚数会有区别,注意区分
gpio mode
gpio 模式可以配置成输入、输出、模拟、复用。
1 #define GPIO_INPUT (0 << GPIO_MODE_SHIFT) /* Input Enable */
2 #define GPIO_OUTPUT (1 << GPIO_MODE_SHIFT) /* Output Enable */
3 #define GPIO_ANALOG (2 << GPIO_MODE_SHIFT) /* Analog Enable */
4 #define GPIO_ALTERNATE (3 << GPIO_MODE_SHIFT) /* Alternate Enable */
gpio function
参考 bflb_gpio.h 文件,不详细列出。
gpio pupd
gpio 上下拉可以选择上拉、下拉、浮空。
1 #define GPIO_FLOAT (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */
2 #define GPIO_PULLUP (1 << GPIO_PUPD_SHIFT) /* Pull-up */
3 #define GPIO_PULLDOWN (2 << GPIO_PUPD_SHIFT) /* Pull-down */
gpio smt
gpio 滤波开关。
1 #define GPIO_SMT_DIS (0 << GPIO_SMT_SHIFT)
2 #define GPIO_SMT_EN (1 << GPIO_SMT_SHIFT)
gpio drive
gpio 输出能力选择。
1 #define GPIO_DRV_0 (0 << GPIO_DRV_SHIFT)
2 #define GPIO_DRV_1 (1 << GPIO_DRV_SHIFT)
3 #define GPIO_DRV_2 (2 << GPIO_DRV_SHIFT)
4 #define GPIO_DRV_3 (3 << GPIO_DRV_SHIFT)
gpio int trig mode
gpio 外部中断触发模式。
1 #define GPIO_INT_TRIG_MODE_SYNC_FALLING_EDGE 0
2 #define GPIO_INT_TRIG_MODE_SYNC_RISING_EDGE 1
3 #define GPIO_INT_TRIG_MODE_SYNC_LOW_LEVEL 2
4 #define GPIO_INT_TRIG_MODE_SYNC_HIGH_LEVEL 3
5 #if defined(BL702)
6 #define GPIO_INT_TRIG_MODE_ASYNC_FALLING_EDGE 4
7 #define GPIO_INT_TRIG_MODE_ASYNC_RISING_EDGE 5
8 #define GPIO_INT_TRIG_MODE_ASYNC_LOW_LEVEL 6
9 #define GPIO_INT_TRIG_MODE_ASYNC_HIGH_LEVEL 7
10 #else
11 #define GPIO_INT_TRIG_MODE_SYNC_FALLING_RISING_EDGE 4
12 #define GPIO_INT_TRIG_MODE_ASYNC_FALLING_EDGE 8
13 #define GPIO_INT_TRIG_MODE_ASYNC_RISING_EDGE 9
14 #define GPIO_INT_TRIG_MODE_ASYNC_LOW_LEVEL 10
15 #define GPIO_INT_TRIG_MODE_ASYNC_HIGH_LEVEL 11
16 #endif
警告
602、702 不支持双边沿
gpio uart function
博流系列芯片,每个 gpio 可以选择到 UART 的任意一个功能。
1 #define GPIO_UART_FUNC_UART0_RTS 0
2 #define GPIO_UART_FUNC_UART0_CTS 1
3 #define GPIO_UART_FUNC_UART0_TX 2
4 #define GPIO_UART_FUNC_UART0_RX 3
5 #define GPIO_UART_FUNC_UART1_RTS 4
6 #define GPIO_UART_FUNC_UART1_CTS 5
7 #define GPIO_UART_FUNC_UART1_TX 6
8 #define GPIO_UART_FUNC_UART1_RX 7
9 #if defined(BL808) || defined(BL606P)
10 #define GPIO_UART_FUNC_UART2_RTS 8
11 #define GPIO_UART_FUNC_UART2_CTS 9
12 #define GPIO_UART_FUNC_UART2_TX 10
13 #define GPIO_UART_FUNC_UART2_RX 11
14 #endif
Structs
无
Functions
bflb_gpio_init
说明: 初始化 gpio。如果配置为 UART 功能,请使用 bflb_gpio_uart_init 。
1 void bflb_gpio_init(struct bflb_device_s *dev, uint8_t pin, uint32_t cfgset);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
cfgset |
gpio 配置项:gpio mode、gpio function、gpio pupd、gpio smt、gpio drive,多个配置需要使用 | 连接 |
bflb_gpio_deinit
说明: 反初始化 gpio,默认为输入浮空状态
1 void bflb_gpio_deinit(struct bflb_device_s *dev, uint8_t pin);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
bflb_gpio_set
说明: gpio 输出高电平
1 void bflb_gpio_set(struct bflb_device_s *dev, uint8_t pin);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
bflb_gpio_reset
说明: gpio 输出低电平
1 void bflb_gpio_reset(struct bflb_device_s *dev, uint8_t pin);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
bflb_gpio_read
说明: 读取 gpio 电平
1 bool bflb_gpio_read(struct bflb_device_s *dev, uint8_t pin);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
return |
true 为 高电平,false 为低电平 |
bflb_gpio_int_init
说明: gpio 外部中断初始化
1 void bflb_gpio_int_init(struct bflb_device_s *dev, uint8_t pin, uint8_t trig_mode);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
trig_mode |
中断触发模式 |
bflb_gpio_int_mask
说明: gpio 外部中断屏蔽开关
1 void bflb_gpio_int_mask(struct bflb_device_s *dev, uint8_t pin, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
mask |
是否屏蔽中断 |
bflb_gpio_get_intstatus
说明: 获取 gpio 外部中断是否触发的标志
1 bool bflb_gpio_get_intstatus(struct bflb_device_s *dev, uint8_t pin);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
return |
为 true 表示触发 |
bflb_gpio_int_clear
说明: 清除 gpio 中断标志
1 void bflb_gpio_int_clear(struct bflb_device_s *dev, uint8_t pin);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
bflb_gpio_uart_init
说明: gpio 配置成 uart 的某一个功能。
1 void bflb_gpio_uart_init(struct bflb_device_s *dev, uint8_t pin, uint8_t uart_func);
parameter |
description |
---|---|
dev |
设备句柄 |
pin |
gpio pin |
uart_func |
uart 具体某一个功能 |
I2C
Macros
无
Structs
struct bflb_i2c_msg_s
i2c 传输时需要填充的消息。
1 struct bflb_i2c_msg_s {
2 uint16_t addr;
3 uint16_t flags;
4 uint8_t *buffer;
5 uint16_t length;
6 };
parameter |
description |
---|---|
addr |
设备地址(7 位或者 10 位) |
flags |
传输时附带标志 |
buffer |
数据区 |
length |
数据长度 |
flag 可以为以下参数:
1#define I2C_M_READ 0x0001
2#define I2C_M_TEN 0x0002
3#define I2C_M_DMA 0x0004
4#define I2C_M_NOSTOP 0x0040
5#define I2C_M_NOSTART 0x0080
备注
I2C_M_NOSTOP 表示 i2c 设备需要操作寄存器地址
Functions
bflb_i2c_init
说明: 初始化 i2c 并配置频率。
1 void bflb_i2c_init(struct bflb_device_s *dev, uint32_t frequency);
parameter |
description |
---|---|
dev |
设备句柄 |
frequency |
配置频率(范围 305 HZ ~ 400KHZ) |
bflb_i2c_deinit
说明: 反初始化 i2c。
1 void bflb_i2c_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_i2c_link_txdma
说明: i2c 发送 dma 使能开关。
1 void bflb_i2c_link_txdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否使能 dma |
bflb_i2c_link_rxdma
说明: i2c 接收 dma 使能开关。
1 void bflb_i2c_link_rxdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否使能 dma |
bflb_i2c_transfer
说明: i2c 消息传输。
1 int bflb_i2c_transfer(struct bflb_device_s *dev, struct bflb_i2c_msg_s *msgs, int count);
parameter |
description |
---|---|
dev |
设备句柄 |
msgs |
消息指针 |
count |
消息个数 |
IRQ
Macros
无
Structs
无
Functions
bflb_irq_initialize
说明: 中断控制器初始化,清除所有中断和中断 pending。
1 void bflb_irq_initialize(void);
bflb_irq_save
说明: 关闭全局中断并保存之前的状态。
1uintptr_t bflb_irq_save(void);
parameter |
description |
---|---|
return |
返回关闭之前的状态 |
bflb_irq_restore
说明: 恢复关闭全局中断之前的状态。
1void bflb_irq_restore(uintptr_t flags);
parameter |
description |
---|---|
flags |
关闭之前的状态 |
bflb_irq_attach
说明: 注册中断入口函数。
1 int bflb_irq_attach(int irq, irq_callback isr, void *arg);
parameter |
description |
---|---|
flags |
关闭之前的状态 |
bflb_irq_detach
说明: 取消中断函数注册。
1 int bflb_irq_detach(int irq);
parameter |
description |
---|---|
flags |
关闭之前的状态 |
bflb_irq_enable
说明: 开启中断。
1 void bflb_irq_enable(int irq);
parameter |
description |
---|---|
irq |
中断号 |
bflb_irq_disable
说明: 关闭中断。
1 void bflb_irq_disable(int irq);
parameter |
description |
---|---|
irq |
中断号 |
bflb_irq_set_pending
说明: 设置中断 pending 位。
1 void bflb_irq_set_pending(int irq);
parameter |
description |
---|---|
irq |
中断号 |
bflb_irq_clear_pending
说明: 清除中断 pending 位。
1 void bflb_irq_clear_pending(int irq);
parameter |
description |
---|---|
irq |
中断号 |
bflb_irq_set_nlbits
说明: 设置中断分组。
1 void bflb_irq_set_nlbits(uint8_t nlbits);
parameter |
description |
---|---|
irq |
中断号 |
bflb_irq_set_priority
说明: 设置中断优先级。
1 void bflb_irq_set_priority(int irq, uint8_t preemptprio, uint8_t subprio);
parameter |
description |
---|---|
irq |
中断号 |
preemptprio |
抢占优先级 |
subprio |
子优先级 |
L1C
Macros
无
Structs
无
Functions
bflb_l1c_icache_enable
说明: 开启 icache。
1 void bflb_l1c_icache_enable(void);
bflb_l1c_icache_disable
说明: 关闭 icache。
1 void bflb_l1c_icache_disable(void);
bflb_l1c_dcache_enable
说明: 开启 dcache。
1 void bflb_l1c_dcache_enable(void);
bflb_l1c_dcache_disable
说明: 关闭 dcache。
1 void bflb_l1c_dcache_disable(void);
bflb_l1c_dcache_clean_range
说明: clean 一段数据到内存中。
1 void bflb_l1c_dcache_clean_range(unsigned long addr, uint32_t len);
parameter |
description |
---|---|
addr |
首地址(必须 32 字节对齐) |
len |
长度 |
bflb_l1c_dcache_invalidate_range
说明: 将 cache 中的数据置为 dity。
1 void bflb_l1c_dcache_invalidate_range(unsigned long addr, uint32_t len);
parameter |
description |
---|---|
addr |
首地址(必须 32 字节对齐) |
len |
长度 |
bflb_l1c_dcache_clean_invalidate_range
说明: clean 一段数据到内存中,并使 cache 中的数据失效。
1 void bflb_l1c_dcache_clean_invalidate_range(unsigned long addr, uint32_t len);
parameter |
description |
---|---|
addr |
首地址(必须 32 字节对齐) |
len |
长度 |
MTIMER
Macros
无
Structs
无
Functions
bflb_mtimer_config
说明: mtimer 定时配置。
1void bflb_mtimer_config(uint64_t ticks, void (*interruptfun)(void));
parameter |
description |
---|---|
ticks |
定时 tick 数 |
interruptfun |
中断回调 |
bflb_mtimer_get_freq
说明: 获取 mtimer 频率。默认 mtimer 经过分频后设置成了 1M,所以频率就是 1M。
1uint32_t bflb_mtimer_get_freq(void);
parameter |
description |
---|---|
return |
频率 |
bflb_mtimer_delay_ms
说明: mtimer 毫秒延时。
1void bflb_mtimer_delay_ms(uint32_t time);
parameter |
description |
---|---|
time |
延时时间 |
bflb_mtimer_delay_us
说明: mtimer 微妙延时。
1void bflb_mtimer_delay_us(uint32_t time);
parameter |
description |
---|---|
time |
延时时间 |
bflb_mtimer_get_time_us
说明: 获取 mtimer 当前时间,us 为单位。
1uint64_t bflb_mtimer_get_time_us();
parameter |
description |
---|---|
return |
当前时间 |
bflb_mtimer_get_time_ms
说明: 获取 mtimer 当前时间,ms 为单位。
1uint64_t bflb_mtimer_get_time_ms();
parameter |
description |
---|---|
return |
当前时间 |
PWM_v1
备注
PWM V1 版本每个 PWM 的所有通道频率可以单独设置。
Macros
pwm channel
PWM V1 版本共 5 个 pwm 通道。(BL702L 只有通道 0)。
Structs
struct bflb_pwm_v1_channel_config_s
pwm v1 初始化配置结构体。
1 struct bflb_pwm_v1_channel_config_s {
2 uint8_t clk_source;
3 uint16_t clk_div;
4 uint16_t period;
5 };
parameter |
description |
---|---|
clk_source |
时钟源选择:PBCLK or XCLK or 32K_CLK |
clk_div |
分频值 |
period |
周期值 |
备注
PWM 最终产生的频率 = clk_source/clk_div/period
Functions
bflb_pwm_v1_channel_init
说明: 初始化 pwm 通道。使用之前需要选择 gpio 为 pwm 功能。
1void bflb_pwm_v1_channel_init(struct bflb_device_s *dev, uint8_t ch, const struct bflb_pwm_v1_channel_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
config |
配置项 |
bflb_pwm_v1_channel_deinit
说明: 复位 pwm 通道。
1void bflb_pwm_v1_channel_deinit(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
bflb_pwm_v1_start
说明: 启动 pwm 通道输出。
1void bflb_pwm_v1_start(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
bflb_pwm_v1_stop
说明: 关闭 pwm 通道输出。
1void bflb_pwm_v1_stop(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
bflb_pwm_v1_set_period
说明: 修改 pwm 通道周期值,从而更改 pwm 通道输出的频率。
1void bflb_pwm_v1_set_period(struct bflb_device_s *dev, uint8_t ch, uint16_t period);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
period |
周期值 |
bflb_pwm_v1_channel_set_threshold
说明: 设置 pwm 占空比。
1void bflb_pwm_v1_channel_set_threshold(struct bflb_device_s *dev, uint8_t ch, uint16_t low_threhold, uint16_t high_threhold);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
low_threhold |
低阈值 |
high_threhold |
高阈值,需要大于 low_threhold,并且小于等于 period |
备注
PWM 占空比 = (high_threhold - low_threhold)/period
PWM_v2
备注
PWM V2 版本每个 PWM 的所有通道共用一个频率。
Macros
pwm channel
PWM V2 版本每个 PWM 共 4 个 pwm 通道。
pwm polarity
PWM V2 版本输出有效极性。当正向通道阈值位于设置的低阈值和高阈值之间,为有效极性,如果设置有效极性为高,则输出高电平,反之输出低电平。反向通道相反,阈值位于设置的低阈值和高阈值之外,为有效极性,如果设置有效极性为高,则输出高电平,反之输出低电平。
1#define PWM_POLARITY_ACTIVE_LOW 0
2#define PWM_POLARITY_ACTIVE_HIGH 1
Structs
struct bflb_pwm_v2_config_s
pwm v2 初始化配置结构体。
1 struct bflb_pwm_v2_config_s {
2 uint8_t clk_source;
3 uint16_t clk_div;
4 uint16_t period;
5 };
parameter |
description |
---|---|
clk_source |
时钟源选择:PBCLK or XCLK or 32K_CLK |
clk_div |
分频值 |
period |
周期值 |
备注
PWM 最终产生的频率 = clk_source/clk_div/period
struct bflb_pwm_v2_channel_config_s
pwm v2 初始化配置结构体。
1 struct bflb_pwm_v2_channel_config_s {
2 uint8_t positive_polarity;
3 uint8_t negative_polarity;
4 uint8_t positive_stop_state;
5 uint8_t negative_stop_state;
6 uint8_t positive_brake_state;
7 uint8_t negative_brake_state;
8 uint8_t dead_time;
9 };
parameter |
description |
---|---|
positive_polarity |
正向输出极性 |
negative_polarity |
反向输出极性 |
positive_stop_state |
正向输出空闲状态 |
negative_stop_state |
反向输出空闲状态 |
positive_brake_state |
正向输出刹车状态 |
negative_brake_state |
反向输出刹车状态 |
dead_time |
死区时间 |
Functions
bflb_pwm_v2_init
说明: 初始化 pwm 。使用之前需要选择 gpio 为 pwm 功能。
1void bflb_pwm_v2_init(struct bflb_device_s *dev, const struct bflb_pwm_v2_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
config |
配置项 |
bflb_pwm_v2_deinit
说明: 复位 pwm 。
1void bflb_pwm_v2_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_pwm_v2_start
说明: 启动 pwm 输出。
1void bflb_pwm_v2_start(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_pwm_v2_stop
说明: 关闭 pwm 输出。
1void bflb_pwm_v2_stop(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_pwm_v2_set_period
说明: 修改 pwm 周期值,从而更改 pwm 输出的频率。
1void bflb_pwm_v2_set_period(struct bflb_device_s *dev, uint16_t period);
parameter |
description |
---|---|
dev |
设备句柄 |
period |
周期值 |
bflb_pwm_v2_channel_init
说明: PWM 通道初始化。
1void bflb_pwm_v2_channel_init(struct bflb_device_s *dev, uint8_t ch, struct bflb_pwm_v2_channel_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
config |
通道配置 |
bflb_pwm_v2_channel_set_threshold
说明: 设置 PWM 占空比。
1void bflb_pwm_v2_channel_set_threshold(struct bflb_device_s *dev, uint8_t ch, uint16_t low_threhold, uint16_t high_threhold);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
low_threhold |
低阈值 |
high_threhold |
高阈值,需要大于 low_threhold,并且小于等于 period |
备注
PWM 占空比 = (high_threhold - low_threhold)/period
bflb_pwm_v2_channel_positive_start
说明: PWM 正向通道使能输出。
1void bflb_pwm_v2_channel_positive_start(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
bflb_pwm_v2_channel_negative_start
说明: PWM 反向通道使能输出。
1void bflb_pwm_v2_channel_negative_start(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
bflb_pwm_v2_channel_positive_stop
说明: PWM 正向通道停止输出。
1void bflb_pwm_v2_channel_positive_stop(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
bflb_pwm_v2_channel_negative_stop
说明: PWM 反向通道停止输出。
1void bflb_pwm_v2_channel_negative_stop(struct bflb_device_s *dev, uint8_t ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
通道号 |
bflb_pwm_v2_int_enable
说明: PWM 中断使能和关闭。
1void bflb_pwm_v2_int_enable(struct bflb_device_s *dev, uint32_t int_en, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
int_en |
中断使能位 |
enable |
是否开启中断 |
int_en 可以填入以下值,多个中断可以使用 | 连接:
1#define PWM_INTEN_CH0_L (1 << 0)
2#define PWM_INTEN_CH0_H (1 << 1)
3#define PWM_INTEN_CH1_L (1 << 2)
4#define PWM_INTEN_CH1_H (1 << 3)
5#define PWM_INTEN_CH2_L (1 << 4)
6#define PWM_INTEN_CH2_H (1 << 5)
7#define PWM_INTEN_CH3_L (1 << 6)
8#define PWM_INTEN_CH3_H (1 << 7)
9#define PWM_INTEN_PERIOD (1 << 8)
10#define PWM_INTEN_BRAKE (1 << 9)
11#define PWM_INTEN_REPT (1 << 10)
bflb_pwm_v2_get_intstatus
说明: 获取 PWM 中断标志。
1uint32_t bflb_pwm_v2_get_intstatus(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
返回中断标志 |
返回值如下:
1#define PWM_INTSTS_CH0_L (1 << 0)
2#define PWM_INTSTS_CH0_H (1 << 1)
3#define PWM_INTSTS_CH1_L (1 << 2)
4#define PWM_INTSTS_CH1_H (1 << 3)
5#define PWM_INTSTS_CH2_L (1 << 4)
6#define PWM_INTSTS_CH2_H (1 << 5)
7#define PWM_INTSTS_CH3_L (1 << 6)
8#define PWM_INTSTS_CH3_H (1 << 7)
9#define PWM_INTSTS_PERIOD (1 << 8)
10#define PWM_INTSTS_BRAKE (1 << 9)
11#define PWM_INTSTS_REPT (1 << 10)
bflb_pwm_v2_int_clear
说明: 清除 PWM 中断标志。
1void bflb_pwm_v2_int_clear(struct bflb_device_s *dev, uint32_t int_clear);
parameter |
description |
---|---|
dev |
设备句柄 |
int_clear |
清除值 |
int_clear 可以填入以下参数:
1#define PWM_INTCLR_CH0_L (1 << 0)
2#define PWM_INTCLR_CH0_H (1 << 1)
3#define PWM_INTCLR_CH1_L (1 << 2)
4#define PWM_INTCLR_CH1_H (1 << 3)
5#define PWM_INTCLR_CH2_L (1 << 4)
6#define PWM_INTCLR_CH2_H (1 << 5)
7#define PWM_INTCLR_CH3_L (1 << 6)
8#define PWM_INTCLR_CH3_H (1 << 7)
9#define PWM_INTCLR_PERIOD (1 << 8)
10#define PWM_INTCLR_BRAKE (1 << 9)
11#define PWM_INTCLR_REPT (1 << 10)
bflb_pwm_v2_feature_control
说明: PWM 其他特性相关控制,一般不常用。
1 int bflb_pwm_v2_feature_control(struct bflb_device_s *dev, int cmd, size_t arg);
parameter |
description |
---|---|
dev |
设备句柄 |
cmd |
控制字 |
arg |
控制参数 |
return |
负值表示不支持此命令 |
cmd 可以填入以下参数:
1#define PWM_CMD_SET_TRIG_ADC_SRC (0x01)
2#define PWM_CMD_SET_EXT_BRAKE_POLARITY (0x02)
3#define PWM_CMD_SET_EXT_BRAKE_ENABLE (0x03)
4#define PWM_CMD_SET_SW_BRAKE_ENABLE (0x04)
5#define PWM_CMD_SET_STOP_ON_REPT (0x05)
6#define PWM_CMD_SET_REPT_COUNT (0x06)
RTC
Macros
BFLB_RTC_SEC2TIME
将秒转换成 RTC 时间
BFLB_RTC_TIME2SEC
将 RTC 时间转换成秒
Structs
无
Functions
bflb_rtc_set_time
说明: 设置 RTC 时间。
1 void bflb_rtc_set_time(struct bflb_device_s *dev, uint64_t time);
parameter |
description |
---|---|
dev |
设备句柄 |
time |
RTC 时间(单位: 1/32768 s) |
bflb_rtc_get_time
说明: 获取 RTC 时间。
1 uint64_t bflb_rtc_get_time(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
RTC 时间(单位: 1/32768 s) |
SEC_AES
Macros
无
Structs
无
Functions
SEC_SHA
Macros
无
Structs
无
Functions
SEC_PKA
Macros
无
Structs
无
Functions
SPI
Macros
spi role
spi 支持主从角色。
1 #define SPI_ROLE_MASTER 0
2 #define SPI_ROLE_SLAVE 1
spi mode
spi 支持 4 种工作模式。
1 #define SPI_DEV_MODE0 0 /* CPOL=0 CHPHA=0 */
2 #define SPI_DEV_MODE1 1 /* CPOL=0 CHPHA=1 */
3 #define SPI_DEV_MODE2 2 /* CPOL=1 CHPHA=0 */
4 #define SPI_DEV_MODE3 3 /* CPOL=1 CHPHA=1 */
spi data_width
spi 支持 4 种位宽。
1 #define SPI_DATA_WIDTH_8BIT 0
2 #define SPI_DATA_WIDTH_16BIT 1
3 #define SPI_DATA_WIDTH_24BIT 2
4 #define SPI_DATA_WIDTH_32BIT 3
spi bit_order
spi bit 先行方式。
1 #define SPI_BIT_LSB 1
2 #define SPI_BIT_MSB 0
spi byte_order
spi 字节先行方式。
1 #define SPI_BYTE_LSB 0
2 #define SPI_BYTE_MSB 1
Structs
struct bflb_spi_config_s
spi 初始化配置结构体。
1 struct bflb_spi_config_s {
2 uint32_t freq;
3 uint8_t role;
4 uint8_t mode;
5 uint8_t data_width;
6 uint8_t bit_order;
7 uint8_t byte_order;
8 uint8_t tx_fifo_threshold;
9 uint8_t rx_fifo_threshold;
10 };
parameter |
description |
---|---|
freq |
频率(BL702 不得超过32M,其他芯片不得超过 40M) |
role |
主从选择 |
mode |
工作模式 |
data_width |
数据宽度 |
bit_order |
bit 先行方式 |
byte_order |
字节先行方式 |
tx_fifo_threshold |
发送 fifo 中断触发阈值(大于阈值触发中断) |
rx_fifo_threshold |
接收 fifo 中断触发阈值(大于阈值触发中断) |
备注
SPI 阈值最大为 16
Functions
bflb_spi_init
说明: 初始化 spi。使用之前需要开启 spi ip 时钟、设置 spi 时钟源和分频值、选择 gpio 为 spi 功能。
1 void bflb_spi_init(struct bflb_device_s *dev, const struct bflb_spi_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
config |
配置项 |
bflb_spi_deinit
说明: 反初始化 spi。
1 void bflb_spi_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_spi_link_txdma
说明: spi tx dma 使能开关。
1 void bflb_spi_link_txdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否使能 dma |
bflb_spi_link_rxdma
说明: spi rx dma 使能开关。
1 void bflb_spi_link_rxdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否使能 dma |
bflb_spi_poll_send
说明: 通过 spi 阻塞式发送一个数据并接收一个数据。
1 uint32_t bflb_spi_poll_send(struct bflb_device_s *dev, uint32_t data);
parameter |
description |
---|---|
dev |
设备句柄 |
data |
发送的数据(可以为字节、字、双字) |
return |
接收的数据(可以为字节、字、双字) |
bflb_spi_poll_exchange
说明: 通过 spi 阻塞式发送一段数据并接收一段数据。
1 int bflb_spi_poll_exchange(struct bflb_device_s *dev, const void *txbuffer, void *rxbuffer, size_t nbyte);
parameter |
description |
---|---|
dev |
设备句柄 |
txbuffer |
发送缓冲区 |
rxbuffer |
接收缓冲区 |
nbyte |
数据长度 |
bflb_spi_txint_mask
说明: spi tx fifo 阈值中断屏蔽开关,开启后超过设定阈值则触发中断。
1 void bflb_spi_txint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_spi_rxint_mask
说明: spi rx fifo 阈值中断和超时屏蔽开关,开启后超过设定阈值则或者超时则触发中断。
1 void bflb_spi_rxint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_spi_errint_mask
说明: spi 错误中断屏蔽开关。
1 void bflb_spi_errint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_spi_get_intstatus
说明: 获取 spi 中断标志。
1 uint32_t bflb_spi_get_intstatus(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
中断标志 |
中断标志有以下选项:
1#define SPI_INTSTS_TC (1 << 0)
2#define SPI_INTSTS_TX_FIFO (1 << 1)
3#define SPI_INTSTS_RX_FIFO (1 << 2)
4#define SPI_INTSTS_SLAVE_TIMEOUT (1 << 3)
5#define SPI_INTSTS_SLAVE_TX_UNDERRUN (1 << 4)
6#define SPI_INTSTS_FIFO_ERR (1 << 5)
bflb_spi_int_clear
说明: 清除 spi 中断标志。
1 void bflb_spi_int_clear(struct bflb_device_s *dev, uint32_t int_clear);
parameter |
description |
---|---|
dev |
设备句柄 |
int_clear |
清除值 |
int_clear 可以填入以下参数:
1#define SPI_INTCLR_TC (1 << 16)
2#define SPI_INTCLR_SLAVE_TIMEOUT (1 << 19)
3#define SPI_INTCLR_SLAVE_TX_UNDERRUN (1 << 20)
bflb_spi_feature_control
说明: spi 其他特性相关控制,一般不常用。
1 int bflb_spi_feature_control(struct bflb_device_s *dev, int cmd, size_t arg);
parameter |
description |
---|---|
dev |
设备句柄 |
cmd |
控制字 |
arg |
控制参数 |
return |
负值表示不支持此命令 |
cmd 可以填入以下参数:
1#define SPI_CMD_SET_DATA_WIDTH (0x01)
2#define SPI_CMD_GET_DATA_WIDTH (0x02)
3#define SPI_CMD_CLEAR_TX_FIFO (0x03)
4#define SPI_CMD_CLEAR_RX_FIFO (0x04)
5#define SPI_CMD_SET_CS_INTERVAL (0x05)
TIMER
Macros
timer clock source
定时器输入时钟源可以选择以下类型,注意: TIMER_CLKSRC_GPIO BL602/BL702 系列没有此功能。
1#define TIMER_CLKSRC_BCLK 0
2#define TIMER_CLKSRC_32K 1
3#define TIMER_CLKSRC_1K 2
4#define TIMER_CLKSRC_XTAL 3
5#define TIMER_CLKSRC_GPIO 4
6#define TIMER_CLKSRC_NO 5
timer counter mode
定时器计数模式分为两种: freerun(向上计数模式)、preload(重装载模式)。
1 #define TIMER_COUNTER_MODE_PROLOAD 0
2 #define TIMER_COUNTER_MODE_UP 1
timer compare id
定时器一共三个 compare id, 用于设置不同的定时时间,可以当三个定时器使用。
1 #define TIMER_COMP_ID_0 0
2 #define TIMER_COMP_ID_1 1
3 #define TIMER_COMP_ID_2 2
Structs
struct bflb_timer_config_s
timer 初始化配置结构体。
1 struct bflb_timer_config_s {
2 uint8_t counter_mode;
3 uint8_t clock_source;
4 uint8_t clock_div;
5 uint8_t trigger_comp_id;
6 uint32_t comp0_val;
7 uint32_t comp1_val;
8 uint32_t comp2_val;
9 uint32_t preload_val;
10 };
parameter |
description |
---|---|
counter_mode |
计数模式 |
clock_source |
时钟源选择 |
clock_div |
分频值 |
trigger_comp_id |
选择触发的最高 comp id(选择越高,则能够定时的个数越多) |
comp0_val |
comp0 比较值 |
comp1_val |
comp1 比较值(需要大于 comp0_val) |
comp2_val |
comp2 比较值(需要大于 comp1_val) |
preload_val |
重装载值 |
Functions
bflb_timer_init
说明: 初始化 timer。使用之前需要开启 timer ip 时钟。
1 void bflb_timer_init(struct bflb_device_s *dev, const struct bflb_timer_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
config |
配置项 |
bflb_timer_deinit
说明: 反初始化 timer。
1 void bflb_timer_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_timer_start
说明: 启动 timer 。
1 void bflb_timer_start(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_timer_stop
说明: 停止 timer。
1 void bflb_timer_stop(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_timer_set_compvalue
说明: 设置 timer comp id 比较值。
1 void bflb_timer_set_compvalue(struct bflb_device_s *dev, uint8_t cmp_no, uint32_t val);
parameter |
description |
---|---|
dev |
设备句柄 |
cmp_no |
comp id |
val |
比较值 |
bflb_timer_get_compvalue
说明: 获取 comp id 比较值。
1 uint32_t bflb_timer_get_compvalue(struct bflb_device_s *dev, uint8_t cmp_no);
parameter |
description |
---|---|
dev |
设备句柄 |
cmp_no |
comp id |
return |
比较值 |
bflb_timer_get_countervalue
说明: 获取 timer 计数值。
1 uint32_t bflb_timer_get_countervalue(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
计数值 |
bflb_timer_compint_mask
说明: timer comp 中断屏蔽开关。
1 void bflb_timer_compint_mask(struct bflb_device_s *dev, uint8_t cmp_no, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
cmp_no |
comp id |
mask |
是否屏蔽中断 |
bflb_timer_get_compint_status
说明: 获取 timer comp id 中断匹配标志。
1 bool bflb_timer_get_compint_status(struct bflb_device_s *dev, uint8_t cmp_no);
parameter |
description |
---|---|
dev |
设备句柄 |
cmp_no |
comp id |
return |
为 true 表示匹配 |
bflb_timer_compint_clear
说明: 清除 timer comp id 中断标志。
1 void bflb_timer_compint_clear(struct bflb_device_s *dev, uint8_t cmp_no);
parameter |
description |
---|---|
dev |
设备句柄 |
cmp_no |
comp id |
UART
Macros
uart direction
UART 方向可以设置为 TX、RX、TXRX
uart databits
1 #define UART_DATA_BITS_5 0
2 #define UART_DATA_BITS_6 1
3 #define UART_DATA_BITS_7 2
4 #define UART_DATA_BITS_8 3
5 #define UART_DATA_BITS_9 4
uart stopbits
1 #define UART_STOP_BITS_0_5 0
2 #define UART_STOP_BITS_1 1
3 #define UART_STOP_BITS_1_5 2
4 #define UART_STOP_BITS_2 3
uart parity
1 #define UART_PARITY_NONE 0
2 #define UART_PARITY_ODD 1
3 #define UART_PARITY_EVEN 2
4 #define UART_PARITY_MARK 3
5 #define UART_PARITY_SPACE 4
uart bit order
1 #define UART_LSB_FIRST 0
2 #define UART_MSB_FIRST 1
Structs
struct bflb_uart_config_s
uart 初始化配置结构体。
1 struct bflb_uart_config_s {
2 uint32_t baudrate;
3 uint8_t direction;
4 uint8_t data_bits;
5 uint8_t stop_bits;
6 uint8_t parity;
7 uint8_t bit_order;
8 uint8_t flow_ctrl;
9 uint8_t tx_fifo_threshold;
10 uint8_t rx_fifo_threshold;
11 };
parameter |
description |
---|---|
baudrate |
波特率 |
direction |
方向 |
data_bits |
数据位 |
stop_bits |
停止位 |
parity |
校验位 |
bit_order |
bit 先行方式 |
flow_ctrl |
流控 |
tx_fifo_threshold |
发送 fifo 中断触发阈值(大于阈值触发中断) |
rx_fifo_threshold |
接收 fifo 中断触发阈值(大于阈值触发中断) |
备注
BL702 阈值为 128, 其他芯片为 32
Functions
bflb_uart_init
说明: 初始化 uart。使用之前需要开启 uart ip 时钟、设置 uart 时钟源和分频值、选择 gpio 为 uart 中的一个功能。
1 void bflb_uart_init(struct bflb_device_s *dev, const struct bflb_uart_config_s *config);
parameter |
description |
---|---|
dev |
设备句柄 |
config |
配置项 |
bflb_uart_deinit
说明: 反初始化 uart。
1 void bflb_uart_deinit(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
bflb_uart_link_txdma
说明: uart tx dma 使能开关。
1 void bflb_uart_link_txdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否使能 dma |
bflb_uart_link_rxdma
说明: uart rx dma 使能开关。
1 void bflb_uart_link_rxdma(struct bflb_device_s *dev, bool enable);
parameter |
description |
---|---|
dev |
设备句柄 |
enable |
是否使能 dma |
bflb_uart_putchar
说明: 通过 uart 阻塞式发送一个字符。
1 void bflb_uart_putchar(struct bflb_device_s *dev, int ch);
parameter |
description |
---|---|
dev |
设备句柄 |
ch |
字符 |
bflb_uart_getchar
说明: 通过 uart 异步接收一个字符。
1 int bflb_uart_getchar(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
返回 -1 表示没有数据,返回其他表示接收的字符 |
bflb_uart_txready
说明: 查询 uart tx fifo 是否准备就绪,准备好才可以填充字符。
1 bool bflb_uart_txready(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
为 true 表示就绪 |
bflb_uart_txempty
说明: 查询 uart tx fifo 是否为空。
1 bool bflb_uart_txempty(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
为 true 表示 fifo 已空,无法填充数据 |
bflb_uart_rxavailable
说明: 查询 uart rx 是否有数据。
1 bool bflb_uart_rxavailable(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
为 true 表示有数据,可以进行读取 |
bflb_uart_txint_mask
说明: uart tx fifo 阈值中断屏蔽开关,开启后超过设定阈值则触发中断。
1 void bflb_uart_txint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_uart_rxint_mask
说明: uart rx fifo 阈值中断和超时屏蔽开关,开启后超过设定阈值则或者超时则触发中断。
1 void bflb_uart_rxint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_uart_errint_mask
说明: uart 错误中断屏蔽开关。
1 void bflb_uart_errint_mask(struct bflb_device_s *dev, bool mask);
parameter |
description |
---|---|
dev |
设备句柄 |
mask |
是否屏蔽中断 |
bflb_uart_get_intstatus
说明: 获取 uart 中断标志。
1 uint32_t bflb_uart_get_intstatus(struct bflb_device_s *dev);
parameter |
description |
---|---|
dev |
设备句柄 |
return |
中断标志 |
中断标志有以下选项:
1#define UART_INTSTS_TX_END (1 << 0)
2#define UART_INTSTS_RX_END (1 << 1)
3#define UART_INTSTS_TX_FIFO (1 << 2)
4#define UART_INTSTS_RX_FIFO (1 << 3)
5#define UART_INTSTS_RTO (1 << 4)
6#define UART_INTSTS_PCE (1 << 5)
7#define UART_INTSTS_TX_FER (1 << 6)
8#define UART_INTSTS_RX_FER (1 << 7)
9#if !defined(BL602)
10#define UART_INTSTS_RX_LSE (1 << 8)
11#endif
12#if !defined(BL602) && !defined(BL702)
13#define UART_INTSTS_RX_BCR (1 << 9)
14#define UART_INTSTS_RX_ADS (1 << 10)
15#define UART_INTSTS_RX_AD5 (1 << 11)
16#endif
bflb_uart_int_clear
说明: 清除 uart 中断标志。
1 void bflb_uart_int_clear(struct bflb_device_s *dev, uint32_t int_clear);
parameter |
description |
---|---|
dev |
设备句柄 |
int_clear |
清除值 |
int_clear 可以填入以下参数:
1#define UART_INTCLR_TX_END (1 << 0)
2#define UART_INTCLR_RX_END (1 << 1)
3#define UART_INTCLR_RTO (1 << 4)
4#define UART_INTCLR_PCE (1 << 5)
5#if !defined(BL602)
6#define UART_INTCLR_RX_LSE (1 << 8)
7#endif
8#if !defined(BL602) && !defined(BL702)
9#define UART_INTCLR_RX_BCR (1 << 9)
10#define UART_INTCLR_RX_ADS (1 << 10)
11#define UART_INTCLR_RX_AD5 (1 << 11)
12#endif
bflb_uart_feature_control
说明: uart 其他特性相关控制,一般不常用。
1 int bflb_uart_feature_control(struct bflb_device_s *dev, int cmd, size_t arg);
parameter |
description |
---|---|
dev |
设备句柄 |
cmd |
控制字 |
arg |
控制参数 |
return |
负值表示不支持此命令 |
cmd 可以填入以下参数:
1#define UART_CMD_SET_BAUD_RATE (0x01)
2#define UART_CMD_SET_DATA_BITS (0x02)
3#define UART_CMD_SET_STOP_BITS (0x03)
4#define UART_CMD_SET_PARITY_BITS (0x04)
5#define UART_CMD_CLR_TX_FIFO (0x05)
6#define UART_CMD_CLR_RX_FIFO (0x06)
7#define UART_CMD_SET_RTO_VALUE (0x07)
8#define UART_CMD_SET_RTS_VALUE (0x08)
9#define UART_CMD_GET_TX_FIFO_CNT (0x09)
10#define UART_CMD_GET_RX_FIFO_CNT (0x0a)
11#define UART_CMD_SET_AUTO_BAUD (0x0b)
12#define UART_CMD_GET_AUTO_BAUD (0x0c)
13#define UART_CMD_SET_BREAK_VALUE (0x0d)
14#define UART_CMD_SET_TX_LIN_VALUE (0x0e)
15#define UART_CMD_SET_RX_LIN_VALUE (0x0f)
16#define UART_CMD_SET_TX_RX_EN (0x10)
17#define UART_CMD_SET_TX_RS485_EN (0x11)
18#define UART_CMD_SET_TX_RS485_POLARITY (0x12)
19#define UART_CMD_SET_ABR_ALLOWABLE_ERROR (0x13)
20#define UART_CMD_SET_SW_RTS_CONTROL (0x14)
21#define UART_CMD_IR_CONFIG (0x15)
22#define UART_CMD_SET_TX_FREERUN (0x16)
23#define UART_CMD_SET_TX_END_INTERRUPT (0x17)
24#define UART_CMD_SET_RX_END_INTERRUPT (0x18)
25#define UART_CMD_SET_TX_TRANSFER_LEN (0x19)
26#define UART_CMD_SET_RX_TRANSFER_LEN (0x20)
27#define UART_CMD_SET_TX_EN (0x21)
28#define UART_CMD_SET_BCR_END_INTERRUPT (0x22)
29#define UART_CMD_GET_BCR_COUNT (0x23)
WDG
Macros
无
Structs
无
Functions
Components
BFLOG
简介
BFLOG 是一个移植简单,功能多样的多线程日志记录库
具有同步异步两种工作模式,异步模式如果缓冲区溢出会将最早的一条记录完整删除
总体三部分、记录器、定向输出、格式化器
一个记录器可多重定向输出,可同时输出到缓冲区、IO外设、文件、文件大小划分、文件时间划分
定向到文件输出,支持设定保留数量,支持按文件大小划分,支持按时间划分
每个定向输出可单独设定格式化器、输出等级、TAG标签过滤、输出方式、颜色
格式化器支持简单格式、用户自定义格式、YAML格式(实现中)、CSV格式(规划中)
六级日志等级控制, FATAL、ERROR、WARNING、INFO、DEBUG、TRACE
支持等级、TAG标签、函数、行数、文件名、TICK数、TIME、线程信息输出
支持等级、TAG标签过滤功能
可对不需要的等级、功能、标签进行裁剪,缩小代码体积

log 样式
配置BFLOG相关功能
如果需要配置BFLOG的相关功能需要在对应的工程目录下 proj.conf 文件中添加对应的代码,举例如下:
以下是一个不支持文件输出的 proj.conf 配置
1# 使能 BFLOG
2set(CONFIG_BFLOG 1)
3# 使能参数检查, 可不开启
4set(CONFIG_BFLOG_DEBUG 1)
此外在 proj.conf 配置中添加以下配置可以使用用户的 bflog_user.h 配置文件,配置文件默认为 bflog_default.h
1# 使能 BFLOG_USER 配置文件
2set(CONFIG_BFLOG_USER 1)
Macros
BFLOG_CSI
Control Sequence Introducer
用于控制终端
1 #define BFLOG_CSI_START "\033["
2 #define BFLOG_CSI_CUU "A"
3 #define BFLOG_CSI_CUD "B"
4 #define BFLOG_CSI_CUF "C"
5 #define BFLOG_CSI_CUB "D"
6 #define BFLOG_CSI_CNL "E"
7 #define BFLOG_CSI_CPL "F"
8 #define BFLOG_CSI_CHA "G"
9 #define BFLOG_CSI_CUP "H"
10 #define BFLOG_CSI_ED "J"
11 #define BFLOG_CSI_EL "K"
12 #define BFLOG_CSI_SU "S"
13 #define BFLOG_CSI_SD "T"
14 #define BFLOG_CSI_SGR "m"
BFLOG_SGR
Select Graphic Rendition
用于文字图形
1 #define BFLOG_SGR_RESET "0"
2 #define BFLOG_SGR_BOLD "1"
3 #define BFLOG_SGR_FAINT "2"
4 #define BFLOG_SGR_ITALICS "3"
5 #define BFLOG_SGR_UNDERLINE "4"
6 #define BFLOG_SGR_BLINKS "5"
7 #define BFLOG_SGR_BLINKR "6"
8 #define BFLOG_SGR_REVERSE "7"
9 #define BFLOG_SGR_HIDE "8"
10 #define BFLOG_SGR_STRIKE "9"
11 #define BFLOG_SGR_NORMAL "22"
12 #define BFLOG_SGR_FG_BLACK "30"
13 #define BFLOG_SGR_FG_RED "31"
14 #define BFLOG_SGR_FG_GREEN "32"
15 #define BFLOG_SGR_FG_YELLOW "33"
16 #define BFLOG_SGR_FG_BLUE "34"
17 #define BFLOG_SGR_FG_MAGENTA "35"
18 #define BFLOG_SGR_FG_CYAN "36"
19 #define BFLOG_SGR_FG_WHITE "37"
20 #define BFLOG_SGR_BG_BLACK "40"
21 #define BFLOG_SGR_BG_RED "41"
22 #define BFLOG_SGR_BG_GREEN "42"
23 #define BFLOG_SGR_BG_YELLOW "43"
24 #define BFLOG_SGR_BG_BLUE "44"
25 #define BFLOG_SGR_BG_MAGENTA "45"
26 #define BFLOG_SGR_BG_CYAN "46"
27 #define BFLOG_SGR_BG_WHITE "47"
BFLOG_COLOR
一系列颜色用于配置使用
1 #define BFLOG_COLOR_START BFLOG_CSI_START
2 #define BFLOG_COLOR_END BFLOG_CSI_SGR
3 #define BFLOG_CLOLR_SEP ";"
4 #define BFLOG_COLOR_DEFAULT
5 #define BFLOG_COLOR_RESET BFLOG_SGR_RESET BFLOG_CLOLR_SEP
6 #define BFLOG_COLOR_FG_NONE
7 #define BFLOG_COLOR_FG_BLACK BFLOG_SGR_FG_BLACK BFLOG_CLOLR_SEP
8 #define BFLOG_COLOR_FG_RED BFLOG_SGR_FG_RED BFLOG_CLOLR_SEP
9 #define BFLOG_COLOR_FG_GREEN BFLOG_SGR_FG_GREEN BFLOG_CLOLR_SEP
10 #define BFLOG_COLOR_FG_YELLOW BFLOG_SGR_FG_YELLOW BFLOG_CLOLR_SEP
11 #define BFLOG_COLOR_FG_BLUE BFLOG_SGR_FG_BLUE BFLOG_CLOLR_SEP
12 #define BFLOG_COLOR_FG_MAGENTA BFLOG_SGR_FG_MAGENTA BFLOG_CLOLR_SEP
13 #define BFLOG_COLOR_FG_CYAN BFLOG_SGR_FG_CYAN BFLOG_CLOLR_SEP
14 #define BFLOG_COLOR_FG_WHITE BFLOG_SGR_FG_WHITE BFLOG_CLOLR_SEP
15 #define BFLOG_COLOR_BG_NONE
16 #define BFLOG_COLOR_BG_BLACK BFLOG_SGR_BG_BLACK BFLOG_CLOLR_SEP
17 #define BFLOG_COLOR_BG_RED BFLOG_SGR_BG_RED BFLOG_CLOLR_SEP
18 #define BFLOG_COLOR_BG_GREEN BFLOG_SGR_BG_GREEN BFLOG_CLOLR_SEP
19 #define BFLOG_COLOR_BG_YELLOW BFLOG_SGR_BG_YELLOW BFLOG_CLOLR_SEP
20 #define BFLOG_COLOR_BG_BLUE BFLOG_SGR_BG_BLUE BFLOG_CLOLR_SEP
21 #define BFLOG_COLOR_BG_MAGENTA BFLOG_SGR_BG_MAGENTA BFLOG_CLOLR_SEP
22 #define BFLOG_COLOR_BG_CYAN BFLOG_SGR_BG_CYAN BFLOG_CLOLR_SEP
23 #define BFLOG_COLOR_BG_WHITE BFLOG_SGR_BG_WHITE BFLOG_CLOLR_SEP
BFLOG_COLOR_CONTROL
默认配置的各等级LOG颜色
1 #ifndef BFLOG_COLOR_FATAL
2 #define BFLOG_COLOR_FATAL BFLOG_COLOR_FG_MAGENTA BFLOG_COLOR_BG_NONE BFLOG_SGR_BLINKS
3 #endif
4
5 #ifndef BFLOG_COLOR_ERROR
6 #define BFLOG_COLOR_ERROR BFLOG_COLOR_FG_RED BFLOG_COLOR_BG_NONE BFLOG_SGR_NORMAL
7 #endif
8
9 #ifndef BFLOG_COLOR_WARN
10 #define BFLOG_COLOR_WARN BFLOG_COLOR_FG_YELLOW BFLOG_COLOR_BG_NONE BFLOG_SGR_NORMAL
11 #endif
12
13 #ifndef BFLOG_COLOR_INFO
14 #define BFLOG_COLOR_INFO BFLOG_COLOR_FG_NONE BFLOG_COLOR_BG_NONE BFLOG_SGR_RESET
15 #endif
16
17 #ifndef BFLOG_COLOR_DEBUG
18 #define BFLOG_COLOR_DEBUG BFLOG_COLOR_FG_WHITE BFLOG_COLOR_BG_NONE BFLOG_SGR_NORMAL
19 #endif
20
21 #ifndef BFLOG_COLOR_TRACE
22 #define BFLOG_COLOR_TRACE BFLOG_COLOR_FG_WHITE BFLOG_COLOR_BG_NONE BFLOG_SGR_FAINT
23 #endif
BFLOG_LEVEL_STRING
默认配置的各等级提示信息
1 #ifndef BFLOG_LEVEL_FATAL_STRING
2 #define BFLOG_LEVEL_FATAL_STRING "FATL"
3 #endif
4
5 #ifndef BFLOG_LEVEL_ERROR_STRING
6 #define BFLOG_LEVEL_ERROR_STRING "ERRO"
7 #endif
8
9 #ifndef BFLOG_LEVEL_WARN_STRING
10 #define BFLOG_LEVEL_WARN_STRING "WARN"
11 #endif
12
13 #ifndef BFLOG_LEVEL_INFO_STRING
14 #define BFLOG_LEVEL_INFO_STRING "INFO"
15 #endif
16
17 #ifndef BFLOG_LEVEL_DEBUG_STRING
18 #define BFLOG_LEVEL_DEBUG_STRING "DBUG"
19 #endif
20
21 #ifndef BFLOG_LEVEL_TRACE_STRING
22 #define BFLOG_LEVEL_TRACE_STRING "TRAC"
23 #endif
BFLOG_LEVEL
用于配置 recorder 和 direct 的 LOG等级
1 #define BFLOG_LEVEL_FATAL 0x00 /*!< level fatal, create a panic */
2 #define BFLOG_LEVEL_ERROR 0x01 /*!< level error */
3 #define BFLOG_LEVEL_WARN 0x02 /*!< level warning */
4 #define BFLOG_LEVEL_INFO 0x03 /*!< level information */
5 #define BFLOG_LEVEL_DEBUG 0x04 /*!< level debug */
6 #define BFLOG_LEVEL_TRACE 0x05 /*!< level trace information */
BFLOG_FLAG
用于配置 recorder 和 direct 的功能
1 #define BFLOG_FLAG_LEVEL ((uint8_t)0x01) /*!< supported print level */
2 #define BFLOG_FLAG_TAG ((uint8_t)0x02) /*!< supported record tag */
3 #define BFLOG_FLAG_FUNC ((uint8_t)0x04) /*!< supported record function */
4 #define BFLOG_FLAG_LINE ((uint8_t)0x08) /*!< supported record line */
5 #define BFLOG_FLAG_FILE ((uint8_t)0x10) /*!< supported record file */
6 #define BFLOG_FLAG_CLK ((uint8_t)0x20) /*!< supported record clock */
7 #define BFLOG_FLAG_TIME ((uint8_t)0x40) /*!< supported record time */
8 #define BFLOG_FLAG_THREAD ((uint8_t)0x80) /*!< supported record thread */
BFLOG_MODE
用于配置 recorder 的模式
1 #define BFLOG_MODE_SYNC ((uint8_t)0x00)
2 #define BFLOG_MODE_ASYNC ((uint8_t)0x01)
BFLOG_COMMAND
配置命令,用于 bflog_control 第二个参数
1 #define BFLOG_CMD_FLAG ((uint32_t)0x01)
2 #define BFLOG_CMD_LEVEL ((uint32_t)0x02)
3 #define BFLOG_CMD_QUEUE_POOL ((uint32_t)0x03)
4 #define BFLOG_CMD_QUEUE_SIZE ((uint32_t)0x04)
5 #define BFLOG_CMD_QUEUE_RST ((uint32_t)0x05)
6 #define BFLOG_CMD_ENTER_CRITICAL ((uint32_t)0x06)
7 #define BFLOG_CMD_EXIT_CRITICAL ((uint32_t)0x07)
8 #define BFLOG_CMD_FLUSH_NOTICE ((uint32_t)0x08)
9 #define BFLOG_CMD_MODE ((uint32_t)0x09)
BFLOG_DIRECT_COMMAND
配置命令,用于 bflog_direct_control 第二个参数
1 #define BFLOG_DIRECT_CMD_ILLEGAL ((uint32_t)0x00)
2 #define BFLOG_DIRECT_CMD_LEVEL ((uint32_t)0x02)
3 #define BFLOG_DIRECT_CMD_LOCK ((uint32_t)0x06)
4 #define BFLOG_DIRECT_CMD_UNLOCK ((uint32_t)0x07)
5 #define BFLOG_DIRECT_CMD_COLOR ((uint32_t)0x0A)
BFLOG_DIRECT_TYPE
要创建的direct类型,用于 bflog_direct_create 第二个参数
1 #define BFLOG_DIRECT_TYPE_BUFFER ((uint8_t)0x01)
2 #define BFLOG_DIRECT_TYPE_STREAM ((uint8_t)0x02)
3 #define BFLOG_DIRECT_TYPE_FILE ((uint8_t)0x03)
4 #define BFLOG_DIRECT_TYPE_FILE_TIME ((uint8_t)0x04)
5 #define BFLOG_DIRECT_TYPE_FILE_SIZE ((uint8_t)0x05)
BFLOG_DIRECT_COLOR
是否启用颜色输出,用于 bflog_direct_create 第三个参数
1 #define BFLOG_DIRECT_COLOR_DISABLE ((uint8_t)0)
2 #define BFLOG_DIRECT_COLOR_ENABLE ((uint8_t)1)
BFLOG_LAYOUT_TYPE
要创建的layout类型,用于 bflog_layout_create 第二个参数
1 #define BFLOG_LAYOUT_TYPE_SIMPLE ((uint8_t)0)
2 #define BFLOG_LAYOUT_TYPE_FORMAT ((uint8_t)1)
3 #define BFLOG_LAYOUT_TYPE_YAML ((uint8_t)2)
Port Functions
移植要实现的接口函数
bflog_clock
获取当前cpu时钟数
1 uint64_t bflog_clock(void);
bflog_time
获取当前UTC时间戳
1 uint32_t bflog_time(void);
bflog_thread
获取当前线程名称
1 char *bflog_thread(void);
Global Functions
bflog_global_filter
用于对标签过滤器进行全局的开关,会影响所有的recorder和direct
1 int bflog_global_filter(void *tag_string, uint8_t enable);
parameter |
description |
---|---|
tag_string |
标签字符串的指针 |
enable |
是否使能 |
1 bflog_global_filter("YOURTAG", true);
2 bflog_global_filter("YOURTAG", false);
Recorder Functions
recorder负责收集日志, 具有illegal、ready、running、suspend四种状态 running状态可以收集日志, ready、suspend状态可以对其进行配置 除level配置操作外, 其他配置操作必须在ready、suspend下
bflog_create
创建一个recorder, 需要定义一个bflog_t结构体并将其指针传入,定义一块内存数组用于换冲
成功返回0,失败返回-1
1 int bflog_create(bflog_t *log, void *pool, uint16_t size, uint8_t mode);
parameter |
description |
---|---|
log |
recorder 指针 |
pool |
用于缓冲的数组 |
size |
用户缓冲的数组大小 |
mode |
BFLOG_MODE |
1 #include "bflog.h"
2
3 #define EXAMPLE_LOG_POOL_SIZE 4096
4
5 bflog_t example_recorder;
6 static uint32_t example_pool[EXAMPLE_LOG_POOL_SIZE / 4];
7
8 /*!< 创建一个记录器, 配置内存池, 内存池大小, 模式为同步 */
9 if (0 != bflog_create((void *)&example_recorder, example_pool, EXAMPLE_LOG_POOL_SIZE, BFLOG_MODE_SYNC)) {
10 printf("bflog_create faild\r\n");
11 }
bflog_delete
删除一个recorder
处于ready、suspend状态下
线程安全
成功返回0,失败返回-1
1 int bflog_delete(bflog_t *log);
parameter |
description |
---|---|
log |
recorder 指针 |
bflog_append
将一个direct添加到此recorder,可以添加多个direct,但一个direct只能被添加到一个recorder
处于ready、suspend状态下
线程安全
成功返回0,失败返回-1
1 int bflog_append(bflog_t *log, bflog_direct_t *direct);
parameter |
description |
---|---|
log |
recorder 指针 |
direct |
direct 指针 |
bflog_remove
将一个direct从recorder移除
处于ready、suspend状态下
线程安全
成功返回0,失败返回-1
1 int bflog_remove(bflog_t *log, bflog_direct_t *direct);
parameter |
description |
---|---|
log |
recorder 指针 |
direct |
direct 指针 |
bflog_suspend
将一个recorder挂起
处于ready、running、suspend状态下
线程安全
成功返回0,失败返回-1
1 int bflog_suspend(bflog_t *log);
parameter |
description |
---|---|
log |
recorder 指针 |
bflog_resume
将一个recorder恢复
处于ready、running、suspend状态下
线程安全
成功返回0,失败返回-1
1 int bflog_resume(bflog_t *log);
parameter |
description |
---|---|
log |
recorder 指针 |
bflog_control
对一个recorder进行配置
处于ready、suspend状态下;当command为BFLOG_CMD_LEVEL可以处于running状态下
线程安全
成功返回0,失败返回-1
1 int bflog_control(bflog_t *log, uint32_t command, uint32_t param);
parameter |
description |
---|---|
log |
recorder 指针 |
command |
配置命令 |
param |
配置参数 |
command param 可以填入以下参数:
command |
param |
description |
---|---|---|
BFLOG_CMD_FLAG |
BFLOG_FLAG |
配置recorder记录功能 |
BFLOG_CMD_LEVEL |
BFLOG_LEVEL |
配置recorder记录的等级 |
BFLOG_CMD_QUEUE_POOL |
内存池地址 |
配置用于缓冲的内存池地址 |
BFLOG_CMD_QUEUE_SIZE |
内存池大小(byte) |
配置用于缓冲的内存池大小 |
BFLOG_CMD_QUEUE_RST |
NULL |
复位缓冲区,清除缓冲区的所有内容 |
BFLOG_CMD_ENTER_CRITICAL |
int (* enter_critical)(void) 函数指针 |
配置进入临界区的函数 |
BFLOG_CMD_EXIT_CRITICAL |
int (* exit_critical)(void) 函数指针 |
配置退出临界区的函数 |
BFLOG_CMD_FLUSH_NOTICE |
int (* flush_notice)(void) 函数指针 |
配置清除缓冲区提示函数,用于多线程flush线程工作 |
BFLOG_CMD_MODE |
BFLOG_MODE |
配置recorder工作模式 |
bflog_filter
配置recorder的tag filter, 配置是否启用对应tag_string的log输出
处于ready、suspend、running状态下
线程安全
成功返回0,失败返回-1
1 int bflog_filter(bflog_t *log, void *tag_string, uint8_t enable);
parameter |
description |
---|---|
log |
recorder 指针 |
tag_string |
tag 字符串 |
enable |
是否使能 |
bflog
将log信息添加到recorder, sync模式会直接调用bflog_flush, async模式调用配置的flush_notice函数
处于running状态下
线程安全
成功返回0,失败返回-1
1 int bflog(void *log, uint8_t level, void *tag, const char *const file, const char *const func, const long line, const char *format, ...);
parameter |
description |
---|---|
log |
recorder 指针 |
level |
此条log的等级 |
tag |
此条log的tag结构体指针 |
file |
此条log的文件名字符串指针 |
func |
此条log的函数名字符串指针 |
line |
此条log的行号 |
format |
此条log的格式化字符串 |
… |
此条log的变长参数列表 |
bflog_flush
将队列中存储的所有log信息全部输出到recorder配置的所有的direct
处于running状态下
线程安全
成功返回0,失败返回-1
1 int bflog_flush(void *log);
parameter |
description |
---|---|
log |
recorder 指针 |
BLE
概述
- BLE支持的特性:
- 蓝牙HOST特性
GAP支持的角色:Peripheral与Central,Observer与Broadcaster
GATT支持的角色:Server与Client
支持配对包括蓝牙4.2中的安全连接特性
支持永久存储蓝牙特定的设置和数据
- 蓝牙mesh特性
支持Relay, Friend Node, Low-Power Node (LPN) and GATT Proxy角色
支持两种Provisioning bearers(PB-ADV & PB-GATT)
- BLE协议栈的架构:
- 总共有3个主要层,共同构成了一个完整的蓝牙低能耗协议栈
Host:这一层位于应用程序之下,由多个(非实时)网络和传输协议组成,使应用程序能够以标准和互操作的方式与对等设备通信。
Controller:控制器实现了链路层(LE LL),这是一种低层次的实时协议,它与无线电硬件一起提供了空中通信的标准互操作。LL处理包的接收和传输,保证数据的传递,并处理所有LL控制程序。
Radio Hardware:实现所需的模拟和数字基带功能块,允许链路层固件在频谱的2.4GHz波段发送和接收。
- 主控Host:
- 蓝牙Host层实现了所有高级协议和配置文件,最重要的是它为应用程序提供了高级API
HCI:Host与controller接口
L2CAP:逻辑链路控制和适应协议
GATT:通用属性配置层(Generic Attribute Profile)
GAP:通用访问配置层(Generic Access Profile)
SMP:安全管理器配置层(Security Manager Specification)
- 应用Application
- 应用层是用户开发实际蓝牙应用的地方,包含必要的协议栈参数设置,以及各种功能函数的调用。我们分别从蓝牙从机和蓝牙主机两种设备来分析。
- 蓝牙从机
相关硬件和基础服务初始化
设置广播参数:广播数据,广播间隔,扫描回应等参数或者数据
设置Profile:添加从机服务、特征值,还有设置回调函数用于接收主机数据等
设置配对参数(可选)
启动广播,开始运行
等待相关事件,及事件处理,例如收到主机发来的数据,被链接等等
- 蓝牙主机
相关硬件和基础服务初始化
设置扫描参数
设置连接参数
设置配对参数(可选)
启动协议栈,开始运行
等待相关事件,及事件处理,例如扫描事件,从机的Notify事件等等。
API参考
API介绍
void ble_controller_init(uint8_t task_priority)
/**
* function controller层初始化
* @param[in] task_priority: 任务优先级
* @return 空
*/
int hci_driver_init(void)
/**
* function HCI接口驱动初始化
* @param[in] 空
* @return 0:成功,!=0:失败
*/
int bt_enable(bt_ready_cb_t cb)
/**
* function Ble使能
* @param[in] cb:如果成功调用回调函数
* @return 0:成功,!=0:失败
*/
int bt_le_adv_start(const struct bt_le_adv_param *param,const struct bt_data *ad, size_t ad_len,
const struct bt_data *sd, size_t sd_len)
/**
* function 开启BLE广播
*
* @param[in] param: 指向广播配置参数指针
* @param[in] ad: 指向广播包中数据指针
* @param[in] ad_len: 广播包中数据的长度
* @param[in] sd: 指向扫描响应包数据指针
* @param[in] sd_len: 扫描响应包数据的长度
* @return 0:成功,!=0:失败
*/
int bt_le_adv_update_data(const struct bt_data *ad, size_t ad_len,const struct bt_data *sd, size_t sd_len)
/**
* function 更新BLE广播数据
* @param[in] ad: 指向广播包中数据指针
* @param[in] ad_len: 广播包中数据的长度
* @param[in] sd: 指向扫描响应包数据指针
* @param[in] sd_len: 扫描响应包数据的长度
* @return 0:成功,!=0:失败
*/
int bt_le_adv_stop(void)
/**
* function 停止BLE广播
* @param[in] 空
* @return 0:成功,!=0:失败
*/
int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb)
/**
* function 开启BLE扫描
* @param[in] param: 指向扫描参数的指针
* @param[in] cb: 扫描回调函数
* @return 0:成功,!=0:失败
*/
int bt_le_scan_stop(void)
/**
* function 停止BLE扫描
* @param[in] 空
* @return 0:成功,!=0:失败
*/
int bt_le_whitelist_add(const bt_addr_le_t *addr)
/**
* function 通过地址添加设备到白名单列表中
* @param[in] addr:指向需要添加设备地址的指针
* @return 0:成功,!=0:失败
*/
int bt_le_whitelist_rem(const bt_addr_le_t *addr)
/**
* function 从白名单列表中移除设备
* @param[in] addr:指向需要移除设备地址的指针
* @return 0:成功,!=0:失败
*/
int bt_le_whitelist_clear(void)
/**
* function 清除白名单列表
* @param[in] 空
* @return 0:成功,!=0:失败
*/
int bt_le_set_chan_map(u8_t chan_map[5])
/**
* function 设置(LE)通道映射
* @param[in] chan_map:通道数组
* @return 0:成功,!=0:失败
*/
int bt_unpair(u8_t id, const bt_addr_le_t *addr)
/**
* function 清除配对信息
* @param[in] id: 本地标识(大多只是默认的BT ID)
* @param[in] addr: 远端设备地址,NULL或者BT_ADDR_LE_ANY清除所有远端设备
* @return 0:成功,!=0:失败
*/
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
/**
* function 获取当前连接设备的信息
* @param[in] conn: 指向当前连接的指针
* @param[in] info: 指向当前连接设备信息的指针
* @return 0:成功,!=0:失败
*/
int bt_conn_get_remote_dev_info(struct bt_conn_info *info)
/**
* function 获取已连接设备的信息
* @param[in] info: 指向当前连接设备信息的指针
* @return 已连接设备的个数
*/
int bt_conn_le_param_update(struct bt_conn *conn,const struct bt_le_conn_param *param)
/**
* function 更新连接参数
* @param[in] conn: 指向当前连接的指针
* @param[in] param: 指向连接参数的指针
* @return 0:成功,!=0:失败
*/
int bt_conn_disconnect(struct bt_conn *conn, u8_t reason)
/**
* function 断开当前连接
* @param[in] conn: 指向当前连接的指针
* @param[in] reason:断开当前连接的原因
* @return 0:成功,!=0:失败
*/
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,const struct bt_le_conn_param *param)
/**
* function 创建连接
* @param[in] peer: 需要连接设备地址的指针
* @param[in] param: 指向连接参数指针
* @return 成功:有效的连接对象,否则失败
*/
int bt_conn_create_auto_le(const struct bt_le_conn_param *param)
/**
* function 自动创建连接白名单列表中的设备
* @param[in] param: 指向连接参数指针
* @return 0:成功,!=0:失败
*/
int bt_conn_create_auto_stop(void)
/**
* function 停止自动创建连接白名单列表中的设备
* @param[in] 空
* @return 0:成功,!=0:失败
*/
int bt_le_set_auto_conn(const bt_addr_le_t *addr,const struct bt_le_conn_param *param)
/**
* function 自动创建连接远端设备
* @param[in] addr: 远端设备地址指针
* @param[in] param: 指向连接参数指针
* @return 0:成功,!=0:失败
*/
struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer,const struct bt_le_adv_param *param)
/**
* function 发起定向的广播包给远端设备
* @param[in] peer: 远端设备地址指针
* @param[in] param: 指向广播参数的指针
* @return 成功:有效的连接对象,否则失败
*/
int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec)
/**
* function 设置连接安全等级
* @param[in] conn: 指向连接对象的指针
* @param[in] sec: 安全等级
* @return 0:成功,!=0:失败
*/
bt_security_t bt_conn_get_security(struct bt_conn *conn)
/**
* function 获取当前连接的安全等级
* @param[in] conn: 指向连接对象的指针
* @return 安全级别
*/
u8_t bt_conn_enc_key_size(struct bt_conn *conn)
/**
* function 获取当前连接的加密key的大小
* @param[in] conn: 指向连接对象的指针
* @return 加密key的大小
*/
void bt_conn_cb_register(struct bt_conn_cb *cb)
/**
* function 注册连接回调函数
* @param[in] cb: 连接回调函数
* @return 空
*/
void bt_set_bondable(bool enable)
/**
* function 设置/清除SMP配对请求/响应数据认证需求中的绑定标志
* @param[in] enable: 1,使能,0:不使能
* @return 空
*/
int bt_conn_auth_cb_register(const struct bt_conn_auth_cb *cb)
/**
* function 注册认证回调函数
* @param[in] cb: 回调函数指针
* @return 0:成功,!=0:失败
*/
int bt_conn_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey)
/**
* function 用密钥回复对方
* @param[in] conn: 连接对象指针
* @param[in] passkey: 输入的密钥
* @return 0:成功,!=0:失败
*/
int bt_conn_auth_cancel(struct bt_conn *conn)
/**
* function 取消认证过程
* @param[in] conn: 连接对象指针
* @return 0:成功,!=0:失败
*/
int bt_conn_auth_passkey_confirm(struct bt_conn *conn)
/**
* function 如果密码匹配,回复对方
* @param[in] conn: 连接对象的指针
* @return 0:成功,!=0:失败
*/
int bt_conn_auth_pincode_entry(struct bt_conn *conn, const char *pin)
/**
* function 用PIN码进行回复对方
* @param[in] conn: 连接对象的指针
* @param[in] pin: PIN码的指针
* @return 0:成功,!=0:失败
*/
int bt_le_read_rssi(u16_t handle,int8_t *rssi)
/**
* function 读取对方RSSI值
* @param[in] handle:连接的句柄值
* @param[in] rssi: rssi的指针
* @return 0:成功,!=0:失败
*/
int bt_get_local_address(bt_addr_le_t *adv_addr)
/**
* function 读取本机的地址
* @param[in] adv_addr: 指向地址的指针
* @return 0:成功,!=0:失败
*/
int bt_set_tx_pwr(int8_t power)
/**
* function 设置本机发射功率
* @param[in] power: 功率值
* @return 0:成功,!=0:失败
*/
数据结构参考
bt_le_adv_param
数据结构:
1 /** LE Advertising Parameters. */
2 struct bt_le_adv_param {
3 /** Local identity */
4 u8_t id;
5
6 /** Bit-field of advertising options */
7 u8_t options;
8
9 /** Minimum Advertising Interval (N * 0.625) */
10 u16_t interval_min;
11
12 /** Maximum Advertising Interval (N * 0.625) */
13 u16_t interval_max;
14
15 #if defined(CONFIG_BT_STACK_PTS)
16 u8_t addr_type;
17 #endif
18 };
此数据结构用来配置广播参数,包括本地识别id、广播选项位域、广播间隙等,其中广播选项位域有如下枚举类型参数可选:
1 enum {
2 /** Convenience value when no options are specified. */
3 BT_LE_ADV_OPT_NONE = 0,
4
5 /** Advertise as connectable. Type of advertising is determined by
6 * providing SCAN_RSP data and/or enabling local privacy support.
7 */
8 BT_LE_ADV_OPT_CONNECTABLE = BIT(0),
9
10 /** Don't try to resume connectable advertising after a connection.
11 * This option is only meaningful when used together with
12 * BT_LE_ADV_OPT_CONNECTABLE. If set the advertising will be stopped
13 * when bt_le_adv_stop() is called or when an incoming (slave)
14 * connection happens. If this option is not set the stack will
15 * take care of keeping advertising enabled even as connections
16 * occur.
17 */
18 BT_LE_ADV_OPT_ONE_TIME = BIT(1),
19
20 /** Advertise using the identity address as the own address.
21 * @warning This will compromise the privacy of the device, so care
22 * must be taken when using this option.
23 */
24 BT_LE_ADV_OPT_USE_IDENTITY = BIT(2),
25
26 /** Advertise using GAP device name */
27 BT_LE_ADV_OPT_USE_NAME = BIT(3),
28
29 /** Use low duty directed advertising mode, otherwise high duty mode
30 * will be used. This option is only effective when used with
31 * bt_conn_create_slave_le().
32 */
33 BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY = BIT(4),
34
35 /** Enable use of Resolvable Private Address (RPA) as the target address
36 * in directed advertisements when CONFIG_BT_PRIVACY is not enabled.
37 * This is required if the remote device is privacy-enabled and
38 * supports address resolution of the target address in directed
39 * advertisement.
40 * It is the responsibility of the application to check that the remote
41 * device supports address resolution of directed advertisements by
42 * reading its Central Address Resolution characteristic.
43 */
44 BT_LE_ADV_OPT_DIR_ADDR_RPA = BIT(5),
45
46 /** Use whitelist to filter devices that can request scan response
47 * data.
48 */
49 BT_LE_ADV_OPT_FILTER_SCAN_REQ = BIT(6),
50
51 /** Use whitelist to filter devices that can connect. */
52 BT_LE_ADV_OPT_FILTER_CONN = BIT(7),
53 };
如果需要发送一个广播包,配置可以如下:
1 param.id = 0;
2 param.options = (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME);
3 param.interval_min = 0x00a0;
4 param.interval_max = 0x00f0;
bt_data
数据结构:
1 struct bt_data {
2 u8_t type;
3 u8_t data_len;
4 const u8_t *data;
5 };
此数据结构用来填充广播包中的数据,具体的数据包类型可以参考如下:
1 Service UUID
2 Local Name
3 Flags
4 Manufacturer Specific Data
5 TX Power Level
6 Secure Simple Pairing OOB
7 Security Manager OOB
8 Security Manager TK Value
9 Slave Connection Interval Range
10 Service Solicitation
11 Service Data
12 Appearance
13 Public Target Address
14 Random Target Address
15 Advertising Interval
16 LE Bluetooth Device Address
17 LE Role
18 Uniform Resource Identifier
19 LE Supported Features
20 Channel Map Update Indication
用该数据结构配置一个广播包数据,如下所示:
1 struct bt_data ad_discov[] = {
2 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
3 BT_DATA(BT_DATA_NAME_COMPLETE, "BL602-BLE-DEV", 13),
4 };
bt_le_scan_param
数据结构:
1 /** LE scan parameters */
2 struct bt_le_scan_param {
3 /** Scan type (BT_LE_SCAN_TYPE_ACTIVE or BT_LE_SCAN_TYPE_PASSIVE) */
4 u8_t type;
5
6 /** Bit-field of scanning filter options. */
7 u8_t filter_dup;
8
9 /** Scan interval (N * 0.625 ms) */
10 u16_t interval;
11
12 /** Scan window (N * 0.625 ms) */
13 u16_t window;
14 };
此数据结构用来填充扫描参数, type:为扫描类型有2种类型BT_LE_SCAN_TYPE_ACTIVE(0x01)、BT_LE_SCAN_TYPE_PASSIVE(0x00)。 filter_dup:0x00,除定向广告外,接受所有广播和扫描响应,0x01,只接收白名单列表中设备的广播和扫描响应。 interval:扫描间隙。 window:扫描窗口。
如果开启扫描请求,可以配置如下:
1 scan_param.type = BT_LE_SCAN_TYPE_PASSIVE
2 scan_param.filter_dup = 0x00
3 interval=BT_GAP_SCAN_SLOW_INTERVAL_1
4 window=BT_GAP_SCAN_SLOW_WINDOW_1
bt_le_conn_param
数据结构:
1 /** Connection parameters for LE connections */
2 struct bt_le_conn_param {
3 u16_t interval_min;
4 u16_t interval_max;
5 u16_t latency;
6 u16_t timeout;
7
8 #if defined(CONFIG_BT_STACK_PTS)
9 u8_t own_address_type;
10 #endif
11 };
此数据结构用来填充连接参数,interval_min:连接间隙最少值(0x0018),interval_max:连接间隙最大值(0x0028), latency:指定为连接事件数的连接允许的最大从延迟。 timeout:连接超时时间。
配置该数据结构,如下:
1 interval_min=BT_GAP_INIT_CONN_INT_MIN(0x0018)
2 interval_max=BT_GAP_INIT_CONN_INT_MAX(0x0028)
3 latency=0
4 timeout=400
bt_conn
数据结构:
1 struct bt_conn {
2 u16_t handle;
3 u8_t type;
4 u8_t role;
5
6 ATOMIC_DEFINE(flags, BT_CONN_NUM_FLAGS);
7
8 /* Which local identity address this connection uses */
9 u8_t id;
10
11 #if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
12 bt_security_t sec_level;
13 bt_security_t required_sec_level;
14 u8_t encrypt;
15 #endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
16
17 /* Connection error or reason for disconnect */
18 u8_t err;
19
20 bt_conn_state_t state;
21
22 u16_t rx_len;
23 struct net_buf *rx;
24
25 /* Sent but not acknowledged TX packets with a callback */
26 sys_slist_t tx_pending;
27 /* Sent but not acknowledged TX packets without a callback before
28 * the next packet (if any) in tx_pending.
29 */
30 u32_t pending_no_cb;
31
32 /* Completed TX for which we need to call the callback */
33 sys_slist_t tx_complete;
34 struct k_work tx_complete_work;
35
36
37 /* Queue for outgoing ACL data */
38 struct k_fifo tx_queue;
39
40 /* Active L2CAP channels */
41 sys_slist_t channels;
42
43 atomic_t ref;
44
45 /* Delayed work for connection update and other deferred tasks */
46 struct k_delayed_work update_work;
47
48 union {
49 struct bt_conn_le le;
50 #if defined(CONFIG_BT_BREDR)
51 struct bt_conn_br br;
52 struct bt_conn_sco sco;
53 #endif
54 };
55
56 #if defined(CONFIG_BT_REMOTE_VERSION)
57 struct bt_conn_rv {
58 u8_t version;
59 u16_t manufacturer;
60 u16_t subversion;
61 } rv;
62 #endif
63 };
此数据结构为当前连接数据结构,其中包括BLE蓝牙连接相关的参数,连接成功后该数据结构可以被用户调用。
WIFI
Peripherals
外设例程如果没有特殊说明,则表示适用于博流所有系列芯片。
ADC
ADC - poll
本 demo 主要演示 adc poll 单端模式下读取电压值。默认扫描通道 0 ~ 通道10。 需要注意,有些芯片不一定支持全部通道。
硬件连接
本 demo 使用到的 gpio 参考 board_adc_gpio_init
。
软件实现
更详细的代码请参考 examples/peripherals/adc/adc_poll
1board_init();
board_init
中会开启 ADC IP 时钟,并选择 ADC 时钟源和分频(ADC 时钟必须小于等于 500K)。
1board_adc_gpio_init();
配置相关引脚为 ADC 功能
1adc = bflb_device_get_by_name("adc");
2
3/* adc clock = XCLK / 2 / 32 */
4struct bflb_adc_config_s cfg;
5cfg.clk_div = ADC_CLK_DIV_32;
6cfg.scan_conv_mode = true;
7cfg.continuous_conv_mode = false;
8cfg.differential_mode = false;
9cfg.resolution = ADC_RESOLUTION_16B;
10cfg.vref = ADC_VREF_3P2V;
11
12bflb_adc_init(adc, &cfg);
获取 adc 句柄,并初始化 adc 配置,设置 adc 采样频率为 500K
1bflb_adc_channel_config(adc, chan, TEST_ADC_CHANNELS);
配置 adc 通道信息,使用的对数根据 TEST_ADC_CHANNELS 可配,默认开启通道 0 ~ 10,根据
board_adc_gpio_init
需要选择性关闭其他通道。
1for (uint32_t i = 0; i < TEST_COUNT; i++) {
2 bflb_adc_start_conversion(adc);
3
4 while (bflb_adc_get_count(adc) < TEST_ADC_CHANNELS) {
5 bflb_mtimer_delay_ms(1);
6 }
7
8 for (size_t j = 0; j < TEST_ADC_CHANNELS; j++) {
9 struct bflb_adc_result_s result;
10 uint32_t raw_data = bflb_adc_read_raw(adc);
11 printf("raw data:%08x\r\n", raw_data);
12 bflb_adc_parse_result(adc, &raw_data, &result, 1);
13 printf("pos chan %d,%d mv \r\n", result.pos_chan, result.millivolt);
14 }
15
16 bflb_adc_stop_conversion(adc);
17 bflb_mtimer_delay_ms(100);
18}
调用
bflb_adc_start_conversion(adc)
启用 adc 的转换调用
bflb_adc_get_count(adc)
读取转换完成的个数调用
bflb_adc_read_raw(adc)
读取一次 adc 的转换值调用
bflb_adc_parse_result(adc, &raw_data, &result, 1)
对 adc 的转换结果进行解析,解析的值保存到result
结构体中调用
bflb_adc_stop_conversion(adc)
停止 adc 转换
编译和烧录
实验现象
打印 raw data,通道号以及通道对应的电压值。
ADC - dma
本 demo 主要演示 adc dma 单端模式下读取电压值。默认扫描通道 0 ~ 通道10。 需要注意,有些芯片不一定支持全部通道。
硬件连接
本 demo 使用到的 gpio 参考 board_adc_gpio_init
。
软件实现
更详细的代码请参考 examples/peripherals/adc/adc_dma
1board_init();
board_init
中会开启 ADC IP 时钟,并选择 ADC 时钟源和分频(ADC 时钟必须小于等于 500K)。
1board_adc_gpio_init();
配置相关引脚为 ADC 功能
1adc = bflb_device_get_by_name("adc");
2
3/* adc clock = XCLK / 2 / 32 */
4struct bflb_adc_config_s cfg;
5cfg.clk_div = ADC_CLK_DIV_32;
6cfg.scan_conv_mode = true;
7cfg.continuous_conv_mode = true;
8cfg.differential_mode = false;
9cfg.resolution = ADC_RESOLUTION_16B;
10cfg.vref = ADC_VREF_3P2V;
11
12bflb_adc_init(adc, &cfg);
获取 adc 句柄,并初始化 adc 配置,设置 adc 采样频率为 500K
1bflb_adc_channel_config(adc, chan, TEST_ADC_CHANNELS);
配置 adc 通道信息,使用的通道数通过 TEST_ADC_CHANNELS 可配,默认开启通道 0 ~ 10,根据
board_adc_gpio_init
需要选择性关闭其他通道。
1bflb_adc_link_rxdma(adc, true);
使能 adc rx dma 功能
1dma0_ch0 = bflb_device_get_by_name("dma0_ch0");
2
3struct bflb_dma_channel_config_s config;
4
5config.direction = DMA_PERIPH_TO_MEMORY;
6config.src_req = DMA_REQUEST_ADC;
7config.dst_req = DMA_REQUEST_NONE;
8config.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
9config.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
10config.src_burst_count = DMA_BURST_INCR1;
11config.dst_burst_count = DMA_BURST_INCR1;
12config.src_width = DMA_DATA_WIDTH_32BIT;
13config.dst_width = DMA_DATA_WIDTH_32BIT;
14bflb_dma_channel_init(dma0_ch0, &config);
15
16bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);
配置 DMA CH0 为 ADC RX
注册 dma 通道中断
1struct bflb_dma_channel_lli_pool_s lli[1]; /* max trasnfer size 4064 * 1 */
2struct bflb_dma_channel_lli_transfer_s transfers[1];
3
4memset(raw_data, 0, sizeof(raw_data));
5
6transfers[0].src_addr = (uint32_t)DMA_ADDR_ADC_RDR;
7transfers[0].dst_addr = (uint32_t)raw_data;
8transfers[0].nbytes = sizeof(raw_data);
9
10bflb_dma_channel_lli_reload(dma0_ch0, lli, 1, transfers, 1);
11bflb_dma_channel_start(dma0_ch0);
12
13bflb_adc_start_conversion(adc);
14
15while (dma_tc_flag0 != 1) {
16 bflb_mtimer_delay_ms(1);
17}
18
19bflb_adc_stop_conversion(adc);
分配一块 lli 内存池,个数为1,最多可以传输 4064 * 1 字节
配置一块内存进行传输
调用
bflb_dma_channel_lli_reload
初始化调用
bflb_dma_channel_start
启动传输调用
bflb_adc_start_conversion
启用 adc 的转换等待传输完成并进入中断
调用
bflb_adc_stop_conversion
停止 adc 转换
1for (size_t j = 0; j < TEST_ADC_CHANNELS * TEST_COUNT; j++) {
2 struct bflb_adc_result_s result;
3 printf("raw data:%08x\r\n", raw_data[j]);
4 bflb_adc_parse_result(adc, &raw_data[j], &result, 1);
5 printf("pos chan %d,%d mv \r\n", result.pos_chan, result.millivolt);
6}
调用
bflb_adc_parse_result
对 adc 的转换结果进行解析,解析的值保存到result
结构体中打印通道号和电压值
编译和烧录
实验现象
打印 raw data,通道号以及通道对应的电压值。
ADC - int
本 demo 主要演示 adc 中断模式下读取电压值。默认扫描通道 0 ~ 通道10。 需要注意,有些芯片不一定支持全部通道。
硬件连接
本 demo 使用到的 gpio 参考 board_adc_gpio_init
。
软件实现
更详细的代码请参考 examples/peripherals/adc/adc_int
1board_init();
board_init
中会开启 ADC IP 时钟,并选择 ADC 时钟源和分频(ADC 时钟必须小于等于 500K)。
1board_adc_gpio_init();
配置相关引脚为 ADC 功能
1adc = bflb_device_get_by_name("adc");
2
3/* adc clock = XCLK / 2 / 32 */
4struct bflb_adc_config_s cfg;
5cfg.clk_div = ADC_CLK_DIV_32;
6cfg.scan_conv_mode = true;
7cfg.continuous_conv_mode = false;
8cfg.differential_mode = false;
9cfg.resolution = ADC_RESOLUTION_16B;
10cfg.vref = ADC_VREF_3P2V;
11
12bflb_adc_init(adc, &cfg);
获取 adc 句柄,并初始化 adc 配置,设置 adc 采样频率为 500K
1bflb_adc_channel_config(adc, chan, TEST_ADC_CHANNELS);
配置 adc 通道信息,使用的对数根据 TEST_ADC_CHANNELS 可配,默认开启通道 0 ~ 10,根据
board_adc_gpio_init
需要选择性关闭其他通道。
1bflb_adc_rxint_mask(adc, false);
2bflb_irq_attach(adc->irq_num, adc_isr, NULL);
3bflb_irq_enable(adc->irq_num);
调用 bflb_adc_rxint_mask 打开 adc 转换完成中断
调用 bflb_irq_attach 连接中断处理函数
调用 bflb_irq_enable 使能中断
1for (size_t i = 0; i < TEST_COUNT; i++) {
2 read_count = 0;
3 bflb_adc_start_conversion(adc);
4
5 while (read_count < TEST_ADC_CHANNELS) {
6 bflb_mtimer_delay_ms(1);
7 }
8 for (size_t j = 0; j < TEST_ADC_CHANNELS; j++) {
9 struct bflb_adc_result_s result;
10 printf("raw data:%08x\r\n", raw_data[j]);
11 bflb_adc_parse_result(adc, (uint32_t *)&raw_data[j], &result, 1);
12 printf("pos chan %d,%d mv \r\n", result.pos_chan, result.millivolt);
13 }
14 bflb_adc_stop_conversion(adc);
15 bflb_mtimer_delay_ms(100);
16}
调用
bflb_adc_start_conversion(adc)
启用 adc 的转换调用
bflb_adc_parse_result(adc, (uint32_t *)&raw_data[j], &result, 1)
对 adc 的转换结果进行解析,解析的值保存到result
结构体中调用
bflb_adc_stop_conversion(adc)
停止 adc 转换
编译和烧录
实验现象
打印 raw data,通道号以及通道对应的电压值。
ADC - poll_diff_mode
本 demo 主要演示 adc poll 差分模式下读取通道 2 和 通道 3 的电压值。
硬件连接
本 demo 使用到的 gpio 参考 board_adc_gpio_init
。
软件实现
更详细的代码请参考 examples/peripherals/adc/adc_poll_diff_mode
1board_init();
board_init
中会开启 ADC IP 时钟,并选择 ADC 时钟源和分频(ADC 时钟必须小于等于 500K)。
1board_adc_gpio_init();
配置相关引脚为 ADC 功能
1adc = bflb_device_get_by_name("adc");
2
3/* adc clock = XCLK / 2 / 32 */
4struct bflb_adc_config_s cfg;
5cfg.clk_div = ADC_CLK_DIV_32;
6cfg.scan_conv_mode = true;
7cfg.continuous_conv_mode = false;
8cfg.differential_mode = true;
9cfg.resolution = ADC_RESOLUTION_16B;
10cfg.vref = ADC_VREF_3P2V;
11
12bflb_adc_init(adc, &cfg);
获取 adc 句柄,并初始化 adc 配置,设置 adc 采样频率为 500K
1bflb_adc_channel_config(adc, chan, TEST_ADC_CHANNELS);
配置通道 2 和 通道 3 信息。
1for (uint32_t i = 0; i < TEST_COUNT; i++) {
2 bflb_adc_start_conversion(adc);
3
4 while (bflb_adc_get_count(adc) < TEST_ADC_CHANNELS) {
5 bflb_mtimer_delay_ms(1);
6 }
7
8 for (size_t j = 0; j < TEST_ADC_CHANNELS; j++) {
9 struct bflb_adc_result_s result;
10 uint32_t raw_data = bflb_adc_read_raw(adc);
11 printf("raw data:%08x\r\n", raw_data);
12 bflb_adc_parse_result(adc, &raw_data, &result, 1);
13 printf("pos chan %d,neg chan %d,%d mv \r\n", result.pos_chan, result.neg_chan, result.millivolt);
14 }
15
16 bflb_adc_stop_conversion(adc);
17 bflb_mtimer_delay_ms(100);
18}
调用
bflb_adc_start_conversion(adc)
启用 adc 的转换调用
bflb_adc_get_count(adc)
读取转换完成的个数调用
bflb_adc_read_raw(adc)
读取一次 adc 的转换值调用
bflb_adc_parse_result(adc, &raw_data, &result, 1)
对 adc 的转换结果进行解析,解析的值保存到result
结构体中调用
bflb_adc_stop_conversion(adc)
停止 adc 转换
编译和烧录
实验现象
打印 raw data,正极和负极通道号以及对应的电压差值。
ADC - tsen
本 demo 主要演示通过 adc 测量二极管的电压差,计算得到环境温度。
软件实现
更详细的代码请参考 examples/peripherals/adc/adc_tsen
1board_init();
board_init
中会开启 ADC IP 时钟,并选择 ADC 时钟源和分频(ADC 时钟必须小于等于 500K)。
1adc = bflb_device_get_by_name("adc");
2
3/* adc clock = XCLK / 2 / 32 */
4struct bflb_adc_config_s cfg;
5cfg.clk_div = ADC_CLK_DIV_32;
6cfg.scan_conv_mode = false;
7cfg.continuous_conv_mode = false;
8cfg.differential_mode = false;
9cfg.resolution = ADC_RESOLUTION_16B;
10cfg.vref = ADC_VREF_2P0V;
11
12struct bflb_adc_channel_s chan;
13
14chan.pos_chan = ADC_CHANNEL_TSEN_P;
15chan.neg_chan = ADC_CHANNEL_GND;
16
17bflb_adc_init(adc, &cfg);
获取 adc 句柄,并初始化 adc 配置(参考电压必须设置为2.0V),设置 adc 采样频率为 500K。
1bflb_adc_channel_config(adc, chan, 1);
配置 adc 通道信息。
1bflb_adc_tsen_init(adc, ADC_TSEN_MOD_INTERNAL_DIODE);
开启 tsen 功能,使用内部二极管测量电压值。
1 for (i = 0; i < 50; i++) {
2 average_filter += bflb_adc_tsen_get_temp(adc);
3 bflb_mtimer_delay_ms(10);
4 }
5
6 printf("temp = %d\r\n", (uint32_t)(average_filter / 50.0));
7 average_filter = 0;
调用
bflb_adc_tsen_get_temp(adc)
获取 adc tsen 计算得到的环境温度值。
编译和烧录
实验现象
打印计算得到的环境温度。
ADC - vbat
本 demo 主要演示 adc 测量芯片 VDD33 的电压值。
软件实现
更详细的代码请参考 examples/peripherals/adc/adc_vbat
1board_init();
board_init
中会开启 ADC IP 时钟,并选择 ADC 时钟源和分频(ADC 时钟必须小于等于 500K)。
1adc = bflb_device_get_by_name("adc");
2
3/* adc clock = XCLK / 2 / 32 */
4struct bflb_adc_config_s cfg;
5cfg.clk_div = ADC_CLK_DIV_32;
6cfg.scan_conv_mode = false;
7cfg.continuous_conv_mode = false;
8cfg.differential_mode = false;
9cfg.resolution = ADC_RESOLUTION_16B;
10cfg.vref = ADC_VREF_3P2V;
11
12struct bflb_adc_channel_s chan;
13
14chan.pos_chan = ADC_CHANNEL_VABT_HALF;
15chan.neg_chan = ADC_CHANNEL_GND;
16
17bflb_adc_init(adc, &cfg);
获取 adc 句柄,并初始化 adc 配置,设置 adc 采样频率为 500K。
1bflb_adc_channel_config(adc, chan, 1);
配置 adc 通道信息。
1bflb_adc_vbat_enable(adc);
开启 vbat 功能。
1struct bflb_adc_result_s result;
2for (uint16_t i = 0; i < 10; i++) {
3 bflb_adc_start_conversion(adc);
4 while (bflb_adc_get_count(adc) == 0) {
5 bflb_mtimer_delay_ms(1);
6 }
7 uint32_t raw_data = bflb_adc_read_raw(adc);
8
9 bflb_adc_parse_result(adc, &raw_data, &result, 1);
10 printf("vBat = %d mV\r\n", (uint32_t)(result.millivolt * 2));
11 bflb_adc_stop_conversion(adc);
12
13 bflb_mtimer_delay_ms(500);
14}
调用
bflb_adc_start_conversion(adc)
启用 adc 的转换调用
bflb_adc_get_count(adc)
读取转换完成的个数调用
bflb_adc_read_raw(adc)
读取一次 adc 的转换值调用
bflb_adc_parse_result(adc, &raw_data, &result, 1)
对 adc 的转换结果进行解析,解析的值保存到result
结构体中调用
bflb_adc_stop_conversion(adc)
停止 adc 转换
编译和烧录
实验现象
打印芯片 VDD33 的电压值。
ADC 各通道对应的 GPIO 如下表:
名称 |
芯片系列 |
GPIO |
---|---|---|
Channel0 |
BL702 |
GPIO 8 |
BL808 |
GPIO 17 |
|
BL616 |
GPIO 20 |
|
Channel1 |
BL702 |
GPIO 15 |
BL808 |
GPIO 5 |
|
BL616 |
GPIO 19 |
|
Channel2 |
BL702 |
GPIO 17 |
BL808 |
GPIO 4 |
|
BL616 |
GPIO 2(Bootstrap 引脚) |
|
Channel3 |
BL702 |
GPIO 11 |
BL808 |
GPIO 11 |
|
BL616 |
GPIO 3 |
|
Channel4 |
BL702 |
GPIO 12 |
BL808 |
GPIO 6 |
|
BL616 |
GPIO 14 |
|
Channel5 |
BL702 |
GPIO 14 |
BL808 |
GPIO 40 |
|
BL616 |
GPIO 13 |
|
Channel6 |
BL702 |
GPIO 7 |
BL808 |
GPIO 12 |
|
BL616 |
GPIO 12 |
|
Channel7 |
BL702 |
GPIO 9 |
BL808 |
GPIO 13 |
|
BL616 |
GPIO 10 |
|
Channel8 |
BL702 |
GPIO 18 |
BL808 |
GPIO 16 |
|
BL616 |
GPIO 1 |
|
Channel9 |
BL702 |
GPIO 19 |
BL808 |
GPIO 18 |
|
BL616 |
GPIO 0 |
|
Channel10 |
BL702 |
GPIO 20 |
BL808 |
GPIO 19 |
|
BL616 |
GPIO 27 |
|
Channel11 |
BL702 |
GPIO 21 |
BL808 |
GPIO 34 |
|
BL616 |
GPIO 28 |
DAC
DAC - poll
本 demo 主要介绍基于 DAC 轮询模式生成正弦波。
硬件连接
本 demo 使用到的 gpio 参考 board_adc_gpio_init
。
软件实现
更详细的代码请参考 examples/peripherals/dac/dac_polling
1board_init();
board_init
中会开启 DAC IP 时钟,并选择 DAC 时钟源和分频。
1board_dac_gpio_init();
配置相关引脚为 DAC 功能
1dac = bflb_device_get_by_name("dac");
2
3bflb_dac_init(dac, DAC_SAMPLING_FREQ_32K);
获取 dac 句柄,并初始化 dac 频率为 32K
1bflb_dac_channel_enable(dac, DAC_CHANNEL_A);
配置 dac 通道信息,当前使用的 A 通道
1for (uint16_t i = 0; i < sizeof(SIN_LIST) / sizeof(uint16_t); i++) {
2 bflb_dac_set_value(dac, DAC_CHANNEL_A, SIN_LIST[i]);
3 bflb_mtimer_delay_us(100);
4}
调用
bflb_dac_set_value(dac, DAC_CHANNEL_A, SIN_LIST[i])
,将需要转换的数据通过通道 A 输出
编译和烧录
实验现象
DAC Channel A 对应的 GPIO 输出正弦波。
DAC - dma
本 demo 主要介绍基于 DAC DMA 模式生成正弦波。
硬件连接
本 demo 使用到的 gpio 参考 board_dac_gpio_init
。
软件实现
更详细的代码请参考 examples/peripherals/dac/dac_dma
1board_init();
board_init
中会开启 DAC IP 时钟,并选择 DAC 时钟源和分频。
1board_dac_gpio_init();
配置相关引脚为 DAC 功能
1dac = bflb_device_get_by_name("dac");
2
3/* 512K / 1 = 512K */
4bflb_dac_init(dac, DAC_CLK_DIV_1);
5bflb_dac_channel_enable(dac, DAC_CHANNEL_A);
6bflb_dac_channel_enable(dac, DAC_CHANNEL_B);
7bflb_dac_link_txdma(dac, true);
获取 dac 句柄,并初始化 dac 频率为 512K
bflb_dac_channel_enable
配置 dac 通道信息,当前使用的 A 通道和 B 通道bflb_dac_link_txdma
开启 dac txdma 功能
1dma0_ch0 = bflb_device_get_by_name("dma0_ch0");
2
3struct bflb_dma_channel_config_s config;
4
5config.direction = DMA_MEMORY_TO_PERIPH;
6config.src_req = DMA_REQUEST_NONE;
7config.dst_req = DMA_REQUEST_DAC;
8config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
9config.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
10config.src_burst_count = DMA_BURST_INCR1;
11config.dst_burst_count = DMA_BURST_INCR1;
12config.src_width = DMA_DATA_WIDTH_16BIT;
13config.dst_width = DMA_DATA_WIDTH_16BIT;
14bflb_dma_channel_init(dma0_ch0, &config);
15
16bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);
配置 DMA CH0 为 DAC
注册 dma 通道中断
1struct bflb_dma_channel_lli_pool_s lli[1]; /* max trasnfer size 4064 * 1 */
2struct bflb_dma_channel_lli_transfer_s transfers[1];
3
4transfers[0].src_addr = (uint32_t)SIN_LIST;
5transfers[0].dst_addr = (uint32_t)DMA_ADDR_DAC_TDR;
6transfers[0].nbytes = sizeof(SIN_LIST);
7bflb_l1c_dcache_clean_range((void*)SIN_LIST,sizeof(SIN_LIST));
8
9bflb_dma_channel_lli_reload(dma0_ch0, lli, 1, transfers, 1);
10bflb_dma_channel_start(dma0_ch0);
11
12while (dma_tc_flag0 != 1) {
13 bflb_mtimer_delay_ms(1);
14}
分配一块 lli 内存池,个数为1,最多可以传输 4064 * 1 字节
配置一块内存进行传输
调用
bflb_dma_channel_lli_reload
初始化调用
bflb_dma_channel_start
启动传输等待传输完成并进入中断
编译和烧录
实验现象
DAC Channel A 和 B 对应的 GPIO 输出正弦波。
DAC 各通道对应的 GPIO 如下表:
名称 |
芯片系列 |
精度 |
GPIO |
---|---|---|---|
ChannelA |
BL702 |
10-bit |
GPIO 11 |
BL808 |
10-bit |
GPIO 11 |
|
BL616 |
12-bit |
GPIO 3 |
|
ChannelB |
BL702 |
10-bit |
GPIO 17 |
BL808 |
10-bit |
GPIO 4 |
|
BL616 |
12-bit |
GPIO 2 |
GPIO
GPIO - input/output
本 demo 主要介绍 GPIO 0 输出和 GPIO 1 输入功能。
硬件连接
使用杜邦线将 GPIO 0 和 GPIO 1 引脚连接。
软件实现
更详细的代码请参考 examples/peripherals/gpio/gpio_input_output
1board_init();
board_init
中开启时钟
1gpio = bflb_device_get_by_name("gpio");
2
3bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_OUTPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
4bflb_gpio_init(gpio, GPIO_PIN_1, GPIO_INPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_0);
配置 GPIO 0 为 GPIO_OUTPUT 功能,GPIO 1 为 GPIO_INPUT 功能。
1while (1) {
2 bflb_gpio_set(gpio, GPIO_PIN_0);
3 printf("GPIO_PIN_1=%x\r\n", bflb_gpio_read(gpio, GPIO_PIN_1));
4 bflb_mtimer_delay_ms(2000);
5
6 bflb_gpio_reset(gpio, GPIO_PIN_0);
7 printf("GPIO_PIN_1=%x\r\n", bflb_gpio_read(gpio, GPIO_PIN_1));
8 bflb_mtimer_delay_ms(2000);
9}
bflb_gpio_set(gpio, GPIO_PIN_0)
将 GPIO 0 引脚置位bflb_gpio_read(gpio, GPIO_PIN_1)
读取 GPIO 1 引脚电平bflb_gpio_reset(gpio, GPIO_PIN_0)
将 GPIO 0 引脚置 0
编译和烧录
实验现象
打印 GPIO 1 引脚电平。
GPIO - interrupt
本 demo 主要介绍 GPIO 0 的同步低电平中断类型。
硬件连接
将 GPIO 0 和 GND 连接。
软件实现
更详细的代码请参考 examples/peripherals/gpio/gpio_interrupt
1board_init();
board_init
中开启时钟
1gpio = bflb_device_get_by_name("gpio");
2
3bflb_gpio_int_init(gpio, GPIO_PIN_0, GPIO_INT_TRIG_MODE_SYNC_LOW_LEVEL);
设置 GPIO 0 的中断类型。
1bflb_gpio_int_mask(gpio, GPIO_PIN_0, false);
2
3bflb_irq_attach(gpio->irq_num, gpio_isr, gpio);
4bflb_irq_enable(gpio->irq_num);
bflb_gpio_int_mask(gpio, GPIO_PIN_0, false)
打开 GPIO 0 中断bflb_irq_attach(gpio->irq_num, gpio_isr, gpio)
注册 GPIO 中断函数bflb_irq_enable(gpio->irq_num)
使能 GPIO 中断
编译和烧录
实验现象
将 GPIO 0 引脚电平拉低,进入中断并打印中断次数。
各开发板支持的 GPIO 引脚如下表:
I2C
I2C - 10-bit
本 demo 主要介绍 I2C 10-bit slave 模式数据传输。
硬件连接
本 demo 使用到的 gpio 参考 board_i2c0_gpio_init
,将 USB 转 I2C 模块与开发板连接,具体引脚连接方式如下表(以BL616为例):
开发板 I2C 引脚 |
USB 转 I2C 模块 |
---|---|
SCL(GPIO14) |
SCL |
SDA(GPIO15) |
SDA |
软件实现
更详细的代码请参考 examples/peripherals/i2c/i2c_10_bit
1board_init();
board_init
中会开启 I2C IP 时钟,并选择 I2C 时钟源和分频。
1board_i2c0_gpio_init();
配置相关引脚为 I2C 功能
1i2c0 = bflb_device_get_by_name("i2c0");
2
3bflb_i2c_init(i2c0, 400000);
获取 i2c0 句柄,并初始化 i2c0 频率为 400K
1struct bflb_i2c_msg_s msgs[2];
2uint8_t subaddr[2] = { 0x00, 0x04};
3uint8_t write_data[I2C_10BIT_TRANSFER_LENGTH];
4
5/* Write buffer init */
6write_data[0] = 0x55;
7write_data[1] = 0x11;
8write_data[2] = 0x22;
9for (size_t i = 3; i < I2C_10BIT_TRANSFER_LENGTH; i++) {
10 write_data[i] = i;
11}
12
13/* Write data */
14msgs[0].addr = I2C_10BIT_SLAVE_ADDR;
15msgs[0].flags = I2C_M_NOSTOP | I2C_M_TEN;
16msgs[0].buffer = subaddr;
17msgs[0].length = 2;
18
19msgs[1].addr = I2C_10BIT_SLAVE_ADDR;
20msgs[1].flags = 0;
21msgs[1].buffer = write_data;
22msgs[1].length = I2C_10BIT_TRANSFER_LENGTH;
23
24bflb_i2c_transfer(i2c0, msgs, 2);
初始化发送数据(write_data)和配置从设备信息(msgs)
bflb_i2c_transfer(i2c0, msgs, 2)
开启 i2c 传输
编译和烧录
实验现象
通过串口(波特率大于115200)发送``04 00 06 01 03 55``命令给 USB 转 I2C 模块,设置 I2C 从机 10-bit 模式数据传输。 按下开发板中 RST 按键,串口打印开发板发送的 write_data 数据。
I2C - eeprom
本 demo 主要介绍 I2C 读写 eeprom。
硬件连接
本 demo 使用到的 gpio 参考 board_i2c0_gpio_init
,将 eeprom 模块与开发板连接,具体引脚连接方式如下表(以BL616为例):
开发板 I2C 引脚 |
eeprom 模块 |
---|---|
SCL(GPIO14) |
SCL |
SDA(GPIO15) |
SDA |
GND |
GND |
VCC |
VCC |
软件实现
更详细的代码请参考 examples/peripherals/i2c/i2c_eeprom
1board_init();
board_init
中会开启 I2C IP 时钟,并选择 I2C 时钟源和分频。
1board_i2c0_gpio_init();
配置相关引脚为 I2C 功能
1i2c0 = bflb_device_get_by_name("i2c0");
2
3bflb_i2c_init(i2c0, 400000);
获取 i2c0 句柄,并初始化 i2c0 频率为 400K
1struct bflb_i2c_msg_s msgs[2];
2uint8_t subaddr[2] = { 0x00, EEPROM_SELECT_PAGE0};
3uint8_t write_data[256];
4
5/* Write and read buffer init */
6for (size_t i = 0; i < 256; i++) {
7 write_data[i] = i;
8 read_data[i] = 0;
9}
10
11/* Write page 0 */
12msgs[0].addr = 0x50;
13msgs[0].flags = I2C_M_NOSTOP;
14msgs[0].buffer = subaddr;
15msgs[0].length = 2;
16
17msgs[1].addr = 0x50;
18msgs[1].flags = 0;
19msgs[1].buffer = write_data;
20msgs[1].length = EEPROM_TRANSFER_LENGTH;
21
22bflb_i2c_transfer(i2c0, msgs, 2);
初始化发送数据(write_data),接收buffer和配置从设备信息(msgs)
bflb_i2c_transfer(i2c0, msgs, 2)
开启 i2c 传输
1uint8_t read_data[256];
2
3/* Read page 0 */
4msgs[1].addr = 0x50;
5msgs[1].flags = I2C_M_READ;
6msgs[1].buffer = read_data;
7msgs[1].length = EEPROM_TRANSFER_LENGTH;
8bflb_i2c_transfer(i2c0, msgs, 2);
读取从设备寄存器地址中的数据,存放至 read_data 中
bflb_i2c_transfer(i2c0, msgs, 2)
开启 i2c 传输
1/* Check read data */
2for (uint8_t i = 0; i < EEPROM_TRANSFER_LENGTH; i++) {
3 if (write_data[i] != read_data[i]) {
4 printf("check fail, %d write: %02x, read: %02x\r\n", i, write_data[i], read_data[i]);
5 }
6}
检查发送和读取的数据是否一致
编译和烧录
实验现象
按下 RST 按键,数据传输完成后,打印“write over”,“read over”和“check over”。
I2C - eeprom_dma
本 demo 主要介绍 I2C 使用 DMA 的方式读写 eeprom。
硬件连接
本 demo 使用到的 gpio 参考 board_i2c0_gpio_init
,将 eeprom 模块与开发板连接,具体引脚连接方式如下表(以BL616为例):
开发板 I2C 引脚 |
eeprom 模块 |
---|---|
SCL(GPIO14) |
SCL |
SDA(GPIO15) |
SDA |
GND |
GND |
VCC |
VCC |
软件实现
更详细的代码请参考 examples/peripherals/i2c/i2c_eeprom_dma
1board_init();
board_init
中会开启 I2C IP 时钟,并选择 I2C 时钟源和分频。
1board_i2c0_gpio_init();
配置相关引脚为 I2C 功能
1/* Send and receive buffer init */
2for (size_t i = 0; i < 32; i++) {
3 ((uint8_t *)send_buffer)[i] = i;
4 ((uint8_t *)receive_buffer)[i] = 0;
5}
6
7i2c0 = bflb_device_get_by_name("i2c0");
8
9bflb_i2c_init(i2c0, 400000);
10bflb_i2c_link_txdma(i2c0, true);
11bflb_i2c_link_rxdma(i2c0, true);
初始化发送和接收 buffer
获取 i2c0 句柄,并初始化 i2c0 频率为 400K
bflb_i2c_link_txdma(i2c0, true)
开启 I2C TX DMA 功能bflb_i2c_link_rxdma(i2c0, true)
开启 I2C RX DMA 功能
1/* Write page 0 */
2dma0_ch0 = bflb_device_get_by_name("dma0_ch0");
3
4struct bflb_dma_channel_config_s tx_config;
5
6tx_config.direction = DMA_MEMORY_TO_PERIPH;
7tx_config.src_req = DMA_REQUEST_NONE;
8tx_config.dst_req = DMA_REQUEST_I2C0_TX;
9tx_config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
10tx_config.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
11tx_config.src_burst_count = DMA_BURST_INCR1;
12tx_config.dst_burst_count = DMA_BURST_INCR1;
13tx_config.src_width = DMA_DATA_WIDTH_32BIT;
14tx_config.dst_width = DMA_DATA_WIDTH_32BIT;
15bflb_dma_channel_init(dma0_ch0, &tx_config);
16
17bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);
对于 TX, DMA 的配置如下:传输方向(direction)为内存到外设(MEMORY_TO_PERIPH),源请求(src_req)为内存,目标请求(dst_req)为 DMA_REQUEST_I2C0_TX
调用
bflb_dma_channel_init(dma0_ch0, &tx_config)
初始化 DMA调用
bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL)
注册 dma 通道 0 中断
1struct bflb_dma_channel_lli_pool_s tx_llipool[20]; /* max trasnfer size 4064 * 20 */
2struct bflb_dma_channel_lli_transfer_s tx_transfers[1];
3tx_transfers[0].src_addr = (uint32_t)send_buffer;
4tx_transfers[0].dst_addr = (uint32_t)DMA_ADDR_I2C0_TDR;
5tx_transfers[0].nbytes = 32;
6bflb_dma_channel_lli_reload(dma0_ch0, tx_llipool, 20, tx_transfers, 1);
7
8msgs[0].addr = 0x50;
9msgs[0].flags = I2C_M_NOSTOP;
10msgs[0].buffer = subaddr;
11msgs[0].length = 2;
12
13msgs[1].addr = 0x50;
14msgs[1].flags = I2C_M_DMA;
15msgs[1].buffer = NULL;
16msgs[1].length = 32;
17bflb_i2c_transfer(i2c0, msgs, 2);
18
19bflb_dma_channel_start(dma0_ch0);
分配二十块 lli 内存池,最多可以传输 4064 * 20 字节
配置一块内存(tx_transfers)进行传输,源地址(src_addr)为存储发送数据的内存地址(send_buffer),目标地址(dst_addr)为 I2C TX FIFO地址(DMA_ADDR_I2C0_TDR)
调用
bflb_dma_channel_lli_reload(dma0_ch0, tx_llipool, 20, tx_transfers, 1)
初始化调用
bflb_i2c_transfer(i2c0, msgs, 2)
开启 I2C 传输调用
bflb_dma_channel_start(dma0_ch0)
启动 DMA 传输
1/* Read page 0 */
2dma0_ch1 = bflb_device_get_by_name("dma0_ch1");
3
4struct bflb_dma_channel_config_s rx_config;
5
6rx_config.direction = DMA_PERIPH_TO_MEMORY;
7rx_config.src_req = DMA_REQUEST_I2C0_RX;
8rx_config.dst_req = DMA_REQUEST_NONE;
9rx_config.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
10rx_config.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
11rx_config.src_burst_count = DMA_BURST_INCR1;
12rx_config.dst_burst_count = DMA_BURST_INCR1;
13rx_config.src_width = DMA_DATA_WIDTH_32BIT;
14rx_config.dst_width = DMA_DATA_WIDTH_32BIT;
15bflb_dma_channel_init(dma0_ch1, &rx_config);
16
17bflb_dma_channel_irq_attach(dma0_ch1, dma0_ch1_isr, NULL);
对于 RX, DMA 的配置如下:传输方向(direction)为外设到内存(PERIPH_TO_MEMORY),源请求(src_req)为 DMA_REQUEST_I2C0_RX ,目标请求(dst_req)为内存
调用
bflb_dma_channel_init(dma0_ch1, &rx_config)
初始化 DMA调用
bflb_dma_channel_irq_attach(dma0_ch1, dma0_ch1_isr, NULL)
注册 dma 通道 1 中断
1struct bflb_dma_channel_lli_pool_s rx_llipool[20];
2struct bflb_dma_channel_lli_transfer_s rx_transfers[1];
3rx_transfers[0].src_addr = (uint32_t)DMA_ADDR_I2C0_RDR;
4rx_transfers[0].dst_addr = (uint32_t)receive_buffer;
5rx_transfers[0].nbytes = 32;
6
7bflb_dma_channel_lli_reload(dma0_ch1, rx_llipool, 20, rx_transfers, 1);
8
9msgs[1].addr = 0x50;
10msgs[1].flags = I2C_M_DMA | I2C_M_READ;
11msgs[1].buffer = NULL;
12msgs[1].length = 32;
13bflb_i2c_transfer(i2c0, msgs, 2);
14
15bflb_dma_channel_start(dma0_ch1);
分配二十块 lli 内存池,最多可以传输 4064 * 20 字节
配置一块内存(rx_transfers)进行传输,源地址(src_addr)为 I2C RX FIFO地址(DMA_ADDR_I2C0_RDR),目标地址(dst_addr)为存储接收数据的内存地址(receive_buffer)
调用
bflb_dma_channel_lli_reload(dma0_ch1, rx_llipool, 20, rx_transfers, 1)
初始化调用
bflb_i2c_transfer(i2c0, msgs, 2)
开启 I2C 传输调用
bflb_dma_channel_start(dma0_ch1)
启动 DMA 传输
1while (dma_tc_flag1 == 0) {
2}
3while ((bflb_i2c_get_intstatus(i2c0) & I2C_INTSTS_END) == 0) {
4}
5bflb_i2c_deinit(i2c0);
数据传输完成后,复位 I2C 模块
1/* Check read data */
2for (uint8_t i = 0; i < 32; i++) {
3 if (((uint8_t *)send_buffer)[i] != ((uint8_t *)receive_buffer)[i]) {
4 printf("check fail, %d write: %02x, read: %02x\r\n", i, ((uint8_t *)send_buffer)[i], ((uint8_t *)receive_buffer)[i]);
5 }
6}
检查发送和读取的数据是否一致
编译和烧录
实验现象
按下 RST 按键,数据传输完成后,打印“write over”,“read over”和“check over”。
I2C - eeprom_interrupt
本 demo 主要介绍 I2C 使用中断的方式读写 eeprom。
硬件连接
本 demo 使用到的 gpio 参考 board_i2c0_gpio_init
,将 eeprom 模块与开发板连接,具体引脚连接方式如下表(以BL616为例):
开发板 I2C 引脚 |
eeprom 模块 |
---|---|
SCL(GPIO14) |
SCL |
SDA(GPIO15) |
SDA |
GND |
GND |
VCC |
VCC |
软件实现
更详细的代码请参考 examples/peripherals/i2c/i2c_eeprom_interrupt
1board_init();
board_init
中会开启 I2C IP 时钟,并选择 I2C 时钟源和分频。
1board_i2c0_gpio_init();
配置相关引脚为 I2C 功能
1i2c0 = bflb_device_get_by_name("i2c0");
2
3bflb_i2c_init(i2c0, 400000);
获取 i2c0 句柄,并初始化 i2c0 频率为 400K
1/* Set i2c interrupt */
2bflb_i2c_int_mask(i2c0, I2C_INTEN_END | I2C_INTEN_TX_FIFO | I2C_INTEN_RX_FIFO | I2C_INTEN_NACK | I2C_INTEN_ARB | I2C_INTEN_FER, false);
3bflb_irq_attach(i2c0->irq_num, i2c_isr, NULL);
4bflb_irq_enable(i2c0->irq_num);
调用
bflb_i2c_int_mask(i2c0, I2C_INTEN_END | I2C_INTEN_TX_FIFO | I2C_INTEN_RX_FIFO | I2C_INTEN_NACK | I2C_INTEN_ARB | I2C_INTEN_FER, false)
打开 I2C 中断注册 I2C 中断
1uint8_t write_data[256];
2uint8_t read_data[256];
3
4/* Write and read buffer init */
5for (size_t i = 0; i < 256; i++) {
6 write_data[i] = i;
7 read_data[i] = 0;
8}
初始化发送和接收 buffer
1/* Write page 0 */
2subaddr[1] = EEPROM_SELECT_PAGE0;
3
4msgs[0].addr = 0x50;
5msgs[0].flags = I2C_M_NOSTOP;
6msgs[0].buffer = subaddr;
7msgs[0].length = 2;
8
9msgs[1].addr = 0x50;
10msgs[1].flags = 0;
11msgs[1].buffer = write_data;
12msgs[1].length = EEPROM_TRANSFER_LENGTH;
13
14bflb_i2c_transfer(i2c0, msgs, 2);
15if (txFifoFlag) {
16 printf("TX FIFO Ready interrupt generated\r\n");
17 txFifoFlag = 0;
18}
19if (rxFifoFlag) {
20 printf("RX FIFO Ready interrupt generated\r\n");
21 rxFifoFlag = 0;
22}
23printf("write over\r\n\r\n");
24bflb_mtimer_delay_ms(100);
bflb_i2c_transfer(i2c0, msgs, 2)
开启 i2c 传输
1/* Unmask interrupt */
2bflb_i2c_int_mask(i2c0, I2C_INTEN_END | I2C_INTEN_TX_FIFO | I2C_INTEN_RX_FIFO | I2C_INTEN_NACK | I2C_INTEN_ARB | I2C_INTEN_FER, false);
3
4/* Write page 1 */
5subaddr[1] = EEPROM_SELECT_PAGE1;
6
7msgs[1].addr = 0x50;
8msgs[1].flags = 0;
9msgs[1].buffer = write_data + EEPROM_TRANSFER_LENGTH;
10msgs[1].length = EEPROM_TRANSFER_LENGTH;
11
12bflb_i2c_transfer(i2c0, msgs, 2);
13if (txFifoFlag) {
14 printf("TX FIFO Ready interrupt generated\r\n");
15 txFifoFlag = 0;
16}
17if (rxFifoFlag) {
18 printf("RX FIFO Ready interrupt generated\r\n");
19 rxFifoFlag = 0;
20}
21printf("write over\r\n\r\n");
22bflb_mtimer_delay_ms(100);
开启 I2C 中断,进行第二次数据传输
1/* Unmask interrupt */
2bflb_i2c_int_mask(i2c0, I2C_INTEN_END | I2C_INTEN_TX_FIFO | I2C_INTEN_RX_FIFO | I2C_INTEN_NACK | I2C_INTEN_ARB | I2C_INTEN_FER, false);
3
4/* Read page 0 */
5subaddr[1] = EEPROM_SELECT_PAGE0;
6
7msgs[1].addr = 0x50;
8msgs[1].flags = I2C_M_READ;
9msgs[1].buffer = read_data;
10msgs[1].length = EEPROM_TRANSFER_LENGTH;
11bflb_i2c_transfer(i2c0, msgs, 2);
12if (txFifoFlag) {
13 printf("TX FIFO Ready interrupt generated\r\n");
14 txFifoFlag = 0;
15}
16if (rxFifoFlag) {
17 printf("RX FIFO Ready interrupt generated\r\n");
18 rxFifoFlag = 0;
19}
20printf("read over\r\n\r\n");
读取 eeprom 的数据
1/* Unmask interrupt */
2bflb_i2c_int_mask(i2c0, I2C_INTEN_END | I2C_INTEN_TX_FIFO | I2C_INTEN_RX_FIFO | I2C_INTEN_NACK | I2C_INTEN_ARB | I2C_INTEN_FER, false);
3
4/* Read page 1 */
5subaddr[1] = EEPROM_SELECT_PAGE1;
6
7msgs[1].addr = 0x50;
8msgs[1].flags = I2C_M_READ;
9msgs[1].buffer = read_data + EEPROM_TRANSFER_LENGTH;
10msgs[1].length = EEPROM_TRANSFER_LENGTH;
11bflb_i2c_transfer(i2c0, msgs, 2);
12if (txFifoFlag) {
13 printf("TX FIFO Ready interrupt generated\r\n");
14 txFifoFlag = 0;
15}
16if (rxFifoFlag) {
17 printf("RX FIFO Ready interrupt generated\r\n");
18 rxFifoFlag = 0;
19}
第二次读取数据
1/* Check read data */
2for (uint8_t i = 0; i < 2 * EEPROM_TRANSFER_LENGTH; i++) {
3 if (write_data[i] != read_data[i]) {
4 printf("check fail, %d write: %02x, read: %02x\r\n", i, write_data[i], read_data[i]);
5 }
6}
检查发送和读取的数据是否一致
编译和烧录
实验现象
按下 RST 按键,数据传输完成后,打印“write over”,“read over”和“check over”。
I2C 信号引脚对应的 GPIO 如下表:
信号 |
芯片系列 |
GPIO |
---|---|---|
SCL |
BL702 |
|
BL808 |
||
BL616 |
GPIO 14 |
|
SDA |
BL702 |
|
BL808 |
||
BL616 |
GPIO 15 |
IR
IR - nec
本 demo 主要介绍 IR 以 nec 协议收发数据。
硬件连接
本 demo 使用到的 gpio 参考 board_ir_gpio_init
,将红外发射二极管和接收头与 IR 引脚连接,具体连接方式如下表(以BL808为例):
开发板 IR 引脚 |
外接模块 |
---|---|
VCC |
红外接收头 VCC |
GND |
红外接收头 GND |
RX(GPIO17) |
红外接收头 OUT |
VCC |
红外发射二极管正极 |
TX(GPIO11) |
红外发射二极管负极 |
软件实现
更详细的代码请参考 examples/peripherals/ir/ir_nec
1board_init();
board_init
中会开启 IR 时钟,并选择 IR 时钟源和分频。
1board_ir_gpio_init();
配置相关引脚为 IR 功能
1uint32_t tx_buffer[1] = { 0xE916FF00 };
2struct bflb_ir_tx_config_s tx_cfg;
3
4irtx = bflb_device_get_by_name("irtx");
5
6/* TX init */
7tx_cfg.tx_mode = IR_TX_NEC;
8bflb_ir_tx_init(irtx, &tx_cfg);
获取 irtx 句柄
设置 tx_mode 为 NEC 模式,调用
bflb_ir_tx_init(irtx, &tx_cfg)
初始化 ir tx
1uint64_t rx_data;
2uint8_t rx_len;
3struct bflb_ir_rx_config_s rx_cfg;
4
5irrx = bflb_device_get_by_name("irrx");
6
7/* RX init */
8rx_cfg.rx_mode = IR_RX_NEC;
9rx_cfg.input_inverse = true;
10rx_cfg.deglitch_enable = false;
11bflb_ir_rx_init(irrx, &rx_cfg);
12
13/* Enable rx, wait for sending */
14bflb_ir_rx_enable(irrx, true);
获取 irrx 句柄
设置 rx_mode 为 NEC 模式,调用
bflb_ir_rx_init(irrx, &rx_cfg)
初始化 ir rx调用
bflb_ir_rx_enable(irrx, true)
使能 ir rx,等待数据发送
1bflb_ir_send(irtx, tx_buffer, 1);
2rx_len = bflb_ir_receive(irrx, &rx_data);
调用
bflb_ir_send(irtx, tx_buffer, 1)
发送 tx_buffer 中的数据调用
bflb_ir_receive(irrx, &rx_data)
将接收到的数据存放在 rx_data 中
1/* Check data received */
2if (rx_data != tx_buffer[0]) {
3 printf("Data error! receive bit: %d, value: 0x%016lx\r\n", rx_len, rx_data);
4} else {
5 printf("Received correctly. receive bit: %d, value: 0x%016lx\r\n", rx_len, rx_data);
6}
检查发送和接收的数据是否一致
编译和烧录
实验现象
按下开发板中 RST 按键,串口打印接收到的数据。
IR - rc5
本 demo 主要介绍 IR 以 rc5 协议收发数据。
硬件连接
本 demo 使用到的 gpio 参考 board_ir_gpio_init
,将红外发射二极管和接收头与 IR 引脚连接,具体连接方式如下表(以BL808为例):
开发板 IR 引脚 |
外接模块 |
---|---|
VCC |
红外接收头 VCC |
GND |
红外接收头 GND |
RX(GPIO17) |
红外接收头 OUT |
VCC |
红外发射二极管正极 |
TX(GPIO11) |
红外发射二极管负极 |
软件实现
更详细的代码请参考 examples/peripherals/ir/ir_rc5
1board_init();
board_init
中会开启 IR 时钟,并选择 IR 时钟源和分频。
1board_ir_gpio_init();
配置相关引脚为 IR 功能
1uint32_t tx_buffer[1] = { 0x123D };
2struct bflb_ir_tx_config_s tx_cfg;
3
4irtx = bflb_device_get_by_name("irtx");
5
6/* TX init */
7tx_cfg.tx_mode = IR_TX_RC5;
8bflb_ir_tx_init(irtx, &tx_cfg);
获取 irtx 句柄
设置 tx_mode 为 RC5 模式,调用
bflb_ir_tx_init(irtx, &tx_cfg)
初始化 ir tx
1uint64_t rx_data;
2uint8_t rx_len;
3struct bflb_ir_rx_config_s rx_cfg;
4
5irrx = bflb_device_get_by_name("irrx");
6
7/* RX init */
8rx_cfg.rx_mode = IR_RX_RC5;
9rx_cfg.input_inverse = true;
10rx_cfg.deglitch_enable = false;
11bflb_ir_rx_init(irrx, &rx_cfg);
12
13/* Enable rx, wait for sending */
14bflb_ir_rx_enable(irrx, true);
获取 irrx 句柄
设置 rx_mode 为 RC5 模式,调用
bflb_ir_rx_init(irrx, &rx_cfg)
初始化 ir rx调用
bflb_ir_rx_enable(irrx, true)
使能 ir rx,等待数据发送
1bflb_ir_send(irtx, tx_buffer, 1);
2rx_len = bflb_ir_receive(irrx, &rx_data);
调用
bflb_ir_send(irtx, tx_buffer, 1)
发送 tx_buffer 中的数据调用
bflb_ir_receive(irrx, &rx_data)
将接收到的数据存放在 rx_data 中
1/* Check data received */
2if (rx_data != tx_buffer[0]) {
3 printf("Data error! receive bit: %d, value: 0x%016lx\r\n", rx_len, rx_data);
4} else {
5 printf("Received correctly. receive bit: %d, value: 0x%016lx\r\n", rx_len, rx_data);
6}
检查发送和接收的数据是否一致
编译和烧录
实验现象
按下开发板中 RST 按键,串口打印接收到的数据。
IR - swm
本 demo 主要介绍 IR 以软件模式收发数据。
硬件连接
本 demo 使用到的 gpio 参考 board_ir_gpio_init
,将红外发射二极管和接收头与 IR 引脚连接,具体连接方式如下表(以BL808为例):
开发板 IR 引脚 |
外接模块 |
---|---|
VCC |
红外接收头 VCC |
GND |
红外接收头 GND |
RX(GPIO17) |
红外接收头 OUT |
VCC |
红外发射二极管正极 |
TX(GPIO11) |
红外发射二极管负极 |
软件实现
更详细的代码请参考 examples/peripherals/ir/ir_swm
1board_init();
board_init
中会开启 IR 时钟,并选择 IR 时钟源和分频。
1board_ir_gpio_init();
配置相关引脚为 IR 功能
1uint16_t tx_buffer[] = { 1777, 1777, 3555, 3555, 1777, 1777, 1777, 1777, 1777, 1777,
2 3555, 1777, 1777, 1777, 1777, 3555, 3555, 1777, 1777, 3555, 1777 };
3struct bflb_ir_tx_config_s tx_cfg;
4
5irtx = bflb_device_get_by_name("irtx");
6
7/* TX init */
8tx_cfg.tx_mode = IR_TX_SWM;
9bflb_ir_tx_init(irtx, &tx_cfg);
获取 irtx 句柄
设置 tx_mode 为 SWM 模式,调用
bflb_ir_tx_init(irtx, &tx_cfg)
初始化 ir tx
1uint16_t rx_buffer[30];
2uint8_t rx_len;
3struct bflb_ir_rx_config_s rx_cfg;
4
5irrx = bflb_device_get_by_name("irrx");
6
7/* RX init */
8rx_cfg.rx_mode = IR_RX_SWM;
9rx_cfg.input_inverse = true;
10rx_cfg.deglitch_enable = false;
11rx_cfg.end_threshold = 3999;
12bflb_ir_rx_init(irrx, &rx_cfg);
13
14/* Enable rx, wait for sending */
15bflb_ir_rx_enable(irrx, true);
获取 irrx 句柄
设置 rx_mode 为 SWM 模式,调用
bflb_ir_rx_init(irrx, &rx_cfg)
初始化 ir rx调用
bflb_ir_rx_enable(irrx, true)
使能 ir rx,等待数据发送
1bflb_ir_swm_send(irtx, tx_buffer, sizeof(tx_buffer) / sizeof(tx_buffer[0]));
2rx_len = bflb_ir_swm_receive(irrx, rx_buffer, 30);
调用
bflb_ir_swm_send(irtx, tx_buffer, sizeof(tx_buffer) / sizeof(tx_buffer[0]))
发送 tx_buffer 中的数据调用
bflb_ir_swm_receive(irrx, rx_buffer, 30)
将接收到的数据存放在 rx_buffer 中
编译和烧录
实验现象
按下开发板中 RST 按键,串口打印接收到的数据。
IR - tx_dma
本 demo 主要介绍 IR 使用 DMA 的方式发送数据。
硬件连接
本 demo 使用到的 gpio 参考 board_ir_gpio_init
,将红外发射二极管与 IR 引脚连接,具体连接方式如下表(以BL808为例):
开发板 IR 引脚 |
外接模块 |
---|---|
VCC |
红外发射二极管正极 |
TX(GPIO11) |
红外发射二极管负极 |
软件实现
更详细的代码请参考 examples/peripherals/ir/ir_tx_dma
1board_init();
board_init
中会开启 IR 时钟,并选择 IR 时钟源和分频。
1board_ir_gpio_init();
配置相关引脚为 IR 功能
1struct bflb_ir_tx_config_s tx_cfg = {
2 .tx_mode = IR_TX_CUSTOMIZE,
3 .data_bits = 0,
4 .tail_inverse = 0,
5 .tail_enable = 0,
6 .head_inverse = 0,
7 .head_enable = 0,
8 .logic1_inverse = 1,
9 .logic0_inverse = 1,
10 .data_enable = 1,
11 .swm_enable = 0,
12 .output_modulation = 1,
13 .output_inverse = 0,
14 .freerun_enable = 1,
15 .continue_enable = 1,
16 .fifo_width = IR_TX_FIFO_WIDTH_24BIT,
17 .fifo_threshold = 1,
18 .logic0_pulse_width_1 = 0,
19 .logic0_pulse_width_0 = 0,
20 .logic1_pulse_width_1 = 2,
21 .logic1_pulse_width_0 = 0,
22 .head_pulse_width_1 = 0,
23 .head_pulse_width_0 = 0,
24 .tail_pulse_width_1 = 0,
25 .tail_pulse_width_0 = 0,
26 .modu_width_1 = 17,
27 .modu_width_0 = 34,
28 .pulse_width_unit = 1124,
29};
30
31irtx = bflb_device_get_by_name("irtx");
32
33/* TX init */
34bflb_ir_tx_init(irtx, &tx_cfg);
35bflb_ir_link_txdma(irtx, true);
36bflb_ir_tx_enable(irtx, true);
获取 irtx 句柄
设置 tx_mode 为 IR_TX_CUSTOMIZE 模式,调用
bflb_ir_tx_init(irtx, &tx_cfg)
初始化 ir tx调用
bflb_ir_link_txdma(irtx, true)
使能 ir tx dma 功能调用
bflb_ir_tx_enable(irtx, true)
开启 ir tx
1struct bflb_dma_channel_config_s dma_config = {
2 .direction = DMA_MEMORY_TO_PERIPH,
3 .src_req = DMA_REQUEST_NONE,
4 .dst_req = DMA_REQUEST_IR_TX,
5 .src_addr_inc = DMA_ADDR_INCREMENT_ENABLE,
6 .dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE,
7 .src_burst_count = DMA_BURST_INCR1,
8 .dst_burst_count = DMA_BURST_INCR1,
9 .src_width = DMA_DATA_WIDTH_32BIT,
10 .dst_width = DMA_DATA_WIDTH_32BIT,
11};
12
13for (i = 0; i < 128; i++) {
14 tx_buffer[i] = i * 0x01010101;
15}
16
17dma0_ch0 = bflb_device_get_by_name("dma0_ch0");
18bflb_dma_channel_init(dma0_ch0, &dma_config);
19bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);
对于 TX, DMA 的配置如下:传输方向(direction)为内存到外设(MEMORY_TO_PERIPH),源请求(src_req)为内存,目标请求(dst_req)为 DMA_REQUEST_IR_TX
初始化 tx_buffer
调用
bflb_dma_channel_init(dma0_ch0, &dma_config)
初始化 DMA调用
bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL)
注册 dma 通道 0 中断
1struct bflb_dma_channel_lli_pool_s tx_llipool[1];
2struct bflb_dma_channel_lli_transfer_s tx_transfers[1];
3
4tx_transfers[0].src_addr = (uint32_t)tx_buffer;
5tx_transfers[0].dst_addr = (uint32_t)DMA_ADDR_IR_TDR;
6tx_transfers[0].nbytes = 128 * 4;
7bflb_dma_channel_lli_reload(dma0_ch0, tx_llipool, 1, tx_transfers, 1);
8bflb_dma_channel_start(dma0_ch0);
分配一块 lli 内存池,最多可以传输 4064 * 1 字节
配置一块内存(tx_transfers)进行传输,源地址(src_addr)为存储发送数据的内存地址(tx_buffer),目标地址(dst_addr)为 IR TX FIFO地址(DMA_ADDR_IR_TDR)
调用
bflb_dma_channel_lli_reload(dma0_ch0, tx_llipool, 1, tx_transfers, 1)
初始化调用
bflb_dma_channel_start(dma0_ch0)
启动 DMA 传输
1while (dma_tc_flag0 != 1) {
2 bflb_mtimer_delay_ms(1);
3}
4printf("Check wave\r\n");
DMA 传输完成后,查看波形
编译和烧录
实验现象
按下 RST 按键,数据传输完成后,查看波形是否正确。
各系列芯片对 IR 接收和发送的支持情况如下表:
信号 |
芯片系列 |
GPIO |
---|---|---|
IR TX |
BL702 |
支持 |
BL808 |
支持 |
|
BL616 |
不支持 |
|
IR RX |
BL702 |
支持 |
BL808 |
支持 |
|
BL616 |
支持 |
UART
UART - poll
本 demo 主要演示 UART 轮询模式收发功能。
硬件连接
芯片 UART TX 引脚连接 USB2TTL 模块 RX
芯片 UART RX 引脚连接 USB2TTL 模块 TX
本 demo 使用到的 gpio 如下表:
名称 |
芯片型号 |
GPIO |
---|---|---|
UART1_TX |
BL702 |
GPIO 18 |
BL616 |
GPIO 23 |
|
UART1_RX |
BL702 |
GPIO 19 |
BL616 |
GPIO 24 |
软件实现
具体软件代码见 examples/peripherals/uart/uart_poll
1board_init();
board_init
中会开启 UART IP 时钟,并选择 UART 时钟源和分频。
1board_uartx_gpio_init();
配置相关引脚为
UARTx TX
、UARTx RX
功能,默认 demo 使用 UART1 外设。
1uartx = bflb_device_get_by_name(DEFAULT_TEST_UART);
2
3struct bflb_uart_config_s cfg;
4
5cfg.baudrate = 2000000;
6cfg.data_bits = UART_DATA_BITS_8;
7cfg.stop_bits = UART_STOP_BITS_1;
8cfg.parity = UART_PARITY_NONE;
9cfg.flow_ctrl = 0;
10cfg.tx_fifo_threshold = 7;
11cfg.rx_fifo_threshold = 7;
12bflb_uart_init(uartx, &cfg);
获取 DEFAULT_TEST_UART 句柄,并初始化 UART
1int ch;
2while (1) {
3 ch = bflb_uart_getchar(uartx);
4 if (ch != -1) {
5 bflb_uart_putchar(uartx, ch);
6 }
7}
调用
bflb_uart_getchar
从 uart rx fifo 中读取数据,如果返回 -1,表示没有数据调用
bflb_uart_putchar
将数据 ch 填充到 uart tx fifo 中
编译和烧录
实验现象
将 UART1 TX, RX, GND 引脚分别与 USB2TTL 模块 RX, TX, GND 相连,按下 reset 按键。
使用串口给 UART1 发送 0123456789
,USB2TTL 模块能接收到同样的数据。
UART - dma
本 demo 主要演示 UART dma 模式收发功能。
硬件连接
芯片 UART TX 引脚连接 USB2TTL 模块 RX
芯片 UART RX 引脚连接 USB2TTL 模块 TX
本 demo 使用到的 gpio 如下表:
名称 |
芯片型号 |
GPIO |
---|---|---|
UART1_TX |
BL702 |
GPIO 18 |
BL616 |
GPIO 23 |
|
UART1_RX |
BL702 |
GPIO 19 |
BL616 |
GPIO 24 |
软件实现
具体软件代码见 examples/peripherals/uart/uart_podma
1board_init();
board_init
中会开启 UART IP 时钟,并选择 UART 时钟源和分频。
1board_uartx_gpio_init();
配置相关引脚为
UARTx TX
、UARTx RX
功能,默认 demo 使用 UART1 外设。
1uartx = bflb_device_get_by_name(DEFAULT_TEST_UART);
2
3struct bflb_uart_config_s cfg;
4
5cfg.baudrate = 2000000;
6cfg.data_bits = UART_DATA_BITS_8;
7cfg.stop_bits = UART_STOP_BITS_1;
8cfg.parity = UART_PARITY_NONE;
9cfg.flow_ctrl = 0;
10cfg.tx_fifo_threshold = 7;
11cfg.rx_fifo_threshold = 7;
12bflb_uart_init(uartx, &cfg);
获取 DEFAULT_TEST_UART 句柄,并初始化 UART
1bflb_uart_link_txdma(uartx, true);
2bflb_uart_link_rxdma(uartx, true);
使能 uart tx、rx dma 功能
1struct bflb_dma_channel_config_s config;
2
3config.direction = DMA_MEMORY_TO_PERIPH;
4config.src_req = DMA_REQUEST_NONE;
5config.dst_req = DEFAULT_TEST_UART_DMA_TX_REQUEST;
6config.src_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
7config.dst_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
8config.src_burst_count = DMA_BURST_INCR1;
9config.dst_burst_count = DMA_BURST_INCR1;
10config.src_width = DMA_DATA_WIDTH_8BIT;
11config.dst_width = DMA_DATA_WIDTH_8BIT;
12bflb_dma_channel_init(dma0_ch0, &config);
13
14struct bflb_dma_channel_config_s rxconfig;
15
16rxconfig.direction = DMA_PERIPH_TO_MEMORY;
17rxconfig.src_req = DEFAULT_TEST_UART_DMA_RX_REQUEST;
18rxconfig.dst_req = DMA_REQUEST_NONE;
19rxconfig.src_addr_inc = DMA_ADDR_INCREMENT_DISABLE;
20rxconfig.dst_addr_inc = DMA_ADDR_INCREMENT_ENABLE;
21rxconfig.src_burst_count = DMA_BURST_INCR1;
22rxconfig.dst_burst_count = DMA_BURST_INCR1;
23rxconfig.src_width = DMA_DATA_WIDTH_8BIT;
24rxconfig.dst_width = DMA_DATA_WIDTH_8BIT;
25bflb_dma_channel_init(dma0_ch1, &rxconfig);
26
27bflb_dma_channel_irq_attach(dma0_ch0, dma0_ch0_isr, NULL);
28bflb_dma_channel_irq_attach(dma0_ch1, dma0_ch1_isr, NULL);
配置 DMA CH0 为 UARTx TX , DMA CH1 为 UARTx RX .
注册 dma 通道中断
1struct bflb_dma_channel_lli_pool_s tx_llipool[20]; /* max trasnfer size 4064 * 20 */
2struct bflb_dma_channel_lli_transfer_s tx_transfers[3];
3
4tx_transfers[0].src_addr = (uint32_t)src_buffer;
5tx_transfers[0].dst_addr = (uint32_t)DEFAULT_TEST_UART_DMA_TDR;
6tx_transfers[0].nbytes = 4100;
7
8tx_transfers[1].src_addr = (uint32_t)src2_buffer;
9tx_transfers[1].dst_addr = (uint32_t)DEFAULT_TEST_UART_DMA_TDR;
10tx_transfers[1].nbytes = 4100;
11
12tx_transfers[2].src_addr = (uint32_t)src3_buffer;
13tx_transfers[2].dst_addr = (uint32_t)DEFAULT_TEST_UART_DMA_TDR;
14tx_transfers[2].nbytes = 4100;
15
16struct bflb_dma_channel_lli_pool_s rx_llipool[20];
17struct bflb_dma_channel_lli_transfer_s rx_transfers[1];
18rx_transfers[0].src_addr = (uint32_t)DEFAULT_TEST_UART_DMA_RDR;
19rx_transfers[0].dst_addr = (uint32_t)receive_buffer;
20rx_transfers[0].nbytes = 50;
21
22bflb_dma_channel_lli_reload(dma0_ch0, tx_llipool, 20, tx_transfers, 3);
23bflb_dma_channel_lli_reload(dma0_ch1, rx_llipool, 20, rx_transfers, 1);
24bflb_dma_channel_start(dma0_ch0);
25bflb_dma_channel_start(dma0_ch1);
分配一块 lli 内存池,个数为20,最多可以传输 4094 * 20 字节
配置三块不连续的内存进行传输
调用
bflb_dma_channel_lli_reload
初始化调用
bflb_dma_channel_start
启动传输等待传输完成并进入中断
编译和烧录
实验现象
Components
FreeRTOS
本 demo 主要演示 FreeRTOS 基本功能:任务创建和任务切换、信号量、内存管理。更详细的代码请参考 examples/freertos。
内存管理
FreeRTOS 内存管理默认使用 heap3。
中断管理
FreeRTOS 为 RISC-V 提供了统一的中断和异常入口,名为 freertos_risc_v_trap_handler
,该函数主要作用如下:
压栈
根据 mcause 查找 mtimer 中断,并执行
xTaskIncrementTick
根据 mcause 查找 ecall 异常,并执行
vTaskSwitchContext
根据 mcause,如果是非 ecall 异常,则执行
exception_entry
;如果是非 mtimer 中断,则执行portasmHANDLE_INTERRUPT
,portasmHANDLE_INTERRUPT
实际调用interrupt_entry
。出栈
那么问题来了,是如何统一中断和异常的呢?
通常 RISC-V SOC 中断支持 vector 模式和 direct 模式,博流系列芯片都使用了 vector 模式,在 startup/start.S 文件中可以看到
1/* mtvec: for all exceptions and non-vector mode IRQs */
2la a0, default_trap_handler
3ori a0, a0, 3
4csrw mtvec, a0
5
6/* mtvt: for all vector mode IRQs */
7la a0, __Vectors
8csrw mtvt, a0
在 startup/interrupt 中可以找到 __Vectors
:
1const pFunc __Vectors[] __attribute__((section(".init"), aligned(64))) = {
2 default_interrupt_handler, /* */
3 default_interrupt_handler, /* */
4 default_interrupt_handler, /* */
5 ....
6};
此时还没有跟 freertos_risc_v_trap_handler
扯上关系,在 freertos/CMakelist.txt 中配置了 freertos_risc_v_trap_handler
和 default_interrupt_handler
之间的关系。那么当中断触发时,
调用 default_interrupt_handler
其实就是调用 freertos_risc_v_trap_handler
了。
1sdk_add_compile_definitions(-DportasmHANDLE_INTERRUPT=interrupt_entry -Ddefault_interrupt_handler=freertos_risc_v_trap_handler)
在 portASM.S 文件中 xPortStartFirstTask
函数又重新配置了 mtvec
为 freertos_risc_v_trap_handler
,这个时候,中断和异常就统一使用 freertos_risc_v_trap_handler
函数了。
编译和烧录
命令行编译
参考 Build with Linux or WSL 或者 Build with Windows CMD
烧录
参考 bl_dev_cube
实验现象
BLE CLI
TODO
UART 引脚映射详解
博流系列芯片每个 pin 都可以配置成 UART 任意一个功能,这种灵活的配置就会出现一些坑,比如多个 pin 配成了一个 uart 功能。
下面介绍下如何正确的理解 每个 pin 都可以配置成 UART 任意一个功能 并防止踩坑。最后讲下 bflb_gpio_uart_init
函数的实现。
UART SIG
在博流系列芯片中,有个 UART SIG 的概念, 每个 SIG 对应到 UART 所有功能,功能类似于 8选1 选择器或者 12 选1 选择器。并且每个 SIG 都有一个默认的 UART 功能,如图所示:

2 个 pin 选了一个 SIG
每个 GPIO 对应一个 SIG, 对应关系跟芯片相关,比如 BL602/BL702 是 mod 8 的关系,而 BL616/BL808 是 mod 12 的关系,这个时候就会产生一个问题, 存在重复的可能性, 假设现在是 mod 8 的关系,则 GPIO0 跟 GPIO8 都对应 SIG0,如果 GPIO0 配置了 UART 一个功能,则不能再使用 GPIO8,否则会出现两个 GPIO 共用一个功能的情况。
2 个 SIG 选了一个 UART 功能
为了方便软件,代码中将默认功能全部改成了 0xF,所有 SIG 都指向一个没有作用的功能。为什么这么做?
假设 GPIO2 默认使用 UART0 TX,这个时候我想使用 GPIO6 作为 UART0 TX,当我软件中配置 GPIO6 为 UART0 TX 以后,请问,GPIO2 是什么功能?没错,还是 UART0 TX,这个时候就是有问题的。
bflb_gpio_uart_init
针对以上两个问题,出现了 bflb_gpio_uart_init
。该函数的作用是避免了 2 个 SIG 选了一个 UART 功能 ,如果出现了,则后配置的覆盖前面的。
而对于 2 个 pin 选了一个 SIG 则是无法靠软件避免的,只能人为的避免。
DMA 链表模式(LLI)深度解析
博流系列芯片的 DMA 都支持链表模式(LLI)。
在进行一次 DMA 读或者写的时候,可以配置多个链表,从而当一个链表的数据传输完成时,会跳到下一个链表的起始地址,并继续传输数据,直到链表的下一个地址为 0。如果 DMA 使能了完成中断,则当 DMA 发送或者接收完成时,会进入完成中断。
那么有了这种 DMA 链表模式,我们就可以实现以下功能:
DMA 发送或者接收长度不限制
DMA 发送接收地址可以不连续
DMA 实现多种中断模式,半中断、3中断、4中断等等
DMA 实现循环功能
OK,那么当我们开始研究链表配置之前,我们需要了解一些前提: - 每个链表最多传输 4095 ,单位根据位宽决定 - 每个链表都可以触发中断
支持长度不限制
由于每个 dma 链表最多支持 4095,假设位宽用的是字节,那么一个链表最多传输 4095 字节,很显然这个不能满足我们需求,性能太低。那么如何提高传输长度呢?
我们可以使用多个链表,串接起来,这样就能够支持更大的传输长度了,并且传输的地址是连续的,dma 链表连接如图所示:

这个时候还有一个问题,当一个链表使用了 4095 字节,下一个链表是从 4095 的偏移开始,这个时候,就会产生非对齐的问题,如果是在 cache 场景下,是会有问题的。
因此,我们将 4095 减少到 4064,这样保证每个链表的首地址都是 32 字节对齐的。到这就实现了长度不限制的功能,具体实现参考 bflb_dma_lli_config
函数。
1void bflb_dma_lli_config(struct bflb_device_s *dev, struct bflb_dma_channel_lli_pool_s *lli_pool, uint32_t lli_count, uint32_t src_addr, uint32_t dst_addr, uint32_t transfer_offset, uint32_t last_transfer_len)
2{
3 uint32_t channel_base;
4 union bflb_dma_lli_control_s dma_ctrl_cfg;
5
6 channel_base = dev->reg_base;
7
8 dma_ctrl_cfg = (union bflb_dma_lli_control_s)getreg32(channel_base + DMA_CxCONTROL_OFFSET);
9
10 dma_ctrl_cfg.bits.TransferSize = 4064;
11 dma_ctrl_cfg.bits.I = 0;
12
13 /* nbytes will be integer multiple of 4064*n or 4064*2*n or 4064*4*n,(n>0) */
14 for (uint32_t i = 0; i < lli_count; i++) {
15 lli_pool[i].src_addr = src_addr;
16 lli_pool[i].dst_addr = dst_addr;
17 lli_pool[i].nextlli = 0;
18
19 if (dma_ctrl_cfg.bits.SI) {
20 src_addr += transfer_offset;
21 }
22
23 if (dma_ctrl_cfg.bits.DI) {
24 dst_addr += transfer_offset;
25 }
26
27 if (i == lli_count - 1) {
28 dma_ctrl_cfg.bits.TransferSize = last_transfer_len;
29 dma_ctrl_cfg.bits.I = 1;
30 }
31
32 if (i) {
33 lli_pool[i - 1].nextlli = (uint32_t)(uintptr_t)&lli_pool[i];
34 }
35
36 lli_pool[i].control = dma_ctrl_cfg;
37 }
38}
支持地址不连续
刚刚我们解决了长度限制问题,那么本身 dma 链表是支持地址不连续的,我们只需要把上面使用的多个链表当成一个大链表,然后两个大链表拼接,并且两个链表传输的首地址不连续,就可以实现地址不连续了。
具体实现参考 bflb_dma_channel_lli_reload
函数中的 bflb_dma_channel_lli_transfer_s
。dma 链表连接如图所示:

支持多中断
完成了上述两步以后,多中断也就完成了。
当我们支持完长度不限制后,最后一个链表会开启中断,当传输完成最后一个链表时,就会触发中断。
当我们支持完地址不连续后,多个大链表(也就是长度不限制的链表的最后一个链表)完成都会触发中断,假设设定了三个传输 bflb_dma_channel_lli_transfer_s
, 那么会触发三次 DMA 完成中断。