通过上篇文章对STM32MP1双核机制的分析。我们知道M4内核的程序,不能够下载到FLASH当中。那怎么调试M4的程序呢。下面我们就开始讲一讲。
% n- o% z8 o* l$ Y0 ySTM32MP1跟普通M4核MCU开发没有太大的区别,一样调用HAL库,一样可以通过CUBEMX工具生成
$ t( W L3 R; W. b初始化代码。当然在能控制的外设方面比真正的M4单片机要少一些,上文已描述过。我们在这里就不多说了。5 A& [2 s9 Y* Z' C
我们打开CUBEMX工具,选择对应型号,配置工程:% ?* a- f, q Z
我们想控制板上一颗LED,并且串口能够收发数据。
3 r" R- A* _! Z: mLED引脚电路位置:1 O" v* i6 n2 ]' L1 X
6 ]7 g4 u' y: @) x1 n0 b7 q与STLINK相连的调试串口UART4电路位置:) z, Q! x/ l0 J. X2 p
8 o0 e4 w6 e! w
: v9 f& L' [2 I: O
2 u, I* U9 i/ a
" z* m, D' P4 F) }$ [CUBEMX配置:
' ~6 z8 d" F1 b4 Z: K# t; d
" Z$ b3 P! o( i7 C6 W
! O& M( y( k* T% @: c# }* O
- r( e1 E" s' [" F0 L
配置时钟:
( @6 Q2 n( `0 P9 o* m& ~
( W# |$ V! k8 I5 z
" k" ?( y' b6 t" G% w7 w Y2 F( d5 E d
工程配置时,选择让每一个外设生成独立文件:
5 {; `2 ^7 n7 `( |; i; r& a" L0 n! ^
! W ^: V$ L V# r% T& }
然后生成代码,我们这里没有官方的STM32CUBEIDE开发,用MDK。
# ~, |& i1 _4 ~: W! U1 o0 A生成的代码,我们不直接用,仅作为参考。( c K1 X3 V6 Z' L5 z5 N J2 K
修改自己的led程序:
. r# r+ E( q6 z1 _) Q! f3 t0 K( N1 uC:6 G8 `. E( p# e7 d
- void led_init(void)
4 R/ K. d4 E) U7 z- l ]8 \$ N - {4 ]9 S% c8 s: {1 d# v
- GPIO_InitTypeDef gpio_init_struct;% d% a! I5 Z" A2 Z" _1 g" f) I2 `
- LED0_GPIO_CLK_ENABLE(); /* LED0时钟使能 */' m1 A4 Q4 m( Z) @7 r* r
o( C/ U. v6 w1 @/ n- [" x# y# F% k0 W8 o9 Q5 ?
- gpio_init_struct.Pin = LED0_GPIO_PIN; /* LED0引脚 */( s1 l2 L6 c# E Y
- gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */9 X" u& ~) L- `0 {# S) e: e
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */# F6 S* P: ]$ t. Q
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */
' F% N; e/ c9 N5 {, p7 g# W - HAL_GPIO_Init(LED0_GPIO_PORT, &gpio_init_struct); /* 初始化LED0引脚 */
, g" F) w. ]+ r4 s" w
4 G$ t7 l @) G0 A& z0 K; w% X/ i
+ S: `5 I m$ j1 X- LED0(0); /* 关闭 LED0 */ }3 ?8 w/ F: j( `; x# I0 ]! i, t' P v9 f
% j+ O# O. o) q5 ]0 |/ l" ~. G' Z- }
复制代码 H:: i. w I* f% { Z: F
- #define LED0_GPIO_PORT GPIOE
, M9 Z8 \) ?, p8 n) u8 | - #define LED0_GPIO_PIN GPIO_PIN_12) ~/ M$ }; y' A% L% L
- #define LED0_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE口时钟使能 */" g6 H6 D& J2 u" [2 i, S6 p
4 N$ f. K2 l3 ? l1 U5 ]- /******************************************************************************************/7 O- ^1 F8 K' b4 r. s
9 ~! B. E/ }) {8 i- 9 X" P: U" X, n' T3 _' g9 ?( |$ c0 n
- /* LED端口定义 */ O; ]: g% Z5 @$ C) _0 G/ q! q( Y$ A
- #define LED0(x) do{ x ? \( ]( D& U# n& C# ]1 a! U8 [' e0 P2 F
- HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_SET) : \
& S& o4 Q4 {6 A( t' [/ L - HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_RESET); \ t* E5 g' K, l% @+ X. o& ]% N/ a0 M
- }while(0) /* LED0 = RED */; x7 n3 w% ?$ f0 U
- 0 S! B; r) s! B$ Y) x k
- /* LED取反定义 */
, {" }$ g# _/ _9 D* Q - #define LED0_TOGGLE() do{ HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); }while(0) /* LED0 = !LED0 */7 K8 Y( F- ^! B& p1 @0 C c6 y
- % D$ {0 d+ L0 C7 r- z
2 Q; Q& {" ?; T% l$ [- #define LED0_STATION HAL_GPIO_ReadPin(LED0_GPIO_PORT, LED0_GPIO_PIN)
9 P4 @8 Y4 s1 S& B+ L2 Z" D# A Z
8 e3 K* I% g5 D8 U5 F4 H6 @- void led_init(void); /* 初始化 */
复制代码 UART4.C
7 ]0 N& { w) i# y6 c! E主要处理都在接收回传函数里面,此接收函数一直参考正点原子。
5 V* z# W' S$ Z- * 接收缓冲, 最大USART_REC_LEN个字节. */) m8 x5 V8 m/ g2 l' m4 F
- uint8_t g_usart_rx_buf[USART_REC_LEN];6 N5 @/ h$ {: u2 ?/ g1 ]9 M: O5 G. `( N
" s' \9 X, E: {9 L' M- /* 接收状态: s: N1 O+ a" i m7 O
- * bit15, 接收完成标志5 S% s1 p- b! ^1 d" Z6 g
- * bit14, 接收到0x0d
$ b7 S4 e( u& z, l; r - * bit13~0, 接收到的有效字节数目
0 i3 }, F, z4 R5 a6 {3 T - */
/ `) A$ N6 Y3 u3 l - uint16_t g_usart_rx_sta = 0;
z% j- H: V7 `* ^6 C
5 A7 d0 \) d6 S8 x, U0 ^( F) E- uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL库使用的串口接收缓冲 */
& n6 o( J5 x* j7 G8 P - 0 Y8 d5 i) B1 \+ j
- UART_HandleTypeDef g_uart4_handle; /* UART句柄 */
' J& s6 X( Y6 a) H - ) T% Y' d' b6 Z$ p% _* w
8 B/ |/ ]" k }- /**
: ~( H1 A% J" @: h9 P - * @brief 串口X初始化函数
( p( @' h1 `6 m! F- w! r - * @param baudrate: 波特率, 根据自己需要设置波特率值
3 n. R( q) C$ ]* r8 v - * @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
, Z! _. m" {3 Y) t# ~1 Z% w+ G - * 这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了." k5 @; x- X, U: L3 \) n8 B
- * @retval 无, P6 x( c/ h, N* U) I$ e5 M# W
- */! p1 g Y' g$ H! ?
- void usart_init(uint32_t baudrate)9 f1 ]) A1 M/ G3 m1 M- Y
- {0 ^$ l' Y; H2 n/ S6 W! i. R: D% y
- g_uart4_handle.Instance = USART_UX; /* USART4 */
! I, K0 K- E) X - g_uart4_handle.Init.BaudRate = baudrate; /* 波特率 */
" i1 C ~4 l$ w3 n - g_uart4_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */5 f ~) |; x: M. j' `& _0 A1 c
- g_uart4_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */" B5 x& g' y$ l, l5 d
- g_uart4_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */
1 h- [2 t3 h4 J, Y2 S - g_uart4_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */9 S5 L1 M$ U; s+ z7 }" h
- g_uart4_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */: L; s# L2 B# p& j
- HAL_UART_Init(&g_uart4_handle); /* HAL_UART_Init()会使能UART4 */8 `& c( E7 r3 K& [$ a4 M$ r
-
! a% a; `9 z( M& Q; v6 {0 X7 W - /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */( N% Y7 f' a8 L/ q2 u1 W# y0 ]5 B# M- J
- HAL_UART_Receive_IT(&g_uart4_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);2 q0 Q1 ?! m0 X1 j& l$ R0 W/ ?
- }, ^! S: K1 j- p
+ K4 c, D3 H: C- /**
' z- A+ p' @$ t2 @- i - * @brief UART底层初始化函数7 y5 g8 A# }8 k6 U2 D- K8 G2 E# `
- * @param huart: UART句柄类型指针
8 O. ~6 [; \6 o& }# x1 A6 h - * @note 此函数会被HAL_UART_Init()调用
5 T* ~5 d6 m/ q& }8 o) e: q0 Z7 F" s - * 完成时钟使能,引脚配置,中断配置
# D N n% N) @- \9 B - * @retval 无
- a! c* L; [/ n- l5 m - */& l7 g0 J5 ^1 U. H) B8 \+ U
- void HAL_UART_MspInit(UART_HandleTypeDef *huart)+ |+ l3 j- Y. ]2 m, f0 I$ w4 |( x
- {
, c% L0 B$ F% S+ R) n - GPIO_InitTypeDef gpio_init_struct;/ f1 j- n6 }, \- n( Q* v6 M) f
- RCC_PeriphCLKInitTypeDef rcc_periphclk_init_struct;
" s8 f4 V8 W8 `1 ?4 J: P! v0 ~ -
& ^& f- K- k. K" M5 C - if(huart->Instance == UART4) /* 如果是串口4,进行串口4 MSP初始化 */
8 O, p- e2 q5 L4 A2 y - {/ X( p5 w2 `( \/ s: k5 W
- USART_UX_CLK_ENABLE(); /* USART4时钟使能 */% v6 K# P/ P3 H% f" u
- USART_TX_GPIO_CLK_ENABLE(); /* 发送引脚时钟使能 */6 k2 K* B8 i9 ^1 N% E {, v
- USART_RX_GPIO_CLK_ENABLE(); /* 接收引脚时钟使能 */
/ p+ |- F) f) y3 u6 D: W( { - 8 Y6 ~* l' B3 i- P
- gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* 指定TX引脚 */
3 R& X5 y: [. _$ ^% ~" T: L: a - gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
9 O# | u- ?8 u& y5 ?6 D - gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */; ?& n2 V4 ~3 h8 K
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */# T& o0 D8 g. A3 l" i3 D
- gpio_init_struct.Alternate = USART_TX_GPIO_AF; /* 复用为UART4 */
4 y! _9 [0 s3 Z& S - HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); /* 初始化发送引脚 */; o) N2 f4 \- u7 J: u. ~ \
2 S0 O$ s& y+ B2 B4 R& `$ n' L- gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* 指定RX引脚 */1 M W7 ~! z' B8 p
- gpio_init_struct.Alternate = USART_RX_GPIO_AF; /* 复用为UART4 */
* N7 u3 |1 G8 O3 ` - HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 初始化接收引脚 */
" g' ?* I6 r; e- v - $ Q8 B5 G+ K; d7 i* N
- /* 设置UART4时钟源=PLL4Q=74.25MHz */
9 x* |' y2 D. f: x2 k9 G - rcc_periphclk_init_struct.Uart24ClockSelection = RCC_UART24CLKSOURCE_PLL4;$ l6 P2 t6 I) S# q" b
- HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_struct);
& @6 Z4 o0 p. _ z - 0 k3 t; y R4 E: C
- #if USART_EN_RX8 [; _1 q6 w' J& F# A$ S- _, Q, R
- HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART4中断通道 */
g8 a! F, _ w% l9 l8 J) u; p - HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
& T& t# T0 X; a3 ^# d3 D - #endif* a" W6 T, o! f5 |0 A( |5 N* Y% O
- }
) E6 Q. q( A. c7 q2 O' @ - }: D [- V9 }( U1 B/ }% k6 N
- 3 ]% h! O$ Z" E( r! V
- /**: D3 K" G9 p' g/ ~- W$ ]
- * @brief Rx传输回调函数
4 Y p! E4 H! B/ b - * @param huart: UART4句柄类型指针# m& o: h" F' E% q% p0 B% L7 D" ?
- * @retval 无4 {( p5 `, [( U4 O+ M
- */
8 ?# Z) j7 g$ @! e# Y - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) ]2 y9 i9 [9 ]0 y6 J
- {6 W# N! y5 {9 z: U5 O! D. m; @
- if(huart->Instance == UART4) /* 如果是串口4 */7 _5 b J- ?/ D' R
- {' b; ~* V0 E' q
- if((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 */+ C) A( A6 A* h* K
- {: ]- B. S' q4 M" t) E" X0 u
- if(g_usart_rx_sta & 0x4000) /* 接收到了0x0d *// r& a) u- x1 G
- {
9 U8 `+ |6 Y+ S: K - if(g_rx_buffer[0] != 0x0a) : J5 R$ w3 ^ E9 t3 X
- {
; t2 {1 e) F% @* w/ P& K& V7 ~ - g_usart_rx_sta = 0; /* 接收错误,重新开始 */! u! A c5 I! a, G1 j. D; {0 V
- }
0 C* r1 C8 J# r - else * T2 `# y3 M: c8 @' y
- {
' X! ?' _! A0 F7 h# e - g_usart_rx_sta |= 0x8000; /* 接收完成了 */) _+ e* T3 X* k) a( V& y
- }
* g9 I% G* F7 I - }
6 ~% r# x& K4 S$ j+ I4 H8 W - else /* 还没收到0X0D */! v& I2 ^/ |( H* K* X
- {1 N4 \/ `! o" X' ^0 K0 c
- if(g_rx_buffer[0] == 0x0d)
" f- @8 s9 ]$ U - {4 e+ H4 ?$ a3 E4 H# O' {$ s
- g_usart_rx_sta |= 0x4000;
! s* A+ r2 Z8 r- R& [ - }2 {* ~# N; l1 g& _. \- [) B w- r
- else
0 a: c2 s7 J' `1 W7 L - {
* s7 g, d4 ~2 p# l - g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0] ;5 M$ A1 A8 \ r! s( g
- g_usart_rx_sta++;% X2 j" G) i! l3 ^$ [& q
- if(g_usart_rx_sta > (USART_REC_LEN - 1))6 {3 n5 @3 g9 W* ?) `
- {% N1 q; m+ N) E+ S( U1 o/ s' ^0 D
- g_usart_rx_sta = 0; /* 接收数据错误,重新开始接收 */" T& Y& Z2 [1 d$ w/ @7 C: M
- }
2 n0 M; R7 a$ Q* T( t( u - }: _0 o7 T9 P9 F* M- t! D
- }
$ f3 m1 d! |' \% h& h - }5 G {9 Y5 |5 r/ A" @
- }
5 q9 }" V& ^% e. k' T N9 u - }
) A3 o) v. G ^: [" N# d+ B4 r
* h2 y" ?( B' Q3 b* D5 J- /**
5 I8 [ J% V3 h1 S+ w" C6 U3 H - * @brief 串口4中断服务函数
7 |7 z# W) d& } - * @param 无
3 h W# P# d# R# g1 {" L% p6 S, z0 i0 ] - * @retval 无
# Z- R+ `3 m+ k! {( l) M - *// Z; u1 O) i ?+ C" c5 F( X
- void USART_UX_IRQHandler(void)
5 G+ Z9 f9 n3 N - { , Q+ W) z% Q U9 t8 h
- uint32_t timeout = 0;2 p8 k3 g. F9 }2 p
- uint32_t maxDelay = 0x1FFFF;, r" z3 @: U' ~8 v2 q
- ; z. m9 f* d# E* \0 p& w' J
- HAL_UART_IRQHandler(&g_uart4_handle); /* 调用HAL库中断处理公用函数 */0 @7 C) v1 X n8 |. z% R
- - d! L* m0 |, |% l: G. ]- f9 v
- timeout = 0;
$ F* g7 O& y4 j1 H C - while (HAL_UART_GetState(&g_uart4_handle) != HAL_UART_STATE_READY) /* 等待就绪 */
( {- m8 v5 l7 P: O c! } - {
$ O( c4 c$ A5 C4 d' F7 ^8 n - timeout++; /* 超时处理 *// ?& L: d) a( u) ]& M" v0 L d5 j9 q
- if(timeout > maxDelay)
4 S% x$ E+ Q6 [0 }) [- _$ b - {- M; V! ^, E/ K% f6 N( X/ [% ^
- break;, D8 \1 x% ]) ?1 Y* S
- }& f8 t' p2 {4 s9 M6 U8 ~
- }/ a3 Q: ^% w% T( f b
- ' M+ G$ s+ K% T5 \! R
- timeout=0;/ v9 ?5 E+ b5 ~% m2 T! Z1 `$ o# q
-
/ n0 U# {: \& `# r; H - /* 一次处理完成之后,重新开启中断并设置RxXferCount为1 */
% x6 s+ ?" Z/ M: N/ A - while (HAL_UART_Receive_IT(&g_uart4_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)
" E" _5 C: o! X( t! O8 F' U- z - {
0 R" f0 I8 i. C* r) ^5 W7 k, S, n, J - timeout++; /* 超时处理 */
/ d0 x! \& R6 B& P5 n - if (timeout > maxDelay)
% [5 Z' T2 S+ U1 E - {( D* q, i- ~, p& s7 ?* [# X
- break;
+ Y- ^7 S; Y$ h* s* V- S - }; a x; h' B. D: y0 S
- }( s6 `0 y7 F: q$ Z( e
- % I8 @. g6 |; g% }' {
- }
复制代码 main函数调用:
8 W) o9 ~& ?' P7 n- if (g_usart_rx_sta & 0x8000) /* 接收到了数据 */$ t; t) g# {+ z7 T% P* R: @4 z
- {
5 ]! ^: C, F- u; J - len = g_usart_rx_sta & 0x3fff; /* 得到此次接收到的数据长度 */
# r `% i* T4 E. t$ k, c# O2 s9 a - printf("\r\nYou send message is: \r\n");! \5 ?! M! B) J! ^& L4 p
- for (t = 0; t < len; t++)
$ E6 p( G- S9 b! Z - {& P" ?9 E8 C' u; \# X
- USART_UX->TDR = g_usart_rx_buf[t];0 z; C7 H5 J0 d( f4 _1 h! |
- while ((USART_UX->ISR & 0X40) == 0); /* 等待发送结束 */- e6 p! j( U N
- }" K( d7 P5 ?6 D! R9 ~2 ~4 s$ s' _7 L
- printf("\r\n\r\n"); /* 插入换行 */; Z$ R& y1 m/ }+ g. m. Y$ N
- g_usart_rx_sta = 0;
. p' S1 A/ ^! e" A5 } - }
0 q! U! @( o. p+ E, } ?& X - else# l4 E9 X' u: {: U
- {7 w* [2 Q; g! n, \- B1 u9 M2 f/ L
- times++;- d1 }9 k/ c( S1 Q9 S' K& B/ H
- if (times % 5000 == 0)( n% @% \/ H+ K9 ]
- {& m% v' r, a0 I7 W# c) {0 x
- printf("\r\nSTM32MP1_DK1 UART4 TEST!\r\n");8 K! v* s9 a4 q; b3 P% _) ]) \! y. K
- printf("JasonQiu@ST community \r\n\r\n\r\n");4 {" t, {! t) N4 ]- _# h
- }
+ F! x. w( H. c, q - if (times % 200 == 0) printf("Please putchar!\r\n");
/ E' k/ N) u# B4 a: }8 L* L - if (times % 30 == 0) " Q. Y- N! m/ @& B+ {+ N8 H! w
- {* U) L) n# n4 ^) m
- LED0_TOGGLE(); Y4 I. D# I9 a7 Y/ E: W
- printf("The led station is %d \r\n\r\n\r\n",LED0_STATION);: o: m0 ]* T- ~' @4 b
- }
/ I- H0 ^" R% Z# ^ k+ E; r6 r: E) W - delay(10);
% T0 C: H4 Z* P' ?5 y. R7 ~ - }
复制代码 编译无误后,此时我们需要修改MCU的BOOT MODE :
5 r# J1 K# K, @% A. k' l+ `我们选择从内部RAM启动的模式:
# W/ T3 E) r9 J% e" w
2 ~6 H, k/ C2 y+ G% A
3 h& e0 Q5 u/ ` y6 |! d$ N8 Z2 ` N/ X# b, [8 d. |' }
MDK中,有几次配置要注意:
, V& A; Y; E$ A+ t8 R' h! M: L& Z2 Q9 c+ S6 v) A( L( X0 S
& _3 I. F. |- w) o( E; \
1 B6 L* f" K2 _7 ]0 Z6 O* s
0 `) g* W2 I+ Z/ X; a
- {6 E8 |0 z* p
3 ?# K& R% Y% B下载后直接运行,看下输出的状态:
7 q, v& P y8 A; K( G5 s) ]
7 ?2 Y( `' L6 r
板子LED状态:
0 o! j) a& j' p: `; O, A% B
& {* L1 O5 T" Z8 `好了,M4核的裸机开发就到这了。2 A% ]7 X. G6 Y! s- X
|