Raspberry Pi 用電源コントローラ
メカトラックスのSlee-Piみたいな スイッチサイエンスの 電源制御モジュールみたいなボード。https://www.switch-science.com/catalog/3268/
です。ATTiny841を使って再度試作してみました。
一度 ATTiny85を使って試作しましたがちょと難があって、、
- 外部コントロールのためのビットが少ない
- i2c通信がソフトウェアでやっているので、時々通信エラーが出る
特に安定してi2c通信はしておきたい処です。もしかするとATTiny85のクロックを上げれば安定するかもしれませんが、消費電力も大きくなってしまうので悩ましいところです。やはりi2cがハードウェアで対応していた方が良いでしょう。
というわけで適当なCPUは無いかと、ATTiny841が丁度良いのではないかと使って見た次第です。ATTiny85の基板を使ってとりあえず試作。結構うまく行きました。
考えている回路図は以下の様なものです。試作なので全部実装はしていませんが、ATTinyからのコントロール線は拡張して使える様にしておきたいです。Raspberry Piとの間はi2cを主に使って通信すれば良いと思っています。
スケッチはこんな感じ、、、i2c関連のライブラリはgithubにあります。
https://github.com/orangkucing/WireS
ATTiny側のソフト次第で色々な機能が付加出来ると考えています。アナログ入力で電源電圧を監視するとか、応用出来ると思います。
# include <WireS.h>
# include <avr/sleep.h>
/*
Wake Up Pi ATTiny841
8MHz Internal Clock
// ATMEL ATTINY84 / ARDUINO ATTiny Universal lib
// Counter Clock Wise
//
// +--U--+
// VCC 1| |14 GND
// (D 0) PB0 2| |13 PA0 (D 10) AREF
// (D 1) PB1 3| |12 PA1 (D 9) {DOWN LED]
// RSET (D 11) PB3 4| |11 PA2 (D 8)
// PWM INT0 (D 2) PB2 5| |10 PA3 (D 7)
// PWM (D 3) PA7 6| |9 PA4 (D 6) SCL
// PWM SDA (D 4) PA6 7| |8 PA5 (D 5) PWM
// +-----+
The SCL of the ATTiny84 (pin 9)
The SDA of the ATTiny84 (pin 7)
*/
# define I2C_SLAVE_ADDRESS 0x5B // the 7-bit address
# ifndef TWI_RX_BUFFER_SIZE
# define TWI_RX_BUFFER_SIZE ( 16 )
# endif
# define FET 3 // GPIO FET pin PA7
# define SW1 7 // PowerON SW PA3
# define DOWN 9 // Shutdown DIO for Rpi PA1
# define SW2 8 // Option SW or DIO PA2
# define testled 2 // test LED
struct led {
int pin; // PIN No.
bool on; // ON/OFF status
int cont; // time count
int ontime; // ON time (100 msec tic )
int intval; // interval time (100 msec tic)
};
struct led waitled={DOWN,0,0,1,30};
struct led wakeled={DOWN,0,0,1,10};
struct led stopled={DOWN,0,0,15,16};
struct led waitled2={testled,0,0,1,30};
bool powon=false;
char stopping=0;
/*
* byt0 ... min
* byt1 ... hour
* byt2 ... day
* byt3 ... WakeupSTART
* byt4 ... ShutDownTimer
* byt5 ... SW Status
* byt6 ... reserve
* byt7 ... reserve
*/
enum {mins,hours,days,wakereg,downreg,swstat};
volatile uint8_t i2c_regs[] =
{
0,0,0,0,0,0,0,0
};
int dly=1000;
volatile byte reg_position;
const byte reg_size = sizeof(i2c_regs);
volatile unsigned wordAddr;
volatile boolean repeatedStart;
uint32_t downtimer;
uint32_t waketimer;
//int led = 7; // for ATT44 pin 6
//int led = 10; // for ATT44 pin 2
// When Address Received
boolean addressEvent(uint16_t slaveAddress,uint8_t count)
{
if(count>0){
reg_position= Wire.read();
}
return true;
}
// GET Reqesut
void requestEvent()
{
reg_position %= reg_size;
Wire.write(i2c_regs[reg_position]);
reg_position++;
}
// SET Event
void receiveEvent(uint8_t howMany)
{
// Sanity check
if ((howMany < 1) || (howMany > TWI_RX_BUFFER_SIZE)) return;
reg_position = Wire.read();
howMany--;
while(howMany--)
{
reg_position %= reg_size;
i2c_regs[reg_position] = Wire.read();
reg_position++;
}
if(i2c_regs[downreg]){
downtimer=i2c_regs[downreg];
}
if(i2c_regs[wakereg]){
waketimer = i2c_regs[mins]*60L+i2c_regs[hours]*60L*60L+i2c_regs[days]*60L*60L*24L;
} else {waketimer=0;}
}
void stopHandler()
{
}
uint32_t tim;
uint32_t last;
//uint32_t mtim;
//uint32_t mlast;
// the setup function runs once when you press reset or power the board
void setup() {
// mlast = mtim = millis();
tim = millis()/1000;
last =tim;
pinMode(FET,OUTPUT);
digitalWrite(FET ,LOW); // Normal Power OFF
pinMode(DOWN,OUTPUT);
pinMode(SW1, INPUT_PULLUP); // power on sw1
pinMode(SW2, INPUT_PULLUP); // power on sw2
pinMode(testled,OUTPUT);
Wire.begin(I2C_SLAVE_ADDRESS);
Wire.onAddrReceive(addressEvent);
Wire.onReceive(receiveEvent);
Wire.onRequest(requestEvent);
Wire.onStop(stopHandler);
delay(500);
}
void mydelay(unsigned long dt);
bool timchk()
{
tim = millis()/1000;
if(tim==last)
return false;
last=tim;
return true;
}
// Loop
void loop() {
if(!powon){
mydelay(100);
}else{
delay(100);
}
i2c_regs[swstat]= ~(digitalRead(SW1) | digitalRead(SW2) << 1) & 0B00000011;
// Power ON SW1
if(!stopping && !powon && !digitalRead(SW1)){
delay(200);
if(!digitalRead(SW1)){
poweron();
}
}
// Power ON SW2
if(!stopping && !powon && !digitalRead(SW2)){
delay(200);
if(!digitalRead(SW2)){
poweron();
}
}
//--------- Blink LED ---------//
if(!powon && !i2c_regs[wakereg]){
blinkled(&waitled);
}
if(i2c_regs[wakereg])
blinkled(&wakeled);
if(stopping){
blinkled(&stopled);
}
if(!timchk())
return;
// Power Down Sequence
if(powon && downtimer){
downtimer--;
i2c_regs[downreg] = (unsigned char)downtimer;
if(downtimer==0){
stopping=10;
digitalWrite(DOWN,HIGH);
}
}
// Wakeup Sequence
if(!powon && waketimer){
waketimer=waketimer-1;
if(waketimer==0){
i2c_regs[wakereg]=0;
poweron();
}
}
// Stop All Sequence
if(stopping){
stopping--;
if(stopping==0){
digitalWrite(FET, LOW);
digitalWrite(DOWN, LOW);
powon=false;
downtimer=0;
i2c_regs[downreg] = 0;
}
}
// SW1 Power Down Chech
/*
if(powon && !digitalRead(SW1)&& !stopping ){
delay(2500);
if(!digitalRead(SW1)){
digitalWrite(DOWN, HIGH);
stopping=15;
} else {stopping = 0;}
}
*/
}
/*
* Sub funcitons...
*/
void poweron()
{
digitalWrite(FET, HIGH);
digitalWrite(DOWN, LOW);
powon=true;
stopping=0;
downtimer=0;
}
void blinkled(struct led *myled)
{
int pin=myled->pin;
if(myled->cont++ == myled->ontime){
digitalWrite(pin,false);
myled->on=false;
} else if(myled->cont >= myled->intval){
digitalWrite(pin,true);
myled->cont=0;
myled->on=true;
}
// return myled->on;
}
void mydelay(unsigned long dt) {
unsigned long _t;
set_sleep_mode (SLEEP_MODE_IDLE);
_t = millis();
while( millis() - _t < dt ) {
sleep_mode();
}
}