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

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

本帖最后由 北纬33度 于 2019-9-14 20:15 编辑
( ]0 F0 X% r8 L
; ~9 `5 R$ E' c最近在学习音频驱动,看过了stm32l475-atk-pandora的代码,有几点疑惑,请指点
, \6 c* K& D7 r; D2 c' E& n1、音频播放时,_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)
    7 w7 e/ z2 o; H) o( D8 r4 [
  2. {6 K, l# W9 v, j6 A% S8 O; ~
  3. : ~1 {4 b" ]3 p( J& ~
  4.     struct rt_audio_device *audio;6 ?3 A$ p% D0 S0 L1 V$ y" |1 A
  5.     rt_uint8_t *ptr;
    ' Z( ^+ K% Q( [% u: A% N! u
  6.     rt_uint16_t block_size, remain_bytes, index = 0;
    " W4 ?7 x( X2 a1 f8 M  f

  7. ! M+ f0 z! @& b
  8.     RT_ASSERT(dev != RT_NULL);
    7 t  I) S: I) _( p2 ~( v- o
  9.     audio = (struct rt_audio_device *) dev;
    5 z2 i* M$ K) ]4 D- `6 D+ _0 y7 O

  10. ; ^5 l# p( [* C% c3 s" L
  11.     if (!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL))
    8 v7 q: V8 v" A$ ?9 ^# i- W/ p
  12.         return 0;
    3 P1 d3 J& G% |

  13. * T# J; `& c/ R2 h# E0 N8 r
  14.     /* push a new frame to replay data queue */
    8 e# F! _! R# I! ]" z7 ]! j( Z
  15.     ptr = (rt_uint8_t *)buffer;
    2 b) `. o3 D) o
  16.     block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE;
    6 O' m( H% P, P- k# a5 `. M
  17. : P2 T% Q4 Z! {* W5 w3 M' _
  18.     rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER);
    & T+ a  M6 S2 U
  19.     while (index < size)) [3 b  ?8 Y( ~
  20.     {
    4 B! S* i8 ^, J2 b
  21.         /* request buffer from replay memory pool */1 D+ g2 ~" b. `2 k! Q, h
  22.         if (audio->replay->write_index % block_size == 0)) p2 L& @/ M) R+ T
  23.         {
    ) ^1 |7 A4 @+ |. R' g% ~" D8 q
  24.             audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER);# b( z. q/ P1 W, H; ^
  25.             memset(audio->replay->write_data, 0, block_size);. K1 ?5 i7 y4 \# m5 j* r- n
  26.         }
    ! w* n/ ]* _6 Q5 {5 ?1 x+ j; J5 m! E7 z

  27. 2 b' `7 d8 A) O
  28.         /* copy data to replay memory pool */
    : {7 \; Z3 i( I- y' a
  29.         remain_bytes = MIN((block_size - audio->replay->write_index), (size - index));% h' K! v5 D: c4 p" q
  30.         memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes);
    # h+ k- e2 r9 N% c# F

  31. . _/ M% Z8 f1 y% H9 w
  32.         index += remain_bytes;' q& f+ |& U/ @. Q' J) d
  33.         audio->replay->write_index += remain_bytes;$ v$ i  h6 l& x. c
  34.         audio->replay->write_index %= block_size;
    / r; I& b& C+ J/ }* g
  35. 3 l2 p0 Q8 E: B! i6 H: g2 }
  36.         if (audio->replay->write_index == 0)
    , R8 }) F: m& J5 b% `3 J, g
  37.         {, Y6 Q: }2 b4 C* t! z) n& c5 k
  38.             rt_data_queue_push(&audio->replay->queue,8 w! Q2 u3 v0 Y
  39.                                audio->replay->write_data,2 K% d: D+ ]- E  {7 @
  40.                                block_size,
    + h8 B+ f6 C, y) l# J
  41.                                RT_WAITING_FOREVER);' U  C4 V8 L3 `. A$ k  L7 x6 a
  42.         }
    + @! v% N! q4 R2 z: ~( ^
  43.     }- o' C+ o, f! v( X7 `; L
  44.     rt_mutex_release(&audio->replay->lock);! B' b" u' U# l/ h! f" J# s$ l. S
  45. , C; }. V) v/ C
  46.     /* check replay state */
    ) L/ v  J; V0 \3 s- G6 e5 R
  47.     if (audio->replay->activated != RT_TRUE)1 j! `! e6 y* T) l. o
  48.     {
    0 l# w( h5 F* @  r! Z& R
  49.         _aduio_replay_start(audio);
    . ^$ M: v" a! G1 D" t  i1 x
  50.         audio->replay->activated = RT_TRUE;' g) D0 ^# W/ \6 @; @& s
  51.     }
    " }7 g  t. V) Y) T
  52. / c/ Q7 n' i% H+ V' d: K
  53.     return index;. g0 D0 ]( T6 c  c4 [, C
  54. }4 K  b. ~0 [/ `
复制代码
2、调用_aduio_replay_start即drv_sound.c中sound_start通过DMA送出
/ J: p5 w- j! r& d$ I6 y! t6 q# f: Z  t/ ^
  1. static rt_err_t sound_start(struct rt_audio_device *audio, int stream)
      m8 L: u* U/ i) d
  2. {
    ' t; u1 R  m6 I: P. ~; i
  3.     struct sound_device *snd_dev;' m1 f8 }' _0 w+ T$ ?

  4. 8 \; a& |. T. n- C4 y1 y
  5.     RT_ASSERT(audio != RT_NULL);
    7 w& w9 \) S! p1 u/ \
  6.     snd_dev = (struct sound_device *)audio->parent.user_data;  W# p" f% L; y: @: h/ \  k
  7. ' A5 m4 G- s: D! m5 W4 e5 a3 C
  8.     if (stream == AUDIO_STREAM_REPLAY)
    : v$ E1 M5 I7 {) V) d& t, x. k
  9.     {) X* k6 |- _/ v/ j2 E- T
  10.         LOG_D("open sound device");
    * X  x1 n  j) N2 d* L
  11.         es8388_start(ES_MODE_DAC);
    3 r" C* Y% c3 g
  12.         HAL_SAI_Transmit_DMA(&SAI1A_Handler, snd_dev->tx_fifo, TX_FIFO_SIZE / 2);6 }% O, C) A# @& A' n$ n0 ]) a1 Y
  13.     }  W$ ~% k0 d0 E" B, E6 O5 }' u

  14. ! `) {! d) l: e* h
  15.     return RT_EOK;
    1 n( Y% w- r6 l& p! [
  16. }
    % C9 K4 F8 c8 S+ g
复制代码
3、一次DMA传输完成后,通过回调函数执行rt_audio_tx_complete,传输下一段音频数据 _audio_send_replay_frame,6 T9 \2 y8 B: Y' F
      data queue中无数据时,一直送出0,直到音频播放结束;
( ~; l( c: ~# I) {1 p- o1 C4 q     有数据时,将数据拷贝到tx_fifo(drv_sound.c中申请的一段内存),调用audio->ops->transmit通过dma送出(然而drv_sound.c中transmit未实现,数据如何发送出去??)5 G" T) Y  m) C; A

  W9 X( a: h4 s) _
  1. static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio)0 H. M5 D" f! H9 l7 x
  2. {
    3 Q" s. K& y- l8 u6 X$ ?8 _
  3.     rt_err_t result = RT_EOK;) _" Y/ @! ^. J6 ~5 c5 ]
  4.     rt_uint8_t *data;
    8 T, s! U% x. c7 O$ m: J
  5.     rt_size_t dst_size, src_size;6 ?7 f  \# [" P
  6.     rt_uint16_t position, remain_bytes, index = 0;
    7 p/ |4 r# @& ^( g# U; c& I
  7.     struct rt_audio_buf_info *buf_info;
    ; m: F7 o& m- f7 u" u" p, B4 Y
  8. ! ^! p7 F* `, M9 h, G6 R& |
  9.     RT_ASSERT(audio != RT_NULL);% e$ g* N2 y+ {

  10. 4 e+ `8 h( B" x; G/ U, W: a1 m4 f& t
  11.     buf_info = &audio->replay->buf_info;9 o! s9 O6 Y- D% K
  12.     /* save current pos */; P. f4 n) l0 f% Z: `2 Q; n( p
  13.     position = audio->replay->pos;
    3 y" [* i- w8 ~7 l2 z( T2 K% M
  14.     dst_size = buf_info->block_size;
    4 w) @7 N1 t  u
  15. . Q, [$ D3 g% S9 R! [, c
  16.     /* check repaly queue is empty */
    7 x8 v1 e  u4 ^- z0 S5 _
  17.     if (rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK)* c' m* x- e) ?! x( {- U) q' s! {
  18.     {3 O* @9 t; J+ b' t4 S
  19.         /* ack stop event */, |4 d3 _: [  V! _3 C, K
  20.         if (audio->replay->event & REPLAY_EVT_STOP)7 V$ R. b- j6 W
  21.             rt_completion_done(&audio->replay->cmp);" O1 w! [4 E7 W! u9 q( |
  22. % T( x8 K2 u8 f
  23.         /* send zero frames */
    1 S3 S9 E% I# e! b6 e& D) V
  24.         memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);; d( c& f8 V: L! ^! q

  25. ( T. ?9 j! m/ \( d) O5 T
  26.         audio->replay->pos += dst_size;' e- P0 u$ Y! w; c  i- F6 n2 Y
  27.         audio->replay->pos %= buf_info->total_size;
    - M5 M% w* Z. `( ?: C' c( y
  28.     }
    % y6 ~7 W; r0 J, z% p
  29.     else
    4 A9 h7 e) j2 [
  30.     {
    . \. [; ^$ g5 ?' j/ U
  31.         memset(&buf_info->buffer[audio->replay->pos], 0, dst_size);# v7 z. V" a6 Y+ X
  32. ' m5 N5 T. d: A$ d
  33.         /* copy data from memory pool to hardware device fifo */0 d& H$ X$ M) j0 N  J8 M2 t
  34.         while (index < dst_size)# u; r) D1 F' J  F* M
  35.         {: V5 s. }9 i3 S
  36.             result = rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size);
    $ Y4 ~' V* p( F0 h6 z* J  T2 ?
  37.             if (result != RT_EOK)
    & T% A. ]2 H2 G
  38.             {- d% h, A0 |: u$ L& q3 h
  39.                 LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes);% t1 @. h1 a. O7 V
  40.                 audio->replay->pos -= remain_bytes;& W! \' H4 Z( q# S+ [) z( L$ D
  41.                 audio->replay->pos += dst_size;
    ! _& [" X7 p4 w" L1 E% H1 u
  42.                 audio->replay->pos %= buf_info->total_size;
    ) q3 h0 s4 j- {- q1 J* Q& Z2 p1 N- |
  43.                 audio->replay->read_index = 0;
    ( m6 y2 \( i( i
  44.                 result = -RT_EEMPTY;% B3 K- L# I$ U
  45.                 break;8 ?7 ?1 q7 k' S* l
  46.             }$ M2 o' P) E. p7 I

  47. ) I; m, q9 O2 q7 ^
  48.             remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index));/ h3 F" n; }* X% u
  49.             memcpy(&buf_info->buffer[audio->replay->pos],' U9 y1 ]$ V! m1 Y  J" ?, |1 `
  50.                    &data[audio->replay->read_index], remain_bytes);# {6 d0 L3 I/ R: }4 n( U
  51. . b: r1 y3 g& O( b, u, N' {
  52.             index += remain_bytes;
    : `: N7 ]1 z& }) E. n. x: Y
  53.             audio->replay->read_index += remain_bytes;
    ( m7 l+ ?& V0 ]. Y
  54.             audio->replay->pos += remain_bytes;; D; [4 n  C1 h, C
  55.             audio->replay->pos %= buf_info->total_size;! p2 l1 W9 N( e

  56. 4 ?- |* d3 M; I( P; f
  57.             if (audio->replay->read_index == src_size)4 K4 [) i' T. W; f5 Q
  58.             {
    ! F' R; ]  Q+ a4 T  D- y+ ~
  59.                 /* free memory */
    , W0 Y# k- j) m% R  V  n6 a* z
  60.                 audio->replay->read_index = 0;
    1 j9 G% q% ]! L; z& A$ N
  61.                 rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO);7 N; ^; P% r7 Z
  62.                 rt_mp_free(data);6 J3 H$ {/ U  B! E# c" [) h: F

  63. " T( ]9 y0 o9 P8 I
  64.                 /* notify transmitted complete. */4 I( ?3 K6 l* G# g
  65.                 if (audio->parent.tx_complete != RT_NULL)& ?: p/ e' x: C* j0 n$ e* Q
  66.                     audio->parent.tx_complete(&audio->parent, (void *)data);
    7 l( W  x/ n2 C+ t
  67.             }
    2 D/ Y; W$ N6 g9 \/ u* i
  68.         }
    + }; u" t2 J4 y  G8 }
  69.     }
    ' ?* ?+ s( E' P- z& s" G1 _) @

  70. 3 n* w4 J7 m6 a7 O6 A; U* \% e' k
  71.     if (audio->ops->transmit != RT_NULL)! ], e/ s7 C2 U: ]; x0 l
  72.     {
    0 ?! x7 q. D% V$ Q
  73.         if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size)# p$ ^1 g9 ?- ~! q$ s; J
  74.             result = -RT_ERROR;
    $ C4 E( N6 |0 i0 Q2 a$ Q5 M
  75.     }4 o: e9 ]0 V+ `6 R  h# H

  76. : Q. N% R# Q# c" y$ h' e- p& D) A
  77.     return result;4 D5 j  i- U" K4 s; g7 K6 _
  78. }
    3 T4 |/ X; l* h
复制代码
4、此过程又将mempool中数据再次拷贝到tx_fifo(drv_sound.c中申请的buf),然后再启动dma送出,整个流程中数据拷贝2次,从 write buf -> mempool -> tx_fifo,个人认为无必要,且在dma传输完成的回调函数中拷贝数据到tx_fifo,占用CPU,可能会造成再次启动dma延迟,从而音频播放有停顿。* z- ], O. ~+ F- D  z1 J' v
5、应用读音频文件,并播放,基本流程如下
- @- d3 r; o1 Q" V, N) X     应用中申请一段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。此过程省掉一次内存拷贝
4 ]+ b+ ?$ A/ B$ H! q- F4 x1 e' V6、或应用中直接使用mempool,但如何融合整个驱动框架,请大家指导
本人为业余学习,以上理解如有错误,请指正。
" s2 O5 T2 s: C/ s" x

% Q7 P; P4 x- V; r* L3 F6 J, O& z- b9 S
使用道具 举报 显示全部楼层 回复
最新评论 | 正序浏览
显示全部楼层 |楼层直达:
发表于 2019-9-18 09:57:22 | 显示全部楼层
是指的这个吧* o( b$ F* u0 V. w6 s* Y
; B' y, R6 y% u% r3 r9 H
https://github.com/RT-Thread/IoT ... ivers/audio/audio.c- O3 F& C1 w% J- K9 R* ]3 K

5 ~( U9 `& ^% c5 Y如果觉得效率低了,欢迎提 PR
使用道具 举报 回复
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  1. 2 主题
  2. 36 帖子
  3. 36 积分

Ta的主页 发消息

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

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

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

Powered by RT-Thread

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