- 追加された行はこの色です。
- 削除された行はこの色です。
*[[キャラクタLCDをアクセス]] [#m5789035]
**はじめに [#e7e50907]
>
>Raspberry Pi 3でCentOS7からのキャラクタLCDへのアクセス方法をまとめました。~
過去の資産(秋月のLCD)が何個jかありますので、これらのアクセスについて記します。
<
**HD44780互換IC系 [#u0dd2208]
***概要 [#l63c5a03]
>
>パラレルバスインタフェースといえばこの系統が主流ですね。往年の68系バスに接続するインタフェース仕様です。~
8ビット以外に4ビットでのアクセスが可能ですが、どうしてもData(4)+E+R/W*RSで最低、7本のインタフェースが必要になります。
#ref(SC1602BSLB.jpg,around,zoom)
#ref(sc1602bslb_pin_assign.jpg,zoom)
<
***基本方針 [#cd5f269c]
>
>ピン数の節約のため、4bitモードででアクセスし必要なソフトはCで作成することにします。
<
***ハードウェア [#m86d0dca]
-ピンアサイン
>
>まず、ピンの割り当てですが、他の機能と併用されていないピンを使用することにします。~
電源はRaspberryPiの3.3Vを使用します。PINのラッチアップ等を避けるため、同一電源とします。
|>|Raspberry Pi| |>|LCD |h
|Signal|Pin#|BGCOLOR(#663300): |Signal|Pin#|
|3V3|01,17|BGCOLOR(#663300): |3V3|01|
|GND|34,39|BGCOLOR(#663300): |GND|02|
| | |BGCOLOR(#663300): |VO(contrast)|03|
|GPIO 20|38|BGCOLOR(#663300): |E|06|
|GPIO 21|40|BGCOLOR(#663300): |R/_W|05|
|GPIO 22|15|BGCOLOR(#663300): |RS|04|
|GPIO 23|16|BGCOLOR(#663300): |D4|11|
|GPIO 24|18|BGCOLOR(#663300): |D5|12|
|GPIO 25|22|BGCOLOR(#663300): |D6|13|
|GPIO 26|37|BGCOLOR(#663300): |D7|14|
|GPIO 21|40|BGCOLOR(#663300): |E|06|
|GPIO 22|15|BGCOLOR(#663300): |R/_W|05|
|GPIO 23|16|BGCOLOR(#663300): |RS|04|
|GPIO 24|18|BGCOLOR(#663300): |D4|11|
|GPIO 25|22|BGCOLOR(#663300): |D5|12|
|GPIO 26|37|BGCOLOR(#663300): |D6|13|
|GPIO 27|13|BGCOLOR(#663300): |D7|14|
<
>
-PullUp/Pulldown
<
>
>信号の衝突を避けるため、R/_W、EはPulldownを行います。~
また、コントラスト調整(VO)は20kΩのVRにより電位を調整するようにします。
<
***ソフトウェア [#j396b47f]
-概要
>
>Read/Write用の関数を作成してアクセスすることになります。~
たとえば
>>
>>void lcd_init( void );~
void lcd_write( int mode, int data );~
int lcd_read( int mode, init data );
<<
>基本として、各種のコマンドを作成することとします。上記の関数を利用して
>>
>>void lcd_set_position( int x, int y );~
void lcd_put_char( int char );~
void lcd_clear( void );~
void lcd_print(char *str );
void lcd_print( int line, char *str );
<<
>位を用意すれば良いでしょう。
>位を用意すれば良いでしょう。~
実際はリード系のコマンドは不要と思いますが。
<
***GPIOへのアクセステスト [#q64a032a]
-実装
>
>では実際にアクセスできるかテストします。
# echo 21 > /sys/class/gpio/export
# ls /sys/class/gpio/
export gpio21 gpiochip0 gpiochip100 unexport
# ls /sys/class/gpio/gpio21/
active_low device direction edge power subsystem uevent value
# echo out > /sys/class/gpio/gpio21/direction
# echo 1 > /sys/class/gpio/gpio21/value
# echo 0 > /sys/class/gpio/gpio21/value
# echo 21 > /sys/class/gpio/unexport
# ls /sys/class/gpio/
export gpiochip0 gpiochip100 unexport
#
>テストのつもりでコーディングします。
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HD44780/SC1602 LCDモジュール(16 x 2) 秋月版 制御TP
// このTPでは、2行表示に対して、これぞれの行に文字を表示します。
// 基本的に16文字固定表示でスクロールはしません。カーソルも表示しません。
//
// コンパイル方法
// gcc -o lcd_test lcd_test.c -l bcm2835
//
// copyright (c) 2016 Kazuhiro WATANABE All right reserved.
// mailto:jj1req@ca.mbn.or.jp
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <bcm2835.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// キャラクタ液晶ディスプレーへの接続
#define LCD_E 21
#define LCD_R_W 22
#define LCD_RS 23
#define LCD_DB4 24
#define LCD_DB5 25
#define LCD_DB6 26
#define LCD_DB7 27
//******************************************************************************
//* LCDモジュールに対してストローブをかけます(E端子ストローブ)
//*
//* Function Name
//* void lcd_strobe( void )
//* Arguments
//* none
//* Return
//* none
//*
//******************************************************************************
void lcd_strobe( void )
{
bcm2835_delayMicroseconds( 1LL );
bcm2835_gpio_write( LCD_E, HIGH );
bcm2835_delayMicroseconds( 1LL );
bcm2835_gpio_write( LCD_E, LOW );
}
//******************************************************************************
//* LCDモジュールに対して表示のクリアを行います
//*
//* Function Name
//* void lcd_clear( void )
//* Arguments
//* none
//* Return
//* none
//*
//******************************************************************************
void lcd_clear( void )
{
// Display OFF 0000 1000
bcm2835_gpio_write( LCD_DB7, LOW );
bcm2835_gpio_write( LCD_DB6, LOW );
bcm2835_gpio_write( LCD_DB5, LOW );
bcm2835_gpio_write( LCD_DB4, LOW );
bcm2835_gpio_write( LCD_RS, LOW );
bcm2835_gpio_write( LCD_R_W, LOW );
lcd_strobe();
bcm2835_gpio_write( LCD_DB7, HIGH );
lcd_strobe();
bcm2835_delayMicroseconds( 40LL );
// Display clear 0000 0001
bcm2835_gpio_write( LCD_DB7, LOW );
lcd_strobe();
bcm2835_gpio_write( LCD_DB4, HIGH );
lcd_strobe();
// Entry Mode set 0000 0110
bcm2835_gpio_write( LCD_DB4, LOW );
lcd_strobe();
bcm2835_gpio_write( LCD_DB6, HIGH );
bcm2835_gpio_write( LCD_DB5, HIGH );
lcd_strobe();
bcm2835_delayMicroseconds( 40LL );
}
//******************************************************************************
//* LCDモジュールに対して初期化を行います
//*
//* Function Name
//* void lcd_init( void )
//* Arguments
//* none
//* Return
//* none
//*
//******************************************************************************
void lcd_init( void )
{
// ライブラリ初期化
if( !bcm2835_init() )
{
printf( "bcm2835 library initialize error!!\n" );
exit(1);
}
// I/O ピンの初期化
bcm2835_gpio_fsel( LCD_DB4, BCM2835_GPIO_FSEL_INPT );
bcm2835_gpio_set_pud( LCD_DB4, BCM2835_GPIO_PUD_UP );
bcm2835_gpio_fsel( LCD_DB5, BCM2835_GPIO_FSEL_INPT );
bcm2835_gpio_set_pud( LCD_DB5, BCM2835_GPIO_PUD_UP );
bcm2835_gpio_fsel( LCD_DB6, BCM2835_GPIO_FSEL_INPT );
bcm2835_gpio_set_pud( LCD_DB6, BCM2835_GPIO_PUD_UP );
bcm2835_gpio_fsel( LCD_DB7, BCM2835_GPIO_FSEL_INPT );
bcm2835_gpio_set_pud( LCD_DB7, BCM2835_GPIO_PUD_UP );
bcm2835_gpio_fsel( LCD_RS, BCM2835_GPIO_FSEL_OUTP );
bcm2835_gpio_set_pud( LCD_RS, BCM2835_GPIO_PUD_DOWN );
bcm2835_gpio_write( LCD_RS, LOW );
bcm2835_gpio_fsel( LCD_R_W, BCM2835_GPIO_FSEL_OUTP );
bcm2835_gpio_set_pud( LCD_R_W, BCM2835_GPIO_PUD_DOWN );
bcm2835_gpio_write( LCD_R_W, LOW );
bcm2835_gpio_fsel( LCD_E, BCM2835_GPIO_FSEL_OUTP );
bcm2835_gpio_set_pud( LCD_E, BCM2835_GPIO_PUD_DOWN );
bcm2835_gpio_write( LCD_E, LOW );
// 初期化フェーズ1
bcm2835_gpio_write( LCD_DB7, LOW );
bcm2835_gpio_write( LCD_DB6, LOW );
bcm2835_gpio_write( LCD_DB5, HIGH );
bcm2835_gpio_write( LCD_DB4, HIGH );
bcm2835_gpio_write( LCD_E, HIGH );
lcd_strobe();
bcm2835_delay( 5 );
// 初期化フェーズ2
lcd_strobe();
bcm2835_delayMicroseconds( 100LL );
// 初期化フェーズ3
lcd_strobe();
// 初期化フェーズ4
bcm2835_gpio_write( LCD_DB4, LOW );
lcd_strobe();
// ファンクション設定( 2 Line 5×10 dots)
lcd_strobe();
bcm2835_gpio_write( LCD_DB7, HIGH );
bcm2835_gpio_write( LCD_DB6, HIGH );
lcd_strobe();
bcm2835_delayMicroseconds( 40LL );
// 通常のクリア処理
lcd_clear();
}
//******************************************************************************
//* LCDモジュールにデータ/コマンドの書き込みを行います
//*
//* Function Name
//* void lcd_write( int rs, unsigned char data )
//* Arguments
//* int rs register select 0:command, 1: data
//* unsigned char data byte data
//* Return
//* none
//*
//******************************************************************************
void lcd_write( int rs, unsigned char data )
{
bcm2835_gpio_write( LCD_R_W, LOW );
bcm2835_gpio_write( LCD_RS, rs );
bcm2835_gpio_write( LCD_DB7, (data >> 7) & 0x01 );
bcm2835_gpio_write( LCD_DB6, (data >> 6) & 0x01 );
bcm2835_gpio_write( LCD_DB5, (data >> 5) & 0x01 );
bcm2835_gpio_write( LCD_DB4, (data >> 4) & 0x01 );
lcd_strobe();
bcm2835_gpio_write( LCD_DB7, (data >> 3) & 0x01 );
bcm2835_gpio_write( LCD_DB6, (data >> 2) & 0x01 );
bcm2835_gpio_write( LCD_DB5, (data >> 1) & 0x01 );
bcm2835_gpio_write( LCD_DB4, data & 0x01 );
lcd_strobe();
bcm2835_delayMicroseconds( 40LL );
}
//******************************************************************************
//* LCDモジュールに文字列を表示します。
//*
//* Function Name
//* void lcd_print( int line, char *str )
//* Arguments
//* int line target position 0:first line, 1:second line
//* char *str string data
//* Return
//* none
//*
//******************************************************************************
void lcd_print( int line, char *str )
{
int i;
int data;
data = (line * 0x40) || 0x80;
lcd_write( 0, data );
for( i=0; i<16; i++)
{
lcd_write( 1, 0x20 );
}
data = (line * 0x40) || 0x80;
lcd_write( 0, data );
for( i=0; i<strlen(str); i++ )
{
lcd_write( 1, (unsigned char)str[i] );
}
}
int main(int argc, char **argv)
{
lcd_init();
lcd_print( 0, "test123" );
lcd_print( 1, "########" );
return( 0 );
}
<
>
>まずは、GPIOには簡単にアクセスできる方法は用意されていました。
<
**その他のアクセス方法 [#ef3f172c]
>
>では、C等でGPIO/IIC/SPIなどのインタフェースはどうすればいいのかを調べました。~
Rasbianでは、ドライバーが用意されているようですが、CentOS7は上記の状況です。~
検索してみたところ、「BCM 2835」という、CのRaspberry Pi 用のIOライブラリがありました。~
早速ダウンロードしてコードを見ると、IOアドレス空間を直接アクセスしています。~
ぎょっとしましたが、Linux Kernel 2.6.23-rc1からUIOがマージされて、このようなことが可能になったようです。~
コードでは、/dev/memをmmapし、メモリ空間をアクセスしています。また、DeviceTreeにも対応しています。~
早速、CentOSでも調べてみます。
# ll /dev/mem
crw-r----- 1 root kmem 1, 1 1月 1 1970 /dev/mem
#
>ありました。これでイケルようです。
<
**[[BCM 2835>http://www.airspayce.com/mikem/bcm2835/]] [#e778179f]
***概要 [#d8175bcb]
>
>Raspberry Pi用のCライブラリで、
> This is a C library for Raspberry Pi (RPi). ~
It provides access to GPIO and other IO functions on the Broadcom BCM 2835 chip, ~
allowing access to the GPIO pins on the 26 pin IDE plug on the RPi board ~
so you can control and interface with various external devices.~
It provides functions for reading digital inputs and setting digital outputs, ~
using SPI and I2C, and for accessing the system timers. ~
Pin event detection is supported by polling (interrupts are not supported).~
It is C++ compatible, and installs as a header file and non-shared library ~
on any Linux-based distro (but clearly is no use except on Raspberry Pi ~
or another board with BCM 2835).
>とありますので、UART、割り込み以外は、おおよそ何でもできそうです。
<
***ライブラリのビルド [#df5725b4]
>
>早速ビルドしてみます。
# cd /opt/
# mkdir bcm2835
# cd bcm2835/
# curl http://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz -O
# tar zxvf bcm2835-1.50.tar.gz
# ls
bcm2835-1.50 bcm2835-1.50.tar.gz
# cd bcm2835-1.50
# ./configure
# make
# make install
<
>
>以下のファイルがインストールされます。
<
>
>>
|種別|ファイル|h
|Lib|/usr/local/lib/libbcm2835.a|
|Header|/usr/local/include/bcm2835.h|
|Document|?|
<<
<
>
>>
>>>
>>>
>>>
>>>Kernelをアップデートするたびにmakeしなくてよさそうなのがありがたい。
<<<
<<
<
***テスト [#re19c440]
>
>サンプルのLEDチカチカがありますので、テストします。~
LEDはGPIO-17(コネクタP1の11)に接続し、1秒間隔で点滅(ON:500ms、OFF:500ms)します。
# cd examples/
# cd blink/
# gcc blink.c -o blink_led -l rt -l bcm2835
# ./blink_led
<
>
>※-l rt は[[real-time extensions>http://devlib.symbian.slions.net/belle/GUID-E21287EF-7211-590B-A1E3-E0B37069FCB2.html]]です。(RTカーネルではないので、意味ないかもしれませんが)
<
お疲れ様でした。