Skip to content

Instantly share code, notes, and snippets.

@Yuikawa-Akira
Created June 22, 2026 19:57
Show Gist options
  • Select an option

  • Save Yuikawa-Akira/af00370917072a164b8cdf960f42bc0c to your computer and use it in GitHub Desktop.

Select an option

Save Yuikawa-Akira/af00370917072a164b8cdf960f42bc0c to your computer and use it in GitHub Desktop.
NTSC test
#include <M5UnitRCA.h>
#include <M5Unified.h>
// M5UnitRCA
const uint16_t canvas_width_pix = 240, canvas_height_pix = 180;
const uint16_t panel_width_pix = 240, panel_height_pix = 180;
M5UnitRCA display(canvas_width_pix, canvas_height_pix, panel_width_pix, panel_height_pix, M5UnitRCA::signal_type_t::NTSC, M5UnitRCA::use_psram_t::psram_no_use, 26, 128);
M5Canvas canvas(&display);
const int BUFFER_SIZE = (canvas_width_pix * canvas_height_pix) / 8; // 9600 bytes
const uint8_t MAGIC[4] = { 0xAA, 0x55, 0x00, 0xFF };
void setup() {
//auto cfg = M5.config();
//M5.begin(cfg);
display.begin();
Serial1.begin(2000000, SERIAL_8N1, 22, 19);
// 表示用キャンバス作成 (1ビットカラー)
canvas.setColorDepth(1);
canvas.createSprite(canvas_width_pix, canvas_height_pix);
// 受信待機画面
canvas.clear();
canvas.setTextSize(2);
canvas.setCursor(10, 10);
canvas.print("Waiting for Signal...");
canvas.pushSprite(0, 0);
}
void loop() {
// マジックナンバーを待機
if (Serial1.available() >= 4) {
uint8_t header[4];
// 1バイトずつ確認してヘッダーを探す(簡易的な実装)
if (Serial1.read() == MAGIC[0]) {
header[0] = MAGIC[0];
Serial1.readBytes(&header[1], 3);
if (header[1] == MAGIC[1] && header[2] == MAGIC[2] && header[3] == MAGIC[3]) {
// マジックナンバーが一致したら映像データを受信
uint8_t* buffer = (uint8_t*)canvas.getBuffer();
size_t readLen = 0;
// タイムアウトを考慮した受信ループ
uint32_t startTime = millis();
while (readLen < BUFFER_SIZE && millis() - startTime < 100) {
if (Serial1.available()) {
size_t len = Serial1.readBytes(&buffer[readLen], BUFFER_SIZE - readLen);
readLen += len;
}
}
// 受信完了したら画面に描画
if (readLen == BUFFER_SIZE) {
canvas.pushSprite(0, 0);
}
}
}
}
}
#include <M5Cardputer.h>
#include <M5GFX.h>
M5Canvas canvas(&M5Cardputer.Display);
// 画面サイズとデータサイズ
const int WIDTH = 240;
const int HEIGHT = 180;
const int BUFFER_SIZE = (WIDTH * HEIGHT) / 8; // 9600 bytes
// 同期用マジックナンバー (4バイト)
const uint8_t MAGIC[4] = { 0xAA, 0x55, 0x00, 0xFF };
int frameCount = 0;
// スクロール量の累積用変数
int currentOffsetX = 0;
int currentOffsetY = 0;
// 8方向のベクトル定義 (上から時計回り)
// 0:上, 1:右上, 2:右, 3:右下, 4:下, 5:左下, 6:左, 7:左上
const int dx[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
const int dy[8] = { -1, -1, 0, 1, 1, 1, 0, -1 };
int currentDirection = 0; // 現在の進行方向 (0〜7)
unsigned long lastChangeTime = 0; // 方向切り替えタイマー用
void setup() {
auto cfg = M5.config();
M5Cardputer.begin(cfg);
// UART初期化: ボーレート2Mbps, RX=G1, TX=G2 (CardputerのGroveポート)
Serial1.begin(2000000, SERIAL_8N1, 1, 2);
// 1ビットカラー(白黒)のキャンバスを作成
canvas.setColorDepth(1);
canvas.createSprite(WIDTH, HEIGHT);
}
void loop() {
M5Cardputer.update();
// 2秒(2000ms)ごとに進行方向を切り替える
if (millis() - lastChangeTime > 2000) {
currentDirection = (currentDirection + 1) % 8; // 0〜7をループ
lastChangeTime = millis();
}
// スクロール速度 (1フレームあたりの移動ピクセル数)
int scrollSpeed = 2;
// オフセット座標を更新してスクロールさせる
currentOffsetX += dx[currentDirection] * scrollSpeed;
currentOffsetY += dy[currentDirection] * scrollSpeed;
// 1マス30ピクセル、緑(TFT_DARKGREEN)と黒(TFT_BLACK)の市松模様を描画
drawCheckerboardScroll(&canvas, 16, TFT_WHITE, TFT_BLACK, currentOffsetX, currentOffsetY);
canvas.setTextSize(2);
canvas.setCursor(10, 10);
canvas.printf("Frame: %d", frameCount);
// カードピューター自身の画面にも描画(縮小表示など適宜)
canvas.pushSprite(0, 0);
// UARTでデータを送信
uint8_t* buffer = (uint8_t*)canvas.getBuffer();
// 1. マジックナンバーを送信
Serial1.write(MAGIC, 4);
// 2. 映像バッファを送信
Serial1.write(buffer, BUFFER_SIZE);
frameCount++;
yield();
}
void drawCheckerboardScroll(M5Canvas* canvas, int gridSize, uint32_t color1, uint32_t color2, int offsetX, int offsetY) {
if (canvas == nullptr || gridSize <= 0) return;
int width = canvas->width();
int height = canvas->height();
int period = gridSize * 2;
int startX = offsetX % period;
if (startX > 0) startX -= period;
int startY = offsetY % period;
if (startY > 0) startY -= period;
for (int y = startY; y < height; y += gridSize) {
for (int x = startX; x < width; x += gridSize) {
int gridX = (x - startX) / gridSize;
int gridY = (y - startY) / gridSize;
bool isColor1 = (gridX + gridY) % 2 == 0;
canvas->fillRect(x, y, gridSize, gridSize, isColor1 ? color1 : color2);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment