かわいい(かわいい) pic.twitter.com/EMdPX4E5g3
— いぬにゃん (@inunyann) April 16, 2024
#include "LittleFS.h"
// [Ctrl] + [Shift] + [P], then "Upload LittleFS to Pico/ESP8266".
#include "LovyanGFX.hpp"
#include "lgfxST7735Sspi.h"
static LGFX lcd;
#define PIC_FILE "/pic##.jpg" // for 7735S(80x160)
#define PIC_NUM_MIN 1
#define PIC_NUM_MAX 24
uint8_t nowPic = PIC_NUM_MIN;
uint8_t btnPressed = 0;
void setup() {
LittleFS.begin();
lcd.init();
pinMode(22, OUTPUT);
digitalWrite(22, HIGH);
showPic(nowPic);
}
void setup1() {}
void loop() {
chkButton();
delay(10);
}
void loop1() {
if (btnPressed) {
if (++nowPic > PIC_NUM_MAX) nowPic = PIC_NUM_MIN;
showPic(nowPic);
btnPressed = 0;
}
delay(10);
}
void showPic(uint8_t n) {
if (n < PIC_NUM_MIN || PIC_NUM_MAX < n) return;
char picFileName[] = PIC_FILE;
char pinNum[3];
snprintf(pinNum, sizeof(pinNum), "%02d", n);
char *ptr = picFileName;
if (ptr = strstr(ptr, "##")) memcpy(ptr, pinNum, 2);
if (!LittleFS.exists(picFileName)) return;
File jpgFile = LittleFS.open(picFileName, "r");
size_t size = jpgFile.size();
char *_buf = (char *)malloc(size);
if (_buf) {
jpgFile.readBytes(_buf, size);
lcd.drawJpg((uint8_t *)_buf, size, 0, 0, 0, 0, 0, 0, lgfx::v1::jpeg_div::jpeg_div_t::JPEG_DIV_NONE);
}
free(_buf);
jpgFile.close();
}
void chkButton() {
uint8_t c = 0;
while (BOOTSEL) if (!++c) rp2040.reboot(); else delay(10);
if (c && (btnPressed = 1) && c > 30) rp2040.reboot();
}
class LGFX : public lgfx::LGFX_Device {
lgfx::Panel_ST7735S _panel_instance;
lgfx::Bus_SPI _bus_instance;
public:
LGFX(void) {
{
auto cfg = _bus_instance.config();
cfg.spi_host = 0;
cfg.spi_mode = 0;
cfg.freq_write = 40000000;
cfg.freq_read = 20000000;
cfg.pin_sclk = 18;
cfg.pin_mosi = 19;
cfg.pin_miso = -1;
cfg.pin_dc = 21;
_bus_instance.config(cfg);
_panel_instance.setBus(&_bus_instance);
}
{
auto cfg = _panel_instance.config();
cfg.pin_cs = 5;
cfg.pin_rst = 20;
cfg.pin_busy = -1;
cfg.panel_width = 80;
cfg.panel_height = 160;
cfg.offset_x = 26;
cfg.offset_y = 1;
cfg.offset_rotation = 1;
cfg.dummy_read_pixel = 8;
cfg.dummy_read_bits = 1;
cfg.readable = true;
cfg.invert = true;
cfg.rgb_order = false;
cfg.dlen_16bit = false;
cfg.bus_shared = false;
_panel_instance.config(cfg);
}
setPanel(&_panel_instance);
}
};
機能面は一通り完成した気がするので、スイッチで切り替えている様子を動画に撮ってみました。
— いぬにゃん (@inunyann) November 20, 2021
あとは持ち運べるようにraspberry pi pico本体を入れるケースとかを探したいですね。キューブも配線部分が折れないか心配なので、ケース必要かも? pic.twitter.com/0lmvkqYEj9
白も作ったので5色になりました!
— いぬにゃん (@inunyann) November 21, 2021
12mm四方のキューブ内に 3 x 2 x 2 で白のLEDを配置し、IC(シフトレジスタ74HC595)も収めました。
先に作った2つ(青、緑黄赤)に比べデザイン的にもいいなと思います。特に内部の配線がきれいに見えるのがお気に入りです。
制作過程の写真は後日ツイートします。 pic.twitter.com/fOcAVaOHEo
raspberry pi picoを8KBのUSBメモリに見せかけて、ファイルを書き込むことでGPIO制御できるようにしてみました。動画は外付け(gpio0)とオンボードLED(同25)にてテスト。GPIO読み取りにも使いたいなと思ったのですが、windowsだとキャッシュ効いて一向に読みに行ってくれない... pic.twitter.com/KFTuprXCiI
— いぬにゃん (@inunyann) May 2, 2022
windowsの読み込みキャッシュはFILE_FLAG_NO_BUFFERINGで無効化できました。いつも通り?のバッチからPS→C#System.IOを呼んで、キャッシュ無しで読込できました。特に使うあては無いのですが、いつか役に立つでしょう。ファイル書き込みで制御できるからOS依存せず、androidとかからも制御できるはず pic.twitter.com/KMWtlzZMct
— いぬにゃん (@inunyann) May 2, 2022
#include "Adafruit_TinyUSB.h"
#define DISK_BLOCK_NUM 16
#define DISK_BLOCK_SIZE 512
#include "ramdisk.h"
Adafruit_USBD_MSC usb_msc;
void setup() {
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
TinyUSB_Device_Init(0);
#endif
for (uint32_t i = 0; i < 30; i++) gpio_init(i);
usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
usb_msc.setUnitReady(true);
usb_msc.begin();
}
void loop() {
}
int32_t msc_read_callback(uint32_t lba, void* buffer, uint32_t bufsize) {
if (lba == 3) get_gpio_status();
uint8_t const* addr = msc_disk[lba];
memcpy(buffer, addr, bufsize);
return bufsize;
}
int32_t msc_write_callback(uint32_t lba, uint8_t* buffer, uint32_t bufsize) {
uint8_t* addr = msc_disk[lba];
memcpy(addr, buffer, bufsize);
if (lba == 3) set_gpio_status();
return bufsize;
}
void msc_flush_callback() { }
void get_gpio_status() {
for (uint32_t i = 0; i < 30; i++) {
msc_disk[3][ i] = gpio_get(i) ? '1' : '0';
msc_disk[3][37 + i] = gpio_get_dir(i) ? 'o' : 'i';
msc_disk[3][74 + i] = gpio_is_pulled_up(i) ? 'u' : gpio_is_pulled_down(i) ? 'd' : '-';
}
}
void set_gpio_status() {
for (uint32_t i = 0; i < 30; i++) {
gpio_set_dir(i, msc_disk[3][37 + i] == 'o');
if (msc_disk[3][74 + i] == 'u') gpio_pull_up(i);
else if (msc_disk[3][74 + i] == 'd') gpio_pull_down(i);
else gpio_disable_pulls(i);
gpio_put(i, msc_disk[3][i] == '1');
}
}
using System;
using System.IO;
public class GpioReader {
public static void Main() {
FileOptions FileFlagNoBuffering = (FileOptions)0x20000000; // FILE_FLAG_NO_BUFFERING
using(FileStream fs = new FileStream(Environment.GetEnvironmentVariable("GPIO_BAT_BASENAME") + ".txt", FileMode.Open, FileAccess.Read, FileShare.Read, 512, FileFlagNoBuffering | FileOptions.Asynchronous & FileOptions.SequentialScan)) {
using(StreamReader sr = new StreamReader(fs)) {
string gpio = sr.ReadToEnd();
Console.WriteLine(gpio);
}
}
}
}
#include "FreeRTOS.h"
uint8_t btnPressed = 0;
void setup() {
xTaskCreate(chkButton, "btn", configMINIMAL_STACK_SIZE, nullptr, 0, nullptr);
}
void loop() {
if (btnPressed) {
// ボタン押された時の処理
btnPressed = 0;
}
}
void chkButton(void *p) {
while (true) {
uint8_t c = 0;
while (BOOTSEL) {
if (!++c) rp2040.reboot();
delay(10);
}
if (c > 30) rp2040.reboot();
if (c) btnPressed = 1;
delay(10);
}
}