2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SPRESENSE で簡単な信号発生器を作ってみた

2
Posted at

SPRESENSEで簡単な信号発生器を作ってみました。材料は以下の通りです。

  1. SPRESENSE メインボード
  2. SPRESENSE LTE拡張ボード
  3. 可変抵抗

LTE拡張ボードは、拡張ボードでもよいと思います。単に小型にしたかっただけですので。
改変抵抗で出力周波数を変更できます。今のところ、ADCの値をそのまま周波数にしているので0~1024Hzまでしか対応していませんが、ここは係数をかけて自由に変更できます。

ソースコードは次の通りです。ADC読み込みに時間がかかっているので、サブコアで値を読み込むようにしています。

メインコア用のコード

#ifdef SUBCORE
#error "Core selection is wrong!!"
#endif

#include <MP.h>
#include <OutputMixer.h>
#include <MemoryUtil.h>
#include <arch/board/board.h>

/* Use CMSIS library */
#define ARM_MATH_CM4
#define __FPU_PRESENT 1U
#include <cmsis/arm_math.h>

#define Q15_SCALE 32768.0f

OutputMixer *theMixer = OutputMixer::getInstance();

const uint32_t sample_num = 480;
const uint32_t sampling_rate = 48000;
static volatile uint32_t output_hz = 440;

const uint32_t subcore = 1;

static void mixer_done_cb(MsgQueId id, MsgType type, AsOutputMixDoneParam *p) { return; }
static void mixer_send_cb(int32_t id, bool is_end) { return; }


void setup() {
  Serial.begin(115200);
  int er;

  initMemoryPools();
  createStaticPools(MEM_LAYOUT_RECORDINGPLAYER);

  theMixer->activateBaseband();
  theMixer->create();
  theMixer->setRenderingClkMode(OUTPUTMIXER_RNDCLK_NORMAL);
  theMixer->activate(OutputMixer0, HPOutputDevice, mixer_done_cb);
  theMixer->setVolume(-30, 0, 0);
  board_external_amp_mute_control(false);    /* Unmute */  

  MP.begin(subcore);
  MP.RecvTimeout(MP_RECV_POLLING);
}

void loop() { 
  static int16_t phase_q15 = 0;
  int er;
  int8_t msgid;

  uint32_t val;
  int ret = MP.Recv(&msgid, &val, subcore);
  if (ret > 0) {
    output_hz = val;
  }

  int16_t phase_inc_q15 = (int16_t)(2.0f * output_hz / sampling_rate * Q15_SCALE);
  if (ret > 0) {
    MPLog("%d, %d\n", output_hz, phase_inc_q15);
  }

  AsPcmDataParam pcm; 
  er = pcm.mh.allocSeg(S0_REND_PCM_BUF_POOL, (sample_num*2*2));  
  if (er != ERR_OK) return;
  q15_t* samples = (q15_t*)pcm.mh.getPa();
  for (int n = 0; n < sample_num*2; n+=2) {
    q15_t level = arm_sin_q15(phase_q15);
    phase_q15 += phase_inc_q15;
    if (phase_q15 > 32767)       phase_q15 -= 65536;
    else if (phase_q15 < -32768) phase_q15 += 65536;    
    samples[n+0] = level;  // L channel
    samples[n+1] = level;  // R channel
  }

  pcm.identifier = 0;
  pcm.callback = 0;
  pcm.bit_length = 16;
  pcm.size = sample_num*2*2; // 16bit, 2channel
  pcm.sample = sample_num;
  pcm.is_end = false;
  pcm.is_valid = true;
  er = theMixer->sendData(OutputMixer0, mixer_send_cb, pcm);
  if (er != OUTPUTMIXER_ECODE_OK) {
    Serial.println("OutputMixer send error:  " + String(er));
    return;
  }
}

サブコア用のコード

#ifndef SUBCORE
#error "Core selection is wrong!!"
#endif

#include <MP.h>

void setup() {
  MP.begin();
}

void loop() {
  uint32_t val = analogRead(A2);
  int8_t sndid = 100;
  //MPLog("%d\n", val);
  MP.Send(sndid, val);
  usleep(100000);
}

計算をリアルタイムで行っているので処理が間に合うか不安でしたが、特に問題なさそうです。さすがCMSISですね。

音が思ったよりもクリアなので、楽器として使うのもよさそうです。
生成する信号も計算で生成しているので処理さえ間に合えば自由に設計できます。
少ない部品で作れますので、皆さんもぜひ試してみてください。:grin:

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?