本帖最后由 power568 于 2019-4-16 16:07 编辑 9 O' n( `1 k" N0 W8 H7 O7 b: s
0 R8 o+ n+ K3 c+ E! F 最近在写一个串口通讯的程序,软件、硬件平台如下:
$ _+ Y$ O5 P! s8 Q硬件: STM32F429ZG
1 E( F& a4 l* c7 \+ ]6 r6 W1 r系统: FreeRtos、HAL库
: m4 Z- t. Q+ f+ o6 ^: U; S工具: Iar7.6
; N4 h! P/ F5 Y0 X* D7 \# R3 P4 ~* f2 D( z" M$ g& s+ T" r
计划是利用串口DMA+IDLE空闲中断的方式接收数据,在中断内将接收到的数据通过队列的方式发送出去,在任务内部等待接收队列,串口中断配置及ISR如下:- HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);//// 中断配置,优先级大小不能乱配置+ y( J9 x6 p9 Q! X9 j/ k/ G
- HAL_NVIC_EnableIRQ(USART1_IRQn);4 ^* s( S& q& C3 Q+ b" v1 `
, p6 m+ l" ^9 k* A* _3 h/ \& o- void USART1_IRQHandler(void)0 `! h2 r! i9 w& H; y& E
- {
& B2 y9 ~8 i a7 N: k - uint32_t flag=0;
' ?# ?* @5 y4 b6 t2 m - BaseType_t pHigherPriorityTaskWoken = pdFALSE;+ u+ o+ ?1 G2 x2 I6 U; \
-
+ ~& h5 X. q) `; o& |2 e - flag = __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE); 7 B! ?" ~0 j# r @, }3 O" [
- if((flag != RESET))& S) h3 b5 C& n7 i. D
- {4 }9 \; ?$ N- X7 g5 X& b
- __HAL_UART_CLEAR_IDLEFLAG(&huart1);2 C6 ]# `$ @1 O
- huart1.Instance->SR; 7 n: R/ [* B' D5 r6 H+ e
- huart1.Instance->DR;1 ?1 v- F7 O- Z6 S" M
- % N% G) Y' I) [6 t. G( P
- HAL_UART_DMAStop(&huart1); ~: ]; T3 Q, E' {, O; A- F3 ~
- xQueueSendFromISR(UrtK125RcvQueue, DrvUsartRcvBuf, &pHigherPriorityTaskWoken);: u" z4 f& S: l; o# g+ S: M" `8 Y
- portYIELD_FROM_ISR(pHigherPriorityTaskWoken);1 p" @9 U) q8 ^0 r
- }9 J* }$ f0 [" o. t' A4 z
- }
复制代码
7 {* }% \+ ?. w ]( z& K* H! V$ T. ~' `
//// 为什么代码提交后,代码对齐格式变了呢???
% `" D, L6 o+ v0 ?$ {
/ z9 _1 }' a7 n) S% V 调试发现进入中断后,程序卡在了函数xQueueSendFromISR(UrtK125RcvQueue, DrvUsartRcvBuf, &pHigherPriorityTaskWoken)内部configASSERT( ucCurrentPriority >= ucMaxSysCallPriority )处,具体为:
, v" l8 ^2 @3 s( h- #if( configASSERT_DEFINED == 1 )
% ^& P8 j) H4 y$ i! Z+ r( ]
% q. g4 m, G |# V6 x- void vPortValidateInterruptPriority( void )
" }- @1 @: @1 ]6 Q - {
# T1 M9 T) ?1 {& U; y# X6 x - uint32_t ulCurrentInterrupt;2 \- _# j, Q/ N# G
- uint8_t ucCurrentPriority;
% u7 f$ p% F. `4 X* ?- `
! I2 Y8 j7 L; H+ ]! I3 J% X, p- /* Obtain the number of the currently executing interrupt. */
+ g. R4 j g' Y3 A6 y5 M8 ] - __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) );5 ?) K) [7 m# {' R8 \: b! [, c! I& M! x
- //// ulCurrentInterrupt 调试显示为53
4 _. q9 }& `& ~) P* V( g
; i& j( M" l& a! C- /* Is the interrupt number a user defined interrupt? */
/ r% p- `4 s3 u9 o - if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )6 }9 I' X* P7 i/ I" T
- {
3 ^ u8 ]. i3 `. v - /* Look up the interrupt's priority. */
! n$ P8 y1 t% C) Y+ h" ]; f - ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];! ^/ }( x1 d; h' Z: T2 s
- //// 当串口优先级设置小于5时,ucCurrentPriority的值小于0x50,导致下面的宏断
, h/ [# }# B% f8 E8 Q4 T - //// 言configASSERT条件值"==0",进而卡住
) n5 A: e, r& V5 N6 J* Q - //// 当串口优先级设置大于等于5时,ucCurrentPriority的值大于等于0x50,下面的
2 [8 @) Y; R" Z7 F5 l - //// 宏configASSERT条件值"==1",所以不会卡住
. u. j2 Z6 G8 h4 L% ?
: H: X( ?7 K3 R3 H6 V- /* The following assertion will fail if a service routine (ISR) for% Z. M$ ~/ s% i* i: s: E
- an interrupt that has been assigned a priority above
1 |: C' [8 L* |8 g; a! w4 x7 I1 Y - configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
) s' D5 p1 A9 N( c - function. ISR safe FreeRTOS API functions must *only* be called
' Z: _7 Y! Y7 r5 {# j - from interrupts that have been assigned a priority at or below
2 [$ Y5 D G! C" q7 S' O - configMAX_SYSCALL_INTERRUPT_PRIORITY.# `3 Z( N- b- l" R: G, l
- //// 如果一个调用FreeRtos安全ISR API接口的中断ISR优先级分配大于
3 m) W6 m, H- Q5 S, g2 k# p - //// configMAX_SYSCALL_INTERRUPT_PRIORITY(即中断优先级值小于
* @7 B9 Q1 I4 [& c4 j/ x4 _; N - //// configMAX_SYSCALL_INTERRUPT_PRIORITY,因为FreeRtos中值越小优先级越高),% u# r, ?( n S# V; C0 }# ]& ~
- //// 下面的断言就会失败。FreeRtos安全ISR API接口必须只能在优先级分配大于# |( N$ \9 ~# A7 q6 e! s- m ?
- //// configMAX_SYSCALL_INTERRUPT_PRIORITY的中断ISR中调用) l+ Z6 U6 v* |- f9 k3 g: \% i
- 9 [! |$ V5 R3 v, B0 A/ A. ]# u
- Numerically low interrupt priority numbers represent logically high
/ O8 @. s$ w: ~4 E* a# ~ - interrupt priorities, therefore the priority of the interrupt must
3 F' d& y" ]6 q: I - be set to a value equal to or numerically *higher* than
6 K! H j/ o0 X2 p6 j) V: \! a1 K - configMAX_SYSCALL_INTERRUPT_PRIORITY.( `$ V4 J( }& H/ s8 r. O
- //// 数值小的中断优先级逻辑上具有高的中断有限权,因此设置时,中断的优先级 X( R! U$ Z6 [ C0 Z( P& a8 [
- //// 值必须必configMAX_SYSCALL_INTERRUPT_PRIORITY大
7 s5 [7 ]6 K2 g1 M" R- a - / _" t% m+ K# P* V
- Interrupts that use the FreeRTOS API must not be left at their9 z3 ]4 L" A+ u K) z' `! \1 b; n9 M
- default priority of zero as that is the highest possible priority,( M, q0 w* K! @
- which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY," T: ?+ ]+ l9 ~2 T
- and therefore also guaranteed to be invalid.
+ c; j" p3 Q; i - //// 使用FreeRTOS API的中断的优先级禁止使用其0的认值,因为此时中断优先级最! L- K: D7 @ C( _
- //// 高,0值的优先级必然大于configMAX_SYSCALL_INTERRUPT_PRIORITY,因此也必 I+ m% O) X; d* j7 u8 B# K
- //// 然无效2 u5 I& d+ f$ v# M$ ] d
- D# C2 u: U2 E' \; X0 C$ P) z( t- FreeRTOS maintains separate thread and ISR API functions to ensure/ p* y, u$ a5 e5 i
- interrupt entry is as fast and simple as possible.# B8 K- e" s; r& d5 @
- //// FreeRTOS为了确保中断入口尽可能的快和简单,因此分离了线程ISR API接口2 o9 C- w' O4 K
: G- j: K2 @3 E; {) n2 Y- The following links provide detailed information:
! C. z% h: k) h7 ] - http://www.freertos.org/RTOS-Cortex-M3-M4.html
! \0 K" q: O& y5 r2 S/ ^' S - http://www.freertos.org/FAQHelp.html */
! N% O( L1 B: T- O4 Z) @ - configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); //// 程序卡住位置
9 s" v$ Q/ u3 n - //// ucMaxSysCallPriority值为0x50
/ z2 ]) c; M- ^/ L$ ` - }/ {+ z6 l7 L0 L& d, @! n
8 ?# Q3 J6 g/ }- |* n# d/ \- /* Priority grouping: The interrupt controller (NVIC) allows the bits
4 R" z5 K3 h/ S! T+ ~ - that define each interrupt's priority to be split between bits that
+ n. l( `& F3 e1 s S - define the interrupt's pre-emption priority bits and bits that define
3 |6 G( b2 e) Z - the interrupt's sub-priority. For simplicity all bits must be defined
2 L3 R, A( q4 | - to be pre-emption priority bits. The following assertion will fail if- U) c, w' ~* c, C; ~
- this is not the case (if some bits represent a sub-priority).
; ]7 Y7 K* p% X! T S; x5 r - + T( _' N3 j3 U0 @3 k# b) ~
- If the application only uses CMSIS libraries for interrupt: w' j. ?# ` F- E$ o* C
- configuration then the correct setting can be achieved on all Cortex-M- y( B7 B3 d$ k; \! J" f
- devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the* b5 Z+ @' e, P
- scheduler. Note however that some vendor specific peripheral libraries
; a; N6 Y9 ^5 \3 T - assume a non-zero priority group setting, in which cases using a value
9 Q5 E9 m9 D" e8 j& g - of zero will result in unpredicable behaviour. */' ]! @" s9 B, d9 |! e
- configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
: h, o( u. L) \% g; S! m - }
6 x/ P. h9 R. N/ v - 6 a0 m* a* D5 o: u
- #endif /* configASSERT_DEFINED */
复制代码 / p4 P. [8 s$ J0 M/ z
相关宏定义如下:5 w& k' Y1 v+ [7 J o4 S" |
- #define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
复制代码
9 i, F7 O$ Y' l" O! V7 m) E- /* The lowest interrupt priority that can be used in a call to a "set priority"" L+ v z" K% t8 i
- function. */
; Q2 f2 U0 M6 g% a. ?/ I+ o - #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15; s% _! v; h4 H) l+ }. A
- ( { U" _- p8 \. _% c5 a7 H
- /* The highest interrupt priority that can be used by any interrupt service
/ i, J- ?, n- D4 }5 e' ?5 K - routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL- q- q, I6 ?% N7 W1 U. u- ~; H
- INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
; @4 S3 D' v: `3 `. h, X) j; l0 f$ I - PRIORITY THAN THIS! (higher priorities are lower numeric values. */
( G8 L$ [( {" d9 I# K2 d - #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 51 V( k, s- z8 c( O1 A- G0 ~8 s
; A N9 _' a5 L: Y% c9 U- /* Interrupt priorities used by the kernel port layer itself. These are generic5 K4 i# S# l% F! }1 k
- to all Cortex-M ports, and do not rely on any particular library functions. */9 g! C. H, h* p+ s# X$ j2 T
- #define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
2 T {! W( D9 M8 P# w& d) t3 u - /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
4 _# q; m b3 ^( V) U - See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. *// F; N. C! V5 N! i+ D" O' n
- #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
8 d& X) E, [7 B W
5 V/ ^- x+ n9 O& X+ {+ |- /* Normal assert() semantics without relying on the provision of an assert.h
3 Z8 Z: f8 H5 A& d - header file. */
5 N) U) z5 [; F6 Z$ M - /* USER CODE BEGIN 1 */
5 r3 }+ [2 d3 A0 d5 c - #define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
* \6 p' j, w7 o$ A - /* USER CODE END 1 */
复制代码- #define configPRIO_BITS 4
复制代码
( I& u0 _7 F1 y
9 H1 i7 ~, E( v A! W' U( ~0 |简单总结如下:
# B5 d$ V6 m: x' O$ r8 R! \ 使用了FreeRtos操作系统后,外设中断优先级值不能设置小于configMAX_SYSCALL_INTERRUPT_PRIORITY,否则会导致了宏configASSERT的条件成立,进而卡住了。- o3 k! [' z, a, R5 x
6 R7 F! a# `/ }# o# x& H6 i3 t
q/ m2 I2 ?( ?! G1 V; j. p
" {3 f" }& ^5 r8 W
* \( O {6 Q( M5 W+ [; I
. L/ ?+ o1 T6 a# a' l/ [9 X/ f |