stm32wb55 基于rtt的ble sample制作过程# [1 A0 Z! c$ ]7 b5 M5 g6 _0 Q4 G: `
准备活动
8 S. I; z7 L, B% n8 R$ C1 \# t: ]硬件
) Z# }" F: u7 d: \stm32wb55 nucleo开发板& y5 M$ I# N3 ]" Y
stm32wb55 dangle
) H: O0 _/ D) U6 Y% j软件
+ _( s0 ^; C- I, hrtthread stm32wb55 bsp/ Q* A" L, D$ ^; q# q9 x1 ?! }! F2 v
st官方 stm32wb固件包
: N4 R( d A* ]7 t! G, K/ N
, r$ b' ?; x, s' c1 l开发环境
) }$ @, X) M. E% N& H! p' ukeil MDK
* b. p1 E" T$ p4 e, U3 Ivscode2 T' p- c# @( V- Y0 S& r# f
rtthread env
) I/ z7 L3 O$ u! n! O8 z- R6 s& p. u! o% Y. ? a
概述9 {& a" u( {3 ]) M0 F! H- H8 }
本文的目的是将ST官方的STM32WB55 固件包里的BLE sample移植到RT-Thread,最终变为rtt生态的一个软件包,让更多开发者都可以直接做基于rtt开箱即用。- [9 t0 o. U q) e# p
" l7 ?1 V" X! G* o, h! w4 V+ O移植前准备; O" c0 P2 e, W ~, q
生成基于rtt的stm32wb55的最小工程
- h0 j+ i) i7 k; S7 P首先需要clone rtthread的stm32wb55的bsp,然后创建基本的工程,这一步很简单,从官方github仓库clone最新的代码,然后定位到stm32wb55的bsp,使用env scons --dist生成wb55最小工程。如下所示:
% r8 E* d3 u& e7 f _. \1 S2 t* s5 {( Q" t1 E
2 Q- A5 w. d# g- xph@XPHPC D:\GitHub\rt-thread\bsp\stm32\stm32wb55-st-nucleo
# ?8 N+ x7 ] {1 |/ h2 }# P) j - > scons --dist
, J7 x4 A& o( u0 |% R3 H: e( k2 e - scons: Reading SConscript files ...
0 y+ f% |2 `' S' d - make distribution.... $ T. w: R+ `/ `- L" Y) M
- => stm32wb55-st-nucleo
/ L: r; q+ ]' \3 X b% ^6 y$ w - => start dist handle
, [* x3 j' J- V! B4 Z - => copy stm32 bsp library 7 g S2 d' L2 W+ V7 t; y) j6 ~- F
- => copy bsp drivers
5 c B9 Y+ F7 e) E# @3 R - => components
8 { N7 T. W, ]% y( j: t8 ?, I - => include 5 S4 w* q: V1 q# j$ i
- => libcpu
' \- q( E9 \7 _& @4 w Y - => src
1 h1 J: M7 I0 ?/ u2 }0 @+ C! J - => tools
" j4 H# y/ c/ M$ Y" g, a! ^; o7 O - update mdk5 project
' h) C- ^9 d) o - update iar project 2 m' W& o! |% u( i* D( |. P h
- done!
复制代码 ! e) ?$ n* j+ m% k& Q) ~8 Q
. H2 p, ?+ W* B, B% A. S) _然后用keil打开,编译烧录到nucleo开发板中验证。当开发板LED1蓝灯开始闪烁,同时串口有打印信息输出,则表示基于rtthread的最小工程生成成功。
% R7 X7 C: p u8 I) D6 a, m
7 T/ Q% I4 i* g* @. l- \ | /! q8 c& h6 c: `* {3 `
- - RT - Thread Operating System
( h0 `! M, x- `3 Y2 t - / | \ 4.0.3 build Jan 7 20210 D$ X8 X" D* p" y) q
- 2006 - 2020 Copyright by rt-thread team C+ D# c6 I8 g7 ^ g) S. m* c, U
- msh >
复制代码
9 ]" m9 |( k! u. ?2 kst官方固件包删除不相关代码# R2 ^' w1 W4 @2 A6 M* `$ y
我们从最基础的beacon工程开始移植,删除其他不必要的工程文件和文件夹,方便代码分析工具分析和定位。如果工程文件夹太多,诸如vscode source insight这类代码工具就很难做到精确跳转。
1 o! Y; e) v8 L) M3 E如下图所示,我只保留基于keil mdk的beacon工程,其他的不相干的工程全部删除。' W3 |% o7 P' \" L; b
6 p4 Y% [) K. l" A
% O/ b' M- ?; }
7 Q: s8 Y+ l: J7 u. I4 G检查的方法也很简单,在固件包中搜索一下main.c函数,看一下有没有多余的就行了。
" g' e2 k/ b; f" s3 r8 ?" A- T然后打开这个beacon工程,编译一下,没有错误,没有警告,那么准备工作就做好了。
! s: {) V9 ~; T0 {: k# l# R+ @9 H4 M$ i
移植! u9 y' l" j& H: t( n6 Q3 S0 R3 i
我的移植思路是,将ST官方的sample当作rtt中的一个线程,这样子即不影响其他线程的使用移植起来也比较方便。3 \: c- p7 r7 |: _4 u
; T# {* ?$ J/ I8 j. J& u) ~工程创建' k8 e+ p# m4 F! D1 B
创建ibeacon线程! P4 Q9 {' Z$ x9 i( J
- static int ibeacon_thread_init(void)/ N) X1 K& e4 u: Z" ]/ L" p
- {( z) c& S3 c2 l# ^( C Q8 @! b
- rt_thread_t ibeacon_thread;4 \, B& h1 _9 w4 h
- ibeacon_thread = rt_thread_create("ibeacon",3 g3 s1 q4 t& r
- ibeacon_thread_entry," U/ w/ `( V% U$ N
- RT_NULL,
& Z( X; O- d9 t% @ - 1024,
" I6 b( J" ^6 a/ F) V/ b - 2,3 ^, j1 Z" F! ]
- 10);7 P' r. }. j. ^9 j Z+ G K
- if (ibeacon_thread != RT_NULL)$ k6 `7 I& V$ N& i$ Z7 [- |7 i
- {
, M- L' j8 A0 o b - rt_thread_startup(ibeacon_thread);& x6 y" W. q6 b8 \" }* f
- }$ ? `+ E8 a7 L& e5 k& S
- return RT_EOK;; n+ Y. z: E, B* J% t& N* T
- }: ?1 C$ e% L3 K$ ^6 D( R
- o U( \5 \9 E; ]2 K! s- INIT_APP_EXPORT(ibeacon_thread_init);
复制代码
, |+ u% j' t. ]8 O) {8 J* p将st官方sample中的main函数移植过来,放在ibeacon线程的入口函数中
6 m# l4 f L* A5 y- static void ibeacon_thread_entry(void *parameter)' x6 P2 a7 N5 g. ~2 l
- {
5 m6 P9 x; V* ] - LOG_D("ibeacon thread entry...");
& ?1 N2 Y- }; \8 l' f4 Z' ]+ C+ O - /**1 `; s* Y* ?& y# z) h( s! D
- * The OPTVERR flag is wrongly set at power on
# b7 u E8 o4 v - * It shall be cleared before using any HAL_FLASH_xxx() api
7 }+ J R- _" d, K7 A - */
; V+ W* V( y0 | - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);2 D2 ]; Q) p, K5 a: L, ?
- HAL_Init();
6 ~3 T$ G* y1 i% f( y8 F" O - Reset_Device();
0 ~8 f8 W% \( y7 N9 j - Init_Exti();' Y0 K9 V6 |( A% Q
- MX_GPIO_Init();: u; ]% @' ?- d8 i7 I4 D
- MX_RTC_Init();9 [8 O: P; j8 E5 i4 s: T
- /* Init code for STM32_WPAN */* a6 }0 V- ? y+ ^! Z
- APPE_Init();
; A3 r8 a$ E! Y+ i2 U9 P0 A9 j - while (1)
; }& X8 P: H9 B6 k0 d - {& [0 z2 E7 L& Z' [$ b* L
- UTIL_SEQ_Run(UTIL_SEQ_DEFAULT);; q$ ?4 L! P1 e3 e( e/ Z# `
- rt_thread_mdelay(10);0 c, M9 C+ C* X) |6 n
- }9 }+ T/ e: ?. y0 L' D0 S
- }
复制代码 2 N: p! r/ ?# w8 U
将STM32_WPAN中间件整体复制过来,然后根据st的sample工程将BLE相关文件都加进去' s" f( @3 n* [% o
: M+ i( |" V, u
" r r4 N. T) S" H% P$ V
* g, U- h- I, g# X" ?编译,根据编译错误将缺失的文件加入到工程中去,直到编译完成
& X4 W0 t- F& }2 ?# f# Z. |) x! y4 J. n
关于文件的分组8 E' `# Y v: s6 F4 p0 ~
STM32_WPAN这个文件夹里面存放的是ST关于无线协议的中间件,包括BLE、thread、zigbee等等,所以移植的时候直接整体搬过去就好了,至于里面的东西可以暂不做考虑。2 O# b! K& v2 K2 @; r2 ]4 X
" w- g; T' s+ B& e
. i0 n8 y" u+ z7 K3 S4 r5 @8 r
; M) K" v% @& o6 M: k
STM32WB特有的低功耗管理组件和列表单独做通用分组
7 P5 C0 a1 }& H- E; b1 U5 ? ^# i/ a
) Y- b- z. A/ Z# P& q
$ G/ P+ {. v# F0 I _: E
其他需要用到的文件统一放到ibeacon分组中& u- ?3 D$ b6 Y2 j
) `( G$ r3 W+ k8 _8 z; A, h$ t0 O3 `7 D0 |) A
" a3 W+ ]! Q* A( p. g
移植注意事项
4 \$ {# H* O- G* E; C& [1 Y. h8 u以上工作全部完成后,编译运行后程序运行正常,但是通过nrf connect是无法扫描到beacon的,对比分析后发现两部分地方需要修改。
( b P6 _: b: i% |2 L" M' c: e, ]; r6 u4 l. _4 ?4 z2 h
中断处理函数需要移植& a, d4 f5 m. H9 Z
之前的固有印象是STM32的HAL库中断处理函数全都是虚函数方式然后通过注册回调函数来最终执行用户自己的中断服务函数。这也是忽略该步骤的重要原因之一,因为之前的STD或者寄存器版本没有写中断服务函数是会编译报错的。8 c- {5 w4 {5 s4 X7 r2 A" a; K
, f. c* j, p+ ?/ B* ~' a将以下三个中断服务函数放在ibeacon线程.c文件中。2 n" L W$ {0 D7 m9 ~1 D2 x$ j
) K$ Q+ e1 e9 y" [3 x- U- /**
- Y0 x1 u% `. D# [ T- w - * ! RTC timeserver处理中断服务函数
6 v2 }# K; T" P( Z5 S8 z - */: c- n! f2 D* W; M- D- V* G
- void RTC_WKUP_IRQHandler(void)
~+ L) L. T% W( D2 _$ `6 } \( s - {
* R: W8 ~0 z, d - HW_TS_RTC_Wakeup_Handler();
( Z8 ]/ L$ S* t& ] M) M h# o7 W- z - }
) |# T+ f& f7 d5 {6 C/ ]
! R! o9 P4 [3 K& M8 v- /**
9 i/ S; q% H/ m6 w* z% W - * ! IPCC 通讯收发中断处理函数; o/ ]: F4 U, X1 ]" ]6 [
- */6 k+ f6 Q+ D/ s4 M# a; M
- void IPCC_C1_TX_IRQHandler(void)
" f2 R# e0 {3 X: [: ` - {
& C- I! ^2 y% ~2 i2 P3 H# J. R - HW_IPCC_Tx_Handler();
% \/ ?, b1 B! z" H0 K - / y' l9 A- b7 t
- return;
/ G ^* ?' w$ B# G( X! c - }
" q# A. c8 e, @ - 2 }8 T! Z; k E2 F4 Y W
- void IPCC_C1_RX_IRQHandler(void)+ W: r9 x7 E% R! [
- {( z/ C( a: f& D1 \; q4 V H: B
- HW_IPCC_Rx_Handler();
' h+ \- h, p# R - return;
) i8 }& b. R" u - }
复制代码
4 ?7 i9 R; z) M+ G- S0 h这三个中断服务函数主要是用来处理CPU1和CPU2之间的通讯的,这部分内容后面再介绍。
8 a3 D3 X8 A/ X4 |2 g% a9 b* L, ]6 p0 B2 w
link文件需要更改
! l* q3 ^) m: c/ P# O1 c: t+ I! g5 MSTM32WB是一颗双核MCU,他们共享了部分flash和RAM,所以不能像传统的单核M4内核那样定义link文件,需要将部分flash和RAM资源留出来给协处理器使用。具体的更改直接参考ST的sample工程中的link文件。
0 |. g. Q- K2 `; [
9 A4 }' Z% {! |5 r2 e. O( T
$ g! U$ n2 P, Z' P4 U" q) @
! G0 f% q9 Q) O6 n5 C7 C2 k4 I { S经过以上两步的修改,编译烧录后就可以正常使用了。! }. ?1 e7 S- L3 q. K! M
, K) L; u. @& Q9 K% p备注
! j! A) ^: @4 v% e名词解释4 e( i; v+ l1 j |+ v0 B1 s5 c1 b
ACI: Application command interface 应用层命令接口
; r l- _# P5 c$ xCLI: Command line interface 命令行接口
1 L" S6 E# |. {3 Z: T" p# E" Y& o8 g7 w ~# V
# X+ N* f- a' C# o/ ^* `0 M8 q' d# }/ M
|