ちょっとTea Time!? PICO(RP2040)を思い出してみる(備忘録) 2024.2.15

Raspberry Pi PICOなるものが出て、飛びついたものの、
いまだにPICばかりつかっています。というのも、PICでできることが
PICOで出来ないとソフト移植もままならないので、そこが完全に
確認できていなかったからです。まずはPICOでも出来るでしょうが、
課題はやり方を知らないということです。

そこで、ここでは備忘録として、PICOの使い方についてすこし調べてみました。

<過去の記事>
ちょっとTea Time !? Raspberry Pi のPICOを動かしてみる。 2021.8.5
ちょっとTea Time!? PICOの開発環境を揃える(備忘録) 2022.7.10
ちょっとTea Time!? 秋月のRP2040マイコンボードを動かしてみる! 2023.3.1


こちらも備忘録がわりに貼り付けておきました。


1.インターバルタイマ割り込みは止められるの?

 インターバルタイマー割り込みはタクトスイッチやエンコーダの接点を定期的に調べるために
1ms間隔で必ずといっていいほど使っているのですが、赤外線リモコンの受信ONを確認すれば、
そこからは割り込みを停止して、赤外線受信に専念するようにしています。というのも、赤外線の
リモコンコードは少なくとも数10msありますので、再帰的に割り込みがかかるとややこしいからです。
PICOでは  disable_interrupts(INT_TIMER0)   enable_interrupts(INT_TIMER0)
タイマー割り込みの停止、再開の関数がありました。
PICOではどうすればいいのだろう?
 ということで、あれこれ調べると、 ありました。
まずは、割り込みの種類で番号は割り当てられています。
そして、割り込みの停止、再開は
 irq_set_enabled(割り込み種類の番号,0:停止 1:再開)
という関数で行えるようです。


 

サンプルプログラムで100usでタイマー割り込みをかけますが、
割り込みルーチンの中で、50usの処理と割り込みを止めて200usほどの処理を行うような
ことをしてみました。
 GPIOの出力を観察すると、100us毎の割り込みですが、250us毎の
処理になっており割り込みが停止していることがわかりました。
なお、割り込みから復帰すると、すでにタイマー割り込みのトリガが
かかっている状態になっている様子なので、直ぐに再度割り込み処理が行われるようです。

// サンプルプログラム
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/interp.h"
#include "hardware/timer.h"
#include "hardware/watchdog.h"
#include "hardware/clocks.h"

#define GPIO_00 (0)
#define GPIO_01 (1)

bool timer_callback( repeating_timer_t *rt )
{
  int i;
  
  gpio_put(GPIO_00,1);
  busy_wait_us_32(100);
  gpio_put(GPIO_00,0);
  irq_set_enabled(17,0);
  for(i=0;i<10;i++){
    gpio_put(GPIO_01,1);
    busy_wait_us_32(10);
    gpio_put(GPIO_01,0);
    busy_wait_us_32(10);
  }
  irq_set_enabled(17,1);
  
  return ( true );
}

void main( void )
{
  static repeating_timer_t timer;
  gpio_init( GPIO_00 );
  gpio_init( GPIO_01 );
  gpio_set_dir( GPIO_00, GPIO_OUT );
  gpio_set_dir( GPIO_01, GPIO_OUT );
  add_repeating_timer_us( -200, &timer_callback, NULL, &timer );
  while( true )
    {  
    }
}


上:GPIO0、下:GPIO1

2.FLASHの書き込み速度は?

PICで設定値を記録・読み出しするときはEEPROMを使います。
関数は
 write_eeprom(int16 adrs, int data)
 read_eeprom(int16 adrs)

です。write関数は1バイトあたり概ね数msかかりますが、PICOの場合はどうだろう?
PICOではeepromの代わりにflashメモリーを使いますが、書き込みの前に
消去をする必要があります。そして消去の単位が4096byteと、書き込みの単位が
256byteと大きいです。どのくらいの時間がかかるのかな?
 あまり時間がかかるようだと、どこかにバッファーをもたせて、適当な
タイミングでまとめて書くようなことをしなければなりません。
一度調べておきましょう。

まずはflashメモリをつかうために、CMakeLists.txt を一部編集(追記)します。


下記のように1024Byte分の領域を仮定して、書き込む時間を測定してみました。
書き込みにかかっているときのGPIOをONにしてオシロで時間を計測です。

で、結果は1024Byteの書き込みで35msほどかかりました。

こりゃ、PICとおなじようにEEPROMのように扱うためには、ちょっとした
サブルーチンをつくる必要がありそうです。

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/interp.h"
#include "hardware/timer.h"
#include "hardware/watchdog.h"
#include "hardware/clocks.h"
#include "hardware/flash.h"

#define GPIO_00 (0)

#define FLASH_TARGET_OFFSET (0x1f0000)

uint8_t write_data[1024];

void main( void )
{
 gpio_init( GPIO_00 );
 gpio_set_dir( GPIO_00, GPIO_OUT );
 while( true )
 { 
  gpio_put(GPIO_00,1);
  flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
  flash_range_program(FLASH_TARGET_OFFSET, write_data, FLASH_PAGE_SIZE * 4);  
  gpio_put(GPIO_00,0);
  busy_wait_us_32(1000);
 }
}

リハビリ〜 2024.8.12

しばらく半田ゴテもソフトも組んでいなかったので、リハビリがてら再開です。
手始めにPICOでのソフトを充実させようかと思っていますが、過去に調べたことが
色々と間違ったことがわかりました。

1.タイマ−割り込みの停止番号は3
 最初はCLOCK_IRQの17と思い込んでいましたが、実際に動かしてみても割り込みが停止しません。
で、色々と調べるとTIMER_IRQ_3の3番が該当することがわかりました。
ただ、新たにわかったことは割り込みの停止は素直に動きますが、割り込みを再開するとなぜか、
ある一定時間の間に頻繁に割り込みがかかってしまいます。そのため、一定時間(1ms程度)は
割り込みを再開しても、割り込み処理は単にすぐにリターンするようにしたほうが良さそうです。
まあ、あくまでもその場しのぎの処理ですが。

2.GPIOの入力はプルダウンがデフォルト?
 GPIOに赤外線リモコンの受光モジュールを接続してもうまく動きません。
調べてみると、信号端子のレベルが1.6Vと中途半端です。どうやら、GPIOを
入力設定にしたときに、開放時の電圧レベルが0Vになっています.ひょっとして、
プルダウンがかかっているのかもしれません。
 ということで、GPIOを設定したときには、プルダウンあるいはプルアップを明示的に
示したほがいいかもしれません。

 
PICOをつかってソフト作成のリハビリ中です。

念のため、GPIOのプルアップ、プルダウン抵抗値を調べてみました。抵抗値はどちらもおよそ30kΩ程度のようです。
いづれにしても、単に入力設定しただけではプルダウンになっているようです。

GPIO 定義 開放時
電圧
47kΩ
負荷(GND)
47kΩ
負荷(VCC)
備考
11 入力 約70mV 0V 1.250V 入力設定だけではプルダウンになっている。
12 入力+プル禁止 約1.2V 20mV 3.247V プル禁止にすると入力はフロート状態
13 入力+プルアップ 3.3V 1.973V プルアップ抵抗は31kΩ程度
14 入力+プルダウン 0V 1.242V プルダウン抵抗は28kΩ程度


(つづく?)