2018年12月29日土曜日

gogsの移動

以前から少しずつやっている自宅サーバーの環境移行。

gitリポジトリ保存用にgogsを使っているのだけど、これを移動させたいと思う。gogsやmariadbバージョンが移行前後で随分違うからすごくハマった。

移行元の環境

かなり昔に構築したため、詳細は全く覚えていない。

  1. gitというユーザーがある

  2. /home/gitにgogsとgogs-repositoriesがある

  3. インストールしていたバージョンは「gogs_v0.9.13_linux_386.tar.gz」みたい。。

  4. /etc/systemd/system/gogs.serviceがある

  5. DBはMariaDB 5.5.45を使用

上記から、おそらく

https://gogs.io/docs/intro/faqs#how-do-i-run-gogs-at-startup-with-systemd%3F

あたりを参考にインストールしたのではないかと思う。

データの引き継ぎについて

このあたりに詳しく書いてあった。コピペでできるのか・・

https://gogs.io/docs/upgrade/upgrade_from_binary

移行先での作業

ユーザー作成

ここでいうユーザーはgogsを起動するユーザー。

gogsのページだとgitになっている。


adduser git

gogsのダウンロード

https://dl.gogs.io/0.11.79/gogs_0.11.79_linux_amd64.zip

/home/gitに展開する。

所有者をgitにしておく。

DBサーバーの準備

mariaDB 10.1.34を使用することにした


apt-get install mariadb-server

apt-get install mariadb-client

rootのパスワード忘れたぁOrz

やれやれ・・・。

https://qiita.com/y1row/items/994ecf8b478b7aac4c7d

https://ips.nekotype.com/3426/

https://better-coding.com/solved-xterm-256color-unknown-terminal-type/

gogs用のデータベースとユーザーの作成


create user 'gogs'@'localhost' identified by '<password>';

create database gogs_git;

grant all on gogs_git.* to 'gogs'@'localhost';

データの移行

先述のデータの引き継ぎ方法にしたがって作業を行う

gogsとgogs-repositoriesを移行元からコピー

移行元から移行先にコピー


scp -r gogs git@移行先:/home/git/gogs_old

scp -r gogs-repositories git@移行先:/home/git/

続いて移行先で


cp -R gogs_old/custom gogs/

cp -R gogs_old/data gogs/

cp -R gogs_old/log gogs/

DBの移行

移行元で


mysqldump -u root -p gogs_git > gogs_bkup.dump.sql

移行先で


mysql -u gogs -p gogs_git < gogs_bkup.dump.sql

これでコピー完了。

テスト起動

コピーが終わったので、テストで起動してみる

gitユーザーで


./gogs web

でlocalhost:3000にアクセス・・・あれタイムアウト。。

切り分け

そもそもデータを引き継がない場合に、ちゃんと起動するか

起動自体はしたが、インストール画面で

Error 1071: Specified key was too long; max key length is 767 bytes

な、なんだこれ???

あーめんどくせー。ぐぐってみたら

https://github.com/gogs/gogs/issues/4992

この通りやってみたら、とりあえずログイン画面まで行けた。

ということは、データを引き継いだ場合もこの手順でいけるのかな?

ということで、同じ手順でやってみたらログイン画面・ログイン後のダッシュボードなどなど行けた。

自動起動設定

移行元の設定と同じような記載があったので、この通りにやってみる。

https://gogs.io/docs/intro/faqs#how-do-i-run-gogs-at-startup-with-systemd%3F


# cat /etc/systemd/system/gogs.service

  

[Unit]

Description=Gogs (Go Git Service)

After=syslog.target

After=network.target

After=mysqld.service

  

[Service]

# Modify these two values and uncomment them if you have

# repos with lots of files and get an HTTP error 500 because

# of that

###

#LimitMEMLOCK=infinity

#LimitNOFILE=65535

Type=simple

User=git

Group=git

WorkingDirectory=/home/git/gogs

ExecStart=/home/git/gogs/gogs web

Restart=always

Environment=USER=git HOME=/home/git

  

[Install]

WantedBy=multi-user.target

自動起動テスト


systemctl enable gogs

>Created symlink /etc/systemd/system/multi-user.target.wants/gogs.service → /etc/systemd/system/gogs.service.

systemctl start gogs

systemctl status gogs

● gogs.service - Gogs (Go Git Service)

Loaded: loaded (/etc/systemd/system/gogs.service; enabled; vendor preset: ena

Active: active (running) since Sat 2018-12-29 00:46:16 JST; 9s ago

Main PID: 6978 (gogs)

Tasks: 8 (limit: 4915)

CGroup: /system.slice/gogs.service

└─6978 /home/git/gogs/gogs web

  

12月 29 00:46:16 blackcube systemd[1]: Started Gogs (Go Git Service).

12月 29 00:46:16 blackcube gogs[6978]: 2018/12/29 00:46:16 [TRACE] Custom path:

12月 29 00:46:16 blackcube gogs[6978]: 2018/12/29 00:46:16 [TRACE] Log path: /ho

12月 29 00:46:16 blackcube gogs[6978]: 2018/12/29 00:46:16 [TRACE] Log Mode: Fil

12月 29 00:46:16 blackcube gogs[6978]: 2018/12/29 00:46:16 [ INFO] Gogs: Go Git

systemdに登録できて、起動できたので、これで移行完了!!

つかれたー。空き時間でやっていたから思い立ってから1か月もかかった。Orz.

2018年11月28日水曜日

VSCodeでMarkdown

VSCodeでMarkdown

Markdown環境にBoostnoteを使おうを思ったけど、VSCodeにしたという話。

はじめに

MarkdownとUMLに触れる機会が出てきたので、何か良い環境が無いかと探していたら、Boostnoteというものを見つけた。

やりたいことは、

1.各種メモとプログラムコードをシンタックスハイライトで見やすく残したい

2.UMLやシーケンス図の作成

3.Markdown→HTMLにして、Blog投稿

4.オフライン環境やネット規制がかかっている環境でも使いたい

最初の2つは、そのままできそう。

Blog(Blogspot)はどうやれば良いのか。

いい感じに装飾して欲しいし、画像やgistの引用もしたい。

と、思っていたのだけど、4が曲者で、BoostnoteのUML(Plantuml)が外部(platumlサーバー)に通信しているため、オフライン環境では使えない??

uml diagram

というような表示になってしまう。

そこで、オフラインでなんとかしようと方法を探してみた。

PlantUMLのローカルインストール

このあたりに

The servlet for server side

GitHub - plantuml/plantuml-server: PlantUML Online Server

方法としては、

1.docker

2.maven

というのがあるみたい。

お出かけ用のネットブックで使うこともあるので、dockerは難しいと思う。


git clone https://github.com/plantuml/plantuml-server.git

apt-get install maven

apt-get install libjetty9-java

cd planyuml-server

mvn jetty:run -Djetty.port=9999

で何やらインストールが始まった。

でさっきの「http://www.plantuml.com/plantuml 」を

http://localhost:9999 」に変えてみる。


ソース・オプション5は現在サポートされていません。

6以降を使用してください。

Orz…挫折。

Boostnoteの使用感が良かったので、ちょっと悲しいけど、

あまり時間をかけたくなかったので、VSCodeに変更。。。

VSCodeでMarkdown環境を構築

VSCodeにしたら情報がたくさんある。

「2」に関しては、PlantUMLで無く、Mermaidを使うことにした。

ゴリゴリにUMLしたいわけでは無いので…。

Mermaidって、昔使ったことがあるような。結局同じようなことしかやっていないね。

http://continue-to-challenge.blogspot.com/2015/10/markdownmermaidjs.html

エクステンション

1.Markdown Preview Enhanced

2.Prettier - Code formatter

3.markdownlint

もう以下の記事のまんま

https://qiita.com/kumapo0313/items/a59df3d74a7eaaaf3137

mermaidに関しての変更

大した変更じゃないけど、見やすくするために


Mermaid  theme, you  can  choose  one  from ["mermaid.css", "mermaid.dark.css", "mermaid.forest.css"]

MarkdownPreviewEnhancedのCSSカスタマイズ

コードブロック

ctrl+,で設定開いて、変更する。


Markdown-preview-enhanced: Code Block Theme

Code block theme. If `auto.css` is chosen, then the code block theme that best matches the current preview theme will be picked.

>monokai.css

本体

以下の説明の通り、ctrl+shift+pでコマンド入力開いて、

https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css


Markdown Preview Enhanced: Customize Css

を入力して、開いたstyle.lessにカスタマイズしたいcssを入力する。


/* Please visit the URL below for more information: */

/* https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */

  

.markdown-preview.markdown-preview {

// modify your style here

// eg: background-color: blue;

  

h1 {

color: #ff4f00;/*文字色*/

position: relative;

line-height: 1.4;

padding:0.25em 0.5em;

display: inline-block;

top:0;

}

  

h1:before,h1:after{

position: absolute;

top: 0;

content:'';

width: 8px;

height: 100%;

display: inline-block;

}

  

h1:before{

// border-top: dotted 1px #404040;

border-left: dotted 1px #404040;

// border-bottom: dotted 1px #404040;

left: 0;

}

  

h1:after{

content: '';

// border-top: dotted 1px #404040;

border-right: dotted 1px #404040;

// border-bottom: dotted 1px #404040;

right: 0;

}

  

h2 {

padding: 0.2em;/*文字周りの余白*/

color: #404040;/*文字色*/

background: #fffaf4;/*背景色*/

border-left: solid 10px #ff4f00;/*左線(実線 太さ 色)*/

border-bottom: dashed 1px #ff4f00;

}

  

h3{

color: #ff4f00;/*文字色*/

border-bottom: dashed 1px #ff0600;

}

  

h4 {

border-bottom: solid 2px #cce4ff;

position: relative;

}

  

h4:after {

position: absolute;

content: " ";

display: block;

border-bottom: solid 2px #5472cd;

bottom: -2px;

width: 10%;

}

}

メモ

シーケンス


title: Authentication Sequence

A->B: text

A->B: text

B->B: tesue

A->B: text

mermaid

Syntax error in textmermaid version 11.6.0

記載例は、以下URLのパクリです。

https://qiita.com/poro1985/items/b23bad93bf721a195f15

こんな感じ。

しばらくは、これでやってみようと思う。

Bloggerへの投稿

最初、いろいろな人がやっていることを真似してmarked.jsを考えたのだけど、表示するときにtextareaが見えてしまうのと、スマホ表示時にうまく表示されなかった(こっちはテーマを修正すれば良いような気がするけど・・)

なので、Blogger投稿時は、オンライン環境だと割り切って、オンラインサービスを使うことにした。

StackEdit

ネット上に情報が溢れているため、特に書くことはない。

以下がとても参考になった。

https://qiita.com/yonori/items/fe733aee419019fbacc4

2018年10月29日月曜日

Nextcloudを導入してみた

まとまった時間を確保するのは難しい。
でもスキマ時間を見つけて、いろいろやっている。続けることが大事。

家族からDropboxがいっぱいになってしまったとクレームが来た。
容量アップするか、他のクラウドサービスにするか、といろんな人が体験したような悩みに直面。
うちの使い方は
  1. 大事な写真・動画の保存
  2. 家族や親戚との共有
  3. ドキュメント類の同期
  4. LINEでは動画が何日かすると消えてしまう
のために使っている。
動画とか保存しだすと1Gとかあっという間なので、一杯になってしまうというのも、頷ける。。。

それぞれいろんなサービスを駆使したら解決できるのだろうけど、
勉強がてら、家サーバーで何かできないか調べてみた。
ちょうど、今のサーバー君が2010年くらいの代物なので、リプレースがてら環境構築してみた。

 メモ
現行 Atom N270 1.6GHz 1コア2スレッド 32bit メモリ:1GB
新規 AMD E-350 1.6GHz 2コア 64bit メモリ:8GB
あれ??あまりスペックアップしていないOrz

(まぁ64bit対応できているからいいか・・・)


ownCloudとNextcloud

歴史とかよくわからないけど、Nextcloudの方がダウンロードリンクが
分かりやすかったので、そっちにした。

インストール手順は以下にまとまっていた
https://docs.nextcloud.com/server/14/admin_manual/installation/source_installation.html#ubuntu-installation-label
0.前提条件
先述のAMD E-350という年代物・・・。これにMint 64bitをインストール。

1.必要なパッケージインストール 
apt-get install mariadb-server
apt-get install mariadb-client
apt-get install nginx
apt-get install php-fpm php-mysqlnd php-zip php-xml php-mbstring php-gd php-curl

2.mariaebのセットアップ
以下のセットアップを実行する
/usr/bin/mysql_secure_installation
rootユーザー設定
create user 'nextcloud'@'localhost' identified by 'パスワード';
create database nextcloud;
grant all on nextcloud.* to 'nextcloud'@'localhost';
これで、mariadbはOK
3.nginxのセットアップ
以下を変更し設定する
/etc/nginx/nginx.conf
/etc/nginx/sites-enabled/default
4.php-fpmのセットアップ
以下を変更し設定する
/etc/php/7.2/fpm/pool.d/www.conf
5.nextcloudのダウンロード
https://nextcloud.com/install/#instructions-server
https://download.nextcloud.com/server/releases/nextcloud-14.0.3.zip
以下のセットアップを実行するだけ
sudo -u www-data php occ  maintenance:install --database "mysql" \
--database-name "nextcloud"  --database-user "nextcloud" \
--database-pass "パスワード" \
--admin-user "admin" --admin-pass "あどみんパスワード"
これでおしまい。 こんな感じ

2018年7月16日月曜日

キャラクタ液晶に天気予報を表示する

暑い・・・。暑すぎる。

キャラクタ液晶の使い道を考えていた。
暑くて、天気予報が知りたくなった。

早速結果からだけど、こんな感じ


1. 天気予報を取得する

livedoorの天気予報サービスを利用させてもらう。
http://weather.livedoor.com/weather_hacks/webservice

都市は「東京」なので「http://weather.livedoor.com/forecast/webservice/json/v1?city=130010

JSONで応答してくれるみたい。
[forecasts][0][telop]に[晴のち曇り]
[forecasts][0][temperature][max][celsius]に[最高気温]

linuxボードにpythonとか入っていないので、awkとsedで頑張る!



2. 天気アイコンをアニメーションしたい

外字(CGRAM)は8種類しかないけれど、書き込むと表示中のものも変更された!
ということは、動的に変更できて、なんちゃってアニメーションできそう。


3. 表示

上段に「サイコウ キオン:●●°C」
下段に「テンキ:■■■■■」
■部分は、例えば「晴のち曇」なら
「晴アイコン」「ハレ」「→」「曇アイコン」「クモリ」

JSON出力はUnicodeで「晴のち曇」は「"\u6674\u306e\u3061\u66c7"」となる。
「のち」なら「→」、「時々」なら「/」とした。
外字は

外字は1s毎に書き換えを行い、アニメーションしてるっぽくした。
また、1時間毎に天気予報を更新する。
(今回は実験なので、この間隔にしたけど、長期に使う場合には、
 利用規約確認したり、迷惑かからないように12時間とか24時間とかのほうがいいかも)

ソース

#!/bin/sh
CDEVNAME=/dev/PicClcdDriver0
SYSDEV=/sys/bus/spi/drivers/PicClcdDriver/spi0.1/
CMD_CLEAR=lcd_clear
CMD_SETCGRAM=lcd_set_cgram
CMD_SETDDRAM=lcd_set_ddram
#URL
TENKI_API="http://weather.livedoor.com/forecast/webservice/json/v1?city=130010"
#debug
#DEBUG_FLG=1
#外形文字(天気アイコン)
HARE0=00411040E04110400
HARE1=004150A110A150400
AME0=111150E1F04140800
AME1=111040E1F04050200
KUMORI0=2000A1500150A0000
KUMORI1=20A150A000A150A00
KAMINARI0=30408180E03020400
KAMINARI1=30408100A04081000
YUKI0=40812050208140800
YUKI1=40205020814090200
#Unicode
U_HARE=6674
U_NO=306E
U_CHI=3061
U_AME=96E8
U_KUMORI=66C7
U_KAMINARI=96F7
U_UKI=96EA
U_TOKI=6642
U_DOKI=3005
#CGRAM
echo $HARE0 > $SYSDEV/$CMD_SETCGRAM
echo $AME0 > $SYSDEV/$CMD_SETCGRAM
echo $KUMORI0 > $SYSDEV/$CMD_SETCGRAM
echo $KAMINARI0 > $SYSDEV/$CMD_SETCGRAM
echo $YUKI0 > $SYSDEV/$CMD_SETCGRAM
while :
do
#最高気温・天気取得
RETTENKI=`wget -O - $TENKI_API | awk -Fforecasts '{print $2}' | awk -Flocation '{print $1}'`
# LCD クリア
echo > $SYSDEV$CMD_CLEAR
# 温度表示
if [ "$DEBUG_FLG" = "1" ]; then
MAXTEMP=`cat test2.txt | awk -Fmax '{print $2}' | awk -Fcelsius '{print $2}' | awk -Ffahrenheit '{print $1}' | sed -e 's/[:,"]//g'`
else
MAXTEMP=`echo $RETTENKI | awk -Fmax '{print $2}' | awk -Fcelsius '{print $2}' | awk -Ffahrenheit '{print $1}' | sed -e 's/[:,"]//g'`
fi
echo 最高気温:$MAXTEMP
#サイコウ キオン:
echo -ne "\xBB" > $CDEVNAME
echo -ne "\xB2" > $CDEVNAME
echo -ne "\xBA" > $CDEVNAME
echo -ne "\xB3" > $CDEVNAME
echo -ne "\xA0" > $CDEVNAME
echo -ne "\xB7" > $CDEVNAME
echo -ne "\xB5" > $CDEVNAME
echo -ne "\xDD" > $CDEVNAME
echo -ne "\x3A" > $CDEVNAME
echo -n $MAXTEMP > $CDEVNAME
echo -en "\xdf" > $CDEVNAME
echo -n "C " > $CDEVNAME
#2行目に移動
echo -n 40 > $SYSDEV/$CMD_SETDDRAM
#テンキ:
echo -ne "\xC3" > $CDEVNAME
echo -ne "\xDD" > $CDEVNAME
echo -ne "\xB7" > $CDEVNAME
echo -ne "\x3A" > $CDEVNAME
# 天気
if [ "$DEBUG_FLG" = "1" ]; then
WEATHER=`cat test2.txt | awk -Ftelop '{print $2}' | awk -Fdate '{print $1}' | sed -e 's/[:,"u]//g' | sed 's/\\\\/ /g' | tr '[a-z]' '[A-Z]'`
else
WEATHER=`echo $RETTENKI | awk -Ftelop '{print $2}' | awk -Fdate '{print $1}' | sed -e 's/[:,"u]//g' | sed 's/\\\\/ /g' | tr '[a-z]' '[A-Z]'`
fi
echo $WEATHER
for i in $WEATHER
do
echo $i
if [ "$i" = "$U_HARE" ]; then
echo 晴
echo -ne "\x08" > $CDEVNAME
echo -ne "\xCA" > $CDEVNAME
echo -ne "\xDA" > $CDEVNAME
elif [ "$i" = "$U_AME" ]; then
echo 雨
echo -ne "\x09" > $CDEVNAME
echo -ne "\xB1" > $CDEVNAME
echo -ne "\xD2" > $CDEVNAME
elif [ "$i" = "$U_KUMORI" ]; then
echo 曇
echo -ne "\x0A" > $CDEVNAME
echo -ne "\xB8" > $CDEVNAME
echo -ne "\xD3" > $CDEVNAME
echo -ne "\xD8" > $CDEVNAME
elif [ "$i" = "$U_KAMINARI" ]; then
echo 雷
echo -ne "\x0B" > $CDEVNAME
echo -ne "\xB6" > $CDEVNAME
echo -ne "\xD0" > $CDEVNAME
echo -ne "\xC5" > $CDEVNAME
echo -ne "\xD8" > $CDEVNAME
elif [ "$i" = "$U_UKI" ]; then
echo 雪
echo -ne "\x0C" > $CDEVNAME
echo -ne "\xD5" > $CDEVNAME
echo -ne "\xB7" > $CDEVNAME
elif [ "$i" = "$U_NO" ]; then
echo の
echo -ne "\x7E" > $CDEVNAME
elif [ "$i" = "$U_TOKI" ]; then
echo 時
echo -ne "\x2F" > $CDEVNAME
fi
done
#echo -ne "\x09" > $CDEVNAME
#echo -ne "\x0A" > $CDEVNAME
#echo -ne "\x0B" > $CDEVNAME
#echo -ne "\x0C" > $CDEVNAME
#echo -ne "\x7E" > $CDEVNAME
OLD_DT=`date '+%Y%m%d %H'`
NEW_DT=`date '+%Y%m%d %H'`
echo $OLD_DT
while [ "$OLD_DT" = "$NEW_DT" ]
do
NEW_DT=`date '+%Y%m%d %H'`
#echo $NEW_DT
sleep 1
echo $HARE1 > $SYSDEV/$CMD_SETCGRAM
echo $AME1 > $SYSDEV/$CMD_SETCGRAM
echo $KUMORI1 > $SYSDEV/$CMD_SETCGRAM
echo $KAMINARI1 > $SYSDEV/$CMD_SETCGRAM
echo $YUKI1 > $SYSDEV/$CMD_SETCGRAM
sleep 1
echo $HARE0 > $SYSDEV/$CMD_SETCGRAM
echo $AME0 > $SYSDEV/$CMD_SETCGRAM
echo $KUMORI0 > $SYSDEV/$CMD_SETCGRAM
echo $KAMINARI0 > $SYSDEV/$CMD_SETCGRAM
echo $YUKI0 > $SYSDEV/$CMD_SETCGRAM
done
echo $NEW_DT
done
view raw weather.sh hosted with ❤ by GitHub

使いそびれたパラレルキャラクタ液晶のSPI化(2/2)

前回からのつづき
制御用のFON2405E(LEDE・Openwrt)向けドライバ作成

1. SPI仕様

[0x01][コントラスト] ※コントラストは0x00〜0x06
[0x02][コマンド]  ※ RS=0 でLCDに出力
[0x03][データ]   ※ RS=1 でLCDに出力

http://akizukidenshi.com/download/ds/sunlike/SD1602HULB-XA-G-G.PDF
http://219.117.208.26/~saka/ham/LCD2/

2. ドライバ仕様

基本的には、MCP23S09の時と同じ。
キャラクタデバイスとして[/dev/ PicClcdDriver0]が作成される。
これに表示したい内容を流しこめばOK
一方で、各種制御は[/sys/bus/spi/drivers/PicClcdDriver/spi0.1/]に
lcd_clear:Clear Display(全表示クリア)
lcd_set_cgram:Set CGRAM address
lcd_set_ddram:Set DDRAM address
が作成される

3. 動作

insmod pic_clcd.ko
echo > /sys/bus/spi/drivers/PicClcdDriver/spi0.1/lcd_clear
echo -n HelloWorld! >  /dev/ PicClcdDriver0

英数字以外 例えば 「イ」とか
echo -ne "\xB2" > /dev/ PicClcdDriver0

外字CGRAM
0番目に「晴?」アイコン
echo 00411040E04110400 > /sys/bus/spi/drivers/PicClcdDriver/spi0.1/lcd_set_cgram



ドライバソースコード
/*
* pic_cled.c
*
* Created on: 2018/07/08
* Author: adeno
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/uaccess.h> //copy_from_user
#include <linux/gpio.h>
#include <linux/spi/spi.h>
MODULE_AUTHOR("Adeno");
MODULE_LICENSE("GPL v2");
//=======================================================================================
/* ドライバ */
#define DRV_NUM_DEVS 1 /* このドライバが制御するデバイスの数 */
#define DRV_DEVNAME "PicClcdDriver" /* このデバイスドライバの名称 */
#define DRV_MAJOR 0 /* メジャー番号だが自動設定なので0 */
#define DRV_MINOR 0 /* マイナー番号のベース番号 */
#define DRV_GPIO_MAPNAME "pcd_gpio_map"
/* SPI PIC設定 */
#define SPCD_PACKET_SIZE 1
const uint8_t SPCD_LCD_PWM = 0x01;
const uint8_t SPCD_LCD_CMD = 0x02;
const uint8_t SPCD_LCD_DATA = 0x03;
const uint8_t SPCD_LCD_CMD_CLEARDISPLAY = 0b00000001;
const uint8_t SPCD_LCD_CMD_RETURNHOME = 0b00000010;
const uint8_t SPCD_LCD_CMD_SETCGRAM = 0b01000000;
const uint8_t SPCD_LCD_CMD_SETDDRAM = 0b10000000;
//=======================================================================================
/* ドライバ */
static int _spcd_major = DRV_MAJOR;
static int _spcd_minor = DRV_MINOR;
/* SPI */
struct drvdata {
struct spi_device *spi;
struct mutex lock;
unsigned char tx[SPCD_PACKET_SIZE];
unsigned char rx[SPCD_PACKET_SIZE];
struct spi_transfer xfer;
struct spi_message msg;
dev_t md_dev;
struct class *drv_class;
struct cdev *drv_cdev_array;
} ____cacheline_aligned;
static struct drvdata spcd;
static struct spi_board_info spcd_info = {
.modalias = "spcd",
.max_speed_hz = 1000000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_3,
};
static struct spi_device_id spcd_id[] = {
{ "spcd", 0 },
{ },
};
MODULE_DEVICE_TABLE(spi, spcd_id);
/* Parameters Setting */
static int gpiono = 9;
static int show_debug = 0;
//static int hexmode = 0;
//=======================================================================================
/* プロトタイプ宣言 */
static unsigned int spcd_set_value( struct drvdata *data,unsigned int v);
static void spi_remove_device(struct spi_master *master, unsigned int cs);
static int spcd_probe(struct spi_device *spi);
static int spcd_remove(struct spi_device *spi);
static int spcd_open(struct inode *inode, struct file *filep);
static int spcd_release(struct inode *inode, struct file *filep);
static ssize_t spcd_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos);
static int spcd_register_dev(void);
static int spcd_init(void);
static void spcd_exit(void);
//=======================================================================================
/* SPIデバイス */
static struct spi_driver spcd_driver = {
.driver = {
.name = DRV_DEVNAME,
.owner = THIS_MODULE,
},
.id_table = spcd_id,
.probe = spcd_probe,
.remove = spcd_remove,
};
/* キャラクタデバイス */
struct file_operations spcd_fops = {
.open = spcd_open,
.release = spcd_release,
.write = spcd_write,
};
//=======================================================================================
static int lcd_clear_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
spcd_set_value(drd,SPCD_LCD_CMD);
spcd_set_value(drd,SPCD_LCD_CMD_CLEARDISPLAY);
// spcd_set_value(drd,SPCD_LCD_FIN);
return size;
}
static DEVICE_ATTR(lcd_clear, S_IWUSR|S_IWGRP, NULL, lcd_clear_store );
static int lcd_set_cgram_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
//CharNo Line(0-7)
//[1] [2]x8
int b[9],i;
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
if(size >= 17){
if(buf[0] >='0' && buf[0] <= '9') b[0] = buf[0]-'0';
b[0] = SPCD_LCD_CMD_SETCGRAM | (((b[0] & 0b111) << 3) & 0b111000);
if(show_debug) printk(KERN_INFO "LCD SET CG Adr size=%d,C=%d\n",size,b[0]);
// /*if(show_debug)*/ printk(KERN_INFO "LCD SET CG Adr output=%d\n",b[0]);
spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,b[0]);
for(i=0; i<8; i++){
if(buf[i*2+1] >='0' && buf[i*2+1] <= '9') b[i] = (buf[i*2+1]-'0') * 0x10;
else if(buf[i*2+1] >='A' && buf[i*2+1] <= 'F') b[i] += (buf[i*2+1]-'A'+0xA) * 0x10;
else if(buf[i*2+1] >='a' && buf[i*2+1] <= 'f') b[i] += (buf[i*2+1]-'A'+0xA) * 0x10;
if(buf[i*2+2] >='0' && buf[i*2+2] <= '9') b[i] += (buf[i*2+2]-'0');
else if(buf[i*2+2] >='A' && buf[i*2+2] <= 'F') b[i] += (buf[i*2+2]-'A'+0xA);
else if(buf[i*2+2] >='a' && buf[i*2+2] <= 'f') b[i] += (buf[i*2+2]-'A'+0xA);
spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,b[i]);
}
// spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,0b10); //ホームに
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,buf[0]-'0');
//
//
//
// if((buf[0] >='0' && buf[0] <= '9') && (buf[1] >='0' && buf[1] <= '9')){
// int cno = buf[0]-'0';
// int lno = buf[1]-'0';
// int b = 0x40 | (((cno & 0b111) << 3) | (lno & 0b111));
// /*if(show_debug)*/ printk(KERN_INFO "LCD SET CG Adr size=%d,C=%d,L=%d,output=%d\n",size,cno,lno,b);
//
// spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,b);
//// spcd_set_value(drd,SPCD_LCD_FIN);
//
// //debug
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b01010);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b10101);
// spcd_set_value(drd,SPCD_LCD_DATA); spcd_set_value(drd,0b00000);
//// spcd_set_value(drd,SPCD_LCD_FIN);
// }
}
return size;
}
static DEVICE_ATTR(lcd_set_cgram, S_IWUSR|S_IWGRP, NULL, lcd_set_cgram_store );
static int lcd_set_ddram_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
//Adr
//[2]
int b;
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
if(size >= 1){
if(buf[0] >='0' && buf[0] <= '9') b = (buf[0]-'0') * 0x10;
else if(buf[0] >='A' && buf[0] <= 'F') b += (buf[0]-'A'+0xA) * 0x10;
else if(buf[0] >='a' && buf[0] <= 'f') b += (buf[0]-'A'+0xA) * 0x10;
if(buf[1] >='0' && buf[1] <= '9') b += (buf[1]-'0');
else if(buf[1] >='A' && buf[1] <= 'F') b += (buf[1]-'A'+0xA);
else if(buf[1] >='a' && buf[1] <= 'f') b += (buf[1]-'A'+0xA);
/*if(show_debug)*/ printk(KERN_INFO "LCD SET DD Adr size=%d,C=%d\n",size,(b | SPCD_LCD_CMD_SETDDRAM));
spcd_set_value(drd,SPCD_LCD_CMD); spcd_set_value(drd,(b | SPCD_LCD_CMD_SETDDRAM));
}
return size;
}
static DEVICE_ATTR(lcd_set_ddram, S_IWUSR|S_IWGRP, NULL, lcd_set_ddram_store );
static int lcd_contrast_store( struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
int size = strlen( buf );
struct drvdata *drd = spi_get_drvdata((struct spi_device *)dev);
if(size > 0){
if(show_debug) printk(KERN_INFO "Change LCD Contrast %d,%c\n", size,buf[0]);
spcd_set_value(drd,SPCD_LCD_PWM);
switch(buf[0]){
case '0':
spcd_set_value(drd,0x00);
break;
case '1':
spcd_set_value(drd,0x01);
break;
case '2':
spcd_set_value(drd,0x02);
break;
case '3':
spcd_set_value(drd,0x03);
break;
case '4':
spcd_set_value(drd,0x04);
break;
case '5':
spcd_set_value(drd,0x05);
break;
case '6':
spcd_set_value(drd,0x06);
break;
default:
spcd_set_value(drd,0x03);
break;
}
}
return size;
}
static DEVICE_ATTR(lcd_contrast, S_IWUSR|S_IWGRP, NULL, lcd_contrast_store );
static unsigned int spcd_set_value( struct drvdata *data,unsigned int v)
{
unsigned int r = 0;
mutex_lock( &data->lock );
data->tx[0] = v;
if( spi_sync( data->spi, &data->msg) ) {
if(show_debug) printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
usleep_range(1000,2000);
mutex_unlock(&data->lock);
return r;
}
/**
* SPIデバイスの削除
*/
static void spi_remove_device(struct spi_master *master, unsigned int cs)
{
struct device *dev;
char str[128];
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
if(show_debug) printk(KERN_INFO "[spi_remove_device] %s\n",str);
// SPIデバイスを探す
dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
// あったら削除
if( dev ){
if(show_debug) printk(KERN_INFO "Delete %s\n", str);
device_del(dev);
}
}
/**
* SPI通信初期化
*/
static int spcd_probe(struct spi_device *spi)
{
// struct mcp_drvdata *data;
int retval;
if(show_debug) printk(KERN_INFO "spcd spi probe\n");
/* SPIを設定する */
spi->max_speed_hz = spcd_info.max_speed_hz;
spi->mode = spcd_info.mode;
spi->bits_per_word = 8;
if( spi_setup( spi ) ) {
printk(KERN_ERR "spi_setup returned error\n");
return -ENODEV;
}
spcd.spi = spi;
mutex_init( &spcd.lock );
spcd.xfer.tx_buf = spcd.tx;
spcd.xfer.rx_buf = 0;//data->rx;
spcd.xfer.bits_per_word = 8;
spcd.xfer.len = SPCD_PACKET_SIZE;
spcd.xfer.cs_change = 0;
spcd.xfer.delay_usecs = 0;
spcd.xfer.speed_hz = 1000000;
spi_message_init_with_transfers( &spcd.msg, &spcd.xfer, 1 );
spi_set_drvdata( spi, &spcd );
mutex_lock( &spcd.lock );
spcd.tx[0] = 0x00;
if( spi_sync( spcd.spi, &spcd.msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mutex_unlock(&spcd.lock);
retval = device_create_file( &spi->dev, &dev_attr_lcd_clear );
if(retval) {
printk(KERN_ERR "failed to add lcd_clear attribute\n" );
}
retval = device_create_file( &spi->dev, &dev_attr_lcd_contrast );
if(retval) {
printk(KERN_ERR "failed to add lcd_contrast attribute\n" );
}
retval = device_create_file( &spi->dev, &dev_attr_lcd_set_cgram );
if(retval) {
printk(KERN_ERR "failed to add lcd_set_cgram attribute\n" );
}
retval = device_create_file( &spi->dev, &dev_attr_lcd_set_ddram );
if(retval) {
printk(KERN_ERR "failed to add lcd_set_ddram attribute\n" );
}
return 0;
}
/**
* SPI通信終了
*/
static int spcd_remove(struct spi_device *spi)
{
if(show_debug) printk(KERN_INFO "[spcd spi_remove]\n");
struct drvdata *drd = spi_get_drvdata(spi);
mutex_lock( &drd->lock );
drd->tx[0] = 0x00;
if( spi_sync( drd->spi, &drd->msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mutex_unlock(&drd->lock);
device_remove_file( &spi->dev, &dev_attr_lcd_clear);
device_remove_file( &spi->dev, &dev_attr_lcd_contrast);
device_remove_file( &spi->dev, &dev_attr_lcd_set_cgram);
device_remove_file( &spi->dev, &dev_attr_lcd_set_ddram);
spi_set_drvdata(drd->spi, NULL);
drd->spi = NULL;
mutex_destroy(&spcd.lock);
if(gpiono != 0) gpio_free(gpiono);
return 0;
}
/**
* デバイスオープン時の処理
*/
static int spcd_open(struct inode *inode, struct file *filep)
{
if(show_debug) printk(KERN_INFO "[spcd_open]\n");
filep->private_data = &spcd;
return 0;
}
/**
* デバイスクローズ時の処理
*/
static int spcd_release(struct inode *inode, struct file *filep)
{
if(show_debug) printk(KERN_INFO "[spcd_release]\n");
struct drvdata *drd = filep->private_data;
if ((drd == NULL) || (drd->spi == NULL))
return -ENODEV;
filep->private_data = NULL;
return 0;
}
/**
* デバイス書き込み処理
*/
static ssize_t spcd_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos)
{
char cvalue;
// int i;
struct drvdata *drd = filep->private_data;
if ((drd == NULL) || (drd->spi == NULL))
return -ENODEV;
// struct mcp_drvdata *data = (struct mcp_drvdata *)dev_get_drvdata(filep->private_data);
if(count > 0) {
if(gpiono != 0) gpio_set_value(gpiono,1);
if(copy_from_user( &cvalue, buf, sizeof(char) )) {
return -EFAULT;
}
spcd_set_value(drd,SPCD_LCD_DATA);
spcd_set_value(drd,cvalue);
// spcd_set_value(drd,SPCD_LCD_FIN);
// if((cvalue >=0) && (cvalue <= 9)) spcd_set_value(drd,cvalue);
// else if(('0' <= cvalue) && (cvalue <= '9')) {
// spcd_set_value(drd,0x03);
// spcd_set_value(drd,cvalue);
// spcd_set_value(drd,0x00);
// }
// else{
// if(hexmode){
// if(('A' <= cvalue) && (cvalue <= 'F')) spcd_set_value(drd,cvalue - 'A' + 10);
// else if(('a' <= cvalue) && (cvalue <= 'f')) spcd_set_value(drd,cvalue - 'a' + 10);
// }
// else if(show_debug) printk(KERN_ALERT "Can not display %d\n", cvalue );
// }
if(gpiono != 0) gpio_set_value(gpiono,0);
return sizeof(char);
}
return 0;
}
/**
* デバイスドライバをカーネルに登録
*/
static int spcd_register_dev(void)
{
int retval;
// dev_t dev;
size_t size;
int i;
/* 空いているメジャー番号を使ってメジャー&
マイナー番号をカーネルに登録する */
retval = alloc_chrdev_region(
&spcd.md_dev, /* 結果を格納するdev_t構造体 */
DRV_MINOR, /* ベースマイナー番号 */
DRV_NUM_DEVS, /* デバイスの数 */
DRV_DEVNAME /* デバイスドライバの名前 */
);
if( retval < 0 ) {
printk(KERN_ERR "alloc_chrdev_region failed.\n" );
return retval;
}
_spcd_major = MAJOR(spcd.md_dev);
/* デバイスクラスを作成する */
spcd.drv_class = class_create(THIS_MODULE,DRV_DEVNAME);
if(IS_ERR(spcd.drv_class))
return PTR_ERR(spcd.drv_class);
/* cdev構造体の用意 */
size = sizeof(struct cdev) * DRV_NUM_DEVS;
spcd.drv_cdev_array = (struct cdev*)kmalloc(size, GFP_KERNEL);
/* デバイスの数だけキャラクタデバイスを登録する */
/* ただし7セグLEDは1個しかない */
for( i = 0; i < DRV_NUM_DEVS; i++ ) {
dev_t devno = MKDEV(_spcd_major, _spcd_minor+i);
/* キャラクタデバイスとしてこのモジュールをカーネルに登録する */
cdev_init(&(spcd.drv_cdev_array[i]), &spcd_fops);
spcd.drv_cdev_array[i].owner = THIS_MODULE;
if( cdev_add( &(spcd.drv_cdev_array[i]), devno, 1) < 0 ) {
/* 登録に失敗した */
printk(KERN_ERR "cdev_add failed minor = %d\n", _spcd_minor+i );
}
else {
/* デバイスノードの作成 */
device_create(
spcd.drv_class,
NULL,
devno,
NULL,
DRV_DEVNAME"%u",_spcd_minor+i
);
}
}
return 0;
}
/**
* モジュールの初期化処理
*/
static int spcd_init(void)
{
int retval;
int i;
/* 開始のメッセージ */
printk(KERN_INFO "%s loading...\n", DRV_DEVNAME );
if(gpiono != 0){
/* GPIOレジスタがマップ可能か調べる */
retval = gpio_request_one(gpiono, GPIOF_OUT_INIT_LOW, DRV_GPIO_MAPNAME);
if (retval) {
printk(KERN_ERR "Unable to request GPIOs: %d\n", retval);
return retval;
}
for( i=0; i<10; i++ ) {
gpio_set_value(gpiono,1);
msleep(10);
gpio_set_value(gpiono,0);
msleep(10);
}
}
/* デバイスドライバをカーネルに登録 */
retval = spcd_register_dev();
if( retval != 0 ) {
printk( KERN_ALERT "mcp7d driver register failed.\n");
return retval;
}
if(show_debug)
printk( KERN_INFO "mcp7d driver register sccessed.\n");
struct spi_master *master;
struct spi_device *spi_device;
spi_register_driver(&spcd_driver);
spcd_info.bus_num = 0;
spcd_info.chip_select = 1;
master = spi_busnum_to_master(spcd_info.bus_num);
if( ! master ) {
printk( KERN_ERR "spi_busnum_to_master returned NULL\n");
spi_unregister_driver(&spcd_driver);
return -ENODEV;
}
spi_remove_device(master, spcd_info.chip_select);
spi_device = spi_new_device( master, &spcd_info );
if( !spi_device ) {
printk(KERN_ERR "spi_new_device returned NULL\n" );
spi_unregister_driver(&spcd_driver);
return -ENODEV;
}
return 0;
}
/**
* モジュールの終了処理
*/
static void spcd_exit(void)
{
int i;
dev_t devno;
if(show_debug) printk(KERN_INFO "[spcd_exit]\n");
if(show_debug) printk(KERN_INFO "[cdev_del]\n");
/* キャラクタデバイスの登録解除 */
for( i = 0; i < DRV_NUM_DEVS; i++ ) {
cdev_del(&(spcd.drv_cdev_array[i]));
devno = MKDEV(_spcd_major, _spcd_minor+i);
device_destroy(spcd.drv_class, devno);
}
/* メジャー番号/マイナー番号を取り除く */
devno = MKDEV(_spcd_major,_spcd_minor);
unregister_chrdev_region(devno, DRV_NUM_DEVS);
/* デバイスノードを取り除く */
class_destroy( spcd.drv_class );
kfree(spcd.drv_cdev_array);
if(show_debug) printk(KERN_INFO "[spcd_del]\n");
spi_unregister_driver(&spcd_driver);
}
module_init(spcd_init);
module_exit(spcd_exit);
module_param( show_debug, int, S_IRUSR | S_IRGRP | S_IROTH );
module_param( gpiono, int, S_IRUSR | S_IRGRP | S_IROTH );
//module_param( hexmode, int, S_IRUSR | S_IRGRP | S_IROTH );
view raw pic_clcd.c hosted with ❤ by GitHub

使いそびれたパラレルキャラクタ液晶のSPI化(1/2)

ずっと昔にまとめ買いした「LCDキャラクタディスプレイモジュール」(秋月電子のSC1602BSLB-XA-GB-KとかSD1602HULB-XA-G-G)が使いそびれていた。
5Vだしパラレル入力だし・・・。
最近では、3VとかI2C通信のものが安価に出ている。
困った。 FON2405E(Linuxボード)は 3Vだし、今のところSPIしか使えていない。
そこで、PICマイコン使って
  • インターフェース変換(SPI to パラレル)
  • 3V駆動
  • SW入力
  • バックライト
を目指す。

先に結論↓ こんな感じで、Linuxボードから制御してみた。



1. インターフェース変換

SPI搭載の手持ちPICマイコン=PIC16F818 / 819 にした。
まぁシフトレジスタでも実現できるような気がするけど。
http://www.aitendo.com/product/14623
だけど3V駆動化とかSW入力とかやりたいので、今回はPICにこだわった。


2. 3V駆動

いろいろな方が実現している。感謝!
PICにてPWM出力し、チャージポンプにて負電圧を生成する。
最初に思いついた方すごいね!
http://elm-chan.org/docs/lcd/lcd3v_j.html
http://jsdiy.web.fc2.com/lcd3v/


3. SW入力

入力ピンが足りないので、アナログ入力+抵抗分圧にて。
こちらもいろいろな方が実現している。感謝。
https://synapse.kyoto/hard/keypad/page001.html


4. バックライト

バックライト駆動するためには4V 40mA程度必要っぽい。
2のチャージポンプでは賄えないか・・・。
要検討・・・。

んでもって、現状の回路図はこんな感じ。


ソースコード
/*
* File: lcd_lib.c
* Author: adeno
*
* Created on 2018/06/25, 1:18
*/
#include <xc.h>
#include "lcd_lib.h"
/*
*
*/
void lcd_change_col(unsigned char i){
// if(i == 1) { lcd_cmd(0xC0); }
// else {lcd_cmd(0x80);}
if(i == 1){
lcd_out(0xC0,0);
lcd_out(0x00,0); //<<4
}else{
lcd_out(0x80,0);
lcd_out(0x00,0); //<<4
}
__delay_ms(2);
}
///
///LCDにコマンド・文字を出力
/// charflg=0 コマンド、charflg=1 文字
/// 要指定
/// #define lcd_e_bit
/// #define lcd_rs_bit
/// #define lcd_port PORTA この場合、RA3 - 0を使う
void lcd_out(unsigned char code,unsigned char charflg){
unsigned char port_bak;
unsigned char rs_bit = (1 << lcd_rs_bit);
unsigned char e_bit = (1 << lcd_e_bit);
//データ出力
port_bak = lcd_port & 0b11100001; //RA4 - 1
port_bak = port_bak | (0b00011110 & (code >> 3));
lcd_port = port_bak;
//rs set
port_bak = port_bak & (~rs_bit);
if (charflg == 1){
//RSをhigh
port_bak = port_bak | rs_bit;
}
lcd_port = port_bak;
//eにワンショット
port_bak = port_bak & (~e_bit);
lcd_port = port_bak | e_bit;
__nop();
lcd_port = port_bak;
}
void lcd_clear(){
lcd_cmd(0x01);
__delay_ms(15);
}
void lcd_init(){
//LCDの初期化
__delay_ms(15);
lcd_out(0x30,0);
__delay_ms(5);
lcd_out(0x30,0);
__delay_ms(1);
lcd_out(0x30,0);
__delay_ms(1);
lcd_out(0x20,0);
__delay_ms(1);
lcd_cmd(0x2e);
// lcd_out(0x2e,0);
// lcd_out(0xe0,0); //<<4
// __delay_ms(2);
lcd_cmd(0x08);
lcd_cmd(0x0d);
lcd_cmd(0x06);
lcd_cmd(0x02);
}
view raw lcd_lib.c hosted with ❤ by GitHub
/*
* File: lcd_lib.h
* Author: adeno
*
* Created on 2018/06/25, 1:20
*/
#ifndef LCD_LIB_H
#define LCD_LIB_H
#ifdef __cplusplus
extern "C" {
#endif
//出力にラッチがないPIC向けで、データと制御のポート群が同じ場合
//データ出力がRx4〜Rx1の場合
#define _XTAL_FREQ 8000000 //delay用に必要(クロック8MHzを指定)
//RA1 D4
//RA2 D5
//RA3 D6
//RA4 D7
//RA4 E
//RA6 RS
#define LCD_ROW 16
#define LCD_COL 2
#define lcd_port PORTA
#define lcd_e_bit 7
#define lcd_rs_bit 6
#define lcd_data(ascii) lcd_out(ascii,1);lcd_out(ascii << 4,1);__delay_us(50);
#define lcd_cmd(cmd) lcd_out(cmd,0);lcd_out(cmd << 4,0);__delay_ms(2);
void lcd_change_col(unsigned char i);
void lcd_out(unsigned char code,unsigned char charflg);
void lcd_init();
void lcd_clear();
#ifdef __cplusplus
}
#endif
#endif /* LCD_LIB_H */
view raw lcd_lib.h hosted with ❤ by GitHub
/*
* File: main.c
* Author: adeno
*
* Created on 2018/06/05, 3:25
*/
// CONFIG
#pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB3/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3 // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
//#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "lcd_lib.h"
__EEPROM_DATA('S','p','i','C','h','a','r','L');
__EEPROM_DATA('C','D',' ','v','0','.','4',' ');
//PWM設定(16-)
__EEPROM_DATA(0b01,166, 83,0,1,0,0,0); //16 {0b01,166, 83,0,1}, //3kHz
__EEPROM_DATA(0b01,199,100,0,0,0,0,0); //24 {0b01,199,100,0,0}, //2.5kHz
__EEPROM_DATA(0b01,249,125,0,0,0,0,0); //32 {0b01,249,125,0,0}, //2kHz
__EEPROM_DATA(0b10, 82, 42,1,0,0,0,0); //40 {0b10, 82, 42,1,0}, //1.5kHz
__EEPROM_DATA(0b10,124, 62,1,0,0,0,0); //48 {0b10,124, 62,1,0}, //1kHz
__EEPROM_DATA(0b10,138, 69,0,1,0,0,0); //56 {0b10,138, 69,0,1}, //0.9kHz
__EEPROM_DATA(0b10,155, 78,0,0,0,0,0); //64 {0b10,155, 78,0,0}, //0.8kHz
void initPWM(void);
//void changePWMindex(unsigned char i);
//void changePWM(int ps,int pr,int duty,int d1y,int d1x);
void changePWMeepromindex(unsigned char i);
void initLCD(void);
void initAD(void);
void initSPI(void);
void initTMR0(void);
unsigned char getAD();
#define RBUFSIZE 32
#define RBUFMASK 0x1f
#define RCV_STATE_FUNC 0
#define RCV_STATE_CPWM 1
#define RCV_STATE_CCMD 2
#define RCV_STATE_CDATA 3
#define RCV_CMD_BKLIGHT 0x00
#define RCV_CMD_PWM 0x01
#define RCV_CMD_LCDCMD 0x02
#define RCV_CMD_LCDDATA 0x03
#define RCV_CMD_SW 0x04
#define RCV_CMD_LCDDATAFIN 0x00
#define RCV_DATA_PWM_0 16
#define RCV_DATA_PWM_1 24
#define RCV_DATA_PWM_2 32
#define RCV_DATA_PWM_3 40
#define RCV_DATA_PWM_4 48
#define RCV_DATA_PWM_5 56
#define RCV_DATA_PWM_6 64
#define GTIMER 131
unsigned char ringbuf[RBUFSIZE];
unsigned char wpoi = 0;
unsigned char rpoi = 0;
unsigned char rcvstate = 0;
unsigned char swadcflg = 0;
//struct pwmsetting {
// unsigned char ps;
// unsigned char pr;
// unsigned char duty;
// bool d1y;
// bool d1x;
//};
//struct pwmsetting pwmary[7] = {
// //ps, pr, duty, d1y, d1x
// {0b01,166, 83,0,1}, //3kHz
// {0b01,199,100,0,0}, //2.5kHz
// {0b01,249,125,0,0}, //2kHz
// {0b10, 82, 42,1,0}, //1.5kHz
// {0b10,124, 62,1,0}, //1kHz
// {0b10,138, 69,0,1}, //0.9kHz
// {0b10,155, 78,0,0}, //0.8kHz
// };
void putch(unsigned char c){
lcd_data(c);
return;
}
/*
*
*/
int main(/*int argc, char** argv*/) {
OSCCONbits.IRCF = 0b111; //8MHz
initPWM();
initAD();
initSPI();
initLCD();
initTMR0();
unsigned char adv;
// unsigned char i;
unsigned char oldsw = 0;
unsigned char sw = 0;
lcd_change_col(1);
TMR0 = GTIMER;
INTCONbits.TMR0IE = 1;
while(1){
if(swadcflg == 1){
swadcflg = 0;
adv = getAD();
if(adv > 21 && adv < 26){
//SW1
sw = 1;
}else if(adv > 54 && adv < 64){
//SW2
sw = 2;
}else if(adv > 105 && adv < 118){
//SW3
sw = 3;
}else if(adv > 157 && adv < 170){
//SW4
sw = 4;
}else if(adv > 210 && adv < 218){
//SW5
sw = 5;
}else if(adv > 238 && adv < 242){
//SW6
sw = 6;
}else{
sw = 0;
}
if(sw != oldsw){
lcd_data(sw+'0');
}
oldsw = sw;
}
// __delay_ms(1);
if(wpoi != rpoi){
if(rcvstate == RCV_STATE_FUNC){
if(ringbuf[rpoi] == RCV_CMD_PWM) { rcvstate = RCV_STATE_CPWM; }
else if(ringbuf[rpoi] == RCV_CMD_LCDDATA) { rcvstate = RCV_STATE_CDATA; }
else if(ringbuf[rpoi] == RCV_CMD_LCDCMD) { rcvstate = RCV_STATE_CCMD; }
}else if(rcvstate == RCV_STATE_CPWM){
sw = 0;
if(ringbuf[rpoi] == 0) { sw = RCV_DATA_PWM_0;}
else if(ringbuf[rpoi] == 1) { sw = RCV_DATA_PWM_1;}
else if(ringbuf[rpoi] == 2) { sw = RCV_DATA_PWM_2;}
else if(ringbuf[rpoi] == 3) { sw = RCV_DATA_PWM_3;}
else if(ringbuf[rpoi] == 4) { sw = RCV_DATA_PWM_4;}
else if(ringbuf[rpoi] == 5) { sw = RCV_DATA_PWM_5;}
else if(ringbuf[rpoi] == 6) { sw = RCV_DATA_PWM_6;}
changePWMeepromindex(sw);
rcvstate = RCV_STATE_FUNC;
}else if(rcvstate == RCV_STATE_CCMD){
lcd_cmd(ringbuf[rpoi]);
rcvstate = RCV_STATE_FUNC;
// if(ringbuf[rpoi] == RCV_CMD_LCDDATAFIN) { rcvstate = RCV_STATE_FUNC;}
// else{lcd_cmd(ringbuf[rpoi]);}
}else if(rcvstate == RCV_STATE_CDATA){
lcd_data(ringbuf[rpoi]);
rcvstate = RCV_STATE_FUNC;
// if(ringbuf[rpoi] == RCV_CMD_LCDDATAFIN) { rcvstate = RCV_STATE_FUNC;}
// else{lcd_data(ringbuf[rpoi]);}
}
rpoi = (rpoi+1) & RBUFMASK;
}
//
// __delay_ms(2000);
// changePWMindex(0);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 3kHz ");
//
// __delay_ms(2000);
// changePWMindex(1);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 2.5kHz ");
//
// for(i=0;i<100;i++){
// __delay_ms(200);
// adv = getAD();
// lcd_change_col(1);
// printf("AD> %d ",adv);
// }
//
// __delay_ms(2000);
// changePWMindex(2);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 2kHz ");
//
// __delay_ms(2000);
// changePWMindex(3);
// lcd_change_col(1);
// // 0123456789ABCDEF
// printf("PWM> 1.5kHz ");
//
//// __delay_ms(2000);
//// changePWMindex(4);
//// lcd_change_col(1);
//// // 0123456789ABCDEF
//// printf("PWM> 1kHz ");
////
//// __delay_ms(2000);
//// changePWMindex(5);
//// lcd_change_col(1);
//// // 0123456789ABCDEF
//// printf("PWM> 0.9kHz ");
////
//// __delay_ms(2000);
//// changePWMindex(6);
//// lcd_change_col(1);
//// // 0123456789ABCDEF
//// printf("PWM> 0.8kHz ");
}
return (EXIT_SUCCESS);
}
void initLCD(void){
//RA1 D4
//RA2 D5
//RA3 D6
//RA4 D7
//RA6 RS
//RA7 E
TRISAbits.TRISA1 = 0;
TRISAbits.TRISA2 = 0;
TRISAbits.TRISA3 = 0;
TRISAbits.TRISA4 = 0;
TRISAbits.TRISA6 = 0;
TRISAbits.TRISA7 = 0;
ADCON1 = 0b1110; //4-1:D 0:A
__delay_ms(100);
//LCDの初期化
lcd_init();
//LCDの表示クリア
lcd_clear();
// dist = DIST_LCD;
// 0123456789ABCDEF
// printf("SpiCharLCD v0.1a");
// lcd_change_col(1);
// printf(">");
// lcd_cmd(0xc0);
unsigned char i,d;
for(i=0;i<16;i++){
d = eeprom_read(i);
lcd_data(d);
}
// lcd_data('S'); lcd_data('p'); lcd_data('i');
// lcd_data('C'); lcd_data('h'); lcd_data('a'); lcd_data('r');
// lcd_data('L'); lcd_data('C'); lcd_data('D'); lcd_data(' ');
// lcd_data('v'); lcd_data('0'); lcd_data('.'); lcd_data('1'); lcd_data('b');
}
void initPWM(void){
//PWM
//1)Set the PWM period by writing to the PR2 register.
//周期 = ( PR2 + 1 ) x 4 x 1クロック分の時間 x プリスケーラ値
//10kHz 周期0.1ms = (PR2+1)x4x(1/8MHz)xPrescale
// 10^-4 = S*4*(1/8)*10^-6*P
// 2*10^2 = S*P
// 200 = (PR2+1)*P --- P=1 PR2=199
CCP1CON = 0b00001100; //PWMを使用
// T2CONbits.T2CKPS = 0b00; //プリスケーラ値1
// PR2 = 199;
//2)Set the PWM duty cycle by writing to the
//CCPR1L register and CCP1CON<5:4> bits.
//PWM Duty Cycle = (CCPR1L:CCP1CON<5:4>) •TOSC • (TMR2 Prescale Value)
//50% 0.1ms*50% 0.05ms=50us
//PWM Duty Cycle = V * (1/8MHz) * 1
//DC = V * 1/8 * 10^-6
//50*10^-6 = V*1/8*10^-6
//400 = V
//Vの下位2bitはCCP1x-CCP1Y
//vの上位8bitはCCPR1L
// CCPR1L = 100;
// CCP1CONbits.CCP1Y = 0;
// CCP1CONbits.CCP1X = 0;
//3)Make the CCP1 pin an output by clearing the TRISB<x> bit.
TRISBbits.TRISB3 = 0;
//4)Set the TMR2 prescale value and enable Timer2 by writing to T2CON.
// T2CONbits.TMR2ON = 1;
//50%
//プリスケーラ PR2 CCPR1L CCP1Y CCP1X
//10kHz 1 00 199 100 0 0
//5kHz 4 01 99 50 0 0
//1kHz 16 1x 124 62.5 1 0
// changePWMindex(3);
changePWMeepromindex(40);
}
//void changePWMindex(unsigned char i){
// T2CONbits.TMR2ON = 0;
// T2CONbits.T2CKPS = pwmary[i].ps; //プリスケーラ値1
// PR2 = pwmary[i].pr;
// CCPR1L = pwmary[i].duty;
//
// CCP1CONbits.CCP1Y = pwmary[i].d1y;
// CCP1CONbits.CCP1X = pwmary[i].d1x;
// T2CONbits.TMR2ON = 1;
//}
void changePWMeepromindex(unsigned char i){
T2CONbits.TMR2ON = 0;
T2CONbits.T2CKPS = eeprom_read(i); //プリスケーラ値1
PR2 = eeprom_read(i+1);
CCPR1L = eeprom_read(i+2);
CCP1CONbits.CCP1Y = eeprom_read(i+3);
CCP1CONbits.CCP1X = eeprom_read(i+4);
T2CONbits.TMR2ON = 1;
}
//void changePWM(int ps,int pr,int duty,int d1y,int d1x){
// T2CONbits.TMR2ON = 0;
// T2CONbits.T2CKPS = (unsigned int)ps; //プリスケーラ値1
// PR2 = (unsigned int)pr;
// CCPR1L = (unsigned int)duty;
// CCP1CONbits.CCP1Y = (unsigned int)d1y;
// CCP1CONbits.CCP1X = (unsigned int)d1x;
// T2CONbits.TMR2ON = 1;
//}
void initAD(){
ADCON1 = 0b1110; //4-1:D 0:A
//16TOSC 1 01 10MHz
ADCON1bits.ADCS2 = 1;
ADCON1bits.ADFM = 0; //左づめ
// ADCON0bits.ADCS = 0b01;
// ADCON0bits.CHS = 0b000;
// ADCON0bits.ADON = 1;
ADCON0 = 0b01000001;
}
unsigned char getAD(){
ADCON0bits.GO = 1;
__delay_us(20);
while(ADCON0bits.GO){
}
return ADRESH;
}
void initSPI(){
SSPCONbits.SSPM = 0b0100;
SSPCONbits.SSPEN = 1;
TRISBbits.TRISB1 = 1; //SDI
TRISBbits.TRISB2 = 0; //SDO
TRISBbits.TRISB4 = 1; //SCK
TRISBbits.TRISB5 = 1; //SS
//mode SSPCON(CKP) SSPSTAT(CKE)
//1 0,1 0 0
//3 1,1 1 0
//0 0,0 0,1
//2 1,0 1,1
SSPCONbits.CKP = 1;
SSPSTATbits.CKE = 0;
PIE1bits.SSPIE = 1;
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;
}
void interrupt ISR(void)
{
if(PIR1bits.SSPIF == 1){
PIR1bits.SSPIF = 0;
ringbuf[wpoi] = SSPBUF;
wpoi = (wpoi+1) & RBUFMASK;
// TMR0 = GTIMER;
// INTCONbits.TMR0IE = 1;
}else if(INTCONbits.TMR0IF == 1){
//rcvstate = 10;
swadcflg = 1;
TMR0 = GTIMER;
INTCONbits.TMR0IF = 0;
}
//lcd_data(SSPBUF);
}
void initTMR0(void){
OPTION_REGbits.PS = 0b011;
OPTION_REGbits.PSA = 0;
OPTION_REGbits.T0CS = 0;
}
view raw main.c hosted with ❤ by GitHub

2018年6月3日日曜日

MCP23S09制御用のFON2405E(LEDE・Openwrt)向けドライバ作成

気づけば、毎年同じようなことをやっているような気がするけど。。。
SPI接続のIOエキスパンダ(MCP23S09)を使う+ドライバ作成練習として
7セグ制御を行うドライバを書いてみた




0.前提

・カスタムファーム入りFON2405E
http://continue-to-challenge.blogspot.com/2018/02/fon2405eledeopenwrtspi.html
http://continue-to-challenge.blogspot.com/2018/02/fon2405eledeopenwrtspi144.html

・MCP23S09
3.3Vで動くSPI-IOエキスパンダ
https://www.microchip.com/wwwproducts/jp/MCP23S09


1.手順

(1)eclipceで空のプロジェクト作成
  Makefile project → Empty Project
(2)ソースファイル・Makefile作成
  ソースは末尾のgist参照、Makefileは


(3)ビルド
(4)ターゲットボードに転送
  scpとかで
(5)動作確認
  insmod /tmp/mcp23s09_7seg.ko


2.ソース

/*
* mcp23s09_7seg_drv.c
*
* Created on: 2018/06/03
* Author: adeno
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/uaccess.h> //copy_from_user
#include <linux/gpio.h>
#include <linux/spi/spi.h>
MODULE_AUTHOR("Adeno");
MODULE_LICENSE("GPL v2");
//=======================================================================================
/* ドライバ */
#define DRV_NUM_DEVS 1 /* このドライバが制御するデバイスの数 */
#define DRV_DEVNAME "mcp7dDriver" /* このデバイスドライバの名称 */
#define DRV_MAJOR 0 /* メジャー番号だが自動設定なので0 */
#define DRV_MINOR 0 /* マイナー番号のベース番号 */
#define DRV_GPIO_MAPNAME "mcp7d_gpio_map"
/* SPI MCP23S09設定 */
#define MCP_PACKET_SIZE 3
const uint8_t MCP23S09_OPCODE = 0b01000000; //dev:0100000 RW
const uint8_t MCP23S09_OPCODE_WRITE = 0b0;
const uint8_t MCP23S09_OPCODE_READ = 0b1;
const uint8_t MCP23S09_IODIR_REG = 0x00;
const uint8_t MCP23S09_GPPU_REG = 0x06;
const uint8_t MCP23S09_GPIO_REG = 0x09;
const uint8_t MCP23S09_OLAT_REG = 0x0A;
/* LED パターン */
// DP A
#define LED7SEG_OFF 0b11111111
#define LED7SEG_0 0b11000000
#define LED7SEG_1 0b11111001
#define LED7SEG_2 0b10100100
#define LED7SEG_3 0b10110000
#define LED7SEG_4 0b10011001
#define LED7SEG_5 0b10010010
#define LED7SEG_6 0b10000010
#define LED7SEG_7 0b11111000
#define LED7SEG_8 0b10000000
#define LED7SEG_9 0b10010000
#define LED7SEG_A 0b10001000
#define LED7SEG_b 0b10000011
#define LED7SEG_C 0b11000110
#define LED7SEG_d 0b10100001
#define LED7SEG_E 0b10000110
#define LED7SEG_F 0b10001110
#define LED7SEG_dot 0b01111111
// hgfedcba
//const uint8_t LED10PTN[10] = {LED7SEG_0,LED7SEG_1,LED7SEG_2,LED7SEG_3,LED7SEG_4,LED7SEG_5,
// LED7SEG_6,LED7SEG_7,LED7SEG_8,LED7SEG_9};
const uint8_t LED16PTN[16] = {LED7SEG_0,LED7SEG_1,LED7SEG_2,LED7SEG_3,LED7SEG_4,LED7SEG_5,
LED7SEG_6,LED7SEG_7,LED7SEG_8,LED7SEG_9,
LED7SEG_A,LED7SEG_b,LED7SEG_C,LED7SEG_d,LED7SEG_E,LED7SEG_F};
//=======================================================================================
/* ドライバ */
static int _mcp7d_major = DRV_MAJOR;
static int _mcp7d_minor = DRV_MINOR;
/* SPI */
struct drvdata {
struct spi_device *spi;
struct mutex lock;
unsigned char tx[MCP_PACKET_SIZE];
unsigned char rx[MCP_PACKET_SIZE];
struct spi_transfer xfer;
struct spi_message msg;
dev_t md_dev;
struct class *drv_class;
struct cdev *drv_cdev_array;
} ____cacheline_aligned;
static struct drvdata mcp7d;
static struct spi_board_info mcp7d_info = {
.modalias = "mcp",
.max_speed_hz = 1000000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_3,
};
static struct spi_device_id mcp_id[] = {
{ "mcp", 0 },
{ },
};
MODULE_DEVICE_TABLE(spi, mcp_id);
/* Parameters Setting */
static int gpiono = 9;
static int show_debug = 0;
static int hexmode = 0;
//=======================================================================================
/* プロトタイプ宣言 */
static unsigned int mcp7d_set_value( struct drvdata *data,unsigned int v);
static void spi_remove_device(struct spi_master *master, unsigned int cs);
static int mcp7d_probe(struct spi_device *spi);
static int mcp7d_remove(struct spi_device *spi);
static int mcp7d_open(struct inode *inode, struct file *filep);
static int mcp7d_release(struct inode *inode, struct file *filep);
static ssize_t mcp7d_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos);
static int mcp7d_register_dev(void);
static int mcp7d_init(void);
static void mcp7d_exit(void);
//=======================================================================================
/* SPIデバイス */
static struct spi_driver mcp_driver = {
.driver = {
.name = DRV_DEVNAME,
.owner = THIS_MODULE,
},
.id_table = mcp_id,
.probe = mcp7d_probe,
.remove = mcp7d_remove,
};
/* キャラクタデバイス */
struct file_operations mcp7d_fops = {
.open = mcp7d_open,
.release = mcp7d_release,
.write = mcp7d_write,
};
//=======================================================================================
static unsigned int mcp7d_set_value( struct drvdata *data,unsigned int v)
{
unsigned int r = 0;
mutex_lock( &data->lock );
data->tx[0] = MCP23S09_OPCODE;
data->tx[1] = MCP23S09_OLAT_REG;
if((v >= 0) && (v < 16)) data->tx[2] = LED16PTN[v];//0xFF; //全て1
else data->tx[2] = LED7SEG_OFF;
if( spi_sync( data->spi, &data->msg) ) {
if(show_debug) printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mutex_unlock(&data->lock);
return r;
}
/**
* SPIデバイスの削除
*/
static void spi_remove_device(struct spi_master *master, unsigned int cs)
{
struct device *dev;
char str[128];
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
if(show_debug) printk(KERN_INFO "[spi_remove_device] %s\n",str);
// SPIデバイスを探す
dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
// あったら削除
if( dev ){
if(show_debug) printk(KERN_INFO "Delete %s\n", str);
device_del(dev);
}
}
/**
* SPI通信初期化
*/
static int mcp7d_probe(struct spi_device *spi)
{
struct mcp_drvdata *data;
int retval;
if(show_debug) printk(KERN_INFO "mcp7d spi probe\n");
/* SPIを設定する */
spi->max_speed_hz = mcp7d_info.max_speed_hz;
spi->mode = mcp7d_info.mode;
spi->bits_per_word = 8;
if( spi_setup( spi ) ) {
printk(KERN_ERR "spi_setup returned error\n");
return -ENODEV;
}
mcp7d.spi = spi;
mutex_init( &mcp7d.lock );
mcp7d.xfer.tx_buf = mcp7d.tx;
mcp7d.xfer.rx_buf = 0;//data->rx;
mcp7d.xfer.bits_per_word = 8;
mcp7d.xfer.len = MCP_PACKET_SIZE;
mcp7d.xfer.cs_change = 0;
mcp7d.xfer.delay_usecs = 0;
mcp7d.xfer.speed_hz = 1000000;
spi_message_init_with_transfers( &mcp7d.msg, &mcp7d.xfer, 1 );
spi_set_drvdata( spi, &mcp7d );
mutex_lock( &mcp7d.lock );
mcp7d.tx[0] = MCP23S09_OPCODE;
mcp7d.tx[1] = MCP23S09_IODIR_REG;
mcp7d.tx[2] = 0x00; //全て出力
if( spi_sync( mcp7d.spi, &mcp7d.msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mcp7d.tx[0] = MCP23S09_OPCODE;
mcp7d.tx[1] = MCP23S09_OLAT_REG;
mcp7d.tx[2] = LED7SEG_dot;//LED7SEG_OFF; //全て1
if( spi_sync( mcp7d.spi, &mcp7d.msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mutex_unlock(&mcp7d.lock);
return 0;
}
/**
* SPI通信終了
*/
static int mcp7d_remove(struct spi_device *spi)
{
if(show_debug) printk(KERN_INFO "[mcp7d spi_remove]\n");
struct drvdata *drd = spi_get_drvdata(spi);
mutex_lock( &drd->lock );
drd->tx[0] = MCP23S09_OPCODE;
drd->tx[1] = MCP23S09_IODIR_REG;
drd->tx[2] = 0x00; //全て出力
if( spi_sync( drd->spi, &drd->msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
drd->tx[0] = MCP23S09_OPCODE;
drd->tx[1] = MCP23S09_OLAT_REG;
drd->tx[2] = LED7SEG_OFF; //全て1
if( spi_sync( drd->spi, &drd->msg) ) {
printk(KERN_INFO "spi_sync_transfer returned non zero\n" );
}
mutex_unlock(&drd->lock);
spi_set_drvdata(drd->spi, NULL);
drd->spi = NULL;
mutex_destroy(&mcp7d.lock);
if(gpiono != 0) gpio_free(gpiono);
return 0;
}
/**
* デバイスオープン時の処理
*/
static int mcp7d_open(struct inode *inode, struct file *filep)
{
if(show_debug) printk(KERN_INFO "[mcp7d_open]\n");
filep->private_data = &mcp7d;
return 0;
}
/**
* デバイスクローズ時の処理
*/
static int mcp7d_release(struct inode *inode, struct file *filep)
{
if(show_debug) printk(KERN_INFO "[mcp7d_release]\n");
struct drvdata *drd = filep->private_data;
if ((drd == NULL) || (drd->spi == NULL))
return -ENODEV;
filep->private_data = NULL;
return 0;
}
/**
* デバイス書き込み処理
*/
static ssize_t mcp7d_write(struct file *filep, const char __user *buf, size_t count, loff_t *f_pos)
{
char cvalue;
int i;
struct drvdata *drd = filep->private_data;
if ((drd == NULL) || (drd->spi == NULL))
return -ENODEV;
// struct mcp_drvdata *data = (struct mcp_drvdata *)dev_get_drvdata(filep->private_data);
if(count > 0) {
if(gpiono != 0) gpio_set_value(gpiono,1);
if(copy_from_user( &cvalue, buf, sizeof(char) )) {
return -EFAULT;
}
if((cvalue >=0) && (cvalue <= 9)) mcp7d_set_value(drd,cvalue);
else if(('0' <= cvalue) && (cvalue <= '9')) mcp7d_set_value(drd,cvalue - '0');
else{
if(hexmode){
if(('A' <= cvalue) && (cvalue <= 'F')) mcp7d_set_value(drd,cvalue - 'A' + 10);
else if(('a' <= cvalue) && (cvalue <= 'f')) mcp7d_set_value(drd,cvalue - 'a' + 10);
}
else if(show_debug) printk(KERN_ALERT "Can not display %d\n", cvalue );
}
if(gpiono != 0) gpio_set_value(gpiono,0);
return sizeof(char);
}
return 0;
}
/**
* デバイスドライバをカーネルに登録
*/
static int mcp7d_register_dev(void)
{
int retval;
// dev_t dev;
size_t size;
int i;
/* 空いているメジャー番号を使ってメジャー&
マイナー番号をカーネルに登録する */
retval = alloc_chrdev_region(
&mcp7d.md_dev, /* 結果を格納するdev_t構造体 */
DRV_MINOR, /* ベースマイナー番号 */
DRV_NUM_DEVS, /* デバイスの数 */
DRV_DEVNAME /* デバイスドライバの名前 */
);
if( retval < 0 ) {
printk(KERN_ERR "alloc_chrdev_region failed.\n" );
return retval;
}
_mcp7d_major = MAJOR(mcp7d.md_dev);
/* デバイスクラスを作成する */
mcp7d.drv_class = class_create(THIS_MODULE,DRV_DEVNAME);
if(IS_ERR(mcp7d.drv_class))
return PTR_ERR(mcp7d.drv_class);
/* cdev構造体の用意 */
size = sizeof(struct cdev) * DRV_NUM_DEVS;
mcp7d.drv_cdev_array = (struct cdev*)kmalloc(size, GFP_KERNEL);
/* デバイスの数だけキャラクタデバイスを登録する */
/* ただし7セグLEDは1個しかない */
for( i = 0; i < DRV_NUM_DEVS; i++ ) {
dev_t devno = MKDEV(_mcp7d_major, _mcp7d_minor+i);
/* キャラクタデバイスとしてこのモジュールをカーネルに登録する */
cdev_init(&(mcp7d.drv_cdev_array[i]), &mcp7d_fops);
mcp7d.drv_cdev_array[i].owner = THIS_MODULE;
if( cdev_add( &(mcp7d.drv_cdev_array[i]), devno, 1) < 0 ) {
/* 登録に失敗した */
printk(KERN_ERR "cdev_add failed minor = %d\n", _mcp7d_minor+i );
}
else {
/* デバイスノードの作成 */
device_create(
mcp7d.drv_class,
NULL,
devno,
NULL,
DRV_DEVNAME"%u",_mcp7d_minor+i
);
}
}
return 0;
}
/**
* モジュールの初期化処理
*/
static int mcp7d_init(void)
{
int retval;
int i;
/* 開始のメッセージ */
printk(KERN_INFO "%s loading...\n", DRV_DEVNAME );
if(gpiono != 0){
/* GPIOレジスタがマップ可能か調べる */
retval = gpio_request_one(gpiono, GPIOF_OUT_INIT_LOW, DRV_GPIO_MAPNAME);
if (retval) {
printk(KERN_ERR "Unable to request GPIOs: %d\n", retval);
return retval;
}
for( i=0; i<10; i++ ) {
gpio_set_value(gpiono,1);
msleep(10);
gpio_set_value(gpiono,0);
msleep(10);
}
}
/* デバイスドライバをカーネルに登録 */
retval = mcp7d_register_dev();
if( retval != 0 ) {
printk( KERN_ALERT "mcp7d driver register failed.\n");
return retval;
}
if(show_debug)
printk( KERN_INFO "mcp7d driver register sccessed.\n");
struct spi_master *master;
struct spi_device *spi_device;
spi_register_driver(&mcp_driver);
mcp7d_info.bus_num = 0;
mcp7d_info.chip_select = 1;
master = spi_busnum_to_master(mcp7d_info.bus_num);
if( ! master ) {
printk( KERN_ERR "spi_busnum_to_master returned NULL\n");
spi_unregister_driver(&mcp_driver);
return -ENODEV;
}
spi_remove_device(master, mcp7d_info.chip_select);
spi_device = spi_new_device( master, &mcp7d_info );
if( !spi_device ) {
printk(KERN_ERR "spi_new_device returned NULL\n" );
spi_unregister_driver(&mcp_driver);
return -ENODEV;
}
return 0;
}
/**
* モジュールの終了処理
*/
static void mcp7d_exit(void)
{
int i;
dev_t devno;
if(show_debug) printk(KERN_INFO "[mcp7d_exit]\n");
if(show_debug) printk(KERN_INFO "[cdev_del]\n");
/* キャラクタデバイスの登録解除 */
for( i = 0; i < DRV_NUM_DEVS; i++ ) {
cdev_del(&(mcp7d.drv_cdev_array[i]));
devno = MKDEV(_mcp7d_major, _mcp7d_minor+i);
device_destroy(mcp7d.drv_class, devno);
}
/* メジャー番号/マイナー番号を取り除く */
devno = MKDEV(_mcp7d_major,_mcp7d_minor);
unregister_chrdev_region(devno, DRV_NUM_DEVS);
/* デバイスノードを取り除く */
class_destroy( mcp7d.drv_class );
kfree(mcp7d.drv_cdev_array);
if(show_debug) printk(KERN_INFO "[mcp_del]\n");
spi_unregister_driver(&mcp_driver);
}
module_init(mcp7d_init);
module_exit(mcp7d_exit);
module_param( show_debug, int, S_IRUSR | S_IRGRP | S_IROTH );
module_param( gpiono, int, S_IRUSR | S_IRGRP | S_IROTH );
module_param( hexmode, int, S_IRUSR | S_IRGRP | S_IROTH );
view raw mcp23s09_7seg.c hosted with ❤ by GitHub

3.参考
 ・Raspberry Piで学ぶARMデバイスドライバープログラミング
 ・LINUXデバイスドライバ 第3版
 ・ci-bridge-spi
https://android.googlesource.com/kernel/msm/+/android-msm-hammerhead-3.4-kk-r1/drivers/misc/ci-bridge-spi.c
 ・spike
https://github.com/scottellis/spike/blob/master/spike.c


2018年5月21日月曜日

FON2405Eのフラッシュメモリを交換してOpenwrt導入

LEDEとOpenWrtが統合したらしいので、再度環境構築手順をまとめてみた。

以前の方法
http://continue-to-challenge.blogspot.jp/2017/11/fon2405eledeopenwrt.html
からあまり変更がないかもしれない。

手順0.フラッシュメモリ交換

リスクをとって簡略化した方法で

0.u-boot他を旧フラッシュからバックアップ

cat /dev/mtdblock0 > /tmp/mtdblock0.img  <Uboot>
cat /dev/mtdblock1 > /tmp/mtdblock1.img  <Config>
cat /dev/mtdblock2 > /tmp/mtdblock2.img  <RF>

1.通電状態でフラッシュを交換する(ハイリスク!)
cp /tmp/mtdblock0.img /dev/mtdblock0
cp /tmp/mtdblock1.img /dev/mtdblock1
cp /tmp/mtdblock2.img /dev/mtdblock2

手順1.OpenWrtのカーネルソース入手

ここは変更なし
git clone https://git.lede-project.org/source.git
./scripts/feeds update -a
./scripts/feeds install -a

手順2 FON2405E用にカスタマイズ・Device Tree Source (dts)を作成


ここも変更なし


手順3 カーネルイメージ作成

適宜、設定を行う

make menuconfig
make kernel_menuconfig
そして
make -j4 V=99
openwrt-ramips-rt305x-fon2405ekai-initramfs-kernel.bin
openwrt-ramips-rt305x-fon2405ekai-squashfs-sysupgrade.bin
が作成される

手順4 ファームアップ

u-bootからのファームアップのあと、sysupgradeを実施
カーネルが4.14.41になったのかー。

メモ(git diff)
git diff origin/master..HEAD > FON2405EKAI.patch

2018年2月17日土曜日

FON2405E(LEDE・Openwrt)でSPI〜1.44インチのグラフィック液晶制御(高速化)


前回作ったものが表示が遅い+メモリリークで落ちるため、いくつか見直しを行った
実際の表示はわからないけど、LCDへの書き出し処理は大体16fpsくらい できているみたい

フリー素材のGIF動画を使わせてもらった「いいね!」
https://www.pakutaso.com/gif/gifpost-135.html



やったことは
・vecterの開放(vector<uint8_t>().swap(tbx);)
・SPIの開放忘れ(free(&spi);)

やってもあまり効果なかったこと
・SPI_IOC_MESSAGEのサイズ 結局1度に送れるのは4096Byte?


差分はここんな感じ
/*
* LibST7735S.cpp
*
* Created on: 2018/02/05
* Author: adeno
*/
#include "LibST7735S.h"
#define LCD_X_OFFSET 2
#define LCD_Y_OFFSET 1
LibST7735S::LibST7735S(int SPI_Bus, int SPI_Ce, int SPI_Speed,uint8_t SPI_Mode,int a0, int rst,
uint8_t width,uint8_t height) {
this->SPI_Bus = SPI_Bus;
this->SPI_Ce = SPI_Ce;
this->SPI_Speed = SPI_Speed;
this->SPI_Mode = SPI_Mode;
this->a0 = a0;
this->rst = rst;
spi = new LibSpi(this->SPI_Bus,this->SPI_Ce,this->SPI_Speed,this->SPI_Mode);
this->createDisplay(width,height,COLOR_FORMAT_18BIT);
}
LibST7735S::~LibST7735S() {
dcpin->portClose();
rstpin->portClose();
delete(spi);
}
void LibST7735S::createDisplay(uint8_t width,uint8_t height,uint8_t color_format){
this->width = width;
this->height = height;
/* Reset Pin */
if(this->rst != -1)
{
this->rstpin = new LibGpio(this->rst,this->OUTPUT); //RST 出力方向
this->rstpin->setVal(this->HIGH);
this->HWReset();
}
/* Data/Command pin */
this->dcpin = new LibGpio(this->a0,this->OUTPUT); //RST 出力方向
this->dcpin->setVal(this->HIGH);
/* Initialzie display */
this->writeCommand(CMD_SW_RESET); usleep(150*1000); //150ms
this->writeCommand(CMD_SLEEP_OUT); usleep(150*1000); //150ms
this->setMADCTL(0,0,0,0,0,0);
// setWindow(1, 1, width, height);
this->setColorFormat(color_format);
// this->writeCommand(CMD_TEON); this->writeData(0x01); usleep(100*1000); //100ms
writeCommand(CMD_DISPLAY_ON); usleep(100*1000); //100ms
}
void LibST7735S::fillScreen(uint8_t red, uint8_t green, uint8_t blue){
this->fillRect(0,0,this->width,this->height,red, green, blue);
}
void LibST7735S::fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h,
uint8_t red, uint8_t green, uint8_t blue){
vector<uint8_t> tbx(w*h*3);
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
int i=0;
for(int wy=0; wy<h; wy++){
for(int wx=0; wx<w; wx++){
tbx[i] = blue;
tbx[i+1] = green;
tbx[i+2] = red;
// tbx.push_back(blue); tbx.push_back(green); tbx.push_back(red);
i+=3;
}
}
activeRAMWrite();
this->writeData_vector2(&tbx);
vector<uint8_t>().swap(tbx);
}
void LibST7735S::drawPx(uint8_t x, uint8_t y,uint8_t red, uint8_t green, uint8_t blue){
/* Check x and y */
// if((x >= this->width) || (y >= this->height)) return;
uint8_t tbram[3] = {blue,green,red};
this->setWindow(LCD_X_OFFSET+x, LCD_X_OFFSET+y, LCD_X_OFFSET+x, LCD_X_OFFSET+y);
activeRAMWrite();
this->writeData(3,tbram);
}
void LibST7735S::drawImage(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d){
//d・・・BGR
vector<uint8_t> tbx(w*h*3);//,tbx2;
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
activeRAMWrite();
int i=0;
// for(int wy=0; wy<h; wy++){
// for(int wx=0; wx<w; wx++){
// tbx.push_back((uint8_t)d[d.size()-(i+1)]); //blue
// tbx.push_back((uint8_t)d[d.size()-(i+2)]); //green
// tbx.push_back((uint8_t)d[d.size()-(i)]); //red
// i=i+3;
// }
// reverse_copy(tbx.begin(),tbx.end(),back_inserter(tbx2));
//// copy(tbx.begin(),tbx.end(),back_inserter(tbx2));
// tbx.clear();
// }
// if(tbx2.size() > 0){
// this->writeData_vector2(tbx2);
// tbx2.clear();
// }
vector<char> dp = *d;
int index,s=d->size();
for(int dy=0; dy<h; dy++){
for(int dx=0; dx<3*w; dx+=3){
index = s -3*w*dy +dx -3*w;
tbx[i] = (uint8_t)dp[index];
tbx[i+1] = (uint8_t)dp[index+1];
tbx[i+2] = (uint8_t)dp[index+2];
// tbx.push_back((uint8_t)d[index]); //blue
// tbx.push_back((uint8_t)d[index+1]); //green
// tbx.push_back((uint8_t)d[index+2]); //red
i+=3;
}
}
this->writeData_vector2(&tbx);
tbx.clear();
}
void LibST7735S::drawImage2(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d){
//d・・・BGR
vector<uint8_t> tbx(w*h*3);
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
activeRAMWrite();
int i=0;
vector<char> dp = *d;
int index,s=d->size();
for(int dy=0; dy<h; dy++){
for(int dx=0; dx<3*w; dx+=3){
index = s -3*w*dy +dx -3*w;
tbx[i] = (uint8_t)dp[index];
tbx[i+1] = (uint8_t)dp[index+1];
tbx[i+2] = (uint8_t)dp[index+2];
i+=3;
}
}
this->writeData_vector3(&tbx);
tbx.clear();
}
void LibST7735S::drawImage3(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<uint8_t>* d){
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
activeRAMWrite();
this->writeData_vector2(d);
}
//==[private]============================================================================
void LibST7735S::setMADCTL(uint8_t MY,uint8_t MX,uint8_t MV,uint8_t ML,
uint8_t RGB,uint8_t MH){
//MY Row Address Order
//MX Column Address Order
//MV Row/Column Exchange
//ML Vertical Refresh Order
//RGB RGB-BGR ORDER
//MH Horizontal Refresh Order
this->writeCommand(CMD_MEMORY_DATA_ACCESS_CONTROL);
uint8_t d = 0;
if(MY > 0) d += 0x80;
if(MX > 0) d += 0x40;
if(MV > 0) d += 0x20;
if(ML > 0) d += 0x10;
if(RGB > 0) d += 0x08;
if(MH > 0) d += 0x04;
this->writeData(d);
}
void LibST7735S::setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2){
vector<uint8_t> tbx = {0, x1, 0, x2};
vector<uint8_t> tby = {0, y1, 0, y2};
this->writeCommand(CMD_COLUMN_ADRRESS_SET);
this->writeData_vector(&tbx);
this->writeCommand(CMD_ROW_ADRRESS_SET);
this->writeData_vector(&tby);
vector<uint8_t>().swap(tbx);
vector<uint8_t>().swap(tby);
}
void LibST7735S::setColorFormat(uint8_t color_format){
switch(color_format)
{ default: color_format = COLOR_FORMAT_18BIT; break;
case COLOR_FORMAT_18BIT: break;
case COLOR_FORMAT_16BIT: break;
case COLOR_FORMAT_12BIT: break;
}
this->color_format = color_format;
writeCommand(CMD_INTERFACE_PIXEL_FORMAT);
writeData(color_format);
}
void LibST7735S::setGamma(uint8_t state){
switch(state)
{ /* [GS_Pin = 0] Checked on hardware! */
default: state = 1; break;
case 2: break;
case 4: break;
case 8: break;
}
this->writeCommand(CMD_GAMMA_SET);
this->writeData(state);
}
void LibST7735S::activeRAMWrite(){
this->writeCommand(CMD_MEMORY_WRITE);
this->dcpin->setVal(this->HIGH);
}
void LibST7735S::writeData(int len, uint8_t *txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer(len,txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData_vector(vector<uint8_t>* txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer_vector(txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData_vector2(vector<uint8_t>* txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer_vector2(txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData_vector3(vector<uint8_t>* txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer_vector3(txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData(uint8_t data){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer(data);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeCommand(uint8_t cmd){
try{
this->dcpin->setVal(this->LOW);
spi->transfer(cmd);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::HWReset(){
if(this->rst == -1) return;
this->rstpin->setVal(this->HIGH); usleep(10*1000); //10ms
this->rstpin->setVal(this->LOW); usleep(10*1000); //10ms
this->rstpin->setVal(this->HIGH); usleep(150*1000); //150ms
}
view raw LibST7735S.cpp hosted with ❤ by GitHub
/*
* LibST7735S.h
*
* Created on: 2018/02/05
* Author: adeno
*/
#ifndef LIBST7735S_H_
#define LIBST7735S_H_
#include <stdint.h> //uint8_t
#include <string>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include "LibSpi.h"
#include "LibGpio.h"
class LibST7735S {
private:
/* SPI */
LibSpi *spi;
int SPI_Bus;
int SPI_Ce;
int SPI_Speed;
uint8_t SPI_Mode;
/* GPIO */
const static int OUTPUT = 0;
const static int INPUT = 1;
const static int HIGH = 1;
const static int LOW = 0;
/* Reset Pin */
LibGpio *rstpin;
/* Data/Command Pin */
LibGpio *dcpin;
/* st7735s Define*/
const static uint8_t CMD_NOP = 0x00;
const static uint8_t CMD_SW_RESET = 0x01;
const static uint8_t CMD_SLEEP_OUT = 0x11;
const static uint8_t CMD_INVOFF = 0x20;
const static uint8_t CMD_INVON = 0x21;
const static uint8_t CMD_GAMMA_SET = 0x26;
const static uint8_t CMD_DISPLAY_OFF = 0x28;
const static uint8_t CMD_DISPLAY_ON = 0x29;
const static uint8_t CMD_COLUMN_ADRRESS_SET = 0x2A;
const static uint8_t CMD_ROW_ADRRESS_SET = 0x2B;
const static uint8_t CMD_MEMORY_WRITE = 0x2C;
const static uint8_t CMD_TEOFF = 0x34;
const static uint8_t CMD_TEON = 0x35;
const static uint8_t CMD_MEMORY_DATA_ACCESS_CONTROL = 0x36;
const static uint8_t CMD_INTERFACE_PIXEL_FORMAT = 0x3A;
const static uint8_t COLOR_FORMAT_12BIT = 0b011;
const static uint8_t COLOR_FORMAT_16BIT = 0b101;
const static uint8_t COLOR_FORMAT_18BIT = 0b110;
/* st7735s RAW Display Type */
int a0; /* Data/Command line */
int rst; /* Reset line */
uint8_t width; /* Currently used width */
uint8_t height; /* Currently used height */
uint8_t color_format;
void createDisplay(uint8_t width,uint8_t height,uint8_t color_format);
void HWReset();
void setMADCTL(uint8_t MY,uint8_t MX,uint8_t MV,uint8_t ML,uint8_t RGB,uint8_t MH);
void setGamma(uint8_t state);
void setColorFormat(uint8_t color_format);
void setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
void activeRAMWrite();
void writeData(uint8_t data);
void writeData(int len, uint8_t *txbuf);
void writeData_vector(vector<uint8_t>* txbuf);
void writeData_vector2(vector<uint8_t>* txbuf);
void writeData_vector3(vector<uint8_t>* txbuf);
void writeCommand(uint8_t cmd);
public:
LibST7735S(int SPI_Bus, int SPI_Ce, int SPI_Speed,uint8_t SPI_Mode,int a0, int rst,uint8_t width,uint8_t height);
void fillScreen(uint8_t red, uint8_t green, uint8_t blue);
void fillRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height,uint8_t red, uint8_t green, uint8_t blue);
void drawPx(uint8_t x, uint8_t y,uint8_t red, uint8_t green, uint8_t blue);
void drawImage(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d);
void drawImage2(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d);
void drawImage3(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<uint8_t>* d);
virtual ~LibST7735S();
};
#endif /* LIBST7735S_H_ */
view raw LibST7735S.h hosted with ❤ by GitHub

メモ
動画やGIFから連続したBMPを作成する
 convert -coalesce -resize 128x128! cinemagraph.gif +adjoin SL%02d.bmp
色を24bitにする
 mogrify -type truecolor SL*.bmp

参考
http://www.c-lang.net/general43/index.html
http://yoppa.org/blog/5862.html
http://cdecrement.blog.fc2.com/blog-entry-65.html

2018年2月11日日曜日

FON2405E(LEDE・Openwrt)でSPI〜1.44インチのグラフィック液晶制御

SPIの動作確認を兼ねて昔に入手した1.44インチのTFT液晶モジュール(多分Z144SN005/aitendo)を繋いでみた。
本当は、IOエキスパンダ+キャラクタ液晶でさっくり確認するつもりだったのだけど、
ヘマしたので・・・。

今回は先に結果から どーん




Z144SN005の情報
単体   http://www.aitendo.com/product/11546
変換基板 http://www.aitendo.com/product/11663
 グラフィックICはST7735Sらしい
サイズ  128x128

データシートと先人たちのライブラリもありがたく確認させてもらう
データシート https://www.crystalfontz.com/controllers/Sitronix/ST7735S
      v1.3が最新?
ライブラリ https://github.com/adafruit/Adafruit-ST7735-Library
     https://github.com/michal037/driver-ST7735S

接続
LCD側--------FON側
VLED--------5V
RST--------VCC(3.3V)
A0--------GPIO9 データ/コマンド切り替え
SDA--------SDO(Master Output)
SCK--------SCK
VCC--------VCC(3.3V)
CS--------GPIO12(CS#2)
GND--------GND

SPI制御
/dev/spidev0.1をioctlで制御
ネット上にサンプルいっぱいあるから省略

A0(データ/コマンド切り替え)制御
 こちらはGPIOを割り当てる(sysfsというのだろうか)
 https://wiki.openwrt.org/doc/hardware/port.gpio
 https://elinux.org/RPi_GPIO_Code_Samples
 汎用性とかありそうなので・・・。
 ただし、ofstreamを使うとタイミングがずれたり出力されないことがあった
 たぶん書き込み処理が最適化されてキャッシュされたりなんかだろう
 あまり突き詰めたくないので、上記例の通りopen/writeを使う

ST7735S用ライブラリ
 先人たちの偉業を参考に作成
 現状、若干モジュールに特化してしまっている感もある

/*
* LibST7735S.cpp
*
* Created on: 2018/02/05
* Author: adeno
*/
#include "LibST7735S.h"
#define LCD_X_OFFSET 2
#define LCD_Y_OFFSET 1
LibST7735S::LibST7735S(int SPI_Bus, int SPI_Ce, int SPI_Speed,uint8_t SPI_Mode,int a0, int rst,
uint8_t width,uint8_t height) {
this->SPI_Bus = SPI_Bus;
this->SPI_Ce = SPI_Ce;
this->SPI_Speed = SPI_Speed;
this->SPI_Mode = SPI_Mode;
this->a0 = a0;
this->rst = rst;
spi = new LibSpi(this->SPI_Bus,this->SPI_Ce,this->SPI_Speed,this->SPI_Mode);
this->createDisplay(width,height,COLOR_FORMAT_18BIT);
}
LibST7735S::~LibST7735S() {
dcpin->portClose();
rstpin->portClose();
delete(spi);
}
void LibST7735S::createDisplay(uint8_t width,uint8_t height,uint8_t color_format){
this->width = width;
this->height = height;
/* Reset Pin */
if(this->rst != -1)
{
this->rstpin = new LibGpio(this->rst,this->OUTPUT); //RST 出力方向
this->rstpin->setVal(this->HIGH);
this->HWReset();
}
/* Data/Command pin */
this->dcpin = new LibGpio(this->a0,this->OUTPUT); //RST 出力方向
this->dcpin->setVal(this->HIGH);
/* Initialzie display */
this->writeCommand(CMD_SW_RESET); usleep(150*1000); //150ms
this->writeCommand(CMD_SLEEP_OUT); usleep(150*1000); //150ms
this->setMADCTL(0,0,0,0,0,0);
// setWindow(1, 1, width, height);
this->setColorFormat(color_format);
// this->writeCommand(CMD_TEON); this->writeData(0x01); usleep(100*1000); //100ms
writeCommand(CMD_DISPLAY_ON); usleep(100*1000); //100ms
}
void LibST7735S::fillScreen(uint8_t red, uint8_t green, uint8_t blue){
this->fillRect(0,0,this->width,this->height,red, green, blue);
}
void LibST7735S::fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h,
uint8_t red, uint8_t green, uint8_t blue){
vector<uint8_t> tbx(w*h*3);
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
int i=0;
for(int wy=0; wy<h; wy++){
for(int wx=0; wx<w; wx++){
tbx[i] = blue;
tbx[i+1] = green;
tbx[i+2] = red;
// tbx.push_back(blue); tbx.push_back(green); tbx.push_back(red);
i+=3;
}
}
activeRAMWrite();
this->writeData_vector2(&tbx);
vector<uint8_t>().swap(tbx);
}
void LibST7735S::drawPx(uint8_t x, uint8_t y,uint8_t red, uint8_t green, uint8_t blue){
/* Check x and y */
// if((x >= this->width) || (y >= this->height)) return;
uint8_t tbram[3] = {blue,green,red};
this->setWindow(LCD_X_OFFSET+x, LCD_X_OFFSET+y, LCD_X_OFFSET+x, LCD_X_OFFSET+y);
activeRAMWrite();
this->writeData(3,tbram);
}
void LibST7735S::drawImage(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d){
//d・・・BGR
vector<uint8_t> tbx(w*h*3);//,tbx2;
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
activeRAMWrite();
int i=0;
// for(int wy=0; wy<h; wy++){
// for(int wx=0; wx<w; wx++){
// tbx.push_back((uint8_t)d[d.size()-(i+1)]); //blue
// tbx.push_back((uint8_t)d[d.size()-(i+2)]); //green
// tbx.push_back((uint8_t)d[d.size()-(i)]); //red
// i=i+3;
// }
// reverse_copy(tbx.begin(),tbx.end(),back_inserter(tbx2));
//// copy(tbx.begin(),tbx.end(),back_inserter(tbx2));
// tbx.clear();
// }
// if(tbx2.size() > 0){
// this->writeData_vector2(tbx2);
// tbx2.clear();
// }
vector<char> dp = *d;
int index,s=d->size();
for(int dy=0; dy<h; dy++){
for(int dx=0; dx<3*w; dx+=3){
index = s -3*w*dy +dx -3*w;
tbx[i] = (uint8_t)dp[index];
tbx[i+1] = (uint8_t)dp[index+1];
tbx[i+2] = (uint8_t)dp[index+2];
// tbx.push_back((uint8_t)d[index]); //blue
// tbx.push_back((uint8_t)d[index+1]); //green
// tbx.push_back((uint8_t)d[index+2]); //red
i+=3;
}
}
this->writeData_vector2(&tbx);
tbx.clear();
}
void LibST7735S::drawImage2(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d){
//d・・・BGR
vector<uint8_t> tbx(w*h*3);
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
activeRAMWrite();
int i=0;
vector<char> dp = *d;
int index,s=d->size();
for(int dy=0; dy<h; dy++){
for(int dx=0; dx<3*w; dx+=3){
index = s -3*w*dy +dx -3*w;
tbx[i] = (uint8_t)dp[index];
tbx[i+1] = (uint8_t)dp[index+1];
tbx[i+2] = (uint8_t)dp[index+2];
i+=3;
}
}
this->writeData_vector3(&tbx);
tbx.clear();
}
void LibST7735S::drawImage3(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<uint8_t>* d){
this->setWindow(LCD_X_OFFSET+x, LCD_Y_OFFSET+y,
LCD_X_OFFSET+x+w-1, LCD_Y_OFFSET+y+h-1);
activeRAMWrite();
this->writeData_vector2(d);
}
//==[private]============================================================================
void LibST7735S::setMADCTL(uint8_t MY,uint8_t MX,uint8_t MV,uint8_t ML,
uint8_t RGB,uint8_t MH){
//MY Row Address Order
//MX Column Address Order
//MV Row/Column Exchange
//ML Vertical Refresh Order
//RGB RGB-BGR ORDER
//MH Horizontal Refresh Order
this->writeCommand(CMD_MEMORY_DATA_ACCESS_CONTROL);
uint8_t d = 0;
if(MY > 0) d += 0x80;
if(MX > 0) d += 0x40;
if(MV > 0) d += 0x20;
if(ML > 0) d += 0x10;
if(RGB > 0) d += 0x08;
if(MH > 0) d += 0x04;
this->writeData(d);
}
void LibST7735S::setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2){
vector<uint8_t> tbx = {0, x1, 0, x2};
vector<uint8_t> tby = {0, y1, 0, y2};
this->writeCommand(CMD_COLUMN_ADRRESS_SET);
this->writeData_vector(&tbx);
this->writeCommand(CMD_ROW_ADRRESS_SET);
this->writeData_vector(&tby);
vector<uint8_t>().swap(tbx);
vector<uint8_t>().swap(tby);
}
void LibST7735S::setColorFormat(uint8_t color_format){
switch(color_format)
{ default: color_format = COLOR_FORMAT_18BIT; break;
case COLOR_FORMAT_18BIT: break;
case COLOR_FORMAT_16BIT: break;
case COLOR_FORMAT_12BIT: break;
}
this->color_format = color_format;
writeCommand(CMD_INTERFACE_PIXEL_FORMAT);
writeData(color_format);
}
void LibST7735S::setGamma(uint8_t state){
switch(state)
{ /* [GS_Pin = 0] Checked on hardware! */
default: state = 1; break;
case 2: break;
case 4: break;
case 8: break;
}
this->writeCommand(CMD_GAMMA_SET);
this->writeData(state);
}
void LibST7735S::activeRAMWrite(){
this->writeCommand(CMD_MEMORY_WRITE);
this->dcpin->setVal(this->HIGH);
}
void LibST7735S::writeData(int len, uint8_t *txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer(len,txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData_vector(vector<uint8_t>* txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer_vector(txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData_vector2(vector<uint8_t>* txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer_vector2(txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData_vector3(vector<uint8_t>* txbuf){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer_vector3(txbuf);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeData(uint8_t data){
try{
this->dcpin->setVal(this->HIGH);
spi->transfer(data);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::writeCommand(uint8_t cmd){
try{
this->dcpin->setVal(this->LOW);
spi->transfer(cmd);
}catch(LibSpiException e){
cerr << e.getString() << endl;
}
}
void LibST7735S::HWReset(){
if(this->rst == -1) return;
this->rstpin->setVal(this->HIGH); usleep(10*1000); //10ms
this->rstpin->setVal(this->LOW); usleep(10*1000); //10ms
this->rstpin->setVal(this->HIGH); usleep(150*1000); //150ms
}
view raw LibST7735S.cpp hosted with ❤ by GitHub
/*
* LibST7735S.h
*
* Created on: 2018/02/05
* Author: adeno
*/
#ifndef LIBST7735S_H_
#define LIBST7735S_H_
#include <stdint.h> //uint8_t
#include <string>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include "LibSpi.h"
#include "LibGpio.h"
class LibST7735S {
private:
/* SPI */
LibSpi *spi;
int SPI_Bus;
int SPI_Ce;
int SPI_Speed;
uint8_t SPI_Mode;
/* GPIO */
const static int OUTPUT = 0;
const static int INPUT = 1;
const static int HIGH = 1;
const static int LOW = 0;
/* Reset Pin */
LibGpio *rstpin;
/* Data/Command Pin */
LibGpio *dcpin;
/* st7735s Define*/
const static uint8_t CMD_NOP = 0x00;
const static uint8_t CMD_SW_RESET = 0x01;
const static uint8_t CMD_SLEEP_OUT = 0x11;
const static uint8_t CMD_INVOFF = 0x20;
const static uint8_t CMD_INVON = 0x21;
const static uint8_t CMD_GAMMA_SET = 0x26;
const static uint8_t CMD_DISPLAY_OFF = 0x28;
const static uint8_t CMD_DISPLAY_ON = 0x29;
const static uint8_t CMD_COLUMN_ADRRESS_SET = 0x2A;
const static uint8_t CMD_ROW_ADRRESS_SET = 0x2B;
const static uint8_t CMD_MEMORY_WRITE = 0x2C;
const static uint8_t CMD_TEOFF = 0x34;
const static uint8_t CMD_TEON = 0x35;
const static uint8_t CMD_MEMORY_DATA_ACCESS_CONTROL = 0x36;
const static uint8_t CMD_INTERFACE_PIXEL_FORMAT = 0x3A;
const static uint8_t COLOR_FORMAT_12BIT = 0b011;
const static uint8_t COLOR_FORMAT_16BIT = 0b101;
const static uint8_t COLOR_FORMAT_18BIT = 0b110;
/* st7735s RAW Display Type */
int a0; /* Data/Command line */
int rst; /* Reset line */
uint8_t width; /* Currently used width */
uint8_t height; /* Currently used height */
uint8_t color_format;
void createDisplay(uint8_t width,uint8_t height,uint8_t color_format);
void HWReset();
void setMADCTL(uint8_t MY,uint8_t MX,uint8_t MV,uint8_t ML,uint8_t RGB,uint8_t MH);
void setGamma(uint8_t state);
void setColorFormat(uint8_t color_format);
void setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
void activeRAMWrite();
void writeData(uint8_t data);
void writeData(int len, uint8_t *txbuf);
void writeData_vector(vector<uint8_t>* txbuf);
void writeData_vector2(vector<uint8_t>* txbuf);
void writeData_vector3(vector<uint8_t>* txbuf);
void writeCommand(uint8_t cmd);
public:
LibST7735S(int SPI_Bus, int SPI_Ce, int SPI_Speed,uint8_t SPI_Mode,int a0, int rst,uint8_t width,uint8_t height);
void fillScreen(uint8_t red, uint8_t green, uint8_t blue);
void fillRect(uint8_t x, uint8_t y, uint8_t width, uint8_t height,uint8_t red, uint8_t green, uint8_t blue);
void drawPx(uint8_t x, uint8_t y,uint8_t red, uint8_t green, uint8_t blue);
void drawImage(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d);
void drawImage2(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<char>* d);
void drawImage3(uint8_t x, uint8_t y, uint8_t w, uint8_t h,vector<uint8_t>* d);
virtual ~LibST7735S();
};
#endif /* LIBST7735S_H_ */
view raw LibST7735S.h hosted with ❤ by GitHub

200円くらいのジャンクFONでついにここまで来れた。
ArduinoとかRaspberryPiとか使えば一瞬なのは知ってる。
これぞ趣味の世界

他にもいろいろ動かしたい!


他のグラフィック液晶・OLED
なんだか行けそうな気がする

I/Oを増やしたい
SPI IOエキスパンダ(MCP23S08-E)を秋月電子で買ったら、動作電圧が5VだったOrz。
しかもSPI系のHi検出レベルが 0.8VDD。 FONは3.3Vなのでた、足りない。
仕方がないので、動作電圧が1.8V〜5.5VのMCP230S09を入手予定。
8-Eの方は、マイコンとか74HC14とかと一緒に使うとするか。
入手でき次第対応する
まだ、SPIでの入力をやっていないからこのタイミングでやってみよう

キャラクタ液晶が・・・
昔にまとめ買いしたキャラクタ液晶が余ってる。
最近のI2Cとかじゃない8bitパラレルインターフェースだよ。
IOエキスパンダ経由で制御してみるか。

SD/MMCカード
SPIでの入出力できるようになってから
多分SPI-MMC的なドライバをカーネルコンフィグ時に選択すれば良いような気がする

FON2405E(LEDE・Openwrt)でSPIデバイス追加

ようやくFONの活用に向けての一歩

フラッシュメモリが接続されているSPIポートを汎用的に使えないか

考えることはみんな同じで、すでにやっている人が居る
というかOpenWrtのHPに書いてある→Deep MMC Mod

・もともとのCS#1にインバーターを繋いでCS#2とするもの
・GPIOを1つ潰してCS#2に割り当てるもの

実現方法
極力ハードを増やしたくなかったので、GPIOにCS#2を割り当てる方法を考えることにした。
CSは負論理なので、起動時からHのままのGPIO12を使うことにした。
ubootもカスタマイズできれば、どのGPIOでも良いんだろうけど。

SPI通信のためにハードは16pinSPIフラッシュ用のランドから線出し
外れないようにホットボンドで固定
黒なので見栄えが少しイマイチ

ソフトは変更点だけを書き出すとこれだけ・・・。
dtsファイル変更、カーネルコンフィグでSPI_SPIDEV追加。
・gpio-ledsからGPIO12に関する定義をコメントアウト
・spi定義部分にcs-gpios追加
・spi定義部分にspidevを追加
+&spi0 {
+ status = "okay";
+
+ num-chipselects = <2>;
+ cs-gpios = <0>,<&gpio0 12 GPIO_ACTIVE_LOW>;
+
+ m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0 0x10000>;
+ read-only;
+ };
+
+ devconf: partition@10000 {
+ label = "devconf";
+ reg = <0x10000 0x10000>;
+ read-only;
+ };
+ firmware: partition@20000 {
+ label = "firmware";
+ reg = <0x20000 0x7b0000>;
+ };
+ };
+
+ spidev@1 {
+ compatible = "spidev";
+ reg = <1>;
+ spi-max-frequency = <10000000>;
+ };
+
+};

ビルド→ファームアップ→デバイス確認

おぉぉぉ
ちなみに、spidevドライバを組み込むとbootログで注意されるみたい
[ 1.459196] spi spi0.1: force spi mode3
[ 1.467875] spidev spi0.1: buggy DT: spidev listed directly in DT
[ 1.480327] ------------[ cut here ]------------
[ 1.489758] WARNING: CPU: 0 PID: 1 at drivers/spi/spidev.c:758 spidev_probe+0x1c0/0x1f0
[ 1.505958] Modules linked in:
[ 1.512139] CPU: 0 PID: 1 Comm: swapper Not tainted 4.9.57 #0
[ 1.523776] Stack : 8041751a 00000031 00000000 00000001 8182c284 803caba7 8037fcdc 00000001
[ 1.540724] 80413660 000002f6 803d0000 803e0000 803a0000 8004d540 8038549c 803d0000
[ 1.557718] 00000003 000002f6 8038368c 81827aa4 803a0000 8007b1dc 8041751a 0000004b
[ 1.574709] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1.591649] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1.608636] ...
[ 1.613628] Call Trace:
[ 1.618611] [<8000e358>] show_stack+0x54/0x88
[ 1.627515] [<80023ec0>] __warn+0xe4/0x118
[ 1.635873] [<80023f88>] warn_slowpath_null+0x1c/0x34
[ 1.646166] [<80229cfc>] spidev_probe+0x1c0/0x1f0
[ 1.655766] [<802095f4>] driver_probe_device+0x140/0x290
[ 1.666574] [<80207ac4>] bus_for_each_drv+0xa0/0xb0
[ 1.676505] [<80209440>] __device_attach+0x8c/0xe4
[ 1.686262] [<802089bc>] bus_probe_device+0x3c/0xb0
[ 1.696191] [<80206b38>] device_add+0x468/0x560
[ 1.705455] [<80226fc4>] spi_add_device+0x118/0x16c
[ 1.715399] [<80228e0c>] spi_register_master+0x4d0/0x770
[ 1.726205] [<802290f8>] devm_spi_register_master+0x4c/0x9c
[ 1.737539] [<8022a98c>] rt2880_spi_probe+0x160/0x1c4
[ 1.747842] [<8020afdc>] platform_drv_probe+0x28/0x70
[ 1.758127] [<802095f4>] driver_probe_device+0x140/0x290
[ 1.768935] [<802097d0>] __driver_attach+0x8c/0xc4
[ 1.778690] [<80207a00>] bus_for_each_dev+0x9c/0xac
[ 1.788622] [<80208c3c>] bus_add_driver+0xec/0x204
[ 1.798381] [<80209f08>] driver_register+0xa8/0xf8
[ 1.808135] [<80004658>] do_one_initcall+0xdc/0x1a4
[ 1.818094] [<803e9d3c>] kernel_init_freeable+0x168/0x220
[ 1.829077] [<8030660c>] kernel_init+0x10/0x10c
[ 1.838313] [<80009258>] ret_from_kernel_thread+0x14/0x1c
[ 1.849303] ---[ end trace ac6e1c084ca3bbc0 ]---
view raw boot.log hosted with ❤ by GitHub
次は動作確認だー

2018年1月23日火曜日

FON2405E(LEDE・Openwrt)のクロス開発環境(Eclipse)構築メモ

Eclipseを使ってエレガント?にクロス開発環境を構築したときの備忘録
基本的にはラズベリーパイのときと同じ

0.前提
 ・Eclipse
 ・FON2405E(LEDE)とSSH接続可能

1. クロスコンパイル環境
 ここにある
 「lede/source/staging_dir/toolchain-mipsel_24kc_gcc-5.5.0_musl/bin/」
 参考→https://wiki.openwrt.org/doc/devel/crosscompile

2.FON2405E(LEDE)側の準備
 
 ・sftpserver(OpenSSH SFTP server)
 ・gdbとgdbserver
 を追加してカーネル作成

3.Eclipse側の設定

 (1)プロジェクト設定
   ・CROSS設定にて

   ・接頭Prefixは「mipsel-openwrt-linux-」
   ・パスは「1.」参照

 (2)デバッグ設定


・Connectionで「New」 選択にて良きに計らう


・GDB debuggerは「mipsel-openwrt-linux-gdb」


あとはラズベリーパイの時と同じで行けた!

2018年1月22日月曜日

FON2405E(LEDE・Openwrt導入後の備忘録)

いろいろとやっていて忘れそうなのでメモ

1.実はGPIO9もある

今まで
・WAN(地球儀マーク?) GPIO12
・LAN GPIO11
・WPS GPIO14
だと思っていたら
WANにはGPIO9も接続されていることがわかった。
なんで今までわからなかったんだろう・・・。



 2.LANポートの割り当て

 LAN1<WAN> 白 IC面を上にして左側
 LAN3<LAN> 黒 IC面を上にして右側
 VLANは以下の通り

2018年1月15日月曜日

2017年を振り返って

もう2018年になって何日も経つけど・・・。

2017年を振り返り、いろいろな事があった。

まずは「Victrola4ZM!
NanoPI NEOにZoneMinderと焦電センサーを導入して
動体検出時にSlackに投稿するというもの。
・ZoneMinder
・焦電センサー
・Slack

次に「3Dプリンタ
 ようやくという気もするけど
 ちょっとしたパーツを作るに重宝している
最近使ってないけど(汗

そしてなんと言っても「FON2405EのLEDE/Openwrtの導入
・フラッシュメモリ交換してのLEDEインストール
・関連してラズベリーパイ+Node.jsでSPI読み書き
今後はSPI通信などを充実させたい

その他
・上半期はそれなりに時間が取れたので、なかなか腰が上がらなかった3Dプリンタにも着手できた
・下半期はNanoPI NEOに出会ってちょっとハマって嬉しかった
・親友に子供が生まれた!よかったよかった
・投資はクリアできなかった。マイナスではなかったけど。

来年(今年)も引き続き家庭も仕事も趣味も充実するといいな。
 目標は
・新しいプラン(目標探し)
・戦略的な投資
・楽しい教育
・「巨人の肩に乗る」
・「ググるよりもググられたい」
・頑張り過ぎないことを頑張る
去年とあまり変わらないか・・・。