diff --git a/build/libraries/mic/ARM7/Makefile b/build/libraries/mic/ARM7/Makefile new file mode 100644 index 0000000..5be8cca --- /dev/null +++ b/build/libraries/mic/ARM7/Makefile @@ -0,0 +1,56 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - libraries - camera/ARM7 +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: $ +# $NoKeywords: $ +#---------------------------------------------------------------------------- + +SUBDIRS = + + +#---------------------------------------------------------------------------- + +# build ARM & THUMB libraries +TWL_CODEGEN_ALL ?= True + +# Codegen for sub processer +TWL_PROC = ARM7 + +SRCDIR = ./src + +SRCS = twl_mic_server.c twl_mic_api.c + +TARGET_LIB = libtwlmic_sp$(TWL_LIBSUFFIX).a + +#---------------------------------------------------------------------------- + +# DEBUG版ビルドの場合、RELEASE版でビルドして +# DEBUG版のライブラリを装います。 + +ifdef NITRO_DEBUG +NITRO_BUILD_TYPE = RELEASE +endif + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(TWL_INSTALL_LIBDIR) + + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + +#===== End of Makefile ===== diff --git a/build/libraries/mic/ARM7/src/twl_mic_api.c b/build/libraries/mic/ARM7/src/twl_mic_api.c new file mode 100644 index 0000000..af39a24 --- /dev/null +++ b/build/libraries/mic/ARM7/src/twl_mic_api.c @@ -0,0 +1,481 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - library - twlmic + File: twl_mic_api.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: $ + $NoKeywords: $ + *---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------* + 現在未実装の機能として以下の2つがあります。 + ・Auto Gain Control (ゲイン自動調節機能) + ・IIR Filter (音声入出力フィルタ : High/Low Pass Filter など) + + 但し、これらの機能は CODEC のセカンドソース品でも互換性を保てるか + どうか確認がとれていないため、ボツる可能性もあります。 + ----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------* + +≪TWLにおけるマイクデータの拾い方≫ + +現在は FIFO Half DMA起動方式 を実装。 + + +★★ FIFO Half DMA起動方式 ★★ + +ブロック転送サイズ  :8ワード +インターバル     :0 +転送ワード      :8ワード +総転送ワード     :バッファサイズ +コンティニュアスモード:OFF + +<解説> + +FIFOに半分データが溜まる度にDMA起動要求がかかり +8ワード転送される。 +バッファサイズ分の転送が完了後に割り込みがかかるので +そこでDMAを再設定。 + +<メリット> +・FIFOとDMAのタイミングがきっちりと合う。 +・色々な周波数に対応しやすい。 + +<デメリット> +・DMAがどこまで進んだか分からないためMIC_GetLastSamplingAddress + で正確なアドレスが取れない。チックを使用して大体の位置を + 予測することは可能。 + +★★ インターバル方式 ★★ + +ブロック転送サイズ  :8ワード +インターバル     :適切値 +転送ワード      :バッファサイズ +総転送ワード     :バッファサイズ +コンティニュアスモード:ON + +<解説> + +周波数からFIFOにデータが溜まるタイミングを逆算し、 +インターバルを使って見込みでブロックDMAを実行する。 +すこしずつDMAとFIFOのタイミングがずれていく可能性 +があるが、バッファサイズ転送毎に再同期が可能。 + +<メリット> +・DMAの再設定が必要ない + +<デメリット> +・他のDMAによりFIFOとのタイミングがずれていく可能性がある。 +・そのため大きなバッファサイズには向かない +・DMAがどこまで進んだか分からないためMIC_GetLastSamplingAddress + で正確なアドレスが取れない。チックを使用して大体の位置を + 予測することは可能。 + +★★ 割り込み頻発方式 ★★ + +<解説> + +FIFOにデータが半分溜まる度にMIC割り込みを発生させ +FIFOからCPUで8ワード取得する。 + +<メリット> +・バッファのどの位置まで進んだかを正確に把握可能。 + MIC_GetLastSamplingAddressで正確なアドレスを返すことができる。 + +<デメリット> +・頻繁に割り込みが発生する。といってもその頻度はDS時代の1/16になる。 +・そもそもMIC_GetLastSamplingAddressに有用性がないならこの方式はありえない。 + + ----------------------------------------------------------------------------*/ + +#include +#include +#include +#include + +/*---------------------------------------------------------------------------* + マクロ定義 + *---------------------------------------------------------------------------*/ + +#define TWL_MIC_TICK_INIT_VALUE 0 + +/*---------------------------------------------------------------------------* + 静的変数定義 + *---------------------------------------------------------------------------*/ + +static TWLMICParam sMicParam; // パラメータ保存用 +static OSTick sMicTickStart; // サンプリング開始時Tick +static OSTick sMicTickStop; // サンプリング停止時Tick + +/*---------------------------------------------------------------------------* + 内部関数定義 + *---------------------------------------------------------------------------*/ + +static void TWL_MICi_ExDmaRecvAsync( u32 dmaNo, void *dest, u32 size ); +static void TWL_MICi_ExDmaInterruptHandler( void ); +static void TWL_MICi_FifoInterruptHandler( void ); + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_DoSampling + + Description: 単発(16bit)のサンプリングを行います。 + + Arguments: buffer : サンプリング結果を格納するバッファ + + Returns: None + *---------------------------------------------------------------------------*/ +void +TWL_MIC_DoSampling( u16* buffer ) +{ + u32 word; + const u32 WAIT_MAX = 100; + u32 i; + + // 引数チェック + SDK_NULL_ASSERT( buffer ); + + // サウンド & I2S 回路ON + SND_Enable(); + + // モノラルサンプリングスタート + reg_SND_MICCNT = REG_SND_MICCNT_FIFO_CLR_MASK; + reg_SND_MICCNT = (u16)(REG_SND_MICCNT_E_MASK | REG_SND_MICCNT_NR_MASK | + MIC_INTR_DISABLE | MIC_SMP_ALL ); + + // データが2個以上入るのを待つ + for (i=0;i= MI_EXDMA_CH_MIN && param.dmaNo <= MI_EXDMA_CH_MAX ); + SDK_NULL_ASSERT( param.buffer ); + + // DMA停止 + TWL_MIC_StopAutoSampling(); + + // 割り込み禁止 + enabled = OS_DisableInterrupts(); + + // サウンド & I2S 回路ON + SND_Enable(); + + // DMA設定 + TWL_MICi_ExDmaRecvAsync( param.dmaNo, param.buffer, param.size ); + + // DMA割り込みの設定 + ch = (u32)param.dmaNo - MI_EXDMA_CH_MIN; + OS_SetIrqFunction( OS_IE_DMA4 << ch, TWL_MICi_ExDmaInterruptHandler ); + reg_OS_IF = (OS_IE_DMA4 << ch); + reg_OS_IE |= (OS_IE_DMA4 << ch); + + // マイクFIFO割り込みの設定 + OS_SetIrqFunction( OS_IE_MIC, TWL_MICi_FifoInterruptHandler ); + reg_OS_IF2 = (OS_IE_MIC >> 32); + reg_OS_IE2 |= (OS_IE_MIC >> 32); + + // スタートTick設定 + sMicTickStart = OS_GetTick(); + + // ストップTickクリア + sMicTickStop = TWL_MIC_TICK_INIT_VALUE; + + // モノラルサンプリングスタート + reg_SND_MICCNT = REG_SND_MICCNT_FIFO_CLR_MASK; // + reg_SND_MICCNT = (u16)( REG_SND_MICCNT_E_MASK | // + REG_SND_MICCNT_NR_MASK | // + MIC_INTR_OVERFLOW | // FIFO破綻で割り込み発生 + param.frequency ); + + // パラメータ保存 + sMicParam = param; + + // 割り込み復帰 + (void)OS_RestoreInterrupts(enabled); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_StopAutoSampling + + Description: オートサンプリングを停止します。 + + Arguments: None + + Returns: None + *---------------------------------------------------------------------------*/ +void +TWL_MIC_StopAutoSampling( void ) +{ + OSIntrMode enabled = OS_DisableInterrupts(); + u32 dmaNo = sMicParam.dmaNo; + + // ストップTick設定 + sMicTickStop = OS_GetTick(); + + // マイク停止 + reg_SND_MICCNT &= ~REG_SND_MICCNT_E_MASK; + + // マイクFIFO割り込み禁止 + reg_OS_IE2 &= ~(OS_IE_MIC >> 32); + reg_OS_IF2 = (OS_IE_MIC >> 32); + + if ( MI_EXDMA_CH_MIN <= dmaNo && dmaNo <= MI_EXDMA_CH_MAX ) + { + u32 ch = dmaNo - MI_EXDMA_CH_MIN; + + // DMA停止 + MIi_StopExDma( dmaNo ); + + // DMA割り込み禁止 + reg_OS_IE &= ~(OS_IE_DMA4 << ch); + reg_OS_IF = (OS_IE_DMA4 << ch); + } + + (void)OS_RestoreInterrupts(enabled); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_GetLastSamplingAddress + + Description: 最新サンプリングデータの格納アドレスを返します。 + マイクFIFOからのデータ取得にはDMAを用いますが、 + DMAが現在どの位置を書き換え中かは知る手段がありません。 + そのためサンプリング経過時間より現在の位置を予想します。 + + Arguments: None + + Returns: 最新サンプリングデータのアドレス(予想) + *---------------------------------------------------------------------------*/ +void* +TWL_MIC_GetLastSamplingAddress( void ) +{ + void* adress; // 最新データアドレス + OSTick past_tick; // 経過チック + u32 sampling_count; // 予想サンプリングカウント + f32 one_sampling_tick; + + // サンプリング停止状態 + if (sMicTickStop != TWL_MIC_TICK_INIT_VALUE) + { + past_tick = sMicTickStop - sMicTickStart; + } + // サンプリング進行状態 + else + { + past_tick = OS_GetTick() - sMicTickStart; + } + + /* + サンプリングレート47.61kHzの場合、 + システムクロックが33.514MHz で + Tickは64分周のタイマカウンタであるため + 1サンプリングに必要なチックは + + 33.514MHz / 47.61kHz / 64 = 10.9988 チック となる + + FPGAボードではさらに半分にする必要がある + */ + + switch ( I2S_GetSamplingRate() ) + { + case I2S_SAMPLING_RATE_32730: + switch ( sMicParam.frequency ) + { + case MIC_SMP_ALL: // 32.73 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 1 / 32730 / 64; + break; + case MIC_SMP_1_2: // 16.36 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 2 / 32730 / 64; + break; + case MIC_SMP_1_3: // 10.91 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 3 / 32730 / 64; + break; + case MIC_SMP_1_4: // 8.18 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 4 / 32730 / 64; + break; + } + break; + case I2S_SAMPLING_RATE_47610: + switch ( sMicParam.frequency ) + { + case MIC_SMP_ALL: // 47.61 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 1 / 47610 / 64; + break; + case MIC_SMP_1_2: // 23.81 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 2 / 47610 / 64; + break; + case MIC_SMP_1_3: // 15.87 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 3 / 47610 / 64; + break; + case MIC_SMP_1_4: // 11.90 kHz + one_sampling_tick = (f32)OS_SYSTEM_CLOCK * 4 / 47610 / 64; + break; + } + break; + } + + // 現在のサンプリング数を計算 + sampling_count = (u32)(past_tick / one_sampling_tick); + + // サンプリング数よりアドレスを計算 + adress = (void*)((u16 *)sMicParam.buffer + sampling_count); + + return adress; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_SetAmpGain + + Description: TWLモードのマイクゲイン(PGAB)を設定します。 +        PGABはAutoGainControlが無効になっているときのみ有効です。 + + Arguments: gain : 設定ゲイン(0〜119 = 0〜59.5dB) + + Returns: None + *---------------------------------------------------------------------------*/ +void +TWL_MIC_SetAmpGain( u8 gain ) +{ + SDK_ASSERT( gain >= 0 && gain <= 119 ); + CDC_SetPGAB( gain ); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_GetAmpGain + + Description: TWLモードのマイクゲイン(PGAB)を取得します。 + + Arguments: None + + Returns: 設定ゲイン + *---------------------------------------------------------------------------*/ +u8 +TWL_MIC_GetAmpGain( void ) +{ + return CDC_GetPGAB(); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_ExDmaRecvAsync + + Description: receive data with DMA + async version + + Arguments: dmaNo : DMA channel No. + buffer : destination address + size : size (byte) + + Returns: None + *---------------------------------------------------------------------------*/ +static void +TWL_MICi_ExDmaRecvAsync( u32 dmaNo, void *buffer, u32 size ) +{ + MIi_ExDmaRecvAsyncCore( + dmaNo, // DMA番号 + (void*)REG_MIC_FIFO_ADDR, // 転送元アドレス + buffer, // 転送先アドレス + (u32)size, // 総転送バイト数 + (u32)32, // 転送バイト数 + MI_EXDMA_BLOCK_32B, // ブロック転送サイズ + 0, // インターバル + MI_EXDMA_PRESCALER_1, // プリスケール1 + MI_EXDMA_CONTINUOUS_OFF, // 非コンティニュアス + MI_EXDMA_SRC_RLD_OFF, // Source Reload Don't Care + MI_EXDMA_DEST_RLD_OFF, // Destination Reload Off + MI_EXDMA_TIMING_MIC ); // マイクFIFOハーフ起動 +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_ExDmaInterruptHandler + + Description: interrupt handler + + Arguments: None + + Returns: None + *---------------------------------------------------------------------------*/ +static void +TWL_MICi_ExDmaInterruptHandler( void ) +{ + // ループする? + if ( sMicParam.loop ) + { + // DMAを再設定 + TWL_MICi_ExDmaRecvAsync( sMicParam.dmaNo, sMicParam.buffer, sMicParam.size ); + + // スタートTick再設定 + sMicTickStart = OS_GetTick(); + } + + // DMA完了コールバックの呼び出し + if ( sMicParam.callback ) + { + sMicParam.callback( sMicParam.loop ); + } +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_FifoInterruptHandler + + Description: マイクFIFO破綻時に呼び出される割り込みハンドラ + 現在の実装ではFIFOクリア後にサンプリングを再スタート + させています。 + + Arguments: None + + Returns: None + *---------------------------------------------------------------------------*/ +static void +TWL_MICi_FifoInterruptHandler( void ) +{ + // マイク停止 + reg_SND_MICCNT &= ~REG_SND_MICCNT_E_MASK; + + // マイクFIFOクリア + reg_SND_MICCNT = REG_SND_MICCNT_FIFO_CLR_MASK; + + // モノラルサンプリング再スタート + reg_SND_MICCNT = (u16)( REG_SND_MICCNT_E_MASK | + REG_SND_MICCNT_NR_MASK | + MIC_INTR_OVERFLOW | // FIFO破綻で割り込み発生 + sMicParam.frequency ); +} + diff --git a/build/libraries/mic/ARM7/src/twl_mic_server.c b/build/libraries/mic/ARM7/src/twl_mic_server.c new file mode 100644 index 0000000..cb448ab --- /dev/null +++ b/build/libraries/mic/ARM7/src/twl_mic_server.c @@ -0,0 +1,495 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - library - twlmic + File: twl_mic_server.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: $ + $NoKeywords: $ + *---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------* + TWL Mic用に勝手にARM7側スレッドを作りました。 + 都合よければSPIスレッドなどに吸収してください。 + ----------------------------------------------------------------------------*/ + +#include +#include + +/*---------------------------------------------------------------------------* + マクロ定義 + *---------------------------------------------------------------------------*/ + +// アライメント調整してコピーする +#define MIC_UNPACK_U16(d, s) \ + (*(d) = (u16)((((u8*)s)[0] << 0) | (((u8*)s)[1] << 8))) +#define MIC_UNPACK_U32(d, s) \ + (*(d) = (u32)((((u8*)s)[0] << 0) | (((u8*)s)[1] << 8) | (((u8*)s)[2] << 16) | (((u8*)s)[3] << 24))) + +/*---------------------------------------------------------------------------* + 静的変数定義 + *---------------------------------------------------------------------------*/ + +static BOOL micInitialized; // 初期化確認フラグ +static TWLMICServerWork micWork; // ワーク変数をまとめた構造体 + +/*---------------------------------------------------------------------------* + 内部関数定義 + *---------------------------------------------------------------------------*/ + +static void TWL_MICi_PxiCallback(PXIFifoTag tag, u32 data, BOOL err); +static void TWL_MICi_ReturnResult(TWLMICPxiCommand command, TWLMICPxiResult result); +static void TWL_MICi_ReturnResultEx(TWLMICPxiCommand command, TWLMICPxiResult result, u8 size, u8* data); +static void TWL_MICi_Thread(void *arg); +static void TWL_MICi_FullCallback( u8 loop ); +static BOOL TWL_MICi_SetEntry(TWLMICPxiCommand command, u16 args, ...); + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_InitServer + + Description: ARM7側とやりとりを行うための準備を行います。 + + Arguments: priority + + Returns: None. + *---------------------------------------------------------------------------*/ +void +TWL_MIC_InitServer(u32 priority) +{ + // 初期化済みを確認 + if (micInitialized) + { + return; + } + micInitialized = 1; + + // 内部状態管理変数をクリア + micWork.status = TWL_MIC_STATUS_READY; + + // PXI関連を初期化 + PXI_Init(); + PXI_SetFifoRecvCallback(PXI_FIFO_TAG_TWL_MIC, TWL_MICi_PxiCallback); + + // 実処理を行うスレッドを作成&起動 + OS_InitMessageQueue(&micWork.msgQ, micWork.msgArray, TWL_MIC_MESSAGE_ARRAY_MAX); + OS_CreateThread(&micWork.thread, + TWL_MICi_Thread, + 0, + (void *)(micWork.stack + (TWL_MIC_THREAD_STACK_SIZE / sizeof(u64))), + TWL_MIC_THREAD_STACK_SIZE, priority); + OS_WakeupThreadDirect(&micWork.thread); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_SetEntry + + Description: TWL MIC スレッドに操作要求を予約する。 + + Arguments: command - 行うべき操作のIDを指定。 + args - 操作に伴うパラメータの数を指定。 + ... - 各パラメータをu32型で指定。 + + Returns: BOOL - 予約に成功した場合にTRUEを、失敗した場合にFALSEを返す。 + *---------------------------------------------------------------------------*/ +static BOOL +TWL_MICi_SetEntry(TWLMICPxiCommand command, u16 args, ...) +{ + OSIntrMode e; + void *w; + va_list vlist; + s32 i; + + // 引数の数をチェック + if (args > TWL_MIC_MESSAGE_ARGS_MAX) + { + return FALSE; + } + + e = OS_DisableInterrupts(); + micWork.entry[micWork.entryIndex].command = command; + + // 指定数個の引数を追加 + va_start(vlist, args); + for (i = 0; i < args; i++) + { + micWork.entry[micWork.entryIndex].arg[i] = va_arg(vlist, u32); + } + va_end(vlist); + + w = &(micWork.entry[micWork.entryIndex]); + micWork.entryIndex = (u32)((micWork.entryIndex + 1) % TWL_MIC_MESSAGE_ARRAY_MAX); + (void)OS_RestoreInterrupts(e); + return OS_SendMessage(&(micWork.msgQ), w, OS_MESSAGE_NOBLOCK); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_PxiCallback + + Description: PXI経由で受信したデータを解析する。 + + Arguments: tag - PXI種別を示すタグ。 + data - 受信したデータ。下位26bitが有効。 + err - PXI通信におけるエラーフラグ。 + ARM9側にて同種別のPXIが初期化されていないことを示す。 + + Returns: None. + *---------------------------------------------------------------------------*/ +static void TWL_MICi_PxiCallback(PXIFifoTag tag, u32 data, BOOL err) +{ +#pragma unused( tag ) + + // PXI通信エラーをチェック + if (err) + { + return; + } + // 先頭データ + if (data & TWL_MIC_PXI_START_BIT) + { + micWork.total = (u8)((data & TWL_MIC_PXI_DATA_NUMS_MASK) >> TWL_MIC_PXI_DATA_NUMS_SHIFT); + micWork.current = 0; + micWork.command = (TWLMICPxiCommand)((data & TWL_MIC_PXI_COMMAND_MASK) >> TWL_MIC_PXI_COMMAND_SHIFT); + micWork.data[micWork.current++] = (u8)((data & TWL_MIC_PXI_1ST_DATA_MASK) >> TWL_MIC_PXI_1ST_DATA_SHIFT); + } + // 後続データ + else + { + micWork.data[micWork.current++] = (u8)((data & 0x00FF0000) >> 16); + micWork.data[micWork.current++] = (u8)((data & 0x0000FF00) >> 8); + micWork.data[micWork.current++] = (u8)((data & 0x000000FF) >> 0); + } + + // パケット完成 + if (micWork.current >= micWork.total) // 最大で2バイト余分に取得する + { + // 受信したコマンドを解析 + switch (micWork.command) + { + // 単発サンプリング + case TWL_MIC_PXI_COMMAND_ONE_SAMPLING: + if (micWork.status != TWL_MIC_STATUS_READY) + { + // コマンドを実行できる状態ではない + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_ILLEGAL_STATUS); + } + else + { + // TWL MIC スレッドに操作要求 + if (TWL_MICi_SetEntry( micWork.command, 0 )) + { + // 状態を"単発サンプリング開始待ち"へ + micWork.status = TWL_MIC_STATUS_ONE_SAMPLING_START; + } + else + { + // エントリー失敗(メッセージキューに空き無し) + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_FATAL_ERROR); + } + } + break; + + // オートサンプリング開始 + case TWL_MIC_PXI_COMMAND_AUTO_START: + if (micWork.status != TWL_MIC_STATUS_READY) + { + // コマンドを実行できる状態ではない + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_ILLEGAL_STATUS); + } + else + { + u32 dmaNo, buffer, size, frequency, loop; + + dmaNo = micWork.data[0]; + MIC_UNPACK_U32(&buffer, &micWork.data[1]); + MIC_UNPACK_U32(&size, &micWork.data[5]); + frequency = (u32)(micWork.data[9] << REG_SND_MICCNT_FIFO_SMP_SHIFT); + loop = micWork.data[10]; + + // TWL MIC スレッドに操作要求 + if (TWL_MICi_SetEntry( micWork.command, 5, dmaNo, buffer, size, frequency, loop )) + { + // 状態を"自動サンプリング開始待ち"へ + micWork.status = TWL_MIC_STATUS_AUTO_START; + } + else + { + // エントリー失敗(メッセージキューに空き無し) + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_FATAL_ERROR); + } + } + break; + + // オートサンプリング停止 + case TWL_MIC_PXI_COMMAND_AUTO_STOP: + if (micWork.status != TWL_MIC_STATUS_AUTO_SAMPLING) + { + // コマンドを実行できる状態ではない + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_ILLEGAL_STATUS); + } + else + { + // TWL MIC スレッドに操作要求 + if (TWL_MICi_SetEntry( micWork.command, 0 )) + { + // 状態を"自動サンプリング停止待ち"へ + micWork.status = TWL_MIC_STATUS_AUTO_END; + } + else + { + // エントリー失敗(メッセージキューに空き無し) + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_FATAL_ERROR); + } + } + break; + + // 最新サンプリングデータアドレス取得 + case TWL_MIC_PXI_COMMAND_GET_LAST_SAMPLING_ADDRESS: + + // TWL MIC スレッドに操作要求 + if (!TWL_MICi_SetEntry( micWork.command, 0 )) + { + // エントリー失敗(メッセージキューに空き無し) + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_FATAL_ERROR); + } + break; + + // プログラマブルアンプゲイン設定 + case TWL_MIC_PXI_COMMAND_SET_AMP_GAIN: + { + u32 gain = micWork.data[0]; + + // TWL MIC スレッドに操作要求 + if (!TWL_MICi_SetEntry( micWork.command, 1, gain )) + { + // エントリー失敗(メッセージキューに空き無し) + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_FATAL_ERROR); + } + } + break; + + // プログラマブルアンプゲイン取得 + case TWL_MIC_PXI_COMMAND_GET_AMP_GAIN: + + // TWL MIC スレッドに操作要求 + if (!TWL_MICi_SetEntry( micWork.command, 0 )) + { + // エントリー失敗(メッセージキューに空き無し) + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_FATAL_ERROR); + } + break; + + // 未知のコマンド + default: + TWL_MICi_ReturnResult(micWork.command, TWL_MIC_PXI_RESULT_INVALID_COMMAND); + } + } +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_ReturnResult + + Description: PXI経由で処理結果をARM9に送信する。 + + Arguments: command - 対象コマンド + result - TWLMICPxiResultのひとつ + + Returns: None. + *---------------------------------------------------------------------------*/ +static void +TWL_MICi_ReturnResult(TWLMICPxiCommand command, TWLMICPxiResult result) +{ + u32 pxiData = (u32)(TWL_MIC_PXI_START_BIT | TWL_MIC_PXI_RESULT_BIT | + ((command << TWL_MIC_PXI_COMMAND_SHIFT) & TWL_MIC_PXI_COMMAND_MASK) | + ((1 << TWL_MIC_PXI_DATA_NUMS_SHIFT) & TWL_MIC_PXI_DATA_NUMS_MASK) | + ((result << TWL_MIC_PXI_1ST_DATA_SHIFT) & TWL_MIC_PXI_1ST_DATA_MASK)); + while (0 > PXI_SendWordByFifo(PXI_FIFO_TAG_TWL_MIC, pxiData, 0)) + { + } +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_ReturnResultEx + + Description: 指定後続データをPXI経由でARM9に送信する。 + + Arguments: command - 対象コマンド + result - TWLMICPxiResultのひとつ + size - 付加データサイズ + data - 付加データ + + Returns: None. + *---------------------------------------------------------------------------*/ +static void +TWL_MICi_ReturnResultEx(TWLMICPxiCommand command, TWLMICPxiResult result, u8 size, u8* data) +{ + u32 pxiData = (u32)(TWL_MIC_PXI_START_BIT | TWL_MIC_PXI_RESULT_BIT | + ((command << TWL_MIC_PXI_COMMAND_SHIFT) & TWL_MIC_PXI_COMMAND_MASK) | + (((size+1) << TWL_MIC_PXI_DATA_NUMS_SHIFT) & TWL_MIC_PXI_DATA_NUMS_MASK) | + ((result << TWL_MIC_PXI_1ST_DATA_SHIFT) & TWL_MIC_PXI_1ST_DATA_MASK)); + int i; + while (0 > PXI_SendWordByFifo(PXI_FIFO_TAG_TWL_MIC, pxiData, 0)) + { + } + for (i = 0; i < size; i += 3) + { + pxiData = (u32)((data[i] << 16) | (data[i+1] << 8) | data[i+2]); + while (0 > PXI_SendWordByFifo(PXI_FIFO_TAG_TWL_MIC, pxiData, 0)) + { + } + } +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_Thread + + Description: MIC操作の実処理を行うスレッド。 + + Arguments: arg - 使用しない。 + + Returns: None. + *---------------------------------------------------------------------------*/ +static void TWL_MICi_Thread(void *arg) +{ +#pragma unused( arg ) + + OSMessage msg; + TWLMICMessageData* entry; + + while (TRUE) + { + // メッセージが発行されるまで寝る + (void)OS_ReceiveMessage(&(micWork.msgQ), &msg, OS_MESSAGE_BLOCK); + entry = (TWLMICMessageData *) msg; + + // コマンドに従って各種処理を実行 + switch (entry->command) + { + //--- 単発サンプリング開始 + case TWL_MIC_PXI_COMMAND_ONE_SAMPLING: + if (micWork.status == TWL_MIC_STATUS_ONE_SAMPLING_START) + { + u16 temp; + TWL_MIC_DoSampling( &temp ); + + TWL_MICi_ReturnResultEx(entry->command, TWL_MIC_PXI_RESULT_SUCCESS, + 2, (u8*)&temp ); // ARM9に処理の成功を通達 + + micWork.status = TWL_MIC_STATUS_READY; // 状態を"通常操作待ち"へ + } + else + { + TWL_MICi_ReturnResult(entry->command, TWL_MIC_PXI_RESULT_ILLEGAL_STATUS); + } + break; + + //--- オートサンプリング開始 + case TWL_MIC_PXI_COMMAND_AUTO_START: + if (micWork.status == TWL_MIC_STATUS_AUTO_START) + { + TWLMICParam param; + + param.dmaNo = (u8)entry->arg[0]; + param.buffer = (void *)entry->arg[1]; + param.size = entry->arg[2]; + param.frequency = (MICSampleRate)entry->arg[3]; + param.loop = (u8)entry->arg[4]; + param.callback = TWL_MICi_FullCallback; + TWL_MIC_StartAutoSampling( param ); + + TWL_MICi_ReturnResult(entry->command, TWL_MIC_PXI_RESULT_SUCCESS); // ARM9に処理の成功を通達 + micWork.status = TWL_MIC_STATUS_AUTO_SAMPLING; // 状態を"自動サンプリング中"へ + } + else + { + TWL_MICi_ReturnResult(entry->command, TWL_MIC_PXI_RESULT_ILLEGAL_STATUS); + } + break; + + //--- オートサンプリング停止 + case TWL_MIC_PXI_COMMAND_AUTO_STOP: + if ((micWork.status == TWL_MIC_STATUS_AUTO_END) || (micWork.status == TWL_MIC_STATUS_END_WAIT)) + { + TWL_MIC_StopAutoSampling(); + + // ARM9に処理の成功を通達 + if (micWork.status == TWL_MIC_STATUS_AUTO_END) + { + TWL_MICi_ReturnResult(TWL_MIC_PXI_COMMAND_AUTO_STOP, TWL_MIC_PXI_RESULT_SUCCESS); + } + // 内部状態を更新 + micWork.status = TWL_MIC_STATUS_READY; // 状態を"通常操作待ち"へ + } + else + { + TWL_MICi_ReturnResult(entry->command, TWL_MIC_PXI_RESULT_ILLEGAL_STATUS); + } + break; + + //--- 最新サンプリングデータアドレス取得 + case TWL_MIC_PXI_COMMAND_GET_LAST_SAMPLING_ADDRESS: + { + void* adress = TWL_MIC_GetLastSamplingAddress(); + + TWL_MICi_ReturnResultEx(entry->command, TWL_MIC_PXI_RESULT_SUCCESS, + 4, (u8*)&adress ); // ARM9に処理の成功を通達 + } + break; + + //--- プログラマブルアンプゲイン設定 + case TWL_MIC_PXI_COMMAND_SET_AMP_GAIN: + { + u8 gain = (u8)entry->arg[0]; + TWL_MIC_SetAmpGain( gain ); + TWL_MICi_ReturnResult(entry->command, TWL_MIC_PXI_RESULT_SUCCESS); // ARM9に処理の成功を通達 + } + break; + + //--- プログラマブルアンプゲイン取得 + case TWL_MIC_PXI_COMMAND_GET_AMP_GAIN: + { + u8 gain = TWL_MIC_GetAmpGain(); + TWL_MICi_ReturnResultEx(entry->command, TWL_MIC_PXI_RESULT_SUCCESS, + 1, (u8*)&gain ); // ARM9に処理の成功を通達 + } + //--- サポートしないコマンド + default: + TWL_MICi_ReturnResult(entry->command, TWL_MIC_PXI_RESULT_INVALID_COMMAND); + } + } +} + +/*---------------------------------------------------------------------------* + Name: TWL_MICi_FullCallback + + Description: + + Arguments: + + Returns: None. + *---------------------------------------------------------------------------*/ +static void TWL_MICi_FullCallback( u8 loop ) +{ + // FULL通知 + TWL_MICi_ReturnResult(TWL_MIC_PXI_COMMAND_MIC_BUFFER_FULL, TWL_MIC_PXI_RESULT_SUCCESS); + + if ( !loop ) + { + // 自動サンプリング停止 + if (TWL_MICi_SetEntry( TWL_MIC_PXI_COMMAND_AUTO_STOP, 0 )) + { + micWork.status = TWL_MIC_STATUS_END_WAIT; // 状態を"自動サンプリング完了待ち"へ + } + else + { + TWL_MICi_ReturnResult(TWL_MIC_PXI_COMMAND_AUTO_STOP, TWL_MIC_PXI_RESULT_FATAL_ERROR); + } + } +} + + diff --git a/build/libraries/mic/ARM9/Makefile b/build/libraries/mic/ARM9/Makefile new file mode 100644 index 0000000..5a446c4 --- /dev/null +++ b/build/libraries/mic/ARM9/Makefile @@ -0,0 +1,55 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - libraries - camera/ARM9 +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Log: $ +# $NoKeywords: $ +#---------------------------------------------------------------------------- + +SUBDIRS = + + +#---------------------------------------------------------------------------- + +# build ARM & THUMB libraries +TWL_CODEGEN_ALL ?= True + +SRCDIR = ../common ./src + +SRCS = twl_mic_api.c \ + +TARGET_LIB = libtwlmic$(TWL_LIBSUFFIX).a + + +#---------------------------------------------------------------------------- + +# DEBUG版ビルドの場合、RELEASE版でビルドして +# DEBUG版のライブラリを装います。 + +#ifdef NITRO_DEBUG +#NITRO_BUILD_TYPE = RELEASE +#endif + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(TWL_INSTALL_LIBDIR) + + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + + +#===== End of Makefile ===== diff --git a/build/libraries/mic/ARM9/src/twl_mic_api.c b/build/libraries/mic/ARM9/src/twl_mic_api.c new file mode 100644 index 0000000..fba7b4a --- /dev/null +++ b/build/libraries/mic/ARM9/src/twl_mic_api.c @@ -0,0 +1,807 @@ +/*---------------------------------------------------------------------------* + Project: TwlSDK - library - camera + File: camera.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Log: $ + $NoKeywords: $ + *---------------------------------------------------------------------------*/ +#include +#include + +/*---------------------------------------------------------------------------* + 定数定義 + *---------------------------------------------------------------------------*/ +// 詰めてコピーする +#define MIC_PACK_U16(d, s) \ + ((d)[0] = (u8)((*((u16*)s) >> 0) & 0xFF), \ + (d)[1] = (u8)((*((u16*)s) >> 8) & 0xFF)) + +#define MIC_PACK_U32(d, s) \ + ((d)[0] = (u8)((*((u32*)s) >> 0) & 0xFF), \ + (d)[1] = (u8)((*((u32*)s) >> 8) & 0xFF), \ + (d)[2] = (u8)((*((u32*)s) >> 16) & 0xFF), \ + (d)[3] = (u8)((*((u32*)s) >> 24) & 0xFF)) + +/*---------------------------------------------------------------------------* + 型定義 + *---------------------------------------------------------------------------*/ +typedef struct _TWLMICWork +{ + BOOL lock; + TwlMicCallback callback; // 非同期関数用コールバック + void* callbackArg; // 上記関数用引数 + TwlMicCallback full_callback; // 非同期関数用コールバック + void* full_arg; // 上記関数用引数 + TWLMICResult result; // 先頭データだけ別枠 + TWLMICPxiCommand command; // コマンド種別 + TWLMICPxiResult pxiResult; // 先頭データだけ別枠 + u16* pOneBuffer; // 単発サンプリングバッファ保存用 + void** pLastSamplingAddress; // 最新サンプリングデータ格納アドレス + u8* pAmpGain; // アンプゲイン格納アドレス + u8 current; // 受信済みデータ個数 (バイト単位) (先頭を除く!!) + u8 total; // 最終データ個数 (1 + 後続コマンド*3) + u8 data[TWL_MIC_PXI_DATA_SIZE_MAX]; // ARM7からのデータ保存用 +} +TWLMICWork; + +/*---------------------------------------------------------------------------* + 静的変数定義 + *---------------------------------------------------------------------------*/ +static BOOL micInitialized; +static TWLMICWork micWork; + +/*---------------------------------------------------------------------------* + 内部関数定義 + *---------------------------------------------------------------------------*/ +static BOOL TWLMICi_SendPxiCommand(TWLMICPxiCommand command, u8 size, u8 data); +static void TWLMICi_SendPxiData(u8 *pData); +static void TWLMICi_PxiCallback(PXIFifoTag tag, u32 data, BOOL err); +static void TWLMICi_CallbackAndUnlock(TWLMICResult result); +static void TWLMICi_GetResultCallback(TWLMICResult result, void *arg); +static void TWLMICi_WaitBusy(void); + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_Init + + Description: MICライブラリを初期化する。 + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +void TWL_MIC_Init(void) +{ + // 初期化済みを確認 + if (micInitialized) + { + return; + } + micInitialized = 1; + + // 変数初期化 + micWork.lock = FALSE; + micWork.callback = NULL; + + // PXI関連を初期化 + PXI_Init(); + while (!PXI_IsCallbackReady(PXI_FIFO_TAG_TWL_MIC, PXI_PROC_ARM7)) + { + } + PXI_SetFifoRecvCallback(PXI_FIFO_TAG_TWL_MIC, TWLMICi_PxiCallback); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_End + + Description: MICライブラリを終了する。 + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +void TWL_MIC_End(void) +{ + // 初期化済みを確認 + if (micInitialized == 0) + { + return; + } + micInitialized = 0; + + // PXI関連停止 + PXI_SetFifoRecvCallback(PXI_FIFO_TAG_TWL_MIC, NULL); +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_DoSamplingAsync + + Description: マイク単発サンプリング開始(非同期版) + + Arguments: + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_DoSamplingAsync(u16* buf, TwlMicCallback callback, void* callbackArg) +{ + const TWLMICPxiCommand command = TWL_MIC_PXI_COMMAND_ONE_SAMPLING; + const u8 size = TWL_MIC_PXI_SIZE_ONE_SAMPLING; // バイト + OSIntrMode enabled; + + // buffer NULLチェック + // ToDo: 適切なアドレスかどうかチェック + if (buf == NULL) + { + return TWL_MIC_RESULT_ILLEGAL_PARAMETER; + } + + // ロック + enabled = OS_DisableInterrupts(); + if (micWork.lock) + { + (void)OS_RestoreInterrupts(enabled); + return TWL_MIC_RESULT_BUSY; + } + micWork.lock = TRUE; + (void)OS_RestoreInterrupts(enabled); + + // 非同期関数用コールバック設定 + micWork.callback = callback; + micWork.callbackArg = callbackArg; + + // バッファアドレス保存 + micWork.pOneBuffer = buf; + + // コマンド送信 + if (TWLMICi_SendPxiCommand(command, size, 0) == FALSE) + { + return TWL_MIC_RESULT_SEND_ERROR; + } + + return TWL_MIC_RESULT_SUCCESS; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_DoSampling + + Description: マイク単発サンプリング開始(同期版) + + Arguments: + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_DoSampling(u16* buf) +{ + micWork.result = TWL_MIC_DoSamplingAsync(buf, TWLMICi_GetResultCallback, 0); + if (micWork.result == TWL_MIC_RESULT_SUCCESS) + { + TWLMICi_WaitBusy(); + } + return micWork.result; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_StartAutoSamplingAsync + + Description: マイク自動サンプリング開始(非同期版) + + Arguments: mic - one of MicSelect + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_StartAutoSamplingAsync(TwlMicAutoParam* param, TwlMicCallback callback, void* callbackArg) +{ + const TWLMICPxiCommand command = TWL_MIC_PXI_COMMAND_AUTO_START; + const u8 size = TWL_MIC_PXI_SIZE_AUTO_START; // バイト + OSIntrMode enabled; + u8 data[size+2]; + int i; + + // DMA-Noチェック + if ( param->dmaNo < MI_EXDMA_CH_MIN || MI_EXDMA_CH_MAX < param->dmaNo ) + { + return TWL_MIC_RESULT_ILLEGAL_PARAMETER; + } + + // buffer NULLチェック & 4バイトアライメントチェック + // ToDo: 適切なアドレスかどうかチェック + if (param->buffer == NULL || (u32)param->buffer & 0x03) + { + return TWL_MIC_RESULT_ILLEGAL_PARAMETER; + } + + // size 4バイトの倍数チェック + // ToDo: buffer + size が適切なメモリ範囲か + if (param->size & 0x03) + { + return TWL_MIC_RESULT_ILLEGAL_PARAMETER; + } + + // frequencyチェック + if ( param->frequency > TWL_MIC_FREQUENCY_1_4 ) + { + return TWL_MIC_RESULT_ILLEGAL_PARAMETER; + } + + // ロック + enabled = OS_DisableInterrupts(); + if (micWork.lock) + { + (void)OS_RestoreInterrupts(enabled); + return TWL_MIC_RESULT_BUSY; + } + micWork.lock = TRUE; + (void)OS_RestoreInterrupts(enabled); + + // 非同期関数用コールバック設定 + micWork.callback = callback; + micWork.callbackArg = callbackArg; + + // FULLコールバック設定 + if (param->full_callback) + { + micWork.full_callback = param->full_callback; + micWork.full_arg = param->full_arg; + } + + // データ作成 + data[0] = (u8)param->dmaNo; + MIC_PACK_U32(&data[1], ¶m->buffer); + MIC_PACK_U32(&data[5], ¶m->size); + data[9] = (u8)param->frequency; + data[10] = (u8)param->loop_enable; + + // コマンド送信 + if (TWLMICi_SendPxiCommand(command, size, data[0]) == FALSE) + { + return TWL_MIC_RESULT_SEND_ERROR; + } + for (i = 1; i < size; i+=3) { + TWLMICi_SendPxiData(&data[i]); + } + + return TWL_MIC_RESULT_SUCCESS; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_StartAutoSampling + + Description: マイク自動サンプリング開始(同期版) + + Arguments: param + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_StartAutoSampling(TwlMicAutoParam* param) +{ + micWork.result = TWL_MIC_StartAutoSamplingAsync(param, TWLMICi_GetResultCallback, 0); + if (micWork.result == TWL_MIC_RESULT_SUCCESS) + { + TWLMICi_WaitBusy(); + } + return micWork.result; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_StopAutoSamplingAsync + + Description: マイク自動サンプリング停止(非同期版) + + Arguments: none + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_StopAutoSamplingAsync( TwlMicCallback callback, void* callbackArg ) +{ + const TWLMICPxiCommand command = TWL_MIC_PXI_COMMAND_AUTO_STOP; + const u8 size = TWL_MIC_PXI_SIZE_AUTO_STOP; // バイト + OSIntrMode enabled; + + // ロック + enabled = OS_DisableInterrupts(); + if (micWork.lock) + { + (void)OS_RestoreInterrupts(enabled); + return TWL_MIC_RESULT_BUSY; + } + micWork.lock = TRUE; + (void)OS_RestoreInterrupts(enabled); + + // コールバック設定 + micWork.callback = callback; + micWork.callbackArg = callbackArg; + + // コマンド送信 + if (TWLMICi_SendPxiCommand(command, size, 0) == FALSE) + { + return TWL_MIC_RESULT_SEND_ERROR; + } + + return TWL_MIC_RESULT_SUCCESS; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_StopAutoSampling + + Description: マイク自動サンプリング停止(同期版) + + Arguments: param + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_StopAutoSampling( void ) +{ + micWork.result = TWL_MIC_StopAutoSamplingAsync(TWLMICi_GetResultCallback, 0); + if (micWork.result == TWL_MIC_RESULT_SUCCESS) + { + TWLMICi_WaitBusy(); + } + return micWork.result; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_GetLastSamplingAddressAsync + + Description: 最新のサンプリングデータの格納アドレスを返します。 + 但し、アドレスはサンプリング時間を元に理論的に計算された + ものであるため誤差を含んでいます。 + (非同期版) + + Arguments: adress : アドレス格納ポインタのアドレス + callback : + callbackArg : + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_GetLastSamplingAddressAsync( void** adress, TwlMicCallback callback, void* callbackArg ) +{ + const TWLMICPxiCommand command = TWL_MIC_PXI_COMMAND_GET_LAST_SAMPLING_ADDRESS; + const u8 size = TWL_MIC_PXI_SIZE_GET_LAST_SAMPLING_ADDRESS; // バイト + OSIntrMode enabled; + + // ロック + enabled = OS_DisableInterrupts(); + if (micWork.lock) + { + (void)OS_RestoreInterrupts(enabled); + return TWL_MIC_RESULT_BUSY; + } + micWork.lock = TRUE; + (void)OS_RestoreInterrupts(enabled); + + // コールバック設定 + micWork.callback = callback; + micWork.callbackArg = callbackArg; + + // アドレス格納アドレス保存 + micWork.pLastSamplingAddress = adress; + + // コマンド送信 + if (TWLMICi_SendPxiCommand(command, size, 0) == FALSE) + { + return TWL_MIC_RESULT_SEND_ERROR; + } + + return TWL_MIC_RESULT_SUCCESS; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_GetLastSamplingAddress + + Description: 最新のサンプリングデータの格納アドレスを返します。 + 但し、アドレスはサンプリング時間を元に理論的に計算された + ものであるため誤差を含んでいます。 + (同期版) + + Arguments: adress : アドレス格納ポインタのアドレス + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_GetLastSamplingAddress( void** adress ) +{ + micWork.result = TWL_MIC_GetLastSamplingAddressAsync( adress, TWLMICi_GetResultCallback, 0); + if (micWork.result == TWL_MIC_RESULT_SUCCESS) + { + TWLMICi_WaitBusy(); + } + return micWork.result; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_SetAmpGainAsync + + Description: プログラマブルゲインアンプの設定を行います。(非同期版) + この関数で設定したゲインはオートゲインコントロールが +        無効になっているときのみ有効となることに注意してください。 + + Arguments: gain : 設定ゲイン(0〜119 = 0〜59.5dB) + callback : + callbackArg : + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_SetAmpGainAsync( u8 gain, TwlMicCallback callback, void* callbackArg ) +{ + const TWLMICPxiCommand command = TWL_MIC_PXI_COMMAND_SET_AMP_GAIN; + const u8 size = TWL_MIC_PXI_SIZE_SET_AMP_GAIN; // バイト + u8 data[size+2]; + OSIntrMode enabled; + + // 設定ゲイン範囲チェック + if ( gain > 119) + { + return TWL_MIC_RESULT_ILLEGAL_PARAMETER; + } + + // ロック + enabled = OS_DisableInterrupts(); + if (micWork.lock) + { + (void)OS_RestoreInterrupts(enabled); + return TWL_MIC_RESULT_BUSY; + } + micWork.lock = TRUE; + (void)OS_RestoreInterrupts(enabled); + + // コールバック設定 + micWork.callback = callback; + micWork.callbackArg = callbackArg; + + // データ作成 + data[0] = gain; + + // コマンド送信 + if (TWLMICi_SendPxiCommand(command, size, data[0]) == FALSE) + { + return TWL_MIC_RESULT_SEND_ERROR; + } + + return TWL_MIC_RESULT_SUCCESS; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_SetAmpGain + + Description: プログラマブルゲインアンプの設定を行います。(同期版) + この関数で設定したゲインはオートゲインコントロールが + 無効になっているときのみ有効となることに注意してください。 + + Arguments: gain : 設定ゲイン(0〜119 = 0〜59.5dB) + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_SetAmpGain( u8 gain ) +{ + micWork.result = TWL_MIC_SetAmpGainAsync( gain, TWLMICi_GetResultCallback, 0); + if (micWork.result == TWL_MIC_RESULT_SUCCESS) + { + TWLMICi_WaitBusy(); + } + return micWork.result; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_GetAmpGainAsync + + Description: TWLモードのマイクゲイン(PGAB)を取得します。 + (非同期版) + + Arguments: gain : マイクゲイン値の格納アドレス + callback : + callbackArg : + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_GetAmpGainAsync( u8* gain, TwlMicCallback callback, void* callbackArg ) +{ + const TWLMICPxiCommand command = TWL_MIC_PXI_COMMAND_GET_AMP_GAIN; + const u8 size = TWL_MIC_PXI_SIZE_GET_AMP_GAIN; // バイト + OSIntrMode enabled; + + // NULLチェック + if ( gain == NULL) + { + return TWL_MIC_RESULT_ILLEGAL_PARAMETER; + } + + // ロック + enabled = OS_DisableInterrupts(); + if (micWork.lock) + { + (void)OS_RestoreInterrupts(enabled); + return TWL_MIC_RESULT_BUSY; + } + micWork.lock = TRUE; + (void)OS_RestoreInterrupts(enabled); + + // コールバック設定 + micWork.callback = callback; + micWork.callbackArg = callbackArg; + + // ゲイン格納アドレス保存 + micWork.pAmpGain = gain; + + // コマンド送信 + if (TWLMICi_SendPxiCommand(command, size, 0) == FALSE) + { + return TWL_MIC_RESULT_SEND_ERROR; + } + + return TWL_MIC_RESULT_SUCCESS; +} + +/*---------------------------------------------------------------------------* + Name: TWL_MIC_GetAmpGain + + Description: TWLモードのマイクゲイン(PGAB)を取得します。 + (同期版) + + Arguments: gain : マイクゲイン値の格納アドレス + + Returns: TWLMICResult + *---------------------------------------------------------------------------*/ +TWLMICResult +TWL_MIC_GetAmpGain( u8* gain ) +{ + micWork.result = TWL_MIC_GetAmpGainAsync( gain, TWLMICi_GetResultCallback, 0); + if (micWork.result == TWL_MIC_RESULT_SUCCESS) + { + TWLMICi_WaitBusy(); + } + return micWork.result; +} + +/*---------------------------------------------------------------------------* + Name: TWLMICi_SendPxiCommand + + Description: 指定先頭コマンドをPXI経由でARM7に送信する。 + + Arguments: command - 対象コマンド + size - 送信データサイズ (バイト単位) + data - 先頭データ (1バイトのみ) + + Returns: BOOL - PXIに対して送信が完了した場合TRUEを、 + PXIによる送信に失敗した場合FALSEを返す。 + *---------------------------------------------------------------------------*/ +static BOOL TWLMICi_SendPxiCommand(TWLMICPxiCommand command, u8 size, u8 data) +{ + u32 pxiData = (u32)(TWL_MIC_PXI_START_BIT | + ((command << TWL_MIC_PXI_COMMAND_SHIFT) & TWL_MIC_PXI_COMMAND_MASK) | + ((size << TWL_MIC_PXI_DATA_NUMS_SHIFT) & TWL_MIC_PXI_DATA_NUMS_MASK) | + ((data << TWL_MIC_PXI_1ST_DATA_SHIFT) & TWL_MIC_PXI_1ST_DATA_MASK)); + if (0 > PXI_SendWordByFifo(PXI_FIFO_TAG_TWL_MIC, pxiData, 0)) + { + return FALSE; + } + return TRUE; +} + +/*---------------------------------------------------------------------------* + Name: TWLMICi_SendPxiData + + Description: 指定後続データをPXI経由でARM7に送信する。 + + Arguments: pData - 3バイトデータの先頭へのポインタ + + Returns: None + *---------------------------------------------------------------------------*/ +static void TWLMICi_SendPxiData(u8 *pData) +{ + u32 pxiData = (u32)((pData[0] << 16) | (pData[1] << 8) | pData[2]); + while (0 > PXI_SendWordByFifo(PXI_FIFO_TAG_TWL_MIC, pxiData, 0)) + { + } +} + +/*---------------------------------------------------------------------------* + Name: TWLMICi_PxiCallback + + Description: 非同期関数用の共通コールバック関数。 + + Arguments: tag - PXI tag which show message type. + data - message from ARM7. + err - PXI transfer error flag. + + Returns: None. + *---------------------------------------------------------------------------*/ +static void TWLMICi_PxiCallback(PXIFifoTag tag, u32 data, BOOL err) +{ +#pragma unused( tag ) + TWLMICResult result; + + // PXI通信エラーを確認 + if (err) + { + // シーケンスを強制終了 + TWLMICi_CallbackAndUnlock(TWL_MIC_RESULT_FATAL_ERROR); + return; + } + // 先頭データ + if (data & TWL_MIC_PXI_START_BIT) + { + // 受信データを解析 + SDK_ASSERT((data & TWL_MIC_PXI_RESULT_BIT) == TWL_MIC_PXI_RESULT_BIT); + micWork.total = (u8)((data & TWL_MIC_PXI_DATA_NUMS_MASK) >> TWL_MIC_PXI_DATA_NUMS_SHIFT); + micWork.current = 0; + micWork.command = (TWLMICPxiCommand)((data & TWL_MIC_PXI_COMMAND_MASK) >> TWL_MIC_PXI_COMMAND_SHIFT); + micWork.pxiResult = (TWLMICPxiResult)((data & TWL_MIC_PXI_1ST_DATA_MASK) >> TWL_MIC_PXI_1ST_DATA_SHIFT); + } + // 後続データ + else + { + if (micWork.current < TWL_MIC_PXI_DATA_SIZE_MAX) + { + micWork.data[micWork.current++] = (u8)((data & 0xFF0000) >> 16); + } + if (micWork.current < TWL_MIC_PXI_DATA_SIZE_MAX) + { + micWork.data[micWork.current++] = (u8)((data & 0x00FF00) >> 8); + } + if (micWork.current < TWL_MIC_PXI_DATA_SIZE_MAX) + { + micWork.data[micWork.current++] = (u8)((data & 0x0000FF) >> 0); + } + } + + if (micWork.current >= micWork.total-1) // > は無いはず + { + // 処理結果を確認 + switch (micWork.pxiResult) + { + case TWL_MIC_PXI_RESULT_SUCCESS: + result = TWL_MIC_RESULT_SUCCESS; + break; + case TWL_MIC_PXI_RESULT_INVALID_COMMAND: + result = TWL_MIC_RESULT_INVALID_COMMAND; + break; + case TWL_MIC_PXI_RESULT_INVALID_PARAMETER: + result = TWL_MIC_RESULT_ILLEGAL_PARAMETER; + break; + case TWL_MIC_PXI_RESULT_ILLEGAL_STATUS: + result = TWL_MIC_RESULT_ILLEGAL_STATUS; + break; + case TWL_MIC_PXI_RESULT_BUSY: + result = TWL_MIC_RESULT_BUSY; + break; + default: + result = TWL_MIC_RESULT_FATAL_ERROR; + } + + switch (micWork.command) + { + case TWL_MIC_PXI_COMMAND_MIC_BUFFER_FULL: + // FULLコールバックの呼び出し + if (micWork.full_callback) + { + micWork.full_callback( result, micWork.full_arg ); + } + break; + + case TWL_MIC_PXI_COMMAND_ONE_SAMPLING: + // 単発サンプリング結果格納 + *micWork.pOneBuffer = (u16)(micWork.data[0] | (micWork.data[1] << 8)); + // 非同期関数用コールバックの呼び出し&ロック解除 + TWLMICi_CallbackAndUnlock(result); + break; + + case TWL_MIC_PXI_COMMAND_GET_LAST_SAMPLING_ADDRESS: + // 最新サンプリングデータアドレス格納 + *micWork.pLastSamplingAddress = (void *)(micWork.data[0] | (micWork.data[1] << 8) | (micWork.data[2] << 16) | (micWork.data[3] << 24)); + // 非同期関数用コールバックの呼び出し&ロック解除 + TWLMICi_CallbackAndUnlock(result); + break; + + case TWL_MIC_PXI_COMMAND_GET_AMP_GAIN: + // アンプゲイン格納 + *micWork.pAmpGain = micWork.data[0]; + // 非同期関数用コールバックの呼び出し&ロック解除 + TWLMICi_CallbackAndUnlock(result); + break; + + default: + // 非同期関数用コールバックの呼び出し&ロック解除 + TWLMICi_CallbackAndUnlock(result); + } + } +} + +/*---------------------------------------------------------------------------* + Name: TWLMICi_CallbackAndUnlock + + Description: コールバックの呼び出しとロックの解除を行う + + Arguments: result - ARM7から送られた結果 + + Returns: None. + *---------------------------------------------------------------------------*/ +static void TWLMICi_CallbackAndUnlock(TWLMICResult result) +{ + TwlMicCallback cb; + + // ロック解除 + if (micWork.lock) + { + micWork.lock = FALSE; + } + + // 非同期関数用コールバック呼び出し + if (micWork.callback) + { + cb = micWork.callback; + micWork.callback = NULL; + cb(result, micWork.callbackArg); + } +} + +/*---------------------------------------------------------------------------* + Name: TWLMICi_GetResultCallback + + Description: 同期関数が内部で実行する非同期関数の結果を取得するために + 使用する。 + + Arguments: result - 非同期関数の処理結果。 + arg - 使用しない。 + + Returns: None. + *---------------------------------------------------------------------------*/ +static void TWLMICi_GetResultCallback(TWLMICResult result, void *arg) +{ +#pragma unused( arg ) + + micWork.result = result; +} + +/*---------------------------------------------------------------------------* + Name: TWLMICi_WaitBusy + + Description: MICの非同期処理がロックされている間待つ。 + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +#if 0 +#include +static asm void TWLMICi_WaitBusy(void) +{ + ldr r12, =micWork.lock +loop: + ldr r0, [ r12, #0 ] + cmp r0, #TRUE + beq loop + bx lr +} +#include +#else +extern void PXIi_HandlerRecvFifoNotEmpty(void); +static void TWLMICi_WaitBusy(void) +{ + volatile BOOL *p = &micWork.lock; + + while (*p) + { + if (OS_GetCpsrIrq() == OS_INTRMODE_IRQ_DISABLE) + { + PXIi_HandlerRecvFifoNotEmpty(); + } + } +} +#endif