Skip to content

Instantly share code, notes, and snippets.

@lovyan03
Last active September 15, 2024 03:43
Show Gist options
  • Save lovyan03/b1abba4f7d200206cb3a06b1c0369821 to your computer and use it in GitHub Desktop.
Save lovyan03/b1abba4f7d200206cb3a06b1c0369821 to your computer and use it in GitHub Desktop.
StickCPlus用 DAC波形生成サンプル
// StickCPlus用 DAC波形生成サンプル (DAC Waveform Generator Sample for StickCPlus)
// GPIO25, GPIO26を使用してアナログ波形を出力します (Output analog waveform using GPIO25, GPIO26)
// ボタンAで波形を切り替えます (Switch waveform with button A)
// PortAをアナログ入力として使用し周波数を変更します (Change frequency using analog input)
// UnitAngleをPortAに接続してください (Connect UnitAngle to PortA)
#include <M5Unified.h>
static M5Canvas cv(&M5.Display);
void setup() {
M5.begin();
{
auto spk_cfg = M5.Speaker.config();
spk_cfg.sample_rate = 384000;
spk_cfg.dac_zero_level = 128;
spk_cfg.pin_data_out = 25; // GPIO_NUM_25;
spk_cfg.stereo = true; // stereo = GPIO25+GPIO26
spk_cfg.i2s_port = I2S_NUM_0;
spk_cfg.use_dac = true;
spk_cfg.buzzer = false;
spk_cfg.magnification = 32;
M5.Speaker.config(spk_cfg);
}
M5.Speaker.setVolume(128);
M5.Display.startWrite();
M5.Display.setRotation(0);
cv.setColorDepth(16);
cv.createSprite(134, 240);
cv.setFont(&fonts::AsciiFont8x16);
cv.setTextSize(2);
cv.setTextColor(~0xC218);
pinMode(33, ANALOG);
}
void loop()
{
static uint8_t wav_index = 4;
static int prev_adc = 0;
static float target_freq = 10;
static float freq = 10;
// ADCサンプリング履歴を256個保持する (Keep 256 ADC sampling history)
static uint16_t adc_buffer[256] = {0,};
static uint8_t adc_index = 0;
uint16_t current_adc = analogRead(33);
adc_buffer[++adc_index] = current_adc;
if (M5.Display.dmaBusy()) {
if (0 == (adc_index&3)){
M5.delay(1);
}
return;
}
static constexpr const uint8_t sin_wav[64] = {
103, 153, 79, 177, 57, 199, 38, 218, 22, 234, 11, 245, 3, 253, 1, 255,
3, 253, 11, 245, 22, 234, 38, 218, 57, 199, 79, 177,103, 153,128, 128,
153, 103,177, 79,199, 57,218, 38,234, 22,245, 11,253, 3,255, 1,
253, 3,245, 11,234, 22,218, 38,199, 57,177, 79,153, 103,128, 128,
};
static constexpr const uint8_t sqr_wav[64] = {
0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255,
255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0,
};
static constexpr const uint8_t tri_wav[64] = {
112, 143, 96, 159, 80, 175, 64, 191, 48, 207, 32, 223, 16, 239, 0, 255,
16, 239, 32, 223, 48, 207, 64, 191, 80, 175, 96, 159, 112, 143, 128, 128,
143, 112, 159, 96, 175, 80, 191, 64, 207, 48, 223, 32, 239, 16, 255, 0,
239, 16, 223, 32, 207, 48, 191, 64, 175, 80, 159, 96, 143, 112, 128, 128,
};
static constexpr const uint8_t saw_wav[64] = {
0, 255, 8, 247, 16, 239, 25, 230, 33, 222, 41, 214, 49, 206, 58, 197,
66, 189, 74, 181, 82, 173, 90, 165, 99, 156,107, 148,115, 140,123, 132,
132, 123,140, 115,148, 107,156, 99,165, 90,173, 82,181, 74,189, 66,
197, 58,206, 49,214, 41,222, 33,230, 25,239, 16,247, 8,255, 0,
};
const uint8_t* const waves[4] = { sin_wav, sqr_wav, tri_wav, saw_wav };
static uint8_t wav_buffer[64];
int prev_wav_index = wav_index;
M5.update();
bool change_flg = false;
if (M5.BtnA.wasPressed()) {
wav_index = (1 + wav_index);
}
wav_index &= 3;
if (prev_wav_index != wav_index) {
memcpy(wav_buffer, waves[wav_index], 64);
change_flg = true;
M5_LOGV("wav_index: %d", wav_index);
}
// ADCサンプリング履歴を合算する
int adc = 0;
for (int i = 0; i < 256; ++i) {
adc += adc_buffer[i];
}
// ADCレンジ端部での誤差補正
static const int adc_margin = 2048;
if (adc < (adc_margin<<1)) {
adc = adc - (adc_margin<<1);
adc *= adc;
adc /= adc_margin;
adc = (adc_margin<<1) - adc;
adc = adc;
} else if (adc > (4095*256 - (adc_margin<<1))) {
adc = (4095*256) - adc;
adc *= adc;
adc /= adc_margin;
adc = 4095*256 - adc;
adc = adc;
}
// ADC揺らぎ除去
adc += adc_margin;
if (abs(prev_adc - adc) >= adc_margin) {
if (prev_adc < adc) {
adc -= adc_margin;
} else {
adc += adc_margin;
}
prev_adc = adc;
float f = 4096.0f - (adc / 256.0f);
f = (f * f) / 8192.0f;
target_freq = f;
M5_LOGV("freq: %6.2f", f);
}
if (freq != target_freq) {
freq += (target_freq - freq) / 2.0f;
change_flg = true;
}
if (change_flg) {
M5.Speaker.tone(freq, -1, 1, true, wav_buffer, 64, true);
cv.fillScreen(TFT_BLACK);
cv.setCursor(0, 208);
cv.printf("%6.1fHz", freq);
int w = cv.width();
int h = cv.height();
cv.drawFastHLine(0, 105, w, ~0xC218);
// 16bit RGB565 swapped カラーテーブル
// C218 == R:11000 / G:010000 / B: 11000
// LCDの画素の色の並び順に応じてどちらを使用するか選ぶ必要があります
// for BGR pixel order
/*
static constexpr const uint32_t colors0[] = { 0x000018C2u, 0x180000C2u, 0x180200C0u, 0x18C20000u, 0x00C20000u, 0x00C00000u };
static constexpr const uint32_t colors1[] = { 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00001800u, 0x00001802u };
/*/
// for RGB pixel order
static constexpr const uint32_t colors0[] = { 0x000018C2u, 0x00C01802u, 0x00C21800u, 0x18C20000u, 0x18020000u, 0x18000000u };
static constexpr const uint32_t colors1[] = { 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x000000C0u, 0x000000C2u };
//*/
int step = roundf(freq * 64);
int w3 = w * 3;
uint32_t wave_period = (65536*31+32768) - (step * w3 / 2);
int sub = 0;
auto b = (uint32_t*)cv.getBuffer();
int add_y = w / 2;
float py = 0;
for (int x = -1; x < w3; ++x) {
wave_period += step;
uint8_t idx = (wave_period >> 16) & 0x1F;
int left_value = wav_buffer[idx << 1];
idx = 0x01F & (idx + 1);
int right_value = wav_buffer[idx << 1];
int diff = wave_period & 0xFFFF;
float y = (left_value + (((right_value - left_value) * diff) / 65536.0f)) * 200.0f / 256.0f;
y += 5.0f;
int y0 = floorf((py < y ? py : y));
int y1 = ceilf((py < y ? y : py) + 0.01f);
py = y;
if (x < 0) continue;
auto bb = &b[y0 * add_y];
int gh = y1 - y0;
uint32_t c0 = colors0[sub];
uint32_t c1 = colors1[sub];
if (x >= w3-3) { c1 = 0; }
if (c1) {
do {
uint32_t b0 = bb[0];
uint32_t b1 = bb[1];
b0 |= c0;
b1 |= c1;
bb[0] = b0;
bb[1] = b1;
bb += add_y;
} while (--gh);
} else {
do {
bb[0] |= c0;
bb += add_y;
} while (--gh);
}
if (++sub >= 6) {
sub = 0;
++b;
}
}
cv.pushSprite(0, 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment