Pico三昧(1) Pico C/C++ SDKで定番74HC595接続、ソフト制御編

Joseph Halfmoon

ラズパイPico関係の投稿が増えてきたので、総目次を新設し、あちこちに散在する投稿へのリンクを整理中です。ついてはラズパイPico専用で1シリーズを設けました。「Pico三昧」ですぞ。栄えある?第1回は以前Pico上のMicroPythonでやったことのある定番のシフトレジスタ74HC595の接続です(新味が無いな。)

(末尾に実験に使用したCソース全文を掲げました。)

開発環境のおさらい

まず最初に、今回使用の開発環境を説明しておきます。

PicoDevBLK
ターゲットボードは、言わずと知れた?

Raspberry Pi Pico

です。RP2040(Arm Cortex-M0+搭載)のマイクロコントローラボードです。このボード上のフラッシュROMにオブジェクトコードを書き込んで走らせるわけです。オブジェクトコードの生成(クロスコンパイル)などは、

Raspberry Pi 4 model B

を使用しています。OSはRaspberry Pi OS (32bit)です。Raspberry Pi 4を開発用の母艦として使うのには以下のような利点があると思っています。

  • Raspberry Pi財団標準の開発環境なのでツール、ライブラリ等充実
  • Raspberry Pi 4そのものがデバッグ・プローブの役目を果たす

ラズパイPicoのクロス開発はPC上でも可能ですが、デバッグをしようとすると何かしらの「プローブ」ハードウエアが必要だと思います。その点、Raspberry Pi 4であればクロス開発のホストがそのままデバッグプローブとなり、デバッガそのものがPi 4上で走ります。

しかし、ソースの編集などはWindows PCが好みです。そこで今や一番人気の定番IDEとなっている

VSCode

をWindows上で走らせ、ネットワーク経由でRaspberry Pi 4に接続しています。見かけはWindows上でソースを書くところから、ビルド、アップロード、デバッグ全てが完結。

今回接続するのは74HC595

74595は、今時(って何時よ?)の若者が生まれる前から存在する(多分)ロジックICです。8ビット・シフトレジスタ/ラッチ(トライステート)。以前、MicroPythonの以下の記事で7セグ4桁のLEDをダイナミック駆動するときにPicoに接続して使っています。

MicroPython的午睡(16) ラズパイPico、PIOで74HC595制御、簡単

今回、C/C++SDKを使ってCから制御するにあたり、以下のように計画いたしましたです。

  1. フルソフトウエア制御でまずは74HC595を1個を動かしてみる
  2. PIOステートマシンを駆使(?)して74HC595を1個を動かしてみる
  3. PIOを使って複数個の74HC595を動かしてみる(直列、並列)

上記のMicroPython記事は真ん中の2番だけだったです。今回は基本に戻って1番です。実験に使用する回路はこんな感じ。シンプル。

Raspberrry Pi Pico 74hc595 Schematicなお、過去記事では、ちょっと出所不明な怪しい(お楽しみの)中華パーツを使っていましたが、今回は以下の東芝製品を購入、使用しております。

TC74HC595AF

上記製品は、SOP16パッケージのため、ブレッドボードには直接刺さらないので秋月電子通商製のDIP化基板上に半田づけしてから使用しています(現物写真は冒頭のアイキャッチ画像ご覧ください。東芝のロゴマークが燦然と。)なお、SOP20用のDIP化ボードしか見当たらなかったので、端の4端子を捨てて16端子で使っています。

回路図は簡単ですが、テスト時は以下のようです。雑然。。。上からラズパイ4、右側ラズパイPico、下側 Digilent Analog Discovery 2(今回はオシロ&ロジアナとして使用)、左側74HC595を載せたブレッドボードです。

Pico74hc595DUT

ソフトウエアの作成

Raspberry Pi 4上でラズパイPico用のプロジェクトを開始する場合は、ラズパイ財団おすすめ?のPico用のProject Generator(Pythonスクリプト)が使えます。Project Generatorについては以下の公式ドキュメントの7.3に説明があります。

Getting started with Raspberry Pi Pico

これを利用するとメンドイ準備などは皆自動でやってくれるのでとても便利です。また、IDE Options欄でVSCodeで作業するためのファイル類もCOPYしておいてねとか、SWDデバッグやるからそれも準備お願い、とかいろいろ頼めます。こんな感じ。

595SoftProj上記でプロジェクトを生成した後、Windows上のVSCodeから、プロジェクトディレクトリへリモート接続したところを以下に示します。まだ何も書いていないのですが、自動生成された CMakeLists.txt が存在するのでそれを開いています。

今回は自動生成したCMakeLists.txtにまったく手を入れていません(ラズパイPico用のC/C++SDKは CMakeでビルドです。)

VScodeCMakeLists

動作確認

末尾のCソースをビルドしてラズパイPicoにアップロード後、まずは74HC595への制御の主要信号であるSCK(黄色)とSI(青色)の動作を確認してみました。黄色のSCKの立ち上がりエッジで青色のSIにのっているデータを取り込んで内部でシフトしていきます。8ビットなので8発SCKを立ち上げれば内部のシフトレジスタが8ビットのデータで満たされることになります。

TC74HC595のデータシートを見ると、もっとシフトクロックを速くしても大丈夫そうなのですが、今回は見やすさ優先でゆっくり動かしてます。他の制御信号についてはソースをご覧くだされ。

OscWaveさて、出力は8ビット分あるので、ロジアナ機能でその出力を観察してみます。末尾のソフトでは0から255までの値を74HC595に書き込んでいるのですが、LSBファーストで送り出しているので、QH端子(ロジアナのDIO7)にLSBの値が、QA端子(ロジアナのDIO0)にMSBの値が見えています。ソフトウエアでMSBファーストで送り出せば当然逆転させることも可能です。

OUTPUT_WAVE

今回は、ソフト制御で74HC595が使えたので、次回はラズパイPicoの特徴である、PIOステートマシンを使って制御してみる予定です。

ラズパイPico関係 総目次へ

Pico三昧(2) Pico C/C++ SDKで74HC595接続、PIO制御編単品

実験に使用したCソース全文
// 74HC595 Software Control
#include <stdio.h>
#include "pico/stdlib.h"

// 74HC595 PINS
#define SI      (18)
#define SCK     (19)
#define RCK     (20)
#define G_      (21)
#define SCLR_   (22)

void clear595() {
    gpio_put(SCLR_, false); //SCLR_=Low, clear
    sleep_us(1);
    gpio_put(SCLR_, true);
}

void outputEnable595() {
    gpio_put(G_, false); //G_=Low, outputEnable
}

void outputDisable595() {
    gpio_put(G_, true); //G_=High, outputDisable
}

void storeStorage595() {
    gpio_put(RCK, true);  //Rising Edge makes storage latch
    sleep_us(1);
    gpio_put(RCK, false);
}

void sendBitTo595(const uint8_t dat) {
    bool datBit = (bool)(dat & 1);
    gpio_put(SI, datBit);
    sleep_us(1);
    gpio_put(SCK, true);
    sleep_us(1);
    gpio_put(SCK, false);
}

void setup595() {
    gpio_init(G_);
    gpio_set_dir(G_, GPIO_OUT);
    outputDisable595();
    gpio_init(SCLR_);
    gpio_set_dir(SCLR_, GPIO_OUT);
    clear595();
    gpio_init(RCK);
    gpio_set_dir(RCK, GPIO_OUT);
    gpio_put(RCK, false); //RCK=Low
    gpio_init(SCK);
    gpio_set_dir(SCK, GPIO_OUT);
    gpio_put(SCK, false); //SCK=Low
    gpio_init(SI);
    gpio_set_dir(SI, GPIO_OUT);
    gpio_put(SI, false); //SI=Low
}

void send595(uint8_t dat) {
    for (int i=0; i<8; i++) {
        sendBitTo595(dat);
        dat >>=1;
    }
    storeStorage595();
    outputEnable595();
}

int main()
{
    uint8_t dat = 0;

    stdio_init_all();
    puts("74HC595 software control.");
    setup595();

    while (1) {
        send595(dat);
        dat = (dat < 255)? ++dat : 0;
        sleep_ms(1);
    }
    return 0;
}