2019-12-22 「Raspberry pi 3A+ HDDブート」
Raspberry pi 3B+, 4Bは箱に裸で入っていたのに、静電気防止フィルムの袋に入っていた。
製造するところが違うのかな。
Easpberry Pi 3A+ にUSB HDDを差し込んで、キーボード、マウスなしで使ってみる。
WD Elements SEの1TBポータブルHDDとRSコンポーネンツ5.1V 2.5A ACアダプタを使っても雷マークがでなかった。
最初は、
(1) USBブートできるようにする。(1回やればよい)
・OSイメージをSDカードに書き込む。
・一度OSを立ち上げる。
・OSセットアップはしなくてとよい。
sudo nano /boot/config.txt
---
program_usb_boot_mode=1
---追加
sudo reboot
vcgencmd otp_dump
--
17:3020000a
--確認
次にUSBシリアルケーブルを用意してRASPI-3A+のUARTに接続する。
(2) USB HDDにOSイメージ 2019-09-26-raspbian-buster.img をコピーする。
(3) コピー直後に、VFAT /bootパーティションのconfig.txtファイルに以下を追加。
sudo nano config.txt
---
enable_uart=1
# hdmi_group,hdmi_modeはVNC接続時の画面の大きさ
hdmi_group=2
hdmi_mode=85
---追加
sudo nano cmdline.txt
---
plymouth.ignore-serial-consoles
---長い1行の最後にある、これを削除するとブート時のメッセージがシリアルコンソールに表示される
(4) 別PC(Windows,RasPiどちらでも)でUSBシリアル端末を開く。
115200BPS パリティなし、ハードウェアハンドシェークなし
sudo apt install uc
uc -f -s 115200 -l /dev/ttyUSB0
で通信可能にする。
(5) RasPi 3A+にUSB HDDを、UARTにUSBシリアルケーブルを接続する。
ディスプレイはあってもなくてもよい。
ACアダプタを接続する。
(6) しばらくして、USBシリアルケーブル接続された別PCの端末に"login :"が表示されたら、
最初のOSセットアップが終わってリブートされている。
ログインユーザ:pi , パスワード:raspberryでログインする。
(7) デスクトップに出るOSインストールのダイアログは出ているが、そちらではできないのでコマンドで手動設定する。
sudo raspi-config
・Piパスワード変更
・ホスト名、Wifi設定(Wifi国設定はこのとき)
・ロケール、タイムゾーン、キーボード(接続しないのでしなくてもいいい)、Wifi国設定
・インターフェース SSH, VNCをONにする。(SerialはすでにON)
リブートする前に
固定IPアドレス設定するか、IPアドレスを確認すること。
sudo reboot
USBシリアルを外す。
(8) 別PCより、VNC接続する。
OSインストールのダイアログは出たままなので設定か、キャンセルする。
キーボード、マウスはUSBコネクタは塞がるのでBluetooth接続で使える。
(シリアルコンソールはOS設定のみでの使用なので)
ディスプレイ接続はありなしどちらでもよい。
(9) OSコンパイル
ーーーー
#!/bin/sh
# Usage: sudo ./compile.sh
#
apt install -y bc bison flex libssl-dev make
cd /usr/src
clone --depth=1 https://github.com/raspberrypi/linux
cd linux
# raspberry pi 1, Zero, Zero W
#KERNEL=kernel
#make bcmrpi_defconfig
# raspberry pi 2,3,3B+
KERNEL=kernel7
make bcm2709_defconfig
# raspberry pi 4B
#sudo apt-get install bc
#KERNEL=kernel7l
#make bcm2711_defconfig
date >> /usr/src/cmpl-log.txt
make -j4 zImage modules dtbs
date >> /usr/src/cmpl-log.txt
ーーーー
1時間45分
2019-12-20 「Device Driverを作る」
久しぶりにGOPIOキャラクタデバイスドライバを作ってみた。
$ nano gpio00.c
---
#include <stdio.h>
#include <bcm_host.h>
int main(int argc, char* argv[]) {
printf("0x%08X\n", bcm_host_get_peripheral_address());
return 0;
}
----
$ cc gpio00.c -I/opt/vc/include -L/opt/vc/lib -lbcm_host -o gpio00
$ ./gpio00
でメモリアドレスを確認する。
参考:「ARMコンピュータ ラズベリー・パイでI/O」第8章 自作LinuxドライバでI/O制御を簡単・確実に! CQ出版
インタフェース 2002.2月号
BCM2835-ARM-Peripherals.pdf
$ sudo apt install raspberrypi-kernel-headers
/usr/src/linux-headers-4.19.75+, ~-4.19.75-V7+, ~4.19.75-V7l+ができる
uname -r で表示される4.19.75+があること。
sudo rpi-updateした後ではこれでは作れないので
sudo apt install --reinstall raspberrypi-bootloader raspberrypi-kernel
sudo reboot
で元に戻す。何回もrpi-updateしたら元に戻らないのでカーネルをソースからビルドする。
Raspberry pi 4BでSSDメモリ上でビルドすると50分くらいだった。(メモリのアクセススピードにより変わる)
3Bだと倍くらいの時間。
インストールしてから使う。
$ nano gpio_drv.h
---
/* gpio_drv.h */
#include <linux/ioctl.h>
struct io_info {
unsigned long adrs;
unsigned long data;
};
#define XXX_MAGIC '3'
#define XXX_MEM_READ_32 (_IOWR(XXX_MAGIC, 9, int))
#define XXX_MEM_WRITE_32 (_IOWR(XXX_MAGIC, 12, int))
#define BCM2835_PERI_BASE 0x3F000000 /* 4B = 0xFE000000 */
#define GPIO_BASE (BCM2835_PERI_BASE + 0x200000)
---
$ nano gpiodrv.c
---
#include <linux/init.h>
#include <linux/module.h>
#include <linux/major.h>
#include <linux/kernel.h> // printk ();
#include <linux/fs.h> // everything
#include <linux/errno.h> // error codes
#include <linux/types.h> // size_t
#include <linux/fcntl.h> // O_ACCMODE
#include <linux/uaccess.h> // copy_from/to_user
#include <linux/cdev.h> // cdev struct.
#include <asm/io.h>
#include "gpio_drv.h"
MODULE_LICENSE ("Dual MIT/GPL");
static int gpiodrv_init(void);
static void gpiodrv_exit(void);
int gpiodrv_open(struct inode *inode, struct file *filp);
int gpiodrv_release(struct inode *inode, struct file *filp);
ssize_t gpiodrv_read(struct file *filp, char *buf, size_t count, loff_t *fpos);
ssize_t gpiodrv_write(struct file *filp, const char *buf, size_t count, loff_t *fpos);
static long gpiodrv_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int gpiodrv_open(struct inode *inode, struct file *filp);
struct file_operations gpiodrv_fops = {
.owner= THIS_MODULE,
.read= gpiodrv_read,
.unlocked_ioctl= gpiodrv_ioctl,
.write= gpiodrv_write,
.open= gpiodrv_open,
.release= gpiodrv_release
};
static dev_t dev_id;
static struct cdev c_dev;
static void *iop;
static int gpiodrv_init(void)
{
int ret;
/* ---- initial driver module --- */
ret = alloc_chrdev_region( &dev_id,
0,
1,
"gpiodrv" // Module-name
);
if( ret < 0 ){
printk( KERN_WARNING "[gpiodrv] alloc_chrdev_region failed\n" );
return ret;
}
cdev_init( &c_dev, &gpiodrv_fops );
c_dev.owner = THIS_MODULE;
ret = cdev_add( &c_dev, dev_id, 1 );
if( ret < 0 ){
printk( KERN_WARNING "[gpiodrv] chrdev add failed\n" );
return ret;
}
/* ---- driver log --- */
printk( KERN_INFO "[gpiodrv] page_size : %ld, major : %d, minor : %d\n", PAGE_SIZE, MAJOR( dev_id ), MINOR( dev_id ) );
return(0);
}
static void gpiodrv_exit(void)
{
cdev_del( &c_dev );
unregister_chrdev_region( dev_id, 1 );
printk( KERN_INFO "[gpiodrv] ByeBye gpiodrv Driver!\n");
}
static long gpiodrv_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg) {
unsigned long io_page;
unsigned long io_pagesize = PAGE_SIZE;
struct io_info io;
printk( KERN_INFO "[gpiodrv] XXX_IO/CONTROL\n");
switch(cmd) {
case XXX_MEM_READ_32:
get_user(io.adrs,((long*)arg));
if( io.adrs > 0x100 ) return (-EINVAL);
io.adrs &= 0xFFFFFFFC;
io_page = GPIO_BASE;
iop = ioremap(io_page,PAGE_SIZE);
io.data = *((unsigned long*)(iop + io.adrs));
iounmap(iop);
put_user(io.adrs, (long *)arg);
put_user(io.data, ((long *)arg+1));
break;
case XXX_MEM_WRITE_32:
get_user(io.adrs,((long*)arg));
get_user(io.data,((long*)arg+1));
if( io.adrs > 0x100 ) return (-EINVAL);
io.adrs &= 0xFFFFFFFC;
io_page = GPIO_BASE;
iop = ioremap(io_page,PAGE_SIZE);
*((unsigned long *)(iop + io.adrs)) = io.data;
iounmap(iop);
put_user(io.adrs, (long *)arg);
break;
default:
return(-EINVAL);
}
return (0);
}
int gpiodrv_open(struct inode *inode, struct file *filp)
{
printk( KERN_INFO "[gpiodrv] gpiodrv Open\n");
return(0);
}
int gpiodrv_release(struct inode *inode, struct file *filp)
{
printk( KERN_INFO "[gpiodrv] gpiodrv Close\n");
return(0);
}
ssize_t gpiodrv_read(struct file *filp, char *buf, size_t count, loff_t *fpos)
{
int i;
unsigned long *pd;
int siz = count > 0x100 ? 0x100 : count;
siz &= 0xFFFC;
printk( KERN_INFO "[gpiodrv] gpiodrv Read\n");
iop = ioremap(GPIO_BASE,PAGE_SIZE);
pd = (unsigned long *)buf;
for (i = 0; (i*4) < siz; i++) {
put_user(*(((unsigned long*)iop) + i), ((long *)buf+i));
}
iounmap(iop);
return(i*4);
}
ssize_t gpiodrv_write(struct file *filp, const char *buf, size_t count, loff_t *fpos)
{
printk( KERN_INFO "[gpiodrv] write request\n");
return 0;
}
module_init(gpiodrv_init);
module_exit(gpiodrv_exit);
ーーー
$ nano Makefile
---
obj-m := gpiodrv.o
all:
make -C /usr/src/linux-headers-$(shell uname -r) M=${PWD} modules
clean:
make -C /usr/src/linux-headers-$(shell uname -r) M=${PWD} clean
---
ドライバコンパイル
$ make
$ nano install_drv.sh
---
#!/bin/sh
if [ -f gpiodrv.ko ]
then
DRV=`lsmod|grep gpiodrv`
if [ "$DRV" != "" ]; then
/sbin/rmmod gpiodrv
fi
/sbin/insmod gpiodrv.ko
rm -f /dev/gpiodrv0
major=$(cat /proc/devices|awk "\$2==\"gpiodrv\" {print \$1}")
mknod /dev/gpiodrv0 c $major 0
chmod 666 /dev/gpiodrv0
fi
#
# driverファイルはfull pathにして /etc/rc.local 追加
# if [ -f /yours/path/install_drv.sh ] ; then /yours/path/install_drv.sh ; fi
---
$ chmod +x install_drv.sh
ドライバロード
$ sudo ./install_drv.sh
$ nano led.c
---
/* led.c */
/* cc led.c -o led */
/* ./led */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <time.h>
#include "gpio_drv.h"
unsigned char b[4096];
void dump4(unsigned long *p, int b)
{
int n, o;
for(n = 0; (n*4) < b; n++ ) {
o = (n*4) & 0x0f;
if( n>0 && o == 0) {
printf("\n");
}
if( o == 0) {
printf("%08X: ", GPIO_BASE+(n*4));
}
printf("%08X ", *p++);
}
printf("\n");
}
int main()
{
int fd;
long n, r;
struct io_info ioc;
printf( "**start\n");
if (( fd = open("/dev/gpiodrv0", O_RDWR)) < 0 ){
printf( "Error device?\n");
return -1;
}
printf( "--Memory Dump\n");
ioc.adrs = 0x00000000;
ioc.data = 0xFFFFFFFF;
for( n = 0; n < 16; n++ ) {
r = ioctl(fd, XXX_MEM_READ_32, &ioc);
printf("Mem: 0x%08X = 0x%08X\n",GPIO_BASE+ioc.adrs, ioc.data);
ioc.adrs += 4;
}
printf( "--LED Blink\n");
ioc.adrs = 0x00000004;
ioc.data = 0xFFFFFFFF;
r = ioctl(fd, XXX_MEM_READ_32, &ioc); // read GPFSEL1
ioc.data &= 0xFFFFF1FF;
ioc.data |= 0x00000200; // Output GPIO13
r = ioctl(fd, XXX_MEM_WRITE_32, &ioc); // write GPFSEL1
ioc.adrs = 0x00000028;
ioc.data = 0x00002000; // set LOW GPIO13 pin
r = ioctl(fd, XXX_MEM_WRITE_32, &ioc); // write GPCLR0
ioc.data = 0x00002000;
for( n = 0; n < 10; n++ ) {
sleep(1);
if ( !(n & 1) )
ioc.adrs = 0x0000001C; // set HIGH GPIO13 pin
else
ioc.adrs = 0x00000028; // set LOW GPIO13 pin
r = ioctl(fd, XXX_MEM_WRITE_32, &ioc); // write GPSET0
printf("count: %d / 10 \n", n);
}
ioc.adrs = 0x00000028;
ioc.data = 0x00002000; // set LOW GPIO13 pin
r = ioctl(fd, XXX_MEM_WRITE_32, &ioc); // write GPCLR0
printf( "--MEMORY READ\n");
read(fd, b, 256);
dump4((unsigned long*)b, 256);
close(fd);
printf( "** end\n");
return 0;
}
---
$ cc led.c -o led
LEDをGPIO-13に配線しておくこと。
GPIO13 <---/\/\/\---▷|---> GND
1kΩ
$ ./led
...
**start
--Memory Dump
Mem: 0x3F200000 = 0x00000000
Mem: 0x3F200004 = 0x00000240
Mem: 0x3F200008 = 0x08000000
Mem: 0x3F20000C = 0x3FFFFFFF
Mem: 0x3F200010 = 0x24200824
Mem: 0x3F200014 = 0x00000924
Mem: 0x3F200018 = 0x00000000
Mem: 0x3F20001C = 0x6770696F
Mem: 0x3F200020 = 0x6770696F
Mem: 0x3F200024 = 0x6770696F
Mem: 0x3F200028 = 0x6770696F
Mem: 0x3F20002C = 0x6770696F
Mem: 0x3F200030 = 0x6770696F
Mem: 0x3F200034 = 0x100081FF
Mem: 0x3F200038 = 0x003EF3FF
Mem: 0x3F20003C = 0x00000000
--LED Blink
count: 0 / 10
count: 1 / 10
count: 2 / 10
count: 3 / 10
count: 4 / 10
count: 5 / 10
count: 6 / 10
count: 7 / 10
count: 8 / 10
count: 9 / 10
--MEMORY READ
3F200000: 00000000 00000240 08000000 3FFFFFFF
3F200010: 24200824 00000924 00000000 6770696F
3F200020: 6770696F 6770696F 6770696F 6770696F
3F200030: 6770696F 100081FF 003EF3FB 00000000
3F200040: 00000000 00000000 00000000 00000000
3F200050: 00000000 00000000 00000000 00000000
3F200060: 00000000 00000000 00000000 00000000
3F200070: 00000000 00000000 00000000 00000000
3F200080: 00000000 00000000 00000000 00000000
3F200090: 00000000 00000002 00000000 00000000
3F2000A0: 00000000 FFFFFFFF 003FFFFF 6770696F
3F2000B0: 00000000 6770696F 6770696F 6770696F
3F2000C0: 00000000 00000000 00000000 00000000
3F2000D0: 6770696F 6770696F 6770696F 6770696F
3F2000E0: 6770696F 6770696F 6770696F 6770696F
3F2000F0: 6770696F 6770696F 6770696F 6770696F
** end
...
2019-11-15 「GNUCOBOL 3.0 インストール」
久しぶりにCOBOLプログラムをやってみました。
OPEN COBOLがGNU COBOLになっていた。
OPEN COBOLもまだ健在でUPDATEされている。同じではないです。
GNUCOBOLはC言語インターフェースがだいぶ修正されている。
Raspberry piにはパッケージでインストールできるのだがcobcrunの機能が新しいのと違うのでソースからインストール。
(1)download
https://jaist.dl.sourceforge.net/project/open-cobol/gnu-cobol/3.0/gnucobol-3.0-rc1.tar.xz
または
https://ja.osdn.net/projects/sfnet_open-cobol/
gnucobol-3.0_nightly_r2793.tar.gz
(2)参考:
https://open-cobol.sourceforge.io/faq/GnuCOBOLFAQ.pdf
GnuCOBOL FAQ Release 2.4.392 sep 28, 2019
https://open-cobol.sourceforge.io/
GnuCOBOL 3.1 (dev) Programmers Guide (A4).pdf
GnuCOBOL FAQ (PDF)
https://sourceforge.net/p/open-cobol/discussion/cobol/thread/94a361d1/9a38/12fa/af3c/fefd/0ae2/7e53/attachment/GnuCOBOL_C%20data_routines.pdf
GnuCOBOL – API for C access to COBOL data(PDF)
(3)インストール手順
gnucobol-3.0-rc1.tar.xz 解凍
cd gnucobol-3.0-rc1
sudo apt install libdb-dev libgmp-dev bison flex help2man texinfo libxml2-dev libncursesw5-dev
他に、Autoconf、Automake、 Libtool、 m4、Gettext もあるかどうかをチェック
./configure
make
make check
sudo make install
nano hello.cob
---hello.cob-----------作成-----------------------------------------------------
123456*7A901B345678901234567890123456789012345678901234567890123456789012M4567890
* Sample COBOL program
IDENTIFICATION DIVISION.
PROGRAM-ID. hello.
PROCEDURE DIVISION.
DISPLAY "Hello, world!".
STOP RUN.
-----------
cobc -x hello.cob
./hello
Hello, world!
翻訳・実行でエラーがないこと。
licob.so ロードエラーの時は、
sudo nano /etc/ld.so.conf
---
/usr/local/lib
を追加するか、/etc/ld.so.conf.d/の下に
上記の内容で”適当な名前xxx.conf”ファイルを作る。
sudo ldconfig
(4)SCREEN SECTIONの日本語対応
ncursesを使っているので通常のCでの対処と同じ。
gnu-cobol 解凍ディレクトリの中にある。
(日本語入力・修正は、コマンドライン入力のようにはなっていないからコメントなのかも)
----lobcob/screenio.c----- 410行付近
#if 1 /* RXWRXW - setlocale */ <<<=== 0 を 1 にする
#ifdef HAVE_SETLOCALE
if (cobglobptr->cob_locale_orig) {
setlocale (LC_ALL, cobglobptr->cob_locale_orig);
}
コメント3行///if (cobglobptr->cob_locale_ctype) {
/// setlocale (LC_CTYPE, cobglobptr->cob_locale_ctype);
///}
#endif
#endif
if (!initscr ()) {
cob_runtime_error (_("failed to initialize curses"));
/* FIXME: likely should raise an exception instead */
cob_stop_run (1);
}
cobglobptr->cob_screen_initialized = 1;
#ifdef HAVE_USE_LEGACY_CODING
use_legacy_coding (2);
#endif
#if 0 /* RXWRXW - setlocale */
#ifdef HAVE_SETLOCALE
if (cobglobptr->cob_locale) {
setlocale (LC_ALL, cobglobptr->cob_locale);
setlocale (LC_CTYPE, "C");
}
#endif
#endif
cbreak ();
keypad (stdscr, 1);
ーーーーー
か、または、コンパイラソースを修正しない場合は、
--- locale.c ---作成
#include <locale.h>
void LOCALE(void)
{
setlocale(LC_ALL,"");
}
-------------
COBOL ソースのSCREEN SECTIONへのアクセス前に
CALL "LOCALE".
といれて、
cobc -x COBOLソース locale.c
でリンクして使う。
(5)SCREEN SECTION のプログラム
COBOLプログラム
---crtform.cob-----------作成-----------------------------------------------------
123456*7A901B345678901234567890123456789012345678901234567890123456789012M4567890
* ******************************
* compile: cobc -x crtform.cob
* ******************************
identification division.
program-id. crtform.
environment division.
configuration section.
special-names.
crt status is yesno.
data division.
working-storage section.
* screenio は crt status の定義
copy screenio.
01 in-data pic X(30).
01 msg pic x(40).
01 yesno pic 9999.
screen section.
01 one-screen.
03 line 3 column 20 value "タイトル".
03 line 5 column 16 value "入力:".
01 two-screen.
03 line 5 column 23 using in-data.
*...................
procedure division.
* CALL "LOCALE".
move 9999 to yesno.
perform until yesno = COB-SCR-OK
move "入力してね!" to msg
display msg at line 10 col 5
display one-screen two-screen
accept two-screen
display two-screen
move "いいですか?(Y=Enter/N=BackSpace)" to msg
display msg at line 10 col 5
accept omitted
end-perform.
goback.
end program crtform.
-------
cobc -x crtform
./crtfotm
実行表示
ーーーーーーー
タイトル
入力: 漢字入力abc_input_____________
いいですか?(Y=Enter/N=BackSpace)
ーーーーーーー
カラム位置は漢字を2、半角英数字を1として数える。
入出力領域はUTF-8文字のバイト数で数える。漢字の後は間があいてしまう。
入力時の修正は良くない。先頭から入れ直す。