2014年1月26日日曜日

STM32F0 Value line Discovery(2) デモプログラムの中身を確認する

初めに

STM32F0のデモプログラムは何をやっているのか確認します。

統合開発環境やメーカーからのライブラリのおかげで、簡単にプログラムが作れるようになったのは良いのですが、最初からお膳立てされれているので逆に何をやっているのか理解が進まない事が有ります。今日はデモプログラムが何をやっているのか確認してみます。

main.c

マイコンの電源が投入されるとまずmain.cの先頭からプログラムが実行されます。(厳密には違いますけど、今のところはそう考えましょう)

インクルードファイル

#include "main.h"

ここでは、外部のヘッダファイルをインクルードしています。main.hの中身はあとで確認する事とします。

変数定義

static __IO uint32_t TimingDelay; uint8_t BlinkSpeed = 0;

二つの変数(TimingDelay,BlinkSpeed)を定義しています。 static は静的変数と言うのもので、メモリ上の(どこかに)常に確保され、どの関数からも読み書きができる変数です。

次の __IO は意味が解りません。 右クリックして宣言に移動してみると、core_cm0.hと言うファイルの中で、

#define __IO volatile /*!< Defines 'read / write' permissions */

volatile の別名として使っている事が解りました。 volatileと言うのは、最適化をしないでね、と言うもので組み込みマイコンでは良く使います。 しかし、普通にvolatileと書いてくれればよいものを...

main関数

変数定義

main関数で定義された変数はmain関数内で有効となります。

RCC_ClocksTypeDef RCC_Clocks;

RCC_ClocksTypeDef というのは、以下の様にstm32f0xx_rcc.hで定義されています。

typedef struct { uint32_t SYSCLK_Frequency; uint32_t HCLK_Frequency; uint32_t PCLK_Frequency; uint32_t ADCCLK_Frequency; uint32_t CECCLK_Frequency; uint32_t I2C1CLK_Frequency; uint32_t USART1CLK_Frequency; }RCC_ClocksTypeDef;

IOの初期化

STM_EVAL_LEDInit(LED3); STM_EVAL_LEDInit(LED4); STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_GPIO);

LED3,4を出力に、USERボタンを入力に設定しています。

1msタイマの設定

RCC_GetClocksFreq(&RCC_Clocks); SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);

RCC_GetClocksFreqで現在のクロック情報を読み出し、その値を 1/1000 して SysTick_Configに渡します。

systickとはARMコア共通のタイマ割り込みで、デフォルトはCPUの動作周波数(RCC_Clocks.HCLK_Frequency)となっています。 STM32F0の場合は48MHzですので、systickに48E6を書き込むと、ちょうど1秒でカウントダウンが完了します 。 このプログラムでは、ちょうど1ms毎に割り込みをかけたいので、48E6/1000を設定するわけです。

メインループ

ボタンのチェック

if(STM_EVAL_PBGetState(BUTTON_USER)== SET)

STM_EVAL_PBGetStateでボタンの状態を取得し押されれているか条件分岐します。

ブリンクスピードの変更

BlinkSpeed++; if(BlinkSpeed == 3) { BlinkSpeed = 0; }

ブリンクスピードをインクリメントしています。

Delay

Delay(1000);

随所にこのDelayがあります。待ち時間タイマと言う事は解るのですが、詳しく見てみましょう。 delay()は、mainの後ろの方で定義されています。

void Delay(__IO uint32_t nTime) { TimingDelay = nTime; while(TimingDelay != 0); }

ここでは、TimingDelayと言うグローバル変数(一番最初に宣言しましたよね)にタイマ値を代入し、 それがゼロにならない限りループする。というルーチンになっています。でもTimingDelayはどこでカウントダウンされるのでしょうか?

ここで、先ほどのsystickが出てきます。 systickは1/1000秒毎に割り込みをする設定をしたのですから、ここで何かをしているはずです。 stm32f0xx_it.cを見ると、以下のコードが有ります。

void SysTick_Handler(void) { TimingDelay_Decrement(); }

SysTick_Handlerとは、systickタイマーがタイムアップした時に飛んでくる場所です。 systickタイマーは1/1000秒毎にタイムアップする設定をしましたから、 1ms毎にこのルーチンが(割り込みで)実行されます。 TimingDelay_Decrementとは、TimingDelayがゼロで無い限りデクリメントをする。というルーチンになっています。

つまり、メインルーチンでTimingDelayに値を書き込むと、割り込みタイマが ---勝手に!--- カウントダウンを行ってくれる。 と言う仕組みになっています。メインルーチンはその値がゼロかどうかを調べるだけで良いわけです。

この方法は、マイコンで正確なタイマーを作る時の定石となっています。このプログラムではタイマーは1個でしたが、 例えば、tim1,tim2,tim3....tim10 などと10個のグローバル変数を用意し、SysTick_Handlerでそれら変数をデクリメントする様にしておけば、 メインルーチンのループ時間に関係なく、正確な1ms単位のタイマーを10個用意する事が出来ます。 (もちろん、メインループが1ms以上かかってしまうとその分の遅れ時間は出ますが)

また、この方法はカウントダウン中に別の作業を行う事が出来ますので、 古典的なマルチタスク(原理が単純なので私は好きですが)はこの方法を応用しています。

今日はこの辺で。次はmain.hは何をやっているのか見てみましょう。

main.c

/* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private variables ---------------------------------------------------------*/ static __IO uint32_t TimingDelay; uint8_t BlinkSpeed = 0; int main(void) { RCC_ClocksTypeDef RCC_Clocks; /* Configure LED3 and LED4 on STM32F0308-Discovery */ STM_EVAL_LEDInit(LED3); STM_EVAL_LEDInit(LED4); /* Initialize User_Button on STM32F0308-Discovery */ STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_GPIO); /* SysTick end of count event each 1ms */ RCC_GetClocksFreq(&RCC_Clocks); SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000); /* Initiate Blink Speed variable */ BlinkSpeed = 1; while(1) { /* Check if the user button is pressed */ if(STM_EVAL_PBGetState(BUTTON_USER)== SET) { /* BlinkSpeed: 1 -> 2 -> 0, then re-cycle */ /* Turn on LD4 Blue LED during 1s each time User button is pressed */ STM_EVAL_LEDOn(LED4); /* wait for 1s */ Delay(1000); /* Turn off LD4 Blue LED after 1s each time User button is pressed */ STM_EVAL_LEDOff(LED4); /* Increment the blink speed counter */ BlinkSpeed++; /* Default value for blink speed counter */ if(BlinkSpeed == 3) { BlinkSpeed = 0; } } /* Test on blink speed */ if(BlinkSpeed == 2) { /* LED3 toggles each 100 ms */ STM_EVAL_LEDToggle(LED3); /* maintain LED3 status for 100ms */ Delay(100); } else if(BlinkSpeed == 1) { /* LED3 toggles each 200 ms */ STM_EVAL_LEDToggle(LED3); /* maintain LED3 status for 200ms */ Delay(200); } else { /* LED3 Off */ STM_EVAL_LEDOff(LED3); } } } /** * @brief Inserts a delay time. * @param nTime: specifies the delay time length, in 1 ms. * @retval None */ void Delay(__IO uint32_t nTime) { TimingDelay = nTime; while(TimingDelay != 0); } /** * @brief Decrements the TimingDelay variable. * @param None * @retval None */ void TimingDelay_Decrement(void) { if (TimingDelay != 0x00) { TimingDelay--; } } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) {} } #endif /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Stellaris launchpad LM4F120XL(1) IAR EWARMで動かしてみる。

以前、販促でTIのLanuchPadをもらった事があるのですが、TI純正のCCS(Code Composer Studio IDE)と言う環境でしか動かしただけでした。
今回、STMのARMで実験した環境(IAR EWARM)で動かしてみました。開発ツールが一緒だとマイコンメーカーが変わっても同じ手順で開発が出来ます。(但し、IARの製品版はかなーりお高いので、個人では買えませんけどね。)

1.Stellaris wareをダウンロード

  •    Stellaris wareというのは、TIのARMマイコンを簡単に使えるようにする為のライブラリです。以下のサイトに飛びます。
   http://www.tij.co.jp/tool/jp/sw-ek-lm4f120xl    
  • ここに各開発環境用のファイルが並んでいます。今回は、IAR用を選んでダウンロード。

2.ファイルの展開

  •     適当なフォルダにzipファイルを展開し、EK-LM4F120XL-IAR-733\index.htmを開きます。

  • Software から Firmware の Install を選びます。
  • SW-EK-LM4F120XL-9453.exe と言うファイルが出来上がりますので、適当なフォルダで実行します。
  • 指示に従って、インストールすると、C:ドライブ直下にStellaris wareと言うフォルダが出来ます。

3.LaunchPadの接続

  •     USBケーブルでLaunchPadをPCと接続します。初めての場合は、デバイスドライバのインストール画面が出ると思いますが、私のPCは既にCCSで接続済みでしたのでそのまま繋がりました。

4.IAR EWARMの起動とプログラムの実行。

  •     C:\StellarisWare\boards\ek-lm4f120xl\ek-lm4f120xl.eww をダブルクリックすると、EWARMが立ち上がります。
  •     左側のウインドウにはたくさんのデモプログラムが並んでいますので、その中からblinkyを右クリックして、アクティブに設定します。
  • プロジェクト -> 全てを再ビルド を実行します。
  • プロジェクト -> ダウンロードしてデバック を実行します。
  • F5を押してプログラムをスタートします。




2014年1月25日土曜日

STM32F0 Value line Discovery(1) とりあえず動かしてみる。

インターフェース誌のプレゼントに当選して、STM32F030VL Discoveryが届きましたあ!
秋月で800円で買えるものなんですが、プレゼントに当選したこと自体がうれしくてテンションあがっちゃいました。(小学生か!)  早速、動かしてみます。

1.製品のページ

http://www.st.com/web/en/catalog/tools/PF259100
  • 昨年あたりにトラ技で連載していた、STM32ディスカバリの後継品と思われます よりも更に低価格のライン(030バリューライン)の製品です。
  • CPUはSTM32F100からSTM32F030に変わっています。大きなスペックは変わっていないようですが、  ARMコアがM3シリーズからM0シリーズに変わっていますし、ピン配置が変わっていますので、IOの接続には注意が必要です。

2.資料をダウンロード

  • DB2010: Discovery kit for STM32F030 Value Line microcontrollers 

  • UM1658: Discovery kit for STM32F030 Value Line microcontrollers 

  • UM1677: Getting started with STM32F030 Value Line Discovery development tools 

3.ファームウエアパッケージのダウンロード

  • STSW-STM32140
  • 展開すると、STM32F0308-Discovery_FW_V1.0.1 というフォルダができます。

4.IARのEWARMの準備

  • 開発環境はIARのEWARMです。
  • IARのサイトからダウンロードしてインストールしておいてください。(詳細は割愛)

5.とりあえず繋いでみる。

Running the built-in demonstration

  • STMのデモボードは購入した時から、既にデモプログラムが書き込まれていますので、USBをPCに差し込めば即動く(はずです。)
  • The board comes with the demonstration firmware preloaded in the Flash memory. Follow the steps below to run it:

  • JP2とCN2にジャンパが刺さっている事を確認します。(出荷時設定)
  • Check the jumper position on the board, JP2 on, CN2 on (Discovery selected).

  • PCとUSBケーブルで接続します。すると、LED1とLED2が点灯し、LED3が点滅します。
  • Connect the STM32F0308-DISCOVERY board to a PC with a 'USB type A to Mini-B' cable through USB connector CN1 to power the board. Then red LEDs LED1 (PWR) and LED2 (COM) light up and green LED3 blinks.

  • USERボタンを押すと、LED3の点滅間隔が変わります。
  • Press user button B1 (Button left corner of the board). The blinking of green LED3 changes according to clicks on user button B1.

  • また、USERボタンの確認用としてLED4(ブルー)が光ります。
  • Each click on the USER push-button is confirmed by blue LED4.

6.プログラムを書きこんでみる。

1)プロジェクトの起動

  • \STM32F0308-Discovery_FW_V1.0.1\Projects\Demonstration\EWARM\STM32F0308-Discovery_Demo.ewp をダブルクリックすると、EWARMが立ち上がります。
    • Userフォルダのmain.cをダブルクリックするとメインプログラムが表示されます。

    2)ビルド

    • プロジェクト -> 全てを再ビルド を実行します。メッセージウインドウに
    .......
    STM32F0308-Discovery_Demo.out
    変換中

    エラーの合計数: 0
    ワーニングの合計数: 0 

    と表示されればコンパイル完了です。

    3)デバッグ

    • プロジェクト -> ダウンロードしてデバック を実行します。
    • 矢印がmain関数の前で止まっています。

    4)プログラムの開始

    • F5を押してプログラムをスタートします。
    • 購入した時と同じプログラムが走ります。一つ違うのは、LED2(COM)が緑と赤の点滅になる事です。これは、デバック用の通信がされている証拠です。

    5)プログラムの停止

    • デバッグ -> ブレーク でプログラムを停止させます。

    6)ブレークポイントの設定

    • メインループの先頭のif文の横をクリックすると赤丸が付きます。
    • これがブレークポイントの印です。この状態で デバッグ -> リセット  。 デバッグ -> 実行 をしてみましょう。

    7)プログラムの続行

    • 先ほど設定したブレークポイントでプログラムが停止しています。F5(実行)を押すとプログラムを1ループ実行して、再びブレークポイントで停止します。
    • こうやって、プログラムのデバッグを行います。ブレークポイントの解除は赤丸をクリックです。

    8)終了

    • 全てを保存を選択して、終了を選べば完了です。

    2014年1月19日日曜日

    20140117江東区臨海部コミュニティサイクル Koutou-ku Coastal Area community cycle

    週末、インターネプコンを見学するためにビックサイトに行ってきました。
    I went to INTERNEPCON exhibition in Big Sight(Tokyo koutou-ku) on the weekend.
    駅までの帰り道、夕暮れにこんな光景を見つけました。
    On the way back to the station, I saw a sight that bike is a lot of side by side. 
    案内図を読んでみると、コミュニティサイクルの実証実験と言う事らしいです。
    It was written that it is doing a demonstration of community cycle(bike) to guide map. 
    使っている人いるのかなーと、歩いていくと…
    Are there any people who are using this rental bike? 
    回収された自転車が戻ってきました。ほほう、こうやって戻って来るのね。
    It came  bike recovered is loaded on the truck.
    今度、暇があったら使ってみようかな?
    I want to use at the next opportunity.

    さて、我が街、松本にも似たような物はありますよ。
    By the way, there is a system of a rental bike also Matsumoto where I live
    規模は小さいけど、その分、気軽に借りる事が出来るし、なんと、
    Due to the small scale is the system, you can use it willingly. And,

    無料です!
    It's free! 


    松本に来る機会があれば、是非使ってみてくださいね。
    So if you come in Matsumoto, I recommend that you make use of it. 
    Evernote から送信

    2014年1月4日土曜日

    Raspberry Pi (9) LCD表示 1

    LCD表示 1 (SPI接続でQVGA LCDパネル表示)


    最初に

    AitendoからSPI制御のQVGA LCDパネルM-TM022-SPIを入手したので接続してみました。
    このLCDはSPIで接続できるので、簡単な配線だけで表示が可能です。
    またドライバICはILI9340という物ですが、この辺のドライバICはどれも似たような コマンド体系を持っているようなので、他のドライバの資料を参考にする事が出来ます。
    参考:LCD&タッチセンサ活用の素

    実験を行う前にbcm2835ライブラリのインストールSPIが使える準備をしておいてください。

    材料

    1. 2.2インチ液晶モジュール(240x320/SPI)[M-TM022-SPI]
    2. 抵抗(220Ω位。私は手元に470Ωしかなかったので、それを代用)
    3. 26pinの2列ソケット。出来れば10pinの1列ソケットも。

    配線

    1. 配線は簡単です。下記のソースリストを参考にしてください。

    プログラム

    1. SPIの初期化

      SPIの初期化はbcm2835ライブラリのサンプルプログラムをそのままお借りしました。
      SPI access
      SPIのモードは以下の様にセッティングしました。

      1. MSBFIRST
      2. MODE0
      3. Clock divide=8
      4. CS=Lo

    2. パネルの初期化

      パネルの初期化はAitendoのサンプルプログラムを流用しました。
      デモコード(8051)

    3. RGB565フォーマット変換

      このLCDの1画素あたりの色情報は16ビットであり、そのフォーマットはRGB565などと呼ばれています。
      RGB565フォーマットとは赤5ビット、緑6ビット、青5ビットで色を表す仕組みで、データの並びは"RRRRRGGG GGGBBBBB"の様になっており、 2バイトで色を表現できるのでプログラムが楽になります。
      但し2バイトだと色数が限られるので、現在のパソコンはは24ビット(8bit*3色)で表現する事が多い。両者を変換するルーチンを用意しておくと便利です。
      詳しくは、16 ビット RGB の操作 - MSDN - Microsoft を見てください。

    4. ILI9340のコマンド

      コマンド発行の仕方
      ILI9340はコマンドを発行し、直後にデータを送信する。と言う形式で操作します。
      D/CラインをLoにしてからデータ送信するとコマンドと解釈されます。
      D/CラインをHighにしてからデータ送信するとデータと解釈されます。
      コマンドは非常に沢山ありますが、基本的に下記の三つのコマンドだけで描画が可能です。

      1. xアドレス(座標)セットコマンド (0x2A)
        操作したいx座標をセットするには、コマンド0x2Aを発行し、その後にスタートアドレス2バイト、エンドアドレス2バイトを送信します。
        1画素だけ操作したい場合はスタートアドレス=エンドアドレスとします。
      2. yアドレス(座標)セットコマンド (0x2B)
        同様に操作したいy座標をセットするには、コマンド0x2Bを発行し、その後にスタートアドレス2バイト、エンドアドレス2バイトを送信します。
        1画素だけ操作したい場合はスタートアドレス=エンドアドレスとします。
      3. メモリ書き込みコマンド (0x2C)
        0x2Cコマンドを発行し、その後にデータ2バイト(RGB565)を送信すると上記のアドレス(1画素)にデータ(色)が書き込まれます。
        更に連続してデータを送信するとエンドアドレスまで順々にデータが書き込まれます。この機能を使えば、矩形の塗りつぶし(FILL)を高速に実行できます。
    5. 直線の描画

      ドライバ標準のコマンドだけでは、点か矩形しか描画が出来ません。任意の直線を引くには計算が必要です。
      どこかから2D描画ルーチンを拝借するのが一番手っ取り早いのですが、お正月で暇なので、復習を兼ねて直線描画ルーチンを書いてみます。 (これを車輪の再発明と言います)
       参考にしたのは、1982年発行 ポケットコンピューティング―情報化時代の知的ツール (アスキーブックス) [単行本]乾 謙一 (著)  名機PC-1500の活用本、何十年ぶりに開きました。

      ブレゼンハムのアルゴリズムが元になっているらしいですが、整数演算だけで直線描画が出来るので、非常に高速です。
      動きを簡単に説明すると、座標をx方向に移動しながら、傾きの余りが残っていたらY座標を1ドット上に上げる。と言う方法で直線を描きます。  傾きが45度以上になる時は、移動方向を入れ替えます。

    完成したプログラム

    // LCD test program 20130103 by ImageWriter
    // ili9340.c
    // This is M-TM022-SPI(controled by ILI9340) LCD-panel test program on Raspberry Pi.
    // Used by bcm2835 library.(Mike McCauley)
    // 
    // After installing bcm2835, you can build this
    // with something like:
    // gcc -o spi ili9340.c -l bcm2835
    // sudo ./ili9340
    //
    //  [Pin connection]
    //  M-TM022-SPI     Rpi(pin)
    //  ------------------------
    //  MISO------------MISO(21)
    //  LED---220ohm----3.3V( 1)
    //  SCK-------------SCLK(23)
    //  MOSI------------MOSI(19)
    //  D/C-------------IO17(11)  LOW = 0 = COMMAND
    //  RES-------------IO18(12)  LOW = 0 = RESET
    //  CS--------------CS0 (24)  LOW = 0 = Chip Select
    //  GND-------------0V  ( 6)
    //  VCC-------------3.3V( 1)
    //  ------------------------
    //  
    //  [SPI settings (spi_init())]
    // ORDER MSB First
    // MODE Mode0
    // Divide 8
    // CS  CS0
    // CS_POL LOW
    //
    //
    
    #include  < bcm2835.h >
    #include  < stdio.h >
    #include  < stdlib.h >
    
    #define D_C  17  // GPIO17=D/C
    #define RES_ 18  // GPIO18=RESET
    
    int a,data;
    
    // SPI interfase initialize
    // MSB,mode0,clock=8,cs0=low
    void spi_init(void){
     bcm2835_spi_begin();
     bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // The default MSBFIRST
     bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // The default MODE0
     bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_8); // The default 65536
     bcm2835_spi_chipSelect(BCM2835_SPI_CS0); // The default CS0
     bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // the default LOW
     // Send a byte to the slave and simultaneously read a byte back from the slave
     // If you tie MISO to MOSI, you should read back what was sent
    }
    
    // SPI setup
    void spi_reset(void){
     bcm2835_gpio_fsel(D_C,BCM2835_GPIO_FSEL_OUTP); // D/C
     bcm2835_gpio_fsel(RES_,BCM2835_GPIO_FSEL_OUTP); // Reset
     bcm2835_gpio_write(D_C, HIGH);   // D/C = H
    
     bcm2835_gpio_write(RES_, LOW);   // Reset
     bcm2835_delay(100);
     bcm2835_gpio_write(RES_, HIGH);   // Reset off
     bcm2835_delay(100); 
    }
    
    // SPI Write Command
    // D/C=LOW then,write command(8bit)
    void write_command(unsigned char c){
     int data;
     bcm2835_gpio_write(D_C,LOW);
     data = bcm2835_spi_transfer(c);
     bcm2835_gpio_write(D_C,HIGH);
    // printf("COMMAND: %02X\n", c);
    // printf("DATA: %02X\n", data);
    }
    
    // SPI Write Data
    // D/C=HIGH then,write data(8bit)
    void write_data(unsigned char c){
     int data;
     bcm2835_gpio_write(D_C,HIGH);
     data = bcm2835_spi_transfer(c);
    }
    
    // ILI9340 initialize
    //  see M-TM022-SPI demo code(8051)
    void lcd_initial(void){
      write_command(0xCB);  
      write_data(0x39); 
      write_data(0x2C); 
      write_data(0x00); 
      write_data(0x34); 
      write_data(0x02); 
    
      write_command(0xCF);  
      write_data(0x00); 
      write_data(0XC1); 
      write_data(0X30); 
    
      write_command(0xE8);  
      write_data(0x85); 
      write_data(0x00); 
      write_data(0x78); 
    
      write_command(0xEA);  
      write_data(0x00); 
      write_data(0x00); 
    
      write_command(0xED);  
      write_data(0x64); 
      write_data(0x03); 
      write_data(0X12); 
      write_data(0X81); 
    
      write_command(0xF7);  
      write_data(0x20); 
    
      write_command(0xC0);    //Power control 
      write_data(0x23);   //VRH[5:0] 
    
      write_command(0xC1);    //Power control 
      write_data(0x10);   //SAP[2:0];BT[3:0] 
    
      write_command(0xC5);    //VCM control 
      write_data(0x3e); //
      write_data(0x28); 
    
      write_command(0xC7);    //VCM control2 
      write_data(0x86);  //--
    
      write_command(0x36);    // Memory Access Control 
    
      //
      //0x48 0x68
      //0x28 0xE8
    
      write_data(0x48); //
    
      write_command(0x3A);    
      write_data(0x55); 
    
      write_command(0xB1);    
      write_data(0x00);  
      write_data(0x18); 
    
      write_command(0xB6);    // Display Function Control 
      write_data(0x08); 
      write_data(0x82);
      write_data(0x27);  
    
      write_command(0xF2);    // 3Gamma Function Disable 
      write_data(0x00); 
    
      write_command(0x26);    //Gamma curve selected 
      write_data(0x01); 
    
      write_command(0xE0);    //Set Gamma 
      write_data(0x0F); 
      write_data(0x31); 
      write_data(0x2B); 
      write_data(0x0C); 
      write_data(0x0E); 
      write_data(0x08); 
      write_data(0x4E); 
      write_data(0xF1); 
      write_data(0x37); 
      write_data(0x07); 
      write_data(0x10); 
      write_data(0x03); 
      write_data(0x0E); 
      write_data(0x09); 
      write_data(0x00); 
    
      write_command(0XE1);    //Set Gamma 
      write_data(0x00); 
      write_data(0x0E); 
      write_data(0x14); 
      write_data(0x03); 
      write_data(0x11); 
      write_data(0x07); 
      write_data(0x31); 
      write_data(0xC1); 
      write_data(0x48); 
      write_data(0x08); 
      write_data(0x0F); 
      write_data(0x0C); 
      write_data(0x31); 
      write_data(0x36); 
      write_data(0x0F); 
    
      write_command(0x11);    //Exit Sleep 
      bcm2835_delay(120); 
      
      write_command(0x29);    //Display on 
      write_command(0x2c); 
    }
    
    // RGB565 conversion
    // RGB565 is R(5)+G(6)+B(5)=16bit color format.
    // Bit image "RRRRRGGGGGGBBBBB"
    // 
    unsigned int rgb565_conv(unsigned int r,unsigned int g,unsigned int b){
     unsigned int RR,GG,BB;
     RR = (r * 31 / 255) << 11;
     GG = (g * 63 / 255) << 5;
     BB = (b * 31 / 255);
     return(RR | GG | BB);
    }
    
    // Write data word
    //
    unsigned int write_data_w(unsigned int w){
     unsigned char hi,lo;
     hi = (char) (w >> 8);
     lo = (char) (w & 0x00FF);
     write_data(hi);
     write_data(lo);
    }
    
    // Addres set (1point)
    //
    void addset(unsigned int x, unsigned int y){
     write_command(0x2A); // set column(x) address
     write_data_w(x);
     write_data_w(x);
     write_command(0x2B); // set Page(y) address
     write_data_w(y);
     write_data_w(y);
     write_command(0x2C); // Memory Write
    }
    
    // Addres set 2 (rectangle)
    //
    void addset2(unsigned int x1, unsigned int y1,
          unsigned int x2, unsigned int y2 ){
     write_command(0x2A); // set column(x) address
     write_data_w(x1); // set start x
     write_data_w(x2); // set end x
     write_command(0x2B); // set Page(y) address
     write_data_w(y1); // set start y
     write_data_w(y2); // set end y
     write_command(0x2C); // Memory Write
    }
    
    // Mem read
    int mem_read(unsigned int x0, unsigned int y0){
     int data;
     write_command(0x2A); // set column(x) address
     write_data_w(x0);
     write_data_w(x0);
     write_command(0x2B); // set Page(y) address
     write_data_w(y0);
     write_data_w(y0);
     write_command(0x2E);
     bcm2835_gpio_write(D_C,HIGH);
     data = bcm2835_spi_transfer(0x00); // dummy data
     data = bcm2835_spi_transfer(0x00);
     printf("%02X",data);
     data = bcm2835_spi_transfer(0x00);
     printf("%02X:",data);
    }
    
    void dot_plot(unsigned int x,unsigned int y){
     addset(x,y);
     write_data_w(rgb565_conv(255,255,255)); //plot
    }
    
    
    // line plot
    //
    //                          /---(x1,y1) -
    //                     /---/            |
    //                /---/                 dy
    //     (x0,y0)---/                      |
    //        |<--------- dx --------->|    -
    //        |<--- SS --->|
    
    void line_plot(int x0,int y0,int x1,int y1){
     int  dx,dy,  // difference x,y
      SS,  // rest
      XX,YY,  // plot point
      temp,  
      ADDX,ADDY; // Addition X,Y
    
     if(x0>240 | y0>320 | x1>240 | y0>320) return;
    
     dx = x1-x0;  // dx
     dy = y1-y0;  // dy
     if(dx>0){  // plot direction x
      ADDX=  1;
     } else if(dx<0){
      ADDX= -1;
     } else {
      ADDX=  0;
     }
     if(dy>=0){  // plot direction y
      ADDY=  1;
     } else if(dy<0){
      ADDY= -1;
     } else {
      ADDY=  0;
     }
     if(abs(dx)>=abs(dy)){ // if angle < 45deg
      SS = abs(dx/2);
      XX = x0;
      YY = y0;
    
      while (XX != x1+ADDX){
       //printf("XX,YY:%d,%d\n",XX,YY);
       addset(XX,YY);
       write_data_w(rgb565_conv(255,255,255)); //plot
       SS = SS - abs(dy);
       if(SS > 0){
        XX = XX + ADDX;
        YY = YY;
       } else {
        XX = XX + ADDX;
        YY = YY + ADDY;
        SS = SS + abs(dx);
       }
      }
     } else {
      SS = abs(dx/2);
      XX = x0;
      YY = y0;
    
      while (YY != y1+ADDY){
       //printf("XX,YY:%d,%d\n",XX,YY);
       addset(XX,YY);
       write_data_w(rgb565_conv(255,255,255)); //plot
       SS = SS - abs(dx);
       if(SS > 0){
        XX = XX;
        YY = YY + ADDY;
       } else {
        XX = XX + ADDX;
        YY = YY + ADDY;
        SS = SS + abs(dy);
       }
      }
    
     }
    
    }
     
    int main(int argc, char **argv)
    {
     if (!bcm2835_init())
      return 1;
     
     spi_init();
     spi_reset();
     lcd_initial(); 
    
     int i,j; 
    
     // color bar
     for(i=0;i<240;i++){   // x = 0 to 239
      for(j=0;j<320;j++){  // y = 0 to 319 
       //write_data(rand());
       //write_data(rand());
       if(j<106){
        addset(i,j);
        write_data_w(rgb565_conv(255,0,0)); //red
       } else if(j<212) {
        addset(i,j);
        write_data_w(rgb565_conv(0,255,0)); //green
       } else { 
        addset(i,j);
        write_data_w(rgb565_conv(0,0,255)); //blue
       }
      }
     }
    
     // rectangle fill
     addset2(200,200,200+30,200+30); // x1,y1,x2,y2
     for(i=0;i<30*30;i++){
      write_data_w(rgb565_conv(64,128,32)); // fill 
     }
     
     // line plot(radial)
     line_plot(100,100, 50, 80);
     line_plot(100,100, 50,120);
     line_plot(100,100,150, 80);
     line_plot(100,100,150,120);
    
     line_plot(100,100, 80, 50);
     line_plot(100,100,120, 50);
     line_plot(100,100, 80,150);
     line_plot(100,100,120,150);
     
     line_plot(100,100, 62, 62);
     line_plot(100,100, 62,138);
     line_plot(100,100,138, 62);
     line_plot(100,100,138,138);
    
     line_plot(100,100,100, 48);
     line_plot(100,100,100,152);
     line_plot(100,100,152,100);
     line_plot(100,100, 48,100);
     
     // line_plot(rectangle)
     line_plot(10,10,10,50);
     line_plot(10,50,50,50);
     line_plot(50,50,50,10);
     line_plot(50,10,10,10);
    
     bcm2835_delay(1000);
    
     // line_plot(random)
     int x0,y0,x1,y1;
     for(i=0;i<50;i++){
      x0=(char)rand();
      y0=((char)rand()*2);
      x1=(char)rand();
      y1=((char)rand()*2);
      line_plot(x0,y0,x1,y1);
    //  printf("%d,%d,%d,%d\n",x0,y0,x1,y1);
     }
    
     //for(i=0;i<240;i++){
     // for(j=0;j<320;j++){
     //  //dot_plot(i,j);
     //  //printf("%d:%d:",i,j);
     //  mem_read(i,j);
     // }
     //}
     //mem_read(10,10);
    
     bcm2835_spi_end();
     bcm2835_close();
     return 0;
    }
    

    最初に3色のカラーバーを表示し、その後、放射状の線の描画、矩形のフィルを行った後、ランダムに直線を描きます。