stm32l475-atk-pandora音频驱动框架疑惑

发表在 Devices2019-9-14 19:56 [复制链接] 1 133

本帖最后由 北纬33度 于 2019-9-14 20:15 编辑 8 c! G: O$ I* F% A! m
1 O4 q! z* C, @
最近在学习音频驱动,看过了stm32l475-atk-pandora的代码,有几点疑惑,请指点7 H  ^6 j  L; W7 h7 G# V( p
1、音频播放时,_audio_dev_write函数中,依次申请mem pool,并将待播放音频的buf中的数据拷贝到mem pool中,然后push入data queue
  1. static rt_size_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
    . a( p+ P& P4 ?1 M! ?3 f
  2. {
    0 {  e( s' J, Z; D3 Z* S0 ]

  3. ) y2 |9 }) g7 \1 N3 [& B
  4.     struct rt_audio_device *audio;
    ; Q; `1 s4 s- o( ]# r. l
  5.     rt_uint8_t *ptr;
    # I: y3 ^& b7 c) Y+ m: j, h
  6.     rt_uint16_t block_size, remain_bytes, index = 0;- m. L" W4 o6 C4 J  V# u4 \
  7. : s" Q5 {  T; l( V
  8.     RT_ASSERT(dev != RT_NULL);  D" B: ?+ @# s2 t. W* q7 `7 D
  9.     audio = (struct rt_audio_device *) dev;
    ( B! V' o2 K. e6 ]) v' z  m$ z! X
  10. + z- c/ H1 F# \; A. ?- w
  11.     if (!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL)), e* U% y' I5 V  O* b7 N
  12.         return 0;# N$ b) x; a, v( Y( y# E- `
  13. 0 O5 k8 J4 A& M/ i
  14.     /* push a new frame to replay data queue */# Y% ?% H" u. s( G, s) e0 S
  15.     ptr = (rt_uint8_t *)buffer;
    ( H1 B8 v& J2 n, w3 [
  16.     block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE;
    1 e6 r; z7 a9 C; U5 t

  17. 5 \- q( q" j: d' }  C+ U" b
  18.     rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER);
    " C% [8 D0 V! B* o1 F
  19.     while (index < size)
    7 C4 W& I5 S" W+ f' x( t2 q' E
  20.     {
    + O. u) z- b5 y9 C2 N$ u/ R4 ~
  21.         /* request buffer from replay memory pool */1 w3 g, \) M, Q: F! S5 T9 _# R
  22.         if (audio->replay->write_index % block_size == 0)* P* F6 {; e8 l2 R# o$ i' d5 B! E
  23.         {8 O/ N5 z! n0 g, s! o
  24.             audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER);; P1 V0 A3 V7 |
  25.             memset(audio->replay->write_data, 0, block_size);/ x+ ?* K: K1 I( a
  26.         }6 ~2 [" G* Z6 f' ?, j, }

  27. & \2 w2 e* B" a& H$ T8 K
  28.         /* copy data to replay memory pool */
    + S; s# j6 I8 n: h9 k% C% L' J
  29.         remain_bytes = MIN((block_size - audio->replay->write_index), (size - index));
    # G+ }4 ?) J) P1 x2 W
  30.         memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes);
    0 U* A" {' B3 q7 z- ~, F+ p( e
  31. $ }$ o* C1 Q7 f8 C; G$ z
  32.         index += remain_bytes;
      T# _( V7 `2 T1 H  H- q" {: k
  33.         audio->replay->write_index += remain_bytes;: j: u' E& y& ~# b* O: k" [
  34.         audio->replay->write_index %= block_size;  w7 d2 R$ ?4 m: t9 v, N6 j

  35. $ M/ p* W" ?  S( Q) g3 h
  36.         if (audio->replay->write_index == 0)
    8 r+ y' u2 J9 h$ R2 f6 g
  37.         {, ?) Z3 _7 {$ @$ N5 ?8 {
  38.             rt_data_queue_push(&audio->replay->queue,
    , h& l) z8 V1 ^  e' Z2 i# ?
  39.                                audio->replay->write_data,4 R! P, g- L. Q. {& f
  40.                                block_size,1 K2 b) `8 p0 A1 u# W) Z5 ~
  41.                                RT_WAITING_FOREVER);
    4 b  t1 n- f1 U1 H
  42.         }. B; O4 a; N% g
  43.     }
    4 K, f; N  A: s* H4 G
  44.     rt_mutex_release(&audio->replay->lock);
    , [, x1 _4 i! @* X8 g; n# g. O
  45. 1 X; {9 Z# T  e8 b+ O
  46.     /* check replay state */- R' N+ q3 A" E
  47.     if (audio->replay->activated != RT_TRUE): ~: I' l, E& _
  48.     {+ p* i  B; p3 H
  49.         _aduio_replay_start(audio);* t9 M6 a/ i  [: g" f5 y. d& Y9 d! p
  50.         audio->replay->activated = RT_TRUE;
    $ x$ ]2 E+ w/ v: t5 F7 V/ d, e
  51.     }
    ) p- d6 x" ^# |; q" l9 t

  52. 9 K. B+ M2 p  @1 I8 }
  53.     return index;6 M& A+ w3 L3 {5 Q! W! f
  54. }# }' i2 t- H7 r3 n$ p
复制代码
2、调用_aduio_replay_start即drv_sound.c中sound_start通过DMA送出
* i4 J# T5 _% r
/ b6 @3 v5 y: b
  1. static rt_err_t sound_start(struct rt_audio_device *audio, int stream)) \0 e0 [/ I/ r0 F& }- ~! @$ ?
  2. {+ g1 B8 }  o$ m6 t
  3.     struct sound_device *snd_dev;
    5 A  W# C& B* ]: Z9 s2 F% e1 x

  4. - Q( |0 k- U5 }, n! a, t( T. M* D
  5.     RT_ASSERT(audio != RT_NULL);
    ! n0 o: J+ j8 [; i3 t" {$ H) o, _
  6.     snd_dev = (struct sound_device *)audio->parent.user_data;( b$ H: q! p, E8 I0 @, R

  7. 3 @! z* e2 `- w. ^
  8.     if (stream == AUDIO_STREAM_REPLAY)& Q4 A6 v" N. y8 k* R, |
  9.     {; r: R1 `9 z) Q' p7 J+ ?
  10.         LOG_D("open sound device");
      U) l' \; X. M, V/ z3 O7 t
  11.         es8388_start(ES_MODE_DAC);
    , a7 V! C4 D6 Y8 y, O! \/ _1 @
  12.         HAL_SAI_Transmit_DMA(&SAI1A_Handler, snd_dev->tx_fifo, TX_FIFO_SIZE / 2);
    & P1 j: \' z1 w! J7 s6 s( V6 z3 Z
  13.     }
    2 r& Q& U" J9 x
  14. * ]' G4 }, `8 A3 i9 ^
  15.     return RT_EOK;; V! R9 C# Y2 I4 A* m/ D
  16. }  Z/ K! F8 ]0 K. @9 A" a
复制代码
3、一次DMA传输完成后,通过回调函数执行rt_audio_tx_complete,传输下一段音频数据 _audio_send_replay_frame,2 ?9 w. ^# @) |+ q2 v  Y
      data queue中无数据时,一直送出0,直到音频播放结束;
& ]0 `# y6 T. k' J* @: H. E     有数据时,将数据拷贝到tx_fifo(drv_sound.c中申请的一段内存),调用audio->ops->transmit通过dma送出(然而drv_sound.c中transmit未实现,数据如何发送出去??)
( Q* q# j5 B/ ?; ]+ A7 J% W+ O) y9 {$ K& }( S, R# X+ }
  1. static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio)+ t8 X$ o+ S2 k( A
  2. {
    0 O8 w# L# D1 H. i
  3.     rt_err_t result = RT_EOK;
    ' g) S8 }8 L/ [
  4.     rt_uint8_t *data;
    6 U- a' b7 |0 N# L- n/ o( X# ~
  5.     rt_size_t dst_size, src_size;5 V! [/ n, }% c5 [0 g, M) m- b. ]5 F
  6.     rt_uint16_t position, remain_bytes, index = 0;
    . K2 L7 G; i: Y$ r
  7.     struct rt_audio_buf_info *buf_info;6 u; \: ]! ]' x2 K

  8. % F$ h3 S4 t* k) v
  9.     RT_ASSERT(audio != RT_NULL);
    & ^. R6 z, @2 T* c* Y6 S7 ^  Q* u
  10. 4 C/ [2 _( j! _( W
  11.     buf_info = &audio->replay->buf_info;
    5 g1 z5 l& P9 a7 H& i8 J
  12.     /* save current pos */" ^& |* D* o" {- k
  13.     position = audio->replay->pos;
    ; J$ f( y0 C& S# C& w
  14.     dst_size = buf_info->block_size;& c/ f; {  |' Q4 y8 H7 I

  15. 3 O, U2 ^1 H: w6 e. x2 C
  16.     /* check repaly queue is empty */: S1 h  i. K" x
  17.     if (rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK)
    ; R) A5 V& G6 `
  18.     {& u$ Z  K; c7 N+ y% Y/ B; G9 w
  19.         /* ack stop event */
    7 k8 u8 S0 v* _# W( k8 V& C. u
  20.         if (audio->replay->event & REPLAY_EVT_STOP); N# c1 E  C% S  W  }
  21.             rt_completion_done(&audio->replay->cmp);
    / y. h7 H" d$ I* b" Z
  22. 6 m4 n- ]; U* T
  23.         /* send zero frames */
    . e/ F& y4 }9 I2 e4 Q0 x# x9 J* V
  24.         memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);
    , V  ]3 p$ J& _; H! W! P0 l* i
  25. # f+ v# K6 m/ ~4 [
  26.         audio->replay->pos += dst_size;7 ?+ t- V- k: R. {
  27.         audio->replay->pos %= buf_info->total_size;8 L  ?' t/ g1 P  C
  28.     }
    ; o' r" V  w8 |- m0 ~6 M
  29.     else! Q" p/ Q& Q# d, N& M
  30.     {$ u; E- {" J% d
  31.         memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);/ [/ T5 W+ N+ E' d  J

  32. 6 T9 r: _* b+ P+ U) `  Q1 Z9 ]6 I
  33.         /* copy data from memory pool to hardware device fifo */9 {4 f7 _: s; r9 P
  34.         while (index < dst_size)
    ; Q; p: {, U: t% \/ w
  35.         {
    , h# _9 g( s$ J: ~( D- Z
  36.             result = rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size);3 m, v4 b8 |; i. d" a, p
  37.             if (result != RT_EOK)8 i( A2 Z5 |* n# ^# g
  38.             {% g% g% A$ L7 W8 U' H# S! o7 J
  39.                 LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes);
    # ~9 m( `1 k( Q
  40.                 audio->replay->pos -= remain_bytes;
    $ k: Y. P' n2 Z+ M" |/ T9 r
  41.                 audio->replay->pos += dst_size;
    8 \" i) g7 U5 ]$ t4 h: X- {
  42.                 audio->replay->pos %= buf_info->total_size;$ p: F$ G2 |2 p. G# c
  43.                 audio->replay->read_index = 0;
    * t8 @- o3 R9 k4 K' |* f
  44.                 result = -RT_EEMPTY;
    ) }7 E; N! e, f/ _2 z, v# O4 ~
  45.                 break;( s, N8 `* K% |
  46.             }  y" [) C9 t1 f! H
  47. - O; }5 K" \5 l2 U- y& o9 P# _
  48.             remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index));
    3 v1 z: g9 ~0 r8 H5 D& i
  49.             memcpy(&buf_info->buffer[audio->replay->pos],
    8 r7 @: g3 Q2 Z) q4 F: e) z
  50.                    &data[audio->replay->read_index], remain_bytes);
    * u2 N2 A+ C# r/ t3 |
  51. 5 q1 C/ R! d9 q( @2 J
  52.             index += remain_bytes;: X( Y+ X7 W8 c6 i; Z8 u
  53.             audio->replay->read_index += remain_bytes;
    ! j1 M6 I& k2 j! U
  54.             audio->replay->pos += remain_bytes;
    7 N' E- r% k  E9 @$ H, ?
  55.             audio->replay->pos %= buf_info->total_size;
    . o. x" _) ~5 g

  56. 8 C$ J4 t% h% p# t6 \+ ~
  57.             if (audio->replay->read_index == src_size)
    . }* x# k' e" V, W
  58.             {
    2 Z; z5 S: n+ c/ t# H9 q: y
  59.                 /* free memory */5 z& M# c5 m4 ]+ s
  60.                 audio->replay->read_index = 0;- N* l- l2 Q7 E; c
  61.                 rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO);
    / ]7 b& W1 C/ k! a4 }; t$ U- B5 N
  62.                 rt_mp_free(data);3 t4 G3 `1 O4 ?* |5 S% W% g
  63. 9 i9 [. g: c8 @7 s# K+ P
  64.                 /* notify transmitted complete. */
    + w+ A7 F) A& A6 r
  65.                 if (audio->parent.tx_complete != RT_NULL); T9 A3 V: ]& }8 p: H
  66.                     audio->parent.tx_complete(&audio->parent, (void *)data);
    # o, N! r4 K! g
  67.             }
    ; J# g# n) G: u+ ~0 I
  68.         }0 h6 J# R& C& R8 x
  69.     }' f0 L0 }( l- h& M/ T  h  W0 m

  70. / T# j  X# A2 c! f3 |7 h' @
  71.     if (audio->ops->transmit != RT_NULL)
    6 f2 ~/ i- R0 g! b8 m" R5 T/ e
  72.     {
    - f- z6 H8 ~+ g
  73.         if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size)
    1 `2 `" \" W0 s
  74.             result = -RT_ERROR;2 E! p% }" Q& u2 r
  75.     }
    # e. A9 z: O6 U& e( L9 f

  76. ! b( a2 Q7 Z6 |
  77.     return result;
    + f6 h$ w" L$ \  J0 Y
  78. }
    , _5 U7 N+ f( H9 P
复制代码
4、此过程又将mempool中数据再次拷贝到tx_fifo(drv_sound.c中申请的buf),然后再启动dma送出,整个流程中数据拷贝2次,从 write buf -> mempool -> tx_fifo,个人认为无必要,且在dma传输完成的回调函数中拷贝数据到tx_fifo,占用CPU,可能会造成再次启动dma延迟,从而音频播放有停顿。1 _- e8 b8 e1 _6 e& T
5、应用读音频文件,并播放,基本流程如下& `. M9 z8 j3 n' o5 Q& K
     应用中申请一段buf,从文件中读数据到buf,然后调用device_write到sound设备播放音频。 将buf中数据拷贝到mempool,并送入data queue,在dma传输完成回调中,释放本次mempool,然后pop出数据,启动下次dma传输,在dma传输期间,应用中可以再次申请到mempool,然后拷贝数据,push到data queue,继续read文件,阻塞在device write函数内(rt_mp_alloc),直到下次dma传输完成释放mempool。此过程省掉一次内存拷贝
+ O& h9 ^8 y$ N1 J: u$ [6 Q  ^6、或应用中直接使用mempool,但如何融合整个驱动框架,请大家指导
本人为业余学习,以上理解如有错误,请指正。
1 r: U) B" {6 x! y4 |

$ g9 R  c8 L# A7 j" K6 F+ F
使用道具 举报 显示全部楼层 回复
最新评论 | 正序浏览
显示全部楼层 |楼层直达:
发表于 2019-9-18 09:57:22 | 显示全部楼层
是指的这个吧
# ?' j9 E8 I5 @' [: `
/ o/ h6 x& q5 ~' N& N  k8 k) b/ N: \https://github.com/RT-Thread/IoT ... ivers/audio/audio.c/ ~7 L; [* k- g( k8 i' E" N0 j# h

9 e. @+ m! ~2 c) D! t; n如果觉得效率低了,欢迎提 PR
使用道具 举报 回复
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|RT-Thread开发者社区 ( 沪ICP备13014002号-1

有害信息举报电话:021-31165890 手机:18930558079

© 2006-2019 上海睿赛德电子科技有限公司

Powered by RT-Thread

快速回复 返回顶部 返回列表