通过上篇文章对STM32MP1双核机制的分析。我们知道M4内核的程序,不能够下载到FLASH当中。那怎么调试M4的程序呢。下面我们就开始讲一讲。
6 j" U9 i' R* ~1 ~3 U2 S# u* lSTM32MP1跟普通M4核MCU开发没有太大的区别,一样调用HAL库,一样可以通过CUBEMX工具生成" w; `: e5 G7 {% Z/ s6 F
初始化代码。当然在能控制的外设方面比真正的M4单片机要少一些,上文已描述过。我们在这里就不多说了。2 [! m* ~8 ?3 i w
我们打开CUBEMX工具,选择对应型号,配置工程:
( |/ f" s3 `) d! \8 U3 _' l/ R我们想控制板上一颗LED,并且串口能够收发数据。" S) r( ?, Z' l6 d" B+ q
LED引脚电路位置:
* c& Y0 Y4 u. j: s2 E6 s
3 o3 I9 ]$ N7 _+ P
与STLINK相连的调试串口UART4电路位置:
: d% [8 v' s5 n: c' v: x8 U, \/ t5 \' [, y0 L! f. O
8 z) V; n7 n1 r9 m. ]- }6 U
+ j- s+ O# \( H) a% U$ o a
, `0 ~/ l# N+ I$ h) F1 z1 ^$ {
CUBEMX配置:( K4 Q$ K# t$ ?& ^7 C: d: e
/ M% A6 i O8 V0 k- D
f6 A! `! h% L f5 T0 C) `, C
9 t4 J) j8 p9 q1 i0 W7 [ P/ P配置时钟:
4 ?, H6 S% Y, I# A7 g
- P0 N$ U) S% \6 b" v* s
, T0 I6 S5 a- B3 ~7 v2 D0 y. j% w, \% V' y/ O, E% I! L% v6 [* A
工程配置时,选择让每一个外设生成独立文件:
, q" ~ T/ m& a5 Q. k
5 P# H: R, g- a; T然后生成代码,我们这里没有官方的STM32CUBEIDE开发,用MDK。
% D q, k% Q; o; q. x2 J生成的代码,我们不直接用,仅作为参考。
& q7 Q* C+ u2 X7 M修改自己的led程序:* a8 W0 L* A7 P+ {" ?' O/ L* `
C:
* z/ k7 Z0 G( O- j9 w! [+ f" q/ l8 I" O- void led_init(void)
8 x6 n; ?, F1 H+ H8 j, S3 A - {; b4 y: ?) ~8 o
- GPIO_InitTypeDef gpio_init_struct;+ i; X# E( k3 M Y6 y" @/ o
- LED0_GPIO_CLK_ENABLE(); /* LED0时钟使能 */9 Z% f% U) A8 G0 e
- 0 c7 `* d H0 q @& _: E- O: c
- 4 c |4 D: H, ~0 F
- gpio_init_struct.Pin = LED0_GPIO_PIN; /* LED0引脚 */
& t, h# g. x) c0 o6 B% _$ | - gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
! _6 V* k3 d0 ]* h0 U8 l8 z# z2 L6 V& q - gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */5 }4 |, j; @, g$ b% V! N
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */4 [2 B2 _# E0 I9 c0 F
- HAL_GPIO_Init(LED0_GPIO_PORT, &gpio_init_struct); /* 初始化LED0引脚 */$ B( p) I5 M. D; l5 ~3 i, v
! q( I7 J" A9 S( z$ _5 w" L- & I5 @& v9 Y g( g( @# c
- LED0(0); /* 关闭 LED0 */( n' y5 z* \5 |& y8 K T
/ |4 ^' o" ]( g. N4 l8 b* j- }
复制代码 H:. e1 M' n, {7 x
- #define LED0_GPIO_PORT GPIOE
, K+ m0 T4 p, ~5 [7 N1 c - #define LED0_GPIO_PIN GPIO_PIN_12
9 I( H' V6 g/ r8 E - #define LED0_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE口时钟使能 */: j; G/ Y! x, |5 B
- ; i0 o, ~3 ~% S; R6 V
- /******************************************************************************************/" \/ O. O; `6 j2 ?. G& D, e. A* t# H
7 J' J& p5 H0 G. \0 u
6 L5 j! A6 V1 w+ O; Y6 A! f5 M- /* LED端口定义 */
% ^$ O$ X( A1 u q' S! i - #define LED0(x) do{ x ? \4 M/ B# ~5 K9 t# w% ]
- HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_SET) : \
+ N! X5 L. S' c& C" p - HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_RESET); \
: ^7 i% a; f1 ~; [1 _ - }while(0) /* LED0 = RED */
0 \- G* r( {5 |0 y& X6 j/ ~: X - $ |3 Z2 E6 F4 E4 ]. P! {% ^
- /* LED取反定义 */
9 i a+ A6 ]: H- R+ Z- y - #define LED0_TOGGLE() do{ HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); }while(0) /* LED0 = !LED0 */
- j% ^) [; J- C0 x
; q0 ^0 ~1 E; Q4 S( b8 P! P- ! o% ?4 Y) g' k' }- Y5 c4 d
- #define LED0_STATION HAL_GPIO_ReadPin(LED0_GPIO_PORT, LED0_GPIO_PIN)
0 k6 _! l) J9 c* @& C: {, f$ X3 W
: @/ c2 a% E$ [7 k6 V8 Q/ m' N2 v- void led_init(void); /* 初始化 */
复制代码 UART4.C3 t* [* C. S: m% b
主要处理都在接收回传函数里面,此接收函数一直参考正点原子。
; t$ n K/ ]: m$ L0 ]- * 接收缓冲, 最大USART_REC_LEN个字节. */
2 a( X4 L! |9 q! x4 `2 P2 b( Z - uint8_t g_usart_rx_buf[USART_REC_LEN];
/ q& t5 T: X5 U& C& ^
, t% k3 q$ U5 t6 R* Q s; L- /* 接收状态
: ~) _1 S5 q# Y0 u& c - * bit15, 接收完成标志
7 n* F2 T, z0 G& e3 a - * bit14, 接收到0x0d, Z6 f {# \' E n& Q
- * bit13~0, 接收到的有效字节数目9 Y( ^* R( x8 V$ `0 j, A
- */
1 e2 P+ B2 ?# ^& [* R8 q - uint16_t g_usart_rx_sta = 0;
/ C9 ?9 Q2 O/ o: @: L# p! M - 7 x! k; J3 H- {8 L+ _
- uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL库使用的串口接收缓冲 */# c# L/ b( S8 Y1 d4 Y* g+ a
- 8 v' K, [5 M* r
- UART_HandleTypeDef g_uart4_handle; /* UART句柄 */6 p9 Y! h& c! l0 {5 o* f
" q; }1 g: S) z4 I5 U6 k3 c4 F( r+ G- ' F1 b3 i& F5 s \
- /*** [$ y; g$ S9 |0 R- l; B* ^( e8 C
- * @brief 串口X初始化函数- x8 ?! u, z0 Q
- * @param baudrate: 波特率, 根据自己需要设置波特率值
4 b2 U9 v7 A" z. s3 K, f- |9 I7 I - * @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.5 p2 O" i1 c+ `; Q! s
- * 这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.9 n; D. P& z, X B4 @
- * @retval 无
1 I* r p1 ?: {+ s - */( p5 ^4 B4 Q% k% I
- void usart_init(uint32_t baudrate)# j) J; V) A% R/ t" ^7 y
- {
& x$ j( d# z! |# P; g - g_uart4_handle.Instance = USART_UX; /* USART4 */$ a8 ?! X1 L7 `& ^+ C
- g_uart4_handle.Init.BaudRate = baudrate; /* 波特率 */
( v7 H5 c4 j& y4 d. R9 u - g_uart4_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */" p0 f0 E( n7 d* ]# Z- l
- g_uart4_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */; d# p. Z5 c; S8 `; }% u
- g_uart4_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */3 N& ?* X e1 Q
- g_uart4_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
4 G& E& f' D3 B - g_uart4_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */1 o* d% M ~6 D$ R+ `! j. @) ?
- HAL_UART_Init(&g_uart4_handle); /* HAL_UART_Init()会使能UART4 */0 G1 e& K' C& J y6 o4 e0 j9 t
-
7 m7 c# {. @2 ~8 z- C - /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
& j6 N% i; G" `: e - HAL_UART_Receive_IT(&g_uart4_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
4 Y m+ j" z+ p5 ?0 c2 v - }
* ` o: B1 d; r! s8 M+ ]
5 D4 V2 O* \* w2 o/ `- /**
0 x+ Y' y3 ~9 z( d* j2 J3 q! D- \ - * @brief UART底层初始化函数
3 q. i$ s+ x; r - * @param huart: UART句柄类型指针
" \% H0 U/ Z3 u* d - * @note 此函数会被HAL_UART_Init()调用& f% x5 d/ Q( \- E3 ]
- * 完成时钟使能,引脚配置,中断配置' r$ Y9 \: a3 f1 `
- * @retval 无" Q/ ?9 _3 |$ X7 J7 ^# S) K' @
- */
% v# Z7 `' s+ u - void HAL_UART_MspInit(UART_HandleTypeDef *huart)
- v# h) B2 V s7 Z* h' D' ]4 q0 E - {1 J" I- _/ |# j1 L U" }+ }
- GPIO_InitTypeDef gpio_init_struct;; R8 G% ?% h; t4 K
- RCC_PeriphCLKInitTypeDef rcc_periphclk_init_struct;, O* i. V. n, E) u
-
# K/ f8 ?5 `3 B7 W# W - if(huart->Instance == UART4) /* 如果是串口4,进行串口4 MSP初始化 */
4 G- o2 O2 q6 w6 C2 m9 C0 a8 } - {
6 C; Y3 I) k/ Z( A. n5 H: b - USART_UX_CLK_ENABLE(); /* USART4时钟使能 */* U( s1 i h2 U( J: @/ D
- USART_TX_GPIO_CLK_ENABLE(); /* 发送引脚时钟使能 */1 ?8 m5 }$ T* F
- USART_RX_GPIO_CLK_ENABLE(); /* 接收引脚时钟使能 */
$ Z, M7 I4 W) s4 x& Y( q' k$ f
8 O9 Q7 j) A1 e! Y' Z* v' g& P- gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* 指定TX引脚 */
& g- H) i* p% {+ ] - gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */! x0 i# v7 `0 F' K6 W
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
& k: O6 v1 Y7 D - gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */( R0 I: ^; K* m. }4 G( t
- gpio_init_struct.Alternate = USART_TX_GPIO_AF; /* 复用为UART4 */" V: b" R7 e. _
- HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); /* 初始化发送引脚 */. ]1 V- q0 B9 n: Z
- ' _1 w( o7 r4 B6 [2 n
- gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* 指定RX引脚 */5 n( s6 a) v2 c2 ?2 E
- gpio_init_struct.Alternate = USART_RX_GPIO_AF; /* 复用为UART4 */
" e7 o9 U7 z) E9 u4 U0 r - HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 初始化接收引脚 */5 |5 {5 J Q8 r; Q, D# E7 Y. o
- $ Y u) w; B, d
- /* 设置UART4时钟源=PLL4Q=74.25MHz */ R. ]2 L3 M( h+ D% H0 N
- rcc_periphclk_init_struct.Uart24ClockSelection = RCC_UART24CLKSOURCE_PLL4;
# ?; t [* L- C9 p" K0 v9 m0 n1 B) Q - HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_struct);
$ m' [0 t3 |; P Z2 S3 f# o' J - 9 U- M3 c4 b4 N" a8 k# Z0 u C
- #if USART_EN_RX& {& d- ]- y( A5 D/ O7 n4 y4 H& i
- HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART4中断通道 */
1 x% e6 w. D' y" @8 B ]3 \ - HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */$ }9 e8 K' E5 _. ] T5 m M
- #endif' v! P3 j; Q6 C& }* w7 l
- }* ^1 P& ?2 I, |
- }
* D1 Q. t8 i+ M - 0 h9 Z E- E9 P! B' o5 g0 ^
- /**5 T3 @4 L& m- ?& d: o0 t- j0 P
- * @brief Rx传输回调函数
- K" |( D5 ^5 T4 m8 o - * @param huart: UART4句柄类型指针
, r0 N2 W2 L4 C1 ?( U& D" K2 g: ~9 x - * @retval 无4 u2 U& [4 G; N- m0 M
- */1 S7 T& U, t6 ?" }" a
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
( S# u! X( U j - {
7 f% u3 O) m/ {( v, z+ Z% k) @! k# ^2 T - if(huart->Instance == UART4) /* 如果是串口4 */6 P" A' o* N/ [9 O0 w
- {
" K6 g+ a2 J- k1 [+ t - if((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 */
0 s2 f# N5 \% a5 c9 A6 z7 B - {
: ?+ H4 A I @' C - if(g_usart_rx_sta & 0x4000) /* 接收到了0x0d */
! t1 C2 b. _ F7 | - {
3 C( [+ h. w1 t# R - if(g_rx_buffer[0] != 0x0a) 1 F" N3 i% U6 [. f% l! c- }- g
- {
' e j6 J3 n* k - g_usart_rx_sta = 0; /* 接收错误,重新开始 */0 v; @; [# B& u! U* u8 s
- }, h; ?* W5 g4 J+ B4 W! U; [
- else
3 j0 J; ]) u6 z( c - {+ ?" b* r- j2 V" v. A% ^" H$ \4 C' E
- g_usart_rx_sta |= 0x8000; /* 接收完成了 */# A4 u: J* ?& y3 J! J! b
- }; {2 F5 O6 L( o0 t0 Q1 ^2 y
- }+ a: v2 x/ a: l; i( {
- else /* 还没收到0X0D */
0 I9 K3 @: n3 q - {
: B* j! J8 P* ~6 T; `4 K - if(g_rx_buffer[0] == 0x0d)
: \9 q5 y3 J) n6 R. \ - {
! d0 O2 Q& V( Z9 c" @+ o - g_usart_rx_sta |= 0x4000;* v6 C4 Z* c3 I0 i) q
- }
/ A7 { }, h5 G5 H5 [& F- L - else5 @1 {) X" e H4 y; N0 x' P% k3 `
- {9 V9 ^# M) c } g* E
- g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0] ;
# A) r1 d( d) ^& Y! y7 y - g_usart_rx_sta++;
8 K- D( h. v/ U0 }7 |, E - if(g_usart_rx_sta > (USART_REC_LEN - 1)). M2 X0 ~+ [% v& R9 g
- {6 ^3 y1 s# O& q
- g_usart_rx_sta = 0; /* 接收数据错误,重新开始接收 */) a7 P& ^% C1 k, R. E+ d1 e
- }
! n# j- B% b9 [$ C" h4 \! T1 s - }
8 r7 u$ z, [2 u7 E7 ?6 g - }% ^- K9 e5 U5 t5 n
- }
7 x1 b% w0 k( G1 [; w% B - }" B- O" O0 R* v* D8 e$ T
- }
7 \8 C a P: J$ I) ^! ~/ _ - $ N# _/ u4 X F$ L7 w- u
- /**8 Y1 ?2 x8 i+ c9 z
- * @brief 串口4中断服务函数
4 ?) M9 w/ D% t+ a - * @param 无4 o4 |1 t# T- `2 F# N) H+ D* A
- * @retval 无
V: ?& g0 v1 a1 }- G - */" b8 N& D) w5 A. O7 \+ K
- void USART_UX_IRQHandler(void)
3 d' I. C* d1 v! h1 _. F. c" l - { : W( r3 m; G2 t% q) ~2 Q. M3 ^
- uint32_t timeout = 0;+ h8 B3 t) L0 D
- uint32_t maxDelay = 0x1FFFF;" C/ U/ j9 B C: b+ \2 w9 G
- 1 d( j1 Y0 a+ q. c+ ^7 T
- HAL_UART_IRQHandler(&g_uart4_handle); /* 调用HAL库中断处理公用函数 */1 V9 D/ e0 E* W( A
/ e# n- A& W# h( `- timeout = 0;4 ~8 M% b7 v) Z( q: K* _
- while (HAL_UART_GetState(&g_uart4_handle) != HAL_UART_STATE_READY) /* 等待就绪 */
o+ @. S, |. h; K; c1 U( B6 P - {) j1 ~8 Q! X1 x8 K
- timeout++; /* 超时处理 */
! l# D! z, J* F) T - if(timeout > maxDelay)
5 d; f% g! g$ e" M' ^ - {5 ^- R- Q/ _- |, t" x$ t4 ^
- break;. e+ t2 `8 c a/ F) F7 u4 M% \( a
- }
8 T N3 b6 p8 p- D, o' v/ G - }
1 z7 S, a! E, `" m+ D" D8 y -
6 P" ]5 `9 Z7 E) V$ B - timeout=0;. K: A$ l ?' f$ g: B2 G ?5 _. K
-
1 R' u9 I! M4 u5 `* A" G - /* 一次处理完成之后,重新开启中断并设置RxXferCount为1 */
& X9 X, }6 y4 U, N! x - while (HAL_UART_Receive_IT(&g_uart4_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)
3 {. m; L5 {% X, u5 {( p3 |* m, D - {
4 c+ h0 S. }9 v* z( I - timeout++; /* 超时处理 */
9 U+ K, p9 t# e) L7 \, ~/ j! B, i - if (timeout > maxDelay)# t0 W/ {. r5 z* @3 C4 O- v8 G
- {. p; P: F( i- P
- break;
9 U! M# ^6 h# `- T! N! {; u - }
4 E! w. S+ Q2 U& }/ k - }7 V: l* \- C N, d. U7 c% ]6 C
- & m' L; W) d0 j, T- j
- }
复制代码 main函数调用:" I: ?7 E9 e! c9 u* u
- if (g_usart_rx_sta & 0x8000) /* 接收到了数据 */
& T2 U/ ?# `5 d) l# R - {
. g' a4 Y1 k- B - len = g_usart_rx_sta & 0x3fff; /* 得到此次接收到的数据长度 */
8 z3 i5 \5 _# u - printf("\r\nYou send message is: \r\n");
1 ?4 Y, Y8 c6 \1 b- M - for (t = 0; t < len; t++)
7 _; G+ e4 M7 O - {
& D( ]: Q- N' `7 @; q x - USART_UX->TDR = g_usart_rx_buf[t];% |2 i6 P% `/ M) K7 Q- t
- while ((USART_UX->ISR & 0X40) == 0); /* 等待发送结束 */" C+ Z9 R( x1 O( R& n9 `- Z' |6 x
- } P% b0 B9 L( z+ ^( z- d
- printf("\r\n\r\n"); /* 插入换行 */
4 z+ C( K, A1 k" ] - g_usart_rx_sta = 0;* c# r: S2 w' h+ v. Q3 b6 i
- }
. N' R8 `8 f/ [' y8 ^ - else
4 W1 X$ `4 ]( j: G - {
% o! D Q$ W9 b7 L* S& D9 A - times++;; Y. @7 k$ {, M) G7 n
- if (times % 5000 == 0)
5 A- E+ X/ R5 O# t$ A* [3 [ - {9 P0 }+ R F: D) A, o8 p
- printf("\r\nSTM32MP1_DK1 UART4 TEST!\r\n");
3 |1 r ~3 N, f3 _, W7 ~. p7 \ - printf("JasonQiu@ST community \r\n\r\n\r\n");
0 ~1 J9 w- ~3 m) l: x; `: M - }
9 l" E! d ?, L: b( n; | - if (times % 200 == 0) printf("Please putchar!\r\n");
5 X$ I/ k& b' M - if (times % 30 == 0) 0 l( M# k V' j" H3 H+ a
- {
$ d/ Z3 G9 g' [' [5 F& n5 a6 n - LED0_TOGGLE(); * _; k2 Z- |% f0 b4 N5 U/ E X3 e
- printf("The led station is %d \r\n\r\n\r\n",LED0_STATION);- o& S% O5 P4 t
- }
3 d0 V, Q2 |! j' y! T0 j - delay(10);2 i' x6 ?: x$ }! D1 a( K O5 z
- }
复制代码 编译无误后,此时我们需要修改MCU的BOOT MODE :3 q/ |- }0 \- e
我们选择从内部RAM启动的模式:
5 O7 X- ^% F) C
! m: `1 s9 K, V& D9 q
# l% O& P: I* }) u* m0 Z% p @
9 H3 t- W3 M$ r# Y/ g V4 FMDK中,有几次配置要注意:9 A" m' m/ o- v& w$ s9 E
$ \% `+ l8 }. C' u* X* m# {
" z6 B/ `$ y2 M4 I$ c7 Y: s
! {7 J+ `5 W9 v/ @# M
; W$ I. D+ p! ]5 m; e1 T4 s
* O5 C2 e# ^6 A% E2 e- S+ r' ^2 s. n% L. J$ p
下载后直接运行,看下输出的状态:
6 h. V+ j! C" F$ D# ~: O9 r
8 r) Z' C' H' v- h* `4 F
板子LED状态:
9 G6 q1 d' c: a; ?- \9 C. W; y! P
7 \5 `& ]! `6 [ p7 P3 Q好了,M4核的裸机开发就到这了。, S9 u+ {% F L0 J2 J
|