Arduino
RaspberryPi
ATtiny

Raspberry Pi 用電源コントローラ

メカトラックスのSlee-Piみたいな スイッチサイエンスの 電源制御モジュールみたいなボード。https://www.switch-science.com/catalog/3268/
です。ATTiny841を使って再度試作してみました。

 一度 ATTiny85を使って試作しましたがちょと難があって、、

  1. 外部コントロールのためのビットが少ない
  2. i2c通信がソフトウェアでやっているので、時々通信エラーが出る

特に安定してi2c通信はしておきたい処です。もしかするとATTiny85のクロックを上げれば安定するかもしれませんが、消費電力も大きくなってしまうので悩ましいところです。やはりi2cがハードウェアで対応していた方が良いでしょう。

というわけで適当なCPUは無いかと、ATTiny841が丁度良いのではないかと使って見た次第です。ATTiny85の基板を使ってとりあえず試作。結構うまく行きました。

Wakeip841.jpeg

考えている回路図は以下の様なものです。試作なので全部実装はしていませんが、ATTinyからのコントロール線は拡張して使える様にしておきたいです。Raspberry Piとの間はi2cを主に使って通信すれば良いと思っています。

Wakeu841sch.png

スケッチはこんな感じ、、、i2c関連のライブラリはgithubにあります。
https://github.com/orangkucing/WireS
ATTiny側のソフト次第で色々な機能が付加出来ると考えています。アナログ入力で電源電圧を監視するとか、応用出来ると思います。

WakeupPi841.c
#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();
    }

}