GadgetSeed  0.9.6
stm32f7xxx-disc_audio.c
[詳解]
1 /** @file
2  @brief STM32F769I-Discovery Audio Driver
3 
4  @date 2017.02.11
5  @author Takashi SHUDO
6 */
7 
8 #include "sysconfig.h"
9 #include "device.h"
10 #include "interrupt.h"
11 #include "task/event.h"
12 #include "task/syscall.h"
13 #include "task/mutex.h"
14 #include "device/audio_ioctl.h"
15 #include "device/ts_ioctl.h"
16 #include "timer.h"
17 #include "tkprintf.h"
18 #include "tprintf.h"
19 #include "sysevent.h"
20 
21 //#define DEBUGKBITS 0x01
22 #include "dkprintf.h"
23 
24 
25 #if defined(GSC_TARGET_SYSTEM_STM32F746GDISCOVERY) // $gsc ターゲットシステムは32F746GDISCOVERY
26 #include "stm32746g_discovery_audio.h"
27 #elif defined(GSC_TARGET_SYSTEM_STM32F769IDISCOVERY) // $gsc ターゲットシステムは32F769IDISCOVERY
28 #include "stm32f769i_discovery_audio.h"
29 #endif
30 
31 static struct st_device *ts_dev = 0;
32 
33 #define MAX_AUDIOBUF (1152*2*2*2)
34 static unsigned char audio_buf[MAX_AUDIOBUF];
35 static int flg_buf_half = 0;
36 
37 static int flg_play = 0;
38 static int flg_audio_start = 0;
39 
40 static int volume = 30;
41 static int bufsize = MAX_AUDIOBUF;
42 static int flg_bs_chg = 0; // バッファサイズが変わった?フラグ
43 static int sampling_rate = I2S_AUDIOFREQ_48K;
44 static struct st_mutex audio_mutex;
45 static struct st_event tx_evq;
46 
47 extern SAI_HandleTypeDef haudio_out_sai;
48 
49 void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
50 {
51  if(flg_play != 0) {
52  flg_buf_half = 2;
53  }
54 }
55 
56 void BSP_AUDIO_OUT_HalfTransfer_CallBack(void)
57 {
58  if(flg_play != 0) {
59  flg_buf_half = 1;
60  }
61 }
62 
63 void BSP_AUDIO_OUT_Error_CallBack(void)
64 {
65  SYSERR_PRINT("AUDIO OUT Error\n");
66 }
67 
68 static void inthdr_audio(unsigned int intnum, void *sp)
69 {
70  HAL_DMA_IRQHandler(haudio_out_sai.hdmatx);
71 
72  event_wakeup_ISR(sp, &tx_evq, 0);
73 }
74 
75 static int audio_register(struct st_device *dev, char *param)
76 {
77  eventqueue_register_ISR(&tx_evq, "audio_tx", 0, 0, 0);
78 
79  register_interrupt(IRQ2VECT(AUDIO_OUT_SAIx_DMAx_IRQ), inthdr_audio);
80 
81  ts_dev = open_device(DEF_DEV_NAME_TS);
82  if(ts_dev != 0) {
83  tprintf("Touch sensor found\n");
84  }
85 
86  return 0;
87 }
88 
89 static void lock_ts(void)
90 {
91  if(ts_dev != 0) {
92  lock_device(ts_dev, 0);
93  }
94 }
95 
96 static void unlock_ts(void)
97 {
98  if(ts_dev != 0) {
99  unlock_device(ts_dev);
100  }
101 }
102 
103 static int audio_init(int vol, int smprate)
104 {
105  lock_ts();
106  if(BSP_AUDIO_OUT_Init(OUTPUT_DEVICE_HEADPHONE, vol, smprate) != AUDIO_OK) {
107  unlock_ts();
108  SYSERR_PRINT("AUDIO Init Error.\n");
109  return -1;
110  } else {
111  BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
112  HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, 0, 0);
113  unlock_ts();
114  }
115 
116  return 0;
117 }
118 
119 static int audio_open(struct st_device *dev)
120 {
121  audio_init(volume, sampling_rate);
122 
123  return 0;
124 }
125 
126 static int audio_close(struct st_device *dev)
127 {
128  lock_ts();
129  BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
130  BSP_AUDIO_OUT_DeInit();
131  unlock_ts();
132 
133  return 0;
134 }
135 
136 static int audio_write(struct st_device *dev, const void *data, unsigned int size)
137 {
138  long i;
139  const unsigned char *sp = data;
140  unsigned char *dp = &audio_buf[0];;
141  long len = size;
142 
143  if(flg_play == 0) {
144  DKPRINTF(0x02, "S");
145  if(len > bufsize) {
146  len = bufsize;
147  }
148  } else {
149  if(len > (bufsize/2)) {
150  len = (bufsize/2);
151  }
152  }
153 
154  if(flg_buf_half != 1) {
155  DKPRINTF(0x02, "F");
156  dp = &audio_buf[bufsize/2];
157  } else {
158  DKPRINTF(0x02, "H");
159  dp = &audio_buf[0];
160  }
161 
162  for(i=0; i<len; i++) {
163  if(dp >= &audio_buf[MAX_AUDIOBUF]) {
164  SYSERR_PRINT("Write buffer over %d %ld\n", bufsize, size);
165  break;
166  }
167  *dp = *sp;
168  dp ++;
169  sp ++;
170  }
171 
172  // 音データの最後のはずなので、残りは"0"で埋める(暫定)
173  if(len < (bufsize/2)) {
174  while(dp < &audio_buf[bufsize]) {
175  *dp = 0;
176  dp ++;
177  }
178  }
179 
180  flg_buf_half = 0;
181 
182  return len;
183 }
184 
185 static int audio_ioctl(struct st_device *dev, unsigned int com, unsigned int arg, void *param)
186 {
187  int rt = 0;
188 
189  switch(com) {
191  DKFPRINTF(0x01, "IOCMD_AUDIO_SET_VOLUME %ld\n", arg);
192  volume = arg;
193  if(flg_play) {
194  lock_ts();
195  if(BSP_AUDIO_OUT_SetVolume(volume) == AUDIO_OK) {
196  rt = 0;
197  } else {
198  rt = -1;
199  }
200  unlock_ts();
201  }
202  break;
203 
205  {
206  long *p_volume = (long *)param;
207  *p_volume = volume;
208  }
209  break;
210 
212  {
213  long *p_bufsize = (long *)param;
214  *p_bufsize = bufsize;
215  }
216  break;
217 
219  if(arg <= MAX_AUDIOBUF) {
220  if(bufsize != arg) {
221  flg_bs_chg = 1;
222  bufsize = arg;
223  //eprintf("bufsize = %d\n", bufsize);
224  }
225  }
226  break;
227 
229  if(flg_play == 0) {
230  flg_play = 1;
231  //audio_init(volume, sampling_rate);
232  if(flg_audio_start == 0) {
233  //eprintf("bufsize = %d\n", bufsize);
234  lock_ts();
235  BSP_AUDIO_OUT_Play((uint16_t*)audio_buf, bufsize);
236  unlock_ts();
237  flg_audio_start = 1;
238  } else {
239  lock_ts();
240  if(flg_bs_chg == 0) {
241  BSP_AUDIO_OUT_Resume();
242  } else {
243  BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
244  BSP_AUDIO_OUT_Play((uint16_t*)audio_buf, bufsize);
245  BSP_AUDIO_OUT_Resume();
246  flg_bs_chg = 0;
247  }
248  BSP_AUDIO_OUT_SetVolume(volume);
249  unlock_ts();
250  }
251  }
252  break;
253 
255  if(flg_play != 0) {
256  int i;
257  lock_ts();
258  //BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
259  BSP_AUDIO_OUT_Pause();
260  unlock_ts();
261  flg_play = 0;
262  flg_buf_half = 0;
263  for(i=0; i<MAX_AUDIOBUF; i++) {
264  audio_buf[i] = 0;
265  }
266  event_wakeup(&tx_evq, 0);
267  break;
268  }
269  break;
270 
272  return flg_play;
273  break;
274 
276  {
277  if(sampling_rate != arg) {
278  sampling_rate = arg;
279  lock_ts();
280  BSP_AUDIO_OUT_SetFrequency(sampling_rate);
281  unlock_ts();
282  }
283  }
284  break;
285 
287  {
288  long *p_sampling_rate = (long *)param;
289  *p_sampling_rate = sampling_rate;
290  }
291  break;
292 
294  {
295  unsigned char **p_audio_buf = (unsigned char **)param;
296  *p_audio_buf = audio_buf;
297  }
298  break;
299 
301  {
302  unsigned char **p_audio_buf = (unsigned char **)param;
303  event_wait(&tx_evq, 0, 0);
304  if(flg_buf_half != 1) {
305  DKPRINTF(0x02, "F");
306  *p_audio_buf = &audio_buf[bufsize/2];
307  } else {
308  DKPRINTF(0x02, "H");
309  *p_audio_buf = &audio_buf[0];
310  }
311  flg_buf_half = 0;
312  }
313  break;
314 
316  {
317  lock_ts();
318  if(arg == 0) {
319  BSP_AUDIO_OUT_SetMute(AUDIO_MUTE_OFF);
320  } else {
321  BSP_AUDIO_OUT_SetMute(AUDIO_MUTE_ON);
322  }
323  unlock_ts();
324  }
325  break;
326 
327  default:
328  SYSERR_PRINT("Unknow command %08lX arg %08lX\n", com, arg);
329  break;
330  }
331 
332  return rt;
333 }
334 
335 static int audio_select(struct st_device *dev, unsigned int timeout)
336 {
337  if(flg_play == 0) {
338  return (long)timeout;
339  } else {
340  return event_wait(&tx_evq, 0, timeout);
341  }
342 }
343 
344 const struct st_device audio_device = {
346  .explan = "STM32F769I-Disc Audio Out",
347  .register_dev = audio_register,
348  .mutex = &audio_mutex,
349  .open = audio_open,
350  .close = audio_close,
351  .write = audio_write,
352  .ioctl = audio_ioctl,
353  .select = audio_select,
354 };
#define IOCMD_AUDIO_PLAY_START
オーディオ再生を開始する
Definition: audio_ioctl.h:28
#define IOCMD_AUDIO_GET_BUFSIZE
オーディオバッファサイズを取得する
Definition: audio_ioctl.h:25
#define IOCMD_AUDIO_GET_BUFFER
オーディオバッファメモリアドレスを取得する
Definition: audio_ioctl.h:37
#define DEF_DEV_NAME_AUDIO
標準AUDIOデバイス名
Definition: audio_ioctl.h:16
#define DEF_DEV_NAME_TS
標準タッチセンサデバイス名
Definition: ts_ioctl.h:15
struct st_device * open_device(char *name)
デバイスをオープンする
Definition: device.c:262
void event_wakeup(struct st_event *evtque, void *arg)
イベントキューにイベントを登録する
Definition: syscall_api.c:453
#define IOCMD_AUDIO_SET_VOLUME
ボリュームを設定する
Definition: audio_ioctl.h:19
Audioドライバ ioctl 用マクロ定義
カーネルタイマ
タッチセンサドライバ ioctl 用マクロ定義
void eventqueue_register_ISR(struct st_event *evtque, const char *name, void *args, unsigned int arg_size, int arg_count)
イベントキューを登録する
Definition: event.c:36
void event_wakeup_ISR(void *sp, struct st_event *evtque, void *arg)
イベントキューにイベントを登録し、イベント待ちタスクを起動する
Definition: task.c:923
#define IOCMD_AUDIO_GET_STATUS
オーディオ再生状態を取得する
Definition: audio_ioctl.h:30
#define IOCMD_AUDIO_PLAY_STOP
オーディオ再生を停止
Definition: audio_ioctl.h:29
int unlock_device(struct st_device *dev)
デバイスをアンロックする
Definition: device.c:343
カーネル用機能限定printf
システムイベント
#define IOCMD_AUDIO_WAIT_BUFFER
オーディオバッファが空くのを待つ
Definition: audio_ioctl.h:38
#define IOCMD_AUDIO_SET_MUTE
ミュートを設定、解除する
Definition: audio_ioctl.h:21
MUTEX
Definition: mutex.h:13
#define IOCMD_AUDIO_SET_BUFSIZE
オーディオバッファサイズを設定する
Definition: audio_ioctl.h:24
イベント
Definition: event.h:15
#define IOCMD_AUDIO_SET_SMPRATE
サンプリングレートを設定する
Definition: audio_ioctl.h:33
int tprintf(const char *fmt,...)
簡易printf
Definition: tprintf.c:85
システムコール
#define IOCMD_AUDIO_GET_VOLUME
ボリュームを取得する
Definition: audio_ioctl.h:20
割り込みハンドラ
MUTEX制御
イベント待ちタスクキューの操作
#define IOCMD_AUDIO_GET_SMPRATE
サンプリングレートを取得する
Definition: audio_ioctl.h:34
デバイスドライバAPI
デバイスドライバ構造体
Definition: device.h:25
カーネル、ドライバ(非タスク)デバッグ用マクロ
char name[MAX_DEVNAMELRN]
デバイス名文字列
Definition: device.h:26
unsigned int size
1イベントのサイズ
Definition: event.h:19
機能限定printf
int lock_device(struct st_device *dev, unsigned int timeout)
デバイスをロックする
Definition: device.c:310
int event_wait(struct st_event *evtque, void *argp, unsigned int timeout)
タスクをイベント待ち状態にする
Definition: syscall_api.c:364