鳥なき里のマイコン屋(144) ラズパイPico、Arduino環境で外付けRTC接続

Joseph Halfmoon

前回、PlatformIOがいつの間にかラズパイPicoのRP2040に対応(Arduinoプラットフォームのみ)していたので吉例のLチカでその動作を確認しました。今回は、外付けのRTCからカレンダ時刻を読み込んで「使えるじゃん」と納得する、と。普通にArduinoのつもりでプログラムできる感じなのでSDKに比べると大分敷居が下がった感じもします。個人の好みだけれども。

※「鳥なき里のマイコン屋」投稿順Indexはこちら

(実験に使用したC++のソース全文は末尾に)

前回に引き続き、PlatformIOのRaspberry Pi PicoのページへのURLを貼っておきます。

Raspberry Pi Pico

ラズパイPicoのSDKを使ってプログラムする場合には、母艦のラズパイ4のRaspberry Pi OS上でビルドしてオブジェクトをSWD経由でアップロードしていました。今回、PlatformIOでArduinoプラットフォームを使う場合は PC 上でビルドして PCから直接 .UF2 ファイルをラズパイPicoに書き込んでいます。結局、どちらもPC上のVSCodeから操作しているので、外目にはやっていることはほとんど一緒に見えますが、気分(?)は大分違います。

ラズパイPicoに外付けするデバイス

外付けしてみるのは、『やっつけな日常(1) ラズパイ4のPython3でRTC-4543SAの読み書きテスト』という投稿で使用した、セイコーエプソン製のRTC-4543SAというデバイスを搭載した秋月製のボードです。先週上記の投稿をしたときに、ラズパイ4上のPython3で書いたプログラムで当日のカレンダ時刻を設定いたしました。そして単三電池3本から作っているゴージャスな独自3.3V電源で動作し続けています。上記の投稿後、ラズパイ4から取り外しましたが、ホストなしで動きつづけているはずのもの。

目論見では、ラズパイPicoに接続すれば、そのまま「生きている」カレンダ時刻を読み取れる筈。今回のラズパイPico接続の回路図は以下です。

RPi_RTC4543Schematic

前述のとおりRTCは単三電池3本から3.3Vを取り出す別電源で動作しています。「普通」はホストの電源が生きていたらそちらから電源をもらい、ホストの電源が落ちたらコイン電池1個でバックアップというスタイルかと思いますけど。

読み取り用のソフトウエア

前記の投稿にてRTCに読み書きできるPython3スクリプトを作成済です。今回は、ラズパイ4上に置いてあったそのPython3スクリプトをPCに転送し、RTCを読む関数について、ほぼほぼPython3と1対1対応な感じにArduino式のC++で書き換えました。既に動いているプログラムなので何も考えなくてよいので簡単だし。ただC++のfor文の中でつい in とか書いて怒られましたが。

書き換えの元になったPython3のソースは前記の投稿の末尾に、書き換え後のC++のソース(Arduinoプラットフォーム用)は本投稿末尾にあります。

PC上のVSCodeから編集しているところがこちら。Arduinoしてますか?という感じ。PlatformIOの「虫さんマーク」が良い感じです。.UF2形式のオブジェクトは、 .pio フォルダの中に build フォルダができているのでその中です。

RPi_RTC4543

実行結果

主要部分はPythonのソースをそのままC++に置き換えていって、「RTCのカレンダ・タイマ値を読んでSerialにprint出力するだけ」のテストプログラムとしました。先ほどの for 文の一件以外はタイポもなく、ビルドして、1発完動でした。Arduinoプラットフォームが楽なうえに、やっぱりPythonでも元のソースがあるとお楽です。

実行結果はこんな感じ。

0
>>Read from RTC 21-11-1 10:41:36

現在時刻読み取れていますね。時刻精度は確かめておらんけど。まあだいたい合ってる。日付もずれておらんし。

ラズパイPicoのRP2040には内蔵のRTCがあります。ネットワークかGPSにでも接続してあるのであれば、NTPとかGPSでもらった時刻を内蔵RTCに設定すればとりあえず使えるじゃないかと思います。ただ、ラズパイPicoには時計用の発振器搭載されていないみたいなので、内蔵RTCを頻繁に時刻補正できないのであれば、外付けのRTCにカレンダ時刻をお任せするのも手かと思います。

まあ、ラズパイPicoのArduinoプラットフォームは役に立つ、ことは確認できた(?)っと。

鳥なき里のマイコン屋(143) ラズパイPico、PlatformIOでArudino へ戻る

鳥なき里のマイコン屋(145) ラズパイPico、C/C++SDKでDMAを使ってみる に進む

実験に使用したソース

VSCode上のPlatformIO環境でセットアップした、Raspberry Pi RP2040用のArudinoプラットフォームでビルドして動作確認したもの

// RTC-4543SA TEST on Raspberry Pi Pico
#include <Arduino.h>

#define LED_PIN   (25)
#define DATA_PIN  (10)
#define CLK_PIN   (11)
#define WR_PIN    (12)
#define CE_PIN    (13)
#define DATA_BITS (52)

struct RTC4543dat {
  uint8_t sec;
  uint8_t min;
  uint8_t hour;
  uint8_t dow;
  uint8_t day;
  uint8_t mon;
  uint8_t year;
  uint8_t fdt;
};

int counter = 0;
uint8_t L[DATA_BITS];

void initRTC4543pins() {
  pinMode(CE_PIN, OUTPUT);
  digitalWrite(CE_PIN, LOW);
  pinMode(DATA_PIN, INPUT);
  pinMode(WR_PIN, OUTPUT);
  digitalWrite(WR_PIN, LOW);
  pinMode(CLK_PIN, OUTPUT);
  digitalWrite(CLK_PIN, LOW);
}

void iowait() {
  delayMicroseconds(3);
}

uint8_t bitRead4543() {
  uint8_t lv;
  digitalWrite(CLK_PIN, HIGH);
  iowait();
  lv = digitalRead(DATA_PIN);
  digitalWrite(CLK_PIN, LOW);
  iowait();
  return lv;
}

void dataRead() {
  digitalWrite(CE_PIN, HIGH);
  for (int i=0; i < DATA_BITS; i++) {
    L[i] = bitRead4543();
  }
  digitalWrite(CE_PIN, LOW);
}

void decode4543(struct RTC4543dat *p) {
  p->sec = L[6]*40 + L[5]*20 + L[4]*10 + L[3]*8 + L[2]*4 + L[1]*2 + L[0];
  p->min = L[14]*40 + L[13]*20 + L[12]*10 + L[11]*8 + L[10]*4 + L[9]*2 + L[8];
  p->hour = L[21]*20 + L[20]*10 + L[19]*8 + L[18]*4 + L[17]*2 + L[16];
  p->dow = L[26]*4 + L[25]*2 + L[24];
  p->day = L[33]*20 + L[32]*10 + L[31]*8 + L[30]*4 + L[29]*2 + L[28];
  p->mon = L[40]*10 + L[39]*8 + L[38]*4 + L[37]*2 + L[36];
  p->year= L[51]*80 + L[50]*40 + L[49]*20 + L[48]*10 + L[47]*8 + L[46]*4 + L[45]*2 + L[44];
  p->fdt = L[7];
}

void printCAL(char *mes, struct RTC4543dat *p) {
    Serial.print(">>");
    Serial.print(mes);
    Serial.print(" ");
    Serial.print(p->year);
    Serial.print("-");
    Serial.print(p->mon);
    Serial.print("-");
    Serial.print(p->day);
    Serial.print(" ");
    Serial.print(p->hour);
    Serial.print(":");
    Serial.print(p->min);
    Serial.print(":");
    Serial.println(p->sec);
}

void setup() {
  Serial.begin(9600);
  while(!Serial);
  pinMode(LED_PIN, OUTPUT);
  initRTC4543pins();
}

void loop() {
  struct RTC4543dat temp;
  Serial.println(counter++);
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);
  delay(1000);
  dataRead();
  decode4543(&temp);
  printCAL("Read from RTC", &temp);
}