4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ベアメタルでRaspberryPiのPWMから音を鳴らす

Last updated at Posted at 2017-12-20

この記事はadventar Raspberry Pi Advent Calendar 2017の21日目です。

初めに

どうも。gyaboと申します。

去年はRaspberryPiベアメタルでGPUをいじくってポリゴンをだして遊びました。記事は以下です。
https://qiita.com/gyabo/items/f3a411a63d608d00b384

今年またグラフィック系でやるのはなんかへんてこだったので、なんか音出せればうれしいなと思って
ベアメタルで音鳴らす方法を書きます。
で、これをマルチコアでやるサンプルをこしらえてたんですがいろいろな環境で動かなかったので体力つきました。すみません。

目的 : ベアメタルで音鳴らす

HDMIつながってるんだから、音鳴らせるだろうと思っていろいろ見てみたんですがどうもHDMI関連は全部VideoCore側に移譲していて、かつオーディオがちゃんとなってくれるソースを見てみたんですが、イマイチよくわからなかったんで、イヤホンジャックのPWMで素直に出すことにしました。フォーラム調べてみると同じ事を考えてる方がいるけど、何も資料がありませんでした。
なので、そこまで複雑なことはしません。

資料

以下がとても詳しいです。
https://github.com/PeterLemon/RaspberryPI

あと、開発環境は前回の私の記事を参考にしていただければと思います。
https://qiita.com/gyabo/items/f3a411a63d608d00b384

環境

RaspberryPi2です。3では動作確認していません。

音ネタを用意する

以下のサイトからお借りしました。感謝!

一式

以下からDLしてください。
image.binをkernel.imgなりなんなり、config.txtに合わせて変えてください。

で、起動すると音が鳴るはずです!
元の曲が良いのか、十分な良い感じになってくれます。

main.cのコアの部分

以下の通りです。


void main() {
	uart_init();
	
	IO_WRITE(GPIO_SEL4, GPIO_FSEL0_ALT0 | GPIO_FSEL5_ALT0 );
	usleep(10);
	int idiv = 11;
	IO_WRITE(CM_PWMCTL, PM_PASSWORD | CM_KILL);
	usleep(150);
	IO_WRITE(CM_PWMDIV, PM_PASSWORD | (idiv << 12) );
	IO_WRITE(CM_PWMCTL, PM_PASSWORD | CM_ENAB | CM_SRC_PLLDPER);
	usleep(150);

	int range      = 1024;
	int samplerate = 500000000.0 / idiv / range;
	usleep(10);
	IO_WRITE(PWM_RNG1, range);
	IO_WRITE(PWM_RNG2, range);
	usleep(10);
	IO_WRITE(PWM_CTL,  PWM_PWEN1 | PWM_PWEN2 | PWM_USEF1 | PWM_USEF2 | PWM_CLRF1);
	
	uint32_t count = 0;
	uint32_t phase = 0;
	while(1) {
		uint32_t offset = (phase >> 8) & 0xFFFFFFFE;
		uint8_t data1 = test_wave[offset + 0];
		uint8_t data2 = test_wave[offset + 1];
		phase += 512;
		IO_WRITE(PWM_FIF1, data1);
		while(IO_READ(PWM_STA) & PWM_FULL1) {}
		IO_WRITE(PWM_FIF1, data2);
		while(IO_READ(PWM_STA) & PWM_FULL1) {}
		count++;
		if((count % 0x1000) == 0) {
			uart_debug_puts("data1=\n", data1);
		}
	}
}

即値があっていやな感じですが、イヤホンジャックをPWMの出力として設定PLLDから分周比設定して、チャンネルレンジを考慮してtest.binからLEFT, PWMのRIGHTそれぞれPCMデータをFIFOにどんどん詰めていく、という単純なものです。
そこそこきれいな音が出ます。ただ鳴らすだけなら十分だと思います。

こいつを適当なcore1とかで実行して、core0側は別なことをできれば~と思ってたんですが、力尽きました。

終わりに

なんか今年はラズベリーパイを使ってもっと変なことをする、というところまで手が回らなかったような気がします。
来年はリベンジしたいです。

おまけ - 開発環境について

やっすいカーナビのアナログTV(1200円くらい)と、HDMI -> AV変換(500円)がとても便利です。
写真の通りなのですが、実にコンパクトな環境が構築できます。3000円程度で機材が手に入るので、ぜひ。

image.png

※地べたにおいてるのは床暖房を全身に受けながら作業したかったからです

終わりです!

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?