Skip to content

Instantly share code, notes, and snippets.

@ksasao
Last active May 4, 2025 06:09
Show Gist options
  • Save ksasao/c74f8dfdca14e6acc21d989f89ec6e66 to your computer and use it in GitHub Desktop.
Save ksasao/c74f8dfdca14e6acc21d989f89ec6e66 to your computer and use it in GitHub Desktop.
8pin RISC-V マイコン CH32V003J4M6 で気圧変化を可視化。https://x.com/ksasao/status/1918255371950670254
// 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