Maixduinoにサーマルカメラをつなぐ

# はじめに

[M5Stackにサーマルカメラをつなぐ](https://ambidata.io/samples/m5stack/thermalcamera/) のMaixduino版です。
時節柄、部屋にこもることが多くなってます、簡単な工作をしてみましょう。

# 準備

- [Maixduino](https://www.seeedstudio.com/Sipeed-Maixduino-Kit-for-RISC-V-AI-IoT-p-4047.html) まずはこれ
![Maixduino](https://media-cdn.seeedstudio.site/media/catalog/product/cache/ab187aaa5f626ad16c8031644cd2de5b/m/a/maixduino-kit_1.jpg)
- [Grove Base Shield V2.0 for Arduino](https://www.seeedstudio.com/Base-Shield-V2.html) MaixduinoにGPIO、I2Cなどのコネクターを追加します。Maixduinoに接続する時は、スイッチを3.3V側に設定する必要があります。
![Grove Base Shield V2.0 for Arduino](https://media-cdn.seeedstudio.site/media/catalog/product/cache/ab187aaa5f626ad16c8031644cd2de5b/h/t/httpsstatics3.seeedstudio.comseeedimg2016-09ojyc6a5jtrgslqwc5j7gw9ti.jpg)
- [Grove - Infrared Temperature Sensor Array (AMG8833)](https://www.seeedstudio.com/Grove-Infrared-Temperature-Sensor-Array-AMG8833.html) サーマルカメラ/赤外線温度センサー。時節柄サーマルカメラの欠品が多いです
![Grove - Infrared Temperature Sensor Array (AMG8833)](https://media-cdn.seeedstudio.site/media/catalog/product/cache/ab187aaa5f626ad16c8031644cd2de5b/h/t/httpsstatics3.seeedstudio.comseeedfile2018-10bazaar956016_1.jpg)


# コード

ほぼ、参考にさせて頂いた [M5Stackにサーマルカメラをつなぐ](https://ambidata.io/samples/m5stack/thermalcamera/) のままです。
MaixduinoのI2Cのデフォルト転送速度が500kですが、センサーの最大が400kなので、400kを指定してます。あと、まだ原因を調査してないですが、I2Cの転送サイズを128バイトにしたときにWireライブラリーがクラッシュしてしまうので、64バイト単位で転送するようにしています。

```c++:main.cpp
#include <Arduino.h>
#include <Sipeed_ST7789.h>
#include <Wire.h>

#define PCTL 0x00
#define RST 0x01
#define FPSC 0x02
#define INTC 0x03
#define STAT 0x04
#define SCLR 0x05
#define AVE 0x07
#define INTHL 0x08
#define TTHL 0x0E
#define INT0 0x10
#define T01L 0x80
#define T33L 0xC0

#define AMG88_ADDR 0x68 // in 7bit

#define WIDTH (320 / 8)
#define HEIGHT (240 / 8)

SPIClass spi_(SPI0); // MUST be SPI0 for Maix series on board LCD
Sipeed_ST7789 lcd(320, 240, spi_);

float gain = 10.0;
float offset_x = 0.2;
float offset_green = 0.6;

float sigmoid(float x, float g, float o) {
    return (tanh((x + o) * g / 2) + 1) / 2;
}

uint16_t heat(float x) {  // 0.0〜1.0の値を青から赤の色に変換する
    x = x * 2 - 1;  // -1 <= x < 1 に変換

    float r = sigmoid(x, gain, -1 * offset_x);
    float b = 1.0 - sigmoid(x, gain, offset_x);
    float g = sigmoid(x, gain, offset_green) + (1.0 - sigmoid(x, gain, -1 * offset_green)) - 1;

    return (((int)(r * 255)>>3)<<11) | (((int)(g * 255)>>2)<<5) | ((int)(b * 255)>>3);
}

void write8(int id, int reg, int data) {
    Wire.beginTransmission(id);
    Wire.write(reg);
    Wire.write(data);
    uint8_t result = Wire.endTransmission();
    // Serial.printf("reg: 0x%02x, result: 0x%02x\r\n", reg, result);
}

void dataread(int id, int reg, int *data, int datasize) {
    Wire.beginTransmission(id);
    Wire.write(reg);
    Wire.endTransmission();

    Wire.requestFrom(id, datasize);
    int i = 0;
    while (Wire.available() && i < datasize) {
        data[i++] = Wire.read();
    }
}

void setup() {
    pll_init();
    uarths_init();
    lcd.begin(15000000, COLOR_BLACK);
    Serial.begin(115200);

    Wire.begin((uint8_t) SDA, (uint8_t) SCL, 400000);
    
    write8(AMG88_ADDR, FPSC, 0x00);  // 10fps
    write8(AMG88_ADDR, INTC, 0x00);  // INT出力無効
    write8(AMG88_ADDR, 0x1F, 0x50);  // 移動平均出力モード有効
    write8(AMG88_ADDR, 0x1F, 0x45);
    write8(AMG88_ADDR, 0x1F, 0x57);
    write8(AMG88_ADDR, AVE, 0x20);
    write8(AMG88_ADDR, 0x1F, 0x00);
}

void loop() {
    float temp[64];

    int sensorData[128];
    dataread(AMG88_ADDR, T01L, sensorData, 64);
    dataread(AMG88_ADDR, T33L, sensorData + 64, 64);
    for (int i = 0 ; i < 64 ; i++) {
        int16_t temporaryData = sensorData[i * 2 + 1] * 256 + sensorData[i * 2];
        if(temporaryData > 0x200) {
            temp[i] = (-temporaryData +  0xfff) * -0.25;
        } else {
            temp[i] = temporaryData * 0.25;
        }
    }

//    lcd.fillScreen(COLOR_BLACK);
    int x, y;
    for (y = 0; y < 8; y++) {
        for (x = 0; x < 8; x++) {
            float t = temp[(8 - y - 1) * 8 + 8 - x - 1];
            uint16_t color = heat(map(constrain((int)t, 0, 60), 0, 60, 0, 100) / 100.0);
            lcd.fillRect(x * WIDTH, y * HEIGHT, WIDTH, HEIGHT, color);
            lcd.setCursor(x * WIDTH + WIDTH / 2, y * HEIGHT + HEIGHT / 2);
            lcd.setTextColor(COLOR_BLACK, color);
            lcd.printf("%d", (int)t);
        }
    }
    delay(500);
}

```


# 最後に

MaixduinoにGrove Base Shieldを組み合わせて、簡単にサーマルカメラを読むことができました。