SSブログ

楽譜再生スケッチをCH552に移植してみた。 [Arduino]

以前につくった楽譜再生スケッチをCH552用に移植してみました。
音楽は、パッヘルベルのカノンのリンナイお風呂バージョンを3和音アレンジにしてみました。

CH552での感想
・プログラムサイズが大きくなると各所で書いてあったが、かなり大きくなり驚いた。
・いままで256クロックで4和音行けていたのが、2和音しか行けなくなった。
どうやら、プログラムサイズ的にも速度的にも、コンパイラの効率がわるいみたい。

拙いスケッチです。
//  CH552 version Score Replay Sketch
//    boards manager URL : https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json
//    Board : CH55x Boards > CH552 Board
//    Clock : 24/16/12 MHz
#if !defined(CH552) && !defined(CH551)
#error "Only compatible with CH552 and CH551"
#endif

#include "notes2.h"                     // Definition data of notes ( pitch (scale & octave), and note value (length))
#define MAX_TRACK   4                   // Maximum number of tracks

// Number of cycles that are the wavelength of the basic 12-note scale (from C0 to B0) (with an interrupt every 512 clocks)
#if   F_CPU == 24000000L
  static const uint16_t CYC_SCALE[] = { 2867, 2706, 2554, 2411, 2275, 2148, 2027, 1913, 1806, 1705, 1609, 1519 };
#elif F_CPU == 16000000L
  static const uint16_t CYC_SCALE[] = { 1911, 1804, 1703, 1607, 1517, 1432, 1351, 1276, 1204, 1136, 1073, 1012 };
#elif F_CPU == 12000000L
  static const uint16_t CYC_SCALE[] = { 1433, 1353, 1277, 1205, 1138, 1074, 1014,  957,  903,  852,  804,  759 };
#endif

static const uint16_t Rinnai[] PROGMEM = {  //  "Canon in D" by Johann Pachelbel
  110 ,   0 ,
  a5e , F5s , g5s , a5e , F5s , g5s,  a5s , a4s , b4s , C5s , d5s , e5s , F5s , g5s ,
  F5e , d5s , e5s , F5e , F4s , g4s , a4s , b4s , a4s , g4s , a4s , d5s , C5s , d5s ,
  g4e , b4s , a4s , g4e , F4s , e4s , F4s , e4s , d4s , e4s , F4s , g4s , a4s , b4s ,
  g4e , b4s , a4s , b4e , C5s , d5s , C5s , d5s , e5s , F5s , g5s , a5s , b5s , C6s ,
  F5s , a5s , d6qt| LNh ,   0 ,
  F4q , d5q , C5h , RSq , b4q , d5h , d4hd, d4q , d4q , g4q , e4q , C5q , d5w ,   0 ,
  d4q , F4q , e4q , a2q , b2q , d4q , F4q , F2q , b3q , g2q , a3q , d3q , RSq , g2q , C4q , a2q , d4w ,   0 ,   0 };

void play552PWM(const uint16_t*);

void setup(){
  // *** PWM pin setteings (P1.5, PWM) *** = pinMode( 15, OUTPUT ); but you can save about 500 bytes
    PIN_FUNC  &= ~(bPWM1_PIN_X);        // Pin Function Select Register: 0(PWM1 use P1.5)
    P1_MOD_OC &= ~(1<<5);               // P1 output mode register: 0(pull output)
    P1_DIR_PU |=   1<<5 ;               // P1 direction control and pull-up enable register: 1(output)
  // *** Register Settings (PWM1 for DAC)  ***
    PWM_CK_SE  = 1;                     // PWM_CK_SE(PWM clock divided Frequency setting register)
    PWM_CTRL  |= bPWM1_OUT_EN;          // PWM_CTRL: PWM1 Output Enable
  // *** Register Settings (TIMER1 for Data) *** Data processing interval 31.25kHz(768clk@24MHz)
    TR2  = 0;                           // T2CON: Timer2 start/stop bit: stop (for initial setting)
    C_T2 = 0;                           // T2CON: Timer2 clock source select bit: using the internal clock
    T2MOD |= bTMR_CLK | bT2_CLK;        // T2MOD: Set Fsys(24/16/12MHz) to Timer2 clock
    RCAP2H = 0xfe;  RCAP2L = 0x00;      // RCAP2(reload count/capture data register 2): Reload value on overflow(65536-512=65024=0xfe00, 24MHz/512=46,875Hz (Interrupt frequency))
    TH2  = RCAP2H;  TL2  = RCAP2L;      // T2COUNT: Timer2 counter, Initialize Timer2 count value with reload value (RCAP2)
    TF2  = 0;                           // T2CON: Timer2 overflow interrupt flag
    TR2  = 1;                           // T2CON: Timer2 start/stop bit: start
}

void loop(){
  play552PWM( Rinnai );                 // Playback
  delay(5000);
}

void play552PWM(const uint16_t *d){     // CH552 PWM version (24/16/12 MHz support)
  uint8_t  Tracks;                      // Number of tracks
  const uint16_t *NoteP[MAX_TRACK];     // Pointer for each track of the score
  uint16_t NoteCycle, n;                // Number of interrupt cycles required for the length of the reference note (96th note) and its counter (n)
  uint16_t note = 0;                    // Note (pitch + note value) information read from PROGMEM
  uint8_t  len[MAX_TRACK];              // Length of note (how many 96th notes) (subtraction counter)
  uint16_t cyc[MAX_TRACK], c[MAX_TRACK];// Number of interrupt cycles (cyc) required for one sound wavelength cycle and its counter (c)
  uint16_t env[MAX_TRACK];              // Sound amplitude (envelope)
  uint16_t out[MAX_TRACK];              // Output value
  uint8_t  lap = 20;                    // Sound transitional cycles(laptime) (for Attenuation calculator)

  // *** Preparing Scores ***
  NoteCycle = F_CPU /512 *4 *60 / *d++ /MIN_NOTE;       // Number of cycles required for reference note
  for( Tracks = 0; Tracks < MAX_TRACK; ) {              // Get the number of tracks and the start position of each track from the song data
    if( *d++ != 0 ) continue;           // Skip until the break comes
    if( *d   == 0 ) break;              // If two zeros follow, end of data
    len[ Tracks ] = 1;                  // Initialize the note length subtraction counter to the remaining 1
    NoteP[ Tracks++ ] = d;              // Get location in memory, Count up the number of tracks
  }
  n = Tracks;                           // Initialize the score processing so that it can be performed immediately after the start of the do loop

  // *** Playback ***
  do {
    // * Processing Scores *
    if( --n < Tracks ) {                // Processing of score for each reference note length
      if( !--len[n] ) {
        note   = *NoteP[n]++;
        len[n] = (uint8_t) note;        // The lower 8 bits are the length of the note (how many times the length of a 96th note)
        cyc[n] = (note>>8) ? CYC_SCALE[ (note>>8) & 0xf ] >> (note>>12) : 0;    // Upper 4 bits are octave, next 4 bits are pitch class (0-11), 0 for rests
          c[n] = 0;                     // Initialize the counter for the number of cycles to create one square wave cycle
        env[n] = 0xffff;                // Initially, the maximum amplitude
      }
      if( !n ) n = NoteCycle;
    }
    // * Waveform Processing / Output *
    switch( Tracks ) {                  // Create output data, Square wave with duty ratio of 1:1
      case 4:   out[3] = ( ( c[3] = (++c[3]==cyc[3]) ? 0 : c[3] ) < (cyc[3]>>1) ) ? env[3] : 0;  //   [[fallthrough]];  // C++
      case 3:   out[2] = ( ( c[2] = (++c[2]==cyc[2]) ? 0 : c[2] ) < (cyc[2]>>1) ) ? env[2] : 0;  //   [[fallthrough]];  // C++
      case 2:   out[1] = ( ( c[1] = (++c[1]==cyc[1]) ? 0 : c[1] ) < (cyc[1]>>1) ) ? env[1] : 0;  //   [[fallthrough]];  // C++
      case 1:   out[0] = ( ( c[0] = (++c[0]==cyc[0]) ? 0 : c[0] ) < (cyc[0]>>1) ) ? env[0] : 0;
    }
    switch( Tracks ) {                  // Change output by number of tracks
      case 1:   PWM_DATA1 =   out[0] >>8;                                   break;
      case 2:   PWM_DATA1 = ((out[0]>>1) + (out[1]>>1)) >>8;                break;
      case 3:   PWM_DATA1 = ((out[0]>>1) + (out[1]>>2) + (out[2]>>2)) >>8;  break;
      case 4:   PWM_DATA1 = ((out[0]>>2) + (out[1]>>2) + (out[2]>>2) + (out[3]>>2)) >>8;
    }
    switch( --lap ) {                   // Amplitude attenuation (Distribute processing per loop)
      case 4:   env[3] -= (env[3]>>9);    break;
      case 3:   env[2] -= (env[2]>>9);    break;
      case 2:   env[1] -= (env[1]>>9);    break;
      case 1:   env[0] -= (env[0]>>9);    break;
      case 0:   lap = 30;               // every 640usec(21.3usec*30) @24MHz (Adjustable)
    }
    while( !TF2 );                      // Waiting for Timer1 overflow (every 21.3usec(=512clk/24MHz))
      TF2 = 0;                          // Clear Timer1 Overflow Flag
  } while( note );                      // Exit if note data is 0
  PWM_DATA1 = 0;                        // Set output to 0
}

"note2.h" は以下参照
Digisparkで音楽演奏【楽譜編】
https://hello-world.blog.ss-blog.jp/2022-07-04



(参考にさせていただいたところ)
ch55xduinoでタイマ割り込み|akita11|note
https://note.com/akita11/n/ne4f2a2fb7c70
nice!(0)  コメント(0) 

CH552 Core Board と Ch55xduino [Arduino]

CH552Eと遊んでいたら、なにかの拍子にUSBから認識されなくなってしまいました。
しかし、こんなこともあろうかと CH552 Core Board というものを購入しておいたのでした。

ch552coreboard.jpg

このボードとCH552のデータシートとCh55xduinoの内容を確認しながら、Ch55xduino でのタイマー、カウンタ、PWMなどについて調べてみました。

Ch55xduinoのcoreのある場所 (windows)
%localappdata%\Arduino15\packages\CH55xDuino\hardware\mcs51\0.0.16\cores\ch55xduino

Ch55xduinoでは、、
・Timer0 : mills(), micros()などの時間関係に使用されている
・Timer1 : UART0 のところで、"use Timer1 for baudrate generator" って書いてあった
・AVRと異なり、タイマー・カウンタとPWMとは別々っぽい
・内部クロック(または外部オシレータ)24MHz(Fosc)で、そこから4倍の96MHz(Fpll)として、Fpllを2分周した48MHzをUSBへ、Fpllを分周設定したものをシステムクロック(Fsys)としている(187.5kHz~24MHz)
・PWMはFsysからの分周数を設定できる(0~255)
・タイマーの分周は、Fsysからの1/4/12分周の三択っぽい

他、気になったところ
・CH552/551のプログラム(ROM)は200回しか書き換えできない (Data Flash は約 10,000 回)。
・CH559のROMは10万回消せるっぽい。
タグ:CH552 Ch55xduino
nice!(0)  コメント(0) 

CH552Eで遊ぶ [Arduino]

ぼくがdigisparkやATtiny85で遊んでいたころ、世間はATtiny202という安価なマイコンで沸いていたらしい。
触ってみたかったけど、半導体不足のせいか秋月電子では売り切れ。
ちょっと割高なところで購入してみた。

digispark, ATtiny85と比較して、、
・とにかく安い
・しかし、売ってない
・UPDIでの書き込みが便利(USB-TTLにダイオードちょい足しするだけ)
・自由なピンが5つ
・フラッシュメモリ、RAMはATtiny85ほどはない
・USBに直接はつながらない
・レジスタがいままでのとちょっと違う

UPDIで書き込みするとして、電源だけUSBからもらう基板を考えてみた。
type-c_at202_updi.jpg

なら、ついでに安いUSB-TTL変換IC(CH340Eとか)も載せちゃったほうが便利じゃん、、と調べていたら、CH552とかいうICを見つけちゃいました。
USBに対応していて、キャパシタ2つつけるだけでよくて、フラッシュメモリも16kB, RAM 1280byteと十分。
いろいろなパッケージがあるのですが、そんなに足はいらないので一番小さいCH552Eを選択。
ということでAliExpressでお取り寄せ。
DIP変換基板に載せます。
かなり細かいのではんだ付け大変。
フラックスでひたひたにしている動画を参考に、フラックスまみれにしてはんだ付けしました。
これをUSB-Cレセプタクル基板(CCの5.1kΩ抵抗なし)と合体させてテストボードを作りました。
ch552e_test1.jpg
ch552e_test2.jpg

ボードマネージャに以下のURLを追加
https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json

ドライバのインストールはよくわからなかかった。
解説のページとは異なり、unknown device #1 (だったと思う)というものが出てきた。
よくわからなかったけど、Zadigで、"libusb-win32"をインストールしてみた。
スケッチ書き込めた。(C++ではなくC言語らしいので、ちょっと修正が必要だった)


(参考)
★ATtiny202など
AVRマイコン ATTINY202-SSNR: マイコン関連 秋月電子通商-電子部品・ネット通販
https://akizukidenshi.com/catalog/g/gI-15731/

GitHub - SpenceKonde/megaTinyCore: Arduino core for the tinyAVR 0/1/2-series -
https://github.com/SpenceKonde/megaTinyCore

ここ↑から、Installation.md へいくと、追加のボードマネージャのURLがある。
http://drazzy.com/package_drazzy.com_index.json

USB Serial AdapterとUPDIの接続は、
AVR-Guidance/jtag2updi.md at master · SpenceKonde/AVR-Guidance · GitHub
https://github.com/SpenceKonde/AVR-Guidance/blob/master/UPDI/jtag2updi.md

★CH55xduino
GitHub - DeqingSun/ch55xduino: An Arduino-like programming API for the CH55X
https://github.com/DeqingSun/ch55xduino

追加のボードマネージャのURL
https://raw.githubusercontent.com/DeqingSun/ch55xduino/ch55xduino/package_ch55xduino_mcs51_index.json

CH55xをArduinoIDEで使う - Qiita
https://qiita.com/akita11/items/d7baed4ca3c06e292637


CH55xでどうでしょう

CH55xでどうでしょう

  • 作者: 秋田純一
  • 出版社/メーカー: ラトルズ
  • 発売日: 2022/12/27
  • メディア: 単行本(ソフトカバー)


タグ:CH552 Ch55xduino
nice!(0)  コメント(0) 

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。