/*******************************************************************************
MPLAB Harmony ApplicationSource File
Company:
Microchip Technology Inc.
File Name:
app.c
Summary:
This file contains the source code for the MPLAB Harmony application.
Description:
This file contains the source code for the MPLAB Harmony application. It
implements the logic of the application's state machine and it may call
API routines of other MPLAB Harmony modules in the system, such as drivers,
system services, and middleware. However, it does not call any of the
system interfaces (such as the "Initialize" and "Tasks" functions) of any of
the modules in the system or make any assumptions about when those functions
are called. That is the responsibility of the configuration-specific system
files.
*******************************************************************************/
// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved.
Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).
You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.
SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
*******************************************************************************/
// DOM-IGNORE-END
// *****************************************************************************
// *****************************************************************************
// Section: Included Files
// *****************************************************************************
// *****************************************************************************
#include "app.h"
#include "stdio.h"
char Buf[32]; //液晶表示バッファー
int Num; //
int Numx; //演奏曲No
int Num_max; //SD収納曲数
APP_DATA appData;
SYS_FS_HANDLE dirHandle; //ディレクトリハンドル
SYS_FS_FSTAT stat;
char longFileName[300];
SYS_FS_RESULT Result;
SYS_FS_HANDLE fileHandle1; //ファイル ハンドル
char File_Name[30][300]; //ファイル名
DRV_HANDLE tmrHandle; //タイマ2ハンドル //44.1KHz
bool PlayFlag; //1:演奏中、 0:非演奏中
int Num_buf; //読込みバイト数
bool Flag_BufAB; //SDからの読み込むバッファモード 0:バッファーB 1:バッファーA
bool SD_Read; //SD読み出しフラグ 1:SDからデータを読み出す 0:SDからデータを読みださない
unsigned int ptr_A, ptr_B; //バッファーポインタ
short int Dummy;
__attribute__((coherent)) unsigned char Buf_A[4096]; // バッファA
__attribute__((coherent)) unsigned char Buf_B[4096]; // バッファB
__attribute__((coherent)) unsigned short SpiOut_A; // 16ビットサウンドSpiデータA
__attribute__((coherent)) unsigned short SpiOut_B; // 16ビットサウンドSpiデータB
//待ち時間設定
uint32_t Wait = 63; //周期レジスタ初期値 //最初の割り込みまでの時間をセット
//5 nsec x2 x63 x 8 = 5040nsec = 5.04μsec
int delay_Clock = 200000000; //200MHz
const unsigned char CS0[] = {0x00};
const unsigned char CS1[] = {0x04};
SYS_DMA_CHANNEL_HANDLE channelHandle0;
SYS_DMA_CHANNEL_HANDLE channelHandle1;
SYS_DMA_CHANNEL_HANDLE channelHandle2;
DRV_HANDLE Wait_Handle;
void delay_us(volatile unsigned int usec);
void delay_ms(volatile unsigned int msec);
void SwCheck(void);
void tmrISR2(uintptr_t context, uint32_t alarmCount );
void tmrISR(uintptr_t context, uint32_t alarmCount );
void delay_us(volatile unsigned int usec);
void delay_ms(volatile unsigned int msec);
void SwCheck(void);
void tmrISR2(uintptr_t context, uint32_t alarmCount );
void tmrISR(uintptr_t context, uint32_t alarmCount );
void PStart(void);
void PlayStop(void);
void APP_SYSFSEventHandler(SYS_FS_EVENT event, void * eventData, uintptr_t context);
void SearchFile(void);
void delay_us(volatile unsigned int usec) //1μsec遅延
{
volatile int count;
count = (int)(delay_Clock/20000000)*usec;
do //実測 at 200MH (Clock=200000000)
{ //delay_us(1000):1000.4μsec delay_us(100):100.6μsec delay_us(10):10.5μsec delay_us(1):1.5μsec
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");asm("NOP");
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
count--;
}while(count != 0);
}
void delay_ms(volatile unsigned int msec) //1msec遅延
{
volatile unsigned int i; //実測:at200MH (Clock=200000000)//delay_ms(1): 1.0006msec delay_ms(100):100.04msec
for(i=0; i<msec; i++)
delay_us(1000);
}
void SwCheck(void) //SW クリック検出
{
if(appData.deviceIsConnected == true)
{
if(PORTBbits.RB0 == 0) //music スタート/ストップ
{
delay_ms(50);
if(PORTBbits.RB0 == 0)appData.state = APP_STATE_START_STOP;
}
if(PORTBbits.RB1 == 0) //music スキップ
{
delay_ms(50);
if(PORTBbits.RB1 == 0)
{
PlayFlag = 0;
appData.state = APP_STATE_SKIP;
}
}
}
}
void tmrISR2(uintptr_t context, uint32_t alarmCount ) //タイマ4コールバック関数
{
//ここにコードは記載されていませんが、このタイミングでDMA2チャンネルが起動しています。
}
void tmrISR(uintptr_t context, uint32_t alarmCount ) //タイマ2コールバック関数 //44.1KHz(22.7μsec)インターバル
{
DRV_TMR_AlarmRegister ( Wait_Handle, Wait, false, 0, tmrISR2 ); //非繰り返し呼び出し
DRV_TMR_Start(Wait_Handle); //タイマ4割り込み許可、タイマ4イネーブル
if(Flag_BufAB == 0){ // バッファAの場合
// LATFbits.LATF2 = 0; //MCP4922 CS = 0
SpiOut_A = ((((Buf_A[ptr_A+1] * 256 + Buf_A[ptr_A])/ 16) + 2048) | 0b0011000000000000); //Lチャンネル Soundデータ送信
//MP4922 制御コマンド
//VoutAにゲイン2で出力
//MCP4922への書き込みコマンド
//bit15(書き込みレジスタ選択) 1:VoutB 0:VoutA
//bit14(予備)
//bit13(出力ゲイン選択) 1:1倍 0:2倍
//bit12(出力オフ制御) 1:出力ON 0:出力OFF
//bit11 - bit0 データ MSBから順次送信される
// SPI4BUF = SpiOut_A;
//
// //Vout = 2.048×2×Dn/4095 Vout(max) = 4.096[V] ( > 3.3V(電源電圧)) 4.096×3.3/5 = 2.7V (< (3.3V時オペアンプ飽和電圧))
// //Vout = 2.7×Dn/4095 //32767
ptr_A += 2; //Sound data 2バイト → ポインタ +2
// while(SPI4STATbits.SPITBF); //: SPI Transmit Buffer Full Status bit //SPI4SRレジスタへの書込み完了
// delay_us(5); //MCP4922の処理待ち(必須)
// LATFbits.LATF2 = 1; //MCP4922 CS = 1;
Dummy = Buf_A[ptr_A+1] * 256 + Buf_A[ptr_A]; //Rチャンネルデータ出力
ptr_A += 2; //Sound data 2バイト → ポインタ +2
if(ptr_A >= Num_buf){ // バッファAデータ読み出し完了の場合
Flag_BufAB = 1; // 読み出し先をバッファーBに変更
SD_Read = 1; // SD読み出しフラグセット
ptr_A = 0; // ポインタAリセット
}
}
else
{ // バッファBの場合
// LATFbits.LATF2 = 0; //MCP4922 CS = 0
SpiOut_A = (((Buf_B[ptr_B+1] * 256 + Buf_B[ptr_B]) /16) + 2048 | 0b0011000000000000);
// SPI4BUF = (((Buf_B[ptr_B+1] * 256 + Buf_B[ptr_B]) /16) + 2048 | 0b0011000000000000);
ptr_B += 2; // ポインタB更新
// while(SPI4STATbits.SPITBF); //: SPI Transmit Buffer Full Status bit //SPI4SRレジスタへの書込み完了
//
Dummy = Buf_B[ptr_B+1] * 256 + Buf_B[ptr_B]; // 次のRchデータ出力
ptr_B += 2; // ポインタB更新
//
// delay_us(5); //MCP4922の処理待ち
//
// LATFbits.LATF2 = 1; //MCP4922 CS = 1;
if(ptr_B >= Num_buf){ // バッファ終了の場合
Flag_BufAB = 0; // バッファ切り替え
SD_Read = 1; // SD読み出しフラグセット
ptr_B = 0; // ポインタBリセット
}
}
}
void PlayStart(void) //演奏開始
{
fileHandle1 = SYS_FS_FileOpen(&File_Name[Numx][300], (SYS_FS_FILE_OPEN_READ));
if(fileHandle1 == SYS_FS_HANDLE_INVALID)LATDbits.LATD4 = 1; //ファイルオープン失敗の場合 RD4 LED点灯
Num_buf = SYS_FS_FileRead(fileHandle1, Buf_A, 4096);
Flag_BufAB = 0; //読込みバッファ:B
ptr_A = 0x2C; // WAVファイルの先頭指定 //オフセット44(0x2C)
ptr_B = 0; // バッファポインタリセット
SD_Read = 1; // SDカード読み込み許可
DRV_TMR_Start(tmrHandle); //タイマ2割り込み許可、タイマ1イネーブル //44.1KHz 割り込み開始
}
void PlayStop(void) //演奏停止
{
int i;
SYS_FS_FileClose(fileHandle1); // ファイルクローズ
DRV_TMR_Stop(tmrHandle); //タイマ2割り込み禁止 //44.1KHz 割り込み禁止 // Lch割り込み禁止
// バッファクリア
for(i=0; i<4096; i++){
Buf_A[i] = 0;
Buf_B[i] = 0;
}
}
void SearchFile(void) //SDカード(ルート)の *.wavファイル探索
{
dirHandle = SYS_FS_DirOpen("/mnt/myDrive1");
stat.lfname = longFileName;
stat.lfsize = 300;
Num = 0;
do
{
Result = SYS_FS_DirSearch(dirHandle, "*.wav", SYS_FS_ATTR_ARC, &stat);
if(Result == SYS_FS_RES_SUCCESS) //SYS_FS_RES_SUCCESS = 0
{
Num++;
sprintf(&File_Name[Num][300],"%s",stat.lfname); //
}
}while(Result == SYS_FS_RES_SUCCESS);
Num_max = Num;
SYS_FS_DirClose(dirHandle);
}
// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************
/*******************************************************************************
Function:
void APP_Initialize ( void )
Remarks:
See prototype in app.h.
*/
void APP_Initialize ( void )
{
/* Place the App state machine in its initial state. */
appData.state = APP_STATE_INIT;
appData.deviceIsConnected = false;
/* TODO: Initialize your application's state machine and other
* parameters.
*/
//DMAチャンネル諸元設定(Harmony ライブラリ関数)
//----------------------------------------------------------------------------------------------------
channelHandle0 = SYS_DMA_ChannelAllocate(DMA_CHANNEL_0); //RFポート用 DMAチャンネルオープン & ハンドル取得
SYS_DMA_ChannelTransferAdd(channelHandle0, &CS0, sizeof(CS0), (const void *)&LATF , 1, 1 ); //RF2 = 0(CS = 0)
SYS_DMA_ChannelSetup(
channelHandle0,
SYS_DMA_CHANNEL_OP_MODE_AUTO, //データ、アドレス自動インクリメント
DMA_TRIGGER_TIMER_2 //トリガソース:タイマ2
);
SYS_DMA_ChannelEnable(channelHandle0);
channelHandle1 = SYS_DMA_ChannelAllocate(DMA_CHANNEL_1); //RGポート用 DMAチャンネルオープン & ハンドル取得
SYS_DMA_ChannelTransferAdd(channelHandle1, &SpiOut_A, sizeof(SpiOut_A), (const void *)&SPI4BUF, 2, 2 ); //SPI4バッファーへ書き込み
SYS_DMA_ChannelSetup(
channelHandle1,
SYS_DMA_CHANNEL_OP_MODE_AUTO, //データ、アドレス自動インクリメント
DMA_TRIGGER_TIMER_2 //トリガソース :タイマ2
);
SYS_DMA_ChannelEnable(channelHandle1);
channelHandle2 = SYS_DMA_ChannelAllocate(DMA_CHANNEL_2); //RFポート用 DMAチャンネルオープン & ハンドル取得
SYS_DMA_ChannelTransferAdd(channelHandle2, &CS1, sizeof(CS1), (const void *)&LATF , 1, 1) ; //RF2 = 1(CS = 1)
SYS_DMA_ChannelSetup(
channelHandle2,
SYS_DMA_CHANNEL_OP_MODE_AUTO, //データ、アドレス自動インクリメント、
DMA_TRIGGER_TIMER_4 //トリガソース:タイマ4
);
SYS_DMA_ChannelEnable(channelHandle2);
//DMAチャンネル諸元設定(レジスタ直接制御)
//----------------------------------------------------------------------------------------------------
////レジスタ直接制御
////割り込み優先度設定
//IPC33bits.DMA0IP = 1; //設定:IPL 1
//IPC33bits.DMA0IS = 0; //設定:sub-IPL 0
//IPC33bits.DMA1IP = 1; //設定:IPL 1
//IPC33bits.DMA1IS = 0; //設定:sub-IPL 0
//IPC34bits.DMA2IP = 1; //設定:IPL 1
//IPC34bits.DMA2IS = 0; //設定:sub-IPL 0
//
//
////チャンネル0
//DCH0CONbits.CHAEN = 1; //チャンネル自動起動モード //必須 繰り返し用
//DCH0CONbits.CHEN = 1; //DCH0有効化 追加
//DCH0ECONbits.CHSIRQ = 9; //★スタートIRQ = 9(タイマ2) データシートより //★★★タイマ1が周期レジスタPR1と一致で割り込み発生
//DCH0ECONbits.SIRQEN = 1; //★IRQスタート有効
//
////チャンネル0 転送諸元
//DCH0SSA = KVA_TO_PA(&CS0); //転送元アドレス
//DCH0DSA = KVA_TO_PA((const void *)&LATF); //転送先アドレス //RF
//DCH0SSIZ = sizeof(CS0); //転送元サイズ
//DCH0DSIZ = 1; //転送先サイズ
//DCH0CSIZ = 1; //転送サイズ(セルサイズ)
//
//
////チャンネル1
//DCH1CONbits.CHAEN = 1; //チャンネル自動起動モード //必須 繰り返し用
//DCH1CONbits.CHEN = 1; //DCH0有効化 追加
//DCH1ECONbits.CHSIRQ = 9; //★スタートIRQ = 9(タイマ2) データシートより
//DCH1ECONbits.SIRQEN = 1; //★IRQスタート有効
//
////チャンネル1 転送諸元
//DCH1SSA = KVA_TO_PA(&SpiOut_A); //転送元アドレス
//DCH1DSA = KVA_TO_PA( (const void *)&SPI4BUF) ; //転送先アドレス //SPI4バッファー
//DCH1SSIZ = sizeof(SpiOut_A); //転送元サイズ
//DCH1DSIZ = 2; //転送先サイズ
//DCH1CSIZ = 2; //転送サイズ(セルサイズ)
//
//
////チャンネル2
//DCH2CONbits.CHAEN = 1; //チャンネル自動起動モード //必須 繰り返し用
//DCH2CONbits.CHEN = 1; //DCH0有効化 追加
//DCH2ECONbits.CHSIRQ = 19; //★スタートIRQ = 19(タイマ4) データシートより //★★★タイマ1が周期レジスタPR1と一致で割り込み発生
//DCH2ECONbits.SIRQEN = 1; //★IRQスタート有効
//
////チャンネル2 転送諸元
//DCH2SSA = KVA_TO_PA(&CS1); //転送元アドレス
//DCH2DSA = KVA_TO_PA((const void *)&LATF); //転送先アドレス //RF
//DCH2SSIZ = sizeof(CS1); //転送元サイズ
//DCH2DSIZ = 1; //転送先サイズ
//DCH2CSIZ = 1; //転送サイズ(セルサイズ)
//
//DMACONbits.ON = 1; // DMAモジュールON
//
//
//
tmrHandle = DRV_TMR_Open ( DRV_TMR_INDEX_1, DRV_IO_INTENT_EXCLUSIVE );
//タイマハンドル取得
uint32_t divider = 2267; //周期レジスタ初期値 //最初の割り込みまでの時間をセット
//5 nsec x2 x 2267 = 22670nsec = 22.67μsec --> 44.111 KHz = 44.1 KHz
//5 nsec x2 x 39063 x 256 = 100.00128msec
DRV_TMR_AlarmRegister ( tmrHandle, divider, true, 0, tmrISR ); //繰り返し呼び出し
//コールバック関数繰り返し呼び出しをセットアップ
// bool DRV_TMR_AlarmRegister(
// DRV_HANDLE handle,
// uint32_t divider, //周期レジスタ初期値
// bool isPeriodic, //周期性の有無
// uintptr_t context,
// DRV_TMR_CALLBACK callBack
// );
// タイマハンドル取得
Wait_Handle = DRV_TMR_Open ( DRV_TMR_INDEX_2, DRV_IO_INTENT_EXCLUSIVE ); //タイマ4ハンドル取得
// DRV_TMR_Start(myHandle); //タイマ1割り込み許可、タイマ1イネーブル
PLIB_SPI_Enable(SPI_ID_4); //SPIモジュール イネーブル
// SPI4CONbits.ON = 1; //SPI2 有効
lcd_init(); // LCD初期化
lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"SD Card ");//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf," WAV File Read "); //
lcd_str(Buf); // 開始メッセージ1行目表示
delay_ms(100);
}
void APP_SYSFSEventHandler(SYS_FS_EVENT event, void * eventData, uintptr_t context)
{
switch(event)
{
case SYS_FS_EVENT_MOUNT: //SDカード挿入済み
appData.deviceIsConnected = true;
LATGbits.LATG15 = 0; //RG15:消灯
break;
case SYS_FS_EVENT_UNMOUNT: //SDカード未挿入
appData.deviceIsConnected = false;
LATGbits.LATG15 = 1; //RG15:点灯
break;
default:
break;
}
}
/******************************************************************************
Function:
void APP_Tasks ( void )
Remarks:
See prototype in app.h.
*/
void APP_Tasks ( void )
{
switch ( appData.state )
{
case APP_STATE_INIT:
{
bool appInitialized = true;
if (appInitialized)
{
SYS_FS_EventHandlerSet(APP_SYSFSEventHandler, (uintptr_t)NULL);
appData.state = APP_STATE_WAIT_FOR_DEVICE_ATTACH;
}
break;
}
case APP_STATE_WAIT_FOR_DEVICE_ATTACH:
if(appData.deviceIsConnected)
{
appData.state = APP_STATE_SEARCH_FILE;
}
break;
case APP_STATE_SEARCH_FILE:
SearchFile();
Numx = 1;
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"%s ",&File_Name[Numx][300]);//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"Num=%d ",Num_max); //
lcd_str(Buf); // 開始メッセージ1行目表示
appData.state = APP_STATE_IDLE;
break;
case APP_STATE_IDLE:
if(appData.deviceIsConnected == false) //SDカードを抜くと 挿入検出待ちモードに移行する。
{
appData.state = APP_STATE_WAIT_FOR_DEVICE_ATTACH;
LATGbits.LATG15 = 1; //RG15:点灯
}
else LATGbits.LATG15 = 0;
if(SD_Read == 1) //SD Sound Data読み出しモード
{
SD_Read = 0;
if(Flag_BufAB == 0) //バッファBへの読み込み
{
Num_buf = SYS_FS_FileRead(fileHandle1, Buf_B, 4096); //4kバイト バッファBに読み込み
ptr_B = 0; // ポインタリセット
LATAbits.LATA14 = 1; //モニタLED ON
LATAbits.LATA15 = 0; //モニタLED OFF
}
else
{ //バッファーAへの読込み
Num_buf = SYS_FS_FileRead(fileHandle1, Buf_A, 4096); //4kバイト バッファAに読み込み
ptr_A = 0; // ポインタリセット
LATAbits.LATA15 = 1; //モニタLED
LATAbits.LATA14 = 0; //モニタLED OFF
}
}
break;
case APP_STATE_START_STOP:
if(PlayFlag == 0) //非演奏中の場合
{
PlayFlag = 1;
PlayStart(); //演奏開始
}
else //演奏中の場合
{
PlayFlag = 0;
PlayStop(); //演奏停止
}
appData.state = APP_STATE_IDLE; //アイドルモードへ
break;
case APP_STATE_SKIP:
PlayStop();
delay_ms(500);
SearchFile();
Numx++;
if(Numx == Num_max +1)Numx = 1;
lcd_cmd(0x80); //1目の先頭へ
sprintf(Buf,"%s ",&File_Name[Numx][300]);//
lcd_str(Buf); //液晶表示
lcd_cmd(0xC0); //2行目の先頭へ
sprintf(Buf,"Numx=%d ",Numx); //
lcd_str(Buf); // 開始メッセージ1行目表示
appData.state = APP_STATE_START_STOP;
break;
default:
break;
}
}
/*******************************************************************************
End of File
*/