ゆるく楽しむプログラミング

M5Stack CORE2で15パズルを作ってみた

M5Stack CORE2のタッチパネルを使って15パズルを作ってみました
ArduinoIDEでライブラリはなしのデバイス直接制御です

M5Stack BASIC + UiFlowで15パズルの作成はコチラ

 

電源管理(PMU) AXP192

M5Stack CORE2の電源関係はAXP192で制御されています
TFT液晶とバックライトの電源もAXP192で制御されています

AXP192はI2Cで接続されています
I2Cアドレス 0x34
SCL 21
SDA 22

関係しているレジスタは▼ (ディフォルト値は間違ってるかも)
グループ 1、電力制御クラス
アドレス レジスタの説明 R/W デフォルト値
00 電源ステータス レジスタ R
01 電力モード/充電ステータス レジスタ R
04 OTG VBUS ステータス レジスタ R
06-0B データバッファレジスタ 0-5 R/W F0/0F/00/FF/00/00
10 EXTEN & DC-DC2 スイッチ制御レジスタ R/W X5H
12 DC-DC1/3 & LDO2/3 スイッチ制御レジスタ R/W XFH
23 DC-DC2 電圧設定レジスタ R/W 16H
25 DC-DC2 電圧スロープパラメータ設定レジスタ R/W 00H
26 DC-DC1 電圧設定レジスタ R/W 68H
27 DC-DC3 電圧設定レジスタ  ※バックライトの電圧 R/W 48H
28 LDO2/3 電圧設定レジスタ R/W CFH
30 VBUS-IPSOUT チャネル設定レジスタ R/W 60H
31 VOFF シャットダウン電圧設定レジスタ R/W X3H
32 シャットダウン、バッテリ検出、CHGLED 制御レジスタ R/W 46H
33 充電制御レジスタ 1 R/W C8H
34 充電制御レジスタ 2 R/W 41H
35 バックアップ電池充電制御レジスタ R/W 22H
36 PEK パラメータ設定レジスタ R/W 5DH
37 DCDCコンバータ動作周波数設定レジスタ R/W 08H
38 バッテリ充電温度低下アラーム設定レジスタ R/W A5H
39 バッテリ充電高温アラーム設定レジスタ R/W 1FH
3A APS ローパワー Level1 設定レジスタ R/W 68H
3B APS ローパワーレベル 2 設定レジスタ R/W 5FH
3C 電池放電低温警報設定レジスタ R/W FCH
3D バッテリ放電高温アラーム設定レジスタ R/W 16H
80 DCDC 動作モード設定レジスタ R/W E0H
82 ADC イネーブル設定レジスタ 1 R/W 83H
83 ADC イネーブル設定レジスタ 2 R/W 80H
84 ADC サンプリングレート設定、TS 端子制御レジスタ R/W 32H
85 GPIO [3:0] 入力レンジ設定レジスタ R/W X0H
86 GPIO1 ADC IRQ 立ち上がりエッジしきい値設定 R/W FFH
87 GPIO1 ADC IRQ 立ち下がりエッジしきい値設定 R/W 00H
8A タイマー制御レジスタ R/W 00H
8B VBUS 監視設定レジスタ R/W 00H
8F 過熱シャットダウン制御レジスタ R/W 01H

レジスタ詳細
REG 12H: 電源出力制御
ビット 説明 R/W デフォルト
7 予約済みで変更不可 R/W X
6 EXTEN スイッチ制御 0: 閉; 1: 開
※外部出力電源(5V)
R/W X
5 予約済みで変更不可 R/W X
4 DC-DC2 スイッチ制御 0: 閉; 1: 開 R/W X ※モーター
3 LDO3 スイッチ制御 0: 閉; 1: 開
※LCDのバックライト
R/W X
2 LDO2 スイッチ制御 0: 閉; 1: 開
※LCD
R/W X ※TFT液晶
1 DC-DC3 スイッチ制御 0: 閉; 1: 開 R/W X ※バックライト
0 DC-DC1 スイッチ制御 0: 閉; 1: 開 R/W X
注: REG12Hbit6/4 はそれぞれ REG10Hbit2/0 に対応します。

REG 27H: DC-DC3 出力電圧設定 デフォルト: 48H
ビット 説明 R/W デフォルト
7 予約済みで変更不可
6 DC-DC3 出力電圧設定 Bit6 0.7-3.5V, 25mV/step R/W 1
5 DC-DC3 出力電圧設定 Bit5 R/W 0
4 DC-DC3 出力電圧設定 Bit4 R/W 0
3 DC-DC3 出力電圧設定 Bit4 R/W 1
2 DC-DC3 出力電圧設定 Bit2 R/W 0
1 DC-DC3 出力電圧設定 Bit1 R/W 0
0 DC-DC3 出力電圧設定 Bit0 R/W 0

スペックシートの必要そうなトコだけ翻訳したPDF

TFT液晶 ILI9342C

TFT液晶 ILI9342CはSPIで接続しています
接続しているGPIOピンは▼ RST/BL/PowerはAXP192に接続しています
MOSI GPIO38
MISO GPIO23
SCK GPIO18
CS GPIO5
DC GPIO15
RST AXP_IO4
BackLight AXP_DC3
POWER AXP_LDO2



基本的なコマンドは▼
動作 COMAND PARAMETA
Software Reset
 ソフトウエア・リセット
0x01 パラメタ - なし
Memory Access Control
 メモリと画面の対応(表示方向の設定)
0x36 パラメタ - 1Byte
 横(0xE8) or 縦(0x48)
COLMOD: Pixel Format Set
 メモリと表示色の対応(色指定方法の設定)
0x3A パラメタ - 1Byte
 16bit色(0x55) or 18bit色(0x66)
Sleep Out
 スリープモードからの復帰
0x11 パラメタ - なし
【重要】コマンド送信後、電源が安定するまで(5m秒以上)待つ必要がある。
Enter Sleep Mode
 スリープモードに設定
0x10
Display ON
 表示ON
0x29 パラメタ - なし
Display OFF
 表示OFF
0x28
Display Inversion OFF
表示色反転 OFF
0x20 パラメタ - なし
Display Inversion ON
表示色反転 ON
0x21 パラメタ - なし
Normal Display Mode On
全画面表示
0x13 パラメタ - なし
Partial Mode ON
部分表示
0x12 パラメタ - なし
範囲はPartial Area command(0x30)で指定
Partial Area
部分表示範囲指定
0x30 パラメタ - 2Bayte + 2Bayte
Column Address Set
ドットデータ書き込みカラム位置
0x2A パラメタ - 2Bayte + 2Bayte
Page Address Set
ドットデータ書き込みページ位置
0x2B パラメタ - 2Bayte + 2Bayte
Memory Write
ドットデータ書き込み
0x2C パラメタ - N Bayte
Memory Read
ドットデータ読み出し
0x2E パラメタ - N Bayte
Vertical Scrolling Start Address
スクロール開始アドレス
0x37 パラメタ - 2Bayte
初期化に必要なコマンド 描画に必要なコマンド

コマンドは1バイトでパラメタはデータ扱いになります
DCをLOWにしてコマンドを送信、DCをHIGHにしてパラメタを送信の手順で使用します


描画方向は、Memory Access Control(0x36)コマンドのパラメタで設定します
パラメタ設定は▼の通り
  D7 D6 D5 D4 D3 D2 D1 D0
コマンド  0 0 1 1 0 1 1 0
パラメタ  MY
(Y軸方向)
MX
(X軸方向)
MV
(XY軸入れ替え)
ML
(Y軸更新方向)
RGB
(色割り当て
 RGB or BGR)
MH
(X軸更新方向)
- -



1Dot(ピクセル)の色を指定する方法(フォーマット)の指定は COLMOD: Pixel Format Setで行います。
M5Stack(CORE2・BASIC共)では表示色を反転モード(INVERT ON)にしないとRGB指定の色が出ないみたいです
Greenが正しい色で表示されないのでBGR表示になっているとかではなく反転しているようです

Memory Writeで書き込む値は 16Bitモードと18Bitモードで▼のようになります


描画は描画範囲を指定し、指定範囲を埋めるBitmapデータを送信する
描画範囲 COLの指定  0X2A  SC,EC
描画範囲 ROWの指定   0x2B  SP,EP
描画データ送信   0x2C  Bitmapデータ
※SC,EC,SP,EPは各16Bit



タッチパネル FT6336U

タッチパネルはFT6336Uで制御されています。
FT6336UはI2Cで接続されています
I2Cアドレス 0x38
SCL 21
SDA 22

FT6336Uのレジスタ(PDF)
▲からの抜粋 取りあえず必要な所だけ
レジスタ R/W Register symbol Register name Register description
00h RW Mode_Switch モードスイッチ 0x40を書き込むと出荷設定モードに切り替わる
出荷設定モードにはキャリブレーションとかあるのでウッカリ触らない方が無難
02h RO TD_STATUS 読み取りポイント数 読み取ったポイントの数 0~2
03h RO P1_XH タッチイベントフラグ Bit7~bit6 は 1 点目のタッチイベントフラグ、bit3~bit0 は 1 点目の X 座標の上位 4 ビットです。
X1ポイントの座標 上位4ビット
04h RO P1_XL X1ポイントの座標 下位バイト
05h RO P1_YH ポイントID Bit7~bit4 は最初のポイントの ID、bit3~bit0 は最初のポイントの Y 座標の上位 4 ビットです。
Y1ポイントの座標 上位4ビット
06h RO P1_YL Y1ポイントの座標 下位バイト
09h RO P2_XH タッチイベントフラグ Bit7~bit6 は 2 点目のタッチイベントフラグ、bit3~bit0 は 12点目の X 座標の上位 4 ビットです。
X2ポイントの座標 上位4ビット
0AH RO P2_XL X2ポイントの座標 下位バイト
0Bh RO P2_YH ポイントID Bit7~bit4 は 2 点目の ID、bit3~bit0 は 2 点目の Y 座標の上位 4 ビットです。
Y2ポイントの座標 上位4ビット
0Ch RO P2_YL Y2ポイントの座標 下位バイト

入力操作の特性
�← な感じで、縦方向にズレた2点は同時入力可能

ボタンはタッチスクリーンに入力で代用されているので
画面とボタンの同時押しは実現できる
← な感じで、縦軸が近い場合には2点の中間点辺りを
  タッチしていると判定される

  スマホのようなワイプ操作は出来ない



タッチしているのが1点の場合、座標はP1に入る。
2点をタッチしている場合、P1,P2に座標が入る。

タッチした順番にポイントID(0~1)が設定される
2点をタッチしてP1,P2に座標が設定されている状態でP1を離すと、P2に入っていた座標がP1に入るようになる

この時、ポイントIDは変わらないので、P1に設定されている座標が、元はP2に入っていた座標である事が分かる

プログラム的には
point[ポイントID].x , point[ポイントID].y で参照すれば
P1,P2の状態の変化に影響されない

タッチスクリーンの座標
タッチスクリーンの座標は (0,0)~(319,279)になっています
※スペックシートに明記されていないので、多分です

(0,0)~(319,239)の範囲はTFT液晶の座標と一致しています
Y軸が240以上の場合にボタンと判定しすれば良いようです

15パズル

イメージデータ
 パズルに使用するイメージデータは320x240ドットのJPEGファイルをSDカードから読み込んで使用する

M5CORE2クラスを使えば M5.Lcd.drawJpgFile(SD,"/image1.jpg"); の1行でJPEG画像を表示できます
ここで、イメージの展開先をLCDではなくメモリーバッファに変更できれば、パズルのチップサイズに画像を分割/加工して使用する事ができます。

ArduinoIDEのESP32系マイコンのボードライブラリにはJPEGイメージをBITMAPに展開するオープンスースのライブラリが入っています
 ライブラリ名:TJpgDec - Tiny JPEG Decompressor
 作者:ChaN氏
 ライセンス:BSD
 ソース:http://elm-chan.org/fsw/tjpgd/00index.html
このライブラリの使用方法は Arduino core ESP32 内のライブラリでJPEGファイルをビットマップに変換(デコード)する を参考にしました。
※M5Stack CORE2で使用する場合、電源管理の都合(M5Stack BASICとは電源関係の回路が違うの)でM5.begin()をSDカード使用前に行わないと、うまく動きません

Cボタンでイメージ切り替え
SDカードに保存されている image1.jpg ~ image10.jpg を順番に読み込み
読み込めなかった場合(ファイルがないなど) 数字だけの白い画像を表示しimage1.jpgに戻ります。

Aボタンでゲームスタート


 15パズルのチップはチップ用のイメージ画像をオーバーラップして作成します
 
← この画像に
 この画像 →
を合成
   LCD Image Converter で 1Dot/1Byte(256色)
のBITMAPデータに変換

白(0x00)と黒(0xFF)だけを元のイメージに上書して
他の色は無視(透過色として扱う)
この画像から 80x60ドット毎に切り出してパズルの1ピースとします

イメージ・チップのシャッフル
 数字の付いている1~15のチップからランダムに2枚を選んで入れ替えます。
 入れ替え回数は必ず偶数回2,4,6,8,10・・・になるようにします。
 奇数回の入れ替えでは絶対解けない配置になる事が証明されています

チップの移動
 移動できるのはブランクチップ(番号のない真っ黒なチップ::プログラム的には[15]のチップ)とX軸またはY軸のどちらか一方が一致しているチップです。
 縦・横にまとめて動かせた方が楽なのでそうしています。
 ブランクチップの隣のチップとした方が簡単かもしれません。

ブランクチップからタッチしたチップまでを順に入れ替え
入れ替えたチップを再描画します。
これで、最小範囲の再描画でチップを移動する事ができます。


チップを入れ替えた後に、チップの順番を確認、0~15の順に並んでいたら完成なのでクリア画像をオーバーラップ表示

スケッチ

ILI9342-DEMO.zip 動画 ~前編~ で使用しているILI9432Cの直接制御スケッチ

FT6336U-DEMO.zip 動画 ~後編~ で使用しているFT6336Uの直接制御スケッチ

15puzzle_CORE2.zip 動画 ~応用編~ で使用している15パズルのスケッチ

動画で使用している ささら&つづみ は著作権の問題で配付できません。
320x240ドットのJPEG画像にimage1.jpg 、image2.jpg ・・・ image10.jpg のファイル名を付けてSDカードに保存してください。

解説動画