89
ARMマイコンで作る シンセサイザー Naomasa Matsubayashi

ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ARMマイコンで作る シンセサイザー

Naomasa Matsubayashi

Page 2: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ARMマイコンで作る シンセサイザー

Naomasa Matsubayashi

@fadis_Twitter

Github

slidesharehttp://www.slideshare.net/fadis

https://github.com/Fadis/

Page 3: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

slidesharehttp://www.slideshare.net/fadis

Page 4: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

世の中には色んな

ARM がある

Page 5: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

でかいARM

ARM Cortex-A

ARM

BeagleBoard-X15 ARM Cortex-A15

1.5GHz x2http://www.elinux.org/Beagleboard:BeagleBoard-X15

Page 6: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

Cortex-R

ARM Cortex-M

小さいARM

LPC812 ARM Cortex-M0+

30MHzhttp://www.nxp-lpc.com/lpc_micon/cortex-m0+/lpc800/

Page 7: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

マイクロコントローラ向けARM Cortex-Mシリーズ

Cortex-M7 Cortex-M4 Cortex-M3 Cortex-M1 Cortex-M0+ CortexM0

http://arm.com/ja/products/processors/cortex-m/index.php

Page 8: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ARM命令には対応していない

Thumb2(+FPU)のみ Thumb2(+FPU)のみ

Thumb2のみ Thumb2の一部だけ Thumb2の一部だけ Thumb2の一部だけ

Cortex-M7 Cortex-M4 Cortex-M3 Cortex-M1 Cortex-M0+ CortexM0

Thumb2とは: ARMプロセッサのもう1つの命令セット。 命令が可変長でARM命令セットよりマシン語が小さくなる。

Page 9: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

パイプラインが短いCortex-M7 Cortex-M4 Cortex-M3 Cortex-M1 Cortex-M0+ CortexM0

6段 投機的実行 3段 投機的実行

3段 3段 2段 3段

投機的実行とは: 処理が必要かどうか確定する前から 実行を始めておく事。必要なかったら実行結果を捨てる。

Page 10: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

MMUが無い

基本的にOSを動かすことは想定されていない

MMUとは: メモリ管理ユニット。仮想アドレスと 物理アドレスの変換、及びメモリ保護を行うハードウェア。

Cortex-M7/M4/M3/M0+には メモリ保護ユニットだけは備わっている

http://www.linux-arm.org/LinuxKernel/LinuxM3ただしLinuxを動かしてしまった人は居る

仮想アドレスの変換は出来ない

Page 11: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ARMにしては遅い

DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行できた回数を周波数で割ったもの。大きい程クロック辺りの性能が良い。速いARMだと15以上、x86_64だと30以上。

200-400MHz 100-300MHz 75-120MHz 30-50MHz 30-50MHz

Cortex-M7 Cortex-M4 Cortex-M3 Cortex-M0+ CortexM0

2.14 1.52 1.50 1.08 0.99

DMIPS/MHzクロック

Page 12: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

安い

マルツとは: 秋葉原の本店をはじめ全国12カ所にある電子部品屋さん。入門キットから特殊用途の石まで幅広い品揃え。

NXP LPC812の場合マルツで1個

http://www.marutsu.co.jp/pc/i/226931/

110円(税抜)

Page 13: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

低消費電力NXP LPC812の場合最大クロック(30MHz)時

10.89mW割り込み待機時

5.28µWクロックを低めに設定すれば コイン型リチウム電池でも動く

Page 14: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ARM Cortex-Mで動く バイナリを作ろう

Page 15: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mbed

ブラウザ上で動く統合開発環境https://mbed.org/

Page 16: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mbed

色んなCortex-Mマイコン向けの バイナリを吐ける

Page 17: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mbed

色んなデバイスのドライバが 最初から用意されている

Page 18: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mbed

Page 19: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mbedUSBストレージをマウントイーサネットドライバ

HTTPサーバ

DHCPでアドレスを貰ってくるHTTPサーバを80番ポートにbind

驚異のレイヤーの高さ

Page 20: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ダメだ もっとレイヤーを下げるんだ

Page 21: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

arm-none-eabi-g++

ローカルのgccでビルドしよう

Page 22: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

CMSISCortex-M向けの

ハードウェア抽象化レイヤーARM社がインターフェースを定めて

マイコンのベンダが実装する

違うベンダのマイコンに移行しても 基本的な機能の使い方は一緒で習得が楽

Page 23: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

Cortex-MマイコンCMSIS

mbedライブラリ

mbedコミュニティ ペリフェラルライブラリ

アプリケーション

mbedはCMSISの上で動く

イーサネット ドライバ とかはここ

HTTPサーバ とかはここ

デバイスの 初期化

とかはここここまでは使いたい

Page 24: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mbedのソースコードは githubで公開されている

各マイコン向けのCMSISの実装も入っているhttps://github.com/mbedmicro/mbed/

CMSIS

Page 25: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ldscript

mbedのヤツは ARM純正コンパイラ用に書かれているldscriptとは: リンカに渡す設定ファイル。バイナリイメージ

のどこに何が置かれるかを記述する。

Page 26: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

MEMORY {! flash (rx) : ORIGIN = 0x00000000, LENGTH = 16K! ram (rwx) : ORIGIN = 0x10000000, LENGTH = 4K!}!ENTRY(Reset_Handler)!SECTIONS {! .text : {! KEEP(*(.isr_vector))! *(.text*)! KEEP(*(.init))! KEEP(*(.fini))! *crtbegin.o(.ctors)! *crtbegin?.o(.ctors)! *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)! *(SORT(.ctors.*))! *(.ctors)! *crtbegin.o(.dtors)! *crtbegin?.o(.dtors)! *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)! *(SORT(.dtors.*))! *(.dtors)! *(.rodata*)! KEEP(*(.eh_frame*))! } > flash! .ARM.extab : {! *(.ARM.extab* .gnu.linkonce.armextab.*)! } > flash! __exidx_start = .;! .ARM.exidx : {! *(.ARM.exidx* .gnu.linkonce.armexidx.*)! } > flash! __exidx_end = .;! __etext__ = .;! .data : AT(__etext__) {! __data_values__ = LOADADDR(.data);! __data_begin__ = .;! *(vtable)! *(.data*)! . = ALIGN(4);!

RAMとフラッシュメモリの 開始アドレスとサイズは

普通データシートに書いてある !

今回使うLPC812の情報は 以下のURLから辿れる

http://www.nxp-lpc.com/lpc_micon/cortex-m0+/lpc800/

ldscript

Page 27: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

MEMORY {! flash (rx) : ORIGIN = 0x00000000, LENGTH = 16K! ram (rwx) : ORIGIN = 0x10000000, LENGTH = 4K!}!ENTRY(Reset_Handler)!SECTIONS {! .text : {! KEEP(*(.isr_vector))! *(.text*)! KEEP(*(.init))! KEEP(*(.fini))! *crtbegin.o(.ctors)! *crtbegin?.o(.ctors)! *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)! *(SORT(.ctors.*))! *(.ctors)! *crtbegin.o(.dtors)! *crtbegin?.o(.dtors)! *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)! *(SORT(.dtors.*))! *(.dtors)! *(.rodata*)! KEEP(*(.eh_frame*))! } > flash! .ARM.extab : {! *(.ARM.extab* .gnu.linkonce.armextab.*)! } > flash! __exidx_start = .;! .ARM.exidx : {! *(.ARM.exidx* .gnu.linkonce.armexidx.*)! } > flash! __exidx_end = .;! __etext__ = .;! .data : AT(__etext__) {! __data_values__ = LOADADDR(.data);! __data_begin__ = .;! *(vtable)! *(.data*)! . = ALIGN(4);! PROVIDE_HIDDEN (__preinit_array_start = .);!

フラッシュメモリには !

割り込みベクタ マシン語

書き変わらないデータ !

を置く

ldscript

Page 28: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

__exidx_start = .;! .ARM.exidx : {! *(.ARM.exidx* .gnu.linkonce.armexidx.*)! } > flash! __exidx_end = .;! __etext__ = .;! .data : AT(__etext__) {! __data_values__ = LOADADDR(.data);! __data_begin__ = .;! *(vtable)! *(.data*)! . = ALIGN(4);! PROVIDE_HIDDEN (__preinit_array_start = .);! KEEP(*(.preinit_array))! PROVIDE_HIDDEN (__preinit_array_end = .);! . = ALIGN(4);! PROVIDE_HIDDEN (__init_array_start = .);! KEEP(*(SORT(.init_array.*)))! KEEP(*(.init_array))! PROVIDE_HIDDEN (__init_array_end = .);! . = ALIGN(4);! PROVIDE_HIDDEN (__fini_array_start = .);! KEEP(*(SORT(.fini_array.*)))! KEEP(*(.fini_array))! PROVIDE_HIDDEN (__fini_array_end = .);! . = ALIGN(4);! __data_end__ = .;! } > ram! .bss : {! __bss_begin__ = .;! *(.bss*)! *(COMMON)! __bss_end__ = .;! } > ram! __stack_begin__ = .;! .stack_dummy : {! *(.stack)! } > ram! __stack_end__ = .;!}

RAMには !

vtable 書き変わるデータ

スタック !

を置く

ldscript

Page 29: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

プログラムが起動してから main関数に入るまでの処理を書いたもの

起動グローバル変数の初期値を設定

グローバル変数のコンストラクタを実行ハードウェアの初期化main()にジャンプ

スタートアップルーチン

Page 30: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mbedのヤツは例によって ARM純正コンパイラ用に書かれている

スタートアップルーチン

Page 31: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

スタートアップルーチンReset_Handler:! ldr r1, =__etext__! ldr r2, =__data_begin__! ldr r3, =__data_end__! ldr r0, =init_data! blx r0! ldr r0, =init_bss! blx r0! ldr r0, =run_preinit! blx r0! ldr r0, =run_init! blx r0! ldr r0, =SystemInit! blx r0! ldr r0, =main! blx r0! .pool ! .size Reset_Handler, . - Reset_Handler

Page 32: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

スタートアップルーチンReset_Handler:! ldr r1, =__etext__! ldr r2, =__data_begin__! ldr r3, =__data_end__! ldr r0, =init_data! blx r0! ldr r0, =init_bss! blx r0! ldr r0, =run_preinit! blx r0! ldr r0, =run_init! blx r0! ldr r0, =SystemInit! blx r0! ldr r0, =main! blx r0! .pool ! .size Reset_Handler, . - Reset_Handlerアセンブリで格闘したくないので

Cで実装した初期化コードに飛ぶ

Page 33: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

スタートアップルーチンReset_Handler:! ldr r1, =__etext__! ldr r2, =__data_begin__! ldr r3, =__data_end__! ldr r0, =init_data! blx r0! ldr r0, =init_bss! blx r0! ldr r0, =run_preinit! blx r0! ldr r0, =run_init! blx r0! ldr r0, =SystemInit! blx r0! ldr r0, =main! blx r0! .pool ! .size Reset_Handler, . - Reset_Handler

デバイスの初期化は CMSISにおまかせ

Page 34: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

void run_preinit(void) {! int *cur = &__preinit_array_start;! for( ; cur < &__preinit_array_end; cur++ ) {! void (*f)(void) = (void *)*cur;! (*f)();! }!}!void run_init(void) {! int *cur = &__init_array_start;! for( ; cur < &__init_array_end; cur++ ) {! void (*f)(void) = (void *)*cur;! (*f)();! }!}!void init_data(void) {! unsigned char *src = &__data_values__;! unsigned char *dest = &__data_begin__;! unsigned int len = &__data_end__ - &__data_begin__;! while( len-- ) *dest++ = *src++;!}!void init_bss(void) {! unsigned char *dest = &__bss_begin__;! unsigned int len = &__bss_end__ - &__bss_begin__;! while( len-- ) *dest++ = 0;!}

Page 35: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

void run_preinit(void) {! int *cur = &__preinit_array_start;! for( ; cur < &__preinit_array_end; cur++ ) {! void (*f)(void) = (void *)*cur;! (*f)();! }!}!void run_init(void) {! int *cur = &__init_array_start;! for( ; cur < &__init_array_end; cur++ ) {! void (*f)(void) = (void *)*cur;! (*f)();! }!}!void init_data(void) {! unsigned char *src = &__data_values__;! unsigned char *dest = &__data_begin__;! unsigned int len = &__data_end__ - &__data_begin__;! while( len-- ) *dest++ = *src++;!}!void init_bss(void) {! unsigned char *dest = &__bss_begin__;! unsigned int len = &__bss_end__ - &__bss_begin__;! while( len-- ) *dest++ = 0;!}

RAMに置いておくデータを フラッシュメモリからコピー

Page 36: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

void run_preinit(void) {! int *cur = &__preinit_array_start;! for( ; cur < &__preinit_array_end; cur++ ) {! void (*f)(void) = (void *)*cur;! (*f)();! }!}!void run_init(void) {! int *cur = &__init_array_start;! for( ; cur < &__init_array_end; cur++ ) {! void (*f)(void) = (void *)*cur;! (*f)();! }!}!void init_data(void) {! unsigned char *src = &__data_values__;! unsigned char *dest = &__data_begin__;! unsigned int len = &__data_end__ - &__data_begin__;! while( len-- ) *dest++ = *src++;!}!void init_bss(void) {! unsigned char *dest = &__bss_begin__;! unsigned int len = &__bss_end__ - &__bss_begin__;! while( len-- ) *dest++ = 0;!}

グローバルオブジェクトの コンストラクタとかを実行

Page 37: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

LEDを点滅させてみよう

Page 38: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

#include "LPC8xx.h"!extern "C"!__attribute__((interrupt("IRQ")))!void SysTick_Handler(void) {! LPC_GPIO_PORT->NOT0 = ( 1 << 16 );!}!int main() {! LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 6);! LPC_GPIO_PORT->DIR0 |= ( 1 << 16 );! SysTick_Config( 6000000 );! while( 1 );!}

Page 39: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

#include "LPC8xx.h"!extern "C"!__attribute__((interrupt("IRQ")))!void SysTick_Handler(void) {! LPC_GPIO_PORT->NOT0 = ( 1 << 16 );!}!int main() {! LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 6);! LPC_GPIO_PORT->DIR0 |= ( 1 << 16 );! SysTick_Config( 6000000 );! while( 1 );!}

SysTickタイマーの割り込みが発生したら

16番目のGPIOの値を反転

__attribute__((interrupt(“IRQ”)))とは: これを指定して おくとgccが割り込みエントリルーチンを付けてくれる

Page 40: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

#include "LPC8xx.h"!extern "C"!__attribute__((interrupt("IRQ")))!void SysTick_Handler(void) {! LPC_GPIO_PORT->NOT0 = ( 1 << 16 );!}!int main() {! LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 6);! LPC_GPIO_PORT->DIR0 |= ( 1 << 16 );! SysTick_Config( 6000000 );! while( 1 );!}

GPIOへのクロックを有効にして 16番目を出力モードに切り替え

SysTickが6,000,000カウントする度に SysTick割り込みを発生させるようにする

Page 41: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

LPC812は 起動時は12MHzで動いている

SysTickが 6,000,000カウントするには

0.5秒かかる0.5秒毎にGPIOの出力が

反転するはず

Page 42: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

http://youtu.be/9GypdG2DmIc

Page 43: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

第2回カーネル/VM関西で紹介したネタ

100MHzのCortex-M3マイコンを使って FM音源とかを作る話

シンセサイザー入門

Page 44: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

30MHzのCortex-M0+でも シンセサイザーが作れるのでは

Page 45: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

音を出せるようにしよう

Page 46: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

マイコンにDACが無いので SPIにDACをぶら下げる

3.3V

ARMマイコン LPC812

SPI DAC MCP4821

アンプIC HT82V739

PIO0_8PIO0_9PIO0_1

VDDVSS

VDDAVSS

CSSCLKSDI

VREF

VOUTA

VSS100kΩ

1μF

1μF

47μF

VDDVSS

VREF

AUDINOUTNOUTP

Page 47: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

void init_dac() {! NVIC_DisableIRQ( (IRQn_Type)( SPI0_IRQn ) );! NVIC_SetPriority(SPI0_IRQn, 0); ! do {! NVIC_ClearPendingIRQ(SPI0_IRQn); ! } while(NVIC_GetPendingIRQ(SPI0_IRQn) != 0);! LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 11);! LPC_SPI0->DLY = 4;! LPC_SPI0->DIV = 2;! LPC_SPI0->TXCTRL = (16-1)<<24 | 1<<22 | ( 1 << 20 );! LPC_SPI0->CFG = (1<<5)|(1<<4)|(1<<2);! switch_matrix::bind_SPI0_SSEL_IO( 8 ); ! switch_matrix::bind_SPI0_SCK_IO( 9 );! switch_matrix::bind_SPI0_MOSI_IO( 1 );! LPC_SPI0->INTENSET = 0x0;! NVIC_EnableIRQ( (IRQn_Type)( SPI0_IRQn ) );! LPC_SPI0->TXDAT = 2048 | ( 1 << 13 )|( 1 << 12 );!}!void set_dac( uint16_t value ) {! value &= 4095;! LPC_SPI0->TXDAT = value | ( 1 << 13 )|( 1 << 12 );!}

Page 48: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

void init_dac() {! NVIC_DisableIRQ( (IRQn_Type)( SPI0_IRQn ) );! NVIC_SetPriority(SPI0_IRQn, 0); ! do {! NVIC_ClearPendingIRQ(SPI0_IRQn); ! } while(NVIC_GetPendingIRQ(SPI0_IRQn) != 0);! LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 11);! LPC_SPI0->DLY = 4;! LPC_SPI0->DIV = 2;! LPC_SPI0->TXCTRL = (16-1)<<24 | 1<<22 | ( 1 << 20 );! LPC_SPI0->CFG = (1<<5)|(1<<4)|(1<<2);! switch_matrix::bind_SPI0_SSEL_IO( 8 ); ! switch_matrix::bind_SPI0_SCK_IO( 9 );! switch_matrix::bind_SPI0_MOSI_IO( 1 );! LPC_SPI0->INTENSET = 0x0;! NVIC_EnableIRQ( (IRQn_Type)( SPI0_IRQn ) );! LPC_SPI0->TXDAT = 2048 | ( 1 << 13 )|( 1 << 12 );!}!void set_dac( uint16_t value ) {! value &= 4095;! LPC_SPI0->TXDAT = value | ( 1 << 13 )|( 1 << 12 );!}

LPC812のSPIは 一度に16bitまで送れる

MCP4821(今回使ったDAC)は 16bit送る毎に出力が更新される

送信完了時の割り込みが要らない 送信バッファも要らない

やったね!

Page 49: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

void init_system_clock() {! LPC_SYSCON->SYSAHBCLKDIV = 2;! LPC_SYSCON->SYSPLLCTRL = 0x24;!}!int main() {! LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 6);! LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 18);! LPC_GPIO_PORT->DIR0 |= ( 1 << 8 );! LPC_GPIO_PORT->DIR0 |= ( 1 << 9 );! LPC_GPIO_PORT->DIR0 |= ( 1 << 1 );! init_system_clock();! init_dac();! SysTick_Config( 1875*2 );! while( 1 );!}

CPUのクロックを30MHzにして SysTickを8kHzに設定

Page 50: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

uint16_t step = 0;!!

extern "C"!__attribute__((interrupt("IRQ")))!void SysTick_Handler(void) {! set_dac( step << 5 );! ++step;!}

SysTick割り込みが発生したら カウンタの値をDACに送る

これでノコギリ波が出るはず

Page 51: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

http://youtu.be/fajL7klkpNI

Page 52: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

音色を計算しよう

Page 53: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの
Page 54: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ダイナミックレンジ圧縮

オーディオバッファ

4オペレータ3和音FM音源

Page 55: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

16.16の固定小数点数を使う浮動小数演算器が無い

整数部16bit符号付き整数 小数部16bit符号無し整数

整数から固定小数点数への変換は左に16bitシフト固定小数点数から整数への変換は右に16bitシフト

Page 56: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ブロック単位で計算PCMのサンプルは8kHzはないと

まともな音に聞こえない音量の上げ下げやキーの状態は もっと低い頻度でしか変化しない

1ブロックブロックの中では音量やキーの変化は

無視できるものとする

Page 57: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

周波数の低い波や線形な値の変化は 間引いて計算出来る

補間 補間 補間 補間

必要なサンプル数 計算したサンプル数 ごまかしたサンプル数

32 4

24

ブロック単位で計算

Page 58: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

http://youtu.be/OaUmnOxzUI0

Page 59: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

計算を速くしよう

Page 60: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

32bitの整数同士の乗算の結果は 最大で64bitの整数になる

FFFFFFFF!FFFFFFFF

32bit32bit64bitFFFFFFFE00000001

*

Page 61: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

乗算命令mulは 32bitと32bitを掛けて 結果の下32bitを得る

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204ij/Cihihggj.html

Page 62: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

FFFF.FFFF!FFFF.FFFF

FFFFFFFE.00000001*

16.16の固定小数点数同士の 乗算の結果は

32.32の固定小数点数になる

結果を16.16で得るには 16bit目から47bit目までが欲しい

Page 63: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

FFFF.FFFF!FFFF.FFFF

FFFFFFFE.00000001*

結果を16.16で得るには 16bit目から47bit目までが欲しい

乗算結果の32bit目以上の値が必要

Page 64: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

32bitと32bitを掛けて 結果を64bitで得る命令

mull

Page 65: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

inline constexpr self_type operator*(! const self_type &y!) const {! return self_type(! (! static_cast< double_type >( base ) *! static_cast< double_type >( y.base )! ) >> Shift::value, raw()! );!}

mullが使われることを期待して 乗算をこんな風に実装していた

Page 66: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

…!00001374 <__aeabi_lmul>:!1374: 469c mov ip, r3!1376: 0403 lsls r3, r0, #16!1378: b5f0 push {r4, r5, r6, r7, lr}!137a: 0c1b lsrs r3, r3, #16!137c: 0417 lsls r7, r2, #16!137e: 0c3f lsrs r7, r7, #16!1380: 0c15 lsrs r5, r2, #16!1382: 1c1e adds r6, r3, #0!1384: 1c04 adds r4, r0, #0!1386: 0c00 lsrs r0, r0, #16!1388: 437e muls r6, r7!138a: 436b muls r3, r5!138c: 4347 muls r7, r0!138e: 4345 muls r5, r0!1390: 18fb adds r3, r7, r3!1392: 0c30 lsrs r0, r6, #16!1394: 1818 adds r0, r3, r0!1396: 4287 cmp r7, r0!1398: d902 bls.n 13a0 <__aeabi_lmul+0x2c>!139a: 2380 movs r3, #128 ; 0x80!139c: 025b lsls r3, r3, #9!

現実

Page 67: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

1392: 0c30 lsrs r0, r6, #16!1394: 1818 adds r0, r3, r0!1396: 4287 cmp r7, r0!1398: d902 bls.n 13a0 <__aeabi_lmul+0x2c>!139a: 2380 movs r3, #128 ; 0x80!139c: 025b lsls r3, r3, #9!139e: 18ed adds r5, r5, r3!13a0: 0c03 lsrs r3, r0, #16!13a2: 18ed adds r5, r5, r3!13a4: 4663 mov r3, ip!13a6: 435c muls r4, r3!13a8: 434a muls r2, r1!13aa: 0436 lsls r6, r6, #16!13ac: 0c36 lsrs r6, r6, #16!13ae: 18a1 adds r1, r4, r2!13b0: 0400 lsls r0, r0, #16!13b2: 1980 adds r0, r0, r6!13b4: 1949 adds r1, r1, r5!13b6: bdf0 pop {r4, r5, r6, r7, pc}!…

現実

mullは使われていない

Page 68: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ARM命令には対応していない

Thumb2(+FPU)のみ Thumb2(+FPU)のみ

Thumb2のみ Thumb2の一部だけ Thumb2の一部だけ Thumb2の一部だけ

Cortex-M7 Cortex-M4 Cortex-M3 Cortex-M1 Cortex-M0+ CortexM0

Thumb2とは: ARMプロセッサのもう1つの命令セット。 命令が可変長でARM命令セットよりマシン語が小さくなる。

Page 69: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ARM命令には対応していない

Thumb2(+FPU)のみ Thumb2(+FPU)のみ

Thumb2のみ Thumb2の一部だけ Thumb2の一部だけ Thumb2の一部だけ

Cortex-M7 Cortex-M4 Cortex-M3 Cortex-M1 Cortex-M0+ CortexM0

Thumb2とは: ARMプロセッサのもう1つの命令セット。 命令が可変長でARM命令セットよりマシン語が小さくなる。

一部とは

Page 70: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mov movw movt add adc adr sub sbc rsb mul mla mls smull umull smlal umlal sdiv udiv ssat usat cmp cmn and eor orr orn bic mvn tst teq lsl lsr asr ror rrx clz ldr ldrh ldrb ldrsh ldrsb ldrt ldrht ldrbt ldrsht ldrsbt ldrd ldm str strh strb strsh strsb strt strht strbt strsht strsbt strd stm push pop ldrex ldrexh ldrexb strex strexh strexb clrex b bl bx blx cbz cbzn tbb tbh svc it cpsid cpsie mrs msr bkpt sxth sxtb uxth uxtb ubfx sbfx bfc bfi rev rev16 revsh rbit sev wef wfi nop isb dmb dsb

M7/M4/M3移動 加算 減算 乗算 除算

飽和演算 比較

論理演算 シフト ロード ストア

スタック操作 セマフォ 分岐

状態変更 型の拡張

ビットフィールド ビット列反転

ヒント バリア ARMv7m

Page 71: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mov movw movt add adc adr sub sbc rsb mul mla mls smull umull smlal umlal sdiv udiv ssat usat cmp cmn and eor orr orn bic mvn tst teq lsl lsr asr ror rrx clz ldr ldrh ldrb ldrsh ldrsb ldrt ldrht ldrbt ldrsht ldrsbt ldrd ldm str strh strb strsh strsb strt strht strbt strsht strsbt strd stm push pop ldrex ldrexh ldrexb strex strexh strexb clrex b bl bx blx cbz cbzn tbb tbh svc it cpsid cpsie mrs msr bkpt sxth sxtb uxth uxtb ubfx sbfx bfc bfi rev rev16 revsh rbit sev wef wfi yeild nop isb dmb dsb

移動 加算 減算 乗算 除算

飽和演算 比較

論理演算 シフト ロード ストア

スタック操作 セマフォ 分岐

状態変更 型の拡張

ビットフィールド ビット列反転

ヒント バリア

M1/M0+/M0

ARMv6m

Page 72: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

M1/M0+/M0mov movw movt add adc adr sub sbc rsb mul mla mls smull umull smlal umlal sdiv udiv ssat usat cmp cmn and eor orr orn bic mvn tst teq lsl lsr asr ror rrx clz ldr ldrh ldrb ldrsh ldrsb ldrt ldrht ldrbt ldrsht ldrsbt ldrd ldm str strh strb strsh strsb strt strht strbt strsht strsbt strd stm push pop ldrex ldrexh ldrexb strex strexh strexb clrex b bl bx blx cbz cbzn tbb tbh svc it cpsid cpsie mrs msr bkpt sxth sxtb uxth uxtb ubfx sbfx bfc bfi rev rev16 revsh rbit sev wef wfi yeild nop isb dmb dsb

移動 加算 減算 乗算 除算

飽和演算 比較

論理演算 シフト ロード ストア

スタック操作 セマフォ 分岐

状態変更 型の拡張

ビットフィールド ビット列反転

ヒント バリア ARMv6m

mullは犠牲になったのだ

mul mla mls smull umull smlal umlal

Page 73: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

mull無しでどうやって 結果が64bitの乗算をするか

a b

a*d b*d* c d

a*c b*c ((a*c)<<32)+((a*d+b*c)<<16)+b*d

abcdはそれぞれ16bit

筆算の要領で16bitづつ 計算していく

Page 74: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

a b

a*d b*d* c d

a*c b*c ((a*c)<<32)+((a*d+b*c)<<16)+b*d

1サンプル毎にこんな計算を 何度もしていたら間に合わない

Page 75: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

64bitの乗算を 回避せよ

Page 76: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

-1<結果<1が明らかな場合

32bit目から47bit目は明らかなので 16bit目から31bit目までが欲しい

この計算はmul命令でできる

0000.FFFF!0000.FFFF

00000000.FFFE0001*

Page 77: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

-1<結果<1が明らかな場合実はFM音源の計算中に現れる 乗算の多くにこれが成り立つ

ADSRFM変調

音量の時間変化 (最大1)

両辺共に1の場合のみ 注意すればmulでOK

Page 78: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

実はFM音源の計算中に現れる 乗算の殆どにこれが成り立つ

ミキサーi1*l1+i2*l2+i3*l3+i4*l4

i1 i2 i3 i4

l1 l2 l3 l4

入力はFMオペレータの出力なので最大1 重みは全部あわせて最大1

両辺共に1の場合のみ注意すればmulでOK

-1<結果<1が明らかな場合

Page 79: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

16.16固定小数点数と整数の乗算FFFF.FFFF!

FFFFFFFEFFFF.0001*

結果を16.16で得るには 0bit目から31bit目までが欲しいこの計算はmul命令でできる

Page 80: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

0 311 2 … …

ブロックの中で何番目のサンプルかは 整数で表される

サンプルのインデックスと時刻の関係は線形

t = 0*fs + ss t= 31*fs + ss

時刻行列

Page 81: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

時刻行列

サンプルのインデックスと時刻の関係は線形

2x2の行列で表現出来る

tはサンプルの時刻 iはサンプルのインデックス

fsはPCMの周波数 ssはこのブロックの再生が始まる時刻

Page 82: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

トーン時間実際の時刻に対して

音の周波数倍で進行するクロック

トーン時間の小数部分だけを取り出すと 意図した周波数と位相のノコギリ波になる

Page 83: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

トーン行列時刻とトーンクロックの関係は線形なので

2x2の行列で表現できる

この乗算は小数同士かつ 結果の絶対値が1以上になる

tはサンプルの時刻、ttはサンプルのトーン時刻 ftはノートの周波数、stはノートの位相

Page 84: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

この部分が事前に求まっていれば インデックスは整数なので

トーンクロックは高速な乗算で求まる

トーン行列時刻とトーンクロックの関係は線形なので

2x2の行列で表現できる

Page 85: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

ブロックの開始時刻がブロック毎に変わるので ブロック毎に

時刻行列とトーン行列の積を求める

行列の積の計算には遅い乗算が入るが ブロックにつき1回の遅い乗算で

サンプル単位の遅い乗算を回避出来る

Page 86: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

結果

Page 87: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

http://youtu.be/DDLSEirr8_A

Page 88: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

まとめ

小さなARMには 大きな魅力が秘められている

Page 89: ARMマイコンで作る シンセサイザー · 2015-05-09 · ARMにしては遅い DMIPS/MHzとは: Dhrystoneベンチマークを1秒間に実行 できた回数を周波数で割ったもの。大きい程クロック辺りの

Thank you for listening.