今となってはスペック不足となって、使わなくなったBananaPI M1。
せっかくなので、就寝時のオーディオプレイヤーとして、色々と機能を持たせて製作したい。
そもそも著者は、就寝時に音楽をかけながら眠りにつくので、少し特殊な使い方(要件)となるので、
備忘として残しておく
今回は色々と弄ったり、PICを使って利便性を上げたりなどしていて、資料が多くなる事が予想されるので、
章立てで進めて行くことにする。
とりあえず、音が出る事を確認。(mp3 or wav ファイル)
ヘッドレス状態で
PC用スピーカーとBPI用スピーカーの2台を置く事は、置き場所の問題もさることながら、
アンプ付きスピーカーである為、USB電源ではあるけど、配線周りもごちゃごちゃする。
また、節電対策としても(チューニングすれば可能かもしれないが)、PCやBPIのシャットダウン状態では、
USB電源は供給されたままであり、スピーカー電源が入りっぱなしだ。
PICやリレーを使って、スピーカー1台を共用する事にする。
今回の要件では、PCとBPIを同時に音を鳴らす必要は無い。
・ スピーカーの電源は、
・ スピーカーへの音声出力は、
PCのシャットダウン状態のUSB電源供給OFFは、BIOS設定で可能となったが、
BPI側の設定が不明 (そもそも設定可能かも不明)
BPI側のUSB電源供給ストップについては、後述する「3.2 BananaPIの電源供給コントロールの仕組み」で実装する。
ブレッドボード上のテストでは、BPI側の電源供給はストップ可能であると仮定して、単体テストを行う。
/* * File: main.c * Author: kampari * PIC: 12F509 * MPLAB X IDE V6.20 * XC8 V2.46 * Created on 2024/09/15, 19:57 * * PCとBananaPiをスピーカー1台で利用する オーディオセレクタ * * 接続環境/仕様 * PC、BPIからそれぞれUSB(5V受電用)と音声出力(3.5φ) * スピーカーは、電源供給用USB(5V) と音声入力(3.5φ) * スピーカーの電源供給は、PC、BPIから供給し、PC、BPIの電源ONにて供給 * PC、BPIが2台同時ON状態時は、BPIからの音声を優先とし、 * スライドSWでPC優先に変更可能とする * PC、BPI両方の電源OFF時は、スピーカーの電源供給OFFとする * BPIはshutdownで電源OFFとなるが、未来RPI置き換え時(shutdownでhalt)を考慮しておく * * 配線仕様 * VDD VSS * PC 5V(IN) GP5 GP0 スピーカー電源供給flag (ON=1 OFF=0) * BPI 5V(IN) GP4 GP1 音声セレクタ(リレー電源) (BPI ON時 1 OFF時0) * GP3(MCR) GP2 PC優先flag (優先時=1 Default=0) */ #include <stdio.h> #include <stdlib.h> #include <xc.h> // PIC12F509 #pragma config OSC = IntRC // Oscillator Selection bits (internal RC oscillator) #pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config CP = OFF // Code Protection bit (Code protection off) #pragma config MCLRE = ON // GP3/MCLR Pin Function Select bit (GP3/MCLR pinfunction is digital input, MCLR internally tied to VDD) #ifndef _XTAL_FREQ #define _XTAL_FREQ 4000000 #endif #define ON 1 #define OFF 0 void main(void) { // 12F509 Settiing OSCCAL = 0b01111110; // 4MHz TRISGPIO = 0b00111100; // GPIO Setting GP2-5:InPut GP0-1:OutPut CLRWDT(); OPTION = 0b11000111; // BIT0-2:TMR0 Prescaler 256 GP0 = OFF; GP1 = OFF; register unsigned char i = 0; register unsigned char j = 0; register unsigned char k = 0; while(1){ for( i = 0 ; i < 6; i++ ) { if ( ( GP4 == ON ) || ( GP5 == ON ) ){ j++; } if ( ( GP4 == OFF ) && ( GP5 == OFF ) ){ k++; } __delay_ms(500); } if ( j == 6 ){ if ( GP0 == OFF ) { GP0 = ON; } if ( ( GP4 == ON ) && ( GP2 == OFF ) && ( GP1 == OFF ) ){ GP1 = ON; } else if ( ( GP4 == ON ) && ( GP2 == ON ) && ( GP1 == ON ) ){ GP1 = OFF; } else if ( ( GP4 == OFF ) && ( GP1 == ON ) ){ GP1 = OFF; } } if ( ( k == 6) && ( GP0 == ON) ) { GP0 = OFF; GP1 = OFF; } j = 0; k = 0; } }
BPI shutdown時にUSB供給をカットする為には、BPIへの電源供給をカットする為に、PICとリレーを使い、電源コントロールを行う。
BPIのUSB電源供給及び、GPIOピン(5V,3.3V,信号ピンなど)は、以下の3パターンである事が分かった。
A. BPI電源未接続状態
→ USB電源供給及び、GPIOピンはLow (当たり前)
B. BPI電源ON状態
→ USB電源供給は5V。 GPIOピン(5V,3.3V)は出力。他の信号PinのHigh/Lowは設定による。
C. BPI電源ON後にshutdown実施 (電源接続状態)
→ LEDランプが消灯するので、USBやGPIOピン電圧も供給停止となると思いきや、
上記Bの状態を維持。
著者はケースファンは未装着なのだが、装着しているとshutdown後も回りっぱなしとなるだろう。
上記の状態からGPIOピンの状態を調査。BPI電源ON状態でデフォルトLow状態。OSからコマンドでHighへ変更可能であること。
もしくは、OS起動状態でHigh状態。上記Cの状態でLow状態である事。
この条件に一致するのは、GPIO J12 Pin5番であり、Pin5のLow/Highにて判定する。
/* * File: main.c * Author: kampari * PIC: 12F509 * MPLAB X IDE V6.20 * XC8 V2.46 * Created on 2024/09/15, 19:57 * * BananaPiの電源を外部リレーを使ってOFF/ONする * * 接続環境/仕様 * Switch押下されるまで待ち状態(何もしない) * GP5 Switch ONにすると、GP0はHighを出力 (リレー動作 BPIへ電源供給開始) * GP4 がHigh入力後に、一定時間 Low状態となった場合、GP0はLowを出力 (リレー復帰 BPIへ電源供給停止) * GP3 Switch ONにすると、MCLR (リレー復帰 BPIへ電源供給停止) * * 配線仕様 * VDD VSS * ON Switch GP5 GP0 BPI電源供給(リレー電源) (BPI ON時 1 OFF時0) * BPI halt状態監視 GP4 GP1 動作確認用LED * Reset Switch GP3 GP2 */ #include <stdio.h> #include <stdlib.h> #include <xc.h> // PIC12F509 #pragma config OSC = IntRC // Oscillator Selection bits (internal RC oscillator) #pragma config WDT = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config CP = OFF // Code Protection bit (Code protection off) #pragma config MCLRE = ON // GP3/MCLR Pin Function Select bit (GP3/MCLR pinfunction is digital input, MCLR internally tied to VDD) #ifndef _XTAL_FREQ #define _XTAL_FREQ 4000000 #endif #define ON 1 #define OFF 0 #define STEP 195 #define TMR0SET 256 - STEP // TMR0はカウントアップして、256でオーバーフローする。 // TMR0の初期値を 256 - 195 = 61に設定すれば、 // 61からカウントアップして、195回目に256 オーバーフローする。 static unsigned char CountTMR0 = 0; void Wait_50ms(void) { // TMR0のプリスケーラ最大256を設定しても、約63msでオーバーフローする。 // まず、基準となる1秒を作りたいので、50msでオーバーフローさせ、 // オーバーフローを20回カウントしたら、1秒(1000ms)とする。 TMR0 = TMR0SET; // Timer Clear while( TMR0 ); // Wait Counter Over Flow CountTMR0++; } void main(void) { // 12F509 Settiing OSCCAL = 0b01111110; // 12F509 IntRC = 4MHz動作 TRISGPIO = 0b00111000; // GPIO Setting GP3-5:InPut GP0-2:OutPut GPIO = 0b00000000; // GPIO ALL OFF; OPTION = 0b11000111; // BIT0-2:TMR0 Prescaler 256 // T0CS: Timer0 Clock Source Select bit 0: FOSC /4 // PICは、基本的に1命令サイクル(=4クロック)で実行する // ※ 1命令サイクル周期:使用クロックが4MHzなら(1/4000000) * 4 = 1 (μs) // TMR0の初期値 = 256 - 任意の割り込み発生間隔 (s) /( 1命令サイクル周期 (s) × プリスケーラ比 ) // 12F509 は、TMR0割り込みやオーバーフロー時のフラグ保存(レジスタ)は無いらしいので、 // TMR0の値を常にチェックして、プログラム上で条件処理を行う必要がある。 static unsigned char i = 0; static unsigned char j = 0; static unsigned char Count_GP4OFF = 0; while(1){ j = 0; for ( i = 1 ; i <= 5; i++ ) { if ( ( GP0 == OFF) && ( GP5 == ON ) ) { j++; } } if ( ( GP0 == OFF) && ( j == 5 ) ){ GP0 = ON; for ( i = 1; i <= 30; i++ ){ GP1 = ON; __delay_ms(500); GP1 = OFF; __delay_ms(500); } } if ( ( GP0 == ON) && ( GP4 == OFF )){ Wait_50ms(); if (CountTMR0 == 20 ){ // 50ms X 20 = 1秒間カウントしたら CountTMR0 = 0; Count_GP4OFF++; if ( Count_GP4OFF == 5 ){ // GP4が5秒間 OFFの場合、Haltと確定 Count_GP4OFF = 0; for ( i = 1; i <= 10; i++ ){ GP1 = ON; __delay_ms(500); GP1 = OFF; __delay_ms(500); } GP0 = OFF; for ( i = 1; i <= 10; i++ ){ GP1 = ON; __delay_ms(500); GP1 = OFF; __delay_ms(500); } } } } else if ( GP0 == OFF) { CountTMR0 = 0; Count_GP4OFF = 0; } } }