電池駆動のデータロガーを作ってみる(3) — SDカードアクセスとタイマー割り込み処理の追加

次の要素はSPIバスにつながるSDカードへのアクセスです

<microPythonのSDカードアクセスライブラリと動作確認>

https://github.com/micropython/micropython-lib/tree/master/micropython

ここから持ってきました、

ライブラリの転送はVScodeでは面倒ぽいので、Thonnyを使って転送、ライブラリは一度ピコに書き込めばVScodeでもそのまま有効です、ただしVScodeですでにUSBシリアル使ってるとThonnyは接続できないから、VScode側は終了しないと競合してしまいます、逆も真也

実行時のVScodeのコンソール出力、上段はmicroSD未挿入だからエラーが出る、カードがラズパイ用のSDカードシステムなので。それらしきファイルが見えます、ファイル形式はおそらくFAT32しか扱えないと思う

———————————————————
MicroPython v1.26.0 on 2025-08-09; Raspberry Pi Pico2 with RP2350
Type "help()" for more information or .help for custom vREPL commands.

>>> 
Traceback (most recent call last):
  File "", line 7, in 
  File "sdcard.py", line 54, in __init__
  File "sdcard.py", line 82, in init_card
OSError: no SD card

>>> 
2025/09/12 17:18:00 Friday
alarm1 time is up
———————————————————

os.listdir(‘/sd’)	の結果を格納して出力(以下のコード)すると、

files = os.listdir('/sd')   # set to mount point

for file in files:
    print(file)

>>> 
overlays
bcm2708-rpi-b-plus.dtb
LICENCE.broadcom
issue.txt

~~~ 以下省略(ラズパイのシステムディスクだからこんな中身)

一応カード検出機能もGPIOに入れてるけど、SDカードにアクセスできなきゃこうなる、実際の運用ではカード検出できなかったら例えばLEDを高速点滅とかの手段だろうね

<タイマー割り込み設定>

タイマーIC(DS3231)のタイマー割り込み設定は絶対時間指定しかできないから、西暦以降全ての指定が必要、ただしタイマーICはデータ形式がBCD(Binary Code Decimal)、例えば十進21は15hではなく21hのような形式だから、内部で都度変換処理が必要、全部生成AIでコード作成したけどね

仮にUSB電源電圧を1分ごとにログするようにしてみた結果はこんな感じ、絶対時間で指定だから、相対時間指定のように段々処理時間が加算されて時間がずれていくようなことはない

Alarm time 1 min later: 20:28:31,Sunday,2025-09-14
5.09
Alarm time 1 min later: 20:29:31,Sunday,2025-09-14
5.09
Alarm time 1 min later: 20:30:31,Sunday,2025-09-14
5.1
Alarm time 1 min later: 20:31:31,Sunday,2025-09-14
5.09
Alarm time 1 min later: 20:32:31,Sunday,2025-09-14
5.1

 

<ファイルへの書き込み>

アナログ的に入力電圧を抵抗分割で1/3しているからリアルの電圧に換算してSDカードに書き込み、書き込みデータの最後の方はこんな風になってます

5.09
5.1
5.09
5.1
5.09
5.1
5.07

次は電源制御だね、広義にはmicroPythonでどこまで省電力動作できるかどうかということ

<今現在のコード>

おそらく冗長になってると思う、

#!/usr/bin/python
# -*- coding: utf-8 -*-
from machine import Pin, I2C, ADC
import time
import binascii
import machine, sdcard, os

#    https://www.waveshare.net/w/upload/0/08/Pico-RTC-DS3231_Sch.pdf
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21
SD_ON = 22

ALARM_PIN = 3
alarm_triggered = False

adc = ADC(Pin(26))  # ADC0 pin


class ds3231():
#            13:45:00 Mon 24 May 2021
#  the register value is the binary-coded decimal (BCD) format
#               sec min hour week day month year
    NowTime = b'\x00\x45\x13\x02\x24\x05\x21'
    w  = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
    address = 0x68
    start_reg = 0x00
    alarm1_reg = 0x07
    control_reg = 0x0e
    status_reg = 0x0f
    
    def __init__(self,i2c_port,i2c_scl,i2c_sda):
        self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))

    def set_time(self,new_time):
        hour = new_time[0] + new_time[1]
        minute = new_time[3] + new_time[4]
        second = new_time[6] + new_time[7]
        week = "0" + str(self.w.index(new_time.split(",",2)[1])+1)
        year = new_time.split(",",2)[2][2] + new_time.split(",",2)[2][3]
        month = new_time.split(",",2)[2][5] + new_time.split(",",2)[2][6]
        day = new_time.split(",",2)[2][8] + new_time.split(",",2)[2][9]
        now_time = binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ',''))
        #print(binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ','')))
        #print(self.NowTime)
        self.bus.writeto_mem(int(self.address),int(self.start_reg),now_time)

    def alarm_irq_handler(self, pin):
        global alarm_triggered
        alarm_triggered = True

    def set_alarm_time(self, alarm_time):
        self.alarm_pin = Pin(ALARM_PIN, Pin.IN, Pin.PULL_UP)
        self.alarm_pin.irq(handler=self.alarm_irq_handler, trigger=Pin.IRQ_FALLING)

    # ステータスフラグクリア
        status = self.bus.readfrom_mem(self.address, self.status_reg, 1)
        self.bus.writeto_mem(self.address, self.status_reg, bytes([status[0] & 0xFE]))

    # コントロールレジスタ設定 (INTCN=1, A1IE=1)
        self.bus.writeto_mem(self.address, self.control_reg, b'\x07')

    # アラーム時刻設定
        hour = alarm_time[0] + alarm_time[1]
        minute = alarm_time[3] + alarm_time[4]
        second = alarm_time[6] + alarm_time[7]
        date = alarm_time.split(",", 2)[2][8] + alarm_time.split(",", 2)[2][9]
        now_time = binascii.unhexlify((second + minute + hour + date).replace(' ', ''))
        self.bus.writeto_mem(self.address, self.alarm1_reg, now_time)

    def get_date(self):
        t = self.bus.readfrom_mem(self.address, self.start_reg, 7)
        year = 2000 + bcd2dec(t[6])
        month = bcd2dec(t[5])
        day = bcd2dec(t[4])
        return year, month, day

# time format conversion
def bcd2dec(bcd):
        return ((bcd >> 4) * 10) + (bcd & 0x0F)

def sdmount_getlist():
    sd = sdcard.SDCard(machine.SPI(0), machine.Pin(17))
    os.mount(sd, '/sd')
    files = os.listdir('/sd')   # set to mount point

    for file in files:
        print(file)

def get_adc_write(filename):
    value = round((adc.read_u16() >> 4) * 3.3 * 3 / 4096, 2)  # calculate real voltage and round to 2 degits below decimal point
    print(value)
    
    with open(filename, 'a') as f:
        f.write("{}\n".format(value))

def add_one_minute_to_rtc_time(rtc):
    # RTCから生の7バイトを取得(BCD形式)
    t = rtc.bus.readfrom_mem(rtc.address, rtc.start_reg, 7)
    
    year = 2000 + bcd2dec(t[6])
    month = bcd2dec(t[5] & 0x1F)
    day = bcd2dec(t[4] & 0x3F)
    hour = bcd2dec(t[2] & 0x3F)
    minute = bcd2dec(t[1] & 0x7F)
    second = bcd2dec(t[0] & 0x7F)
    weekday = t[3] & 0x07  # 1-7
    
    # 月ごとの日数 (うるう年考慮)
    def is_leap(year):
        return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
    def days_in_month(y, m):
        mdays = [31, 29 if is_leap(y) else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        return mdays[m-1]
    
    # 1分加算
    minute += 1
    if minute >= 60:
        minute = 0
        hour += 1
    if hour >= 24:
        hour = 0
        day += 1
        weekday = weekday + 1 if weekday < 7 else 1 if day > days_in_month(year, month):
            day = 1
            month += 1
            if month > 12:
                month = 1
                year += 1
    
    # 曜日文字列
    w = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
    weekday_str = w[weekday-1]
    
    # alarm_time 文字列形式 'HH:MM:SS,Weekday,YYYY-MM-DD'
    alarm_time_str = "{:02d}:{:02d}:{:02d},{},{:04d}-{:02d}-{:02d}".format(
        hour, minute, second, weekday_str, year, month, day)
    
    return alarm_time_str

# set alrm time period
def set_alarm():
    alarm_time_1min_later = add_one_minute_to_rtc_time(rtc)
    print("Alarm time 1 min later:", alarm_time_1min_later)
    rtc.set_alarm_time(alarm_time_1min_later)

if __name__ == '__main__':

    # SD card power control
    pow_pin = Pin(SD_ON, Pin.OUT)
    pow_pin.value(0)

    sdmount_getlist()
    
    # make RTC instance
    rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
    #rtc.set_time('15:38:00,Sunday,2025-09-14')
    
    set_alarm()
    
    # create file if not exists or open for append later
    year, month, day = rtc.get_date()
    filename = "/sd/{:04d}-{:02d}-{:02d}.txt".format(year, month, day)

    with open(filename, 'a') as f:
        pass  # to create if not exist

    get_adc_write(filename)
        
    try:
        while True:
            if alarm_triggered:
                alarm_triggered = False
                set_alarm()
                get_adc_write(filename)
    except KeyboardInterrupt:
        print("terminated")

<写真>

表裏です、裏はもりそばです

 

admin

電池駆動のデータロガーを作ってみる(2) — RTC周りをmicroPythonで動作確認

部品一式揃ったので、まずはRTC周りの動作確認

パーツだけは載せてみた、配線はまだ終わってないけどRTC動作確認はできる状態

VScodeでのmicroPython使い方としては以下を参考

https://kousaku-prog.com/vscode-micropython/

・拡張機能(MicroPico:VScodeの拡張機能として最も一般的)をインスト、実際はインスト済みであった

・プロジェクト初期化(メニューから以下の画像の機能を選択)して、以下から持ってきたmicroPythonのサンプルプロジェクトを置いとく

% wget -P ~/pico https://files.waveshare.com/upload/5/5a/Pico-rtc-ds3231_code.zip

スクリーンショット 2025-09-12 17.06.15.png

・microPythonのファーム(2025.8.9版:v1.26.0)をダウンロードしてきて、ディスクモードでラズピコに書き込むと接続状態になる(VScode下端のステータス表示)

スクリーンショット 2025-09-12 17.11.50.png

・VScodeのターミナルでrunをクリックすると実行される

スクリーンショット 2025-09-12 17.14.36.png

日時はPythonソースで設定されているだけ

・割り込み処理の受け側がないのでそれを追加、同時に割り込みが配線されてないからハードも修正(汚いけどR5相当をはんだブリッジした、これでGPIO3番につながる)

R5相当をジャンパーしたところ

jumper.jpg

コード(set_alarm_time())も元のコードでは割り込み待ち処理ないし、割り込み要因も適切じゃないので修正必要で、それは生成A.Iで修正、

#!/usr/bin/python
# -*- coding: utf-8 -*-
from machine import Pin, I2C
import time
import binascii

#    the first version use i2c1
#I2C_PORT = 1
#I2C_SDA = 6
#I2C_SCL = 7

#    the new version use i2c0,if it dont work,try to uncomment the line 14 and comment line 17
#    it should solder the R3 with 0R resistor if want to use alarm function,please refer to the Sch file on waveshare Pico-RTC-DS3231 wiki
#    https://www.waveshare.net/w/upload/0/08/Pico-RTC-DS3231_Sch.pdf
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21

ALARM_PIN = 3


class ds3231(object):
#            13:45:00 Mon 24 May 2021
#  the register value is the binary-coded decimal (BCD) format
#               sec min hour week day month year
    NowTime = b'\x00\x45\x13\x02\x24\x05\x21'
    w  = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
    address = 0x68
    start_reg = 0x00
    alarm1_reg = 0x07
    control_reg = 0x0e
    status_reg = 0x0f
    
    def __init__(self,i2c_port,i2c_scl,i2c_sda):
        self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))

    def set_time(self,new_time):
        hour = new_time[0] + new_time[1]
        minute = new_time[3] + new_time[4]
        second = new_time[6] + new_time[7]
        week = "0" + str(self.w.index(new_time.split(",",2)[1])+1)
        year = new_time.split(",",2)[2][2] + new_time.split(",",2)[2][3]
        month = new_time.split(",",2)[2][5] + new_time.split(",",2)[2][6]
        day = new_time.split(",",2)[2][8] + new_time.split(",",2)[2][9]
        now_time = binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ',''))
        #print(binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ','')))
        #print(self.NowTime)
        self.bus.writeto_mem(int(self.address),int(self.start_reg),now_time)
    
    def read_time(self):
        t = self.bus.readfrom_mem(int(self.address),int(self.start_reg),7)
        a = t[0]&0x7F  #second
        b = t[1]&0x7F  #minute
        c = t[2]&0x3F  #hour
        d = t[3]&0x07  #week
        e = t[4]&0x3F  #day
        f = t[5]&0x1F  #month
        print("20%x/%02x/%02x %02x:%02x:%02x %s" %(t[6],t[5],t[4],t[2],t[1],t[0],self.w[t[3]-1]))

    def set_alarm_time(self, alarm_time):
        self.alarm_pin = Pin(ALARM_PIN, Pin.IN, Pin.PULL_UP)
        self.alarm_pin.irq(lambda pin: print("alarm1 time is up"), Pin.IRQ_FALLING)

    # ステータスフラグクリア
        status = self.bus.readfrom_mem(self.address, self.status_reg, 1)
        self.bus.writeto_mem(self.address, self.status_reg, bytes([status[0] & 0xFE]))

    # コントロールレジスタ設定 (INTCN=1, A1IE=1)
        self.bus.writeto_mem(self.address, self.control_reg, b'\x07')

    # アラーム時刻設定
        hour = alarm_time[0] + alarm_time[1]
        minute = alarm_time[3] + alarm_time[4]
        second = alarm_time[6] + alarm_time[7]
        date = alarm_time.split(",", 2)[2][8] + alarm_time.split(",", 2)[2][9]
        now_time = binascii.unhexlify((second + minute + hour + date).replace(' ', ''))
        self.bus.writeto_mem(self.address, self.alarm1_reg, now_time)
        
if __name__ == '__main__':
    rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
    rtc.set_time('17:18:00,Friday,2025-09-12')
    rtc.read_time()
    rtc.set_alarm_time('17:18:10,Friday,2025-09-12')
    
    try:
        while True:
            time.sleep(1)  
    except KeyboardInterrupt:
        print("terminated")

割り込み処理が実行できました、

 

<今の回路図>

前回から手直し、特にRTC周りをオプションの回路図から書き写し

 

microPythonではdeepsleepとかちゃんと動かないらしいので、microPythonはプロトタイピングで本番はpico-sdkになるかな

 

admin

電池駆動のデータロガーを作ってみる(1)

ラズピコで低消費電力、概ね電池駆動(単三3本)で数ヶ月稼働、のデータロガーを作ってみる

<考慮点>

① 消費電力の観点からはラジピコはWi-Fi無しの素のモデルで、なおかつ相対的に低消費電力になるラズピコ2を使う

電源はVSYSから供給(単三アルカリ電池3直)する、内部のDC-DCで1.8V~5.5V程度の電圧変動範囲が受付可能、ただしDC-DCの効率最適化のような考慮は必要そう

② Wi-Fiなどの通信は使わずにSDスロットのカードにログを取る、但し待機電力大きいから電源のオンオフは制御必要

シンプルにP-chのFETスイッチで電源をオン・オフする

③ 時計機能が必要だからRTC機能を外付けする

https://www.switch-science.com/products/7335?_pos=41&_sid=61626aafc&_ss=r

④ 開発環境はVScodeでmicroPythonを使う、簡便で速度も不要だし

microPythonのファームウェアは現時点で(v1.26.0)が最新

machine.deepsleep処理はは実質ハードリセットと同じだから、再開時は初期化処理が必要

https://docs.micropython.org/en/latest/library/machine.html

<回路図>

部品は発注した、

 

admin

 

デジポテをi2cインターフェースからSPIに変更

i2cのMCP4018はレスポンスはまともに帰ってきても機能しなかった(レスポンスは返るから実装の問題ではないと思う)から、DIP品のMCP4131に変えてみた

MCP4131はデータ線が入出力共通なので、ドライバー側には抵抗入れてMCP4131が出力モードの時にレベルを確保できるようにしないといけない、その割には戻り値は使ってないですが

三端子ともオープンなので、使い方の自由度はMCP4018に比べると高い、これだとちゃんと書き込み値に応じて抵抗値も変化(当たり前、それが普通)

SPI版のデジポテ制御に変えたソースコードは、

https://github.com/chateight/dsp/blob/main/dsp.c

になります

 

admin

この機能に、フロントエンド(アナログ信号の前処理)追加、

https://isehara-3lv.sakura.ne.jp/blog/2025/07/02/オシロスコープのスイープとトリガ条件を追加/

① AC入力のマイナス側も扱えるように、GNDレベルをVss/2 = 1.65 V付近にする、ゲインはフルスケール考慮して-6db

② 次の処理でゲイン6db(プラス方向にしか振れないパルス用)と0db(AC信号用)の選択をデジタルポテンショメーター使ってできるようにした(ただし、i2cバスで値を書き込んでもレスポンスまともだけだけど結果は無視された状態、つまり電源投入状態のwiperが中点状態のまま)、目的はADCの前にダイナミックレンジを確保したかったから

後の処理ではオシロスコープとするには、ADCから読み取った値が反転しているから元に戻す処理必要だけど、コードには未反映

https://github.com/chateight/dsp

回路図とi2cのタイムチャートをアップロードしてあります

 

admin

 

 

 

オシロスコープのスイープとトリガ条件を追加

概ねどんなオシロスコープにもある表示モードは、

・トリガーモード

・フリーランモード

・ワンショットモード

昨日までの実装はトリガーモードだけだったので、フリーランモードを追加した

該当部分のロジックは、以下のコード、

要はおよそ4ms(2μs*2*1000)の間にトリガー要件が発生しないと、そこからADCのデータ取得して表示しています

ワンショットモードは、トリガーモードで一度条件発生したら以降のトリガーは無効にするだけだろうから包含されていて設定だけの問題

この機能を追加するだけで、普通のオシロスコープらしくなります

ADCの入力開放でフリーラン状態の写真、入力開放だと概ね0.8Vぐらいに見えるようです、何らかの入力保護回路は入っているんだろうけども

 

admin

スペアナにオシロスコープ機能を追加

周波数軸のスペアナに対して時間軸のオシロスコープ機能の実装、最終的には物理スイッチで機能切り替えだろうけど、今はソースコードに埋め込んだ変数で機能切り替え

ソースコードは以下になるけれども、スペアナコードをかなり流用

① ADCのサンプリングコード中に立ち上がりのエッジ検出ロジックを入れ込み(ほぼ方形波前提の検出ロジックになってます)

② LCDの表示バッファーは二面持たせて、変化分だけ描画はスペアナと同じだけどライン描画からドット描画だから相対的に高速のはず

以下は現状のコード

https://github.com/chateight/dsp

スペアナに入力しているおよそ2.3KHzの方形波を表示させたところ

・サンプル周期2μs(およそ500KHz)

・表示時間長はおよそ500μs(256フレーム*2μs)

 

admin

 

表示含めて基本のロジックは組み込み(ラズピコスペアナ)

いくつか当初の思惑と違ったところ、

1. 結局ADCデータ読み取りのDMA処理終わった後の割り込みが2回目以降は発生しない、デバッガで止めながらだと発生するからタイミング問題だろ受けで原因突き止めできない

2.  ADCのクロックデバイドはDMAモード以外でも有効化できない

従って、現状のロジックは、CPUが介在しておよそ500KHzで動くADCのデータを2μsごとに読み取って蓄積

以降の処理はDMA使った時と大差なし

3. LCDの表示処理は初回描画だけは画面全面書き込みになるけど、2回目以降は差分処理だけにして高速化、ただしフレーム周期は今の所およそ12ms*10 =120 ms にしている

4. 初回のLCD(全面書き込み)は500ms程度掛かっているから、FFTデータは一度表示用にコピーして、次のFFT処理で壊されないように別保存している、今は表示周期をおよそ120msぐらいにしているけども、2回目以降は変更部分のみの書き換えだから高速

この画像はおよそ2KHz(ちょっと下)の方形波をPWMから入力して9次の高調波まで表示されている状態

コード全体は、以下のリンクから

https://github.com/chateight/dsp

もちろん用途によるけど、ラズパイシリーズではラズピコが値段考えると一番使い出があるように思う

 

admin

pico-sdk使用してLCD表示(SPIバス)

LCDの動作確認のためにArduino IDEで動作確認(受入試験みたいなもので以下のリンク)しましたが、Cのライブラリ使わないとスペアナ計算と結合できないのでpico-sdk使ってやってみます

https://isehara-3lv.sakura.ne.jp/blog/2025/06/20/ラズピコでspiバス経由でlcd表示させる/

ライブラリは使い方がシンプルなので構造が単純な以下を使います

https://github.com/Imel23/lcd-st7789-library

ライブラリを使う時には、ハードワイヤリングの設定をソース上で行うこととSPIの動作モードを指定しないと動作しなかった(以下変更部分のコード)、それ以外には画面ローテーションの指定もしています、この記事の最後の方に記載

SPI clockは62.5MHzのままだと動作に不安があるので20MHzまで落としてます、どうせ62.5MHzでも最初の電源オンのチラつき(データが初期状態では不定だから)はあるから、バックライト信号の制御がいずれ必要

// Pin definitions for the LCD connection
//#define BL_PIN 13 // Backlight pin
#define DC_PIN 20   // Data/Command pin
#define RST_PIN 21  // Reset pin
#define MOSI_PIN 19 // SPI MOSI pin
#define SCK_PIN 18  // SPI Clock pin
#define CS_PIN 17   // Chip Select pin

// SPI configuration
#define SPI_PORT spi0
#define SPI_BAUDRATE 2000000  // 62.5 MHz SPI clock

// Function prototypes for internal use
static void lcd_write_command(uint8_t cmd);
static void lcd_write_data(uint8_t data);
static void lcd_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);

// Initialize the LCD
void lcd_init() {
    // Initialize SPI
    spi_init(SPI_PORT, SPI_BAUDRATE);
    spi_set_format(SPI_PORT, 8, SPI_CPOL_1, SPI_CPHA_1, SPI_MSB_FIRST);     // to add this line

ライブラリ用にcmakeファイルに設定を追加して、現状の中身は、

# Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)

# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
    set(USERHOME $ENV{USERPROFILE})
else()
    set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.1.1)
set(toolchainVersion 14_2_Rel1)
set(picotoolVersion 2.1.1)
#set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
#if (EXISTS ${picoVscode})
#    include(${picoVscode})
#endif()
# ====================================================================================
set(PICO_BOARD pico2_w CACHE STRING "Board type")

set(PICO_SDK_PATH "$ENV{HOME}/pi/pico/pico-sdk")
#set(PICO_SDK_PATH "/Users/usamiryuuichi/pi/pico/pico-sdk")


# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)

project(dsp C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Create a library for the LCD driver
add_library(lcd_driver STATIC
    lcd_st7789_library.c
    font_5x7.c
)

add_library(CMSISDSP STATIC IMPORTED GLOBAL)
set_target_properties(CMSISDSP PROPERTIES IMPORTED_LOCATION
  $ENV{HOME}/pi/pico/CMSISDSP/build/bin_dsp/libCMSISDSP.a)

#target_link_libraries(dsp CMSISDSP ...)

# Add executable. Default name is the project name, version 0.1

add_executable(dsp dsp.c )

pico_set_program_name(dsp "dsp")
pico_set_program_version(dsp "0.1")

# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(dsp 0)
pico_enable_stdio_usb(dsp 1)

# Add the standard library to the build
target_link_libraries(dsp
        pico_stdlib
        pico_multicore
        hardware_adc
        hardware_dma
        hardware_pio
        hardware_pwm
        hardware_spi
        CMSISDSP
        lcd_driver
        hardware_timer 
        pico_multicore
)

target_link_libraries(lcd_driver
    pico_stdlib
    hardware_spi
)

# Add the standard include files to the build
target_include_directories(dsp PRIVATE
        ${CMAKE_CURRENT_LIST_DIR}
        $ENV{HOME}/pi/pico/CMSISDSP/CMSIS-DSP/Include
        $ENV{HOME}/pi/pico/CMSISDSP/CMSIS_6/CMSIS/Core/Include
        ${PICO_SDK_PATH}/src/rp2
)

target_include_directories(lcd_driver PRIVATE
    ${CMAKE_CURRENT_LIST_DIR}
    ${PICO_SDK_PATH}/src/common
    ${PICO_SDK_PATH}/src/rp2
)

pico_add_extra_outputs(dsp)

ディレクトリ構成は、

スペアナのコードに追加したのは、動作確認のためだけですが、

// core1 will be used for LCD display control
#include "pico/stdlib.h"
#include "lcd_st7789_library.h"
#include "hardware/spi.h"

void core1_main()
{
    // Initialize the LCD
    lcd_init();

    // Fill the screen
    lcd_fill_color(create_color(255, 255, 255));

    // Draw a rectangle
    lcd_draw_rect(10, 10, 100, 50, create_color(0, 0, 255));

    // Draw some text
    lcd_draw_text(20, 20, "Hello, World!", create_color(255, 0, 0), create_color(255, 255, 255), 1); // char color, bg color, font size

    while (1)
    {

    }
}

実行結果は、

ローテーション指定はライブラリ中のここで、関数もあるようですが関数で後から指定すると表示が二重になった

    lcd_write_command(0x36);  // Memory Data Access Control
    lcd_write_data(0xA0);     // display rotation

 

admin

ラズピコでspiバス経由でLCD表示させる

スペアナプロジェクト用ですが、2インチのLCD(240*320 dots)を購入、SDカードのアクセスもできるようになってますが

https://learn.adafruit.com/2-0-inch-320-x-240-color-ips-tft-display/pinouts

動作確認はArduino IDE使って、ライブラリは、

をインストします

接続は以下のソースコードの通りですが、電源はピコの3.3V出力から取ろうとすると過電流(おそらくピコの電源電圧低下して動作不能状態になってる)でUF2ファイルのダウンロードできないので、USB電源であるVBUSから取らないと機能しなかった

電源電圧とバックライト制御信号(PWM)をまとめてVBUSに接続しています、従ってバックライトの輝度はmax状態ということ、GNDは一本なのでピコ – LCD間の接続は全部で8本です

<テスト用コード>

#include <adafruit_gfx.h>
#include <adafruit_st7789.h>
#include <spi.h>

// ピン定義(PicoのGPIO番号)
#define TFT_CS    17  // pin 22
#define TFT_RST   21  // pin 27
#define TFT_DC    20  // pin 26
#define TFT_SCK   18  // pin 24
#define TFT_MOSI  19  // pin 25

SPISettings settings(2000000, MSBFIRST, SPI_MODE3);
Adafruit_ST7789 tft = Adafruit_ST7789(&SPI, TFT_CS, TFT_DC, TFT_RST);

void setup() {
  tft.init(240, 320, SPI_MODE3);
  delay(100);

  tft.fillScreen(ST77XX_WHITE);   // 背景を白に設定
  tft.setRotation(1);             // 画面を90度回転
  tft.setCursor(20, 100);         // 文字の表示位置を設定
  tft.setTextColor(ST77XX_BLUE);
  tft.setTextSize(3);             // 文字サイズを設定
  tft.print("Hello Pico");       // 文字の表示
}

void loop() {
  delay(1000);
}

ST7789は制御回路にフレームメモリを持っているので、ラズピコからのリフレッシュ動作は不要なので使いやすいと思う、まあラズピコでリフレッシュさせたら負荷も大変だろうから、こういう制御チップがあるということだろう

 

admin