通过上篇文章对STM32MP1双核机制的分析。我们知道M4内核的程序,不能够下载到FLASH当中。那怎么调试M4的程序呢。下面我们就开始讲一讲。8 O8 Y# s1 J& o+ O) F
STM32MP1跟普通M4核MCU开发没有太大的区别,一样调用HAL库,一样可以通过CUBEMX工具生成+ ]9 h* k+ M" @: }
初始化代码。当然在能控制的外设方面比真正的M4单片机要少一些,上文已描述过。我们在这里就不多说了。
, H+ x7 t5 w* c; i( S我们打开CUBEMX工具,选择对应型号,配置工程:6 W/ W9 U' B6 Y
我们想控制板上一颗LED,并且串口能够收发数据。
; o/ `7 {2 o( b) u9 P+ z7 j8 W% u5 aLED引脚电路位置:
+ P, w7 h. L+ p( \
: r: K6 F8 u; q n
与STLINK相连的调试串口UART4电路位置:, r- X$ n( A0 Y& J5 R
, M- Z2 r0 I6 P+ `7 H
; m: k5 p* w- `; S. d" l' q6 [( {
8 [4 \. K3 i+ W) c) n% ~
, O5 t4 c. j" ~; H+ H% Z; R% U/ KCUBEMX配置:
2 }% p6 ?9 x" h3 w
4 D( @6 F+ T! ~4 d' l* L( L
C0 E: s+ N' K3 F, T( \& C
. ^ M9 |! M; x" W% l4 i7 r
配置时钟:
' X1 ^! K6 l& N7 Y# p' } c' ?
4 l) n9 S2 @7 ]/ N
3 m4 V/ u( L7 }$ |4 h+ k0 @$ V
) s! B7 L0 P" d! h; G工程配置时,选择让每一个外设生成独立文件:
% O/ H2 F7 r/ p& k" g
1 o; i/ x& @. R- b: \4 X
然后生成代码,我们这里没有官方的STM32CUBEIDE开发,用MDK。' N) I. }. G& e- K7 Z" D1 Y6 L$ G
生成的代码,我们不直接用,仅作为参考。- n( ?. H& O- v: d7 Q
修改自己的led程序:; w; w& h( h9 V" q9 D5 r+ r- W2 Q
C:8 Q! i( J& a3 W1 C3 E' @3 E
- void led_init(void)
% s, S# A8 b8 `0 d; S6 M5 m - {
: ]9 Q7 ^' w6 z4 S" B+ S - GPIO_InitTypeDef gpio_init_struct;
1 O8 J. p& k/ W - LED0_GPIO_CLK_ENABLE(); /* LED0时钟使能 */3 A4 [- u5 P" q: `1 v
! i/ \4 t8 M0 }) F- a- & G; B2 h- H8 R) w- ]
- gpio_init_struct.Pin = LED0_GPIO_PIN; /* LED0引脚 */1 m: c. M- Q1 c$ g" P
- gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */& a X" o& ^) w: _, D2 T, ]
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */9 G0 S& F% L: \: X
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */9 U+ d+ m! Y% L+ G
- HAL_GPIO_Init(LED0_GPIO_PORT, &gpio_init_struct); /* 初始化LED0引脚 */' v2 M1 f9 K ]! j! {( K( Y7 N
- 3 m' c9 i+ c( @1 m4 P9 b2 S- I- m
- 6 u# I# C3 d D7 b" `) F8 |" S
- LED0(0); /* 关闭 LED0 */
& p$ v4 s& V5 b/ ~9 z - ; C8 C3 ^3 e1 q( y' q' j6 e z; k
- }
复制代码 H:
( n; {3 N4 _* d" J8 V! q8 @/ g- #define LED0_GPIO_PORT GPIOE4 O' S1 b6 v5 x
- #define LED0_GPIO_PIN GPIO_PIN_12& b8 S6 b" i; W J8 ?" i
- #define LED0_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOE_CLK_ENABLE(); }while(0) /* PE口时钟使能 */
g1 E7 q: K9 F, ~ @+ _0 R! X/ Q
' z7 q' p9 n8 r) D- /******************************************************************************************/$ V# Z0 U* z6 T y) z G
- 3 P; C+ v$ ^" E1 Z: t8 j
# u5 v7 ?# {6 i$ ~7 C- /* LED端口定义 */
- d4 \5 h- ^4 | - #define LED0(x) do{ x ? \2 B0 f; V- h1 K( C7 Z
- HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_SET) : \
8 Q7 r a! @5 I: q/ ^1 R% y - HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_RESET); \
- Z" D0 o! g5 y `8 Y; p - }while(0) /* LED0 = RED */
; y- q; ^( z* F - H. Q/ ]4 q/ B% y& }* t
- /* LED取反定义 */
0 ?3 N& ], q( ]0 L% C9 a& R - #define LED0_TOGGLE() do{ HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); }while(0) /* LED0 = !LED0 */
+ Z2 k7 u" F, G3 d K% J2 X$ r- d. U
$ r- r {9 x7 L e" \
) Z$ N' X! j& W4 _% I- #define LED0_STATION HAL_GPIO_ReadPin(LED0_GPIO_PORT, LED0_GPIO_PIN) & v/ ?8 @7 Q9 t; [
- `+ j- t3 x6 C7 A, O- ]; M2 r6 R
- void led_init(void); /* 初始化 */
复制代码 UART4.C
6 o+ D. v( o; _% _主要处理都在接收回传函数里面,此接收函数一直参考正点原子。
$ C: w) ]& W+ t3 Y- D1 [& \( H: g- * 接收缓冲, 最大USART_REC_LEN个字节. */
( D" H+ s9 y1 X& u% ? K - uint8_t g_usart_rx_buf[USART_REC_LEN];
) ?; L v2 T1 d5 T5 u& w0 s - ( a0 E( v& E/ C% [" @# L% \
- /* 接收状态4 H+ {7 Q( L) ^5 H6 C$ T9 \
- * bit15, 接收完成标志3 i Z$ V( P. E; S: h) z
- * bit14, 接收到0x0d
8 [, |7 i: ^0 p/ H) F - * bit13~0, 接收到的有效字节数目8 ^3 f3 o6 ~+ e# e& d, l: w; @
- */# O' K9 P8 U$ x; Q6 g: _( c
- uint16_t g_usart_rx_sta = 0;
. B; ^ G8 T; [* f' M+ N0 _5 T - D3 L3 [; R% \! s: H. E
- uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL库使用的串口接收缓冲 */4 Y {: ?( I0 n! r, W( A
- * |3 B$ x# |7 o7 M0 R! J% ~
- UART_HandleTypeDef g_uart4_handle; /* UART句柄 */3 U( Z6 } R) T" J' i
- % P. V! w( M! \8 M
- + o% _) R4 N+ J9 ^& A, g% w* \
- /**
' C) l. V; z% j+ \7 J - * @brief 串口X初始化函数
2 M" f6 u6 a, X" f2 y - * @param baudrate: 波特率, 根据自己需要设置波特率值/ {( [' c, I1 Q: U' B; p( }
- * @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.6 b5 Q& Z- }* T, L
- * 这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.
- U9 f$ A) B4 B- s0 X9 R/ f& K3 k - * @retval 无7 y$ E6 D# Y6 z) W0 K
- */
/ E. Y+ ^* x# K" N* s' }5 w - void usart_init(uint32_t baudrate)# p+ K5 n' A* H/ E
- {5 D6 h6 y1 S6 {
- g_uart4_handle.Instance = USART_UX; /* USART4 */
( h: D+ h& I* X* Z - g_uart4_handle.Init.BaudRate = baudrate; /* 波特率 */
$ T1 {" e3 _; [( M5 Y& N! A- ? - g_uart4_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */. F2 ]2 b7 V. f1 z8 R) R6 `
- g_uart4_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */* c& x/ P5 \) u
- g_uart4_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */1 H! l& @' m1 G1 T
- g_uart4_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
- l; e. @/ m9 V! L; |- I- ?5 U6 A* f - g_uart4_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
7 D# Z6 t* z8 {7 C( c - HAL_UART_Init(&g_uart4_handle); /* HAL_UART_Init()会使能UART4 */
) p8 x# C' O% |, b -
' a! x, u% e5 y' U- ?) z; b - /* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
4 w- T- H. K/ n- c - HAL_UART_Receive_IT(&g_uart4_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
( q4 P) O! E! n% k N( R8 s& X; m - }$ I& ^1 H3 V9 T$ }( [
3 a3 u3 P1 o- J- m# l7 q$ |- /**6 @: G( @2 I$ x" }
- * @brief UART底层初始化函数
" Y! p1 ~7 u4 g% J4 v! R - * @param huart: UART句柄类型指针
: y; S* E0 \2 E - * @note 此函数会被HAL_UART_Init()调用6 \" r) r: w5 f# k+ ~% u$ q
- * 完成时钟使能,引脚配置,中断配置
% A0 E1 J& p8 F$ ?- y - * @retval 无
1 H b2 g' ^8 @0 n' R - */' O2 V( f; ?% e! t& G5 h
- void HAL_UART_MspInit(UART_HandleTypeDef *huart)0 R5 ]" \8 E7 j
- {. [: u* J# v# a) @/ z& S7 h
- GPIO_InitTypeDef gpio_init_struct;
% i2 p* b. O2 ^* l - RCC_PeriphCLKInitTypeDef rcc_periphclk_init_struct;7 M6 l" L7 ~% o# m1 k7 S* B
-
/ t5 y/ n+ D6 T7 t" }7 _ Q' T - if(huart->Instance == UART4) /* 如果是串口4,进行串口4 MSP初始化 */$ h1 S/ V' S6 a/ g+ z7 M- h
- {- _1 e7 E8 }4 o: @4 V) w" g0 \
- USART_UX_CLK_ENABLE(); /* USART4时钟使能 */0 W3 Q$ {: s) t8 ^1 K
- USART_TX_GPIO_CLK_ENABLE(); /* 发送引脚时钟使能 */
( X0 D- n! A6 a1 v - USART_RX_GPIO_CLK_ENABLE(); /* 接收引脚时钟使能 */
" f Z# V! x% ?+ A - @9 `5 ]2 C4 R
- gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* 指定TX引脚 */
' G+ {" P0 J- B! K7 y - gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */) D, P' A) U4 t4 W: [- E* p
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
( P' T3 F$ F) H3 a. \- @ - gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
- N3 F3 f5 ]" Q - gpio_init_struct.Alternate = USART_TX_GPIO_AF; /* 复用为UART4 */* _4 Z% S* Q& ~; G6 p- D8 E
- HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); /* 初始化发送引脚 */
1 a1 ^9 `0 _. v/ H; x, Z
! [& a% o) p9 L- r0 \- gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* 指定RX引脚 */% K0 i) Q6 U' G' Q- w7 y3 |2 b
- gpio_init_struct.Alternate = USART_RX_GPIO_AF; /* 复用为UART4 *// f+ j& R" l# q% s8 L& D
- HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 初始化接收引脚 */
- D5 n/ X& | T/ N+ m - 7 G8 y4 J8 [& x1 P5 n4 A7 \ P
- /* 设置UART4时钟源=PLL4Q=74.25MHz */% j6 R/ v! } v8 Q) [
- rcc_periphclk_init_struct.Uart24ClockSelection = RCC_UART24CLKSOURCE_PLL4;
, U* H+ S4 c- ` - HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_struct);
8 T& Z. a2 W2 f! s4 G% y
7 U5 H& v) H' M. k1 Z2 h3 ]5 S- #if USART_EN_RX
2 V: }. @4 V( r1 }6 C - HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART4中断通道 */! K3 y8 e8 z& J+ r) E Y2 E+ a
- HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */, V3 e* V. h* c" {7 p
- #endif( P, u; Q" C& F& k7 T
- }4 b4 Q1 m7 Y2 L& A: j7 M
- }; [0 l. T7 d3 f& E2 t8 x
4 |3 J5 k2 l$ s p9 Z- /**
% V( P5 O& T$ @! {8 R - * @brief Rx传输回调函数! X- U3 o+ Y% _& X
- * @param huart: UART4句柄类型指针
2 ^* x9 [' W& \4 M- N: e& @ - * @retval 无
7 \% R3 c4 E6 x - */! K2 i1 ~' w" ^8 L6 l1 W$ r7 q0 M
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
! ?' K. t+ d& Z" O7 x% V6 O( ` - {- C x7 g. J: x
- if(huart->Instance == UART4) /* 如果是串口4 */& ?# }3 o3 l; b
- {8 L( Y; h/ O. ~1 }
- if((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 */5 }0 a8 x" W2 j* f- j
- {0 |/ `/ Q7 e% f t v5 `
- if(g_usart_rx_sta & 0x4000) /* 接收到了0x0d */
5 e( n, h- ~# S# K$ R p - {
" r: p! j* t2 j( w e( v( | - if(g_rx_buffer[0] != 0x0a)
1 n- J8 l: l. o, v I3 I' a - {/ ]! Z0 u0 A3 A9 }# O% Q- v6 [% s ]
- g_usart_rx_sta = 0; /* 接收错误,重新开始 */, G+ I8 t% x" N
- }3 }, F8 R; @6 F, ]
- else ' {1 q6 k& l$ \! B! @! R
- {% L* E8 G/ V; _* l
- g_usart_rx_sta |= 0x8000; /* 接收完成了 */
) D/ l O$ Z5 q# F - }
3 Y5 g* y7 e1 S8 |7 V - }5 q n* M9 A9 ]+ z. _. `
- else /* 还没收到0X0D */
& R. T4 k1 A- e' {" B7 V - {( ^) o$ `; @* X
- if(g_rx_buffer[0] == 0x0d)
4 Q) h$ R! A1 D+ E" X4 e' f" x - {# E4 e0 }, I& O0 V: Y( ^
- g_usart_rx_sta |= 0x4000;2 p" v5 l% ^: R9 j% \: ]$ M
- }
: @# J7 k6 K1 y - else+ Q3 P- X- n( X$ y8 G
- {2 S/ q2 Y0 G# x7 B
- g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0] ;
( N; C/ k1 b" l9 n$ J' J) I - g_usart_rx_sta++;( y6 m u8 G! b# i" r% ]
- if(g_usart_rx_sta > (USART_REC_LEN - 1)), @3 ?9 ]/ f1 P3 d0 o$ t
- {2 s# P- U$ m' }8 {, O; M* D
- g_usart_rx_sta = 0; /* 接收数据错误,重新开始接收 */" j" D* c& l/ A' M1 E2 N
- }
9 _: ~2 J" L; b - }3 I; W9 |0 @* D
- }, v" d! a9 a5 G1 @8 G$ b
- }+ c- a4 M, p" ?1 t: X
- }4 M7 A Y- r* G ?
- }
" \. T8 R2 C. u( B. u" t. m - % v5 A" H& K. V6 K( ?
- /**4 J& q7 \7 T" v8 N; G- A
- * @brief 串口4中断服务函数
8 W. P# V6 D& Y: E$ b4 Y: r' N - * @param 无' G: f0 Y) k- W# D( q
- * @retval 无; I( u. D/ E$ _+ w; t
- */
2 p+ [5 H! z2 `/ v9 Z. D - void USART_UX_IRQHandler(void)! N1 C6 z/ S/ ]9 V" ?5 g
- {
8 p- H+ D3 P: N w/ c, x - uint32_t timeout = 0;! `1 i" k5 ?+ L2 E# }# `
- uint32_t maxDelay = 0x1FFFF;, y) B5 m5 A& o- q+ I
- ; }% u( O3 W4 }% \9 B7 _
- HAL_UART_IRQHandler(&g_uart4_handle); /* 调用HAL库中断处理公用函数 */' x0 A- p! r6 d1 g" d8 a& L- C
" X, G1 I2 Z0 u- a" s; i- timeout = 0;- s7 t) A# k- ]: F' N; [; V* K
- while (HAL_UART_GetState(&g_uart4_handle) != HAL_UART_STATE_READY) /* 等待就绪 */
2 E0 C4 M8 { s; U - {. W3 F l/ b7 [6 \1 P
- timeout++; /* 超时处理 */
/ P! I( R* K8 L+ m s4 m- ^ - if(timeout > maxDelay). k( R/ X; e( B; f2 O2 v
- {/ k! ~7 u) E7 M, q
- break;
3 b- k: u* G$ f1 W9 M" S* V% G+ Y - }$ R; s! L1 {& t. K* O2 t
- }4 A, Z& K5 y( @* G
-
/ X" p# ^) @6 S1 D! L - timeout=0;. O- Q. p$ N7 r) f4 A2 {& [+ R) b% p5 c
- 2 \1 l% E, A# @, \5 @( F. Q* H
- /* 一次处理完成之后,重新开启中断并设置RxXferCount为1 */
. W# Y0 H7 v i0 }7 E" \ - while (HAL_UART_Receive_IT(&g_uart4_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE) != HAL_OK)+ d, D/ |$ ~2 K- u; R4 ~/ |3 S7 I4 w
- {0 {6 z% w5 K, g0 r: d! X& Y* ~ @
- timeout++; /* 超时处理 */
) V" S" M8 c' }+ m9 ~4 c. J$ _* s o - if (timeout > maxDelay)* I9 b e9 l- K. ^+ J! |2 m
- {* R" k8 z* t# B4 A7 f
- break;: J7 R1 s2 _$ z7 X
- }' z. n$ A5 ~ D8 w( p7 o0 J- \2 H
- }* d( T# e& F t( q, ]+ N
3 i* y( j1 ]& ~& W, O1 S- }
复制代码 main函数调用:# {7 F* ~$ k. [( q& D6 E/ ]
- if (g_usart_rx_sta & 0x8000) /* 接收到了数据 */. |/ D/ X4 V, ^
- {6 }- y; a7 _8 l4 ~
- len = g_usart_rx_sta & 0x3fff; /* 得到此次接收到的数据长度 */
8 ^! e e0 U1 C( M5 r - printf("\r\nYou send message is: \r\n");8 s0 v9 O/ n+ E8 v3 H+ r
- for (t = 0; t < len; t++)
7 V' o2 J+ |1 p( K - {
4 e5 B- u( d/ T$ w! N6 S3 p - USART_UX->TDR = g_usart_rx_buf[t];" r& d. Y( _, k; I, |& J# {7 d+ \6 x
- while ((USART_UX->ISR & 0X40) == 0); /* 等待发送结束 */, J* i# p8 w8 w7 I l: U8 r8 B
- }
$ g R5 @/ W( j* e' Y - printf("\r\n\r\n"); /* 插入换行 */% w) J+ h3 y) ], C9 x
- g_usart_rx_sta = 0;( o8 N, |& g4 r5 l! Z
- }3 T3 p& _1 P: W- j2 F1 d
- else; F; m- g5 Z8 y$ u) G
- {4 B; [9 f0 M( D' X- |
- times++;; T/ k3 Y9 L# _) U
- if (times % 5000 == 0)
0 Q* S( O- K6 c) A9 G9 z* f1 D - {1 N* O5 N' b9 t9 }- ?8 L' y
- printf("\r\nSTM32MP1_DK1 UART4 TEST!\r\n");+ [( ?* ]) b7 e0 l& v% R4 n. R
- printf("JasonQiu@ST community \r\n\r\n\r\n");
* o8 j1 S" l. R - }" f: M+ ]8 J- j
- if (times % 200 == 0) printf("Please putchar!\r\n");
# J6 |, I+ V7 @: o) A6 ^7 g9 x# o - if (times % 30 == 0) 7 o& Z: J, w* m4 [# v
- {
* e/ h" P8 {+ T' P0 V7 r - LED0_TOGGLE(); 8 A1 X2 \, F# U: _* E6 ~
- printf("The led station is %d \r\n\r\n\r\n",LED0_STATION);* _6 U% b9 k: m/ ~
- }3 C; m, z1 q6 a8 S
- delay(10);
7 U. C& B2 n9 o* J% w2 M# f - }
复制代码 编译无误后,此时我们需要修改MCU的BOOT MODE :# k" ]. J% [5 d1 d
我们选择从内部RAM启动的模式:. X3 G9 T, }$ a% X4 D
+ Y" a5 l5 z9 |9 _
0 _* I3 W: g- ?7 V: H8 ~( E0 m$ f% Z( j* q$ O3 \% f
MDK中,有几次配置要注意:
7 z3 A, J* }) B& P9 K* X Q
2 d; C G/ x" j R! d3 r: Q
/ g- o- u" r- u; e! j# w7 T! Y+ X
- d* K9 A5 h1 x6 N& ]1 D
# ]" I/ }. z J4 `5 y; G* n1 J1 w
: j3 h ~, m( G) u2 U- n2 t" {5 k2 Z) {# m8 i% Y7 P
下载后直接运行,看下输出的状态:& i( f, u; G- @, T/ U1 `* t
+ T' x. p: h1 [) R$ Z
板子LED状态:
7 k$ y+ d$ L1 N; ?( y
Q' k7 ]$ u4 Y2 ~好了,M4核的裸机开发就到这了。
* t! G; `+ N* D- B; D |