本帖最后由 power568 于 2019-4-16 16:07 编辑
2 K" w( {6 Y, [. H& T/ ]- y' i: v; }
最近在写一个串口通讯的程序,软件、硬件平台如下:3 K) \1 I R/ e; X( |4 }& s
硬件: STM32F429ZG
! P8 q3 y! o) ^+ Y7 \系统: FreeRtos、HAL库* T: v( g9 [- X
工具: Iar7.6
, x( {, T& D& l3 Z0 X
0 l# W9 t3 ~+ T9 v2 F. F 计划是利用串口DMA+IDLE空闲中断的方式接收数据,在中断内将接收到的数据通过队列的方式发送出去,在任务内部等待接收队列,串口中断配置及ISR如下:- HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);//// 中断配置,优先级大小不能乱配置+ ?& b5 ]+ z( D( _5 `$ M% v; L
- HAL_NVIC_EnableIRQ(USART1_IRQn);" u6 Q, p1 B+ P$ O
7 X$ D' s% I0 F& S- void USART1_IRQHandler(void); v, p9 }, p3 D1 ]! ?
- { h- @4 i- B- t5 e
- uint32_t flag=0;7 ?# Z) f0 b x) o/ W' Z& ?1 X
- BaseType_t pHigherPriorityTaskWoken = pdFALSE;* q3 E/ Y5 R! @6 j& T
-
8 d; `5 t& h4 Q! H$ i, j! [ - flag = __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE);
) c, ~4 L d( X - if((flag != RESET))& P! E8 i, i) i3 c" A `
- {8 f& Q' Q U% E7 F& b# C6 j
- __HAL_UART_CLEAR_IDLEFLAG(&huart1);6 N3 p/ Z' V+ f$ D/ E5 K2 X( _6 R+ j
- huart1.Instance->SR; ' c/ j- W! T$ ?. @0 |" D, s
- huart1.Instance->DR;* z7 n" j+ q; ~6 X6 C6 l$ g7 z4 C+ x
- 1 _4 c) f, B- m, e! J
- HAL_UART_DMAStop(&huart1);; [5 C( M ]8 x7 y' s" K
- xQueueSendFromISR(UrtK125RcvQueue, DrvUsartRcvBuf, &pHigherPriorityTaskWoken);
* Y7 o( l+ d& J$ N' E6 B3 ~ - portYIELD_FROM_ISR(pHigherPriorityTaskWoken);
* A& T: d1 ?- k- \ - }
- d% m9 j( ?0 H" N$ Z - }
复制代码 ' d- E1 I- k' i0 x
% k" o) q/ s, Z, Q$ g, }7 [: s //// 为什么代码提交后,代码对齐格式变了呢???* O1 |1 g$ i! ~ l# \: B$ n& W" L+ r
" j( y# V* y$ o- G3 D. f
调试发现进入中断后,程序卡在了函数xQueueSendFromISR(UrtK125RcvQueue, DrvUsartRcvBuf, &pHigherPriorityTaskWoken)内部configASSERT( ucCurrentPriority >= ucMaxSysCallPriority )处,具体为:
1 c ?. j' G! h1 N D' F0 ~- #if( configASSERT_DEFINED == 1 )
2 g0 d& r- ? ?9 M+ \3 B; P6 U6 D7 F - 4 J; J6 }" {% y
- void vPortValidateInterruptPriority( void )
$ J, z3 p$ N: f9 I* G+ a - {
2 f" w* T# s" h1 g9 g4 J; C - uint32_t ulCurrentInterrupt;
7 x2 l1 T7 H$ |6 T - uint8_t ucCurrentPriority;
( W5 U$ b/ _1 P) w# h7 y! e
0 q2 r: x8 i; `% [ Z- z- /* Obtain the number of the currently executing interrupt. */- [# c/ v8 X0 V& ] g7 o+ r
- __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) );, E2 a. z' |2 {+ W
- //// ulCurrentInterrupt 调试显示为537 e) O0 {, o/ e" j
- 3 D; W: U- m' i2 u
- /* Is the interrupt number a user defined interrupt? */
+ _/ n7 ?. l5 f. l7 U3 J - if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
- h5 K! n9 |" X' g U- z - {) }7 E* I8 n( ^. n
- /* Look up the interrupt's priority. */
! q& z4 |+ G' k' w, f1 C - ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
. A t, [0 d x/ ? - //// 当串口优先级设置小于5时,ucCurrentPriority的值小于0x50,导致下面的宏断
+ c) J7 Q' M, g" A! |$ k- F* v4 n4 @ - //// 言configASSERT条件值"==0",进而卡住
8 U' l' {4 A1 M$ { - //// 当串口优先级设置大于等于5时,ucCurrentPriority的值大于等于0x50,下面的 s$ y: d* k% @ U- g
- //// 宏configASSERT条件值"==1",所以不会卡住
; n7 z# _+ i1 a4 g7 G' S2 u
+ J) z: r: j- p0 q8 w6 B" g m+ ^9 b- /* The following assertion will fail if a service routine (ISR) for1 X) U9 i# i( i$ g L$ v. P7 s
- an interrupt that has been assigned a priority above
8 K3 I* N: \* q7 Y1 T) z( _+ o! O - configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
" V9 A8 t: z1 S* v: G* b# B: r - function. ISR safe FreeRTOS API functions must *only* be called& n4 M& n" {( o2 C$ N! t8 b" N
- from interrupts that have been assigned a priority at or below
. N5 c* e e: X4 s/ K- R, X - configMAX_SYSCALL_INTERRUPT_PRIORITY./ N7 L% t( b A/ `; O
- //// 如果一个调用FreeRtos安全ISR API接口的中断ISR优先级分配大于+ M) Q" u/ o- m% _
- //// configMAX_SYSCALL_INTERRUPT_PRIORITY(即中断优先级值小于
, y( B! ?9 A$ V% {/ G& ~ - //// configMAX_SYSCALL_INTERRUPT_PRIORITY,因为FreeRtos中值越小优先级越高),) K, R0 Y- n4 u- E e0 E
- //// 下面的断言就会失败。FreeRtos安全ISR API接口必须只能在优先级分配大于
8 t5 O( l& K. R; y0 l* K" \3 {; R - //// configMAX_SYSCALL_INTERRUPT_PRIORITY的中断ISR中调用& f P# \9 g% ^3 ?* Y
-
, P( n1 R! b' z: L - Numerically low interrupt priority numbers represent logically high
1 H8 w) G) n& k! _; a - interrupt priorities, therefore the priority of the interrupt must# r6 z$ Z5 g9 @' u/ w
- be set to a value equal to or numerically *higher* than# y" o7 r R" g8 Y& r# ~
- configMAX_SYSCALL_INTERRUPT_PRIORITY.
( V9 g2 k* }3 M( k! D$ ~2 u8 C - //// 数值小的中断优先级逻辑上具有高的中断有限权,因此设置时,中断的优先级! n# F9 m- [+ J8 j( s
- //// 值必须必configMAX_SYSCALL_INTERRUPT_PRIORITY大
, l4 p" m. Z9 m6 P: ]3 |" v
5 I, k/ x$ X7 T; k7 }$ g2 N# S- Interrupts that use the FreeRTOS API must not be left at their; `; c) a; l" R& B% t9 G8 {
- default priority of zero as that is the highest possible priority,
9 Y, }) Z! U) z; K, W3 C - which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,7 z- y: j6 D8 b# V
- and therefore also guaranteed to be invalid.3 ~, P: b0 t# G8 v# A1 w3 h' v7 H
- //// 使用FreeRTOS API的中断的优先级禁止使用其0的认值,因为此时中断优先级最) y3 M3 U- a% x, M. n" c
- //// 高,0值的优先级必然大于configMAX_SYSCALL_INTERRUPT_PRIORITY,因此也必0 e" O' J! \& F: ^; Q5 E$ W3 A
- //// 然无效, [& n2 ^5 q. v' u N% X2 p5 M5 l L
& z4 N2 F; \$ f8 B# e' K- FreeRTOS maintains separate thread and ISR API functions to ensure
& K/ X5 O) \7 e2 u - interrupt entry is as fast and simple as possible.3 ~5 P+ }% ~$ K# x, k: A. G3 U
- //// FreeRTOS为了确保中断入口尽可能的快和简单,因此分离了线程ISR API接口
! x, ]" R6 g) l& _ - 1 y" Q& }3 d, r, @+ y, x
- The following links provide detailed information:
% |" V: Q$ o$ d! I8 S J - http://www.freertos.org/RTOS-Cortex-M3-M4.html& N, Z N% i0 h& G
- http://www.freertos.org/FAQHelp.html */3 N- e8 q* A' Y7 g
- configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); //// 程序卡住位置+ b0 e4 I' P/ m c+ [1 i
- //// ucMaxSysCallPriority值为0x50
, Y H6 E% T2 w - }; }/ r" l6 C5 X; X
5 D6 S9 x# M/ x/ Y8 N7 S: S* R; R- /* Priority grouping: The interrupt controller (NVIC) allows the bits" i) w, o+ m1 `0 \) Q
- that define each interrupt's priority to be split between bits that4 w0 p# e p: f; s) }
- define the interrupt's pre-emption priority bits and bits that define
5 B4 p& T7 I+ a( D! S' N# n - the interrupt's sub-priority. For simplicity all bits must be defined
1 x, O$ P, ]+ i4 {3 a - to be pre-emption priority bits. The following assertion will fail if
+ ], Q z( J. W6 w z - this is not the case (if some bits represent a sub-priority).: j) j: t/ Q$ x" U% E
- ) o; l1 S3 P) _
- If the application only uses CMSIS libraries for interrupt/ B; R6 B# ^; w4 @5 Z8 _3 h
- configuration then the correct setting can be achieved on all Cortex-M& `& J1 I: k* M6 F
- devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the8 k$ R. P$ z2 L% i/ s5 y5 F8 |# U
- scheduler. Note however that some vendor specific peripheral libraries
6 ?! X* D6 g1 B' G: R, ]; V - assume a non-zero priority group setting, in which cases using a value
. j6 g$ Z7 [6 g - of zero will result in unpredicable behaviour. */
# b; n1 O1 f* o! D l8 e$ F - configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
; }- ~" X- f! k5 x0 _7 O% F - }9 h( P f1 B0 A" W
& W0 w! ]% k+ t) q- X- a( e- #endif /* configASSERT_DEFINED */
复制代码 0 x. `7 {5 E; _& X9 k2 x5 z H
相关宏定义如下:4 g5 r% N7 s: J$ J1 V
- #define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
复制代码
! h) _- h! x6 ?/ K" E: t# D- /* The lowest interrupt priority that can be used in a call to a "set priority"6 E) X2 U* Y. ~* ?6 D9 B6 G
- function. */0 \" f% L! p! h8 B8 x
- #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
6 H6 z; b* R, L- k9 s" |" l - 3 l3 P1 q* K* s7 n$ u, y3 p7 f+ Z
- /* The highest interrupt priority that can be used by any interrupt service
5 W9 m( H8 i4 t$ M& j& x - routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
6 w2 y- Y# b- y9 t - INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
. ~- G5 D; _9 i3 D( Z+ c - PRIORITY THAN THIS! (higher priorities are lower numeric values. */
. z1 c" g! X0 ]! U u - #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
( G' i9 k% A1 N F3 d
2 {3 P0 E* C4 |0 n$ ?8 D1 `- /* Interrupt priorities used by the kernel port layer itself. These are generic1 O" A' l b/ X' d+ W& J
- to all Cortex-M ports, and do not rely on any particular library functions. */
- Q6 c7 t# \5 I3 J - #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )0 Q$ m! ^+ {5 T
- /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
; h6 P) u: n5 [8 f! h - See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */+ C5 s! [. @! [8 d
- #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )4 A, U9 @- ~* U# b5 V5 _
; ?0 T1 Y& l4 e% ^8 N- /* Normal assert() semantics without relying on the provision of an assert.h
5 f/ w9 A* M0 p X: H - header file. */
4 u. q: m5 L0 j4 E - /* USER CODE BEGIN 1 */ + q9 P u: `/ D# K+ J' Q3 d/ I
- #define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
6 O1 k- `6 r: Q0 x( Y - /* USER CODE END 1 */
复制代码- #define configPRIO_BITS 4
复制代码
0 m c) \& @/ k0 F$ M' |3 d& @
8 k2 H5 k6 J% h; ^/ B- T* j简单总结如下:& [4 ~9 c e1 u! g# n
使用了FreeRtos操作系统后,外设中断优先级值不能设置小于configMAX_SYSCALL_INTERRUPT_PRIORITY,否则会导致了宏configASSERT的条件成立,进而卡住了。
& x- w8 X) H) n, N4 T) T
! B! s4 V# B' `) N8 o5 D, P+ j2 x2 a
% A4 N, f$ y Y1 g7 O
. s. V* y- ^3 r/ \& X- H1 a/ n+ ?% Y3 ?- A, G& Y/ O$ w- p( l; v
|