source: azure_iot_hub_f767zi/trunk/asp_baseplatform/pdic/stm32f7xx/sai.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 31.5 KB
Line 
1/*
2 * TOPPERS/ASP Kernel
3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
5 *
6 * Copyright (C) 2008-2011 by Embedded and Real-Time Systems Laboratory
7 * Graduate School of Information Science, Nagoya Univ., JAPAN
8 * Copyright (C) 2015-2018 by TOPPERS PROJECT Educational Working Group.
9 *
10 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
11 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
12 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
13 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
14 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
15 * スコード中に含まれていること.
16 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
17 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
18 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
19 * の無保証規定を掲載すること.
20 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
21 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
22 * と.
23 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
24 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
25 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
26 * 報告すること.
27 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
28 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
29 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
30 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
31 * 免責すること.
32 *
33 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
34 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
35 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
36 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
37 * の責任を負わない.
38 *
39 * @(#) $Id$
40 */
41/*
42 *
43 * AUDIOドライバ関数群
44 *
45 */
46#include "kernel_impl.h"
47#include <t_syslog.h>
48#include <t_stdlib.h>
49#include <sil.h>
50#include <target_syssvc.h>
51#include <string.h>
52#include "device.h"
53#include "sai.h"
54
55/*
56 * SIL関数のマクロ定義
57 */
58#define sil_orw_mem(a, b) sil_wrw_mem((a), sil_rew_mem(a) | (b))
59#define sil_andw_mem(a, b) sil_wrw_mem((a), sil_rew_mem(a) & ~(b))
60#define sil_modw_mem(a, b, c) sil_wrw_mem((a), (sil_rew_mem(a) & (~b)) | (c))
61
62/*
63 * AUDIOポートIDから管理ブロックを取り出すためのマクロ
64 */
65#define INDEX_AUDIO(id) ((uint_t)((id) - 1))
66
67#define SAI_TIMEOUT_VALUE (10*1000) /* 10ms */
68#define PLLI2S_TIMEOUT_VALUE 100 /* Timeout value fixed to 100 ms */
69#define EXTERNAL_CLOCK_VALUE 12288000 /* Value of the Internal oscillator in Hz*/
70
71#define FREQUENCY_44K 44100
72#define FREQUENCY_22K 22050
73#define FREQUENCY_11K 11025
74
75/*
76 * AUDIOポート設定テーブル
77 */
78static const AUDIO_PortControlBlock audio_pcb[NUM_AUDIOPORT] = {
79 { TADR_SAI1_BASE,
80 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_GPIOEEN,
81 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_GPIOGEN,
82 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_GPIOJEN,
83 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_DMA2EN,
84 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_DMA2EN,
85 (TADR_RCC_BASE+TOFF_RCC_APB2ENR), RCC_APB2ENR_SAI1EN,
86
87
88 TADR_GPIOE_BASE, TADR_GPIOG_BASE, TADR_GPIOE_BASE, TADR_GPIOJ_BASE,
89#ifdef TOPPERS_STM32F769_DISCOVERY
90 TADR_DMA2_STM3_BASE, DMA_CHANNEL_0, TADR_DMA2_STM4_BASE, DMA_CHANNEL_1,
91#else
92 TADR_DMA2_STM1_BASE, DMA_CHANNEL_0, TADR_DMA2_STM4_BASE, DMA_CHANNEL_1,
93#endif
94 7, 4, 5, 6, 3, 12, 0x06, 0x06},
95
96 { TADR_SAI2_BASE,
97 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_GPIOIEN,
98 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_GPIOGEN,
99#ifdef TOPPERS_STM32F723_DISCOVERY
100 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_GPIOGEN,
101#else
102 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_GPIOHEN,
103#endif
104 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_DMA2EN,
105 (TADR_RCC_BASE+TOFF_RCC_AHB1ENR), RCC_AHB1ENR_DMA2EN,
106 (TADR_RCC_BASE+TOFF_RCC_APB2ENR), RCC_APB2ENR_SAI2EN,
107
108
109#ifdef TOPPERS_STM32F723_DISCOVERY
110 TADR_GPIOI_BASE, TADR_GPIOI_BASE, TADR_GPIOG_BASE, TADR_GPIOG_BASE,
111 TADR_DMA2_STM4_BASE, DMA_CHANNEL_3, TADR_DMA2_STM6_BASE, DMA_CHANNEL_3,
112#else
113 TADR_GPIOI_BASE, TADR_GPIOI_BASE, TADR_GPIOG_BASE, TADR_GPIOH_BASE,
114 TADR_DMA2_STM4_BASE, DMA_CHANNEL_3, TADR_DMA2_STM7_BASE, DMA_CHANNEL_0,
115#endif
116 4, 7, 5, 6, 10, 15, 0x0A, 0x0A}
117};
118
119static AUDIO_Handle_t haudio_sai[NUM_AUDIOPORT];
120
121/*
122 * SAI1割込みハンドラ
123 */
124static void
125audio_exti1_int_handler(void)
126{
127 audio_irqhandler(&haudio_sai[0]);
128}
129
130/*
131 * SAI2割込みハンドラ
132 */
133static void
134audio_exti2_int_handler(void)
135{
136 audio_irqhandler(&haudio_sai[1]);
137}
138
139/*
140 * SAIベースブロック取出し関数
141 */
142static uint32_t
143audio_get_blockbase(AUDIO_Handle_t *haudio, uint32_t mode)
144{
145 if(haudio == NULL || mode > 1)
146 return 0;
147 return haudio->base + mode * SAI_WINDOW_SIZE + 4;
148}
149
150/*
151 * SAI BLOCKハードウェア起動
152 * parameter1 haudio:AUDIOハンドラ
153 * parameter2 mode:入出力モード
154 * return ERコード
155 */
156void
157audio_enable(AUDIO_Handle_t *haudio, uint32_t mode)
158{
159 uint32_t bbase = audio_get_blockbase(haudio, mode);
160
161 if(bbase == 0)
162 return;
163 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_SAIEN);
164}
165
166
167/*
168 * SAI BLOCKハードウェア停止
169 * parameter1 haudio:AUDIOハンドラ
170 * parameter2 mode:入出力モード
171 * return ERコード
172 */
173ER
174audio_disable(AUDIO_Handle_t *haudio, uint32_t mode)
175{
176 uint32_t tick = 0;
177 uint32_t bbase = audio_get_blockbase(haudio, mode);
178
179 if(bbase == 0)
180 return E_PAR;
181 sil_andw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_SAIEN);
182 while((sil_rew_mem((uint32_t *)(bbase+TOFF_SAI_CR1)) & SAI_xCR1_SAIEN) != 0){
183 if(tick > SAI_TIMEOUT_VALUE){ /* タイムアウト監視 */
184 haudio->ErrorCode |= AUDIO_ERROR_TIMEOUT;
185 return E_TMOUT;
186 }
187 sil_dly_nse(1000);
188 tick++;
189 }
190 return E_OK;
191}
192
193/*
194 * AUDIOドライバ初期化関数
195 * parammter1 id: ポートID
196 * return AUDIOハンドラ
197 */
198AUDIO_Handle_t *audio_init(ID id)
199{
200 static DMA_Handle_t hdma_sai_tx;
201 static DMA_Handle_t hdma_sai_rx;
202 GPIO_Init_t gpio_init_structure;
203 const AUDIO_PortControlBlock *apcb;
204 AUDIO_Handle_t *haudio;
205 DMA_Handle_t *hdma;
206 volatile uint32_t tmpreg;
207 uint32_t no;
208
209 if(id > NUM_AUDIOPORT)
210 return NULL;
211 no = INDEX_AUDIO(id);
212 apcb = &audio_pcb[no];
213 haudio = &haudio_sai[no];
214
215 memset(haudio, 0, sizeof(AUDIO_Handle_t));
216 haudio->base = apcb->base;
217 haudio->pcb = apcb;
218 /*
219 * SAIクロックイネーブル
220 */
221 sil_orw_mem((uint32_t *)apcb->audioclockbase, apcb->audioclockbit);
222 tmpreg = sil_rew_mem((uint32_t *)apcb->audioclockbase);
223
224 /*
225 * OUT GPIOクロックイネーブル
226 */
227 sil_orw_mem((uint32_t *)apcb->outgioclockbase, apcb->outgioclockbit);
228 tmpreg = sil_rew_mem((uint32_t *)apcb->outgioclockbase);
229
230 /*
231 * SAI FS, SCK, MCK,SDピン初期化
232 */
233 gpio_init_structure.mode = GPIO_MODE_AF;
234 gpio_init_structure.pull = GPIO_NOPULL;
235 gpio_init_structure.otype = GPIO_OTYPE_PP;
236 gpio_init_structure.speed = GPIO_SPEED_HIGH;
237 gpio_init_structure.alternate = apcb->outaf;
238 gpio_setup(apcb->giofsobase, &gpio_init_structure, apcb->outfspin);
239
240 gpio_init_structure.alternate = apcb->outaf;
241 gpio_setup(apcb->giofsobase, &gpio_init_structure, apcb->outsckin);
242
243 gpio_init_structure.alternate = apcb->outaf;
244 gpio_setup(apcb->giofsobase, &gpio_init_structure, apcb->outsdpin);
245
246 gpio_init_structure.alternate = apcb->outaf;
247 gpio_setup(apcb->giomcobase, &gpio_init_structure, apcb->outmsckpin);
248
249 /*
250 * OUT-DMAイネーブル
251 */
252 sil_orw_mem((uint32_t *)apcb->outdmaclockbase, apcb->outdmaclockbit);
253 tmpreg = sil_rew_mem((uint32_t *)apcb->outdmaclockbase);
254
255 hdma = &hdma_sai_tx;
256 hdma->Init.Channel = apcb->outdmachannel;
257 hdma->Init.Direction = DMA_MEMORY_TO_PERIPH;
258 hdma->Init.PeriphInc = DMA_PINC_DISABLE;
259 hdma->Init.MemInc = DMA_MINC_ENABLE;
260 hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
261 hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
262 hdma->Init.Mode = DMA_CIRCULAR;
263 hdma->Init.Priority = DMA_PRIORITY_HIGH;
264 hdma->Init.FIFOMode = DMA_FIFOMODE_ENABLE;
265 hdma->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
266 hdma->Init.MemBurst = DMA_MBURST_SINGLE;
267 hdma->Init.PeriphBurst = DMA_PBURST_SINGLE;
268 hdma->base = apcb->outdmabase;
269
270 /*
271 * OUT-DMA設定
272 */
273 haudio->hdmatx = hdma;
274 hdma->localdata = haudio;
275 dma_deinit(hdma);
276 dma_init(hdma);
277
278 /*
279 * SD GPIOクロック設定
280 */
281 sil_orw_mem((uint32_t *)apcb->ingioclockbase, apcb->ingioclockbit);
282 tmpreg = sil_rew_mem((uint32_t *)apcb->ingioclockbase);
283
284 /*
285 * SD GPIO設定
286 */
287 gpio_init_structure.mode = GPIO_MODE_AF;
288 gpio_init_structure.pull = GPIO_NOPULL;
289 gpio_init_structure.otype = GPIO_OTYPE_PP;
290 gpio_init_structure.speed = GPIO_SPEED_FAST;
291 gpio_init_structure.alternate = apcb->inaf;
292 gpio_setup(apcb->giosdibase, &gpio_init_structure, apcb->insdpin);
293
294 /*
295 * AUDIO-割込みGPIOクロック設定
296 */
297 sil_orw_mem((uint32_t *)apcb->intgioclockbase, apcb->intgioclockbit);
298 tmpreg = sil_rew_mem((uint32_t *)apcb->intgioclockbase);
299
300 /*
301 * AUDIO-割込みピンGPIO設定
302 */
303 gpio_init_structure.mode = GPIO_MODE_INPUT;
304 gpio_init_structure.pull = GPIO_NOPULL;
305 gpio_init_structure.speed = GPIO_SPEED_FAST;
306 gpio_setup(apcb->giointbase, &gpio_init_structure, apcb->inintpin);
307
308 /*
309 * IN-DMAクロック設定
310 */
311 sil_orw_mem((uint32_t *)apcb->indmaclockbase, apcb->indmaclockbit);
312 tmpreg = sil_rew_mem((uint32_t *)apcb->indmaclockbase);
313 ((void)(tmpreg));
314
315 hdma = &hdma_sai_rx;
316 hdma->Init.Channel = apcb->indmachannel;
317 hdma->Init.Direction = DMA_PERIPH_TO_MEMORY;
318 hdma->Init.PeriphInc = DMA_PINC_DISABLE;
319 hdma->Init.MemInc = DMA_MINC_ENABLE;
320 hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
321 hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
322 hdma->Init.Mode = DMA_CIRCULAR;
323 hdma->Init.Priority = DMA_PRIORITY_HIGH;
324 hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
325 hdma->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
326 hdma->Init.MemBurst = DMA_MBURST_SINGLE;
327 hdma->Init.PeriphBurst = DMA_MBURST_SINGLE;
328 hdma->base = apcb->indmabase;
329
330#ifndef TOPPERS_STM32F769_DISCOVERY
331 /*
332 * IN-DMA設定
333 */
334 haudio->hdmarx = hdma;
335 hdma->localdata = haudio;
336 dma_deinit(hdma);
337 dma_init(hdma);
338#endif
339
340 /*
341 * SAI割込み設定
342 */
343 if(no == 0)
344 exti_func[apcb->inintpin] = audio_exti1_int_handler;
345 else
346 exti_func[apcb->inintpin] = audio_exti2_int_handler;
347 return haudio;
348}
349
350/*
351 * AUDIOドライバ終了設定関数
352 * parameter1 haudio:AUDIOハンドラ
353 * parameter2 mode:入出力モード
354 */
355void
356audio_deinit(AUDIO_Handle_t *haudio, uint32_t mode)
357{
358 uint32_t bbase = audio_get_blockbase(haudio, mode);
359
360 if(bbase != 0 && haudio->pcb != NULL){
361 if(mode == AUDIO_OUT_BLOCK && haudio->hdmatx != NULL){
362 dma_deinit(haudio->hdmatx); /* OUT-DMA停止 */
363 }
364 if(mode == AUDIO_IN_BLOCK && haudio->hdmarx != NULL){
365 /* Deinitialize the DMA stream */
366 dma_deinit(haudio->hdmarx); /* IN-DMA停止 */
367 }
368
369 /*
370 * SAIハード、クロック停止
371 */
372 audio_disable(haudio, mode);
373 sil_andw_mem((uint32_t *)haudio->pcb->audioclockbase, haudio->pcb->audioclockbit);
374 }
375}
376
377
378/*
379 * AUDIO割込みフラグ取出し
380 * parameter1 haudio:AUDIOハンドラ
381 * parameter2 pini:初期化構造体
382 * return 割込みフラグ
383 */
384static uint32_t
385audio_interruptflag(AUDIO_Handle_t *haudio, SAI_Init_t *pini)
386{
387 if(pini->AudioMode == SAI_MODESLAVE_RX || pini->AudioMode == SAI_MODESLAVE_TX)
388 return SAI_xIMR_OVRUDRIE | SAI_xIMR_AFSDETIE | SAI_xIMR_LFSDETIE;
389 else
390 return SAI_xIMR_OVRUDRIE | SAI_xIMR_WCKCFGIE;
391}
392
393/*
394 * SAIの入力クロック取得
395 * parameter1 haudio:AUDIOハンドラ
396 * return SAI入力クロック
397 */
398static uint32_t
399audio_get_inputclock(AUDIO_Handle_t *haudio)
400{
401 uint32_t tmp = 0;
402 uint32_t cfgr = 0;
403 /* This variable used to store the SAI clock frequency (value in Hz) */
404 uint32_t frequency = 0;
405 /* This variable used to store the VCO Input (value in Hz) */
406 uint32_t vcoinput = 0;
407 /* This variable used to store the SAI clock source */
408 uint32_t configreg = sil_rew_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_PLLCFGR));
409 uint32_t clocksource = sil_rew_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_DCKCFGR1));
410
411 switch ((clocksource & (RCC_DCKCFGR1_SAI1SEL | RCC_DCKCFGR1_SAI2SEL))){
412 case 0: /* PLLSAI is the clock source for SAI*/
413 cfgr = sil_rew_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_PLLSAICFGR));
414 /* Configure the PLLSAI division factor */
415 /* PLLSAI_VCO Input = PLL_SOURCE/PLLM */
416 if((configreg & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSI){
417 /* In Case the PLL Source is HSI (Internal Clock) */
418 vcoinput = (HSI_VALUE / (uint32_t)(configreg & RCC_PLLCFGR_PLLM));
419 }
420 else{
421 /* In Case the PLL Source is HSE (External Clock) */
422 vcoinput = ((HSE_VALUE / (uint32_t)(configreg & RCC_PLLCFGR_PLLM)));
423 }
424 /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
425 /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
426 tmp = (cfgr & RCC_PLLSAICFGR_PLLSAIQ) >> 24;
427 frequency = (vcoinput * ((cfgr & RCC_PLLSAICFGR_PLLSAIN) >> 6))/(tmp);
428
429 /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
430 frequency = frequency/(((clocksource & RCC_DCKCFGR1_PLLSAIDIVQ) >> 8) + 1);
431 break;
432 case RCC_DCKCFGR1_SAI1SEL_0: /* PLLI2S is the clock source for SAI*/
433 case RCC_DCKCFGR1_SAI2SEL_0: /* PLLI2S is the clock source for SAI*/
434 cfgr = sil_rew_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_PLLI2SCFGR));
435 /* Configure the PLLI2S division factor */
436 /* PLLI2S_VCO Input = PLL_SOURCE/PLLM */
437 if((configreg & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSI){
438 /* In Case the PLL Source is HSI (Internal Clock) */
439 vcoinput = (HSI_VALUE / (uint32_t)(configreg & RCC_PLLCFGR_PLLM));
440 }
441 else{
442 /* In Case the PLL Source is HSE (External Clock) */
443 vcoinput = ((HSE_VALUE / (uint32_t)(configreg & RCC_PLLCFGR_PLLM)));
444 }
445
446 /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
447 /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
448 tmp = (cfgr & RCC_PLLI2SCFGR_PLLI2SQ) >> 24;
449 frequency = (vcoinput * ((cfgr & RCC_PLLI2SCFGR_PLLI2SN) >> 6))/tmp;
450
451 /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
452 frequency = frequency/((clocksource & RCC_DCKCFGR1_PLLI2SDIVQ) + 1);
453 break;
454 case RCC_DCKCFGR1_SAI1SEL_1: /* External clock is the clock source for SAI*/
455 case RCC_DCKCFGR1_SAI2SEL_1: /* External clock is the clock source for SAI*/
456 frequency = EXTERNAL_CLOCK_VALUE;
457 break;
458 default :
459 break;
460 }
461 return frequency;
462}
463
464/*
465 * SAIクロックコンフィグレーション
466 * parameter1 haudio:AUDIOハンドラ
467 * parameter2 AudioFreq: Audio周波数
468 * parameter3 Params: 補助パラメータポインタ
469 */
470void
471audio_clockconfig(AUDIO_Handle_t *haudio, uint32_t AudioFreq, void *Params)
472{
473 uint32_t PLLI2SN, PLLI2SQ, PLLI2SDivQ;
474 uint32_t tick = 0;
475
476 /*
477 * AUDIO周波数からPLL設定値の取得
478 */
479 if((AudioFreq == FREQUENCY_11K) || (AudioFreq == FREQUENCY_22K) || (AudioFreq == FREQUENCY_44K)){
480 /* Configure PLLI2S prescalers */
481 /* PLLI2S_VCO: VCO_429M
482 I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 429/2 = 214.5 Mhz
483 I2S_CLK_x = I2S_CLK(first level)/PLLI2SDIVQ = 214.5/19 = 11.289 Mhz */
484 PLLI2SN = 429;
485 PLLI2SQ = 2;
486 PLLI2SDivQ = 19;
487 }
488 else /* FREQUENCY_8K, FREQUENCY_16K, FREQUENCY_48K, FREQUENCY_96K */{
489 /* I2S clock config
490 PLLI2S_VCO: VCO_344M
491 I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz
492 I2S_CLK_x = I2S_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */
493 PLLI2SN = 344;
494 PLLI2SQ = 7;
495 PLLI2SDivQ = 1;
496 }
497
498 /*
499 * SAI1/2クロック設定
500 */
501 if(haudio->base == TADR_SAI1_BASE){
502 sil_modw_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_DCKCFGR1), RCC_DCKCFGR1_SAI1SEL, RCC_DCKCFGR1_SAI1SEL_0);
503 }
504 else{
505 sil_modw_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_DCKCFGR1), RCC_DCKCFGR1_SAI2SEL, RCC_DCKCFGR1_SAI2SEL_0);
506 }
507
508 /*
509 * PLLI2Sデゼーブル
510 */
511 sil_andw_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_CR), RCC_CR_PLLI2SON);
512
513 /*
514 * PLLI2S停止待ち
515 */
516 tick = 0;
517 while((sil_rew_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_CR)) & RCC_CR_PLLI2SRDY) != 0){
518 if(tick > PLLI2S_TIMEOUT_VALUE){
519 return; /* タイムアウトエラー */
520 }
521 dly_tsk(1);
522 tick++;
523 }
524
525 /*
526 * PLLI2SSN/PLLI2SN値設定
527 */
528 sil_modw_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_PLLI2SCFGR), (RCC_PLLI2SCFGR_PLLI2SN | RCC_PLLI2SCFGR_PLLI2SQ), ((PLLI2SN << 6) | (PLLI2SQ << 24)));
529
530 /*
531 * PLLI2SDIVQ設定
532 */
533 sil_modw_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_DCKCFGR1), RCC_DCKCFGR1_PLLI2SDIVQ, (PLLI2SDivQ-1));
534
535 /*
536 * PLLI2Sイネーブル
537 */
538 sil_orw_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_CR), RCC_CR_PLLI2SON);
539
540 /*
541 * PLLI2S再開待ち
542 */
543 tick = 0;
544 while((sil_rew_mem((uint32_t *)(TADR_RCC_BASE+TOFF_RCC_CR)) & RCC_CR_PLLI2SRDY) == 0){
545 if(tick > PLLI2S_TIMEOUT_VALUE){
546 return; /* タイムアウトエラー */
547 }
548 dly_tsk(1);
549 tick++;
550 }
551}
552
553/*
554 * AUDIO動作開始関数
555 * parameter1 haudio:AUDIOハンドラ
556 * parameter2 mode:入出力モード
557 * return ERコード
558 */
559ER
560audio_start(AUDIO_Handle_t *haudio, uint32_t mode)
561{
562 ER ercd = E_OK;
563 SAI_Init_t *pini;
564 uint32_t gcr = 0;
565 uint32_t bbase = audio_get_blockbase(haudio, mode);
566
567 if(bbase == 0)
568 return E_PAR;
569
570 if(mode == AUDIO_OUT_BLOCK)
571 pini = &haudio->OutInit;
572 else
573 pini = &haudio->InInit;
574
575 /*
576 * SAIハードウェア停止
577 */
578 ercd = audio_disable(haudio, mode);
579 if(ercd != E_OK)
580 return ercd;
581
582 /*
583 * ジェネラルコンフィグレーションレジスタ設定
584 */
585 switch(pini->SynchroExt){
586 case SAI_SYNCEXT_DISABLE:
587 gcr = 0;
588 break;
589 case SAI_SYNCEXT_IN_ENABLE:
590 gcr = SAI_GCR_SYNCIN_0;
591 break;
592 case SAI_SYNCEXT_OUTBLOCKA_ENABLE:
593 gcr = SAI_GCR_SYNCOUT_0;
594 break;
595 case SAI_SYNCEXT_OUTBLOCKB_ENABLE:
596 gcr = SAI_GCR_SYNCOUT_1;
597 break;
598 default :
599 break;
600 }
601 sil_wrw_mem((uint32_t *)(haudio->base+TOFF_SAI_GCR), gcr);
602
603 /*
604 * マスタクロックデバイダ再設定
605 * MCKDIV[3:0] = SAI_CK_x / FS * 512
606 */
607 if(pini->AudioFrequency != 0){
608 uint32_t clock;
609
610 clock = (((audio_get_inputclock(haudio) * 10) / ((pini->AudioFrequency) * 512)));
611 pini->Mckdiv = clock / 10;
612 if((clock % 10) > 8){ /* 9を切り上げ */
613 pini->Mckdiv++;
614 }
615 }
616
617 /*
618 * SAI CR1設定
619 */
620 sil_modw_mem((uint32_t *)(bbase+TOFF_SAI_CR1),
621 (SAI_xCR1_MODE | SAI_xCR1_PRTCFG | SAI_xCR1_DS | SAI_xCR1_LSBFIRST | SAI_xCR1_CKSTR |
622 SAI_xCR1_SYNCEN | SAI_xCR1_MONO | SAI_xCR1_OUTDRIV | SAI_xCR1_DMAEN | SAI_xCR1_NODIV | SAI_xCR1_MCKDIV),
623 (pini->AudioMode | pini->Protocol | pini->DataSize | pini->FirstBit |
624 pini->ClockStrobing | pini->Synchro | pini->MonoStereoMode | pini->OutputDrive |
625 pini->NoDivider | (pini->Mckdiv << 20) | pini->CompandingMode));
626
627 /*
628 * SAI CR2設定
629 */
630 sil_modw_mem((uint32_t *)(bbase+TOFF_SAI_CR2),
631 (SAI_xCR2_FTH | SAI_xCR2_TRIS | SAI_xCR2_COMP),
632 (pini->FIFOThreshold | pini->CompandingMode | pini->TriState));
633
634 /*
635 * SAI フレーム設定
636 */
637 sil_modw_mem((uint32_t *)(bbase+TOFF_SAI_FRCR),
638 (SAI_xFRCR_FRL | SAI_xFRCR_FSALL | SAI_xFRCR_FSDEF | SAI_xFRCR_FSPO | SAI_xFRCR_FSOFF),
639 ((pini->FrameLength - 1) | pini->FSOffset | pini->FSDefinition |
640 pini->FSPolarity | ((pini->ActiveFrameLength - 1) << 8)));
641
642 /*
643 * SAIブロックスロット設定
644 */
645 sil_modw_mem((uint32_t *)(bbase+TOFF_SAI_SLOTR),
646 (SAI_xSLOTR_FBOFF | SAI_xSLOTR_SLOTSZ | SAI_xSLOTR_NBSLOT | SAI_xSLOTR_SLOTEN),
647 (pini->FirstBitOffset | pini->SlotSize | ((pini->SlotNumber - 1) << 8)) | pini->SlotActive);
648
649 /*
650 * エラー設定初期化
651 */
652 haudio->ErrorCode = AUDIO_ERROR_NONE;
653
654 /*
655 * ステータス設定
656 */
657 haudio->status[mode] = AUDIO_STATUS_READY;
658 return ercd;
659}
660
661
662/*
663 * AUDIO動作停止関数
664 * parameter1 haudio:AUDIOハンドラ
665 * parameter2 mode:入出力モード
666 * return ERコード
667 */
668ER
669audio_end(AUDIO_Handle_t *haudio, uint32_t mode)
670{
671 ER ercd = E_OK;
672 uint32_t bbase = audio_get_blockbase(haudio, mode);
673
674 if(bbase == 0)
675 return E_PAR;
676
677 /*
678 * 割込みとフラグクリア、SAI停止
679 */
680 sil_wrw_mem((uint32_t *)(bbase+TOFF_SAI_IMR), 0);
681 sil_wrw_mem((uint32_t *)(bbase+TOFF_SAI_CLRFR), 0xFFFFFFFF);
682 ercd = audio_disable(haudio, mode);
683
684 /*
685 * FIFOをフラッシュ
686 */
687 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR2), SAI_xCR2_FFLUSH);
688
689 /*
690 * エラー設定初期化
691 */
692 haudio->ErrorCode = AUDIO_ERROR_NONE;
693
694 /*
695 * ステータスをリセットに戻す
696 */
697 haudio->status[mode] = AUDIO_STATUS_RESET;
698 return ercd;
699}
700
701/*
702 * AUDIO 送信DMA完了コールバック関数
703 * parameter1 hdma: DMAハンドラ
704 */
705static void
706audio_dmatx_tran(DMA_Handle_t *hdma)
707{
708 uint32_t tick = 0;
709 uint32_t bbase;
710
711 AUDIO_Handle_t* haudio = (AUDIO_Handle_t*)((DMA_Handle_t* )hdma)->localdata;
712
713 bbase = audio_get_blockbase(haudio, AUDIO_OUT_BLOCK);
714 if((sil_rew_mem((uint32_t *)(hdma->base+TOFF_DMAS_CR)) & DMA_SxCR_CIRC) == 0){
715 /*
716 * 送信DMAを停止
717 */
718 sil_andw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_DMAEN);
719
720 /*
721 * FIFOが空になるまで待ち
722 */
723 while((sil_rew_mem((uint32_t *)(bbase+TOFF_SAI_SR)) & SAI_xSR_FLVL) != 0){
724 /* Check for the Timeout */
725 if(tick > SAI_TIMEOUT_VALUE){
726 /*
727 * タイムアウトエラー設定
728 */
729 haudio->ErrorCode |= AUDIO_ERROR_TIMEOUT;
730 if(haudio->errorcallback != NULL)
731 haudio->errorcallback(haudio);
732 }
733 tick++;
734 sil_dly_nse(1000);
735 }
736
737 /*
738 * エラー割込み停止
739 */
740 sil_andw_mem((uint32_t *)(bbase+TOFF_SAI_IMR), audio_interruptflag(haudio, &haudio->OutInit));
741 haudio->status[AUDIO_OUT_BLOCK] = AUDIO_STATUS_READY;
742 haudio->XferCount = 0;
743 }
744 if(haudio->transcallback != NULL)
745 haudio->transcallback(haudio);
746}
747
748/*
749 * AUDIO 送信DMAハーフコールバック関数
750 * parameter1 hdma: DMAハンドラ
751 */
752static void
753audio_dmatx_halftran(DMA_Handle_t *hdma)
754{
755 AUDIO_Handle_t* haudio = (AUDIO_Handle_t*)((DMA_Handle_t*)hdma)->localdata;
756
757 if(haudio->transhalfcallback != NULL)
758 haudio->transhalfcallback(haudio);
759}
760
761/*
762 * AUDIO 送信DMAエラーコールバック関数
763 * parameter1 hdma: DMAハンドラ
764 */
765static void
766audio_dmatx_error(DMA_Handle_t *hdma)
767{
768 AUDIO_Handle_t* haudio = ( AUDIO_Handle_t*)((DMA_Handle_t* )hdma)->localdata;
769
770 /*
771 * 送信DMA停止
772 */
773 audio_dmastop(haudio, AUDIO_OUT_BLOCK);
774
775 /*
776 * ステータスをレディに戻す
777 */
778 haudio->status[AUDIO_OUT_BLOCK] = AUDIO_STATUS_READY;
779 if(haudio->errorcallback != NULL)
780 haudio->errorcallback(haudio);
781 haudio->XferCount = 0;
782}
783
784/*
785 * AUDIO 受信DMA完了コールバック関数
786 * parameter1 hdma: DMAハンドラ
787 */
788static void
789audio_dmarx_recv(DMA_Handle_t *hdma)
790{
791 AUDIO_Handle_t* haudio = ( AUDIO_Handle_t* )((DMA_Handle_t* )hdma)->localdata;
792 uint32_t bbase;
793
794 bbase = audio_get_blockbase(haudio, AUDIO_IN_BLOCK);
795 if((sil_rew_mem((uint32_t *)(hdma->base+TOFF_DMAS_CR)) & DMA_SxCR_CIRC) == 0){
796 /*
797 * 受信DMA停止
798 */
799 sil_andw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_DMAEN);
800
801 /*
802 * エラー割込み停止
803 */
804 sil_andw_mem((uint32_t *)(bbase+TOFF_SAI_IMR), audio_interruptflag(haudio, &haudio->InInit));
805
806 haudio->status[AUDIO_IN_BLOCK] = AUDIO_STATUS_READY;
807 haudio->XferCount = 0;
808 }
809 if(haudio->recevcallback != NULL)
810 haudio->recevcallback(haudio);
811}
812
813/*
814 * AUDIO 受信DMAハーフコールバック関数
815 * parameter1 hdma: DMAハンドラ
816 */
817static void
818audio_dmarx_recvhalf(DMA_Handle_t *hdma)
819{
820 AUDIO_Handle_t* haudio = (AUDIO_Handle_t*)((DMA_Handle_t*)hdma)->localdata;
821
822 if(haudio->recevhalfcallback != NULL)
823 haudio->recevhalfcallback(haudio);
824}
825
826/*
827 * AUDIO 受信DMAエラーコールバック関数
828 * parameter1 hdma: DMAハンドラ
829 */
830static void
831audio_dmarx_error(DMA_Handle_t *hdma)
832{
833 AUDIO_Handle_t* haudio = ( AUDIO_Handle_t* )((DMA_Handle_t* )hdma)->localdata;
834
835 /*
836 * 受信DMA停止
837 */
838 audio_dmastop(haudio, AUDIO_IN_BLOCK);
839
840 /*
841 * ステータスをレディに戻す
842 */
843 haudio->status[AUDIO_IN_BLOCK]= AUDIO_STATUS_READY;
844 if(haudio->errorcallback != NULL)
845 haudio->errorcallback(haudio);
846 haudio->XferCount = 0;
847}
848
849
850/*
851 * AUDIOデータ送信
852 * parameter1 haudio:AUDIOハンドラ
853 * parameter2 pData:送信データ領域
854 * parameter3 Size:送信データサイズ
855 * return ERコード
856 */
857ER
858audio_transmit(AUDIO_Handle_t *haudio, uint8_t *pData, uint16_t Size)
859{
860 uint32_t bbase = audio_get_blockbase(haudio, AUDIO_OUT_BLOCK);
861
862 if(pData == NULL || Size == 0 || bbase == 0)
863 return E_PAR;
864
865 if(haudio->status[AUDIO_OUT_BLOCK] != AUDIO_STATUS_READY)
866 return E_OBJ;
867
868 haudio->pBuffPtr = pData;
869 haudio->XferSize = Size;
870 haudio->XferCount = Size;
871 haudio->status[AUDIO_OUT_BLOCK] = AUDIO_STATUS_BUSY_TX;
872
873 /*
874 * DMAコールバック関数設定
875 */
876 haudio->hdmatx->xferhalfcallback = audio_dmatx_halftran;
877 haudio->hdmatx->xfercallback = audio_dmatx_tran;
878 haudio->hdmatx->errorcallback = audio_dmatx_error;
879
880 /*
881 * 送信DMA起動
882 */
883 dma_start(haudio->hdmatx, (uint32_t)pData, bbase+TOFF_SAI_DR, haudio->XferSize);
884
885 /*
886 * SAI起動
887 */
888 if((sil_rew_mem((uint32_t *)(bbase+TOFF_SAI_CR1)) & SAI_xCR1_SAIEN) == 0){
889 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_SAIEN);
890 }
891
892 /*
893 * エラー割込み設定
894 */
895 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_IMR), audio_interruptflag(haudio, &haudio->OutInit));
896
897 /*
898 * SAI送信DMA要求
899 */
900 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_DMAEN);
901 return E_OK;
902}
903
904/*
905 * AUDIOデータ受信
906 * parameter1 haudio:AUDIOハンドラ
907 * parameter2 pData:受信データ領域
908 * parameter3 Size:受信データサイズ
909 * return ERコード
910 */
911ER
912audio_receive(AUDIO_Handle_t *haudio, uint8_t *pData, uint16_t Size)
913{
914 uint32_t bbase = audio_get_blockbase(haudio, AUDIO_IN_BLOCK);
915
916 if(pData == NULL || Size == 0 || bbase == 0)
917 return E_PAR;
918
919 if(haudio->status[AUDIO_IN_BLOCK] != AUDIO_STATUS_READY)
920 return E_OBJ;
921
922 haudio->pBuffPtr = pData;
923 haudio->XferSize = Size;
924 haudio->XferCount = Size;
925
926 haudio->status[AUDIO_IN_BLOCK] = AUDIO_STATUS_BUSY_RX;
927
928 /*
929 * DMAコールバック関数設定
930 */
931 haudio->hdmarx->xferhalfcallback = audio_dmarx_recvhalf;
932 haudio->hdmarx->xfercallback = audio_dmarx_recv;
933 haudio->hdmarx->errorcallback = audio_dmarx_error;
934
935 /*
936 * 受信DMA起動
937 */
938 dma_start(haudio->hdmarx, bbase+TOFF_SAI_DR, (uint32_t)pData, haudio->XferSize);
939
940 /*
941 * SAI起動
942 */
943 if((sil_rew_mem((uint32_t *)(bbase+TOFF_SAI_CR1)) & SAI_xCR1_SAIEN) == 0){
944 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_SAIEN);
945 }
946
947 /*
948 * エラー割込み設定
949 */
950 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_IMR), audio_interruptflag(haudio, &haudio->InInit));
951
952 /*
953 * SAI受信DMA要求
954 */
955 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_DMAEN);
956 return E_OK;
957}
958
959/*
960 * AUDIOポーズ
961 * parameter1 haudio:AUDIOハンドラ
962 * parameter2 mode:入出力モード
963 * return ERコード
964 */
965ER
966audio_dmapause(AUDIO_Handle_t *haudio, uint32_t mode)
967{
968 uint32_t bbase = audio_get_blockbase(haudio, mode);
969
970 if(bbase == 0)
971 return E_PAR;
972 sil_andw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_DMAEN);
973 return E_OK;
974}
975
976/*
977 * AUDIOレジューム
978 * parameter1 haudio:AUDIOハンドラ
979 * parameter2 mode:入出力モード
980 * return ERコード
981 */
982ER
983audio_dmaresume(AUDIO_Handle_t *haudio, uint32_t mode)
984{
985 uint32_t bbase = audio_get_blockbase(haudio, mode);
986
987 if(bbase == 0)
988 return E_PAR;
989
990 /*
991 * SAI-DMA要求
992 */
993 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_DMAEN);
994
995 /*
996 * SAI起動
997 */
998 if ((sil_rew_mem((uint32_t *)(bbase+TOFF_SAI_CR1)) & SAI_xCR1_SAIEN) == 0){
999 sil_orw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_SAIEN);
1000 }
1001 return E_OK;
1002}
1003
1004/*
1005 * AUDIO用DMA停止
1006 * parameter1 haudio:AUDIOハンドラ
1007 * parameter2 mode:入出力モード
1008 * return ERコード
1009 */
1010ER
1011audio_dmastop(AUDIO_Handle_t *haudio, uint32_t mode)
1012{
1013 ER ercd = E_OK;
1014 uint32_t bbase = audio_get_blockbase(haudio, mode);
1015
1016 if(bbase == 0)
1017 return E_PAR;
1018 /*
1019 * SAI-DMA停止
1020 */
1021 sil_andw_mem((uint32_t *)(bbase+TOFF_SAI_CR1), SAI_xCR1_DMAEN);
1022
1023 /*
1024 * 送信モードなら送信DMA停止
1025 */
1026 if(haudio->hdmatx != NULL && mode == AUDIO_OUT_BLOCK){
1027 dma_end(haudio->hdmatx);
1028 }
1029
1030 /*
1031 * 受信モードなら受信DMA停止
1032 */
1033 if(haudio->hdmarx != NULL && mode == AUDIO_IN_BLOCK){
1034 dma_end(haudio->hdmarx);
1035 }
1036
1037 /*
1038 * SAI停止
1039 */
1040 ercd = audio_disable(haudio, mode);
1041
1042 haudio->status[mode] = AUDIO_STATUS_READY;
1043 return ercd;
1044}
1045
1046/*
1047 * AUDIOハンドラ取出し
1048 * parameter1: id ポートID
1049 */
1050AUDIO_Handle_t *
1051audio_gethandle(ID id)
1052{
1053 return &haudio_sai[INDEX_AUDIO(id)];
1054}
1055
1056/*
1057 * AUDIOステータスの取出し
1058 * parameter1 haudio:AUDIOハンドラ
1059 * parameter2 mode:入出力モード
1060 * return AUDIOステータス
1061 */
1062uint32_t
1063audio_status(AUDIO_Handle_t *haudio, uint32_t mode)
1064{
1065 return haudio->status[mode];
1066}
1067
1068/*
1069 * AUDIO割込みハンドラ
1070 * parameter1 haudio:AUDIOハンドラ
1071 */
1072void
1073audio_irqhandler(AUDIO_Handle_t *haudio)
1074{
1075 uint32_t bbase, mode;
1076 uint32_t sr, imr;
1077
1078 for(mode = AUDIO_OUT_BLOCK ; mode <= AUDIO_IN_BLOCK ; mode++){
1079 bbase = audio_get_blockbase(haudio, mode);
1080 sr = sil_rew_mem((uint32_t *)(bbase+TOFF_SAI_SR));
1081 imr = sil_rew_mem((uint32_t *)(bbase+TOFF_SAI_IMR));
1082
1083 /*
1084 * 割込みステータス確認
1085 */
1086 if(sr != 0x00000000){
1087 /*
1088 * オーバーラン/アンダーランチェック
1089 */
1090 if((sr & SAI_xSR_OVRUDR) != 0 && (imr & SAI_xIMR_OVRUDRIE) != 0){
1091 sil_wrw_mem((uint32_t *)(bbase+TOFF_SAI_CLRFR), SAI_xSR_OVRUDR);
1092 haudio->ErrorCode = AUDIO_ERROR_OVRUDR;
1093 if(haudio->audioerrorcallback != NULL)
1094 haudio->audioerrorcallback(haudio, mode);
1095 }
1096
1097 /*
1098 * MUTE割込みチェック
1099 */
1100 if((sr & SAI_xSR_MUTEDET) != 0 && (imr & SAI_xIMR_MUTEDETIE) != 0){
1101 sil_wrw_mem((uint32_t *)(bbase+TOFF_SAI_CLRFR), SAI_xSR_MUTEDET);
1102 if(haudio->audiomutecallback != NULL)
1103 haudio->audiomutecallback(haudio, mode);
1104 }
1105
1106 /*
1107 * AFSDET割込みチェック
1108 */
1109 if((sr & SAI_xSR_AFSDET) != 0 && (imr & SAI_xIMR_AFSDETIE) != 0){
1110 haudio->ErrorCode = AUDIO_ERROR_AFSDET;
1111 if(haudio->audioerrorcallback != NULL)
1112 haudio->audioerrorcallback(haudio, mode);
1113 }
1114
1115 /*
1116 * LFSDET割込みチェック
1117 */
1118 if((sr & SAI_xSR_LFSDET) != 0 && (imr & SAI_xIMR_LFSDETIE) != 0){
1119 haudio->ErrorCode = AUDIO_ERROR_LFSDET;
1120 if(haudio->audioerrorcallback != NULL)
1121 haudio->audioerrorcallback(haudio, mode);
1122 }
1123
1124 /*
1125 * WCKCFG割込みチェック
1126 */
1127 if((sr & SAI_xSR_WCKCFG) != 0 && (imr & SAI_xIMR_WCKCFGIE) != 0){
1128 haudio->ErrorCode = AUDIO_ERROR_WCKCFG;
1129 if(haudio->audioerrorcallback != NULL)
1130 haudio->audioerrorcallback(haudio, mode);
1131 }
1132 }
1133 }
1134}
1135
1136
Note: See TracBrowser for help on using the repository browser.