ラズパイ・ピコ

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が
            // 使えないのでピン番号指定を実行

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

| | コメント (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)

2023年2月21日 (火)

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

2023年2月20日:ラズピコのPWM。 なんかおかしいような #2
この続き。

ここ↓で、PWMを使ったタイマー割り込みを試していました。
2022年4月12日:Arduino IDEでラズパイ・ピコ:1msタイマー割り込み
それの応用で500HzのPWMを確認してみます。
  ※analogWriteを捨てるための実験です

/****************************/
/* PWM出力 */
/****************************/
#include "pwm.h" // PWM処理に必要
// PWMデータ
int pwm_port; // PWMポート番号
int pwm_range = 256; // PWM レンジ 初期値は256
int pwm_data; // PWM設定値データ
/***** PWM出力 *****/
// pinに出力 valがPWM H区間 最大がrange
// val=0ならL出力 val=rangeならH出力
// ピコのクロックは125MHz
// val,rangeを10倍して処理
// set_clkdivは256.0未満 m・n/16で分周
// set_wrap,set_chan_levelはuint16_tなので65535がmax
void pwmWrite(pin_size_t pin, int val, int range)
{
uint sn; // slice number
gpio_set_function(pwm_port, GPIO_FUNC_PWM); // ポートはPWM出力で
sn = pwm_gpio_to_slice_num(pwm_port); // スライス番号を得る
pwm_set_clkdiv(sn, 97.66); // 1.28MHzに
pwm_set_wrap(sn, (10 * range) - 1); // 256で500Hz
pwm_set_chan_level(sn, (pwm_port & 1), 10 * val); // ch-A,ch-B
pwm_set_enabled(sn, true); // PWMスタート
}

グラフにすると、よく分かるかと。
   ※前のと同じスケールで
Cap110
   ※拡大
Cap111
へんな周期性は見えません。

「半値」のあたりはこんな具合。

・range = 255で
PWM発生  実測値   n/255で  実測値   差分
n 1/255 H H+L
126 255 15744 31864 49.412% 49.410% -0.002%
127 255 15870 31865 49.804% 49.804% -0.000%
128 255 15995 31865 50.196% 50.196% 0.000%
129 255 16120 31865 50.588% 50.588% 0.000%
130 255 16245 31865 50.980% 50.981% 0.000%

・range = 256で
PWM発生  実測値   n/255で  実測値   差分
n 1/256 H H+L
126 256 15745 31990 49.219% 49.219% -0.000%
127 256 15870 31990 49.609% 49.609% -0.000%
128 256 15995 31990 50.000% 50.000% 0.000%
129 256 16120 31990 50.391% 50.391% 0.000%
130 256 16245 31990 50.781% 50.781% 0.000%

実測値は16MHzのクロックでサンプリングしたHとLのパルス幅です。
128/255も128/256も期待値が出ています。

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

(.inoではなく.txtにしてます。 UTF-8Nエンコード)

| | コメント (3)

2023年2月20日 (月)

ラズピコのPWM。 なんかおかしいような #2

ラズピコのPWM。 なんかおかしいような
これの続きです。

analogWrite()を処理しているソースを探し出すと
どうやらこれのようです。

void analogWrite(pin_size_t pin, int val)
{
if (pin >= PINS_COUNT) {
return;
}
float percent = (float)val/(float)((1 << write_resolution)-1); // ★1
mbed::PwmOut* pwm = digitalPinToPwm(pin);
if (pwm == NULL) {
pwm = new mbed::PwmOut(digitalPinToPinName(pin));
digitalPinToPwm(pin) = pwm;
pwm->period_ms(2); //500Hz
}
if (percent < 0) {
delete pwm;
digitalPinToPwm(pin) = NULL;
} else {
pwm->write(percent);
}
}

★1のところで、write_resolutionが
  8bitなら255に、
  10bitにしたら1023に。
これがデューティ100%での浮動小数点除算の
除数になります。
つまりPWMの出力が出力がHに固定される値です。

得られた「percent」値がデューティ比でそれを
  pwm->write(percent);
でPWM出力しています。
  ※「pwm->write」の中味はまだ追いかけてません
このanalogWriteをこんなふうに書き換えました。
  (1 << m) - 1
をやめて、「write_resolution」を任意の値に設定でき
るようにします。

/***** PWM出力     *****/
// analogWiteの代替
// フルスケールはpwm_range -1
// 元々は (1 << write_resolution)-1 で8bitなら255に
void pwmWrite(pin_size_t pin, int val, int range)
{
float percent; // デューティサイクル
if(pin >= PINS_COUNT){
return;
}
percent = (float)val / (float)range; // デューティ比を計算
mbed::PwmOut* pwm = digitalPinToPwm(pin);
if(pwm == NULL){
pwm = new mbed::PwmOut(digitalPinToPinName(pin));
digitalPinToPwm(pin) = pwm;
pwm->period_ms(2); // 500Hz PWM周波数
}
if(percent < 0){
delete pwm;
digitalPinToPwm(pin) = NULL;
}
else{
pwm->write(percent); // デューティ指定でPWM出力
}
}

これで、フルスケール値(デューティ100%)を任意に書き換え
できます。

で、試してみました。
デューティ計算値と実測値の差をグラフにします。
まず、n/255 と n/256
Cap108_20230220112701

微妙に変動の周期が異なります。
n/256にしても半値の128で差が生じました。
128/256で50.000%になるはずが、実測値49.950%
で、-0.050%の差です。

そして、試したのがn/100、n/105、n/200、n/250の4つ。

Cap109
10^0桁が0の100、200、250は右下がりの直線になりましたが、
n/105が「なんじゃこれは」に。

デューティ比の設定がfloatなのが問題なのかなぁ。
「pwm->write」の中味を調べなくっちゃというところ
でしょうね。

| | コメント (3)

2023年2月16日 (木)

ラズピコのPWM。 なんかおかしいような

ありゃま。ラズピコがおかしくなった。 PWMを調べたかったのに
これの続き。
  書き込み出来なかったのはUSB回りのゴソゴソ。
    よく分からんけど。
  2022年4月13日:Arduino IDEでRaspberry Pi Pico:Win7でのUSB問題解決です
    これで使ったZagig.exeを触ってたら
    書き込みできるようになりました。

さて、ラズピコのPWM。
なんかおかしい。
単純な整数値でPWMしてたら誤差なんて出ない(1clkの変動
はあるだろけど)はず。
  analogWriteと名乗るからにはちゃんとしてほしい。

まず、テストで使ったスケッチ
   ・ダウンロード - pwm_serial_in1.txt
     (ファイルタイプを.inoではなく.txtにしてます)

・USBでシリアル通信。
・スケッチを書き込み後ターミナルを起動。
・最初の「CR」入力でタイトルを出力。
・次に使うPWMポート番号を入力。
   # PWM Port >
  そのポートに対しデューティ50%の
  (つもりの)波形を出力
・その次からPWMデータ入力を繰り返し。
   # PWM Data (0...255) >
  0~255の入力で設定したポートに
  analogWriteでPWM値を設定
・「CR」だけだとPWMポート番号入力に戻る。
・データを「-1」で設定したらPWM値を順番に
 増加させるモードに
 1~254まで2秒ごとに+1。
 254で停止。
 設定したPWM値はSerial1にも出力。
   これをデューティチェッカの出力とともに記録。
   デューティチェッカの出力サイクルが1秒なので
   ピコは2秒ごとにPWM値を変更。

設定したデューティ「n/255」値とデューティチェッカで
拾ったH/Lクロック数から計算した実デューティの差を
グラフにしたら、こうなりました。
Cap105

デューティ比の差が「-0.1~0.0」を周期的に変動。
なんなんだこれは。

まず、測定した生データ。
設定したPWM値とデューティチェッカで拾った値です。
  ・ダウンロード - pico_pwm2a.txt

そこからそれぞれのデューティ比を計算。
  ・ダウンロード - pico_pwm3a.txt

その2つのデューティの差をグラフにしたのが↑。

| | コメント (6)

2023年2月14日 (火)

ありゃま。ラズピコがおかしくなった。 PWMを調べたかったのに

ラジオペンチさんからのコメント(2023年2月12日13時09分)
件の記事(2023年3月号p.155)を読んで、図8の
ラズパイpicoの疑似DAC特性」が気になったので
ごそごそしていました。

で、昨夕は手持ちのラズピコにちゃんとスケッチを書き込
めたんですが(Arduino IDE環境)、今朝、ゴソゴソしたら
エラーが出てしまって書き込めません。
昨夕、最後に書いた、シリアル入力値でPWMを設定するという
スケッチは動いていてUSBを通してのシリアル送受はできてい
るのです。
ところが、スケッチのアップロードは失敗。
BOOT SWを押しながらUSBコネクタを挿しても、普通なら現れる
はずのドライブが出てきません。
どこか何かがおかしくなったようです。

Arduino UNOのPWMは、
Arduino、analogWriteは捨てちゃえ。ちゃんとしたPWMを使おう
で記してますように、「途中で1/256狂って」います。

で、ピコのPWMにも違和感。
記事には最大1.4mV未満と測定結果が記されますが、
PWMによるDAC、少々リップルが乗ってもこんな
誤差は生じないはずです。
Bb10_20230214160301

3.3V/255で1bit変化で12.9mV。 (あえて1/255で表記)
10%ほどがプラスに積み重なって、128あたりで最大に
なってます。
8bitのPWMそのものに何かがあるんじゃないかと感じました。

2020年11月12日:Arduino UNOでデューティー比測定回路 ケースに入れて完成

Bb11_20230214160301
    PWM=128にした時のデューティ、周波数と
   H区間クロック数、L区間、計測クロック(MHz)

これで、ピコが出すPWM波のディーティを調べてみようとした
のです。
とりあえず手入力した0~255の値でPWMを設定という
スケッチ、これは昨夕にピコに書けたのですが、
今朝になってこれを更新しようとしたらアウトっとい
う状態になってしまったのです。

で、1~254の値を手入力してちょっと調べてみました。
ピコもUNOと同じように、設定値0で出力L固定、255でH固定
となっています。

ピコでの1~4までのH区間とL区間を見てみます。
デューティチェッカーのクロックは16MHz。
PWM H  L
 1  96 31937
 2 224 31809
 3 352 31681
 4 480 31553

1と2、2と3、3と4の差は128クロック。
つまり125kHz=8μs。
しかし、1のH区間が96で6μsしかありません。
  オシロでも確認したんで、デューティ比チェッカの
  ミスじゃありません。

L区間がちょこっと出る253と254はこんな値。
PWM  H   L
 253 31777 256
 254 31905 128

これで、1~254の端っこを見たわけですが、1の時の
96を考慮したら、253の時のはH区間は「32352」に
なって欲しいところ。
  252 * 128 + 96=32352
ところが31777。 なんか小さい。
254も「32480」が妥当じゃないのかと。

  ※ピコのスケッチを、手入力じゃなく自動で順にPWM値を
   変化させて、デューティ比をチェックできればと
   考えたのですが、アップロードできなくなってし
   まったのです。

どこかでおかしくなっているようなのですが、手での
入力と目で見ての確認はちょっとつらい。
気を取り直して、まず1に近いところから順におかしく
なっている場所を探してみました。

すると12~16でこんな変化が。
PWM 期待値 実値H 実値L
 12 1504 1504  30529
 13 1632 1632  30400
 14 1760 1728  30305
 15 1888 1856  30177

実値Hの13と14の間が「96」になってます。
そして、14と15の間は「128」に復帰。

ピコのPWM、何かが潜んでいそうですぞ。
   ※単調性がどこかで狂ってる?

しかし、ピコへのスケッチ書き込み失敗、困りました。
なんとかしなくちゃ。

デューティ比チェッカ、自動記録用にシリアル出力が
いりますなぁ。

| | コメント (3)

2022年5月 2日 (月)

マイコン出力ポートのプルアップ、プルダウン問題 誤パルス出力を避けるために

トランジスタ技術2004年1月号に
  『マイコン内蔵I/Oポートによる各種ドライブ回路』
という題で、入出力ポートに対する注意点を載せてもらい
ました。
Tt1_20220502131301
「定番エレクトロニクス回路140」という特集記事で、
小さな記事がいくつもならんでいます。
Tt2_20220502131301

その中の一つで、掲載記事は1ページにまとまっています。
Tt31

出力が不定な、プログラムが走る前のリセット期間に
要注意という内容です。
インターフェースするデバイスにより、プルダウン抵抗
を付けたり、プルアップ抵抗を使ったりということで、
あれこれ解説しています。
あらためて図示しておきます。

まず「Hアクティブ」で使う信号考えます。
Pp01
ポートを直で使うのではなく、
  ・駆動電流を増やしたい
  ・異電圧でドライブしたい
など、インターフェース素子を間にはさむ場合が出てきます。
  ※例では LEDを負荷にしました。

これはアカンぞ! という例。
Pp02
ベースやゲートなどの入力インピーダンスを下げておかないと
誘導や隣の信号のパルスを拾ってしまって
「誤作動するかも」です。

「勝手な出力が出てもOKだよ」という回路じゃ限り
面倒でも抵抗を入れておきましょう。
Pp03
これで、まっとうな「Hアクティブ出力」になります。
バイポーラトランジスタだと「抵抗内蔵トランジシタ=デジトラ」が
使えます。

多信号なら、トランジスタアレイを使いましょう。
Pp04
入力を安定させる抵抗が入っています。

問題は「Lアクティブ」信号。
昔からある「TTL」は
  入力オープンだとHと認識。
  Lに引っ張って(GNDに電流を流して)オン。
  入力を安定させるにはプルアップ抵抗を。
  ストローブ信号など、Lアクティブが多い。
という特徴があります。
Pp11
TTLでインターフェースするなど、Lアクティブで使う時は
プルアップ抵抗を入れるのが定石になります。
しかし、マイコンのポートを初期化する時にこつが必要です。
 ・ポートの出力レジスタを先にHに。
 ・その後からポートを出力モードに。
「先にH」を処置せず、出力モードにしてからHを出力すると、
一瞬のLパルスが出てしまいます。
  ※このパルスが無視できる回路なら良いのですが

この処置、昔のI/Oチップ「8255」などは
  「出力に初期化したらポートはLからスタート」
となっていて、Lアクティブで使うには、不要なLパルスが出ても
大丈夫な回路を構築しておかなくてはなりませんでした。

LEDの点灯回路ならこんな具合です。
Pp13

間違って「Hアクティブ」で使う回路にプルアップ抵抗を
入れてしまうと、
  電源オン→リセット解除→プログラムが走り始める
この間、不要なパルスが出てしまいます。

TTLだから入力をプルアップしたのにHアクティブで使う、
というのはちょっとなぁです。
出てくる余計な信号が悪さをしなければ良いのですが。
Pp12
LEDだと「一瞬光る」だけで済むのですが、メカを駆動する
ような回路だと、問題が生じるかもしれません。

Raspberry Pi PicoのマイコンRP2040、
「リセットで内蔵プルダウン抵抗が有効になる」は、
  ・入力がオープンのまま放置されるのを防止
  ・Hアクティブ出力での不要パルスの防止
この二つの役目があります。

Pp05  
しかし、RP2040を「Lアクティブ出力」で使う時は要注意になります。
内蔵プルダウン抵抗に負けない(抵抗値の小さな)プルアップ抵抗を
使っておかないと、リセットで不要なパルス(L出力)が出てしまいます。

| | コメント (1)

2022年5月 1日 (日)

Raspberry Pi Pico リセット起動後のポートはプルダウン抵抗が有効に

まだまだ使いこなせていないRaspberry Pi Picoですが、
ラジオペンチさんところの
Raspberry Pi Picoで72LEDのクリスマスツリーイルミネーションを作る
この記事にコメントした関係で、PicoのI/Oポートについて
あれこれ調べてみました。

参考資料はこれ。
P11_20220501113801

I/Oポートの構成図、こんなのが記されています。
P12_20220501113801

その機能、ポート1ビットごと独立して設定できるように
なっています。
P21
P22

リセット後はこんな状態になります。
 ・出力は禁止。 入力ポートに。
 ・出力ドライブ能力は4mAに。
   (4種類あってmaxは12mA)
 ・プルアップ抵抗はなし。
 ・プルダウン抵抗が有効に。★
 ・入力のシュミットトリガー機能は有効。
 ・出力Slew rateはSlowに。
となっています。

Arduino UNOのAtmega328Pなどと異なるのが★の
プルダウン抵抗有効」という機能です。
これで「未使用ポート」の処理を省けます。

Arduino IDE下でスケッチを組んだ時、入出力を
決めるのに「pinMode()」を使います。
どんな処理がされているのか探しますと、
  ※wiring_digital.cppの中
~~~~~~~~~~~~~~~~~~~~~~~~~
void pinMode(pin_size_t ulPin, PinMode ulMode) {
 switch (ulMode) {
  case INPUT:
    gpio_init(ulPin);
    gpio_set_dir(ulPin, false);
    gpio_disable_pulls(ulPin);
    break;
  case INPUT_PULLUP:
    gpio_init(ulPin);
    gpio_set_dir(ulPin, false);
    gpio_pull_up(ulPin);
    gpio_put(ulPin, 0);
    break;
  case INPUT_PULLDOWN:
    gpio_init(ulPin);
    gpio_set_dir(ulPin, false);
    gpio_pull_down(ulPin);
    gpio_put(ulPin, 1);
    break;
  case OUTPUT:
    gpio_init(ulPin);
    gpio_set_dir(ulPin, true);
    break;
  default:
    DEBUGCORE("ERROR: Illegal pinMode mode (%d)\n", ulMode);
    return;
 }
 if (ulPin > 29) {
    DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
    return;
 }
 _pm[ulPin] = ulMode;
}
~~~~~~~~~~~~~~~~~~~~~~~~~

gpio_disable_pulls();」という関数で、
「プルアップ抵抗、プルダウン抵抗、両方ともなし」を
設定しています。
全ポート一括して処理するという関数は用意されていない
ようです。


もう一つ。
gpio_init() 」の中味。
~~~~~~~~~~~~~~~~~~~~~~~~~
void gpio_init(uint gpio) {
  sio_hw->gpio_oe_clr = 1ul << gpio;
  sio_hw->gpio_clr = 1ul << gpio;
  gpio_set_function(gpio, GPIO_FUNC_SIO);
}

void gpio_init_mask(uint gpio_mask) {
  for(uint i=0;i<32;i++) {
    if (gpio_mask & 1) {
      gpio_init(i);
    }
    gpio_mask >>= 1;
  }
}
~~~~~~~~~~~~~~~~~~~~~~~~~
指定ピンを「GPIO_FUNC_SIO」にということで。

  ※SIOシリアルI/Oじゃなく、
   シングルサイクルI/Oのこと。
   ちょいと違和感がぁ。

 

| | コメント (2)