拿到了nucleo-U385开发板,在KEIL环境下编程,需要下载CubeU3支持包,在ST官网即可下载,并且在CubeU3支持包内还有KEIL环境所需要的pack安装包,这个应该是最近才做的一个方便开发者开发的一个机制:; H& D R& n0 |. p# i, ?& \& P- W
! k9 Z! y Z, r/ l我直接用点灯的例程来改串口例程,方便省事:
8 ^" }/ S6 `! i9 V P) r: [* L
7 h$ p4 b8 _# w" a" a( _2 D; I整理好的例程结构如下:
8 q* w! {4 Y; ]6 I2 M" T2 i
" r" O4 x: |, U$ w/ C% c( N% o) i% w
根据原理图可以得知,开发板的STLINKV3 VCP连接的串口是UART1,即PA9 PA10,可以直接与电脑的串口助手进行通信,另外开发板上还有PA2 PA3引脚,这个引脚被复用为LPUART1:
- M: \9 S9 y" ~- l& k$ H/ n3 Q
, A. K1 q" B1 n, m5 X! W- I我这个帖子就实现UART1和LPUART1的双通道串口通信,其中把LPUART1的接收功能打开,使用空闲中断和DMA进行接收,先看看UART1的初始化代码:- <font face="微软雅黑" size="5">UART_HandleTypeDef huart1;
% p' x3 d* h/ o* b B5 K+ g/ R
I8 s, e* m+ J- ?- ^- int fputc(int ch , FILE *f)! u4 R- _1 B+ o5 V3 a* }8 [0 P1 L5 f
- {2 k9 I; G e( f+ x1 Q
- while ((USART1->ISR & 0X40) == 0);
# G/ n7 ~5 S L5 P3 d# D - USART1->TDR = (uint8_t)ch;
, ]5 H; j0 ~' |+ \% q - return ch;5 Y, A2 @7 H+ A, i1 g0 p3 x: r
- }* K d2 q. t6 W c
% g8 \- m2 E! j0 z' }7 I- void UART1_Init(uint32_t baud)# P; f( ]% M: z' T. j
- {
) ?& G' f$ m8 c - GPIO_InitTypeDef GPIO_InitStruct = {0};4 G. e( q3 i1 K+ r" q: j* O7 z" g
- RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
" z1 P" \6 A% Y7 h+ L/ [+ K - 5 O5 A/ f) l' F% {& D
- __HAL_RCC_USART1_CLK_ENABLE();
3 z7 R+ [- E$ O - __HAL_RCC_GPIOA_CLK_ENABLE();
B9 `& i d7 @! z
; d0 b. f, ~% n, v' j; H. i- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
3 R* M1 I, a1 g - PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
2 S1 }+ N5 d# N) M - HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);9 o- L; i3 V7 I. g: ?& h
- W' a; m% d( X. ]; y: Q- GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;, E- H# o' w! |0 j
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
! K- b B7 h) I/ n. `' q4 F& o( |7 m - GPIO_InitStruct.Pull = GPIO_PULLUP;% f) _. Z6 |/ J& B, B8 a8 ]
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ l g) T( x4 Q1 w6 E3 a# d - GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
6 p; q- h3 h! |7 X( D+ C( E0 ] - HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);) \' G: S1 C- o6 H& L( [! z
- </font> <font face="微软雅黑" size="5">
( S5 e2 q1 h, C( ? - huart1.Instance = USART1;- [+ U) O% e# ]
- huart1.Init.BaudRate = baud;
% Y# U# | r; ^3 D - huart1.Init.WordLength = UART_WORDLENGTH_8B;
: W. ]6 H3 f1 q$ s% W# x - huart1.Init.StopBits = UART_STOPBITS_1;
4 ]$ M6 a) i8 y! D* c+ Z - huart1.Init.Parity = UART_PARITY_NONE;) X! f. `( g9 R h+ S# g
- huart1.Init.Mode = UART_MODE_TX_RX;
" n& {" r& S* ]3 S, s - huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;6 ^5 ^3 ^2 T1 Q" V& [2 D x
- huart1.Init.OverSampling = UART_OVERSAMPLING_16;0 E9 B9 f) L1 L
- huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;$ ?" m" n u# I9 C1 L/ _
- huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;1 F, r4 _; p& G8 o4 ^1 B
- huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;% u" _8 x/ r) J$ }
- HAL_UART_Init(&huart1);
1 h$ C. b6 d3 R% H- ~0 a - }</font>
复制代码 非常简单,只要熟悉STM32编程的没有一点难度,然后是LPUART1:
1 {1 m( j/ w# P0 h y o- <font face="微软雅黑" size="5">UART_HandleTypeDef hlpuart1;" o2 G9 i& [$ @; l% _: ^
- * o3 `* m1 d! @0 Z- A- j
- DMA_NodeTypeDef Node_GPDMA1_Channel0;
1 D1 ~ N0 N: g! e4 t R - DMA_QListTypeDef List_GPDMA1_Channel0;$ L+ _" H; H- v$ O: }
- DMA_HandleTypeDef handle_GPDMA1_Channel0;
! {. |6 K9 g/ F6 ]
: m. A3 Z3 @8 S- x \; B3 E, c# s- void LPUART1_Init(uint32_t baud)( i/ ?& m1 j/ h; T! ]4 N, j
- {% B+ c5 Q- |- j1 `7 G2 Y
- GPIO_InitTypeDef GPIO_InitStruct = {0};
1 A9 i( c" }/ I! \ - RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
7 f9 e* W- S2 J( K% T5 ^( y8 V - DMA_NodeConfTypeDef NodeConfig;
8 S& n5 l! P( F - $ P, M% @' @, e# Y
- __HAL_RCC_LPUART1_CLK_ENABLE();% V- a# F+ }( \- `, |
- __HAL_RCC_GPIOA_CLK_ENABLE();
2 V4 `1 z I% |' x/ D& F. f; } - __HAL_RCC_GPDMA1_CLK_ENABLE();
! C/ ]$ q$ Q5 C r
% k; B- i5 \$ l6 {8 m4 n& b# d( x- PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;- f. x0 T5 v. `! r# Q% p f) n
- PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK3;% S, k/ V8 K% g7 G
- HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
7 L- U9 t; N4 l" ?4 s( Z7 X, j - : A0 u* k4 Y; h; p! [0 x" n
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
) c8 {4 S( E: P8 ~ - GPIO_InitStruct.Pull = GPIO_PULLUP;
& D6 L4 t2 v! o# _1 a' K - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;) ?4 t0 S( t6 o# M: M
- </font> <font face="微软雅黑" size="5">' ?9 j g0 ]0 N3 q2 \
- GPIO_InitStruct.Alternate = GPIO_AF8_LPUART1;" _9 s9 x6 c9 ^8 H: O& o7 p
- GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3;& [4 o: Q# @3 W q2 ?
- HAL_GPIO_Init(GPIOA , &GPIO_InitStruct);4 S2 K/ o3 Q4 E% C4 T7 f/ i6 u
- </font> <font face="微软雅黑" size="5">! G0 q' k( h- e: Y' C3 \
- hlpuart1.Instance = LPUART1;
. l) r0 a3 v2 L6 H1 e - hlpuart1.Init.BaudRate = baud;
9 i4 X& b- Z2 e8 J% a - hlpuart1.Init.WordLength = UART_WORDLENGTH_8B;
3 J* W0 ^# `" b' A- u0 C - hlpuart1.Init.StopBits = UART_STOPBITS_1;
' c; \# Z( X* P% |' n; g - hlpuart1.Init.Parity = UART_PARITY_NONE;& ~" H" D9 ?7 R+ k( L: ~+ C
- hlpuart1.Init.Mode = UART_MODE_TX_RX;8 u& ^( Y& L0 q( B: e8 D! c
- hlpuart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;7 [$ j# p5 K$ `7 U0 L. G
- hlpuart1.Init.OverSampling = UART_OVERSAMPLING_16;
) x% V; ]" g: ] - hlpuart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;, A7 M6 K! W% W! P, e
- hlpuart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;/ O; B7 O( p5 B: M# N( Z# A. { K: A
- hlpuart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
3 T. G* B! Z% g2 z [5 n6 c: m6 I0 Q - HAL_UART_Init(&hlpuart1);
) J$ k" o4 Z3 u% ]4 w* E0 w - </font> <font face="微软雅黑" size="5">2 }6 w6 e+ t. j4 C/ L
- __HAL_UART_ENABLE_IT(&hlpuart1 , UART_IT_IDLE);$ J/ p7 f* a5 |8 }$ e
- HAL_NVIC_SetPriority(LPUART1_IRQn,1,1);7 @ ]3 Q- E# X4 Z# h+ l/ h) U
- HAL_NVIC_EnableIRQ(LPUART1_IRQn);
. N# e# q* U3 s3 X# f* U - </font> <font face="微软雅黑" size="5"> T! S3 \" w) C0 L
- NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
( k* ~9 `" C( w8 X V - NodeConfig.Init.Request = GPDMA1_REQUEST_LPUART1_RX;3 @. U6 G F; u. k
- NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;2 r6 h5 i+ Z( c6 }5 l7 ^
- NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;' S# R/ @" R! ~
- NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
3 s5 b; V4 u& C. U - NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;8 I! C& P/ O0 |+ s3 r- j
- NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
! T0 ~! T' |( u& ]/ f - NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
% J& k+ a9 Y# X3 K F# k4 B - NodeConfig.Init.SrcBurstLength = 1;
% r$ q! Z, X& b* f( W5 ] - NodeConfig.Init.DestBurstLength = 1;2 q5 v* |* B" f3 F5 M3 L+ V* C/ ?
- NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;& H. G% K( x6 u9 B4 a& ]! A; G
- NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;) Q+ h8 B" H D& r% f% i7 x, s' U
- NodeConfig.Init.Mode = DMA_NORMAL;
# U: V1 M, k4 `3 n2 T ]! { - NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;6 s! f8 ^* h2 _4 B
- NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
$ |+ o! G: ]+ e% {$ ^9 }/ \0 `) f - NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;) m9 w1 K$ J' _8 {0 q. V
- HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel0);$ B- U+ Z" X( y9 ~
- % G; Q+ K' C+ h" _/ A
- HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel0, NULL, &Node_GPDMA1_Channel0);
- x1 f$ Y6 v7 \- q0 K# d8 m0 A
# ~3 F7 J: R7 a1 n% X- HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel0);
, n% N |, s$ l! J6 b, O& q% z# i8 {
+ u! I. P" X1 s0 ~- Z7 L- handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
/ T. L5 t6 p8 O9 g/ }1 v" N- j - handle_GPDMA1_Channel0.InitLinkedList.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;" G2 X5 n# }; B
- handle_GPDMA1_Channel0.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
2 d* v1 e0 ^% v. v# s7 g - handle_GPDMA1_Channel0.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0; p- Z: S/ y; L- h
- handle_GPDMA1_Channel0.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;0 U7 f* H$ L2 a+ V: H! |8 Z% Y
- handle_GPDMA1_Channel0.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
3 A3 a' J% {4 H# X% Q: R - HAL_DMAEx_List_Init(&handle_GPDMA1_Channel0);+ V) w! G6 A* G+ C( [
- & Q/ ^6 B, b/ k* q* {5 V% S
- HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel0, &List_GPDMA1_Channel0);
( x$ Y j* M( o& b
% M, T. m. D' g) G8 M$ p( q- T- __HAL_LINKDMA(&hlpuart1, hdmarx, handle_GPDMA1_Channel0);
1 {# h2 i! v: Y M9 {$ g% f9 u8 ^
/ h( B. M4 }! G5 L o: H0 s6 o1 S" a) X- HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV);
$ \9 Z0 V- s: O - </font> <font face="微软雅黑" size="5">
6 ?5 J5 C+ C5 u! ^+ M - HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0);, l9 \0 f6 J2 d; f
- HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn);
7 g1 w- U6 r- V - }
% }" t' H1 k% p K - 0 T+ ^! D# E+ E1 H+ O8 ^: x! ^
- void LPUART1_Send_Char(uint8_t ch): N S; ]9 B% L) x) p9 S; Y7 G
- {( j# ]- T# w1 j6 M! K; y
- while ((LPUART1->ISR & 0X40) == 0);4 b( p8 E" r/ d
- LPUART1->TDR = (uint8_t)ch;
) P* U! p) Q: R5 Y6 l: \ - }8 D! e* \4 e3 v, `" z
- ! C2 Y: Y* `9 D, ?9 H9 p# I4 B# a8 ~
- void LPUART1_Send_String(uint8_t * s)% o" r6 Y, |. @- v; z
- {* ?1 F# }2 K! \! u0 i
- uint32_t i;- T- \0 ?% F$ v0 C; Z# L
- for(i = 0 ; s != '\0' ; i++)9 C: I5 P4 h( G7 Y# J8 }
- LPUART1_Send_Char(s);
3 @* _: p8 }+ K1 [5 j - }
6 d% E: o1 O3 ]; j - 7 i4 ]( g* j0 k$ q; }6 B8 o: `" v9 U
- void GPDMA1_Channel0_IRQHandler(void)
; G8 w6 b5 _6 a! k8 @( W - {: ^: O. o' J4 O# `3 B
- HAL_DMA_IRQHandler(&handle_GPDMA1_Channel0);
! c. d c/ H2 E8 ?+ Q# }% u E( |1 X - }: p5 Q* w$ | k; Z
$ {0 p' M* R0 o" ~ Z) K- uint8_t aRxBuffer[RXBUFFERSIZE];
( M8 |; P0 R0 `( x+ }1 J
8 D( H3 Q1 F% _* i; w- void LPUART1_IRQHandler(void) ; E; d' @3 X- c8 u
- {! x# _' x% n$ }
- // int temp;+ f4 W) U- `! |* G0 \
- if(LPUART1->ISR & UART_FLAG_IDLE), _; v) o( ~5 R: v3 y$ L: P9 i
- {% G/ h8 H2 ]$ `& t0 p. X' w" z
- __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);; y! @0 C9 ]+ w7 i' K5 w, {
- printf("LPUART1_IRQHandler. %d %s\n" , GPDMA1_Channel0->CBR1 , aRxBuffer);0 r) Q# H2 f9 D# u
- </font> <font face="微软雅黑" size="5">
6 W5 w# d9 _$ M5 J7 | - HAL_UART_DMAStop(&hlpuart1);
9 S. O J3 x! Y3 F4 U/ o" Y+ t - HAL_UART_Receive_DMA(&hlpuart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE);
' A w! T1 Z4 _2 `& O' b. c - // rx1_len = BUFFERSIZE - DMA1_Channel5->CNDTR;
8 t- w: d# T" K0 u7 n0 Z5 x - // uart1_recv_end_flag = 1;
3 v$ n* \( i4 ~: y- B' z - }% e* K/ R7 `2 x4 ?$ N1 x1 J
- }</font>
复制代码 在ST的新系列里面,有个特殊机制,使用任何形式的DMA通信必须要打开DMA中断,这个在F103系列是不需要的,是F4以及之后的大部分系列都需要,另外,在F4之后的系列中,对于外设要用的DMA,可以自由配置通道Channel(流Stream/节点Node)等,其实是一个东西,就是DMA通道的意思,不同系列的名称不同,只有F103和F4系列的特定外设是绑定在特定DMA通道的。像本帖子,就把LPUART1的RX功能设置在在GPDMA的通道0(后续还把SPI1的TX功能设置在GPDMA的通道1)。" q( t6 I" m0 T! t/ j, k$ K
3 w1 ^3 o; f% | t6 G
5 i' j5 W! u H$ p @% i
- e5 s A5 X# O$ b; M( C看看运行效果,使用两根typec线分别连接开发板的STLINKV3接口以及用一个USB转TTL模块接在PA2 PA3引脚上:
}) l- p- o; L5 w8 d
8 x) y {; h. O/ x. u首先上电之后UART1和LPUART1都会打印信息,然后,对LPUART1发送数据,UART1会打印接收到的数据以及接收长度(100-DTR寄存器值)。 |