BL MCU SDK development guide
The BL702 series products are general-purpose microcontrollers based on “SiFive E24 Core” RISC-V , with network functions such as BLE 5.0, zigbee and Ethernet, as well as other rich peripherals. It can be used in a wide range of IoT and other low-power applications. Supports programming and debugging of the chip through JTAG , and also supports through UART programming. BL MCU SDK will provide users with comprehensive support for BL70X series MCU development.
Preparation
Hardware environment
At least one board for BL702 series MCU:
BL706_IOT
BL706_AVB
BL706_Iot as shown in the figure below

BL706_IoT
BL706_AVB as shown in the figure below

BL706_AVB
A debugger that supports standard JTAG, just choose one of the following debuggers:
CK-Link
Jlink V11
Sipeed RV-Debugger Plus
Bouffalo Lab Debugger
One PC host (Windows or Linux system)
Software Environment
In order to better use the BL702 series MCU, it is recommended that you have at least one of the following development environments:
Sipeed RV-Debugger Plus driver installation settings
This section mainly introduces the driver installation settings of the Sipeed RV-Debugger Plus debugger.
If you use **CK-Link** or **J-Link**, you don’t need to read this section.

Sipeed RV-Debugger plus
Windows
To use the Sipeed RV-Debugger Plus debugger on Windows we need to change the driver to the
Win USB
driverFirst, connect the Type-C USB interface of the debugger to the PC with a USB data cable, open the device manager of the PC, and you can see that the debugger is recognized as two serial ports in the port column (Note: not the Serial port of the board’s Boot interface), or in the
Universal Serial Bus Controller
, you seeUSB Serial Converter A
andUSB Serial Converter B
重要
The debugger port number must start with
usb serial port
, if you plug in more than one similar device, please leave only one, confirm the debugger port number
重要
If you see “USB Serial Device (COM*)” in the Device Manager, it means that the debugger has entered the “Boot” mode. Please power off the debugger and power it on again, and be careful not to connect the debugger to the target board; at this time, go to the device manager to see if it is normal
重要
If the serial port is not shown in the device manager, only other devices are shown, or if you only see
USB Serial Converter A
andUSB Serial Converter B
in the Universal Serial Bus Controller, please go to the FTDI official website Download the driver that matches your system
Download the
zadig-2.4
replacement driver from the sipeed website. Download : http://dl.sipeed.com/MAIX/tools/sipeed-rv-debugger/zadig-2.4.exe
After downloading, double-click to open
zadig-2.4.exe
, selectOptions
and checkList All Devices
.
Find JTAG Debugger (Interface 0), then select the replacement driver as
WinUSB
and clickReplace Driver
to replace
Open the device manager again and see that one of the serial ports has been replaced with a universal serial bus device, indicating that the installation is successful
At this point, the device driver of Sipeed RV-Debugger Plus has been replaced, and then you can play happily~
Possible problems:
小心
There are no two serial ports when the debugger is connected, and an LED on the debugger is always on, then it should be in Boot mode. Please power off the debugger and power it on again. Be careful not to connect the debugger to the target board; after the debugger is powered on, the two LED lights will flicker and go out under normal circumstances; at this time, check whether the device in the task manager is correct.
小心
If you still can’t use it normally after the above operations, and there is no correct phenomenon, it is recommended to download from the official Sipeed repository GitHub obtain the firmware and re-write; press and hold the
Boot
button on the debugger without releasing it, insert the debugger into the computer and power on, make the debugger enter the Boot mode, and flash the firmware again; power off and restart
Linux
First, connect the Type-C USB interface of the debugger to the PC host using the USB cable, open Terminal, and enter the command
lsusb
in the terminal to see the device with the following information
$ lsusb
...
Bus 001 Device 003: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
...

If the above diagram does not show the
FT2232C
, you need to install the ftdi driver
$ sudo apt install libusb-dev libftdi-dev libhidapi-dev
Re-plug the debugger to make the changes take effect
Debugging code requires openocd to be installed, using openocd version 0.11
备注
In Linux system, /dev/ttyUSB1 is used for serial port, /dev/ttyUSB0 is used for debug port, if /dev/ttyACM0 is displayed, it means boot mode is entered.
Hardware connection
This document introduces how to connect the board of BL70x series MCU.
BL706_IOT
Use CK-Link to Programming and debug
Connect the CK-Link USB interface to the PC with a suitable USB data cable
Connect the standard
JTAG
pin of theHD3
group of the Iot board with theJTAG
pin ofCK-Link
using a DuPont cableIf you do not use CK-Link to power the board, you need to power the board separately
bl706-iot board CK-Link
-------------------------------
JTAG_TDI <--> TDI
JTAG_TDO <--> TDO
JTAG_TCK <--> TCK
JTAG_TMS <--> TMS
VDD33 <--> VREF
GND <--> GND

ck_link connect bl706-iot board
Use J-Link to Programming and debug
Connect the USB interface of j-link to the PC with a USB data cable
Connect the standard
JTAG
pins of theHD3
group of the Iot board with theJTAG
pins of thej-link
using DuPont wiresIn the case of j-link connection, the board needs to be independently powered, and the power supply of the board is connected to the
VTref
pin of j-link
bl706-iot board j-link
-------------------------------
JTAG_TDI <--> TDI
JTAG_TDO <--> TDO
JTAG_TCK <--> TCK
JTAG_TMS <--> TMS
VDD33 <--> VTref
GND <--> GND

jlink connect bl706-iot board
Use serial port to Programming
Before using the serial port to Programming, please make sure that
Bouffalo Lab Dev Cube
or the command programming tool is installed correctlyUse
Type-C USB
data cable orMini USB
data cable to connect to theType-C
interface orMini
interface on the board.Press the
Boot
key on the board, don’t release it.Press the
RST
key on the board, now you have enteredBoot ROM
, you can release the two keys.At this time, you can see the corresponding serial port
COM
number from theBouffalo Lab Dev Cube
, if it does not appear, please click theRefresh
key to refresh.
If you don’t have a suitable data cable, you can also use some common
USB-TTL
modules to connect to the UART0 port of the development board for programming.UART0
is on theHD1
group, the connection method is as follows:
USB-TTL BL702_IoT
----------------------
3V3 <--> VDD
TXD <--> RX0
RXD <--> TX0
GND <--> GND
The programming step is the same as above
BL706_AVB
重要
BL706_AVB has multiple multiplexed pins, please check carefully whether the required function pins are multiplexed; FUNC1: “Default: PIX; Connect: I2S/JTAG”, FUNC2: “Default: I2S; Connect: SPI” ; If you need to debug, please remember to connect the FUNC1 jumper
Use Sipeed RV-Debugger Plus to programming and debug
Powering the BL706_AVB
Connect the RV-Debugger Plus debugger to the USB port of the computer. If the driver is not installed correctly, please refer to Sipeed RV-Debugger Plus driver installation settings, set the driver, and proceed to the following steps
Connect the debugger and the BL706_AVB with a cable (as shown in the figure below)
重要
The FUNC1 jumper must be connected when debugging, otherwise the pins will be multiplexed with other functions and the JTAG function cannot be used; the serial port function can be used normally

RV-Debugger connect bl706_avb board
Use CK-Link to programming and debug
Connect the CK-Link USB interface to the PC with a suitable USB data cable
Connect the FUNC1 jump caps of the bl706_avb
Connect the pins of the
HD8
group to the adapter board using a flat cableConnect the
JTAG
pin of the adapter board with the correspondingJTAG
pin ofCK-Link
using a Dupont wireIf you do not use CK-Link to power the board, you need to power the board separately
bl706-avb board CK-Link
-------------------------------
JTAG_TDI <--> TDI
JTAG_TDO <--> TDO
JTAG_TCK <--> TCK
JTAG_TMS <--> TMS
VDD33 <--> VREF
GND <--> GND

ck_link connect bl706_avb board
Use serial port to programming
Before using the serial port to programming, please make sure that
Bouffalo Lab Dev Cube
or the command programming tool is installed correctlyUse the
Type-C USB
orMini USB
data cable to connect to the correspondingType-C
port orMini
port on the board.Press the
Boot
key on the board, don’t release it.Press the
RST
key on the board, now you have enteredBoot ROM
, you can release the two keys.At this time, you can see the corresponding serial port
COM
number from theBouffalo Lab Dev Cube
, if it does not appear, please click theRefresh
button to refresh.
If you don’t have a suitable data cable, you can also use some common
USB-TTL
modules to connect to the UART0 port of the development board for programming.UART0
on theHD12
group, the connection method is as follows:If you use Sipeed RV-Debugger Plus to connect BL706_AVB through a flat cable, you can also use the serial port of Sipeed RV Debugger Plus
USB-TTL BL706_AVB
----------------------
TXD <--> RX0
RXD <--> TX0
GND <--> GND
Connect BL706 AVB sub-modules
This section describes how to connect the BL706_AVB board with other modules, mainly including camera connection, Audio Codec module connection, and SPI screen connection.
BL706_AVB Connects to GC0308 Camera Module
First, take the black locking part of the
J5
drawer type FPC cable holder on the back of the BL706_AVB development board and pull it out from the edge

When fully disconnected, as shown in the figure below.

The FPC cable holder is a drawer down type, so next insert the camera with the side without metal contact points facing upwards into the FPC cable holder

After inserting the camera, press the black latch tightly

BL706_AVB Connecting Audio Codec Modules
Insert the
HD19
group of pins of Audio Codec module into theHD11
row female socket of BL706_AVB development board; note that the module is extended outward.The schematic diagram is as follows:

Development environment setup guide
Before the formal development, please set up a suitable development environment. The specific steps are as follows:
Guide to using CDK (like MDK Keil) under Windows
This document introduces the use of the CDK developed by T-HEAD Semiconductor under Windows to complete the related software development of BL702 series MCU.
Regarding T-HEAD CDK, this is an integrated development environment developed by T-HEAD. It has operations and settings that are very similar to the traditional MCU development environment, and aims to fully access cloud development resources without changing user development habits, combined with graphical debugging and analysis tools such as OSTracer and Profiling, to accelerate user product development.
Software and hardware environment
T-HEAD CDK software
One USB Type-A data cable, one Type-C data cable
A CK-Link emulator or a Sipeed RV-Debugger Plus debugger
A USB-TTL serial port module
Several Dupont lines
Download CDK
CDK software can be obtained from the official website of T-HEAD OCC
After the download is complete, unzip, double-click
setup.exe
, follow the prompts, and complete the software installation
Download bl_mcu_sdk
Download bl_mcu_sdk from the open source community.
You can use
git clone
or directlydownload
to download the SDKBefore using
git clone
, please make sure thatgit
has been installed correctly, open a terminal that supportsgit
and enter the following command to get the latest SDK
1$ git clone https://gitee.com/bouffalolab/bl_mcu_sdk.git --recursive
Hardware connection
For specific connection methods, please refer to Hardware connection
Please make sure that the board is set up correctly before proceeding to the following steps
Test the Hello World project
When using Sipeed RV-Debugger Plus to debug a project, please follow the steps below:
Use CDK + Sipeed RV-Debugger Plus to compile and debug
Open Hello World
After obtaining the SDK, enter the
examples/hellowd/helloworld/cdk
directory and double-clickhelloworld.cdkproj
to open theHelloworld
project
Compile Hello World

helloworld.cdkproj
Select the
OpenOCD_Debug
project in the drop-down menu. Since Sipeed RV-Debugger Plus uses OpenOCD for debugging, this tutorial is based on theOpenOCD_Debug
project;If Sipeed RV-Debugger Plus does not install the driver correctly, please refer to Sipeed RV-Debugger Plus driver installation settings, set up the driver, and then proceed to the following steps
In the CDK toolbar, click the compile icon to compile the project
Click
1
Build Project
to compile the currently selected projectClick
2
Clean Project
to clear the results of the last compilationClick
3
Flash Download
to download the compiled code to the chip (Flash download function cannot be used with OpenOCD Debug)Click
5
Start/Stop Debug whitout Download
to debug directly without loading the current bin fileYou can also right-click the project name in
Project
, and compile the project through the options in the right-click menu
Program Hello World
When using the OpenOCD mode debugging method in the CDK, it is not currently supported to directly use the CDK related
flash
tool to download the code, so please use the BL Dev Cube tool to program, please refer to BLDevCube start guideUse CDK to debug after the code is programmed
Run Hello World
From the menu bar of the CDK
View->Serial Pane
, open the serial port panel, right-click in the openedSerial Pane
, set the serial port, select your corresponding serial port number and baud rate


CDK Serial Pane setting
Press the
RST
key on the board, you can see the result of the code in the serial port

HelloWorld!
Debug Hello World
Click the
Start/Stop Debugger
button at the top of the toolbar to enter the debug interface, as shown in the figure below

Debug HelloWorld!
In the debug interface, the
Register
window can view theCPU
internal register data; thePeripherals
peripheral panel, you can view the corresponding peripheral register data, the top menu barPeripherals-> System Viewer
can select peripherals; click the relevant debugging button in the upper toolbar to perform operations such as breakpoint setting, single-step debugging, single-step instruction, and full-speed operation. Of course, these operations have corresponding shortcut keys and shortcut setting methods. For details, please refer toCDK Help
.We click the single step button to run the code, and we can see that the cursor moves to the next sentence of code, and we can see our output
Hello World!
displayed in the serial port panel.
When using CK-Link to debug the project, please follow the steps below:
Use CDK + CK-Link to compile and debug
Open Hello World
After obtaining the SDK, enter the
examples/hellowd/helloworld/cdk
directory in the SDK, double-clickhelloworld.cdkproj
, and you can open theHelloworld
project
Compile Hello World

helloworld.cdkproj
In the drop-down menu, you can select the
CK_Link_Debug
orOpenOCD_Debug
project, this tutorial is based on theCK_Link_Debug
projectIn the CDK toolbar, click the compile icon to compile the project
Click the icon
Build Project
at1
to compile the currently selected projectClick the icon
Clean Project
at2
to clear the result of the last compilationClick the
3
iconFlash Download
to download the compiled code to the chipClick the icon
Start/Stop Debug
at4
to perform debugging related operations (when usingCK-Link
, you can load the code to flash first)Click the
5
iconStart/Stop Debug whitout Download
to debug directly without loading the current bin fileYou can also right-click the project name in
Project
, and compile the project through the options in the right-click menu
Program Hello World
Since our flash algorithm is not currently included in the CDK software, we need to put the flash algorithm in the CDK installation directory. The specific operations are as follows:
Enter the
tools\cdk_flashloader
directory under the SDK directoryCopy the
bl70x_flasher.elf
file in the directory to theC-Sky\CDK\CSKY\Flash
directory of the CDK tool
CDK Flash Loader

CDK Project Setting
Click the project setting button in the
Project View
to open theProject Setting
window, or open it through theProject
menu barIn the opened
Project Setting
window, select theFlash
tab to configure the required Flash algorithm

CDK Project Flash setting
In the
Flash
tab, click theAdd
button, select thebl70x_flash
algorithm in the opened list, and clickAdd
to add it to the project. Others inFlash
configuration, as shown in the figure:After clicking OK, if the configuration is correct, click
Flash Download
to download the compiled code to the chip

CDK Flashdownload Success
If the download fails, please check:
Whether the code is compiled correctly and generate files such as
.elf
,.bin
, etc.
Is the Flash algorithm correctly set?
Whether the CK-Link and the board are properly connected
Whether the development board is powered normally and whether the power indicator is on
Run Hello World
From the menu bar of the CDK
View->Serial Pane
, open the serial port panel, right-click in the openedSerial Pane
, set the serial port, select your corresponding serial port number and baud rate


CDK Serial Pane setting
Press the
RST
key on the board, you can see the result of the code in the serial port

HelloWorld!
Debug Hello World
Click the
Start/Stop Debugger
button at the top of the toolbar to enter the debug interface, as shown in the figure below

Debug HelloWorld!
In the debug interface, the
Register
window can view theCPU
internal register data; thePeripherals
peripheral panel, you can view the corresponding peripheral register data, the top menu barPeripherals-> System Viewer
can select peripherals; click the relevant debugging button in the upper toolbar to perform operations such as breakpoint setting, single-step debugging, single-step instruction, and full-speed operation. Of course, these operations have corresponding shortcut keys and shortcut setting methods. For details, please refer toCDK Help
.We click the single step button to run the code, and we can see that the cursor moves to the next sentence of code, and we can see our output
Hello World!
displayed in the serial port panel.

Debug HelloWorld!
Eclipse Development Guide under Windows
This document introduces the use of eclipse under Windows to build a software development environment for BL702 series MCU.
Software and hardware environment
Eclipse free installation package
Serial port assistant software
A USB Type-A data cable
A j-link emulator
A USB-TTL serial port module
Several Dupont lines
Download Eclipse
Download the installation package with the RISC-V toolchain from the Bouffalo Lab developer community Eclipse https://dev.bouffalolab.com/download .
Download bl_mcu_sdk
Download from the open source community bl_mcu_sdk.
You can use
git clone
or directlydownload
to download the SDKBefore using
git clone
, please make sure thatgit
has been installed correctly. Open a terminal that supportsgit
and enter the following command to get the latest SDK.
1$ git clone https://gitee.com/bouffalolab/bl_mcu_sdk.git --recursive
Configure eclipse
Copy the eclipse compressed package to the working directory, unzip the eclipse compressed package
Enter the eclipse directory, double-click
eclipse.exe
to start eclipseSelect your
Workspace
directory, clickLaunch
to enter the workspaceClick
Window->preferences
in the menu bar to open the environment configuration related page, ready to import the related configuration environment- Click the icon at “1” in the figure below to open the import configuration interface, follow the steps shown in the figure, and select the
bflb_mcu_preferences.epf
configuration file in theeclipse.exe
directory.
- Click the icon at “1” in the figure below to open the import configuration interface, follow the steps shown in the figure, and select the
After selecting the corresponding file, click
Finish
, select and clickcancel
in the dialog box without restarting.
Import bl_mcu_sdk
Click on the menu bar
File->Import
to open the configuration interface of the imported projectIn the opened
Import
window, selectGeneral->Existing Projects into Workspace
, and then clickNext
After loading the project path of bl_mcu_sdk, click
Finsh
to complete the importAfter the import is complete, close the
Welcome
window to see the imported projectExpand
Build Target
, you can see the three function buttonsbl_clean
,bl_make
, anddownload
.Double-click the
bl_clean
button, it will clear the compilation cache in thebuild
andout
directoriesDouble-click the
bl_make
button, the set case will be compiled normally, if the default configuration is not modified, thehelloworld
project will be compiledDouble-click the
download
button, the code will be downloaded to the chip, if it is not compiled successfully, the default or last.bin
file will be downloaded
Hardware connection
For specific board connection, please refer to Hardware connection; (The eclipse environment recommends using
j-link
for programming and debugging)Please make sure that the development board is set up correctly before proceeding to the following steps
Test the Hello World project
Open Hello World
Open
examples/hellowd/helloworld/main.c
, you can edit and modify the code of thehelloworld
test demo. If you modify it, please save it and execute the compilation
Compile Hello World
Double click
bl_make
to compile the helloworld projectAfter successful compilation, you can see the log information as shown in the figure below in the
Console
window

Program Hello World
Double-click
download
to program the helloworld projectbin
file to the chipAfter the download is successful, you can see the log information as shown in the figure below in the
Console
window

Run Hello World
Connect the
TXD0
,RXD0
andGND
pins of the board to the USB-TTL serial port module with a DuPont cable, insert the serial port module into the PC, and use any serial port assistant software to open the serial portAfter the programming is successful, press the
rst
button on the board. If the download is correct, you can see the log information as shown in the figure below in the serial port assistant software.

Debug Hello World
Click the
Debug
button in the eclipse toolbar to enter the debug configuration windowSelect
GDB SEGGER J-Link Debugging->Jlink_bl_mcu_sdk
, select the.elf
file that needs to be debugged inC/C++ Application:
Click
Apply
first, then clickDebug
to startDebug

After entering the Debug interface, you can see that the program stops at
main
, click theStep Over
button in the upper toolbar to perform single-step debugging of the code project.

Eclipse Debugging
Compile and program different target projects
When you right-click the
bl_make
button and clickEdit
, the configuration interface for replacing the target project will pop up, as shown in the figure below

Where
APP=xxx
can be changed to the name of the target project that needs to be compiled and programmed. For example, if you want to compile and program thegpio/gpio_blink
project, modify it toAPP=gpio_blink
.make BOARD=bl706_iot
inBuild command
will specify different Board types to adapt to different types of boards.The
Board
type determines the correspondingborad
header file when compiling. The default selection ismake build BOARD=bl706_iot
Linux OR WSL environment development guide
This document introduces how to install and configure the software development tools needed for BL702 series MCUs in Linux. The installation and configuration method under WSL system is the same as under linux, please install WSL system by yourself. The difference is that one runs on a pure linux system and the other runs on windows. If you don’t want to install a virtual machine or a linux system, you can choose WSL.
Windows Subsystem for Linux (WSL) is a compatibility layer that can run native Linux binary executable files (ELF format) on Windows 10. It was developed by Microsoft and Canonical in cooperation. Its goal is to enable the pure Ubuntu image to be downloaded and decompressed to the user’s local computer, and the tools in the image can run on this subsystem. Therefore, the operation mode under WSL is exactly the same as the operation mode under linux.
Software and hardware environment
A mini USB data cable
A USB-TTL serial port module
Several Dupont lines
Configure RISC-V toolchain
1$ cd ~
2$ wget -c https://dev.bouffalolab.com/media/upload/download/riscv64-elf-x86_64-20210120.tar.gz
3$ mkdir -p riscv64-elf-20210120
4$ tar -zxvf riscv64-elf-x86_64-20210120.tar.gz -C riscv64-elf-20210120
5$ sudo cp -rf ~/riscv64-elf-20210120 /usr/bin
6$ echo "export PATH=\"$PATH:/usr/bin/riscv64-elf-20210120/bin\"" >> ~/.bashrc
7$ source ~/.bashrc
Configure cmake & make tools
1$ sudo apt update
2$ sudo apt install make
3$ cd ~
4$ wget -c https://cmake.org/files/v3.19/cmake-3.19.3-Linux-x86_64.tar.gz
5$ tar -zxvf cmake-3.19.3-Linux-x86_64.tar.gz
6$ sudo cp -rf ~/cmake-3.19.3-Linux-x86_64 /usr/bin
7$ echo "export PATH=\"$PATH:/usr/bin/cmake-3.19.3-Linux-x86_64/bin\"" >> ~/.bashrc
8$ source ~/.bashrc
Hardware connection
For the connection of the board, please refer to Hardware connection
Please make sure that the board is set correctly before proceeding to the following steps (Serial connection is recommended under Linux)
Get bl_mcu_sdk
Open the terminal and enter the following command to get bl_mcu_sdk
1 $ cd ~
2 $ git clone https://gitee.com/bouffalolab/bl_mcu_sdk.git --recursive
Test Hello World project
Open Hello World
After obtaining the SDK, enter
examples/hellowd/helloworld
in the SDK, openmain.c
, and then edit the related code of helloworld.
1 $ cd ~/bl_mcu_sdk/examples/hellowd/helloworld
2 $ vi main.c
After editing, save the changes and close the file, and then compile
Compile Hello World
1 $ cd ~/bl_mcu_sdk
2 $ make build BOARD=bl706_iot APP=helloworld
Program Hello World
Please confirm the programming method first. If you use serial programming, please press and hold the
boot
key on the board and don’t release it. At this time, press therst
key, and then release the two keys. The board enters the boot_rom state.At this time, enter the following command in the terminal to program
1 $ cd ~/bl_mcu_sdk
2 $ make download INTERFACE=uart COMx=/dev/ttyUSB1
If the download fails, please check:
Whether the serial port is used for programming, whether the development board is powered, and whether the hardware connection is correct.
Is the programming command executed in the
bl_mcu_sdk
directory
Whether to enter boot_rom mode
Whether the serial port is occupied, and whether your available serial port is selected correctly, if your serial port is not
ttyUSB1
, then please specify the correct serial port
Run Hello World
Open a new terminal, install and run the serial port tool
1 $ sudo apt install picocom # Ignore if it is already installed
2 $ picocom -b 2000000 /dev/ttyUSB1 # Pay attention to your available serial port number (if you use the serial port of Sipeed RV-debugger Plus, it will be ``ttyUSB1``)
Press the
rst
key on the board, you can seehello world!
in the serial terminal.

helloworld!
Debug Hello World
New Project Guide based on cmake framework
This document will introduce how to create a new project based on this SDK.
Examples directory structure
There are two levels of subdirectories under bl_mcu_sdk/examples
, the first level is the folders of different peripherals. The second level is a specific test case of the peripheral, and the directory usually contains a CMakeList.txt
and the source code related to the case.
Add a single source file project
备注
The source file must contain the c program entry, usually the main
function, the source file may not be called main.c
Create a new
my_case
folder underexamples
to store your caseCreate a new folder that needs to be tested in the
my_case
directory, such asgpio_case
Then add the
main.c
andCMakeLists.txt
files in thegpio_case
directory
The directory structure is as follows:
1bl_mcu_sdk
2├── examples
3 ├── my_case
4 ├── gpio_case
5 │ ├──CMakeLists.txt
6 │ └──main.c
7 └── xxxx_case
CMakeLists.txt:
1set(mains main.c)
2generate_bin()
After writing the code in main.c, compile it in the bl_mcu_sdk directory. The compilation command is as follows:
1make BOARD=bl706_iot APP=gpio_case
Add multiple source file projects
备注
One of the source files must contain the c program entry, usually the main
function, the source file does not need to be called main.c
. This source file depends on other source files.
The steps for adding a multi-source file project are the same as the basic steps for adding a single source file project
Add
test1.c
,test1.h
,test2.c
,test2.h
and other source files and header files that need to be relied on in thegpio_case
directory
The directory structure is as follows:
1bl_mcu_sdk
2├── examples
3 ├── my_case
4 ├── gpio_case
5 │ ├──CMakeLists.txt
6 │ ├──test1.c
7 │ ├──test1.h
8 │ ├──test2.c
9 │ ├──test2.h
10 │ └──main.c
11 └── xxxx_case
At this time, the
CMakeLists.txt
file needs to add the corresponding dependent source file, the content is as follows:
CMakeLists.txt:
1set(mains main.c)
2set(TARGET_REQUIRED_SRCS test1.c test2.c)
3generate_bin()
After writing the code, compile it in the bl_mcu_sdk directory. The compilation command is as follows:
1make BOARD=bl706_iot APP=gpio_case
Add a new project with dependent libraries
The steps for adding a new project with dependent libraries are the same as the basic steps for adding a single source file project
If the dependent library used already exists in this SDK, you only need to modify CMakeLists.txt
If the dependent library does not exist, you need to add it yourself, please refer to the follow-up instructions for details
If it already exists, the directory structure is as follows:
1bl_mcu_sdk
2├── examples
3 ├── my_case
4 ├── gpio_case
5 │ ├──CMakeLists.txt
6 │ └──main.c
7 └── xxxx_case
At this time, the
CMakeLists.txt
file needs to add the corresponding dependent library files. For example, we add the FreeRTOS component library, the content is as follows:
CMakeLists.txt:
1set(TARGET_REQUIRED_LIBS freertos)
2set(mains main.c)
3generate_bin()
After writing the code, compile it in the bl_mcu_sdk directory. The compilation command is as follows:
1make BOARD=bl706_iot APP=gpio_case SUPPORT_FREERTOS=y
Add a new project and set the private compilation option (gcc option)
The steps of adding a new project are basically the same as adding a single source file project
Mainly modify the CMakeLists.txt file and add private compilation options
CMakeLists.txt:
1set(mains main.c)
2set(TARGET_REQUIRED_PRIVATE_OPTIONS -Ofast)
3generate_bin()
After writing the code, compile it in the bl_mcu_sdk directory. The compilation command is as follows:
1make BOARD=bl706_iot APP=gpio_case
Add a new project and set up a private link script (ld)
The steps of adding a new project are basically the same as adding a single source file project
Add a private link script file, such as
gpio_test_case.ld
The directory structure is as follows:
1bl_mcu_sdk
2├── examples
3 ├── my_case
4 ├── gpio_case
5 │ ├──CMakeLists.txt
6 │ ├──gpio_test_case.ld
7 │ └──main.c
8 └── xxxx_case
Modify the CMakeLists.txt file and add private link script settings
CMakeLists.txt:
1set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/gpio_test_case.ld)
2set(mains main.c)
3generate_bin()
After writing the code, compile it in the bl_mcu_sdk directory. The compilation command is as follows:
1make BOARD=bl706_iot APP=gpio_case
Add a new project and its dependent source files and library files
New Project Guide based on CDK
This document will briefly explain how to create a new CDK project based on this SDK, please make sure that the CDK IDE is properly installed before following this tutorial.
Examples directory structure
There are two levels of subdirectories under bl_mcu_sdk/examples
, the first level is the folders of different peripherals. The second level is a specific test case of the peripheral, The second level directory usually also contains a directory named cdk
and the source code associated with the case.
The cdk
directory usually contains a xxx.cdkproj
file, which is a CDK project file. If the CDK IDE is properly installed, double-click the project to open it. The newly created project should be at the same level as the case level in the current examples
directory.
备注
The source file must contain the c program entry, usually the main
function, the source file may not be called main.c
Create a new
my_case
folder underexamples
to store your caseCreate a new folder that needs to be tested in the
my_case
directory, such asgpio_case
Then add the
main.c
file andcdk
directory in thegpio_case
directory
The directory structure is as follows:
1bl_mcu_sdk
2├── examples
3 ├── my_case
4 ├── gpio_case
5 │ ├── cdk
6 │ │ ├──gpio_case.cdkproj
7 │ ├── CMakeLists.txt
8 │ └── main.c
9 └── xxxx_case
BLDevCube start guide
This document mainly introduces the use of Bouffalo Lab Dev Cube for code programming. For more details, please refer to BLDevCube user manual
Download Bouffalo Lab Dev Cube
Download the version suitable for your operating system from the developer community, download address:https://dev.bouffalolab.com/download
For users who do not have a registered account, click on the guest portal
After the download is complete, you can use it after decompression
Configure tool download method
Double-click
BLDevCube.exe
, in theChip Type
drop-down box, select the corresponding chip model, clickFinish
to enter theDev Cube
interfaceEnter the interface, select
MCU
underView
in the menu bar to enter the MCU program download interface

select mcu
Select the corresponding download method in the
Interface
column underImage
, and choose according to your actual physical connectionImage file
configure the absolute path of the downloaded image, clickBrowse
to select the Bin fileWhen you click
click here to show advanced options
, the advanced mirroring configuration will be expanded, usually keep the default configuration; it should be noted thatFlash Clock
will affect the clock frequency of Flash and PSRAM at the same time , If you need to use PSRAM, you can increase the clock frequency to get better performance
Download with UART
COM Port
is used for UART download, select the COM number connected to the chip, and clickRefresh
to refresh the COM numberWhen
Uart Speed
is used for UART download, configure the appropriate baud rate, the default is 2MPlease make sure the hardware configuration is correct before downloading:
Use
Type-C USB
orMini USB
to connect to the corresponding USBType-C
port orMini
port on the board.Press the
Boot
key on the board, don’t release itPress the
RST
key on the board, now you have enteredBoot ROM
model, you can release the two keysAt this time, you can see the corresponding serial port
COM
number from theBouffalo Lab Dev Cube
, if it does not appear, please click theRefresh
button to refresh
After completing the above configuration correctly, click the
Create&Program
button to downloadAfter the download is successful, you will see the status bar turn green and display
Success

download success!
Download with Openocd
Download using openocd is basically the same as using serial port download option configuration, just switch
Interface
toOpenocd
The hardware connection needs to be changed to a debugger connection that supports Openocd (this tutorial takes Sipeed RV Debugger as an example):
Connect the RV debugger to the USB port of the computer, open the device manager, you will find that the debugger is recognized as two serial ports (note: not the serial port on the board)
Download the
zadig-2.4
replacement driver from sipeed. Download link: http://dl.sipeed.com/MAIX/tools/sipeed-rv-debugger/zadig-2.4.exe
After downloading, double-click to open
zadig-2.4.exe
, and check List All Devices in Options.
Find JTAG Debugger (Interface 0), then select the replacement driver as WinUSB and click Replace Driver to replace
Open the device manager again and see that one of the serial ports has been replaced with a universal serial bus device, indicating that the installation is successful
Connect the JTAG pins of the debugger with the JTAG pins of the board
After completing the above configuration correctly, click the
Create&Program
button to downloadAfter the download is successful, you will see the status bar turn green and display
Success
Download with Jlink
The tool configuration for downloading using Jlink and Openocd is basically the same, just switch
Interface
toJlink
The hardware connection needs to be changed to use Jlink connection (this tutorial takes Jlink V11 as an example, it is recommended to use Jlink V10 or later):
Download the appropriate Jlink driver from Segger official website and install it
Connect the Jlink debugger to the USB port of the computer
Connect the JTAG pins of the JLink debugger with the JTAG pins of the board
After completing the above configuration correctly, click the
Create&Program
button to downloadAfter the download is successful, you will see the status bar turn green and display
Success
Board Configuration System User Guide
In order to implement the idea of everything is a file, we propose a Board configuration system for embedded applications with different hardware configuration requirements. The Board configuration system is mainly used for initializing the three basic elements of clock, GPIO, and peripheral default configuration in embedded applications.
Board Configuration System contains three configuration files, and a bl_config_wizard
graphical configuration software
clock_config.h Clock configuration Include file
peripheral_config.h Peripheral configuration Include file
pinmux_config.h Pin Function Configuration Include file
bl_config_wizard The graphical interface configures the above three types of files
The user only needs to modify three configuration files and the system will be initialized automatically, thus eliminating the need to call a series of complex and lengthy initialization functions in the user program. Boufflao Lab provides bl_config_wizard
configuration software for users to quickly and easily generate configuration files for their projects.
bl_config_wizard supports PC-side online configuration, but currently does not support mobile terminal online configuration.

bl_config_wizard Preview
The features of each file in the Board configuration system
The board system is mainly used for different boards, different boards create different board files and put them in bsp/board
directory, and a board file, in the case of pins not conflicting, can be shared to different demos, no need to create multiple projects and reduce the project file size.
错误
If there is a pin conflict and you have to use the same Board file, please modify the pins yourself
board.c
board.c
Main initialization of clock and pins
blxxx_config.h
blxxx_config.h
Mainly contains some header files for the HAL layer driver.
提示
The above two files do not need to be changed by the user, and the same MCU can be copied and pasted directly into your own board directory for use
clock_config.h
clock_config.h
Mainly configures the clock sources for the system and peripherals as well as the frequency division system.
peripheral_config.h
peripheral_config.h
It mainly contains the enablement of peripherals and the configuration of parameters.
警告
Macros starting with #define BSP_USING_XXX
are used to enable the configuration of the peripheral, if the macro is not enabled, all functions of the peripheral cannot be used
警告
Macro starting with XXX_CONFIG
, used to initialize the configuration of the peripheral, which is later used by calling device_open
pinmux_config.h
pinmux_config.h
Mainly configures the GPIO pin function of the peripheral.
警告
In mcu sdk, all demos share this file, so some demos are not usable and require frequent changes to the pin function configuration in this file. If the user has already set the pin assignments, there is no need to modify them frequently.
Use of the Board configuration tool bl_config_wizard
The
bl_config_wizard
can be accessed by clicking on this link https://dev.bouffalolab.com/media/config/index.html wizard in the online version. Chrome, Firefox, Microsoft Edge browsers are recommended.
Generate a new pinmux_config.h file
Select
Pin & Peripheral Configuration
in the window bar.Select MCU model, currently supports
BL706 pin configuration
,BL704 pin configuration
,BL702 pin configuration
.Select the function of the pin, take
BL706 pin configuration
as an example, click on the drop-down box of PAD_GPIO_XX and select the desired function, as shown in the figure.

Select pin function
After configuring all the pin functions, click
Export Configuration File
and then you can select the path and modify the file name in the pop-up box, as shown in the figure.

Exporting configuration files
Modify the original pinmux_config.h file
Often in use, instead of generating a new pinmux_config.h file, we make changes to the original pinmux_config.h file, and bl_config_wizard
supports such a need.
Select
Pin & Peripheral Configuration
in the window bar.Select MCU model, currently supports
BL706 pin configuration
,BL704 pin configuration
,BL702 pin configuration
.Click on
import configuration file
and select the pinmux_config.h file in the pop-up box.Select the pin to be modified and click on its drop-down box to change the pin function
When you are done, click
Export Profile
and then you can select the path and modify the file name in the pop-up box.
Modify the pinmux_config.h file in the CDK tool
pinmux_config.h Also supports the use of graphical configuration wizards in the CDK for adjusting the corresponding pin functions
Drag the pinmux_config.h file directly into the CDK text editor interface, and you will see the
Configuration Wizard
tab at the bottom of the text editorConfiguration Wizard
Click on the
Configuration Wizard
tab to open the graphical configuration wizard interfaceThe functions supported by the pin can be selected by selecting the drop-down box
Graphical configuration wizard to set pin functions
Please refer to the Graphical Configuration Wizard section of CDK Help for more information on the specific functions and code rules of the Graphical Configuration Wizard.
Differences with STM32CUBEMX Configuration Tool
STM32CUBEMX is also a tool to configure the clock, peripherals and GPIO initialization, eventually generating a complete project with initialization at the very beginning of main.c
, and the GPIO and peripheral initialization base will be called in stm32xxx_hal_msp.c
.
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_QUADSPI_Init();
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==UART5)
{
/* USER CODE BEGIN UART5_MspInit 0 */
/* USER CODE END UART5_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_UART5_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**UART5 GPIO Configuration
PB12 ------> UART5_RX
PB13 ------> UART5_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF14_UART5;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* UART5 interrupt Init */
HAL_NVIC_SetPriority(UART5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(UART5_IRQn);
/* USER CODE BEGIN UART5_MspInit 1 */
/* USER CODE END UART5_MspInit 1 */
}
}
提示
The projects generated by stm32 all work for one project and cannot be compiled for more than one project at the same time. If you use more than one project, you have to generate more than one of these two files. When using multiple projects, it will indirectly increase the file size and add duplicate files.
API Overview
Introduction
bl_mcu_sdk code hierarchy is divided into the following main layers.
The application layer: codes written by users.
The component layer: some opensource components,the interface calls the HAL layer, while the wireless layer is used for wireless functions.
- HAL layer and wireless layer for adaptation to different MCUs, where the HAL layer is divided into two layers
Device driver management: provides a standard set of interfaces, which are implemented by the peripheral driver adaptation layer
Peripheral driver adaptation layer: implements the standard interface of the device driver management and extends its own unique interface
Standard driver layer based on register packaging
Hardware layer, also known as the register layer

code structure
Device driver management layer
The realization of the device driver management layer adopts the object-oriented idea. First of all, we regard the peripheral as a device or a file, adhering to the concept of everything is a file, and files have standard calling interfaces: open
, close
, ctrl
, write
, read
, callback
. Different file types are different (such as serial device, ADC device, SPI device), and the way of opening is also different (such as polling, interrupt, DMA), from this, we can construct a base class (parent class) of an object.
Base class
struct device
{
char name[NAME_MAX]; /*name of device */
dlist_t list; /*list node of device */
enum device_status_type status; /*status of device */
enum device_class_type type; /*type of device */
uint16_t oflag; /*oflag of device */
int (*open)(struct device *dev, uint16_t oflag);
int (*close)(struct device *dev);
int (*control)(struct device *dev, int cmd, void *args);
int (*write)(struct device *dev, uint32_t pos, const void *buffer, uint32_t size);
int (*read)(struct device *dev, uint32_t pos, void *buffer, uint32_t size);
void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event);
void *handle;
};
Base class member: name
Name the device and use device_find
to find the device.
Base class member: type
type
records the category of the current device, and the type
that can be selected are as follows.
enum device_class_type
{
DEVICE_CLASS_NONE = 0,
DEVICE_CLASS_GPIO,
DEVICE_CLASS_UART,
DEVICE_CLASS_SPI,
DEVICE_CLASS_I2C,
DEVICE_CLASS_ADC,
DEVICE_CLASS_DMA,
DEVICE_CLASS_TIMER,
DEVICE_CLASS_PWM,
DEVICE_CLASS_SDIO,
DEVICE_CLASS_USB,
DEVICE_CLASS_I2S,
DEVICE_CLASS_CAMERA,
DEVICE_CLASS_SEC_HASH,
} ;
Base class member: status
status
is used to record the current status of the device and provides 4 statuses.
enum device_status_type
{
DEVICE_UNREGISTER = 0,
DEVICE_REGISTERED,
DEVICE_OPENED,
DEVICE_CLOSED
} ;
Base class member: oflag
oflag
records the flag information filled in during registration and the oflag
information filled in when using device_open
.
Base class members: list
The addition and deletion of equipment is stored in a doubly linked list, which saves memory.
Base class members: standard function pointers
Provides a standard function interface for different peripherals. When the peripheral implements this type of interface and assigns it to the member, the function of rewriting can be achieved.
Device driver management layer standard interface
device_register
device_register
is used to register the device and register the device information in the linked list.
int device_register(struct device *dev, const char *name);
dev: device handle.
name: the name of the device.
return: return error code, 0 means registration is successful, others mean errors.
device_unregister
device_unregister
is used to delete the device and delete the device information from the linked list.
int device_unregister(const char *name);
dev: device handle
name: the name of the device to be deleted
return: error code, 0 means delete, others mean error
device_find
device_find
is used to find the device from the linked list according to name
, and return the first address of the device handle.
struct device *device_find(const char *name);
dev: device handle
name: the name of the device to be searched
return: error code,! 0 means the device handle was found, NULL means the device was not found.
device_open
device_open
is used to open the device, and oflag
represents the opening method. Currently, there are 6 opening methods available. The bottom layer calls the open
member in the dev
handle.
int device_open(struct device *dev, uint16_t oflag);
dev: device handle
oflag: open method
return: error code, 0 means opening is successful, others mean errors
oflag
can write the following parameters:
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
device_close
device_close
is used to close the device. The bottom layer calls the close
member in the dev
handle.
int device_close(struct device *dev);
-dev: device handle -return: error code, 0 means closing is successful, others mean error
device_control
device_control
is used to control the device and modify parameters according to commands. The bottom layer calls the control
member in the dev
handle.
int device_control(struct device *dev, int cmd, void *args);
dev: device handle
cmd: device control command
args: control parameters
return: Different control commands return different meanings.
cmd
provides the following standard commands. In addition, different peripherals also have their own commands
#define DEVICE_CTRL_SET_INT 0x01 /* set interrupt */
#define DEVICE_CTRL_CLR_INT 0x02 /* clear interrupt */
#define DEVICE_CTRL_GET_INT 0x03 /* get interrupt status*/
#define DEVICE_CTRL_RESUME 0x04 /* resume device */
#define DEVICE_CTRL_SUSPEND 0x05 /* suspend device */
#define DEVICE_CTRL_CONFIG 0x06 /* config device */
#define DEVICE_CTRL_GET_CONFIG 0x07 /* get device configuration */
#define DEVICE_CTRL_ATTACH_TX_DMA 0x08
#define DEVICE_CTRL_ATTACH_RX_DMA 0x09
#define DEVICE_CTRL_TX_DMA_SUSPEND 0x0a
#define DEVICE_CTRL_RX_DMA_SUSPEND 0x0b
#define DEVICE_CTRL_TX_DMA_RESUME 0x0c
#define DEVICE_CTRL_RX_DMA_RESUME 0x0d
#define DEVICE_CTRL_RESVD1 0x0E
#define DEVICE_CTRL_RESVD2 0x0F
device_write
device_write
is used to send data, and the sending mode can be polling, interrupt, dma. The bottom layer calls the write
member in the dev
handle.
int device_write(struct device *dev, uint32_t pos, const void *buffer, uint32_t size);
dev: device handle
pos: different devices have different meanings for pos
buffer: the buffer to be written
size: the length to be written
return: error code, 0 means writing is successful, others mean errors
device_read
device_read
is used to receive data, and the receiving mode can be polling, interrupt, dma. The bottom layer calls the read
member in the dev
handle.
int device_read(struct device *dev, uint32_t pos, void *buffer, uint32_t size);
dev: device handle
pos: different devices have different meanings for pos
buffer: the buffer to be read
size: the length to be read
return: error code, 0 means successful reading, others mean errors
device_set_callback
device_set_callback
is used to register interrupt callback function. The bottom layer calls the callback
member in the dev
handle.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev: device handle
callback: the interrupt callback function to be registered
dev: device handle
args: Different peripherals have different meanings
size: transmission length
event: interrupt event type
Peripheral driver adaptation layer
Subclass inherits from parent class
The first member of different peripherals is struct device
, which is equivalent to the inheritance of the parent class, so that the subclass can be used to access the parent class member. When the subclass is used to modify the members of the parent class, it has its own functions. The realization principle is that the first address of different structures is the address of the first member in the structure.
typedef struct xxx_device
{
struct device parent;
} xxx_device_t;
Rewrite standard interface
Each peripheral has a xxx_register
function, which is used to rewrite the standard interface.
dev->open = xxx_open;
dev->close = xxx_close;
dev->control = xxx_control;
dev->write = xxx_write;
dev->read = xxx_read;
Peripheral
Clock tree
Introduction
The BL series chips have a lot of clock source selection and provide a clock tree configuration table to facilitate user configuration. Users do not need to call the clock setting interface. Users only need to care about the final system clock and peripheral clock frequency. The clock configuration table is located in the clock_config.h
file under the bsp/board/xxx_board
directory.
Clock Frequency Acquisition Interface
system_clock_get
system_clock_get
is used to get the system clock frequency.
uint32_t system_clock_get(enum system_clock_type type);
type the type of system clock frequency
type
provide the following types
enum system_clock_type
{
SYSTEM_CLOCK_ROOT_CLOCK = 0,
SYSTEM_CLOCK_FCLK,
SYSTEM_CLOCK_BCLK,
SYSTEM_CLOCK_XCLK,
SYSTEM_CLOCK_32K_CLK,
SYSTEM_CLOCK_AUPLL,
};
peripheral_clock_get
peripheral_clock_get
is used to get the peripheral clock frequency.
uint32_t peripheral_clock_get(enum peripheral_clock_type type);
type peripheral clock frequency type
type
provide the following types
enum peripheral_clock_type
{
PERIPHERAL_CLOCK_UART = 0,
PERIPHERAL_CLOCK_SPI,
PERIPHERAL_CLOCK_I2C,
PERIPHERAL_CLOCK_ADC,
PERIPHERAL_CLOCK_DAC,
PERIPHERAL_CLOCK_I2S,
PERIPHERAL_CLOCK_PWM,
PERIPHERAL_CLOCK_CAM,
};
GPIO
Introduction
The full name of GPIO is General Purpose Input Output. The GPIO peripherals of BL series chips mainly have the following functions.
General input and output pull-up and pull-down
Multiplex function pull-up and pull-down
Simulation function
External interrupt (rising edge, falling edge, high level, low level)
Hardware eliminate jitter
Drive capacity control
The pin configuration of bl mcu sdk is divided into two kinds.
GPIO multiplexing function is through a special pinmux table, users only need to modify the functions of related pins in the table, and the program will automatically configure these pins. pinmux table is located in the
pinmux_config.h
file under thebsp/board/xxx_board
directory.Configure the pins through the standard GPIO device interface. The disadvantage is that only common input and output and interrupt functions can be configured. It is recommended to use the table to configure the multiplexing functions.
GPIO Device Interface
gpio_set_mode
gpio_set_mode
is used to configure the mode of gpio.
void gpio_set_mode(uint32_t pin, uint32_t mode);
pin the pin to be configured
mode pin function to be configured
mode
provides the following types
#define GPIO_OUTPUT_MODE 0
#define GPIO_OUTPUT_PP_MODE 1
#define GPIO_OUTPUT_PD_MODE 2
#define GPIO_INPUT_MODE 3
#define GPIO_INPUT_PP_MODE 4
#define GPIO_INPUT_PD_MODE 5
#define GPIO_ASYNC_RISING_TRIGER_INT_MODE 6
#define GPIO_ASYNC_FALLING_TRIGER_INT_MODE 7
#define GPIO_ASYNC_HIGH_LEVEL_INT_MODE 8
#define GPIO_ASYNC_LOW_LEVEL_INT_MODE 9
#define GPIO_SYNC_RISING_TRIGER_INT_MODE 10
#define GPIO_SYNC_FALLING_TRIGER_INT_MODE 11
#define GPIO_SYNC_HIGH_LEVEL_INT_MODE 12
#define GPIO_SYNC_LOW_LEVEL_INT_MODE 13
gpio_write
gpio_write
is used to set pin level
void gpio_write(uint32_t pin, uint32_t value);
pin the pin to be set
value the level to be set
gpio_toggle
gpio_toggle
: is used to toggle pin level
void gpio_toggle(uint32_t pin);
pin: the pin to be toggled
gpio_read
gpio_read
is used to read pin level
int gpio_read(uint32_t pin);
pin the pin to read the level
return 0 is low level, 1 is high level
gpio_attach_irq
gpio_attach_irq
is used to attache an interrupt callback function to the interrupt pin
void gpio_attach_irq(uint32_t pin, void (*cbfun)(uint32_t pin));
pin the pin to which the interrupt callback is attached
cbfun register interrupt callback
gpio_irq_enable
gpio_irq_enable
is used to enable gpio interrupt
void gpio_irq_enable(uint32_t pin,uint8_t enabled);
pin the pin to turn on or off the interrupt
enabled 0 is to close the interrupt, 1 is to open the interrupt
UART
Introduction
UART is a universal asynchronous transmitter-receiver, which provides a flexible way for full-duplex data exchange with external devices. The UART device in BL series MCU has the following characteristics:
Data bit length can choose 5/6/7/8 bits
Stop bit length can be selected 0.5/1/1.5/2 bits
Support odd/even/no parity bit
Support hardware flow control (RTS/CTS)
Automatic baud rate detection
Support LIN protocol (transceive BREAK/SYNC)
Send/receive FIFO
Support polling, interrupt, DMA transfer
Unique rto interrupt
UART Device Structure Definition
typedef struct uart_device
{
struct device parent;
uint8_t id;
uint32_t baudrate;
uart_databits_t databits;
uart_stopbits_t stopbits;
uart_parity_t parity;
uint8_t fifo_threshold;
void* tx_dma;
void* rx_dma;
} uart_device_t;
parent inherit the properties of the parent class
id serial port id, if serial port 0 is enabled, id is 0, if serial port 1 is enabled, id is 1, and so on
baudrate baud rate
databits data bits
stopbits stop bits
parity parity
fifo_threshold fifo threshold, the maximum value of different mcu is different
tx_dma additional send dma handle
rx_dma additional receive dma handle
databits
provides the following types
typedef enum
{
UART_DATA_LEN_5 = 0, /*!< Data length is 5 bits */
UART_DATA_LEN_6 = 1, /*!< Data length is 6 bits */
UART_DATA_LEN_7 = 2, /*!< Data length is 7 bits */
UART_DATA_LEN_8 = 3 /*!< Data length is 8 bits */
} uart_databits_t;
stopbits
provides the following types
typedef enum
{
UART_STOP_ONE = 0, /*!< One stop bit */
UART_STOP_ONE_D_FIVE = 1, /*!< 1.5 stop bit */
UART_STOP_TWO = 2 /*!< Two stop bits */
} uart_stopbits_t;
parity
provides the following types
typedef enum
{
UART_PAR_NONE = 0, /*!< No parity */
UART_PAR_ODD = 1, /*!< Parity bit is odd */
UART_PAR_EVEN = 2, /*!< Parity bit is even */
} uart_parity_t;
UART Device Parameter Configuration Table
Each UART device has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_uart.c
, so the user does not need to define variable. When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_UART0
, UART0_CONFIG
will take effect, and the UART0
device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_UART0)
#ifndef UART0_CONFIG
#define UART0_CONFIG \
{ \
.id = 0, \
.baudrate = 2000000,\
.databits = UART_DATA_LEN_8, \
.stopbits = UART_STOP_ONE, \
.parity = UART_PAR_NONE, \
.fifo_threshold = 1, \
}
#endif
#endif
/*Variable definitions*/
static uart_device_t uartx_device[UART_MAX_INDEX] =
{
#ifdef BSP_USING_UART0
UART0_CONFIG,
#endif
#ifdef BSP_USING_UART1
UART1_CONFIG,
#endif
};
备注
The above configuration can be modified through UART_DEV(dev)->xxx
and can only be used before calling device_open
.
UART Device Interface
UART device interface follows which provided by the standard device driver management layer.
uart_register
uart_register
is used to register a UART device standard driver interface. Before registering, you need to open the macro definition of the corresponding UART device. For example, define the macro BSP_USING_UART0
to use the UART0
device. After the registration is completed, other interfaces can be used. If the macro is not defined, the UART0
device cannot be used.
int uart_register(enum uart_index_type index, const char *name);
index the index of the device to be registered
name device name
index
is used to select UART device configuration, one index corresponds to a UART device configuration, such as UART0_INDEX
corresponds to UART0_CONFIG
configuration, index
has the following optional types
enum uart_index_type
{
#ifdef BSP_USING_UART0
UART0_INDEX,
#endif
#ifdef BSP_USING_UART1
UART1_INDEX,
#endif
UART_MAX_INDEX
};
device_open
device_open
is used to open a UART device, this funtion calls uart_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open mode
return error code, 0 means opening is successful, others mean errors
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in rotation receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
device_close
device_close
is used to close a UART device,this funtion calls uart_close
actually.
int device_close(struct device *dev);
dev device handle
return error code, 0 means closing is successful, others mean error
device_control
device_control
is used to control and modify the parameters of the UART device according to commands.This funtion calls uart_control
actually.
int device_control(struct device *dev, int cmd, void *args);
dev device handle
cmd device control command
args control parameters
return different control commands return different meanings.
In addition to standard control commands, UART device also has its own special control commands.
#define DEVICE_CTRL_UART_GET_TX_FIFO 0x10
#define DEVICE_CTRL_UART_GET_RX_FIFO 0x11
args
input is different depending on cmd
, the list is as follows:
cmd |
args |
description |
---|---|---|
DEVICE_CTRL_SET_INT |
uart_it_type |
Enable uart device interrupt |
DEVICE_CTRL_CLR_INT |
uart_it_type |
Disable uart device interrupt |
DEVICE_CTRL_CONFIG |
uart_param_cfg_t* |
Modify the serial port configuration |
DEVICE_CTRL_ATTACH_TX_DMA |
NULL |
Link to tx dma device |
DEVICE_CTRL_ATTACH_RX_DMA |
NULL |
Link to rx dma device |
DEVICE_CTRL_TX_DMA_SUSPEND |
NULL |
Suspend uart tx dma mode |
DEVICE_CTRL_RX_DMA_SUSPEND |
NULL |
Suspend uart rx dma mode |
DEVICE_CTRL_TX_DMA_RESUME |
NULL |
Resume uart tx dma mode |
DEVICE_CTRL_RX_DMA_RESUME |
NULL |
Resume uart rx dma mode |
DEVICE_CTRL_UART_GET_TX_FIFO |
uint32_t* |
Get the number of uart tx fifo |
DEVICE_CTRL_UART_GET_RX_FIFO |
uint32_t* |
Get the number of uart rx fifo |
device_write
device_write
is used to send data. The sending mode can be polling, interrupt, dma according to the open mode.This funtion calls uart_write
actually.
int device_write(struct device *dev, uint32_t pos, const void *buffer, uint32_t size);
dev device handle
pos useless
buffer the buffer to be written
size the length to be written
return error code, 0 means writing is successful, others mean errors
device_read
device_read
is used to receive data. The receiving mode can be polling, interrupt, dma according to the open mode.This funtion calls uart_read
actually.
int device_read(struct device *dev, uint32_t pos, void *buffer, uint32_t size);
dev device handle
pos useless
buffer the buffer to be read
size the length to be read
return error code, 0 means successful reading, others mean errors
device_set_callback
device_set_callback
is used to register a uart interrupt callback function.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev device handle
callback the interrupt callback function to be registered
dev device handle
args receive and send buffer, the data type is uint8_t*
size transmission length
event interrupt event type
event
type definition is as follows:
enum uart_event_type
{
UART_EVENT_TX_END,
UART_EVENT_TX_FIFO,
UART_EVENT_RX_END,
UART_EVENT_RX_FIFO,
UART_EVENT_RTO,
UART_EVENT_UNKNOWN
};
PWM
Introduction
PWM is a technology that implements analog voltage control in a digital way. It modulates the width of a series of pulses, equivalent to the required waveform (including shape and amplitude), and digitally encodes the analog signal level. That is to say, by adjusting the change of the duty cycle to adjust the change of the signal, energy, etc. The duty cycle refers to the percentage of the entire signal period when the signal is at a high level. For example, the duty cycle of a square wave is 50%. The DMA device in BL series MCU has the following characteristics:
Support 5-channel PWM
Three clock sources can be selected (bus clock <bclk>, crystal oscillator clock <xtal_ck>, slow clock <32k>), with 16-bit clock divider
Double threshold domain setting, increase pulse flexibility
PWM Device Structure Definition
typedef struct pwm_device {
struct device parent;
uint8_t ch;
uint8_t polarity_invert_mode;
uint16_t period;
uint16_t threshold_low;
uint16_t threshold_high;
uint16_t it_pulse_count;
} pwm_device_t;
parent inherit the properties of the parent class
ch channel number, ch is 0 if PWM channel 0 is enabled, ch is 1 if PWM channel 1 is enabled, and so on
polarity_invert_mode polarity invert enable
period PWM period value
threshold_low PWM low threshold
threshold_high PWM high threshold
it_pulse_count The cycle count value that triggered the interrupt condition
备注
PWM actual frequency = pwm_clock_source/frequency_division/period, period is not the actual PWM period,it just has the same name.
备注
PWM Duty cycle = (threshold_high-threshold_low)/period * 100%
PWM Device Parameter Configuration Table
Each PWM device has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_pwm.c
, so the user does not need to define variable. When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_PWM_CH2
, and PWM_CH2_CONFIG
will take effect, and at the same time, channel 2 of the PWM
device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_PWM_CH2)
#ifndef PWM_CH2_CONFIG
#define PWM_CH2_CONFIG \
{ \
.ch = 2, \
.polarity_invert_mode = DISABLE, \
.period = 0, \
.threshold_low = 0, \
.threshold_high = 0, \
.it_pulse_count = 0, \
}
#endif
#endif
/*Variable definitions*/
static pwm_device_t pwmx_device[PWM_MAX_INDEX] = {
#ifdef BSP_USING_PWM_CH0
PWM_CH0_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH1
PWM_CH1_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH2
PWM_CH2_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH3
PWM_CH3_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH4
PWM_CH4_CONFIG,
#endif
};
备注
The above configuration can be modified through PWM_DEV(dev)->xxx
, and can only be used before calling device_open
.
PWM device interface
The PWM device interfaces all follow the interfaces provided by the standard device driver management layer. And in order to facilitate the user to call, some standard interfaces are redefined using macros.
pwm_register
pwm_register
is used to register a channel of the PWM device standard driver interface. Before registering, you need to open the macro definition of a certain channel of the corresponding PWM device. For example, define BSP_USING_PWM_CH0
before you can use the PWM
channel 0 device. After the registration is completed, other interfaces can be used. If no macro is defined, the PWM device cannot be used.
int pwm_register(enum pwm_index_type index, const char *name);
index the index of the device to be registered
name name the registered device
index
is used to select the configuration of a certain channel of the PWM device. An index corresponds to a channel configuration of a PWM device. For example, PWM_CH0_INDEX
corresponds to the configuration of PWM channel 0, and index
has the following optional types:
enum pwm_index_type
{
#ifdef BSP_USING_PWM_CH0
PWM_CH0_INDEX,
#endif
#ifdef BSP_USING_PWM_CH1
PWM_CH1_INDEX,
#endif
#ifdef BSP_USING_PWM_CH2
PWM_CH2_INDEX,
#endif
#ifdef BSP_USING_PWM_CH3
PWM_CH3_INDEX,
#endif
#ifdef BSP_USING_PWM_CH4
PWM_CH4_INDEX,
#endif
PWM_MAX_INDEX
};
device_open
device_open
is used to open a channel of a pwm device,this funtion calls pwm_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open mode
return error code, 0 means opening is successful, others mean errors
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
device_close
device_close
is used to close a channel of a pwm device.this funtion calls pwm_close
actually.
int device_close(struct device *dev);
dev device handle
return error code, 0 means closing is successful, others mean error
device_control
device_control
is used to control and modify the parameters of the PWM device according to commands.This funtion calls pwm_control
actually.
int device_control(struct device *dev, int cmd, void *args);
dev device handle
cmd device control command
args control parameters
return different control commands return different meanings
In addition to standard control commands, PWM devices also have their own special control commands.
#define DEIVCE_CTRL_PWM_IT_PULSE_COUNT_CONFIG 0x10
args
input is different depending on cmd
, the list is as follows:
cmd |
args |
description |
---|---|---|
DEVICE_CTRL_RESUME |
NULL |
Enable the current PWM channel |
DEVICE_CTRL_SUSPEND |
NULL |
Disable the current PWM channel |
DEVICE_CTRL_PWM_FREQUENCE_CONFIG |
uint32_t |
Configure the current PWM channel period |
DEVICE_CTRL_PWM_DUTYCYCLE_CONFIG |
pwm_dutycycle_config_t |
Configure the current PWM channel duty cycle |
DEVICE_CTRL_PWM_IT_PULSE_COUNT_CONFIG |
uint32_t |
Configure the trigger PWM interrupt period value |
device_set_callback
device_set_callback
is used to register a PWM channel interrupt callback function.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev device handle
callback the interrupt callback function to be registered
dev device handle
args unused
size unused
event interrupt event type
event
type definition is as follows:
enum pwm_event_type
{
PWM_EVENT_COMPLETE,
};
pwm_channel_start
pwm_channel_start
is used to start the PWM channel. It actually calls device_control
, where cmd
is DEVICE_CTRL_RESUME
.
pwm_channel_start(dev)
dev pwm channel handle that needs to be opened
pwm_channel_stop
pwm_channel_stop
is used to close the PWM channel. It actually calls device_control
, where cmd
is DEVICE_CTRL_SUSPEND
.
pwm_channel_stop(dev)
dev pwm channel handle that needs to be closed
pwm_channel_update
pwm_channel_update
is used to update the frequency and duty cycle of the PWM channel. The actual call is device_control
, where cmd
is DEVICE_CTRL_CONFIG
.
pwm_channel_update(dev,cfg)
dev pwm channel handle that needs to be updated
cfg pwm_config_t handle
pwm_it_pulse_count_update
pwm_it_pulse_count_update
is used to update the count value of the PWM channel. The PWM interrupt needs to be enabled before it takes effect. When the PWM count reaches the set period count value, an interrupt will be generated. The actual call is device_control
, where cmd
is DEIVCE_CTRL_PWM_IT_PULSE_COUNT_CONFIG
.
pwm_it_pulse_count_update(dev,count)
dev pwm channel handle that needs to update the cycle count value
count cycle count value
DMA
Introduction
DMA is a memory access technology that can directly read and write system memory independently without processor intervention. Under the same degree of processor burden, DMA is a fast data transfer method. The DMA device in BL series MCU has the following characteristics:
8 independent dedicated channels
Four transmission directions: memory to memory, memory to peripheral, peripheral to memory, peripheral to peripheral
LLI linked list
DMA Device Structure Definition
typedef struct dma_device
{
struct device parent;
uint8_t id;
uint8_t ch;
uint8_t direction;
uint8_t transfer_mode;
uint32_t src_req;
uint32_t dst_req;
uint8_t src_burst_size;
uint8_t dst_burst_size;
uint8_t src_width;
uint8_t dst_width;
dma_lli_ctrl_t *lli_cfg;
} dma_device_t;
parent inherits the properties of the parent class
id DMA id number, default 0, currently there is only one DMA
ch channel number
direction transmission direction
transfer_mode transfer mode
src_req source request
dst_req destination request
src_burst_size source burst bytes
dst_burst_size destination number of burst bytes
src_width source transmission bit width
dst_width destination transmission bit width
lli_cfg used to store some information of the dma channel, the user does not need to worry about it
direction
provides the following types
typedef enum {
DMA_MEMORY_TO_MEMORY = 0, /*!< DMA transfer tyep:memory to memory */
DMA_MEMORY_TO_PERIPH, /*!< DMA transfer tyep:memory to peripheral */
DMA_PERIPH_TO_MEMORY, /*!< DMA transfer tyep:peripheral to memory */
DMA_PERIPH_TO_PERIPH, /*!< DMA transfer tyep:peripheral to peripheral */
}dma_transfer_dir_type;
transfer_mode
provides the following types
#define DMA_LLI_ONCE_MODE 0
#define DMA_LLI_CYCLE_MODE 1
src_req
provides the following types
#define DMA_REQUEST_NONE 0x00000000 /*!< DMA request peripheral:None */
#define DMA_REQUEST_UART0_RX 0x00000000 /*!< DMA request peripheral:UART0 RX */
#define DMA_REQUEST_UART0_TX 0x00000001 /*!< DMA request peripheral:UART0 TX */
#define DMA_REQUEST_UART1_RX 0x00000002 /*!< DMA request peripheral:UART1 RX */
#define DMA_REQUEST_UART1_TX 0x00000003 /*!< DMA request peripheral:UART1 TX */
#define DMA_REQUEST_I2C0_RX 0x00000006 /*!< DMA request peripheral:I2C RX */
#define DMA_REQUEST_I2C0_TX 0x00000007 /*!< DMA request peripheral:I2C TX */
#define DMA_REQUEST_SPI0_RX 0x0000000A /*!< DMA request peripheral:SPI RX */
#define DMA_REQUEST_SPI0_TX 0x0000000B /*!< DMA request peripheral:SPI TX */
#define DMA_REQUEST_I2S_RX 0x00000014 /*!< DMA request peripheral:I2S RX */
#define DMA_REQUEST_I2S_TX 0x00000015 /*!< DMA request peripheral:I2S TX */
#define DMA_REQUEST_ADC0 0x00000016 /*!< DMA request peripheral:ADC0 */
#define DMA_REQUEST_DAC0 0x00000017 /*!< DMA request peripheral:DAC0 */
#define DMA_REQUEST_USB_EP0 0x00000018 /*!< DMA request peripheral:USB EP0*/
#define DMA_REQUEST_USB_EP1 0x00000019 /*!< DMA request peripheral:USB EP1*/
#define DMA_REQUEST_USB_EP2 0x0000001A /*!< DMA request peripheral:USB EP2*/
#define DMA_REQUEST_USB_EP3 0x0000001B /*!< DMA request peripheral:USB EP3*/
#define DMA_REQUEST_USB_EP4 0x0000001C /*!< DMA request peripheral:USB EP4*/
#define DMA_REQUEST_USB_EP5 0x0000001D /*!< DMA request peripheral:USB EP5*/
#define DMA_REQUEST_USB_EP6 0x0000001E /*!< DMA request peripheral:USB EP6*/
#define DMA_REQUEST_USB_EP7 0x0000001F /*!< DMA request peripheral:USB EP7 */
dst_req
provides the following types
#define DMA_REQUEST_NONE 0x00000000 /*!< DMA request peripheral:None */
#define DMA_REQUEST_UART0_RX 0x00000000 /*!< DMA request peripheral:UART0 RX */
#define DMA_REQUEST_UART0_TX 0x00000001 /*!< DMA request peripheral:UART0 TX */
#define DMA_REQUEST_UART1_RX 0x00000002 /*!< DMA request peripheral:UART1 RX */
#define DMA_REQUEST_UART1_TX 0x00000003 /*!< DMA request peripheral:UART1 TX */
#define DMA_REQUEST_I2C0_RX 0x00000006 /*!< DMA request peripheral:I2C RX */
#define DMA_REQUEST_I2C0_TX 0x00000007 /*!< DMA request peripheral:I2C TX */
#define DMA_REQUEST_SPI0_RX 0x0000000A /*!< DMA request peripheral:SPI RX */
#define DMA_REQUEST_SPI0_TX 0x0000000B /*!< DMA request peripheral:SPI TX */
#define DMA_REQUEST_I2S_RX 0x00000014 /*!< DMA request peripheral:I2S RX */
#define DMA_REQUEST_I2S_TX 0x00000015 /*!< DMA request peripheral:I2S TX */
#define DMA_REQUEST_ADC0 0x00000016 /*!< DMA request peripheral:ADC0 */
#define DMA_REQUEST_DAC0 0x00000017 /*!< DMA request peripheral:DAC0 */
#define DMA_REQUEST_USB_EP0 0x00000018 /*!< DMA request peripheral:USB EP0*/
#define DMA_REQUEST_USB_EP1 0x00000019 /*!< DMA request peripheral:USB EP1*/
#define DMA_REQUEST_USB_EP2 0x0000001A /*!< DMA request peripheral:USB EP2*/
#define DMA_REQUEST_USB_EP3 0x0000001B /*!< DMA request peripheral:USB EP3*/
#define DMA_REQUEST_USB_EP4 0x0000001C /*!< DMA request peripheral:USB EP4*/
#define DMA_REQUEST_USB_EP5 0x0000001D /*!< DMA request peripheral:USB EP5*/
#define DMA_REQUEST_USB_EP6 0x0000001E /*!< DMA request peripheral:USB EP6*/
#define DMA_REQUEST_USB_EP7 0x0000001F /*!< DMA request peripheral:USB EP7 */
src_burst_size
provides the following types
#define DMA_BURST_INCR1 0
#define DMA_BURST_INCR4 1
#define DMA_BURST_INCR8 2
#define DMA_BURST_INCR16 3
dst_burst_size
provides the following types
#define DMA_BURST_INCR1 0
#define DMA_BURST_INCR4 1
#define DMA_BURST_INCR8 2
#define DMA_BURST_INCR16 3
src_width
provides the following types
#define DMA_TRANSFER_WIDTH_8BIT 0
#define DMA_TRANSFER_WIDTH_16BIT 1
#define DMA_TRANSFER_WIDTH_32BIT 2
dst_width
: provide the following types
#define DMA_TRANSFER_WIDTH_8BIT 0
#define DMA_TRANSFER_WIDTH_16BIT 1
#define DMA_TRANSFER_WIDTH_32BIT 2
DMA Device Parameter Configuration Table
Each DMA device has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_dma.c
, so there is no need for the user himself Define variables. When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_DMA0_CH0
, DMA0_CH0_CONFIG
will take effect, and the DMA channel 0 device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_DMA0_CH0)
#ifndef DMA0_CH0_CONFIG
#define DMA0_CH0_CONFIG \
{ \
.id = 0, \
.ch = 0,\
.direction = DMA_MEMORY_TO_MEMORY,\
.transfer_mode = DMA_LLI_ONCE_MODE, \
.src_req = DMA_REQUEST_NONE, \
.dst_req = DMA_REQUEST_NONE, \
.src_width = DMA_TRANSFER_WIDTH_32BIT , \
.dst_width = DMA_TRANSFER_WIDTH_32BIT , \
}
#endif
#endif
/*Variable definitions*/
static dma_device_t dmax_device[DMA_MAX_INDEX] =
{
#ifdef BSP_USING_DMA0_CH0
DMA0_CH0_CONFIG,
#endif
#ifdef BSP_USING_DMA0_CH1
DMA0_CH1_CONFIG,
#endif
#ifdef BSP_USING_DMA0_CH2
DMA0_CH2_CONFIG,
#endif
#ifdef BSP_USING_DMA0_CH3
DMA0_CH3_CONFIG,
#endif
#ifdef BSP_USING_DMA0_CH4
DMA0_CH4_CONFIG,
#endif
#ifdef BSP_USING_DMA0_CH5
DMA0_CH5_CONFIG,
#endif
#ifdef BSP_USING_DMA0_CH6
DMA0_CH6_CONFIG,
#endif
#ifdef BSP_USING_DMA0_CH7
DMA0_CH7_CONFIG,
#endif
};
备注
The above configuration can be modified through DMA_DEV(dev)->xxx
and can only be used before calling device_open
.
DMA Device Interface
The DMA device interface follows which provided by the standard device driver management layer. In order to facilitate the user to call, some standard interfaces are redefined using macros.
dma_register
dma_register
is used to register a DMA device standard driver interface. Before registering, you need to open the channel macro definition of the corresponding DMA device. For example, after defining the macro BSP_USING_DMA_CH0
, the 0 channel of the DMA
device can be used. After the registration is completed, other interfaces can be used. If the macro is not defined, the 0 channel of the DMA
device cannot be used.
int dma_register(enum dma_index_type index, const char *name);
index device index to be registered
name device name to be registered
index
is used to select the configuration of a certain channel of DMA, an index corresponds to a channel configuration of a DMA, for example, DMA_CH0_INDEX
corresponds to the configuration of DMA channel 0, and index
has the following optional types
enum dma_index_type
{
#ifdef BSP_USING_DMA0_CH0
DMA0_CH0_INDEX,
#endif
#ifdef BSP_USING_DMA0_CH1
DMA0_CH1_INDEX,
#endif
#ifdef BSP_USING_DMA0_CH2
DMA0_CH2_INDEX,
#endif
#ifdef BSP_USING_DMA0_CH3
DMA0_CH3_INDEX,
#endif
#ifdef BSP_USING_DMA0_CH4
DMA0_CH4_INDEX,
#endif
#ifdef BSP_USING_DMA0_CH5
DMA0_CH5_INDEX,
#endif
#ifdef BSP_USING_DMA0_CH6
DMA0_CH6_INDEX,
#endif
#ifdef BSP_USING_DMA0_CH7
DMA0_CH7_INDEX,
#endif
DMA_MAX_INDEX
};
device_open
device_open
is used to open a channel of a dma device,this funtion calls dma_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open mode
return Error code, 0 means opening is successful, other means error
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
device_close
device_close
is used to close a channel of a dma device,this funtion calls dma_close
actually.
int device_close(struct device *dev);
dev device handle
return error code, 0 means closing is successful, others mean error
device_control
device_control
is used to control and modify the parameters of the dma device according to commands.This funtion calls dma_control
actually.
int device_control(struct device *dev, int cmd, void *args);
dev device handle
cmd device control command
args control parameters
return different control commands return different meanings
In addition to standard control commands, DMA devices also have their own special control commands.
#define DMA_CHANNEL_GET_STATUS 0x10
#define DMA_CHANNEL_START 0x11
#define DMA_CHANNEL_STOP 0x12
#define DMA_CHANNEL_UPDATE 0x13
args
input is different depending on cmd
, the list is as follows:
cmd |
args |
description |
---|---|---|
DEVICE_CTRL_SET_INT |
NULL |
Enable DMA transfer completion interrupt |
DEVICE_CTRL_CLR_INT |
NULL |
Disable DMA transfer completion interrupt |
DMA_CHANNEL_GET_STATUS |
NULL |
Get DMA channel completion status |
DMA_CHANNEL_START |
NULL |
Open dma channel |
DMA_CHANNEL_STOP |
NULL |
Close dma channel |
DMA_CHANNEL_UPDATE |
NULL |
Update dma transmission configuration |
device_set_callback
device_set_callback
is used to register a DMA channel interrupt callback function.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev Device handle
callback The interrupt callback function to be registered
dev device handle
args unused
size unused
event interrupt event type
event
type definition is as follows:
enum dma_event_type
{
DMA_EVENT_COMPLETE,
};
dma_channel_start
dma_channel_start
is used to open the DMA channel. It actually calls device_control
, where cmd
is DMA_CHANNEL_START
.
dma_channel_start(dev)
dev dma channel handle that needs to be opened
dma_channel_stop
dma_channel_stop
is used to close the DMA channel. It actually calls device_control
, where cmd
is DMA_CHANNEL_STOP
.
dma_channel_stop(dev)
dev dma channel handle that needs to be closed
dma_channel_update
dma_channel_update
is used to update the DMA configuration. The actual call is device_control
, where cmd
is DMA_CHANNEL_UPDATE
.
dma_channel_update(dev,list)
dev dma channel handle that needs to be updated
list dma_lli_ctrl_t handle
dma_channel_check_busy
dma_channel_check_busy
is used to query whether the currently used DMA channel has completed the transfer. It actually calls device_control
, where cmd
is DMA_CHANNEL_GET_STATUS
.
dma_channel_check_busy(dev)
dev DMA channel handle to be queried
return return the current DMA status, 0 means the transfer is complete, 1 means the transfer is not complete
dma_reload
dma_reload
is used to update the configuration of a certain channel of DMA. Compared with dma_channel_update
, this function does not require the user to pass many parameters, but only needs to fill in the source address, destination address, and length. After this function is called, the DMA channel is not turned on. You need to manually call the dma_channel_start
function.
int dma_reload(struct device *dev, uint32_t src_addr, uint32_t dst_addr, uint32_t transfer_size);
dev DMA channel handle to be queried
src_addr transmission source address
dst_addr transmission destination address
transfer_size the total length of transferred bytes. If the number of bits transferred is 16 bits or 32 bits, it needs to be converted into byte length here.
I2C
Introduction
I2C (Inter-Intergrated Circuit) is a serial communication bus that uses a multi-master-slave architecture to connect low-speed peripheral devices. Each device has a unique address identification, and can be used as a transmitter or receiver. Each device connected to the bus can set the address with software through a unique address and the always-existing relationship between master and slave, and the host can be used as a host transmitter or host receiver. If two or more hosts are initialized at the same time, data transmission can prevent data from being destroyed through conflict detection and arbitration. The I2C devices in the BL series MCU have the following characteristics:
Flexible configuration of slave address
slaveAddr
, register addresssubAddr
Clock frequency that can be flexibly adjusted
Support polling, interrupt, DMA transfer
I2C Device Structure Definition
typedef struct i2c_device
{
struct device parent;
uint8_t id;
uint8_t mode;
uint32_t phase;
} i2c_device_t;
parent inherit the properties of the parent class
ch i2c id, 0 means i2c0, 1 means i2c1
mode i2c transmission mode, 0 means using hardware i2c, 1 means using software i2c, current software i2c is temporarily invalid
phase i2c clock phase div, i2c_clk = i2c_source_clk/(4*(phase+1))
TODO
I2C Device Parameter Configuration Table
Each I2C device has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_i2c.c
, so the user does not need to define variable. When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_I2C0
, I2C0_CONFIG
will take effect, and the I2C
device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_I2C0)
#ifndef I2C0_CONFIG
#define I2C0_CONFIG \
{ \
.id = 0, \
.mode = I2C_HW_MODE,\
.phase = 15, \
}
#endif
#endif
/*Variable definition*/
static i2c_device_t i2cx_device[I2C_MAX_INDEX] =
{
#ifdef BSP_USING_I2C0
I2C0_CONFIG,
#endif
};
备注
The above configuration can be modified through I2C_DEV(dev)->xxx
and can only be used before calling device_open
.
I2C Device Interface
The I2C device standard interface currently only uses device_open
, and provides a standard data transceiver interface.
i2c_register
i2c_register
is used to register an I2C device standard driver interface. The macro definition of the corresponding I2C device needs to be opened before registration. For example, define the macro BSP_USING_I2C0
to use the I2C0
device. After the registration is completed, other interfaces can be used. If the macro is not defined, the I2C0
device cannot be used.
int i2c_register(enum i2c_index_type index, const char *name);
index device index to be registered
name device name to be registered
index
is used to select I2C device, one index corresponds to one I2C device configuration, for example, I2C0_INDEX
corresponds to I2C0_CONFIG
configuration, index
has the following optional types
enum i2c_index_type
{
#ifdef BSP_USING_I2C0
I2C0_INDEX,
#endif
I2C_MAX_INDEX
};
device_open
device_open
is used to open an i2c device, this funtion calls i2c_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open mode
return error code, 0 means opening is successful, others mean errors
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
i2c_transfer
i2c_transfer
is used to transfer i2c msg. The member flags
in i2c_msg_t
structure indicates whether the direction of the transfer is writing or reading, and the length of the specified register address is 0, 1, 2.
int i2c_transfer(struct device *dev, i2c_msg_t msgs[], uint32_t num);
dev device handle
msgs message to be transmitted
num the number of messages
return error code, 0 means opening is successful, others mean error
i2c_msg_t
structure is defined as follows:
typedef struct i2c_msg
{
uint8_t slaveaddr;
uint32_t subaddr;
uint16_t flags;
uint16_t len;
uint8_t *buf;
} i2c_msg_t;
slaveaddr i2c slave device 7-bit slave address
subaddr i2c slave device register address
flags read and write mode and register address length
len transmission data length
buf data buffer
flags
definition is as follows:
/*Read and write mode*/
#define I2C_WR 0x0000
#define I2C_RD 0x0001
/*Register address length*/
#define SUB_ADDR_0BYTE 0x0010
#define SUB_ADDR_1BYTE 0x0020
#define SUB_ADDR_2BYTE 0x0040
SPI
Introduction
Serial Peripheral Interface Bus (SPI) is a synchronous serial communication interface specification for short-range communication. The full-duplex communication mode is used between devices, which is a master-slave mode of one master and one or more slaves, and requires at least 4 wires. In fact, 3 wires are also available (when transmitting in one direction), including SDI (data input), SDO (data output), SCLK (clock), CS (chip select). The SPI devices in the BL series MCU have the following characteristics:
It can be used as both SPI master and SPI slave.
The transmit and receive channels each have a FIFO with a depth of 4 words
Both master and slave devices support 4 clock formats (CPOL, CPHA)
Both master and slave devices support 1/2/3/4 byte transmission mode
Flexible clock configuration, up to 40M clock
Configurable MSB/LSB priority transmission
Receive filter function
Timeout mechanism under slave device
Support polling, interrupt, DMA transfer
SPI Device Structure Definition
typedef struct spi_device
{
struct device parent;
uint8_t id;
uint32_t clk;
uint8_t mode;
uint8_t direction;
uint8_t clk_polaraity;
uint8_t clk_phase;
uint8_t datasize;
uint8_t fifo_threshold;
void* tx_dma;
void* rx_dma;
} spi_device_t;
parent inherit the properties of the parent class
id SPI id, 0 means SPI0
clk SPI clock frequency
mode master mode or slave mode
direction transmission first mode
clk_polaraity clock polarity
clk_phase clock phase
datasize data transmission bit width
fifo_threshold fifo threshold, the maximum is 4
tx_dma additional send dma handle
rx_dma dditional receive dma handle
mode
provides the following types
#define SPI_SLVAE_MODE 0
#define SPI_MASTER_MODE 1
direction
provides the following types
#define SPI_LSB_BYTE0_DIRECTION_FIRST 0
#define SPI_LSB_BYTE3_DIRECTION_FIRST 1
#define SPI_MSB_BYTE0_DIRECTION_FIRST 2
#define SPI_MSB_BYTE3_DIRECTION_FIRST 3
clk_polaraity
provides the following types
#define SPI_POLARITY_LOW 0
#define SPI_POLARITY_HIGH 1
clk_phase
provides the following types
#define SPI_PHASE_1EDGE 0
#define SPI_PHASE_2EDGE 1
datasize
provides the following types
#define SPI_DATASIZE_8BIT 0
#define SPI_DATASIZE_16BIT 1
#define SPI_DATASIZE_24BIT 2
#define SPI_DATASIZE_32BIT 3
SPI Device Parameter Configuration Table
Each SPI device has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_spi.c
, so the user does not need to define variable. When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_SPI0
, SPI0_CONFIG
will take effect, and the SPI0
device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_SPI0)
#ifndef SPI0_CONFIG
#define SPI0_CONFIG \
{ \
.id = 0, \
.clk = 18000000,\
.mode = SPI_MASTER_MODE, \
.direction = SPI_MSB_BYTE0_DIRECTION_FIRST, \
.clk_polaraity = SPI_POLARITY_LOW, \
.clk_phase = SPI_PHASE_1EDGE, \
.datasize = SPI_DATASIZE_8BIT, \
.fifo_threshold = 1, \
}
#endif
#endif
/*Variable definition*/
static spi_device_t spix_device[SPI_MAX_INDEX] =
{
#ifdef BSP_USING_SPI0
SPI0_CONFIG,
#endif
};
备注
The above configuration can be modified through SPI_DEV(dev)->xxx
and can only be used before calling device_open
.
SPI Device Interface
SPI device interface follows which provided by the standard device driver management layer.
spi_register
spi_register
is used to register an SPI device standard driver interface. Before registering, you need to open the macro definition of the corresponding SPI device. For example, define the macro BSP_USING_SPI0
before you can use the SPI0 device. After the registration is completed, other interfaces can be used. If no macro is defined, the SPI device cannot be used.
int spi_register(enum spi_index_type index, const char *name);
index device index to be registered
name device name to be registered
index
is used to select SPI device configuration, one index corresponds to one SPI device configuration, for example, SPI0_INDEX
corresponds to SPI0_CONFIG
configuration, and index
has the following optional types
enum spi_index_type
{
#ifdef BSP_USING_SPI0
SPI0_INDEX,
#endif
SPI_MAX_INDEX
};
device_open
device_open
is used to open the device,this funtion calls spi_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open mode
return error code, 0 means opening is successful, others mean errors
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
device_close
device_close
is used to close the device,this funtion calls spi_close
actually.
int device_close(struct device *dev);
dev device handle
return error code, 0 means closing is successful, others means error
device_control
device_control
is used to control the device and modify parameters according to commands.This funtion calls spi_control
actually.
int device_control(struct device *dev, int cmd, void *args);
dev device handle
cmd device control command
args control parameters
return Different control commands return different meanings.
In addition to standard control commands, SPI devices also have their own special control commands.
#define DEVICE_CTRL_SPI_CONFIG_CLOCK 0x10
args
input is different depending on cmd
, the list is as follows:
cmd |
args |
description |
---|---|---|
DEVICE_CTRL_SET_INT |
NULL |
Enable spi device interrupt |
DEVICE_CTRL_CLR_INT |
NULL |
Disable spi device interrupt |
DEVICE_CTRL_RESUME |
NULL |
Resume spi device |
DEVICE_CTRL_SUSPEND |
NULL |
Suspend spi device |
DEVICE_CTRL_ATTACH_TX_DMA |
NULL |
Link to tx dma device |
DEVICE_CTRL_ATTACH_RX_DMA |
NULL |
Link to rx dma device |
DEVICE_CTRL_SPI_CONFIG_CLOCK |
NULL |
Modify SPI device clock |
DEVICE_CTRL_TX_DMA_SUSPEND |
NULL |
Suspend spi tx dma mode |
DEVICE_CTRL_RX_DMA_SUSPEND |
NULL |
Suspend spi rx dma mode |
DEVICE_CTRL_TX_DMA_RESUME |
NULL |
Resume spi tx dma mode |
DEVICE_CTRL_RX_DMA_RESUME |
NULL |
Resume spi rx dma mode |
device_write
device_write
is used to send data. The sending mode can be polling, interrupt, dma according to the open mode.This funtion calls spi_write
actually.
int device_write(struct device *dev, uint32_t pos, const void *buffer, uint32_t size);
dev device handle
pos useless
buffer the buffer to be written
size the length to be written
return error code, 0 means writing is successful, others mean errors
device_read
device_read
is used to receive data, and the receiving mode can be polling, interrupt, dma according to the open mode.This funtion calls spi_read
actually.
int device_read(struct device *dev, uint32_t pos, void *buffer, uint32_t size);
dev device handle
pos useless
buffer the buffer to be read
size the length to be read
return error code, 0 means successful reading, others mean errors
device_set_callback
device_set_callback
is used to register an SPI device interrupt callback function.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev device handle
callback the interrupt callback function to be registered
dev device handle
args receive and send buffer, the data type is uint8_t*
size transmission length
event interrupt event type
event
type definition is as follows:
enum spi_event_type
{
SPI_EVENT_TX_FIFO,
SPI_EVENT_RX_FIFO,
SPI_EVENT_UNKNOWN
};
spi_transmit
spi_transmit
is used to send data from SPI devices.
int spi_transmit(struct device *dev, void *buffer, uint32_t size, uint8_t type);
dev device handle
buffer send data buffer
size send length
type send bit width type
type
provides the following types
#define SPI_TRANSFER_TYPE_8BIT 0
#define SPI_TRANSFER_TYPE_16BIT 1
#define SPI_TRANSFER_TPYE_24BIT 2
#define SPI_TRANSFER_TYPE_32BIT 3
spi_receive
spi_receive
is used to receive data from SPI devices.
int spi_receive(struct device *dev, void *buffer, uint32_t size, uint8_t type);
dev device handle
buffer receive data buffer
size receiving length
type bit width type
spi_transmit_receive
spi_transmit_receive
is used to send and receive data from SPI devices.
int spi_transmit_receive(struct device *dev, const void *send_buf, void *recv_buf, uint32_t length, uint8_t type);
dev device handle
send_buf send data buffer
recv_buf receive data buffer
length send and receive length
type bit width type
ADC
Introduction
ADC (Analog-to-digital Converter) can convert continuous analog signals into discrete digital signals.
The ADC module in BL MCU series has the following characteristics:
Support selecting 12/14/16 bits conversion result output
ADC maximum working clock is 2MHZ
Support 2.0V, 3.2V optional internal reference voltage
DMA support
Support four modes: single channel single conversion, continuous single channel conversion, single multi-channel conversion and continuous multi-channel conversion mode
Support both single-ended and differential input modes
12 external analog channels
2 DAC internal channels
1 VBAT /2 channel
ADC Device Structure Definition
typedef struct adc_device {
struct device parent;
adc_clk_div_t clk_div;
adc_vref_t vref;
bool continuous_conv_mode;
bool differential_mode;
adc_data_width_t data_width;
adc_fifo_threshold_t fifo_threshold;
adc_pga_gain_t gain;
} adc_device_t;
parent inherits the properties of the parent class
clk_div Partial frequency clock in ADC module
vref 2.0/3.2V reference voltage optional
continuous_conv_mode Whether to select continuous mode. If it is in continuous mode, once adc_start operation, ADC will continue to work until adc_stop. If it is not in continuous mode, adc will only convert the result once every adc_start.
differential_mode Whether it is in differential mode, if it is in differential mode, negative voltage can be measured.
data_width Measurement width selection, the actual accuracy of ADC is 12 bits, but the accuracy of 14bits / 16bits can be achieved by averaging multiple times through OSR. Note that when a higher data width is selected, the frequency will decrease due to averaging. For details, please refer to the enumeration information.
fifo_threshold This parameter affects the DMA handling threshold and ADC FIFO interrupt threshold
gain ADC gain selection for input signal
Others to be added
ADC Device Parameter Configuration Table
Each ADC has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_adc.c
, so there is no need for the user to define it by himself . When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_ADC0
to take effect, and at the same time, the ADC
device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_ADC0)
#ifndef ADC0_CONFIG
#define ADC0_CONFIG \
{ \
.clk_div = ADC_CLOCK_DIV_32, \
.vref = ADC_VREF_3P2V, \
.continuous_conv_mode = DISABLE, \
.differential_mode = DISABLE, \
.data_width = ADC_DATA_WIDTH_16B_WITH_256_AVERAGE, \
.fifo_threshold = ADC_FIFO_THRESHOLD_1BYTE, \
.gain = ADC_GAIN_1 \
}
#endif
#endif
/*Variable definitions*/
static adc_device_t adcx_device[ADC_MAX_INDEX] = {
#ifdef BSP_USING_ADC0
ADC0_CONFIG,
#endif
};
备注
The above configuration can be modified through ADC_DEV(dev)->xxx
and can only be used before device_open
.
ADC Device Interface
ADC device interfaces all follow the interfaces provided by the standard device driver management layer.
adc_register
adc_register
is used to register an ADC device standard driver interface.Before registering, you need to open the macro definition of the corresponding ADC device. For example, define the macro BSP_USING_ADC0
to use the ADC0
device. After the registration is completed, other interfaces can be used. If no macro is defined, the ADC0
device cannot be used.
int adc_register(enum adc_index_type index, const char *name);
index device index to be registered
name device name to be registered
index
is used to select ADC device configuration, one index corresponds to one ADC device configuration, for example, ADC0_INDEX
corresponds to ADC0_CONFIG
configuration. index
has the following optional types:
enum adc_index_type
{
#ifdef BSP_USING_ADC0
ADC0_INDEX,
#endif
ADC_MAX_INDEX
};
device_open
device_open
is used to open an ADC device,this funtion calls adc_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open mode
return Error code, 0: open successfully, others: error
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in rotation sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in rotation receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
device_close
device_close
is used to close an ADC device,this funtion calls adc_close
actually.
int device_close(struct device *dev);
dev device handle
return Error code, 0: open successfully, others: error
device_control
device_control
is used to control and modify the parameters of the adc device according to commands.This funtion calls adc_control
actually.
int device_control(struct device *dev, int cmd, void *args);
dev Device handle
cmd Device control commands
args Control parameter
return Different control commands return different meanings.
In addition to standard control commands, serial devices also have their own special control commands.
#define DEVICE_CTRL_ADC_CHANNEL_START 0x10
#define DEVICE_CTRL_ADC_CHANNEL_STOP 0x11
#define DEVICE_CTRL_ADC_CHANNEL_CONFIG 0x12
#define DEVICE_CTRL_ADC_VBAT_ON 0x13
#define DEVICE_CTRL_ADC_VBAT_OFF 0x14
#define DEVICE_CTRL_ADC_TSEN_ON 0x15
#define DEVICE_CTRL_ADC_TSEN_OFF 0x16
args
input is different depending on cmd
, the list is as follows:
cmd |
args |
description |
---|---|---|
DEVICE_CTRL_SET_INT |
adc_it_type |
Enable ADC device interrupt |
DEVICE_CTRL_CLR_INT |
adc_it_type |
Disable ADC device interrupt |
DEVICE_CTRL_CONFIG |
ADC_param_cfg_t |
Modify ADC configuration |
DEVICE_CTRL_ADC_CHANNEL_CONFIG |
adc_channel_cfg_t |
Modify ADC channel configuration |
DEVICE_CTRL_ATTACH_RX_DMA |
struct device* |
Link receiving DMA device |
DEVICE_CTRL_ADC_CHANNEL_START |
NULL |
Start/continue ADC conversion |
DEVICE_CTRL_ADC_CHANNEL_STOP |
NULL |
Stop ADC conversion |
DEVICE_CTRL_ADC_VBAT_ON |
NULL |
Turn on the internal VDD measurement circuit |
DEVICE_CTRL_ADC_VBAT_OFF |
NULL |
Turn off the internal VDD measurement circuit |
DEVICE_CTRL_ADC_TSEN_ON |
NULL |
Turn on the internal temperature measurement circuit (requires hardware support) |
DEVICE_CTRL_ADC_TSEN_OFF |
NULL |
Turn off the internal temperature measurement circuit (requires hardware support) |
device_read
device_read
is used to receive the data of ADC device, the receiving mode can be polling, interrupt, dma.
int device_read(struct device *dev, uint32_t pos, void *buffer, uint32_t size);
dev Dvice handle
pos No effect
buffer Buffer to read
size Length to read
return Error code, 0: open successfully, others: error
device_set_callback
device_set_callback
is used to register an ADC threshold interrupt callback function.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev Device handle
callback The interrupt callback function to be registered
dev Device handle
args Receive and send buffer, the data type is uint8_t*
size Transmission length
event Type of interrupt event
event
type is as follows:
enum ADC_event_type
{
ADC_EVENT_FIFO_READY,
ADC_EVENT_OVERRUN,
ADC_EVENT_UNDERRUN,
};
DAC
Introduction
DAC Structure Definition
DAC Parameter Configuration Table
DAC Device Interface
TIMER
Introduction
The TIMER device in BL series MCU has the following characteristics:
Multiple clock source options
8-bit clock divider, the division factor is 1-256
Two 32-bit timers
Each timer can independently set three groups of alarm values
Support FreeRun mode and PreLoad mode
16-bit watchdog
Support write protection to prevent system abnormalities caused by incorrect settings
Support two watchdog overflow modes, interrupt or reset
TIMER Device Structure Definition
typedef struct timer_device {
struct device parent;
uint8_t id;
enum timer_cnt_mode_type cnt_mode;
enum timer_preload_trigger_type trigger;
uint32_t reload;
uint32_t timeout1;
uint32_t timeout2;
uint32_t timeout3;
} timer_device_t;
parent inherit the properties of the parent class
id timer id
cnt_mode counting mode:FreeRun and preload
trigger source of preload comparator
reload reload value in preload mode
timeout1 compare source 0 timout value ,unit is us
timeout2 compare source 1 timout value ,unit is us
timeout3 compare source 2 timout value ,unit is us
ch
provides the following types
enum timer_index_type {
TIMER0_INDEX,
TIMER1_INDEX,
TIMER_MAX_INDEX
};
cnt_mode
provides the following types
enum timer_cnt_mode_type {
TIMER_CNT_PRELOAD,
TIMER_CNT_FREERUN,
};
pl_trig_src
provides the following types
enum timer_preload_trigger_type {
TIMER_PRELOAD_TRIGGER_NONE,
TIMER_PRELOAD_TRIGGER_COMP0,
TIMER_PRELOAD_TRIGGER_COMP1,
TIMER_PRELOAD_TRIGGER_COMP2,
};
TIMER Device Parameter Configuration Table
Each TIMER has a parameter configuration macro, the macro definition is located in the peripheral_config.h
file under the bsp/board/xxx
directory, and the variable definition is located in hal_timer.c
, so the user does not need to define the variable . When the user opens the macro of the corresponding device, the configuration of the device will take effect. For example, open the macro BSP_USING_TIMER_CH0
, TIMER_CH0_CONFIG
will take effect, and the TIMER_CH0_INDEX
device can be registered and used.
/*Parameter configuration macro*/
#if defined(BSP_USING_TIMER0)
#ifndef TIMER0_CONFIG
#define TIMER0_CONFIG \
{ \
.id = 0, \
.cnt_mode = TIMER_CNT_PRELOAD, \
.trigger = TIMER_PRELOAD_TRIGGER_COMP2, \
.reload = 0, \
.timeout1 = 1000000, \
.timeout2 = 2000000, \
.timeout3 = 3000000, \
}
#endif
#endif
#if defined(BSP_USING_TIMER1)
#ifndef TIMER1_CONFIG
#define TIMER1_CONFIG \
{ \
.id = 1, \
.cnt_mode = TIMER_CNT_PRELOAD, \
.trigger = TIMER_PRELOAD_TRIGGER_COMP0, \
.reload = 0, \
.timeout1 = 1000000, \
.timeout2 = 2000000, \
.timeout3 = 3000000, \
}
#endif
#endif
/*Variable definitions*/
static timer_device_t timerx_device[TIMER_MAX_INDEX] = {
#ifdef BSP_USING_TIMER0
TIMER0_CONFIG,
#endif
#ifdef BSP_USING_TIMER1
TIMER1_CONFIG,
#endif
};
备注
The above configuration can be modified through TIMER_DEV(dev)->xxx
and can only be used before calling device_open
.
TIMER Device Interface
TIMER device interface follows which provided by the standard device driver management layer.
timer_register
timer_register
is used to register a TIMER device standard driver interface. Before registering, you need to open the macro definition of the corresponding TIMER device. For example, define the macro BSP_USING_TIMER_CH0
to use the TIMER_CH0_INDEX
device. After the registration is completed, other interfaces can be used. If the macro is not defined, the TIMER_CH0_INDEX
device cannot be used.
int timer_register(enum timer_index_type index, const char *name);
index the index of the device to be registered
name Name the device
index
is used to select TIMER device configuration, one index corresponds to a TIMER device configuration, for example, TIMER_CH0_INDEX
corresponds to TIMER_CH0_CONFIG
configuration, and index
has the following optional types
enum timer_index_type {
#ifdef BSP_USING_TIMER0
TIMER0_INDEX,
#endif
#ifdef BSP_USING_TIMER1
TIMER1_INDEX,
#endif
TIMER_MAX_INDEX
};
device_open
device_open
is used to open a TIMER device, this funtion calls timer_open
actually.
int device_open(struct device *dev, uint16_t oflag);
dev device handle
oflag open method
return error code, 0 means opening is successful, others mean error
oflag
provides the following types
#define DEVICE_OFLAG_STREAM_TX 0x001 /* The device is turned on in polling sending mode */
#define DEVICE_OFLAG_STREAM_RX 0x002 /* The device is turned on in polling receiving mode */
#define DEVICE_OFLAG_INT_TX 0x004 /* The device is turned on in interrupt sending mode */
#define DEVICE_OFLAG_INT_RX 0x008 /* The device is turned on in interrupt receiving mode */
#define DEVICE_OFLAG_DMA_TX 0x010 /* The device is turned on in DMA transmission mode */
#define DEVICE_OFLAG_DMA_RX 0x020 /* The device is turned on in DMA receiving mode */
device_close
device_close
is used to close a TIMER device,this funtion calls timer_open
actually.
int device_close(struct device *dev);
dev device handle
return error code, 0 means closing is successful, others mean error
device_control
device_control
is used to control and modify the parameters of the TIMER device according to commands.This funtion calls timer_control
actually.
int device_control(struct device *dev, int cmd, void *args);
dev device handle
cmd device control command
args control parameters
return different control commands return different meanings
In addition to standard control commands, TIMER device also has its own special control commands.
#define DEVICE_CTRL_TIMER_CH_START 0x80
#define DEVICE_CTRL_TIMER_CH_STOP 0x81
#define DEVICE_CTRL_GET_MATCH_STATUS 0x82
args
input is different depending on cmd
, the list is as follows:
cmd |
args |
description |
---|---|---|
DEVICE_CTRL_SET_INT |
timer_it_type |
Enable TIMER interrupt |
DEVICE_CTRL_CLR_INT |
timer_it_type |
Disable TIMER interrupt |
DEVICE_CTRL_GET_INT |
NULL |
Get TIMER interrupt status |
DEVICE_CTRL_RESUME |
NULL |
Enable TIMER |
DEVICE_CTRL_SUSPEND |
NULL |
Disable TIMER |
DEVICE_CTRL_GET_CONFIG |
NULL |
Get TIMER current count |
device_write
device_write
is used to config timer device timeout value.This funtion calls timer_write
actually.
int device_write(struct device *dev, uint32_t pos, const void *buffer, uint32_t size);
dev device handle
pos unused
buffer timer_timeout_cfg_t handle
size the length of timer_timeout_cfg_t
return error code, 0 means writing is successful, others mean errors
device_set_callback
device_set_callback
is used to register a timer compare interrupt callback function.
int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
dev device handle
callback the interrupt callback function to be registered
dev device handle
args unused
size unused
event interrupt event type
event
type definition is as follows:
enum timer_event_type {
TIMER_EVENT_COMP0,
TIMER_EVENT_COMP1,
TIMER_EVENT_COMP2,
TIMER_EVENT_UNKNOWN
};
BLE
Introduction
- Features
- HOST
GAP support peripheral and Central, Observer and Broadcaster
GATT support server and Client
Support pairing with the secure connection feature in Bluetooth 4.2
Support permanent storage of Bluetooth specific settings and data
- mesh
TODO
- The architecture of the BLE protocol stack:
- There are 3 main layers, which together form a complete Bluetooth low power protocol stack
Host: Under the application program, it is composed of multiple (non-real-time) networks and transmission protocols, enabling the application program to communicate with peer devices in a standard and interoperable manner
Controller:The controller implements the link layer (LE LL), which is a low-level real-time protocol that provides standard interoperability for over-the-air communication with the radio. LL handles the reception and transmission of packets, guarantees the transfer of data, and handles all LL control procedures
Radio Hardware:Implement analog and digital baseband functions, allowing link layer firmware to transmit and receive in the 2.4GHz band of the spectrum
- Master Host:
- The Bluetooth Host layer implements all high-level protocols and configuration files, the most important thing is that it provides high-level APIs for applications
HCI: Host and controller interface
L2CAP: Logical Link Control and Adaptation Protocol
GATT: Generic Attribute Profile
GAP: Generic Access Profile
SMP: Security Manager Specification
- Application
- The application layer contains the necessary protocol stack parameter settings and api reference. We analyze the two devices separately from the Bluetooth slave and the Bluetooth master
- Bluetooth slave
Hardware and basic service initialization
Set broadcast parameters: broadcast data, broadcast interval, scan response, etc
Profile settings: add slave services, feature values, and set callback functions to receive host data, etc
Set pairing parameters (optional)
Start the broadcast, start running
Waiting for related events, and event processing, such as receiving data from the host, being linked, etc
- Bluetooth host
Related hardware and basic service initialization
Set scan parameters
Set connection parameters
Set pairing parameters (optional)
Start the protocol stack and start running
Wait for related events, and event processing, such as scan events, Notify events from slaves, etc
API
API introduction
void ble_controller_init(uint8_t task_priority)
/**
* function Controller layer initialization
* @param[in] task_priority: task priority
* @return None
*/
int hci_driver_init(void)
/**
* function HCI interface driver initialization
* @param[in] None
* @return 0: success, !=0: fail
*/
int bt_enable(bt_ready_cb_t cb)
/**
* function BLE enable
* @param[in] cb: Call the callback function if successful
* @return 0: success, !=0: fail
*/
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 Turn on BLE broadcast
*
* @param[in] param: Pointer to broadcast configuration parameter
* @param[in] ad: Pointer to the data in the broadcast packet
* @param[in] ad_len: The length of the data in the broadcast packet
* @param[in] sd: Pointer to scan response packet data
* @param[in] sd_len: Scan response packet data length
* @return 0: success, !=0: fail
*/
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 Update BLE broadcast data
* @param[in] ad: Pointer to the data in the broadcast packet
* @param[in] ad_len: The length of the data in the broadcast packet
* @param[in] sd: Pointer to scan response packet data
* @param[in] sd_len: Scan response packet data length
* @return 0: success, !=0: fail
*/
int bt_le_adv_stop(void)
/**
* function Stop BLE broadcast
* @param[in] None
* @return 0: success, !=0: fail
*/
int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb)
/**
* function Turn on BLE scanning
* @param[in] param: Pointer to scan parameter
* @param[in] cb: Scan callback function
* @return 0: success, !=0: fail
*/
int bt_le_scan_stop(void)
/**
* function Stop BLE scanning
* @param[in] None
* @return 0: success, !=0: fail
*/
int bt_le_whitelist_add(const bt_addr_le_t *addr)
/**
* function Add devices to the whitelist by address
* @param[in] addr: Pointer to the address of the device that needs to be added
* @return 0: success, !=0: fail
*/
int bt_le_whitelist_rem(const bt_addr_le_t *addr)
/**
* function Remove the device from the whitelist
* @param[in] addr: Pointer to the address of the device that needs to be removed
* @return 0: success, !=0: fail
*/
int bt_le_whitelist_clear(void)
/**
* function Clear the whitelist list
* @param[in] None
* @return 0: success, !=0: fail
*/
int bt_le_set_chan_map(u8_t chan_map[5])
/**
* function Set (LE) channel mapping
* @param[in] chan_map: channel array
* @return 0: success, !=0: fail
*/
int bt_unpair(u8_t id, const bt_addr_le_t *addr)
/**
* function Clear pairing information
* @param[in] id: Local ID (mostly just the default BT ID)
* @param[in] addr: Remote device address, NULL or BT_ADDR_LE_ANY to clear all remote devices
* @return 0: success, !=0: fail
*/
int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
/**
* function Get the information of the currently connected device
* @param[in] conn: Pointer to the current connection
* @param[in] info: Pointer to the information of the currently connected device
* @return 0: success, !=0: fail
*/
int bt_conn_get_remote_dev_info(struct bt_conn_info *info)
/**
* function Get information about connected devices
* @param[in] info: Pointer to the information of the currently connected device
* @return Number of connected devices
*/
int bt_conn_le_param_update(struct bt_conn *conn,const struct bt_le_conn_param *param)
/**
* function Update connection parameters
* @param[in] conn: Pointer to the current connection
* @param[in] param: Pointer to connection parameter
* @return 0: success, !=0: fail
*/
int bt_conn_disconnect(struct bt_conn *conn, u8_t reason)
/**
* function Disconnect current connection
* @param[in] conn: pointer to the current connection
* @param[in] reason: the reason for disconnecting the current connection
* @return 0: success, !=0: fail
*/
struct bt_conn *bt_conn_create_le(const bt_addr_le_t *peer,const struct bt_le_conn_param *param)
/**
* function Create connection
* @param[in] peer: The pointer of the device address that needs to be connected
* @param[in] param: Pointer to connection parameter
* @return Success: a valid connection object, otherwise it fails
*/
int bt_conn_create_auto_le(const struct bt_le_conn_param *param)
/**
* function Automatically create and connect to devices in the whitelist
* @param[in] param: pointer to connection parameter
* @return 0: success, !=0: fail
*/
int bt_conn_create_auto_stop(void)
/**
* function Stop automatic creation and connect to devices in the whitelist
* @param[in] None
* @return 0: success, !=0: fail
*/
int bt_le_set_auto_conn(const bt_addr_le_t *addr,const struct bt_le_conn_param *param)
/**
* function Automatically create a connection to the remote device
* @param[in] addr: Remote device address pointer
* @param[in] param: Pointer to connection parameter
* @return 0: success, !=0: fail
*/
struct bt_conn *bt_conn_create_slave_le(const bt_addr_le_t *peer,const struct bt_le_adv_param *param)
/**
* function Initiate a directed broadcast packet to the remote device
* @param[in] peer: Remote device address pointer
* @param[in] param: Pointer to broadcast parameters
* @return Success: a valid connection object, otherwise it fails
*/
int bt_conn_set_security(struct bt_conn *conn, bt_security_t sec)
/**
* function Set the connection security level
* @param[in] conn: Pointer to the connection object
* @param[in] sec: Security level
* @return 0: success, !=0: fail
*/
bt_security_t bt_conn_get_security(struct bt_conn *conn)
/**
* function Get the security level of the current connection
* @param[in] conn: Pointer to the connection object
* @return Security Level
*/
u8_t bt_conn_enc_key_size(struct bt_conn *conn)
/**
* function Get the size of the encryption key of the current connection
* @param[in] conn: Pointer to the connection object
* @return The size of the encryption key
*/
void bt_conn_cb_register(struct bt_conn_cb *cb)
/**
* function Register connection callback function
* @param[in] cb: Connection callback function
* @return None
*/
void bt_set_bondable(bool enable)
/**
* function Set/clear the binding flag in the SMP pairing request/response to the data authentication request
* @param[in] enable: 1: enable, 0: disable
* @return None
*/
int bt_conn_auth_cb_register(const struct bt_conn_auth_cb *cb)
/**
* function Register authentication callback function
* @param[in] cb: Callback function pointer
* @return 0: success, !=0: failure
*/
int bt_conn_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey)
/**
* function Reply with the key
* @param[in] conn: Connect object pointer
* @param[in] passkey: the key entered
* @return 0: success, !=0: failure
*/
int bt_conn_auth_cancel(struct bt_conn *conn)
/**
* function Cancel the authentication process
* @param[in] conn: Connection object pointer
* @return 0: success, !=0: failure
*/
int bt_conn_auth_passkey_confirm(struct bt_conn *conn)
/**
* function If the password matches, reply to the other side
* @param[in] conn: Pointer to connection object
* @return 0: success, !=0: failure
*/
int bt_conn_auth_pincode_entry(struct bt_conn *conn, const char *pin)
/**
* function Reply with PIN code
* @param[in] conn: Pointer to connection object
* @param[in] pin: PIN code pointer
* @return 0: success, !=0: failure
*/
int bt_le_read_rssi(u16_t handle,int8_t *rssi)
/**
* function Read the RSSI value of the opposite device
* @param[in] handle: The handle value of the connection
* @param[in] rssi: rssi pointer
* @return 0: success, !=0: failure
*/
int bt_get_local_address(bt_addr_le_t *adv_addr)
/**
* function Read the address of the machine
* @param[in] adv_addr: Pointer to address
* @return 0: success, !=0: failure
*/
int bt_set_tx_pwr(int8_t power)
/**
* function Set the transmit power of this device
* @param[in] power: power value
* @return 0: success, !=0: failure
*/
Data structure reference
bt_le_adv_param
data structure:
/** LE Advertising Parameters. */
struct bt_le_adv_param {
/** Local identity */
u8_t id;
/** Bit-field of advertising options */
u8_t options;
/** Minimum Advertising Interval (N * 0.625) */
u16_t interval_min;
/** Maximum Advertising Interval (N * 0.625) */
u16_t interval_max;
#if defined(CONFIG_BT_STACK_PTS)
u8_t addr_type;
#endif
};
This data structure is used to configure broadcast parameters, including local identification, broadcast option bit fields, broadcast gaps, etc. The broadcast option bit fields have the following enumerated type parameters to choose from:
enum {
/** Convenience value when no options are specified. */
BT_LE_ADV_OPT_NONE = 0,
/** Advertise as connectable. Type of advertising is determined by
* providing SCAN_RSP data and/or enabling local privacy support.
*/
BT_LE_ADV_OPT_CONNECTABLE = BIT(0),
/** Don't try to resume connectable advertising after a connection.
* This option is only meaningful when used together with
* BT_LE_ADV_OPT_CONNECTABLE. If set the advertising will be stopped
* when bt_le_adv_stop() is called or when an incoming (slave)
* connection happens. If this option is not set the stack will
* take care of keeping advertising enabled even as connections
* occur.
*/
BT_LE_ADV_OPT_ONE_TIME = BIT(1),
/** Advertise using the identity address as the own address.
* @warning This will compromise the privacy of the device, so care
* must be taken when using this option.
*/
BT_LE_ADV_OPT_USE_IDENTITY = BIT(2),
/** Advertise using GAP device name */
BT_LE_ADV_OPT_USE_NAME = BIT(3),
/** Use low duty directed advertising mode, otherwise high duty mode
* will be used. This option is only effective when used with
* bt_conn_create_slave_le().
*/
BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY = BIT(4),
/** Enable use of Resolvable Private Address (RPA) as the target address
* in directed advertisements when CONFIG_BT_PRIVACY is not enabled.
* This is required if the remote device is privacy-enabled and
* supports address resolution of the target address in directed
* advertisement.
* It is the responsibility of the application to check that the remote
* device supports address resolution of directed advertisements by
* reading its Central Address Resolution characteristic.
*/
BT_LE_ADV_OPT_DIR_ADDR_RPA = BIT(5),
/** Use whitelist to filter devices that can request scan response
* data.
*/
BT_LE_ADV_OPT_FILTER_SCAN_REQ = BIT(6),
/** Use whitelist to filter devices that can connect. */
BT_LE_ADV_OPT_FILTER_CONN = BIT(7),
};
If you need to send a broadcast packet, the configuration can be as follows:
param.id = 0;
param.options = (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME);
param.interval_min = 0x00a0;
param.interval_max = 0x00f0;
bt_data
data structure:
struct bt_data {
u8_t type;
u8_t data_len;
const u8_t *data;
};
This data structure is used to fill the data in the broadcast packet, the specific data packet type can refer to the following:
Service UUID
Local Name
Flags
Manufacturer Specific Data
TX Power Level
Secure Simple Pairing OOB
Security Manager OOB
Security Manager TK Value
Slave Connection Interval Range
Service Solicitation
Service Data
Appearance
Public Target Address
Random Target Address
Advertising Interval
LE Bluetooth Device Address
LE Role
Uniform Resource Identifier
LE Supported Features
Channel Map Update Indication
Use this data structure to configure a broadcast packet data, as shown below:
struct bt_data ad_discov[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA(BT_DATA_NAME_COMPLETE, "BL602-BLE-DEV", 13),
};
bt_le_scan_param
data structure:
/** LE scan parameters */
struct bt_le_scan_param {
/** Scan type (BT_LE_SCAN_TYPE_ACTIVE or BT_LE_SCAN_TYPE_PASSIVE) */
u8_t type;
/** Bit-field of scanning filter options. */
u8_t filter_dup;
/** Scan interval (N * 0.625 ms) */
u16_t interval;
/** Scan window (N * 0.625 ms) */
u16_t window;
};
This data structure is used to fill scan parameters, type: There are two types of scan types: BT_LE_SCAN_TYPE_ACTIVE (0x01) and BT_LE_SCAN_TYPE_PASSIVE (0x00) filter_dup: 0x00, except for targeted advertisements, accept all broadcast and scan responses, 0x01, only receive broadcast and scan responses from devices in the whitelist interval: Scan interval window: Scan window
If the scan request is enabled, it can be configured as follows:
scan_param.type = BT_LE_SCAN_TYPE_PASSIVE
scan_param.filter_dup = 0x00
interval=BT_GAP_SCAN_SLOW_INTERVAL_1
window=BT_GAP_SCAN_SLOW_WINDOW_1
bt_le_conn_param
data structure:
/** Connection parameters for LE connections */
struct bt_le_conn_param {
u16_t interval_min;
u16_t interval_max;
u16_t latency;
u16_t timeout;
#if defined(CONFIG_BT_STACK_PTS)
u8_t own_address_type;
#endif
};
This data structure is used to fill in the connection parameters, interval_min: the minimum value of the connection interval (0x0018), interval_max: the maximum value of the connection interval (0x0028), latency: The maximum slave latency allowed for connection events timeout: The time for the connection to time out
Configure the data structure as follows:
interval_min=BT_GAP_INIT_CONN_INT_MIN(0x0018)
interval_max=BT_GAP_INIT_CONN_INT_MAX(0x0028)
latency=0
timeout=400
bt_conn
data structure:
struct bt_conn {
u16_t handle;
u8_t type;
u8_t role;
ATOMIC_DEFINE(flags, BT_CONN_NUM_FLAGS);
/* Which local identity address this connection uses */
u8_t id;
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
bt_security_t sec_level;
bt_security_t required_sec_level;
u8_t encrypt;
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
/* Connection error or reason for disconnect */
u8_t err;
bt_conn_state_t state;
u16_t rx_len;
struct net_buf *rx;
/* Sent but not acknowledged TX packets with a callback */
sys_slist_t tx_pending;
/* Sent but not acknowledged TX packets without a callback before
* the next packet (if any) in tx_pending.
*/
u32_t pending_no_cb;
/* Completed TX for which we need to call the callback */
sys_slist_t tx_complete;
struct k_work tx_complete_work;
/* Queue for outgoing ACL data */
struct k_fifo tx_queue;
/* Active L2CAP channels */
sys_slist_t channels;
atomic_t ref;
/* Delayed work for connection update and other deferred tasks */
struct k_delayed_work update_work;
union {
struct bt_conn_le le;
#if defined(CONFIG_BT_BREDR)
struct bt_conn_br br;
struct bt_conn_sco sco;
#endif
};
#if defined(CONFIG_BT_REMOTE_VERSION)
struct bt_conn_rv {
u8_t version;
u16_t manufacturer;
u16_t subversion;
} rv;
#endif
};
This data structure is the current connection data structure, which includes the parameters related to the BLE connection. After the connection is successful, the data structure can be called by the user.
GPIO
GPIO output - Lamp LED
This demo is based on the output mode of GPIO.
Hardware Connection
This demo is based on BL706_IOT and the connection method is as follows
GPIO function GPIO pin
----------------------------------
D0 <--> GPIO22
D1 <--> GPIO29
D2 <--> GPIO30
D3 <--> GPIO31

Software Implementation
See
examples/gpio/gpio_blink
for the software code
1gpio_set_mode(GPIO_PIN_22, GPIO_OUTPUT_PP_MODE);
2gpio_set_mode(GPIO_PIN_29, GPIO_OUTPUT_PP_MODE);
3gpio_set_mode(GPIO_PIN_30, GPIO_OUTPUT_PP_MODE);
4gpio_set_mode(GPIO_PIN_31, GPIO_OUTPUT_PP_MODE);
Use the above code to configure
GPIO22
GPIO29
GPIO30
GPIO31
to output pull-up mode.
1gpio_write(GPIO_PIN_22, 0);
Use the above code to modify the output level value.
Compile and Program
CDK compilation
Open project:gpio_blink.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=gpio_blink
Program
Experimental Phenomena
Video display:
UART
UART - Loopback
This demo is based on UART polling sending and receiving FIFO interrupt mode.
Hardware Connection
This demo is based on BL706_IOT and the connection method is as follows
GPIO function GPIO pin
----------------------------------
UART0_TX <--> GPIO14
UART0_RX <--> GPIO15
Software Implementation
See
examples/uart/uart_echo
for the software code
1#define BSP_UART_CLOCK_SOURCE ROOT_CLOCK_SOURCE_PLL_96M
2#define BSP_UART_CLOCK_DIV 0
-Configure the UART
device clock source, see bsp/board/bl706_iot/clock_config.h
1#define CONFIG_GPIO14_FUNC GPIO_FUN_UART0_TX
2#define CONFIG_GPIO15_FUNC GPIO_FUN_UART0_RX
Configure
UART
device multiplexing pins, seebsp/board/bl706_iot/pinmux_config.h
1#define BSP_USING_UART0
2
3#if defined(BSP_USING_UART0)
4#ifndef UART0_CONFIG
5#define UART0_CONFIG \
6{ \
7.id = 0, \
8.baudrate = 2000000,\
9.databits = UART_DATA_LEN_8, \
10.stopbits = UART_STOP_ONE, \
11.parity = UART_PAR_NONE, \
12.fifo_threshold = 1, \
13}
14#endif
15#endif
Enable
BSP_USING_UART0
and configure theUART
device, seebsp/board/bl706_iot/peripheral_config.h
1bflb_platform_init();
In the
bflb_platform_init
function, we have registered and opened a serial port device for debugging, to provide users with a basic function ofMSG
for printing out messages. The specific implementation is as follows
1 uart_register(board_get_debug_uart_index(), "debug_log", DEVICE_OFLAG_RDWR);
2 struct device *uart = device_find("debug_log");
3
4 if (uart)
5 {
6 device_open(uart, DEVICE_OFLAG_STREAM_TX | DEVICE_OFLAG_INT_RX);
7 device_set_callback(uart, NULL);
8 device_control(uart, DEVICE_CTRL_CLR_INT, (void *)(UART_RX_FIFO_IT));
9 }
First call the
uart_register
function to register theUART
device, currently registerUART0
Then use the
find
function to find the handle corresponding to the device and save it in theuart
handleFinally use
device_open
to open theuart
device with polling sending and interrupt receiving, the interrupt is closed by default and the receiving interrupt callback function is not registered
1if (uart)
2{
3 device_set_callback(uart, uart_irq_callback);
4 device_control(uart, DEVICE_CTRL_SET_INT, (void *)(UART_RX_FIFO_IT|UART_RTO_IT));
5}
Register the user-specified
UART0
receiving interrupt service function through thedevice_set_callback
function. Open theRX_FIFO
andRTO
interrupts through thedevice_control
function
1void uart_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state)
2{
3 if (state == UART_EVENT_RX_FIFO)
4 {
5 device_write(dev,0,(uint8_t *)args,size);
6 }
7 else if (state == UART_EVENT_RTO)
8 {
9 device_write(dev,0,(uint8_t *)args,size);
10 }
11}
This function is the interrupt service function of the example, and its function is to send out the received data.
state
will return the interrupt type of theUART
deviceargs
contains the return data pointersize
contains the length of the returned datadev
is the handle of the interrupteduart
device
When an interrupt occurs, the
device_write
function will be called to send the received data back.
Compile and Program
CDK compilation
Open project:uart_echo.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=uart_echo
Program
Experimental Phenomena
Video display:
PWM
PWM - Breathing LED
This demo is based on PWM polling mode.
Hardware Connection
This demo is based on BL706_IOT, and the connection method is as follows
GPIO function GPIO pin
----------------------------------
PWM_CH2 <--> GPIO22

Software Implementation
-See examples/pwm/pwm_breath_led
for the software code
1#define BSP_PWM_CLOCK_SOURCE ROOT_CLOCK_SOURCE_XCLK
2#define BSP_PWM_CLOCK_DIV 1
Configure the
PWM
device clock source, seebsp/board/bl706_iot/clock_config.h
1#define CONFIG_GPIO22_FUNC GPIO_FUN_PWM
Configure
PWM
device multiplexing pins, seebsp/board/bl706_iot/pinmux_config.h
1#define BSP_USING_PWM_CH2
2
3#if defined(BSP_USING_PWM_CH2)
4#ifndef PWM_CH2_CONFIG
5#define PWM_CH2_CONFIG \
6{ \
7 .ch = 2, \
8 .frequency = 1000000, \
9 .dutycycle = 0, \
10 .it_pulse_count = 0,\
11}
12#endif
13#endif
Enable
BSP_USING_PWM_CH2
and configurePWM
device configuration, seebsp/board/bl706_iot/peripheral_config.h
1pwm_register(PWM_CH2_INDEX, "led_breath", DEVICE_OFLAG_RDWR);
2
3struct device *led_breath = device_find("led_breath");
4
5if (led_breath) {
6 PWM_DEV(led_breath)->period = 32; //frequence = 32M/1/32 = 1Mhz
7 PWM_DEV(led_breath)->threshold_low = 16;
8 PWM_DEV(led_breath)->threshold_high = 32;
9 device_open(led_breath, DEVICE_OFLAG_STREAM_TX);
10 pwm_channel_start(led_breath);
11}
First call the
pwm_register
function to register a channel of thePWM
device, currently registerPWM_CH2
Then use the
find
function to find the handle corresponding to the device and save it in theled_breath
handleSet the frequency of
PWM_CH2
to 1Mhz, and the duty cycle to 50%Use
device_open
to open theled_breath
device in polling mode
1 for (pwm_cfg.threshold_high = 0; pwm_cfg.threshold_high <= 32; pwm_cfg.threshold_high++) {
2 device_control(led_breath, DEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG, &pwm_cfg);
3 bflb_platform_delay_ms(50);
4 }
5
6 for (pwm_cfg.threshold_high = 32; 0 <= pwm_cfg.threshold_high && pwm_cfg.threshold_high <= 32; pwm_cfg.threshold_high--) {
7 device_control(led_breath, DEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG, &pwm_cfg);
8 bflb_platform_delay_ms(50);
9 }
Use the
device_contorl
function with theDEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG
instruction to modify the duty cycle of the current PWM channel.
Compile and Program
CDK compilation
Open project:pwm_breath_led.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=pwm_breath_led
Program
Experimental Phenomena

pwm breath led!
Video display:
PWM - 驱动步进电机
步进电机是一种将电脉冲转化为角位移的执行机构。当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(及步进角)。可以通过控制脉冲个来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。
本 demo 采用步进电机 28BYJ48 型四相八拍电机,使用 ULN2003 芯片驱动,电压为 DC5V—DC12V。当对步进电机施加一系列连续不断的控制脉冲时,它可以连续不断地转动。每一个脉冲信号对应步进电机的某一相或两相绕组的通电状态改变一次,也就对应转子转过一定的角度(一个步距角)。当通电状态的改变完成一个循环时,转子转过一个齿距。

28BYJ48

ULN2003
这个步进电机内部有个真正的步进马达转子,每一个脉冲能使这个真正的转子转动5.625°,看下图的数据表格中的减速比是1:64,意思是这个真正的步进马达转子转动64周才能让输出轴转动1周,因此下图的表格中步距角度才写的是5.625°/64,表明的意思是一个脉冲可以让输出轴转动5.625°/64的角度。所以要让马达转一周(360°), 则需要360/5.625*64=4096个脉冲。 脉冲(或拍)的数量决定转动的角度,单位时间内脉冲(或拍)的数量决定转动的速度

四相步进电机可以在不同的通电方式下运行,常见的通电方式有如下三种:
一相励磁:单(单相绕组通电)四拍(A+,B+,A-,B-……)

二相励磁:双(双相绕组通电)四拍(A+B+,B+A-,A-B-,B-A+……)

一二相励磁:八拍(A+B+,B+,B+A-,A-,A-B-,B-,B-A+,A+……)

硬件连接
本 demo 基于BL706_IOT开发板,连接方式如下
GPIO function GPIO pin
----------------------------------
PWM_CH0 <--> GPIO10
PWM_CH1 <--> GPIO11
PWM_CH2 <--> GPIO12
PWM_CH3 <--> GPIO3

参考电路
软件实现
软件代码见
examples/pwm/pwm_step_motor
1#define BSP_PWM_CLOCK_SOURCE ROOT_CLOCK_SOURCE_RC_32K
2#define BSP_PWM_CLOCK_DIV 32
配置
PWM
设备时钟源,见bsp/board/bl706_iot/clock_config.h
1#define CONFIG_GPIO3_FUNC GPIO_FUN_PWM
2#define CONFIG_GPIO10_FUNC GPIO_FUN_PWM
3#define CONFIG_GPIO11_FUNC GPIO_FUN_PWM
4#define CONFIG_GPIO12_FUNC GPIO_FUN_PWM
配置
PWM
设备复用引脚,见bsp/board/bl706_iot/pinmux_config.h
1#define BSP_USING_PWM_CH0
2#define BSP_USING_PWM_CH1
3#define BSP_USING_PWM_CH2
4#define BSP_USING_PWM_CH3
5
6#if defined(BSP_USING_PWM_CH0)
7#ifndef PWM_CH0_CONFIG
8#define PWM_CH0_CONFIG \
9 { \
10 .ch = 0, \
11 .polarity_invert_mode = DISABLE, \
12 .period = 0, \
13 .threshold_low = 0, \
14 .threshold_high = 0, \
15 .it_pulse_count = 0, \
16 }
17#endif
18#endif
19
20#if defined(BSP_USING_PWM_CH1)
21#ifndef PWM_CH1_CONFIG
22#define PWM_CH1_CONFIG \
23 { \
24 .ch = 1, \
25 .polarity_invert_mode = DISABLE, \
26 .period = 0, \
27 .threshold_low = 0, \
28 .threshold_high = 0, \
29 .it_pulse_count = 0, \
30 }
31#endif
32#endif
33
34#if defined(BSP_USING_PWM_CH2)
35#ifndef PWM_CH2_CONFIG
36#define PWM_CH2_CONFIG \
37 { \
38 .ch = 2, \
39 .polarity_invert_mode = DISABLE, \
40 .period = 0, \
41 .threshold_low = 0, \
42 .threshold_high = 0, \
43 .it_pulse_count = 0, \
44 }
45#endif
46#endif
47
48#if defined(BSP_USING_PWM_CH3)
49#ifndef PWM_CH3_CONFIG
50#define PWM_CH3_CONFIG \
51 { \
52 .ch = 3, \
53 .polarity_invert_mode = DISABLE, \
54 .period = 0, \
55 .threshold_low = 0, \
56 .threshold_high = 0, \
57 .it_pulse_count = 0, \
58 }
59#endif
60#endif
使能
BSP_USING_PWM_CH0
,BSP_USING_PWM_CH1
,BSP_USING_PWM_CH2
,BSP_USING_PWM_CH3
并配置PWM
设备配置,见bsp/board/bl706_iot/peripheral_config.h
1pwm_register(PWM_CH0_INDEX, "motor_ch0", DEVICE_OFLAG_RDWR);
2pwm_register(PWM_CH1_INDEX, "motor_ch1", DEVICE_OFLAG_RDWR);
3pwm_register(PWM_CH2_INDEX, "motor_ch2", DEVICE_OFLAG_RDWR);
4pwm_register(PWM_CH3_INDEX, "motor_ch3", DEVICE_OFLAG_RDWR);
5
6motor_ch0 = device_find("motor_ch0");
7motor_ch1 = device_find("motor_ch1");
8motor_ch2 = device_find("motor_ch2");
9motor_ch3 = device_find("motor_ch3");
10
11if (motor_ch0) {
12 PWM_DEV(motor_ch0)->period = 8; //frequence = 32K/160/8 = 25hz
13 PWM_DEV(motor_ch0)->threshold_low = 2;
14 PWM_DEV(motor_ch0)->threshold_high = 7;
15 PWM_DEV(motor_ch0)->polarity_invert_mode = ENABLE;
16 device_open(motor_ch0, DEVICE_OFLAG_STREAM_TX);
17}
18if (motor_ch1) {
19 PWM_DEV(motor_ch1)->period = 8; //frequence = 32K/160/8 = 25hz
20 PWM_DEV(motor_ch1)->threshold_low = 1;
21 PWM_DEV(motor_ch1)->threshold_high = 4;
22 device_open(motor_ch1, DEVICE_OFLAG_STREAM_TX);
23}
24if (motor_ch2) {
25 PWM_DEV(motor_ch2)->period = 8; //frequence = 32K/160/8 = 25hz
26 PWM_DEV(motor_ch2)->threshold_low = 3;
27 PWM_DEV(motor_ch2)->threshold_high = 6;
28 device_open(motor_ch2, DEVICE_OFLAG_STREAM_TX);
29}
30if (motor_ch3) {
31 PWM_DEV(motor_ch3)->period = 8; //frequence = 32K/160/8 = 25hz
32 PWM_DEV(motor_ch3)->threshold_low = 5;
33 PWM_DEV(motor_ch3)->threshold_high = 8;
34 device_open(motor_ch3, DEVICE_OFLAG_STREAM_TX);
35}
36pwm_channel_start(motor_ch0);
37pwm_channel_start(motor_ch1);
38pwm_channel_start(motor_ch2);
39pwm_channel_start(motor_ch3);
首先调用
pwm_register
函数注册PWM
设备的一个通道,当前注册 PWM 通道0/1/2/3然后通过
find
函数找到设备对应的句柄,保存于4个句柄中设置 4个通道 的频率为 125hz,占空比为37.5%
使用
device_open
以轮询模式来打开 4个通道
1enum motor_dir_type {
2 CW,
3 CCW,
4 STOP
5};
6
7void motor_set_dir(enum motor_dir_type dir)
8{
9 pwm_dutycycle_config_t pwm_cfg[4];
10
11 if (dir == CW) {
12 pwm_cfg[0].threshold_low = 2;
13 pwm_cfg[0].threshold_high = 7;
14 pwm_cfg[1].threshold_low = 1;
15 pwm_cfg[1].threshold_high = 4;
16 pwm_cfg[2].threshold_low = 3;
17 pwm_cfg[2].threshold_high = 6;
18 pwm_cfg[3].threshold_low = 5;
19 pwm_cfg[3].threshold_high = 8;
20 }
21
22 else if (dir == CCW) {
23 pwm_cfg[0].threshold_low = 2;
24 pwm_cfg[0].threshold_high = 7;
25 pwm_cfg[1].threshold_low = 5;
26 pwm_cfg[1].threshold_high = 8;
27 pwm_cfg[2].threshold_low = 3;
28 pwm_cfg[2].threshold_high = 6;
29 pwm_cfg[3].threshold_low = 1;
30 pwm_cfg[3].threshold_high = 4;
31 } else if (dir == STOP) {
32 pwm_cfg[0].threshold_low = 0;
33 pwm_cfg[0].threshold_high = 0;
34 pwm_cfg[1].threshold_low = 0;
35 pwm_cfg[1].threshold_high = 0;
36 pwm_cfg[2].threshold_low = 0;
37 pwm_cfg[2].threshold_high = 0;
38 pwm_cfg[3].threshold_low = 0;
39 pwm_cfg[3].threshold_high = 0;
40 }
41 device_control(motor_ch0, DEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG, &pwm_cfg[0]);
42 device_control(motor_ch1, DEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG, &pwm_cfg[1]);
43 device_control(motor_ch2, DEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG, &pwm_cfg[2]);
44 device_control(motor_ch3, DEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG, &pwm_cfg[3]);
45}
使用
device_contorl
函数,配合DEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG
指令,修改4个 PWM 通道的的高低阈值。
备注
该函数的功能主要用于切换步进电机的方向
编译和烧录
CDK 编译
打开项目中提供的工程文件:pwm_step_motor.cdkproj
参照 Guide to using CDK (like MDK Keil) under Windows 的步骤编译下载即可
命令行编译
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=pwm_step_motor
烧录
实验现象

MTIMER
MTIMER - System Timer
This demo is based on a 64-bit timer (MTIMER) that comes with the risc-v kernel. This demo can provide reference for os tick.
Hardware Connection
None
Software Implementation
See
examples/systick
for the software code
备注
The mtimer
clock defaults to 1M after frequency division, which is convenient for later use and reduces calculation time.
1void systick_isr()
2{
3 static uint32_t tick=0;
4 tick++;
5 MSG("tick:%d\r\n",tick);
6}
7
8bflb_platform_set_alarm_time(1000000,systick_isr);
Use the above code to set the mtimer timing time to 1s, and register the interrupt callback function.
Compile and Program
CDK compilation
Open project:systick.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=systick
Program
Experimental Phenomena
The tick
value is incremented by 1 per second and printed through the serial port.
DMA
DMA - Data Transfer Between RAM
This demo is based on the memory to memory mode of DMA for data transfer.
Hardware Connection
None
Software Implementation
For the code see
examples/dma/dma_m2m
1#define BSP_USING_DMA0_CH0
2
3#if defined(BSP_USING_DMA0_CH0)
4#ifndef DMA0_CH0_CONFIG
5#define DMA0_CH0_CONFIG \
6{ \
7.id = 0, \
8.ch = 0,\
9.direction = DMA_MEMORY_TO_MEMORY,\
10.transfer_mode = DMA_LLI_ONCE_MODE, \
11.src_req = DMA_REQUEST_NONE, \
12.dst_req = DMA_REQUEST_NONE, \
13.src_width = DMA_TRANSFER_WIDTH_32BIT , \
14.dst_width = DMA_TRANSFER_WIDTH_32BIT , \
15}
16#endif
17#endif
Enable
BSP_USING_DMA0_CH0
and configure theDMA
device, seebsp/board/bl706_iot/peripheral_config.h
1dma_register(DMA0_CH0_INDEX, "DMA", DEVICE_OFLAG_RDWR);
2
3struct device *dma = device_find("DMA");
4
5if (dma)
6{
7 device_open(dma, 0);
8 device_set_callback(dma, dma_transfer_done);
9 device_control(dma, DEVICE_CTRL_SET_INT, NULL);
10}
First call the
dma_register
function to register a channel of theDMA
device, currently registerDMA_CH0
Then use the
find
function to find the handle corresponding to the device and save it in thedma
handleFinally use
device_open
to open thedma
device in the default mode, calldevice_set_callback
to register a dma channel 0 interrupt callback function, and calldevice_control
to open the dma transmission completion interrupt
1dma_reload(dma,(uint32_t)dma_src_buffer,(uint32_t)dma_dst_buffer,8000);
2dma_channel_start(dma);
Call the
dma_reload
function to supplement the configuration of dma channel 0. A part of the configuration has been supplemented inDMA0_CH0_CONFIG
. Here we mainly supplement the source data address, destination data address and total transmission lengthCall
dma_channel_start
to start dma transmission
1void dma_transfer_done(struct device *dev, void *args, uint32_t size, uint32_t state)
2{
3 uint32_t index=0;
4
5 if(!state)
6 {
7 MSG("dma transfer task done\r\n");
8
9 for(index=0;index<8000;index++){
10 if(dma_dst_buffer[index]!=0xff){
11 MSG("dma transfer error\r\n");
12 }
13 }
14
15 MSG("dma transfer success\r\n");
16 }
17
18}
Check whether the data transmission is correct in the interrupt function
Compile and Program
CDK compilation
Open project:dma_m2m.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=dma_m2m
Program
Experimental Phenomena
The data in the dma_src_buffer
array is transferred to the dma_dst_buffer
array through DMA channel 0 with a source 32-bit width and a target 32-bit width. After the data transfer is completed, the serial port prints dma transfer success
.
SPI
SPI - TFT LCD Display
Hardware Connection
This demo is based on BL706_AVB, and the connection method is as follows
GPIO function GPIO pin
----------------------------------
LCD_CS <--> GPIO10
LCD_DC <--> GPIO22
SPI_SCK <--> GPIO19
SPI_MISO <--> GPIO20
SPI_MOSI <--> GPIO21
Software Implementation
See
examples/spi/spi_lcd
for the software code
1#define BSP_SPI_CLOCK_SOURCE ROOT_CLOCK_SOURCE_BCLK
2#define BSP_SPI_CLOCK_DIV 0
Configure the
SPI
device clock source, seebsp/board/bl706_avb/clock_config.h
1#define CONFIG_GPIO19_FUNC GPIO_FUN_SPI
2#define CONFIG_GPIO20_FUNC GPIO_FUN_SPI
3#define CONFIG_GPIO21_FUNC GPIO_FUN_SPI
Configure
SPI
device multiplexing pins, seebsp/board/bl706_avb/pinmux_config.h
备注
bsp/board/bl706_avb/pinmux_config.h
is currently used by all demo demos, so you need to select PINMUX_SELECT
as PINMUX_LVGL
, and open one of the demos
备注
In order to adapt to the bl702_avb hardware, the MOSI and MISO of SPI have been swapped by default. If you want to restore the default, modify SPI_SWAP_ENABLE
in drivers/bl702_driver/hal_drv/default_config/spi_config.h
to 0
1#define BSP_USING_SPI0
2
3#if defined(BSP_USING_SPI0)
4#ifndef SPI0_CONFIG
5#define SPI0_CONFIG \
6{ \
7.id = 0, \
8.clk = 36000000,\
9.mode = SPI_MASTER_MODE, \
10.direction = SPI_MSB_BYTE0_DIRECTION_FIRST, \
11.clk_polaraity = SPI_POLARITY_LOW, \
12.clk_phase = SPI_PHASE_1EDGE, \
13.datasize = SPI_DATASIZE_8BIT, \
14.fifo_threshold = 4, \
15}
16#endif
17#endif
Enable
BSP_USING_SPI0
and configureSPI
device, seebsp/board/bl706_avb/peripheral_config.h
1gpio_set_mode(LCD_CS_PIN,GPIO_OUTPUT_MODE);
2gpio_set_mode(LCD_DC_PIN,GPIO_OUTPUT_MODE);
3gpio_write(LCD_CS_PIN,1); //CS1
4gpio_write(LCD_DC_PIN,1); //DC
5
6spi0 = device_find("spi0");
7if(spi0)
8{
9 device_close(spi0);
10}
11else{
12 spi_register(SPI0_INDEX,"spi0",DEVICE_OFLAG_RDWR);
13 spi0 = device_find("spi0");
14}
15if(spi0)
16{
17 device_open(spi0,DEVICE_OFLAG_STREAM_TX|DEVICE_OFLAG_STREAM_RX);
18}
Configure the
LCD_CS
andLCD_DC
pins as output mode and pull upCall
spi_register
function to registerSPI
device, currently registerSPI0
Then use the
find
function to find the handle corresponding to the device and save it in thespi0
handleFinally use
device_open
to open thespi0
device in polling sending mode
1void LCD_WR_Byte(uint8_t data)
2{
3 CS1_LOW;
4 DC_HIGH;
5 spi_transmit(spi0,&data,1,SPI_TRANSFER_TYPE_8BIT);
6 CS1_HIGH;
7}
8
9void LCD_WR_HalfWord(uint16_t data)
10{
11 CS1_LOW;
12 DC_HIGH;
13 spi_transmit(spi0,&data,1,SPI_TRANSFER_TYPE_16BIT);
14 CS1_HIGH;
15}
16
17void LCD_WR_Word(uint32_t data)
18{
19 CS1_LOW;
20 DC_HIGH;
21 spi_transmit(spi0,&data,1,SPI_TRANSFER_TYPE_32BIT);
22 CS1_HIGH;
23}
Provide interface for LCD display driver
Compile and Program
CDK compilation
Open project:spi_lcd.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_avb APP=spi_lcd
Program
Experimental Phenomena

spi display!
I2C
I2C - AT24CXX read and write
Hardware Connection
This demo is based on BL706_IOT, add AT24CXX circuit by yourself, the connection method is as follows
GPIO function GPIO pin
----------------------------------
I2C_SCL <--> GPIO11
I2C_SDA <--> GPIO16
Software Implementation
See
examples/i2c/i2c_at24cxx
for the software code
1#define BSP_I2C_CLOCK_SOURCE ROOT_CLOCK_SOURCE_BCLK
2#define BSP_I2C_CLOCK_DIV 0
Configure the
I2C
device clock source, seebsp/board/bl706_iot/clock_config.h
1#define CONFIG_GPIO11_FUNC GPIO_FUN_I2C
2#define CONFIG_GPIO16_FUNC GPIO_FUN_I2C
Configure
I2C
device multiplexing pins, seebsp/board/bl706_iot/peripheral_config.h
1#define BSP_USING_I2C0
2
3#if defined(BSP_USING_I2C0)
4#ifndef I2C0_CONFIG
5#define I2C0_CONFIG \
6{ \
7.id = 0, \
8.mode = I2C_HW_MODE,\
9.phase = 15, \
10}
11#endif
12#endif
Enable
BSP_USING_I2C0
and configureI2C
device, seebsp/board/bl706_iot/peripheral_config.h
1i2c_register(I2C0_INDEX, "i2c", DEVICE_OFLAG_RDWR);
2struct device *i2c0 = device_find("i2c");
3
4if (i2c0)
5{
6 MSG("device find success\r\n");
7 device_open(i2c0, 0);
8}
First call the
i2c_register
function to register theI2C
device, currently registerI2C0
Then use the
find
function to find the handle corresponding to the device and save it in thei2c0
handleFinally use
device_open
to open theI2C0
device in the default mode
1i2c_msg_t msg[2];
2uint8_t buf[8] = {0};
3
4msg[0].buf = buf;
5msg[0].flags = SUB_ADDR_1BYTE | I2C_WR;
6msg[0].len = 8;
7msg[0].slaveaddr = 0x50;
8msg[0].subaddr = 0x00;
9
10msg[1].buf = buf;
11msg[1].flags = SUB_ADDR_1BYTE | I2C_RD;
12msg[1].len = 8;
13msg[1].slaveaddr = 0x50;
14msg[1].subaddr = 0x00;
15if (i2c_transfer(i2c0, &msg[0], 2) == 0)
16 MSG("\r\n read:%0x\r\n", msg[1].buf[0] << 8 | msg[1].buf[1]);
Call
i2c_transfer
to transfer twomsg
, onemsg
represents writing 8-byte data to eeprom, and onemsg
represents reading 8-byte data from eeprom
Compile and Program
CDK compilation
Open project:i2c_at24cxx.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=i2c_at24cxx
Program
Experimental Phenomena
ADC
ADC - Key Detection Voltage
This demo mainly introduces the key functions of the ADC. The ADC is used to detect the voltage value of the key input pin and judge whether the corresponding key is pressed according to different voltage divisions.
Hardware Connection
This demo is based on BL706_AVB:
GPIO function GPIO pin
----------------------------------
ADC CH8 <--> GPIO18
Voltage divider circuit:

adc key
Software Implementation
For the code see
examples/adc/adc_key
1#define BSP_ADC_CLOCK_SOURCE ROOT_CLOCK_SOURCE_XCLK
2#define BSP_ADC_CLOCK_DIV 0
Configure the
ADC
device clock source, seebsp/board/bl706_avb/clock_config.h
1#define CONFIG_GPIO18_FUNC GPIO_FUN_ADC
Configure
ADC
device multiplexing pins, seebsp/board/bl706_avb/pinmux_config.h
1#define BSP_USING_ADC0
2
3#if defined(BSP_USING_ADC0)
4#ifndef ADC0_CONFIG
5#define ADC0_CONFIG \
6{ \
7 .clk_div = ADC_CLOCK_DIV_32,\
8 .vref = ADC_VREF_3P2V,\
9 .continuous_conv_mode = DISABLE,\
10 .differential_mode = DISABLE,\
11 .data_width = ADC_DATA_WIDTH_16B_WITH_256_AVERAGE,\
12 .fifo_threshold = ADC_FIFO_THRESHOLD_1BYTE,\
13 .gain = ADC_GAIN_1\
14}
15#endif
16#endif
Enable
BSP_USING_ADC0
and configure theADC
device, seebsp/board/bl706_iot/peripheral_config.h
1adc_channel_cfg_t adc_channel_cfg;
2adc_channel_cfg.pos_channel = posChList;
3adc_channel_cfg.neg_channel = negChList;
4
5adc_register(ADC0_INDEX, "adc_key", DEVICE_OFLAG_STREAM_RX);
6
7adc_key = device_find("adc_key");
8
9if(adc_key)
10{
11 ADC_DEV(adc_key)->continuous_conv_mode = ENABLE;
12 device_open(adc_key, DEVICE_OFLAG_STREAM_RX);
13 device_control(adc_key,DEVICE_CTRL_ADC_CHANNEL_CONFIG,&adc_channel_cfg);
14
15}else{
16 MSG("device open failed\r\n");
17}
18
19adc_channel_start(adc_key);
First call the
adc_register
function to register theadc_key
device, which is currently registered as ADC0Then use the
find
function to find the handle corresponding to the device and save it in theadc_key
handleThen use
device_open
to open theadc_key
device in polling mode, and calldevice_control
to complete the ADC related configurationFinally call
adc_channel_start
to enable ADC conversion
1device_read(adc_key,0,(void *)&result_val,1);
2keyValue = get_adc_key_value(result_val.volt * 1000);
3if( keyValue!=KEY_NO_VALUE){
4
5 MSG("key %d pressed\r\n",keyValue);
6 MSG("result_val.volt: %0.2f mv\n", (result_val.volt * 1000));
7}
Call
device_read
to read theadc_key
device information and save it to theresult_val
structureCall the
get_adc_key_value
function to get the current key value and voltage value
Compile and Program
CDK compilation
Open project:adc_key.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_avb APP=adc_key
Program
Experimental Phenomena
In this experiment, pressing SW1 ~ SW5 on the board in turn will get different voltage values:
key 0: ~0V
key 1: ~0.1V
key 2: ~0.2V
key 3: ~0.3V
key 4: ~0.43V
operation result:

Video display:
TIMER
TIMER - Second Timing Interrupt
This demo is based on TIMER interrupt mode with second timing.
Hardware Connection
None
Software Implementation
See
examples/timer/timer_int
for the software code
1#define BSP_TIMER0_CLOCK_SOURCE ROOT_CLOCK_SOURCE_FCLK
2#define BSP_TIMER0_CLOCK_DIV 0
Configure
TIMER
device clock source,seebsp/board/bl706_iot/clock_config.h
1#define BSP_USING_TIMER0
2
3#if defined(BSP_USING_TIMER0)
4#ifndef TIMER0_CONFIG
5#define TIMER0_CONFIG \
6 { \
7 .id = 0, \
8 .cnt_mode = TIMER_CNT_PRELOAD, \
9 .trigger = TIMER_PRELOAD_TRIGGER_COMP2, \
10 .reload = 0, \
11 .timeout1 = 1000000, \
12 .timeout2 = 2000000, \
13 .timeout3 = 3000000, \
14 }
15#endif
16#endif
Enable
BSP_USING_TIMER0
and configureTIMER0
device,seebsp/board/bl706_iot/peripheral_config.h
1timer_register(TIMER0_INDEX, "timer0");
2
3timer0 = device_find("timer0");
4
5if (timer0) {
6 device_open(timer0, DEVICE_OFLAG_INT_TX); /* 1s,2s,3s timing*/
7 device_set_callback(timer0, timer0_irq_callback);
8 device_control(timer0, DEVICE_CTRL_SET_INT, (void *)(TIMER_COMP0_IT | TIMER_COMP1_IT | TIMER_COMP2_IT));
9} else {
10 MSG("timer device open failed! \n");
11}
Call
timer_register
function to registerTIMER
device, currently registerTIMER0
Then use the
find
function to find the handle corresponding to the device and save it in thetimer0
handleFinally use
device_open
to open thetimer0
device in interrupt modeCall
device_set_callback
to register irq callback namedtimer0_irq_callback
. Calldevice_control
to enable irq and configure timing period.
1void timer0_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state)
2{
3 if (state == TIMER_EVENT_COMP0) {
4 MSG("timer event comp0! \r\n");
5 } else if (state == TIMER_EVENT_COMP1) {
6 MSG("timer event comp1! \r\n");
7 } else if (state == TIMER_EVENT_COMP2) {
8 BL_CASE_SUCCESS;
9 timer_timeout_cfg_t cfg = { 2, 12000000 }; /*modify compare id 2 timeout 12s*/
10 device_write(dev, 0, &cfg, sizeof(timer_timeout_cfg_t));
11 MSG("timer event comp2! \r\n");
12 }
13}
In irq callback,try to determine whether compare id flag is coming.
Call
device_write
to modify compare id 2 timeout with 12s.
Compile and Program
CDK compilation
Open project:timer_int.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=timer_int
Program
Experimental Phenomena
SHELL Command Debugging
In order to facilitate the user to use the pc or other controllers to debug the functions of the development board (non-emulator debugging), we provide users with a shell command component, which is similar to the command operation under linux. The user sends commands on the PC or other control terminals, and sends the data to the shell of the development board through serial port, usb, Ethernet, Bluetooth, wifi, etc. The shell will read the received commands for analysis and scan the registered internal functions. After scanning the matching function, execute the matching function, and return the incoming key value and the result of the function execution to the pc or control terminal in real time . It should be noted that the controller side needs to send the key value of the standard keyboard. This demo will demonstrate how to use shell to debug commands through the serial port.
This shell component has the following functions:
Support standard keyboard character control
Support command auto completion
Support up and down keys to view historical commands
Support left and right keys to modify commands
Support file system and network system debugging
Prepare
PC control terminal uses serial terminal software: xshell or mobaxterm
Connection medium: usb to serial port or network or usb
Hardware Connection
This demo is based on BL706_IOT and the connection method is as follows
GPIO function GPIO pin
----------------------------------
UART0_TX <--> GPIO14
UART0_RX <--> GPIO15
Software Implementation
Shell porting to serial port
See
examples/shell
for the software code
1#define BSP_UART_CLOCK_SOURCE ROOT_CLOCK_SOURCE_PLL_96M
2#define BSP_UART_CLOCK_DIV 0
Configure the
UART
device clock source, seebsp/board/bl706_iot/clock_config.h
1#define CONFIG_GPIO14_FUNC GPIO_FUN_UART0_TX
2#define CONFIG_GPIO15_FUNC GPIO_FUN_UART0_RX
Configure
UART
device multiplexing pins, seebsp/board/bl706_iot/pinmux_config.h
1#define BSP_USING_UART0
2
3#if defined(BSP_USING_UART0)
4#ifndef UART0_CONFIG
5#define UART0_CONFIG \
6{ \
7.id = 0, \
8.baudrate = 2000000,\
9.databits = UART_DATA_LEN_8, \
10.stopbits = UART_STOP_ONE, \
11.parity = UART_PAR_NONE, \
12.fifo_threshold = 1, \
13}
14#endif
15#endif
Enable
BSP_USING_UART0
and configureUART
device configuration, seebsp/board/bl706_iot/peripheral_config.h
1bflb_platform_init();
In the
bflb_platform_init
function, we have registered and opened a serial port device for debugging, to provide users with a basic function ofMSG
for printing out messages. The specific implementation is as follows
1 uart_register(board_get_debug_uart_index(), "debug_log", DEVICE_OFLAG_RDWR);
2 struct device *uart = device_find("debug_log");
3
4 if (uart)
5 {
6 device_open(uart, DEVICE_OFLAG_STREAM_TX | DEVICE_OFLAG_INT_RX);
7 device_set_callback(uart, NULL);
8 device_control(uart, DEVICE_CTRL_CLR_INT, (void *)(UART_RX_FIFO_IT));
9 }
First call the
uart_register
function to register theUART
device, currently registerUART0
Then use the
find
function to find the handle corresponding to the device and save it in theuart
handleFinally use
device_open
to open theuart
device with polling sending and interrupt receiving, the interrupt is closed by default and the receiving interrupt callback function is not registered
1struct device *uart = device_find("debug_log");
2if (uart) {
3 device_set_callback(uart, shell_irq_callback);
4 device_control(uart, DEVICE_CTRL_SET_INT, (void *)(UART_RX_FIFO_IT));
5}
Register the receive interrupt service function for
UART0
through thedevice_set_callback
function. Open theUART_RX_FIFO_IT
interrupt via thedevice_control
function
1void shell_irq_callback(struct device *dev, void *args, uint32_t size, uint32_t state)
2{
3 uint8_t data;
4 if (state == UART_EVENT_RX_FIFO) {
5 data = *(uint8_t *)args;
6 shell_handler(data);
7 }
8}
-In the interrupt callback function, judge whether the state
is UART_EVENT_RX_FIFO
, and if it is, pass the received byte to the shell_handler
function.
1shell_init();
Call
shell_init
to initialize the shell components.
SHELL Command Registration
Shell command registration uses the following two macros
1void hellowd()
2{
3 MSG("hello World\r\n");
4}
5
6int echo(int argc, char *argv[])
7{
8 MSG("%dparameter(s)\r\n", argc);
9
10 for (uint8_t i = 1; i < argc; i++) {
11 MSG("%s\r\n", argv[i]);
12 }
13
14 return 0;
15}
16
17SHELL_CMD_EXPORT(hellowd, hellowd test)
18SHELL_CMD_EXPORT(echo, echo test)
1void hellowd()
2{
3 MSG("hello World\r\n");
4}
5
6int cmd_echo(int argc, char *argv[])
7{
8 MSG("%dparameter(s)\r\n", argc);
9
10 for (uint8_t i = 1; i < argc; i++) {
11 MSG("%s\r\n", argv[i]);
12 }
13
14 return 0;
15}
16
17SHELL_CMD_EXPORT_ALIAS(hellowd, hellwd,hellowd test)
18SHELL_CMD_EXPORT_ALIAS(cmd_echo, echo,echo test)
Compile and Program
CDK compile
Open project:shell.cdkproj
Refer to the steps of Guide to using CDK (like MDK Keil) under Windows to compile and download
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=shell SUPPORT_SHELL=y
Program
Experimental Phenomena

shell test
FATFS Read And Write
LowPower Evaluation
Introduction
BL series chips have rich low-power features to adapt to different low-power applications. In order to facilitate users to quickly evaluate and use the low-power performance of bl series MCUs, bl_mcu_sdk provides a set of low-power interfaces. The low-power levels are divided into four levels.
Running: The power consumption when the CPU is running normally, and the power consumption is determined by the function executed by the customer application code.
WFI: WFI mode, the clock of the CPU is in the Gating state, the CPU stops running, and the program will continue to run when the user exits the WFI mode.
PDS: In PDS mode, most power domains on the chip are turned off, and the CPU is turned off at the same time. RAMs such as ITCM and DTCM in the same power domain as the CPU cannot be used. Only 64K OCTAM can save data. The internal RTC can be used to wake up, or use GPIO pins (when the GPIO power domain is not turned off) to wake up.
HBN: HBN mode, shuts down most of the power domains on the chip, shuts down the CPU and 64K OCRAM, only 4K RAM in the AON domain can save data. The internal RTC can be used to wake up, or a specific wake-up pin (pin located in the AON domain) can be used to wake up.
bl_mcu_sdk provides a simple low-power reference example (bl_mcu_sdk examples/power/lowpower_test/) to help users quickly evaluate low-power features. If you need to further adapt to your own low-power scenarios and adopt different low-power methods, please refer to the relevant datasheet or seek technical support from Boufflao Lab. In this example, the clock selection of peripherals and CPU are both crystal oscillator 32M. The power consumption measurement results based on this example are shown in the following table:
Mode
Reference current
Basic mode
Wake-up source
Remark
Running
5.68 mA
Run
All peripheral clocks are turned on
WFI
3.14 mA
WFI
Any interruption
Except the serial port, other peripheral clocks are closed
PDS
10 uA
PDS 31
Internal RTC/pin interrupt
64K OCRAM to save data
HBN
1 uA
HBN 1
Internal RTC/pin interrupt
4K AON RAM to save data
The reference current in the above table is obtained through the sample firmware test. The definition of four levels of “run” ” wfi” “pds” “hbn” simplifies the original setting of hbn level and pds level.
See bl702_bl704_bl706_DS_EN_Combo_1.9.pdf page 28

Low power consumption example test method
Compile low-power sample code
Write make APP=lowpower_test SUPPORT_SHELL=y BOARD=bl706_lp
in the project directory to complete the compilation of the low power consumption example bl706, or use the CDK project directly to complete the compilation and download.
You can refer to this document “Quick Development Guide” to get more information about compiling and programming.
When the compilation and programming are successful, connect the serial port to the computer and reset the chip, Xshell will display the page as shown in the figure below.

Prepare the hardware environment required for low-power testing
It is possible to connect the ammeter and the circuit board of the power supply side in series
Ammeter
PC (running Windows or Linux system)
TTL to USB
As shown in the figure below, connect the ammeter in series into the power supply circuit of the bl706 module, and issue different low-power commands through the serial debugging assistant software on the PC side, so that the bl706 enters the corresponding low-power mode. Observe the indicated current value and complete the evaluation.

Use Xshell to start evaluating low-power performance
The user can enter the corresponding low power consumption mode by entering the following commands in Xshell.
run
After resetting the chip, it enters the run mode by default without entering any low power consumption mode. The chip is actually running the while(1); statement.
wfi
Enter wfi mode without adding any parameters. After entering, the CPU is in clock gating state to reduce power consumption
After entering wfi mode, any interrupt will wake up, such as uart interrupt. Pressing Enter in Xshell will trigger the BL706 UART RX interrupt, so the wfi low power consumption mode can be awakened by this method.
pds sleeptime
pds can choose to take the parameter “sleeptime” to determine its internal RTC wake-up time. If the command does not carry this parameter, the RTC internal wake-up is not used by default. The current firmware only supports power-on reset wake-up.
If the instruction contains the sleeptime parameter, pds will be awakened at the moment of
sleeptime * clock_period
, which will behave as resetting the chip and reprinting the initial message.After entering the low-power mode, the RTC clock is 32K, so when the sleeptime is 32768, it appears to wake up after a second of sleep.
hbn sleeptime
hbn can choose to take the parameter “sleeptime” to determine its internal RTC wake-up time. If the command does not carry this parameter, the RTC internal wake-up is not used by default. The current firmware only supports power-on reset wake-up.
If the instruction contains the sleeptime parameter, hbn will be awakened at the moment of
sleeptime * clock_period
, which will behave as resetting the chip and printing the start message again.After entering the low-power mode, the RTC clock is 32K, so when the sleeptime is 32768, it appears to wake up after a second of sleep.
BOOT2 IAP
IAP (In Application Programming) is to program some areas of User Flash during the running of the user program. The purpose is to update the firmware program in the product through the reserved communication port after the product is released.
If you need to realize the IAP function, that is, it will be automatically updated when the user program is running. Need to write two project codes when designing the firmware program. The first project program does not perform normal functional operations, but only receives programs or data through some communication channel (such as USB, USART) to update the second part of the code, and the second project code is the real function Code.
Bouffalo Lab provides the boot2_iap.bin file and releases it simultaneously with the Dev Cube software package. Users can use Dev Cube to program boot2_iap.bin into the target board. After programming once, the user code can be updated online through the IAP function.
bl_mcu_sdk contains the source code of boot2_iap, users can check the code in examples/boot2_iap, and complete the compilation and programming. For the compilation and programming process, please refer to the introduction of “Quick Development Guide”.
Prepare
The latest version of Dev Cube
Bl706
TTL-USB
Experimental phenomena
For the specific steps of using Dev Cube to complete the IAP function, please refer to DevCube User Manual “IAP Program Download”.
BLE Client And Server Interconnection
This demo is based on bl702 to demonstrate the connection and data sending and receiving of ble server and ble client.
Prepare
Two bl702 boards or one bl702 board + mobile app
Software Implementation
BLE client software Implementation
For the software code, see
examples/ble/ble_central
1static struct bt_conn_cb ble_tp_conn_callbacks = {
2 .connected = ble_tp_connected,
3 .disconnected = ble_tp_disconnected,
4}
5
6void ble_tp_init()
7{
8 if( !isRegister )
9 {
10 isRegister = 1;
11 bt_conn_cb_register(&ble_tp_conn_callbacks);
12 }
13}
In the
bt_conn_cb_register
function, register thecallback
function for successful connection and disconnectionIn the
ble_start_scan
function, the device will start scanningIn the
device_found
function, the device uploads the scanned Bluetooth device, the code usesadv_name
to find the Bluetooth device that needs to be connected, and initiate the connection
1static void ble_write_data_task(void *pvParameters)
2{
3 int error;
4 uint8_t buf[20] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5 while(1)
6 {
7 k_sem_take(&write_data_poll_sem, K_FOREVER);
8 BT_WARN("ble_write_data\r\n");
9 // Send data to server
10 error = bt_gatt_write_without_response(ble_tp_conn,char_hdl.tp_wr_hdl,buf,20,0);
11 BT_WARN("Write Complete (err %d)\r\n", error);
12 }
13}
After the connection is successful, in the
ble_write_data_task
function, the client sends the data inbuf
to the server
1static u8_t notify_func(struct bt_conn *conn,struct bt_gatt_subscribe_params *params,const void *data, u16_t length);
After the connection is successful, in the
notify_func
function, the client receives the data from the server,data
is the data content,length
is the data length
BLE server software implementation
See
examples/ble/ble_peripheral
for the software code
1int ble_start_adv(void)
2{
3 struct bt_le_adv_param adv_param = {
4 //options:3, connectable undirected, adv one time
5 .options = 3, \
6 .interval_min = BT_GAP_ADV_FAST_INT_MIN_3, \
7 .interval_max = BT_GAP_ADV_FAST_INT_MAX_3, \
8 };
9
10
11 char *adv_name = "BL_TEST_01"; // This name must be the same as adv_name in ble_central
12 uint8_t data[1] = {(BT_LE_AD_LIMITED | BT_LE_AD_NO_BREDR)};
13 uint8_t data_uuid[2] = {0x12, 0x18};//0x1812
14 uint8_t data_appearance[2] = {0x80, 0x01};//0x0180
15 uint8_t data_manu[4] = {0x71, 0x01, 0x04, 0x13};
16 struct bt_data adv_data[] = {
17 BT_DATA(BT_DATA_FLAGS, data, 1),
18 BT_DATA(BT_DATA_UUID16_ALL, data_uuid, sizeof(data_uuid)),
19 BT_DATA(BT_DATA_GAP_APPEARANCE, data_appearance, sizeof(data_appearance)),
20 BT_DATA(BT_DATA_NAME_COMPLETE, adv_name, strlen(adv_name)),
21 BT_DATA(BT_DATA_MANUFACTURER_DATA, data_manu, sizeof(data_manu))
22 };
23
24
25 return bt_le_adv_start(&adv_param, adv_data, ARRAY_SIZE(adv_data), NULL, 0);
26}
In the
ble_start_adv
function,adv_name
sets the name of the broadcast device, and the device starts to broadcast
1static int ble_tp_recv_wr(struct bt_conn *conn, const struct bt_gatt_attr *attr,const void *buf, u16_t len, u16_t offset, u8_t flags);
-After the connection is successful, in ble_tp_recv_wr
, the server receives the data from the client, buf
is the data content, len
is the data length
1static void ble_tp_notify_task(void *pvParameters)
2{
3 int err = -1;
4 char data[244] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
5 k_sem_give(¬ify_poll_sem);
6 while(1)
7 {
8 k_sem_take(¬ify_poll_sem, K_FOREVER);
9 //send data to client
10 err = bt_gatt_notify(ble_tp_conn, get_attr(BT_CHAR_BLE_TP_NOT_ATTR_VAL_INDEX), data, (tx_mtu_size - 3));
11 BT_WARN("ble tp send notify : %d\n", err);
12
13 }
14}
After the connection is successful, in the
ble_tp_notify_task
function, the server sends the data indata
to the client.
Compile and program
CDK tool compilation
Not currently supported
Command compilation
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=ble_peripheral SUPPORT_FREERTOS=y SUPPORT_FLOAT=y SUPPORT_BLE=y
1 $ cd <sdk_path>/bl_mcu_sdk
2 $ make BOARD=bl706_iot APP=ble_central SUPPORT_FREERTOS=y SUPPORT_FLOAT=y SUPPORT_BLE=y
Program
Experimental phenomena
Two bl702 connections


Mobile phone connect bl702

The connection is successful, as shown in the figure below

Steps to send and receive data
Click
1
Unknow Service
to display specific service propertiesClick
2
to turn onNotification
, allowing the server to send data to the clientClick
3
where the client sends data to the server, fill in the data you want to send, and click theSEND
button


