マイコンの割り込みをLinux上で再現する

マイコンの割り込みをLinux上でシグナルとスレッドを使って再現してみた。

大まかな処理は、マルチスレッドで制御のスレッドとマイコンの処理相当を行うスレッドの2つを作成、
制御側からマイコンの処理相当のスレッドをシグナルで一時停止させ、その間に割り込みハンドラを実行する。
フルのソースコードは以下を参照。

https://github.com/yasuharu/micon_int_on_linux/

まずマイコン側の処理。UARTの受信を意図したもの。
uart_rx_handlerが割り込みハンドラ、micon_mainがマイコン側のメイン処理。

 1void uart_rx_handler()
 2{
 3  static int     pos   = 0;
 4  static uint8_t buf[] = "test";
 5
 6  ringbuf_push(buf[pos]);
 7
 8  pos++;
 9}
10
11void micon_main()
12{
13  register_irq_handler(uart_rx_handler);
14
15  while(1)
16  {
17    if(ringbuf_length() > 0)
18    {
19      printf("%d\n", ringbuf_pop());
20    }
21  }
22}

メイン側の処理は、マイコン用のスレッドを作成し、一定期間ごとに割り込みを生成する。
割り込みの生成タイミングは、お好きなタイミングでどうぞ。

 1pthread_t thread_handle;
 2
 3int main()
 4{
 5  pthread_create(&thread_handle, NULL, micon_thread, NULL);
 6
 7  for(int i = 0 ; i < 5 ; i++)
 8  {
 9    sleep(1);
10
11    suspend_micon_thread();
12    do_irq_handler();
13    resume_micon_thread();
14  }
15}

シグナルはSIGUSR1とSIGUSR2を使用する。
SIGUSR1はマイコン側の処理をsuspend、SIGUSR2はマイコン側の処理をresumeするために使用する。
micon_thread内で以下の通り初期化する。

 1void micon_thread()
 2{
 3  struct sigaction sigusr1, sigusr2;
 4
 5  sigusr1.sa_flags   = 0;
 6  sigusr1.sa_handler = micon_thread_signal_usr1_handler;
 7  sigemptyset(&sigusr1.sa_mask);
 8  sigaction(SIGUSR1, &sigusr1, NULL);
 9
10  sigusr2.sa_flags   = 0;
11  sigusr2.sa_handler = micon_thread_signal_usr2_handler;
12  sigemptyset(&sigusr2.sa_mask);
13  sigaction(SIGUSR2, &sigusr2, NULL);
14
15  micon_main();
16}

今回のポイントは、以下のコードの部分。
suspend/resumeでマイコン側のスレッドを一時停止させる。
SIGUSRT1のハンドラ(micon_thread_signal_usr1_handler)内では、
sigsuspendを呼んで、SIGUSR2が発生するまで待つ。

割り込みハンドラはメインのスレッド、シグナルのハンドラはマイコンのスレッドと、
それぞれで実行しているコンテキストが違うことに注意が必要。
特にシグナルのハンドラのsigsuspendを実行する前に、割り込みハンドラが実行されないよう、
int_statusで処理待ちを行うようにしている。
(ちなみに、int_statusは本来であればmutexでロックが必要)

割り込みが発生したときの処理をまとめると以下の図になる。

処理

do_irq_handlerはこんな感じ。
int_statusを待つことだけ注意。

1void      (*irq_handler)(void);
2
3void do_irq_handler()
4{
5  while(int_status != 1);
6
7  irq_handler();
8}
Posted at : 2018-01-28 15:46:12 / Category : avr

AVRのクロック供給をまとめてみた

AVRを使ったボードの設計をしていて、クロックの供給方法がいくつかあり、どういう違いがあるのかまとめてみた。
ATMEL 8-BIT MICROCONTROLLER WITH 4/8/16/32KBYTES IN-SYSTEM PROGRAMMABLE FLASH DATASHEETを元にしています。

使用するクロックのデバイスごとに、以下のように設定を行う。
デバイスに対応する設定値は、データシートのTable 9-1を参照。

  • Low Power Crystal Oscillator
    • 外部の水晶発振子を接続。消費電力が少ない代わりに、外部のデバイスにクロックを供給したり、ノイズが多い環境では使えない
  • Full Swing Crystal Oscillator
    • 外部の水晶発振子を接続。消費電力が多分、上記の問題が解消される
  • Low Frequency Crystal Oscillator
    • 時計のクロック(32.768kHz)を使用する場合
  • Internal 128kHz RC Oscillator
    • 内部のRC発振回路を使用する場合。電圧、温度などにより変化する(この場合、キャリブレーションできないため、3V、25度で128KHzとなる)
  • Calibrated Internal RC Oscillator
    • 内部のRC発振回路を使用する場合。電圧、温度などにより変化する。キャリブレーションすることで、適切なクロックを得ることができる
  • External Clock
    • 外部の水晶発振器を接続する。この場合は、外部端子はXTAL1のみを使用する

ちなみに、水晶発振器、水晶発振子は違いがややこしい。
前者は発振回路を含んだパッケージになっているもの。製品によっては温度補償などもあるみたい。
後者はコンデンサなどを含む回路を接続する必要がある(マイコンの中に入っているものもある)。
AVRの場合は、Figure 9-2.にあるようにコンデンサを付ける必要がある。

上の表に戻って、上から3種類に関しては、さらにCKSEL[9]、SUT[0]、SUT[1]のそれぞれのビットで動作が変わる。
設定値で変わるのは、以下の2点。要はクロックが供給開始するタイミングからのdelay時間を規定している。

  • Start-up times from Power-down and Power-save
    • Power-down, Power-saveからの起動時間。(ここがあまり自身がなくて、おそらく、この時間までにクロックを安定させて欲しい、ってことだと思う)
  • Additional Delay from Reset
    • 外部のリセットからシステム内部のリセット(Internal Reset)の遅延時間。Figure 11-2.のT_TOUTに相当する

まとめは以上のとおり。

結局、どれが良いのか?という話になるけど、コストとかも考えると Low Power Crystal Oscillatorが 良いんだろうな。

Posted at : 2015-07-18 18:27:12 / Category : avr

AVRでSDとISPを共用する

AVRでSDとISPを共用する場合、どのように端子を接続すれば良いのか?
仕様書とかネットとか見て調べてみた。
(間違っていたらご指摘お願いいたします)

ISPの仕様書は以下を参照。

CPUはATMEGA328/168/88をターゲットに。

要点としては以下のとおりとなる。

  • コネクタの端子は以下のとおり
    • 端子配列
  • 実際の通信はSPIに従う
  • ResetがLowの時にSPIでデータを送る
  • ISPと他のデバイスと端子共用することができる
    • 外部からの駆動で影響を受けないように直列に抵抗を入れる

こんな感じの回路で良いのかな。

SD_ISP端子共用

Posted at : 2015-06-13 17:49:30 / Category : avr