你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F7使用SPI发送完成和接收中断

[复制链接]
STMCU小助手 发布时间:2021-12-17 12:04
虽然在平常的使用中,spi使用轮询等待发送完成或者接收完成就行了。
* d9 c' t' u3 x& }但是在对时间有严格要求的设计中,假设我们需要发送完成后立马做xx事情,此时如果有低优先级的信号需要处理,我们的轮询方式就得不到及时的响应;3 a; `; w1 Q% j5 {# B3 T
或者说比如需要定时从spi设备中采集数据,定时器中断来了我们就要马上调用接收函数,接收完成马上进行其他计算,同样此时应该保证数据的优先级。  x& ?- {; N# }6 M" A
此时就需要用到发送完成和接收中断了。
% v' ^) O' V5 v8 C4 ]& j% d  b0 |+ S- B8 A- S( o
前面我们已经实现了SPI轮询的发送和接收,在前面的基础上进行修改。' p& d# o5 X8 c9 E& |/ M: i  H# e, M
* V8 p8 t9 L) s( r( v  T
接缓冲区满中断+ e* E. D, B' ~  _4 n, y5 I
新增发送和接收的回调函数,并在初始化的时候配置,使能SPI接收中断:7 G: V/ |2 `) i: L+ x  O

# w7 P/ d/ ^! {# Y1 y
  1. SPI_HandleTypeDef SPI3_Handler;  //SPI2句柄
    / R! u$ ]" ]- U

  2. 2 s  J& N9 w6 K3 w  J5 t4 o, k9 S, Y
  3. void rx_isr(SPI_HandleTypeDef *hspi)
    * H$ U5 H, ?7 N( [/ n1 _; [1 D2 e
  4. {
    ! r0 u/ O) z9 c. s
  5.     if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)/ }' i) T; s/ W
  6.     {" T: i* i7 C6 \8 K
  7.         u8 data = SPI3->DR;+ N2 [3 Y. T4 Q- }$ P* X
  8.                 printf("0x%X  ",data);
    1 E4 U4 }! T& c# s
  9.     }
    5 |- S* I0 J) E7 n7 N& D
  10. }
    $ s% a/ w5 c0 a; i
  11. void tx_isr(SPI_HandleTypeDef *hspi)6 l; X: e4 l( a1 ]$ B: s: i3 E7 T
  12. {5 L/ F* [+ y1 P* W* h5 ^' H
  13.     if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE) == 1)
    " G9 F5 l, t6 g/ u* x. W4 [+ J; ]/ ?
  14.     {
    ' n( p7 Q6 N( E6 X

  15. 8 b% d( p9 m3 F9 h2 J
  16.     }( J$ F! F; _* `* y) k' q: d8 H
  17. }
    ' _1 Y. P3 E( v0 C/ ?% u/ ~
  18. void SPI3_Init(void)
    2 E% L+ o+ W; ?9 e
  19. {6 x9 T$ @0 S. N- S; N
  20.     HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);9 J1 _+ r  C( I* O* V
  21.     HAL_NVIC_EnableIRQ(SPI3_IRQn);
    4 N' E: n  d$ Y0 Q, }' l" T
  22. " w& L) m+ J- m5 O6 @' Z. F! H
  23.     SPI3_Handler.Instance = SPI3;
    3 [" k' c0 B: Q
  24.     SPI3_Handler.Init.Mode = SPI_MODE_MASTER;) E% d' J) m! y% S
  25.     SPI3_Handler.Init.Direction = SPI_DIRECTION_2LINES;
    , |# Y; z0 ]+ W, V
  26.     SPI3_Handler.Init.DataSize = SPI_DATASIZE_8BIT;( }# y6 I4 L  x/ k/ M2 Y
  27.     SPI3_Handler.Init.CLKPolarity = SPI_POLARITY_LOW;
    % _* @$ `" R' ]. k2 A
  28.     SPI3_Handler.Init.CLKPhase = SPI_PHASE_1EDGE;
    * N% f8 R4 n' B
  29.     SPI3_Handler.Init.NSS = SPI_NSS_SOFT;* K# ?& w2 X' q9 }6 [5 o
  30.     SPI3_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
    ( d0 n: i4 S: n+ G
  31.     SPI3_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB;
    0 m6 n/ \- |+ m
  32.     SPI3_Handler.Init.TIMode = SPI_TIMODE_DISABLE;1 t0 F! L4 P( S7 L9 G) l' u* b
  33.     SPI3_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;8 C; Q3 m$ Y  K" \
  34.     SPI3_Handler.Init.CRCPolynomial = 7;
    ( K2 ~3 n. Q( L1 ]. o
  35.     SPI3_Handler.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;( I+ L8 ?9 l9 k  N
  36.     SPI3_Handler.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    / E/ ]. a/ |* a# n, k, {4 D

  37. ! u) U5 M/ K/ H! b" W6 J3 }8 J8 X* ^
  38.     SPI3_Handler.RxISR = rx_isr;
    2 F3 [7 y5 ]1 D* O$ q  h
  39.     SPI3_Handler.TxISR = tx_isr;
    6 J% T8 [; h. C  \* b- f' r
  40.                
    1 O4 o. q+ P+ d" f7 V) U
  41.     HAL_SPI_Init(&SPI3_Handler);6 P% ~" }( o8 W  l5 ]

  42. 5 J3 H6 {  u: u! H/ E
  43.     //__HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);' J# L8 t, @1 W) R
  44.     __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_RXNE);& a* k0 U/ d- Q+ R, l# L

  45. 9 T( W( H* X% e+ R' ~
  46. }8 m. V; j, d+ m2 r2 @, ~1 C) P- o/ F" S
  47. void SPI3_IRQHandler(void)
    5 |* V5 r4 v+ p& a9 }
  48. {
    . I5 ~# d# u% @" E/ J  w" H' V4 B
  49.     HAL_SPI_IRQHandler(&SPI3_Handler);  ^  m( l/ ^4 C1 c5 J8 C* m
  50. }
复制代码
0 f( D5 R4 ~5 H$ ]( [4 A
对应的读写操作如下:
6 s  S, K9 @6 b: b$ y% P0 i- H" {" V6 T; _! o& ?) F
  1. u16 W25QXX_ReadID(void)
    ) p6 ~3 A9 _# t" Q0 C: u
  2. {, j) ~7 w2 M+ }. Y
  3.     u16 Temp = 0;( M! `/ |4 G+ I- h8 O* ]* {
  4. % @% N5 {2 {! t9 s+ c( a
  5.     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);) r4 e+ o0 {; O" Q; n) A
  6.     SPI3_ReadWriteByte(0x90);//发送读取ID命令  y: ^2 ^9 v0 w
  7.     SPI3_ReadWriteByte(0x00);' T; E* n7 F. }% R* g* A2 z
  8.     SPI3_ReadWriteByte(0x00);
    3 c5 {7 @. \: S
  9.     SPI3_ReadWriteByte(0x00);
    - Y6 q. U5 {8 a* k7 y7 K+ D- [8 o
  10.     Temp |= SPI3_ReadWriteByte(0xFF) << 8;
    7 P# j# U! T1 n$ q& P" J$ P0 m9 F
  11.     Temp |= SPI3_ReadWriteByte(0xFF);( ^; k# |5 Q! F9 l
  12.     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);8 D1 _  o/ t7 i! q( A
  13.     return Temp;
    7 e7 Y" Y8 Y2 S7 l4 i) F
  14. }
复制代码

$ ]) s/ A& b% |% {显示结果如下:0 m7 M9 E( _/ g% Q! k0 Y+ N9 w
20200423172457741.png

4 U  K/ l8 R* Z) _6 ?( p' N: n" f7 x* s4 ~
其中前面4个0xFF是因为在写,写完4个byte同样会进入4次中断,但由于我们在接收中断就把数据接受了,所以SPI3_ReadWriteByte因为超时才退出的,可以明显看到几个数不是同时打印的,至于后面的ID没有显示也是同样的道理。1 j+ I, r4 O( C6 A

& t( ?0 R/ ?1 y: ?: l# x/ |' ^/ Q3 o3 X发送缓冲区空中断
+ v4 T# `6 ]" K2 R# W同样在前面使能发送完成中断就可以了:
7 ^1 J' [9 V$ c
1 g8 d$ [. h$ d1 O' j4 u
  1. __HAL_SPI_ENABLE_IT(&SPI3_Handler, SPI_IT_TXE);
复制代码
4 n/ x) u# S$ M' S2 n
但是由于发送完成了之后,发送缓冲区一直为空,所以会一直进入中断,所以我们使用发送完成中断的话,发送完成后除非再次填值或者关闭中断,否则会一直不停进入中断。: x. m9 H7 }5 ]" `, k

  b8 A3 @0 j5 D. @5 F0 ?3 N而实际上HAL库是提供了一个HAL_SPI_TransmitReceive_IT用于中断使用的发送接收函数,其中很重要的一部分内容:
7 Z  R+ {& S4 r2 z: u
; b3 a3 E0 N( f
  1.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
    & @  g3 m, ]+ t" s8 w! q
  2.   hspi->pTxBuffPtr  = pTxData;+ _3 Q- F% j2 K  t0 {; _
  3.   hspi->TxXferSize  = Size;! e* ?5 p' j6 h0 C! D  V
  4.   hspi->TxXferCount = Size;; i- e( U; J/ m* [: X! X0 T" q# ]) S
  5.   hspi->pRxBuffPtr  = pRxData;
    % P9 t4 p6 I; l- e1 k
  6.   hspi->RxXferSize  = Size;' Z2 w8 E. C! g. S
  7.   hspi->RxXferCount = Size;
    # H: z; y% W  }8 T9 R1 N& ^
  8. $ T: s; _( A3 l$ L" e. w8 n5 S- e
  9.   /* Set the function for IT treatment */
    * a) I6 m0 `5 J( u& a8 R1 {! m; N
  10.   if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )4 O& j! e3 L! f1 I7 R3 i9 S( c  s
  11.   {3 ?; x+ d- e/ |- E
  12.     hspi->RxISR = SPI_2linesRxISR_16BIT;
    " I/ s* r3 x) \& a' j- V$ t, Z
  13.     hspi->TxISR = SPI_2linesTxISR_16BIT;# j2 g! t1 p5 _/ t
  14.   }0 n, x; `' E% P( X% U
  15.   else4 j. v, i" R+ E% j' f
  16.   {
    1 @, W( d3 y5 J. @# ?0 k
  17.     hspi->RxISR = SPI_2linesRxISR_8BIT;6 g0 Y' I$ X& v
  18.     hspi->TxISR = SPI_2linesTxISR_8BIT;7 W/ f# T0 {9 O9 ?* Q
  19.   }* g. ]; F* l. B1 ]" [+ ^4 C
  20.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR));
复制代码
+ g' F2 r( G/ d3 m# U7 m
重新配置了中断函数,配置了发送和接收缓冲区为传入的数组,所以这里的数组要设置为全局变量,而前面设置的中断函数也失效了,而且使能了中断,所以我们前面所作的工作都是白费了。
1 B5 a( c& B5 }5 ^) b- C/ e- y- Q; b/ I: j, Q# x4 Y6 F# O# a5 x
5 t. @" X! @, r1 R: b" q

. o* l7 U  J" X: F. f$ ^/ [  z! w" c
收藏 评论0 发布时间:2021-12-17 12:04

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版