Shuttle XS35V2 自動電源投入回路の製作


Shuttle XS35V2 自動電源投入回路の製作

24時間運用のサーバ用途としてShuttle の XS35 V2というベアボーンPCを買いました。なかなか小さくて省電力でいいのですが、このPCはACアダプタをコンセントを挿しただけでは電源が入りません。その後で本体の電源ボタンを押す必要があります。これでは、停電した場合、その後の復帰時に電源が切れたままになって不便です。

そこで、自動で電源を入れる回路を作ってみました

7/18 22:22追記

…ちょっと某所でXS35が話題に上がったので慌てて作ったエントリなのですが…2012/5/3に公開されたBIOS XS35V200.104では、「Restore on AC Power Loss」が追加されましたので、もはやこの回路は用済みです…orz…

XS35 V2 の解析


XS35を分解したところ、電源スイッチ部の基板には、12芯フラットケーブルと2Pコネクタの2種類の配線が繋がっています。テスターで確認したところ、この2pコネクタは、以下のような信号線になっていました。

  • 1番(茶色): 電源スイッチ。常時4.4V程度の電圧がかかっており、GNDに落とすことで電源が入る。GNDとの短絡電流を測ると50μAぐらいでしたので、100kΩ程度のプルアップ抵抗でVccに繋がっているものと推測されます。
  • 2番(黒色): 電源LED。電源が入っている時は3.4Vになっている。おそらく電流制限抵抗を通した出力で、スイッチ基板ではLEDと直結しているのでしょう。

この2本を制御することで、電源が切れている場合は自動で電源を入れる回路が作れそうです。

製作方針

大前提として、「メインテナンス性を考慮し、既存のコネクタから二股で信号線を取り出すなど、できるだけ本体に半田改造はしない」ことを目指します。

問題は制御回路を動作させるための電源です。電源が切れている状況でも、制御回路は動作させる必要がありますが、手当たり次第にコネクタの電圧をチェックしたのですが、スタンバイ電源らしき線はどこにもありませんでした。

そこで、電源スイッチ用のプルアップ電流で駆動することにします。100kΩ程度でプルアップされているということは、おおよそ15μA以内にすれば、端子電圧を3.3V以上に保ち、Hi のままになります。

XS35V2からは、[電源スイッチ]、[電源LED]、[GND]の3本を取り出して、これを電源投入回路につなぎます。

仕様


  • 8pinマイコン、Atmel ATtiny13V を使用
  • 電源スイッチおよび電源LEDからダイオードを通して電源供給。
  • 電源投入動作時は電源スイッチ端子をGNDに落とすため、電解コンデンサでマイコン供給電源を安定化する。
  • 電源LED端子をpin2=PB3/ADC3につなぐ。この電圧をA/D変換して電源状態を判別する。
  • 電源スイッチ端子をpin3=PB4につなぐ。普段は入力端子としておき、電源投入動作時には、出力Loにする。

回路

部品 価格
マイコン Atmel ATtiny13V 130円
molex PicoBlade 53047 1.25mm 2pピンヘッダポスト 15円
molex PicoBlade 51021 1.25mm 2pメスコネクタハウジング 10円
molex 1.25mm 2pメスコンタクトピン×2 20円
ICクリップ 85円
電解コンデンサ 22μF たぶん20円ぐらい
小信号用ダイオード×2本 たぶん10円ぐらい
合計 たぶん300円ぐらい

組み込み

下記のように3本の配線を接続してXS35に組み込みました

  • 電源スイッチ・電源LED: スイッチ基板へのコネクタを割り込む形で接続します
  • GND: 近くに無線LANのアンテナ端子がありますので、そこにICクリップで接続します

以上で、ACアダプタをつなぐと自動で起動するようになりました。実測で消費電流は5μAぐらいです。

写真を取り忘れてました…

プログラム

AVRstudio4 + WinAVR(avrgcc)で作りました。

概略

  • 内蔵のウォッチドッグタイマ用128kHz発振回路を8分周した16kHzで駆動します
  • 通常はスリープ状態に落として消費電力を削減。定期的に復帰して信号線を確認します。
  • 消費電力を最小限にするため、「パワーダウンモード」にして、起動にはウォッチドッグタイマー割り込みを使います。
  • 1秒に1回復帰し、電源LEDの電圧をA/D変換、1.2V(80/255)より低い場合は電源オフと判定
  • 10回続けて電源オフと判定された場合、電源スイッチ端子を0.2秒間GNDに落とす

ソースコード

ライセンスは修正BSDLモドキとします。煮るなり焼くなり好きにしてください。
プログラム(xs35power.c)

/*
シャトル製ベアボーンPC XS35 強制電源投入
 Ver.2012.07.03

ライセンス 日本語版:

Copyright (c) 2012, taka2. All rights reseved.

本ソフトウェアは、「ソース配布の際には、上述の著作権表示、この条項、
下記免責事項を含めること」という条件の下で、利用および配布することを
許可します。

本ソフトウェアは、著作権者によって現状のまま提供されるものであり、
品質などについては一切保証いたしません。また、本ソフトウェアを使用
することによって発生したいかなる損害に対して、著作権者は責任を一切
負いません。


license agreement English version:

Copyright (c) 2012, taka2. All rights reserved.

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright 
      notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY TAKA2 ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL TAKA2 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are 
those of the authors and should not be interpreted as representing official 
policies, either expressed or implied, of taka2.

砕けた日本語:
…なんか堅苦しいことを書いていますが、要は、修正BSDライセンスに対しバイナリ
配布の著作権表示条項を無くしたものです。ソースコードを再配布したりする時には、
ここにある文章は残しておいて欲しいですけど、あとは煮るなり焼くなり好きにして
構いません。

また、本当に参考になるかどうかは判りませんが、以下のソースコードの一部を参考に
して別のプログラムを作った場合には、著作権表示なんかは不要です。適当にコピペし
てもOKです。

対象CPU: ATtiny13V
ピン接続:
入力:
	pin2=PB3: 電源オン表示LEDアノード
出力
	pin3=PB4: 電源スイッチ

電源
	pin2・pin3から小信号用ダイオードを通してVCCに接続、10μFをVccとGNDに

デバイス利用割り当て
	WATCHDOG TIMER: 1秒間隔の割り込み発生

ヒューズ設定
	High
		0xFF=11111111
	Low
		0x6B=01101011
		CKDIV8=0: クロック8分周
		CKSEL10=11: 内蔵128kHz

*/
#define F_CPU (128000/8) // 128kHz DIV8 = 16kHz

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

#define TIME_BASE 1000				// ウォッチドッグタイマーを1秒間隔で動作
#define TIME_STARTUP_WAIT 5000		// 起動5秒後に電源オン
#define TIME_BUTTON_PUSH 200		// ボタンは0.2秒押す
#define TIME_WATCH_POWERDOWN 10000	// 電源が切れて10秒経ったら再度電源オン

#define COUNT_STARTUP_WAIT (TIME_STARTUP_WAIT / TIME_BASE)
#define COUNT_WATCH_POWERDOWN (TIME_WATCH_POWERDOWN / TIME_BASE)

#define TRUE (!0)
#define FALSE 0


ISR ( WDT_vect )
{
	// sleep からの復帰が目的なので何もしない
}

// A/Dコンバータから8bitデータを取得する
uint8_t adinput(void)
{
	uint8_t advalue;

	ADCSRA = (1<<ADEN);
	
	ADCSRA |= (1<<ADSC);
	loop_until_bit_is_clear(ADCSRA,ADSC);

	advalue = ADCH; // 結果取得
	ADCSRA = 0; // ADCオフ
	return advalue;
}

// 電源LEDの電圧を取得し、PCの電源が入っているかどうかをチェックする
uint8_t ispoweron(void)
{
	uint8_t advalue = adinput();
	return (advalue > 80) ? TRUE : FALSE;
}


// PCの電源を入れる
void poweron(void)
{
	// 電源ボタン押す、PB4 Z→L
	DDRB |= (1<<PB4);
	PORTB &= ~(1<<PB4);

	_delay_ms(TIME_BUTTON_PUSH);

	// 電源ボタン離す、PB4 L→Z
	DDRB &= ~(1<<PB4);
	PORTB &= ~(1<<PB4);
}

void init(void)
{
	// 割り込み禁止
	cli();

	// PB3/4を入力に、それ以外は出力
	DDRB = 0b11100111;
	PORTB = 0;

	// ADコンバータ設定
	// REFS0=0 基準電圧はVcc
	// ADLAR=1 結果を左揃え
	// MUX1:0=11 ADC3(PB3)を選択
	ADMUX = (1<<ADLAR) | (1<<MUX1) | (1<<MUX0);
	ADCSRA = 0;
	ADCSRB = 0;

	// pin2はADC3に接続(PB3デジタル入力切り離し)
	// pin7はADC1に接続(PB2デジタル入力切り離し)
	DIDR0 = (1<<ADC3D);
	DIDR0 = 0;

	// ウォッチドッグタイマー設定
	WDTCR |= (1<<WDCE);
	// ウォッチドッグ割り込み有効、監視間隔1秒
	WDTCR = (1<<WDTIE)|(1<<WDP2)|(1<<WDP1);
	//パワーダウンモード
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);

	// 割り込み有効
	sei();
}


int main(void)
{
	// 電源投入カウンタ。これが0になったら電源投入操作を行う
	int8_t powercheck = COUNT_STARTUP_WAIT;
	init();

	while (1) {
		// 1秒待つ(ウォッチドッグ割り込みでスリープ復帰)
		sleep_mode();
		if (ispoweron()) {
			// 電源が入っている場合は、カウンタ初期化
			powercheck = COUNT_WATCH_POWERDOWN;
		} else {
			// 電源が入っていない場合は、カウントダウン
			powercheck--;
			if (powercheck <= 0) {
				// 0になったら、電源投入操作実施
				poweron();
				// カウンタ初期化
				powercheck = COUNT_WATCH_POWERDOWN;
			}
		}
	}

}