Raspberry Pi CM3でJUCE開発 #4 ラズパイをI2Sマスターに
オーディオコーデックをAK4558に変更することにした。
Raspberry PiはI2Sのマスタークロックが出力できないためにこれまでI2Sスレーブとして開発するつもりだった(Raspberry Pi CM3でJUCE開発 #2を参照)が、AK4558は内蔵PLLでビットクロックからマスタークロックを生成することができる。 そのため、ラズパイをI2Sマスター、AK4558をI2Sスレーブとして動かすことを目標として進めていく。
おおまかな流れとしては、
I2S入出力(マスター)のデバイスツリーオーバーレイを作成
I2CでAK4558の設定
JUCEからオーディオ入出力の確認
となる。
I2Sマスター用デバイスツリーオーバーレイ
使い方は前回と同じ。READMEにも諸々書いてあります。
pigpioを使う
pigpioはPythonやC/C++で使えるラズパイ用GPIO操作ライブラリです。 もちろんI2CやSPIも使えます。
JUCEでpigpioを使えるようにします。
インストール
code:console
sudo apt-get install pigpio
pigoioのデジタル出力サンプルコード(C++)
I2Cの前にデジタル出力を試します。
ラズパイのGPIOピン5を1秒間LOWにしたあとにHIGHにします。
ロジアナやLチカで確認してください。
code: pigpioDigitalOut.h
//chronoとthreadはスリープ関数用
static constexpr unsigned int DIGITALOUTPIN = 5;//GPIO pin 5
static constexpr unsigned int GPIOHIGH = 1;
static constexpr unsigned int GPIOLOW = 0;
code:pigpioDigitalOut.cpp
using std::chrono::milliseconds;
using std::this_thread::sleep_for;
/*
pigpioとI2Sを同時に使う場合はgpioInitialise()を呼ぶ前にgpioCfgClock(5, 0, 0)を呼ぶ
gpioCfgClock(macro, PWM/PCM, deprecated param)
macro: 5
PWM/PCM: 0:PWM, 1:PCM
*/
gpioCfgClock(5, 0, 0);
//pigpio初期化
if (gpioInitialise() < 0) {
//初期化失敗
std::cout << "Error: pigpio init failed" << std::endl;
}
else {
//初期化成功
std::cout << "pigpio is initialized" << std::endl;
}
//gpio 5をデジタル出力に設定
gpioSetMode(AK4558RESET, PI_OUTPUT);
//デジタル出力 LOW->High
gpioWrite(ak4558ResetGPIO, GPIOLOW);
sleep_for(milliseconds(1000)); //1000ms sleep
gpioWrite(ak4558ResetGPIO, GPIOHIGH);
//終了処理
gpioTerminate();
pigpioのI2Cサンプルコード(C++)
I2Cの簡単なサンプルです。
code: pigpioi2c.h
int i2cHandler;
static constexpr unsigned int i2cAddr = 0xF0; //I2Cアドレス
static constexpr unsigned int i2cRegister = 0x10; //I2Cレジスタ
static constexpr unsigned int i2cPort = 1;//Raspberry Pi I2C Port 1(0 or 1)
static constexpr unsigned int i2cFlag = 0;
static constexpr int TX_PACKET_SIZE = 1;//I2C data size(byte)
code:pigpioi2c.cpp
using std::chrono::milliseconds;
using std::this_thread::sleep_for;
/*
pigpioとI2Sを同時に使う場合はgpioInitialise()を呼ぶ前にgpioCfgClock(5, 0, 0)を呼ぶ
gpioCfgClock(macro, PWM/PCM, deprecated param)
macro: 5
PWM/PCM: 0:PWM, 1:PCM
*/
gpioCfgClock(5, 0, 0);
//pigpio初期化
if (gpioInitialise() < 0) {
//初期化失敗
std::cout << "Error: pigpio init failed" << std::endl;
}
else {
//初期化成功
std::cout << "pigpio is initialized" << std::endl;
}
//I2C初期化
//I2Cアドレス: i2cAddr
i2cHandler = i2cOpen(i2cPort, i2cAddr, i2cFlag);
if (i2cHandler < 0) {
//I2C初期化失敗
std::cout << "Error: i2cOpen()" << std::endl;
std::cout << "i2cHandler: " << i2cHandler << std::endl;
std::cout << "BADI2CBUS: " << PI_BAD_I2C_BUS << ", BADI2CADDR: " << PI_BAD_I2C_ADDR << ", NOHANDLE: " << PI_NO_HANDLE << ", I2COPENFAILED: " << PI_I2C_OPEN_FAILED << std::endl;
}
else {
//I2C初期化成功
std::cout << "I2C port is opened" << std::endl;
}
i2cTXBuffer0 = 0xFF//なんらかのI2Cデータ //I2C通信
//レジスタ: i2cRegister
if (i2cWriteI2CBlockData(i2cHandler, i2cRegisterA, i2cTXBuffer, TX_PACKET_SIZE)) {
//I2C通信失敗
std::cout<<"I2C failed"<<std::endl;
}
else {
//I2C通信成功
std::cout<<"I2C success"<<std::endl;
}
//終了処理
if(i2cClose(i2cHandler)) {
//I2C終了失敗
std::cout << "Error:i2cClose" << std::endl;
}
gpioTerminate();
JUCEでpigpioを使う
JUCEでpigpioを使うにあたってProjucerにいくつかのパスなどを記載する必要がある。
Linux Makefileの設定
External Libraries to Linkにpigpioを追加
https://gyazo.com/4d0407384f2c202974ebdc5374748385
Debug, Releaseビルドの設定
Header Search Pathsに/usr/includeを追加
Extra Library Search Pathsに/usr/libを追加
https://gyazo.com/8b8e51f17a6685f75283429b0de29aef
AK4558初期化コード
以上をつかって、自作AK4558基板のコーデック初期化フローを記述したプログラムがこちら。
AK4558.hのak4558Config()がコーデックの初期化処理。
オーディオ入力をそのままオーディオ出力にスルーするプログラム。
また、pigpioには管理者権限が必要なのでビルドしたアプリケーションは
code: console
sudo /AppName/Builds/LinuxMakefile/build/AppName
で起動しなければならない。
参考