Last active
May 4, 2025 06:09
-
-
Save ksasao/c74f8dfdca14e6acc21d989f89ec6e66 to your computer and use it in GitHub Desktop.
8pin RISC-V マイコン CH32V003J4M6 で気圧変化を可視化。https://x.com/ksasao/status/1918255371950670254
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 8pin RISC-V マイコン CH32V003J4M6 で気圧変化を可視化します | |
// 気圧センサの生データを直接参照し温度補正等をしていないことに注意してください | |
// https://x.com/ksasao/status/1918255371950670254 | |
// | |
// ■ 開発環境 | |
// Arduino IDE 2.3.6 | |
// Boards Manager: CH32 MCU EVT Boards 1.0.4 | |
// https://github.com/openwch/board_manager_files/raw/main/package_ch32v_index.json | |
// Board: CH32V00x | |
// ■ パーツ | |
// CH32V003J4M6 https://akizukidenshi.com/catalog/g/g118062/ | |
// マイコン内蔵RGBLEDモジュール WS2812B (NeoPixel) https://akizukidenshi.com/catalog/g/g108414/ | |
// 絶対圧センサ DPS310 https://www.switch-science.com/products/6286 | |
// | |
// 参考: | |
// amanoya3: ArduinoでRISC-VマイコンCH32V003にNeoPixelのLEDをつないでみた | |
// https://ameblo.jp/pta55/entry-12813320408.html | |
// | |
// ■ 配線 | |
// CH32V003J4M6 のピンから見た接続 | |
//--------------------------------------------- | |
// 1: RGBLED の DI | |
// 2: WCH-Linkエミュレータ と RGBLEDのGND | |
// 3: | |
// 4: WCH-Linkエミュレータの3V3 とRGBLEDのVDD | |
// 5: 2SMPBのSDA | |
// 6: 2SMPBのSDL | |
// 7: | |
// 8: WCH-LinkエミュレータのSWDIOおよびRX | |
//--------------------------------------------- | |
#include <Wire.h> | |
// PORTD レジスタへの直接アクセス | |
// CH32V003RM.PDF p.57-58 参照 | |
// https://www.wch-ic.com/downloads/CH32V003RM_PDF.html | |
#define R32_GPIOD_BSHR (*(volatile uint32_t *)0x40011410) | |
#define DPS310_ADDR 0x77 | |
// ■ 気圧センサDPS310 | |
int32_t readRawPressure() | |
{ | |
delay(10); | |
// 測定開始 | |
Wire.beginTransmission(DPS310_ADDR); | |
Wire.write(0x08); | |
Wire.write(0x01); | |
Wire.endTransmission(); | |
// データ読み取り | |
Wire.beginTransmission(DPS310_ADDR); | |
Wire.write(0x00); | |
Wire.endTransmission(); | |
Wire.requestFrom(DPS310_ADDR, 3); | |
int32_t raw = (Wire.read() << 16) | (Wire.read() << 8) | Wire.read(); | |
return raw; | |
} | |
void configDPS310(){ | |
delay(500); | |
// prs_cfg 圧力測定レート32Hz(5 << 4)、オーバーサンプリング2回 (1) | |
// https://www.infineon.com/dgdl/Infineon-DPS310-DS-v01_00-EN.pdf?fileId=5546d462576f34750157750826c42242 | |
// p.29 | |
byte prs_cfg_val = (5 << 4) | 1; | |
Wire.beginTransmission(DPS310_ADDR); | |
Wire.write(0x06); // PRS_CFG_ADDR | |
Wire.write(prs_cfg_val); | |
Wire.endTransmission(); | |
} | |
int initDPS310(){ | |
// チップID読み取り | |
Wire.beginTransmission(DPS310_ADDR); | |
Wire.write(0x0D); // チップIDレジスタ | |
Wire.endTransmission(false); | |
Wire.requestFrom(DPS310_ADDR, 1, true); | |
if (Wire.available()) { | |
uint8_t chip_id = Wire.read(); | |
if (chip_id == 0x10) { | |
configDPS310(); | |
return 0; // 正常に初期化済み | |
} else { | |
return -1; // DPS310が見つからない | |
} | |
} | |
return -2; // I2Cが応答しない | |
} | |
// ■ LED | |
void initLED(){ | |
pinMode(PD6, OUTPUT); | |
// LEDを初期化するためのダミー書込み | |
for(int i=0;i<3;i++){ | |
setColor(0,0,0); | |
delay(10); | |
} | |
} | |
void setColor(byte r, byte g, byte b){ | |
byte aData[3] = {g,r,b}; | |
noInterrupts(); | |
volatile uint32_t d6High = R32_GPIOD_BSHR | 0x0040; // PortD 6bit目を1 | |
for(byte rgbLed=0; rgbLed < 3;rgbLed++){ | |
byte a=aData[rgbLed]; | |
for(byte i=0;i<8;i++){ | |
byte hl=a & 0x80; | |
if(hl>0){ // H: 600ns, L: 500ns | |
R32_GPIOD_BSHR = d6High; // High - 100ns | |
digitalWriteFast(PD_6, HIGH); // High - 500ns | |
digitalWriteFast(PD_6, LOW); // Low - 500ns | |
}else{ // H: 200ns, L: 500ns | |
R32_GPIOD_BSHR |= d6High; // High - 200ns | |
digitalWriteFast(PD_6, LOW); // Low - 500ns | |
} | |
a=a*2; | |
} | |
} | |
interrupts(); | |
} | |
// ■ ハイパスフィルタ | |
const int32_t SHIFT = 8; | |
int32_t getHPFValue(long x){ | |
static int32_t prev_x = x; // 初期値として初めてこの関数が呼ばれた時の値を使う | |
static int32_t y = 0; // フィルタ出力の初期値 | |
// 差分を計算 | |
int32_t diff = x - prev_x; | |
// 対称的な減衰項の計算 | |
// 絶対値に対して丸め処理を行い、その後に符号を適用 | |
int32_t abs_y = y >= 0 ? y : -y; // 絶対値計算 | |
int32_t decay = (abs_y + (1 << (SHIFT - 1))) >> SHIFT; // 丸め処理を含む絶対値の減衰 | |
// 元の値が負だった場合は減衰項も負にする | |
if (y < 0) { | |
decay = -decay; | |
} | |
// フィルタ更新式 | |
y = y + diff - decay; | |
Serial.print(x); // センサ生値 | |
Serial.print(" "); | |
Serial.println(y); // HPF出力 | |
prev_x = x; | |
// 計算されたHPFの値を返す | |
return y; | |
} | |
void setup(){ | |
delay(1000); // 少し待つとArduinoの文字化けが減らせる | |
Serial.begin(115200); | |
initLED(); | |
Wire.begin(); | |
delay(100); | |
// DPS310初期化 | |
switch(initDPS310()){ | |
case 0: | |
setColor(0,0,127); // 正常に初期化(青) | |
break; | |
case -1: | |
setColor(127,127,0); // DPS310ではない(橙) | |
break; | |
case -2: | |
setColor(127,0,127); // I2Cアドレスエラー(紫) | |
} | |
delay(500); | |
// 最初はセンサ値が安定していないため読み飛ばす | |
for(int i=0;i<20;i++){ | |
readRawPressure(); | |
} | |
} | |
void loop(){ | |
int32_t delta = getHPFValue(readRawPressure()); | |
byte r,g,b; | |
const int32_t limit = 50; // 微小すぎる変化をLEDオフにする閾値 | |
const int32_t mask = 0x7F; // 変化量の下位7ビットのみを参照する | |
const int32_t div = 4; // 明るさを調整。大きいほど暗くなる。 | |
if(delta>limit){ | |
delta = (delta-limit)>>div; | |
r = 0; | |
g = (byte)(delta & mask); | |
b = 0; | |
}else if(delta<-limit){ | |
delta = -delta; | |
delta = (delta-limit)>>div; | |
r = (byte)(delta & mask); | |
g = 0; | |
b = 0; | |
}else{ | |
r=0;g=0;b=0; | |
} | |
if(delta > mask){ // 値がオーバーフローしている場合には青色を混ぜる | |
b = 64; | |
} | |
setColor(r,g,b); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment