本帖最后由 power568 于 2019-4-16 16:07 编辑
! S( q( u# R; n% J! J; y
' z& }" M! L$ H" n& X. q- i 最近在写一个串口通讯的程序,软件、硬件平台如下:( Q5 i+ g9 T! i& C' |: p
硬件: STM32F429ZG
+ S, i3 o, e9 u系统: FreeRtos、HAL库# `, ~8 g8 m @2 K: d% |5 S2 K
工具: Iar7.6% m0 c0 a/ w3 N$ f
' H s) B0 m3 p9 \+ w/ y 计划是利用串口DMA+IDLE空闲中断的方式接收数据,在中断内将接收到的数据通过队列的方式发送出去,在任务内部等待接收队列,串口中断配置及ISR如下:- HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);//// 中断配置,优先级大小不能乱配置
; c( V4 E) Z0 ~0 O0 q - HAL_NVIC_EnableIRQ(USART1_IRQn);. {0 F7 o8 U) K h2 o0 ^( R
- . s$ R r% ~9 ]2 h: e
- void USART1_IRQHandler(void)) P' N( u9 {5 s+ o4 y
- {
3 c& U: e& C2 z+ |" ] - uint32_t flag=0;: C' ^; K1 V' H1 l( [6 B* c+ o
- BaseType_t pHigherPriorityTaskWoken = pdFALSE;. G y7 S2 P, }/ T8 @4 N+ p
- 4 P; g' C8 a" @) ^. S+ {
- flag = __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE); . |; u+ b. M+ }+ L2 B6 o
- if((flag != RESET))
( Q" ?! z( h4 x+ b% j - {
0 E$ V4 g! `8 j+ a1 O - __HAL_UART_CLEAR_IDLEFLAG(&huart1);% B7 A2 O" i8 w: o9 x* v" g
- huart1.Instance->SR; 3 u+ {& k! M. k( r
- huart1.Instance->DR;8 L/ C! g+ Q& |- d
3 v+ h! N$ k4 N, L: h7 v7 Z- HAL_UART_DMAStop(&huart1);7 N# n7 H; S7 M2 s
- xQueueSendFromISR(UrtK125RcvQueue, DrvUsartRcvBuf, &pHigherPriorityTaskWoken);; M& P" }+ z$ o
- portYIELD_FROM_ISR(pHigherPriorityTaskWoken);
, B6 j+ p' u3 N) v: w) b - }* p! n# x" T6 ?+ K( M& g
- }
复制代码
1 M! u" F7 K! L) m3 p8 A
& A- m4 \6 e' i //// 为什么代码提交后,代码对齐格式变了呢???
! J6 S3 l& g& d7 y$ N( w6 X$ }, V% d8 j' p( W3 `6 n$ P
调试发现进入中断后,程序卡在了函数xQueueSendFromISR(UrtK125RcvQueue, DrvUsartRcvBuf, &pHigherPriorityTaskWoken)内部configASSERT( ucCurrentPriority >= ucMaxSysCallPriority )处,具体为:
2 }' k, P+ {9 _* u' j$ \- #if( configASSERT_DEFINED == 1 )
) H& g: u9 m9 H* Z4 `: u
$ o0 f! x0 k% R ?$ t- void vPortValidateInterruptPriority( void )
) J4 G9 Z# t8 \ - {7 l7 P1 z L; J6 w! h
- uint32_t ulCurrentInterrupt;
h( G: m! ~. L9 n - uint8_t ucCurrentPriority;# R. i ]2 L9 R! B2 r8 p
- O& |, D! H6 p' [; C* M- /* Obtain the number of the currently executing interrupt. */
1 M6 W9 m5 x4 f5 J# ] - __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) );
' U( R5 a7 [$ N% z4 V5 n) [+ r - //// ulCurrentInterrupt 调试显示为532 R4 X' g9 V# c( x/ w
- 8 J8 K7 J, T4 L+ r J
- /* Is the interrupt number a user defined interrupt? */
+ H! i0 ?$ u F/ o4 U5 K - if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
6 u5 D+ O* {+ g7 w) d0 L, y4 | - {
0 Z5 c" W" y" z' d - /* Look up the interrupt's priority. */
[' z. c2 B5 {; c* E; d - ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];( `/ `( H& z* v" f; S* X; Z: e
- //// 当串口优先级设置小于5时,ucCurrentPriority的值小于0x50,导致下面的宏断
9 c1 k$ y# Q e# e* \4 }' }; j - //// 言configASSERT条件值"==0",进而卡住: |, e$ x# V- H" D* X% _0 x# ?1 s
- //// 当串口优先级设置大于等于5时,ucCurrentPriority的值大于等于0x50,下面的
6 s# Q5 T% z) M - //// 宏configASSERT条件值"==1",所以不会卡住
, A7 d0 n C( t
7 c3 J. \( c+ \2 S- /* The following assertion will fail if a service routine (ISR) for- c, z3 P, g: n, d9 e) C0 p1 e7 c
- an interrupt that has been assigned a priority above" E% u' W) ?* u; d" x
- configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API; x6 k$ B* J ~* t
- function. ISR safe FreeRTOS API functions must *only* be called
: L- \7 J" E) ], Z - from interrupts that have been assigned a priority at or below
& t+ f c: p, P - configMAX_SYSCALL_INTERRUPT_PRIORITY./ b& c7 }6 I( s8 ?" S4 x- U
- //// 如果一个调用FreeRtos安全ISR API接口的中断ISR优先级分配大于. W1 o5 |6 B( n5 n
- //// configMAX_SYSCALL_INTERRUPT_PRIORITY(即中断优先级值小于
) w) f7 K& T. ]6 C+ t6 L - //// configMAX_SYSCALL_INTERRUPT_PRIORITY,因为FreeRtos中值越小优先级越高),/ B! B8 F- ~) |' u8 B+ p2 H7 T
- //// 下面的断言就会失败。FreeRtos安全ISR API接口必须只能在优先级分配大于& V& _* A0 x* u5 K6 X7 R
- //// configMAX_SYSCALL_INTERRUPT_PRIORITY的中断ISR中调用! A: f8 L, ?: g. O l# Y
-
_, D3 Y+ \8 l8 Y$ t6 a, D2 T% t - Numerically low interrupt priority numbers represent logically high
& [7 X2 J' W7 d2 U/ p/ Y/ V - interrupt priorities, therefore the priority of the interrupt must" E# {1 u* n6 O! \+ `; }
- be set to a value equal to or numerically *higher* than0 F8 X' p4 L" l* e
- configMAX_SYSCALL_INTERRUPT_PRIORITY.
n! g* S) R- L% w - //// 数值小的中断优先级逻辑上具有高的中断有限权,因此设置时,中断的优先级
( o }5 a0 z, S( Y3 Q* z1 y" Z - //// 值必须必configMAX_SYSCALL_INTERRUPT_PRIORITY大' X, m4 Z" c/ T- @
- . n; `7 k* o' Z$ g7 y# a8 S
- Interrupts that use the FreeRTOS API must not be left at their; Q2 N8 O8 x: R2 {! \/ f- O
- default priority of zero as that is the highest possible priority,4 |9 C$ T# `% z
- which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,! M& ]" O5 H6 L/ k8 [% L
- and therefore also guaranteed to be invalid.
5 Y7 k9 V& g& Z& H) ?2 d6 K. G - //// 使用FreeRTOS API的中断的优先级禁止使用其0的认值,因为此时中断优先级最
+ [* g" R4 d2 N. S: [ - //// 高,0值的优先级必然大于configMAX_SYSCALL_INTERRUPT_PRIORITY,因此也必1 X$ ^5 L5 x3 l
- //// 然无效
6 G3 |& @" I$ ^; D
7 @, {; p r3 B* z. p" P1 j3 Y9 i- FreeRTOS maintains separate thread and ISR API functions to ensure
1 e6 B W( W B8 L: k: a$ ? - interrupt entry is as fast and simple as possible.% _1 s2 p* G% t! F& U2 S4 I$ p" W2 n
- //// FreeRTOS为了确保中断入口尽可能的快和简单,因此分离了线程ISR API接口1 ?6 _* d4 ^. I/ s; R
- " H9 j# g P1 F+ R! ?
- The following links provide detailed information:, n; |$ s. u" ~5 o3 q
- http://www.freertos.org/RTOS-Cortex-M3-M4.html
/ a0 }& h3 p5 a: F# P, Q - http://www.freertos.org/FAQHelp.html */" n& R/ J4 Q8 m; ^9 {. O
- configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); //// 程序卡住位置. l$ F* m) B: K& H
- //// ucMaxSysCallPriority值为0x50
" |! E4 T2 L2 |% _ - }: M; B0 I' Y, \$ G& d+ B# _
- ; x9 b0 M) `: i! D; J+ A& |* n
- /* Priority grouping: The interrupt controller (NVIC) allows the bits
. U* R p& Q$ S6 `% @' A& D5 u$ T - that define each interrupt's priority to be split between bits that
3 `( B; Q) }; i - define the interrupt's pre-emption priority bits and bits that define
8 k6 [. Z% h9 j1 d - the interrupt's sub-priority. For simplicity all bits must be defined
' H' }& R& h4 p0 j8 ~* Y - to be pre-emption priority bits. The following assertion will fail if1 U9 i% q, h* M# G+ v
- this is not the case (if some bits represent a sub-priority).
! J$ H0 m3 e+ n9 }4 e
0 o# p! Z$ F6 x& R2 {- If the application only uses CMSIS libraries for interrupt
( B* ^' y1 u' j g1 W - configuration then the correct setting can be achieved on all Cortex-M
0 o. ^4 a9 O# L' h - devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the; S) ~, @( ]7 ] C6 j! z
- scheduler. Note however that some vendor specific peripheral libraries
& Y/ S0 F/ X) W" M/ B& j$ F - assume a non-zero priority group setting, in which cases using a value
/ e: J5 G9 _4 h7 L - of zero will result in unpredicable behaviour. */
( Y* M) T/ |* p - configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
) y Z v5 f! y( p$ `% y - }
: [( Y5 m) h/ y% `; B; x - & D0 \0 t/ `4 m# @0 R
- #endif /* configASSERT_DEFINED */
复制代码 $ ?) W+ z3 n. M6 F" E
相关宏定义如下:
9 I. C5 E7 R9 ^0 C; [. O' I- #define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
复制代码- 0 ?' j1 z9 K& d' X& \5 K: r
- /* The lowest interrupt priority that can be used in a call to a "set priority": K7 v- i+ P" ~4 a8 q
- function. */
* V1 R% g% }0 a- y+ S, F - #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 158 V( ~. }: P4 A6 m
/ W9 t3 E2 B4 i% R" R- /* The highest interrupt priority that can be used by any interrupt service
4 K( e" l; P4 `- c - routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL) K& W. I: B7 g$ R* |* l
- INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
8 Y+ R, Y$ a9 l c; P - PRIORITY THAN THIS! (higher priorities are lower numeric values. */9 K& t5 R0 X. _, P& y% y1 g
- #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/ g2 y @2 U# r0 f d
% C$ t3 {, @- y+ z- /* Interrupt priorities used by the kernel port layer itself. These are generic/ I, S: S1 ]4 e5 D( r( |' C
- to all Cortex-M ports, and do not rely on any particular library functions. */
' n8 b7 M" r8 Z' b1 d& g - #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )) b0 K; a% C4 W" [' t+ o
- /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!- i* ]* W7 ^4 T& T2 n) i1 i7 W
- See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. *// b5 i ~- l8 b/ b
- #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )" g+ C; l7 s6 l% x/ v
/ A5 @: p& L; l6 r r( T9 w+ W- /* Normal assert() semantics without relying on the provision of an assert.h
4 Z- C2 K) o# B6 K5 Q: f - header file. */
: X% I" d8 @5 n - /* USER CODE BEGIN 1 */
7 Q8 w1 E) U; s: L6 |' ?- u - #define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
# e5 z5 X; N& e, E- W - /* USER CODE END 1 */
复制代码- #define configPRIO_BITS 4
复制代码
1 I9 ^ x0 F6 z# J/ z& I3 r3 A( Q4 T
' V Z V, A$ ?9 x4 o简单总结如下:/ A3 s& Z# t. a7 M, ?6 f8 N
使用了FreeRtos操作系统后,外设中断优先级值不能设置小于configMAX_SYSCALL_INTERRUPT_PRIORITY,否则会导致了宏configASSERT的条件成立,进而卡住了。6 i# D' U1 v* a5 h( @3 g
6 j- Y( w5 a' ^9 P1 c( S
8 D, g9 }" N) F$ `3 D, K7 d4 h/ d; n# q
- y* C6 W8 I2 L! U {: Y3 i% e& h% D6 I0 c \0 k0 Q( ~% N
|