YAS's VB.NET Tips
 
ラズベリーパイ活用
ラズベリーパイ活用
12
2022/02/19

VBでRaspberry Pi PICOにファイルを転送する

| by:YAS
 Raspberry Pi PICOにファイルを転送するには、Thonnyなどを使えば簡単にできますが、PICOを使った自作VOCAにWAVEファイルを転送しようとすると、簡単にできる方法はなさそうです。バイナリ配列の内容をファイルを書き込むコードをREPLモードで実行してみましたが、メモリ不足のエラーが出て、ごく小さいファイルしか転送できませんでした。そこで、仮想COMポートのcom0comを使ってThonnyの通信内容を解読したところ、2kbyteずつ送信・書き込みを行っていることがわかりました。
 下のサンプルコードはtest.wavをPICOのルートディレクトリに転送します。コードをForm1にコピー・貼り付けすれば動作します。

Form1.vb

14:20
2021/11/01

ELEGOOのArduino用2.8インチTFT液晶にビットマップを表示する④(完結編)

| by:YAS
 前々前回に引き続き、Arduino用のTFT液晶をRaspberry Pi PICOにつなぎ、240 x 320ピクセルのBitmapを表示してみました。前回24bitBitmapを16bitBitmapに変換する処理とGPIOへの出力部分をPIOを使って作りました。残念ながら遅くなってしまいましたが、BitmapデータをPIOにそのまま流し込めるようになりましたので、今回は、DMAを使って画像データをPIOに転送してみました。
 その結果は、なんと0.094秒と、最初の18.2秒から193倍の速度になりました。すごいぞDMAとPIO!C++なんていらないじゃん!何でもMicroPythonで作れるんじゃない?
 DMAの利用は、myDMA.pyを使わせていただきました。下のページからコピペし、同じフォルダに入れておいてください。
 danjperron/PicoAudioPWM - GitHub
 DMAを使う際に注意する点として、フルスピードのDMAで転送するとPIOのFIFOがオーバーフローしてしまうので、DMAのクロックを1/5にしています。(この値は1/2,1/3…と試してみて、うまくいった値を使っています。適当です。)
 
 下のコードは,MicroPython1.17をインストールしたRaspberry Pi PICOで作成・動作確認をしています。(同じフォルダに240 x 340ピクセル、24bitカラーの画像を「sample.bmp」という名前で配置してください。)


01:34
2021/11/01

ELEGOOのArduino用2.8インチTFT液晶にビットマップを表示する③

| by:YAS
 前々回前回に引き続き、Arduino用のTFT液晶をRaspberry Pi PICOにつなぎ、240 x 320ピクセルのBitmapを表示してみました。前回はGPIOへの出力部分をPIOを使って高速化しました。今回は、24bitBitmapを16bitBitmapに変換する部分もPIOで行いました。
 その結果は、前回と同じ画像を5.9秒で表示と、前回の4.5秒よりも遅くなってしまいました。変換そのものは絶対にPIOの方が速いと思うので、StateMachineへのputが2byteから3byteに増えたところがボトルネックなのだと推測しています。(StateMachineへのputにそんなに時間がかかるとも思えないのですが…。不思議です。)
 今回のPIOの処理の追加で、Bitmap画像のデータをそのままStateMachineのFIFOへ流し込めばよくなったので、DMAが使えそうです。次回はさらにDMAを使ってPIOにデータを流し込んでみたいと思います。
 
 下のコードは,MicroPython1.17をインストールしたRaspberry Pi PICOで作成・動作確認をしています。(同じフォルダに240 x 340ピクセル、24bitカラーの画像を「sample.bmp」という名前で配置してください。)


01:02
2021/11/01

ELEGOOのArduino用2.8インチTFT液晶にビットマップを表示する②

| by:YAS
 前回に引き続き、Arduino用のTFT液晶をRaspberry Pi PICOにつなぎ、240 x 320ピクセルのBitmapを表示してみました。前回はSIOにmem32でアクセスしたのですが、Bitmap画像を表示するのに18.2秒もかかってしまいました。今回は、PIOを使って高速化を図ってみます。
 24bitBitmapを16bitBitmapに変換するのはPythonで行い、GPIOへの出力部分をPIOを使って行いました。
 その結果、前回と同じ画像を4.5秒で表示できました。(関数デコレーターに@micropython.nativeを指定した場合は、2.8秒!)4倍の高速化!PIOは強力ですね。
 しかし、4.5秒でも実用的とは言えないので、次回はさらにPIOに処理を移してみたいと思います。
 
 下のコードは,MicroPython1.17をインストールしたRaspberry Pi PICOで作成・動作確認をしています。(同じフォルダに240 x 340ピクセル、24bitカラーの画像を「sample.bmp」という名前で配置してください。)


00:36
2021/10/31

ELEGOOのArduino用2.8インチTFT液晶にビットマップを表示する①

| by:YAS
 Arduino用のTFT液晶をRaspberry Pi PICOにつなぎ、240 x 320ピクセルのBitmapを表示してみました。このLCDは5Vで動作しますが、横のCON1のピンを使うことで、3.3Vでも使うことができるようです。詳しくは、ELEGOOの製品ページに情報があります。
 今回は、下のようにPICOと接続しました。
 LCD Raspberry Pi PICO
 LCD_D0 GPIO0 (1pin)
 LCD_D1 GPIO1 (2pin)
 LCD_D2 GPIO2 (4pin)
 LCD_D3 GPIO3 (5pin)
 LCD_D4 GPIO4 (6pin)
 LCD_D5 GPIO5 (7pin)
 LCD_D6 GPIO6 (9pin)
 LCD_D7 GPIO7 (10pin)
 LCD_RD GPIO8 (11pin)
 LCD_WR GPIO9 (12pin)
 LCD_RS GPIO10 (14pin)
 LCD_CS GPIO11 (15pin)
 LCD_RST GPIO12 (16pin)
 GND GND (38pin)
 CON1の3.3V 3.3V (36pin)

 TFTに付属のArduinoのサンプル_9341uno.inoとShowBMP.inoを参考に、MicroPythonでBitmap画像を表示しました。LCDの初期化は_9341uno.inoの処理をそのまま使いました。ShowBMP.inoによると、ビットマップデータは赤5bit・緑6bit・青5bitの16bitで、上位8bitを先に、下位8bitを後に送信するようです。
 今回は、mem32でSIOのGPIO_OUT(0xd0000010)に書き込むことで、パラレル出力を制御しました。しかし、これでは1画面を更新するのに18.2秒かかりました。また、関数デコレーターに@micropytnon.nativeを指定しても、16.9秒かかり、実用的ではありません。(ArduinoUNOではSDカードの画像を11秒くらいで表示する。これも遅いけど。)だからと言ってC++を使うのは面倒くさいので、今後、PIOやDMAを使った高速化に挑戦したいと思います。

 下のコードは,MicroPython1.17をインストールしたRaspberry Pi PICOで作成・動作確認をしています。(同じフォルダに240 x 340ピクセル、24bitカラーの画像を「sample.bmp」という名前で配置してください。)


23:09
2021/10/17

Raspberry Pi PICOのGPIOを複数同時に変更する

| by:YAS
 Arduino用のTFT液晶が安かったので、Raspberry Pi PICOにつないでみようと思ったのですが、入力が8bitパラレル入力でした。Arduinoのコード例を参考にMicroPythonで制御しようとしているのですが、パラレル入力に対してGPIOを1本ずつ8本変更すると時間差が生じて、不具合が出ること間違いなしだと思ったので、GPIO8本を同時に変更する方法を調べました。下のページを参考にして実現することができました。
参考:Writing Multiple GPIO Pins AT ONCE
   https://forums.raspberrypi.com/viewtopic.php?t=311660

 下のコードは,MicroPython1.17をインストールしたRaspberry Pi PICOで作成・動作確認をしています。GPIO 0~7に抵抗付きLEDを接続して実行してください。

 さらに調べたところ、「RP2040 Datasheet」の42ページの「2.3.1.7.List of Registers」に公式の詳しい情報がちゃんとありました。32bitのうち1~30bitがGPIOの0~29に対応しているようです。
 直接値を設定するOUT、bitが1のGPIOがHighになるOUT_SET、bitが1のGPIOがLowになるOUT_CLR、bitが1のGPIOが反転するOUT_XORの4種類のレジスタがありました。
 他にも色々なレジスタがあり、MicroPythonで簡潔&高速に記述したいときに役立ちそうです。(コードが分かりにくくなるかもしれませんけれど。)

18:04
2019/08/16

温度・湿度・気圧ロガー&ロググラフ化合体

| by:YAS
 

 前回作ったBME280のロガーと,ログをグラフ化するコードを合体させてみました。1秒間隔で温度・湿度・気圧を測定し,表示を更新します。ログへの記録は5分間隔で行います。ログは日にちごとに分けて保存します。画面のどこかをクリックすると「グラフ作成中...」と表示され,しばらく待つとグラフが表示されます。ログファイルがない場合は「ログファイルがありません」と表示されます。グラフの画面をクリックすると,リアルタイムデータの画面に戻ります。
 Raspberry Pi -Zeroシリーズで実行すると,グラフを作成するところでフリーズしたかと思うほど待つので,別スレッドでグラフを作り,グラフ作成中もリアルタイムの計測値を表示し続けるようにしてみました。(また,メッセージ表示の枠の角を丸くするなど,どうでもよいところに力を入れています。なぜか,どうでもよいところほどやる気がでるのです。)
 画面表示にはpygameライブラリを,グラフ作成にはmatplotlibライブラリを使っています。

 気圧が下がると一部の発達障害の子どもたちは気持ちが落ち着かなくなるとよく言われますが,あまり事例のデータは無いようです。本当にそうなのか,今回作った装置&コードを使って確かめてみたいと思っています。

☆関連する記事

☆Pythonのコード
 下のコードは,ハードはRaspberry Pi - Zero WHにBME280をI2C接続したもの,OSはRaspbian Buster,Pythonのバージョンは 3.7.3 で作成・動作確認をしています。

17:00
2019/08/16

スレッドプール利用のサンプル

| by:YAS
 Raspberry Pi Zeroシリーズが非力であるのは分かっているが,matplotlibでグラフを作成するのに8~10秒かかるので,サブスレッドで処理することにした。
 下のコードはサブスレッドに引き数を渡し,サブスレッドの終了時に返り値を受け取るサンプル。

16:00
2019/08/15

BME280のログデータのグラフ化

| by:YAS


 先日作った,BME280ボードを使った,温度・湿度・気圧ロガーのデータをmatplotlibでグラフ化してみました。
 DATA_DIRにあるログデータを読み込んで,PIC_DIRに画像で出力します。
 Y軸のラベルの向きと位置を変えて,Y軸の単位の表示にしていますが,出力画像のサイズを変えると位置がずれてしまいます。Y軸の目盛を3種類にしたり,X軸のラベルを斜めにしたり,少し凝って作ってみました。。
 これを前回作ったロガーと合体させて。1つにし,簡易Webサーバーで外部から参照できるように機能追加しようと思っています。

☆コード
 pygameではデフォルトでは日本語を表示できないので,IPAゴシックをダウンロードし,同じフォルダに配置して使っています。
import csv
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.font_manager as mfontm
import matplotlib.dates as mdates
import datetime

DATA_DIR = "./BME280log/" # データのあるディレクトリ
LOG_NAME = " BME280.log" # 入力ログファイル名
PIC_DIR = "./BME280log/" # 画像を出力するディレクトリ
PIC_NAME = " BME280.png" # 出力画像ファイル名
PIC_SIZE = (4.83.2# 出力画像サイズ(480 x 320)
LINE_WIDTH = 1 # 折れ線グラフの線の太さ
DAYS_AGO = 0  # DAYS_AGO日前のデータを使う

# データを読み込む
timestamps = []
tempertures = []
humidities = []
pressures = []
date = "{0:%Y.%m.%d}".format(datetime.date.today() - datetime.timedelta(days=DAYS_AGO))
log_filename = DATA_DIR + date + LOG_NAME
with open(log_filename, "r"as f:
    reader = csv.reader(f)
    for row in reader:
        timestamps.append(datetime.datetime.strptime(row[0] ,"%Y/%m/%d %H:%M:%S"))
        tempertures.append(float(row[1]))
        humidities.append(float(row[2]))
        pressures.append(float(row[3]))
# グラフ作成
# フォントファイルの指定
fp = mfontm.FontProperties(fname="./ipag.ttf")
# 3つ重ね合わせたグラフ作成
fig = plt.figure(figsize=PIC_SIZE)
plt.subplots_adjust(left=0.07, bottom=0.15, top=0.9, right=1)
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax3 = ax1.twinx()
ax1.plot(timestamps, tempertures, color='orange', alpha=1.0, lw=LINE_WIDTH, antialiased=True)
ax2.plot(timestamps, humidities, color='deepskyblue', alpha=0.6, lw=LINE_WIDTH, antialiased=True)
ax3.plot(timestamps, pressures, color='green', alpha=0.8, lw=LINE_WIDTH, antialiased=True)
# Y軸の目盛り設定
ax1.set_ylim(040)
ax2.set_ylim(0100)
ax3.set_ylim(9601020)
ax1.yaxis.set_major_locator(ticker.MultipleLocator(5))
ax2.yaxis.set_major_locator(ticker.MultipleLocator(10))
ax3.yaxis.set_major_locator(ticker.MultipleLocator(10))
# 気圧の目盛りを外側に表示する
fig.subplots_adjust(right=0.80)
ax3.spines["right"].set_position(("axes"1.13))
# X軸のラベル(時分)
hoursfmt = mdates.DateFormatter("%H:%M")
ax1.xaxis.set_major_formatter(hoursfmt)
xlabels = ax1.get_xticklabels()
plt.setp(xlabels, rotation=45)
# Y軸のラベル(単位)
ax1.yaxis.set_label_coords(-0.0451.03)
ax2.yaxis.set_label_coords(1.071.09)
ax3.yaxis.set_label_coords(1.211.09)
ax1.set_ylabel("(℃)", fontproperties=fp, rotation=0)
ax2.set_ylabel("(%)", fontproperties=fp, rotation=0)
ax3.set_ylabel("(hPa)", fontproperties=fp, rotation=0)
# 凡例
fig.legend(["温度""湿度""気圧"], bbox_to_anchor=(00), bbox_transform=ax1.transAxes, loc="lower left", prop=fp)
#plt.xkcd()
pic_filename = PIC_DIR + date + PIC_NAME
plt.savefig(pic_filename)

11:49
2019/08/14

温度・湿度・気圧ロガー

| by:YAS


 先日作った,BME280ボードを使って,温度・湿度・気圧ロガーを作ってみました。画面の表示はpygameを使っています。1秒ごとに測定と画面更新を行い,10秒ごとにログに出力します。ログは日が変わる毎に新しく作られます。480 x 320のミニ液晶が前提で,フルスクリーン表示で起動します。ESCキーで終了します。
 今後は,画面タッチで1日の変化をmatplotlibを使ってグラフ表示するよう機能追加をしていきます。

☆コード
 pygameではデフォルトでは日本語を表示できないので,IPAゴシックをダウンロードし,同じフォルダに配置して使っています。
import smbus2 
import bme280
import datetime
import time
import pygame
from pygame.locals import *
import sys
import csv

BME280_PORT = 1
BME280_ADDRESS = 0x76
PYGAME_SCREEN_SIZE = (480320)
LOG_INTERVAL = 10

# BME280初期設定
bus = smbus2.SMBus(BME280_PORT)
calibration_params = bme280.load_calibration_params(bus, BME280_ADDRESS)

# pygame初期設定
pygame.init()
screen = pygame.display.set_mode((PYGAME_SCREEN_SIZE), FULLSCREEN)
pygame.display.set_caption("温度・湿度・気圧計"
myfont1 = pygame.font.Font("ipag.ttf"35)
myfont2 = pygame.font.Font("ipag.ttf"62)

old_time = time.perf_counter()
while True:
    new_time = time.perf_counter()
    if new_time - old_time >= 1:
        old_time = new_time
        # BME280からデータを読み出す
        data = bme280.sample(bus, BME280_ADDRESS, calibration_params)
        timestamp_str = "{0:%Y年%m月%d日 %H時%M分%S秒}".format(data.timestamp)
        temperture_str = "温度:{0:>6.1f} ℃".format(data.temperature)
        humidity_str = "湿度:{0:>6.1f} %".format(data.humidity)
        pressure_str = "気圧:{0:>6.1f} hPa".format(data.pressure)
        # pygameでデータを表示する
        timestamp = myfont1.render(timestamp_str, True, (255255255))
        temperture = myfont2.render(temperture_str, True, (255255255))
        humidity = myfont2.render(humidity_str, True, (255255255))
        pressure = myfont2.render(pressure_str, True, (255255255))                       
        screen.fill((000))
        screen.blit(timestamp, (010))
        screen.blit(temperture, (070))
        screen.blit(humidity, (0155))
        screen.blit(pressure, (0240))
        pygame.display.update()
        # 10秒毎にCSVに保存する
        if data.timestamp.second % 10 == 0:
            filename = "./BME280log/{0:%Y.%m.%d} BME280.log".format(datetime.date.today())
            f = open(filename, "a")
            writer = csv.writer(f)
            csvrow = []
            csvrow.append("{0:%Y/%m/%d %H:%M:%S}".format(data.timestamp))
            csvrow.append("{0:.1f}".format(data.temperature))
            csvrow.append("{0:.1f}".format(data.humidity))
            csvrow.append("{0:.1f}".format(data.pressure))
            writer.writerow(csvrow)
            f.close()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN and event.key == K_ESCAPE:
            pygame.quit()
            sys.exit()                

23:45
12