ラズパイ・ピコ

2025年4月28日 (月)

Arduino UNO R3のクロック精度を1MHzパルスで確かめる

ラジオペンチさんが、
Arduinoのmicros()を使ったLチカでCPUのクロック精度を測定 
という記事を書かれていたんで、別のアプローチで迎撃してみます。
こんなスケッチ。

・16ビットタイマーをCTCモードにしてOC1A(PB1:D9)にジャスト
 1MHzの方形波を出力。
   このパルス出力はATmega328Pのハードが出してくれるので
   ジッターは無し。
・おまけで、
   loopの毎サイクルでLEDポート(D13)をトグル。
   millis()値の変化でD8ポートをトグル。

//  Arduino UNO R3 発振周波数確認
// PB1:OC1A(D9)に1MHz方形波を出力
// 16MHz / 8 / 2 で1MHz
// PB0(D8) millis()で1msをチェックして方形波出力
// PB5(D13) LEDポート loopで方形波出力
/***** セットアップ *****/
void setup()
{
pinMode( 9, OUTPUT); // PB1 OC1A 1MHz出力
pinMode( 8, OUTPUT); // PB0 1msごとにトグル出力
pinMode(13, OUTPUT); // PB5 LED loopでトグル出力
// タイマー1 16MHz/8 COM1Aトグル出力
TCCR1A = 0b01000000;
// |||| ++--- WGM OCR1AでCTC
// ||++------- COM1B
// ++--------- COM1A トグル出力
TCCR1B = 0b00001001;
// || ||+++--- CS 16MHz入力
// || ++------ WGM OCR1AでCTC
// |+--------- ICES1
// |---------- ICNC1
TIMSK1 = 0b00000000; // 割り込みオフ
// | ||+--- TOIE1
// | |+---- OCIE1A
// | +----- OCIE1B
// +-------- ICIE1
OCR1A = 8 - 1; // 16MHz/8 2MHz, OC1Aトグルで1MHzに
}

/***** LOOP *****/
void loop()
{
uint32_t ms , a;
ms = millis(); // 現1ms値
while(1){
PINB |= (1 << PB5); // LEDポートトグル
a = millis();
if(ms != a){ // 1ms変化?
PINB |= (1 << PB0); // PB0 (D8)ポートトグル
ms = a; // 次の1msを待つ
}
}
}

これで、
(a) PB1の周波数を読めば、クロックの誤差がわかる。
(b) millis()値の変化は1msサイクルじゃないことがわかる。
(c) タイマー0割り込みの処理時間がわかる。
というのを確かめられるかと。

この命令、
  PINB |= (1 << PB5); // LEDポートトグル
AVRマイコンデータシートのポート解説のところを見てください。
 「PINxnへの論理1書き込みはDDRxnの値によらず
  PORTxnの値を反転切り替えします。」
となっていて、SBI命令ひとつで出力ビットの反転操作が
できるのです。

BLINKの応用で、LEDを点滅させることが
あるかと思いますが、
  現在のon/offを判断
  digitalWriteでon/offを設定
なんてまどろっこしいことをしなくても
最短の時間、最小の命令バイト数でポートを
トグルできるのです。

どうか、覚えておいてください。

※関連
2020年2月4日:Arduinoのタイマー OCRレジスタは「n」じゃなく「n - 1」の値を設定せよ


*追記:Raspberry Pi Picoだと

//  ラズパイピコの周波数確認
// GP2 1MHz方形波 PWMで出力
// GP4 LOOPでトグル出力
// GP6 millisによる1msごとにトグル(500Hz)
#define GP2 2 // PWM出力
#define SN2 (GP2 / 2) // PWMスライスナンバー
/***** SETUP *****/
void setup(){
pinMode(25, OUTPUT); // LED
pinMode( 4, OUTPUT); // loopで反転
pinMode( 6, OUTPUT); // 1msで反転
// PWMの設定
gpio_set_function(GP2, GPIO_FUNC_PWM); // GP2をPWM出力に
pwm_set_clkdiv(SN2, 12.5); // 125MHz / 12.5 = 10MHz
pwm_set_wrap(SN2, 10 - 1); // PWM 分解能
pwm_set_chan_level(SN2, GP2 & 1, 5); // ch-A PWM値
pwm_set_enabled(SN2, 1); // PWMスタート
}

/***** LOOP *****/
void loop(){
uint32_t ms, a;
byte f_xLED = 0; // LEDポート反転フラグ
byte f_xGP6 = 0; // GP6ポート反転フラグ
ms = millis(); // ms現在値
while(1){
f_xLED ^= 1; // LEDポートトグル
gpio_put(25, f_xLED); // LED出力
gpio_put( 4, f_xLED); // GP4出力
a = millis();
if(ms != a){ // 1ms変化?
f_xGP6 ^= 1; // GP6ポートトグル
gpio_put( 6, f_xGP6); // GP6出力
ms = a; // 次の1msを待つ
}
}
}

GP2ポートをPWM出力にして1MHzを出すようにしてみました。
こちらも搭載マイコンRP2040のハードウェアを使って
パルスを出していますんで、走っているソフトの影響で
パルスが遅れるとか進むとかはありません。

  ※RP2040のPWMユニットの分周器、n・m/16で
   設定できるのが面白い。
   主クロックの125MHzを1/12.5とすれば10MHzが
   出てきます。

| | コメント (0)

2024年4月 7日 (日)

トラ技2024年5月号に「3.3/65535」

トランジスタ技術の最新号、2024年5月号を
パラパラめくりしていたら、p.70のリスト1に
怪しい記述を発見。
A/D値から電圧値を計算するための定数を出す
のに「3.3/65535」と。

Pp21
65536と65535の差はほんの僅か。

でも、リストの7行目のPID演算のところで、
6桁の数値が出ているんで、5桁数値の最小桁で
の1違いは大きくないかいなとちょいと心配。

電源電圧「3.3V」も、「ほんまかいな」だし。

元データはA/D値のまま使い、「CAL(校正)したらこうなった」
にして、「浮動小数点化したmap関数」を使って線形補間して
答えを出すてなほうが「理にかなっている」ような気がします。

ラズピコだと1/65535が出現:トラ技2022年5月

※検索
ラズパイマガジン2022年12月12日の訂正
   ・・・本文中の「1023」は「1024」、図2下の式の
  「4095」は「4096」の誤りです。
   ・・・Raspberry Piのところで分割数が「4095」と
  あるのは「4096」の誤り、Raspberry Pi Picoでは
  「65535」が「65536」、micro:bitとArduinoでは
  「1023」が「1024」の誤りでした。
訂正が出ています。

 

| | コメント (2)

2024年3月30日 (土)

ラズピコだと1/65535が出現

Arduinoでぐだぐだ言ったのが1023 vs 1024問題

トラ技のラズピコ特集、2022年5月号を見ていたら・・・
Pc12
A/D変換の値から電圧を計算するのに「1/65535」が
出ていました。

ただし言語は「python」。
analogioを検索してみると、Aanaloginは
16bitの値になるそうで、
https://learn.adafruit.com/circuitpython-essentials/circuitpython-analog-in
ここでは1/65536して電圧に変換しています。

https://www.denshi.club/pc/python/circuitpython/circuitpython-10-3.html
ここは、「65535は間違いなので」と注記があって
1/65536になっています。

https://logikara.blog/raspi-pico-basic/
ここは1/65536。

もう一つ、気になったのが
  v / (ref - v)
のところ。
Pc11

vが電圧値でrefが基準電圧つまり3.3Vなら、
adc.valueがフルスケールの65535になったときは
  v = 65535 / 65535 * 3.3 で
   = 3.3 となります。
すると、
  3.3 / (3.3 - 3.3)
で、ゼロ除算が発生。

図15のCDSが外れて、A/D値がフルスケールになると
ゼロ除算してしまうわけです。
1/65536にしていれば、v = 3.29995となり、
ゼロ除算は避けられます。

pythonでの数値型がよく分かってないので、
これでどんな挙動になるのかは知りません。
記事をぱっと見して、
  1/65535が出てきたぞ
  1023 vs 1024と同じ匂いか
っと、感じた次第です。

 

| | コメント (0)

2023年4月12日 (水)

Help me! ラズピコ、Philhower版だとスケッチをアップロードできない

Arduino IDE環境でゴソゴソしている「Raspberry Pi Pico」。

Arduino IDEでのラズピコ開発環境 Philhower版が正解でしょう
なんかと言いながら、ゴソゴソしたのですが、Philhower版だと
スケッチをアップロードできないのです。

ありゃま。ラズピコがおかしくなった。 PWMを調べたかったのに
これが2月半ば。
プログラムを書き込んだあとでも「BOOTスイッチ」を押しながら
USBに挿せば、外部ドライブとして認識されるはず。
この時から、ドライブとして認識してくれなくなりました。

そのせいか、Philhower版に切り替えると、エラーが出て
スケッチをアップロードできません。
しかし、「Mbed版」に切り替えると、ちゃんとアップでき
るのです。

Philhower版とMbed版でアップロードの方法が異なるようです。
同じピコをつないでいても、認識していたCOMポート番号も
変わっちゃうし・・・

Philhower版は、通信でBOOTモードにして、現れたドライブに
ファイルを書き込んでいるような気配です。
現PC、ピコのドライブが出てこないからエラーとなっている
ような感じです。

手元には3つのラズピコ基板がありますが、どれも同じ。
現PCではダメですが、他のPCだとちゃんとドライブとして
認めてくれます。
現PC、USB回りの何かがおかしくなってしまったようです。
  ※USBの口を変えてもだめ。 ケーブルでもない。

Arduino IDEでラズパイ・ピコ:Earle Philhower版で
去年の4月時点では、間違いなくPhilhower版も試せていたのです。
それが・・・アウトに。
どうしたものか・・・

Win7でのシリアルポートに関しては
Arduino IDEでRaspberry Pi Pico:Win7でのUSB問題解決です
これでうまいこと行ってました。
ところが、ある日からドライブとして認識してくれないという
問題が発生。
それが、Philhower版で、スケッチを書き込めない
ということにつながっているようなのです。

どこかに解決の糸口があれば・・・

FTDIのUSB通信アダプタを挿してCOMポートがどんどん進む問題
は、この記事のコメントで教えてもらって解決したことがありました。

| | コメント (4)

2023年4月 4日 (火)

Arduino IDEでのラズピコ開発環境 Philhower版が正解でしょう

Arduino IDEでのラズピコ開発環境でうだうだ言ってましたが、
環境が変わってしまったようで、ボードマネージャーに出なく
なっていた「Earle F. Philhower, III」版。

「環境設定」にある
「追加のボードマネージャーのURL」が変わっていた
(誰が変えた?私でしょうなぁ)のが原因でした。
こんな具合に「earlepPhilhower」版のパッケージを
選んだら、出てきました。

Aa2_20230404103201

ボードマネージャーにPICOと入れたら出てくるように
Aa3_20230404103201

Philhower版だと、シリアル通信のバッファサイズも触れそうです。
ヘッダーファイルやソースを追いかけれそうな気がします。

Philhower版での「pins_arduino.h」の在処、これでしょ。
・・AppData\Local\Arduino15\packages\rp2040\hardware\rp2040\3.1.0\variants\rpipico

ピン接続の位置、Mbed版とは異なっています。

// LEDs
#define PIN_LED (25u)

// Serial
#define PIN_SERIAL1_TX (0u)
#define PIN_SERIAL1_RX (1u)

#define PIN_SERIAL2_TX (8u)
#define PIN_SERIAL2_RX (9u)

// SPI
#define PIN_SPI0_MISO (16u)
#define PIN_SPI0_MOSI (19u)
#define PIN_SPI0_SCK (18u)
#define PIN_SPI0_SS (17u)

#define PIN_SPI1_MISO (12u)
#define PIN_SPI1_MOSI (15u)
#define PIN_SPI1_SCK (14u)
#define PIN_SPI1_SS (13u)

// Wire
#define PIN_WIRE0_SDA (4u)
#define PIN_WIRE0_SCL (5u)

#define PIN_WIRE1_SDA (26u)
#define PIN_WIRE1_SCL (27u)



| | コメント (1)

2023年4月 3日 (月)

ラズピコのピン:自由になりそうだけど定義で固定されている

Arduino IDEでのラズピコのI/Oピン、RP2040そのものの
ハードでは自由に割り振りできるようになっているんですが、
pins_arduino.h」でほぼ固定されています。

ラズピコユーザー、まずはこのファイルを確認しと
きましょう。 ざっと、こんな具合。

// LEDs  基板上のLED
#define PIN_LED   (25u)
#define LED_BUILTIN PIN_LED

// Analog pins アナログ入力
#define PIN_A0 (26u)
#define PIN_A1 (27u)
#define PIN_A2 (28u)
#define PIN_A3 (29u)

// Serial シリアル:定義はSerila1だけ
#define PIN_SERIAL_TX (0ul)
#define PIN_SERIAL_RX (1ul)

// SPI  SPIも固定
#define PIN_SPI_MISO (16u)
#define PIN_SPI_MOSI (19u)
#define PIN_SPI_SCK  (18u)
#define PIN_SPI_SS  (17u)

// Wire  I2Cも固定
#define PIN_WIRE_SDA (4u)
#define PIN_WIRE_SCL (5u)

汎用I/Oは、基本これ以外の場所を選んでという使い方に
なります。

残りの「Serial2SPI1I2C1」を使うには
どうすりゃいいの?
は、まだ調べ切れていません。

Serila2は「UART Serial2(4, 5, NC, NC);」で行けたけど。

※追記
ラズピコ基板の
  水魚堂さんの回路図エディタBSch3-V部品ライブラリ
ピン名称、ちょっと追記しました。
Rp1
左側がこれまでの。
真ん中が、Xサイズをちょい増やして、TX/RX、SPI、
I2C信号を追加。
空いているポートがわかりやすいかと。
右のは 秋月のAE-RP2040マイコンボード

ここからダウンロードしてください。
・BSch3V用パーツライブラり bsch3v_lib_230403.zip
この中の「SPECIAL.LB3」に入れてます。
ご自由にどうぞ。


※注記
これ、Arduino Mbed OS RP2040 Boads の環境での話。
Earle F. Philhower, III」版だとどうなるのか、
Arduino IDE、触ってみます。



| | コメント (2)

2023年3月30日 (木)

ラズピコで2chシリアル入出力のテスト

ラズベリーパイ・ピコのシリアル入力は二つ。(USBを除いて)
これを使って2ch入力のシリアルデータロガーを実現できたら
エエなぁっと、ごそごそしてます。

Arduino UNOベースでは1ch入力のは作ってあり、
現用中です。
  ・Arduino-UNO + SDカードでシリアルデータロガー 完成形 今度こそ
ニッケル水素電池の放電データなどはこれで
記録しています。

なぜ2ch入力のが欲しいかというと、あれこれ測定した
計測データの集計です。
例えば、温度や照度や電圧、電流。
センサー側はシリアルデータとして出力できるように作って
あるのですが、それらを集計するとき、別の装置が出すデータ
との結合に困っちゃうのです。

例えば、4ch入力アナログデータロガー
これも、アナログ値の記録とともに、外部からのシリアル
データを取り込めるようにしています。
 これが便利。
 シリアルデータの結合がロガー内で実現できちゃうのです。

あれこれ計っていると、2ch以上のシリアル入力を持っていて、
それをうまいことログできる装置が「いるぞ!」っというのが
お試しの理由です。

ラズピコは2つのシリアル通信機能を持てっています。
それを生かして、2chのログをできないかと試したのが
今回のゴソゴソです。

まずはこんな回路。
Ll1_20230330165801
  ↓ 左のピコ、裏返しはマズイぞと描き直しました
Ll51

手っ取り早くでっち上げた実物回路がこれ。
Ll00
ラズピコ基板が2枚。
GNDを共通にして、シリアルが2ch。

回路図左側のラズピコは、試しとなるシリアルデータを
出力するだけ。
1chは1秒おきに。 2chは乱数で送出周期を可変。

回路図右のラズピコはそれを受けて、USBに(PCに向けて)
出力するというテスト回路です。

ch1とch2の二つのデータを受けて集約して、USBに出力
するのです。
その集約方法、例えば・・・
Ll2_20230330165801
こんなモードを考えました。
こんな具合に、受信データをまとめます。
Ll3
mode0はそれぞれの受信データを別行にしてログ。

mode1は固定長のデータを1行にまとめて処理でき
るように。

mode2はデータの受信順序を確認できるように、
ch1を優先してch2は補助で。

Ll2_20230330165801

PCを使ってこれをするのは、USB通信アダプタをつないで
できるように、こんなソフトを作ってあります。
  ※これは仕事で!
Ll4

4chの入力まで対応しています。
通信があった日時情報とともにログします。
あちこちからやってくる通信データの内容確認、
整合性をチェックするのが目的です。

今回のは単純ログ。
受けた内容を取りこぼさずにログできればOKと。
その前段階のテストプログラムです。

 ・送信側
   ダウンロード - tx_data_2ch1.txt
 ・受信側
   ダウンロード - rx_data_2ch1.txt

これからもうちょい「身を付けて」(太らせて)
SDカードにログできるように手直しします。

もう一つ、こんなモードもいるかな。
ch1をマスター、ch2をスレーブに接続。
ch1がch2にコマンドを送って、ch2からの返答を
待つような通信だと、ch1の受信後、ch2を待って
から1行の電文にして出力。

mode0のように電文が別の行だと、後処理で
まとめなくてはなりません。
mode1のように1行が固定文字数だと、例えば
グラフ化のためGNUPLOTに食わすのも楽になります。

ATmega4809 だとシリアルが4本(40pin DIPだと3本)。
もっとチャンネルを増やせます。

それにしても、ラズピコの内部処理がつかみ切れません。
シリアル通信の割り込み、バッファを増やしたいんだけど、
・・・わからんまま。
  Arduino IDEで使ってる環境のせい?
  Earle F. Philhower, III 版だとどうだ?を
  調べるほうがエエかも。

| | コメント (0)

2023年3月29日 (水)

Arduino IDEでのラズピコ開発環境

Arduino IDEのボードマネージャーを
見たら、いつのまにやら「Earle F. Philhower, III」版
のが出てこなくなっています。

Pp11_20230329100701
ラズピコを触り始めた時は・・・出てきたような。
Arduino Mbed OS RP2040 Boads」というのだけに。
  ※下のは非推奨と

トラ技2022年5月号で、これをっと推奨されていた
「Earle F. Philhower, III」さんのはどこへ?

ラズピコ、USB以外のシリアル通信ポートが二つ
載っています。
Serial1とSerial2で行けるはずだったんですが、
今の環境だと、Serial2を使うのに
こんなおまじないが必要でした。
 UART Serial2(4, 5, NC, NC);  // そのままではSerial2が
            // 使えないのでピン番号指定を実行

シリアルの送受バッファの問題もあり、
ラズピコ、なかなかむつかしいです。

※追記
「Earle F. Philhower, III」版の設定が出なくなっていたの、
  「追加のボードマネージャーのURL」
が変わっていたのが原因でした。
設定し直したらちゃんと出現しました。


| | コメント (0)

2023年2月24日 (金)

ラズピコ analogWriteの誤差

ラズピコのanalogWriteで 1/255 ~ 254/255と
デューティ比を変えた時、出力されるH/Lパルス幅から
実測したデューティ比の差を示したのがこのグラフ。
設定値を1変化させた時の測定クロック数の差を書き
加えました。
Cap112

16MHzのクロック数で128(8μs)が続いた後、、
13あるいは14カウントごと96(6μs)
出現しています。

この13と14がどこから来るのか・・・
その推測です。

ピコのクロックは125MHz
analogWriteの周波数は500Hz。
PWMの分解能が255
  で、125e6 ÷ 500 ÷ 255 = 980.392

RP2040のPWM分周回路、最大が 1/255.9375。
  m・n/16で設定できます。

980.392は256を越えるので1/256すると 3.82966
整数部が 3 で 小数部が 0.82966
小数部は 1/16 単位なので
  0.82966 × 16 = 13.2745

「13」と「14」の間
こんな数字が出てきました。

元クロック周波数とPWM周波数、そして分解能から
求める分周比、そして最終的なパルス幅設定値の計算に
浮動小数点を使っているからかと推測できます。

ラズピコのPWM。やっぱしanalogWriteは捨てちゃえ #2
これ↑の手法、PWMの分解能とH/Lパルス数は整数と整数の
乗数で設定するので実パルスとの誤差は生じません。
その代わり、主クロックからPWMの周波数を計算するところで
誤差が生じます。

PWMでDACするなら(analogWriteを名乗るなら)、デューティ比
に誤差が出るのはあきません。

 

| | コメント (0)

2023年2月22日 (水)

ラズピコのPWM。やっぱしanalogWriteは捨てちゃえ #2

2023年2月21日:ラズピコのPWM。 やっぱしanalogWriteは捨てちゃえ
この続き。

ラジオペンチさんのコメント
  「せっかくだから analogWritePure なんて関数・・・」と
ありましたので、難しいことはせずにサクッとまとめてみました。
   ※サクッとで、エラーチェックや
    数値範囲チェックはしてません。

関数は2つ。

 int pwmStart(pin_size_t pin, int val, int range, int frq)
まず、これで
 分解能 range と 周波数 frq から、
val値に対する乗数を計算します。
 pinはPWM出力ピン番号。 valはPWM幅。

というのはピコのPWM、クロックが125MHzで分周器の最大が
8bitの256未満 (m・n/16の浮動小数点で設定できる)という
制限があるのです。

PWM周波数500Hzで8bit分解能だと分周比が976.56になって
しまい、256.0を越えてしまいます。
そこで、PWM幅を得るval値にmlt値を乗じるようにして、
分周比が256.0を越えないようにします。

PWM周波数1kHzで分解能が100だと分周比が1/250で、
PWM幅valへの乗数が5となります。
val値0でL、100でH。
1~99でデューティ1%~99%が出てきます。

pwmStartの返り値である乗数(mlt)を得たあとは、
この関数↓でPWM幅を出力。
 void pwmVal(pin_size_t pin, int val, int mlt)
浮動小数点計算が不要な分、処理が早くなります。

テストプログラムを走らせるとこんな感じ。
  USBで通信 出力ピンをオシロで観察

# Pico PWM Test #5 (2023-02-22) Entでタイトル出力
# PWM Port >22      出力ピン番号
# PWM Freq (500Hz) >1000 PWM周波数
# PWM Range (256) >100   分解能 0~100で
PWM:22 m:5 1/250.000   mltとclkdiv値

# PWM Data >10  10だとデューティ10%
10/100 10.000%
# PWM Data >99
99/100 99.000%
# PWM Data >45
45/100 45.000%
# PWM Data >33
33/100 33.000%

# PWM Data >  Entだけ入力で最初から
# PWM Port >
# PWM Port >19  出力を19ピンに
# PWM Freq (500Hz) >800  周波数を800Hzに
# PWM Range (256) >1000  分解能を1000に
PWM:19 m:1 1/156.250  mltとclkdivが確定

# PWM Data >120
120/1000 12.000%
# PWM Data >990
990/1000 99.000%
# PWM Data >10
10/1000 1.000%

# PWM Port >19
# PWM Freq (500Hz) >1200  1200Hz
# PWM Range (256) >4096  分解能12bitで
PWM:19 m:1 1/25.431  mltとclkdivが確定
# PWM Data >100
100/4096 2.441%
# PWM Data >4000
4000/4096 97.656%
# PWM Data >4095
4095/4096 99.976%
# PWM Data >4090
4090/4096 99.854%

1Hz単位でPWM周波数が設定できます。
PWM分解能も「2^n」だけでなく、100とか1000に
できるので、10進でPWMデューティを設定する時に
便利かと。
分解能が偶数だと、半値で1/2デューティが得られます。

※テストプログラム
  ・ダウンロード - pwm_serial_in5.txt

Arduino IDEの環境によってはコンパイルエラーが出るかも。

※ pwmStart() 実行時間
Pp1_20230222141401

※ pwmVal() 実行時間
Pp2_20230222141401



| | コメント (2)

より以前の記事一覧