投稿

STM32F3 Discovery、タイマーと割り込みのキホン

イメージ
STM32F3 Discovery、タイマーと割り込みのキホン 今回のSTM32F3 Discovery企画では、基本的なタイマー動作についての設定と、そのタイマーを割り込みで使うための基本について解説したいと思います。 写真ではわかりづらいですが、タイマーでPWM制御しています。 STM32F303は、タイマーとしてTIM1, TIM2, TIM3, TIM4, TIM6, TIM7, TIM8, TIM15, TIM16, TIM17 と10個のタイマーを持っています。(なぜ番号が飛んでいるのかは不明) この中で、TIM1と8は高機能なタイマーとして実装されていますが、今回の記事ではTIM1を使ったプログラミングを行いたいと思います。 また、タイマーとともに割り込みでの処理を行いたいので、割り込み設定についても解説していきます。 なお、このサンプルではタイマー設定などについて、直接レジスタ設定で実現しています。 レジスタ、割り込みの定義は、stm32f303xc.hで行われています。他のSTM32を利用する場合、それぞれのMPUに適したヘッダファイルが存在していますので、そちらのヘッダーファイルを参照してください。 stm32f303xc.h 中で、TIM1に関するレジスタのベースアドレスや各操作レジスタが定義されていて、  TIM1->PSC = 4800;  → TIM1タイマーのプリスケーラーレジスタに4800を設定する の、ような記述が可能になります。 一般的にMCUのタイマーは、タイマーモジュールに供給されているクロックをカウントすることで、ある時点からどのくらい時間が経過したかを測るものです。 このため、使用するタイマーモジュールに供給されるクロック数を確認しないと正確なタイマー設定を行うことができません。 タイマー1(TIM1)は、STM32F303xB STM32F303xCデーターシート(DS9118.pdf)のブロックダイアグラム(13/149)を確認すると、APB2/72MHzに接続されています。しかし、実際に供給されているクロック設定をCubeMXで確認すると、48MHzとなっています。Eclipse CubeMXのパースペクティブのClockConfigurationを確認して...

Linuxシステムコール、POSIX スレッドの生成

UNIX / Linux システムコール・プログラミング POSIXスレッドの生成 スレッドとは? スレッドは、実行の単位ですがプロセスとは異なります。プロセスは、プロセスごとに独立した論理アドレス空間をもち、異なるプロセス間ではメモリの共有をしていません。 プロセスの生成に関しては下記を参照。  →  Linuxシステムコール、プロセスの生成 これに対してスレッドは、1つのプロセスのメモリ空間を共有する複数の実行単位となります。簡単に言ってしまえば、ある関数fx()を呼び出すときにスレッドとして呼び出すことでfx()を複数、同時並列的に実行できるようになります。 同様のことは fork()で別プロセスとして分岐し、fx()を呼ぶことで実現できますがfork()はプロセスのメモリイメージのコピー(実際にはコピーオンライトで異なる部分だけのコピーでその他は共有されます)が発生し、プロセス動作するためのスタック領域などが別個に確保されるためのコストが発生します。 スレッドは、このようなコストを必要としないという特徴があります。 また、スレッドはマルチコアのCPUの場合に特定のコアにスレッドを結びつけることも可能という特徴もあります。 また、通常c言語は、main() から始まりますが、この大本をメインスレッドとも表現します。 スレッドを動かしてみよう! それでは、実際にLinux上でスレッドを使ったコードについて解説していきたいと思います。 サンプルコードは下記のような処理を行います。 1.3つの新しいスレッドを、pthread_create() で生成します。  このとき、メインスレッドから起動時の引数として文字列を渡します。 2.それぞれのスレッドが同時並行で処理を行います。  このコードでは下記の2つの処理を実装しています。   スレッド関数1. 引数の文字列の長さ分タイマーウエイトを行う   スレッド関数2. 引数の文字列を大文字・小文字変換して返す 3.メインスレッドは、各スレッドの完了を待ち合わせます。  起動されたスレッドは終了時に、pthread_exit() を使って終了コードを通知します。  メインスレッドは、pthread_join() を使って各スレッドの終了状態を受け...

Beaglebone Black ネットワーク・ブート環境の構築

イメージ
Beaglebone Black ネットワーク・ブート環境の構築     Beaglebone Black networking boot via Network over USB. 前回記事、「 BeagleBone Black 起動SDカードの作成 」では、Linuxを起動できるSDカードを作成してBeaglebone BlackをLinux動作させる方法について紹介しました。 しかし、この方法ではカーネル周りを開発する場合に毎回開発PCでSDカードを作成し、Beaglebone BlackにSDカードを戻して起動、という手順を毎回ふまなければなりません。 また、SDカードを頻繁に抜き差しするため、SDカードスロットへの負荷も大きくなり、SDカードスロットが故障する原因ともなり得ます。 このため、実際の開発現場においてはターゲットボードをネットワーク経由でブートする環境を構築することが現実的です。 今回の記事は、実際にBeaglebone Blackをネットワーク経由でブートするための環境を構築する方法について紹介します。 なお、この記事の内容はUbuntuのバージョンなど「 BeagleBone Black 起動SDカードの作成 」で紹介した環境をベースにしています。 ネットワーク・ブートとは? ネットワーク経由でのブートとは、ターゲットであるBeagleBone Blackと開発ホスト(サーバー)をTCP/IPで接続します。実現のために、このネットワーク上では、2つの技術を利用します。 1つ目は、ネットワーク経由でカーネルイメージをダウンロードしてメインメモリに展開するための「 TFTP 」。 もう1つは、システムが起動するためのルートファイルシステムをネットワークから与えるための「 NFS 」です。 AM3359は、電源投入後ROMプログラムが動作し、U-Bootをメインメモリにロードします。ここまではSDカード起動と同様です。このU-BootはBeaglebone Black上のMMCでも、SDカードでも問題ありません。 このU-Bootの機能を使ってTFTPサーバーから、カーネルイメージをダウンロードします。TFTPとは、Trivial File Transfer Prot...

Linuxシステムコール、プロセスの生成

イメージ
UNIX / Linux システムコール・プログラミング プロセスの生成 Linuxのプロセスとは? Linuxでは、プログラムの実行単位がプロセスとして定義されています。 これまで、このシリーズでもプロセス間通信を取り上げてきましたが、そもそもプロセスとは何でしょうか? 今回は、このプロセスについて取り上げてみたいと思います。 さて、先程プログラムの実行単位がプロセスだと書きました。通常、我々はgccなどを使って作成された ”実行ファイル” をメモリに読み込んでプログラムを実行します。これがプロセスです。 簡単な”Hello World”を例題に説明します。 hello.c #include <stdio.h> int main(int argc, char** argv) { printf("Hello World\n"); } このプログラムをコンパイルします。     $ gcc hello.c -o hello とすると、実行ファイル hello が出来上がります。 実行するには、     $ ./hello とすれば、実行されます。 当然ですが、このときにナニが起きているのか? 今まで気にしたことは無いかもしれませんが、詳しく見てみましょう。 ”$ ./hello”では、実行ファイルをコマンドとして、シェルから実行しています。 このシェルというユーザーインターフェイスも1つのプロセスとしてメモリ空間に存在しています。 ユーザーが、”$ ./hello”と、入力するとシェルは、fork() というシステムコールを呼び出して別のプロセスのためのユーザー空間を生成します。 そして、exec()というシステムコールを使ってそのメモリ空間に実行ファイル”hello”を読み出して展開し、main()にジャンプすることで、実行ファイル”hello”が実行され、コンソールに"Hello World"が表示されます。 UNIX系のOSでは伝統的に fork()/exec() という2段階のシステムコールによってプロセスの生成を行います。 まず、fork()ですが、このシステムコールは呼び出したプロセスのコピーを作り出します。 実際のコードを見て...

Linuxシステムコール、INETドメイン ソケット

UNIX / Linux システムコール・プログラミング プロセス間通信(IPC)、ソケット通信/INETドメイン ソケット Unixドメイン ソケットとは? Unixドメイン ソケットは、ノード間のネットワーク通信を行うことができ、現代のインターネット環境の基盤技術の1つと言えます。 INETドメイン ソケットを利用することで実際のネットワーク上のプロトコルであるTCP/IPやUDP/IPを意識したプログラミングが可能になります。 ※今回のサンプルコードは、TCP/IPです。 基本的に、INETドメイン ソケットもUnixドメイン ソケットと同様の実装となりますが、異なるノード間での通信を実現するため、ネットワークアドレスやポート番号を意識する必要があります。 それでは、サーバー側のコードを以下に示します。 inet-dimain-server.c #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> // Make server socket. // int makeServer(int portNo) { int sfd; int ret; struct sockaddr_in serv; // Create server socket. if((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("ERROR:Server Socket()"); return -1; } // Bind socket memset(&serv, 0, sizeof(struct sockaddr_in)); ...

Linuxシステムコール、Unixドメイン ソケット

UNIX / Linux システムコール・プログラミング プロセス間通信(IPC)、ソケット通信/Unixドメイン ソケット Unixドメイン ソケットとは? Unixドメイン ソケットは、同一ノード内(1つのCPUで動作する1つのオペレーティング・システム内)で動作するプロセス間で、双方向の通信手段を提供します。 また、ソケットはクライアント/サーバー モデルで構成されており、1つのサーバーが複数のクライアントからの通信を受け入れる構造をとります。 まず、以下にサーバー側のサンプルコードを示します。 unix-dimain-server.c #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> // Make server socket. // int makeServer(char* sockName) { int sfd; int ret; struct sockaddr_un name; // Unlink, last running remove the socket. unlink(sockName); // Create server socket. if((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("ERROR:Server Socket()"); return -1; } // Bind socket memset(&name, 0, sizeof(struct sockaddr_un)); name.sun_family = AF_UNIX; strncpy(name.sun_path, sockName, sizeof(name.sun_path) - 1); if ((r...