SSブログ

RL78/G15 FPB と USBシリアル変換モジュール [Arduino]

自作 RL78/G15 Fast Prototyping Board のUSBインターフェイスに、これまで一番差し障りのないFTDI FT232 シリーズでやっていましたが、他のものはどうでしょう?
DTR#が出ていればよさそうなので、CH340Cが載ったやつで試してみました。

rl78g15_ch340c.jpg
結果はOKでした。
USB type-Cで気持ちいい。
さらに、書き込みに30秒かかっていたのが、5秒もかからなくなりました。
本家より優秀になっている。

<追加報告>
rl78g15_cp2102.jpg
CP2102のUSBシリアル変換モジュールが出てきたので試してみたら、こちらはダメでした。
タグ:RL78/G15 CH340C DTR#
nice!(0)  コメント(0) 

RL78/G15 FPB の tone()関数で和音 [Arduino]

RL78/G15 のレジスタを直接いじるの大変そう。PWM作るのにもe2stdioとかいうのを使ってやるみたい。
そこでtone()関数をみてみると、、

RL78G15 20ピン Fast Prototyping Board ピンリスト · renesas_Arduino Wiki · GitHub
https://github.com/renesas/Arduino/wiki/RL78G15-20%E3%83%94%E3%83%B3-Fast-Prototyping-Board-%E3%83%94%E3%83%B3%E3%83%AA%E3%82%B9%E3%83%88

2-7. Tone のところで、Tone output pinに指定できるのは、Arduino 0番, 3番, 13番の3つ。
3つ同時に使えるかと思ったら、3番, 13番を同時に使うのはダメで2和音まででした。

rl78g15frogs.jpg

// RL78/G15 FPB tone function test
#include "notes2.h"                         // Definition data of notes ( pitch (scale & octave), and note value (length))
#define MAX_TRACK   2                       // Maximum number of tracks
const uint8_t  ToneOutputPin[] = { 0, 13 }; // two of 0,3,13 pins (No combination of 3 and 13)
const uint16_t F_SCALE[] = { 33488, 35479, 37589, 39824, 42192, 44701, 47359, 50175, 53159, 56320, 59669, 63217 };
                                            // basic frequency of 12-note scale (from C11 to B11)(Hz)
const uint16_t Frogs[] = {                  // melody data
  120 ,   0 ,
  c5q , d5q , e5q , f5q , e5q , d5q , c5q , RSq , e5q , f5q , g5q , a5q , g5q , f5q , e5q , RSq ,
  c5q , RSq , c5q , RSq , c5q , RSq , c5q , RSq , c5e , c5e , d5e , d5e , e5e , e5e , f5e , f5e ,
  e5q , d5q , c5q , RSq , RSd , RSd ,   0 ,
  RSd ,
  c5q , d5q , e5q , f5q , e5q , d5q , c5q , RSq , e5q , f5q , g5q , a5q , g5q , f5q , e5q , RSq ,
  c5q , RSq , c5q , RSq , c5q , RSq , c5q , RSq , c5e , c5e , d5e , d5e , e5e , e5e , f5e , f5e ,
  e5q , d5q , c5q , RSq , RSd ,   0 ,   0 };

void setup(){
}

void loop(){
  const uint16_t *d = Frogs;                // Pointer of melody data
  const uint16_t *p[MAX_TRACK];             // Pointer for each track of the score
  uint8_t  Tracks, t;                       // Number of tracks and counter
  uint16_t note;                            // Note (pitch + note value) information
  uint8_t  len[MAX_TRACK] = {};             // Length of note (how many 96th notes) (subtraction counter)
  uint32_t usInt, usExp;                    // sound division interval, sound expire time(usec)
  usInt = 1000000*60*4 / MIN_NOTE / *d++;   // Calculate standard 96th note length(usec) from tempo
  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
    p[ Tracks++ ] = d;                      // Get location in memory, Count up the number of tracks
  }
  usExp = micros();
  do {                                      // Processing of score for each reference note(96th note) length
    for( t=0; t<Tracks; t++) {
      if( !len[t]-- ) {                     // Subtract the length of the note, and when it reaches 0, go to the next note
        if( !(note = *p[t]++) ) return;     // end if note = 0
        len[t]  = (note & 0x00ff) - 1;      // The lower 8 bits are the length of the note (how many times the length of a 96th note)
        if(note & 0xff00)                   // note(16bit) : Upper 4 bits are octave, next 4 bits are pitch class (0-11)
                tone( ToneOutputPin[t], F_SCALE[(note>>8)&0x0f] >> (11-(note>>12)), 0 ); 
        else  noTone( ToneOutputPin[t] );   // 0 for rests
      }
    }
    usExp += usInt;
    while( micros() < usExp );              // wait until expiration
  } while( note );
  for( t=0; t<Tracks; t++) noTone( ToneOutputPin[t] );  // stop all sounds
  delay(1000);
}

第5オクターブで曲データを作っています。
これより低い音はうまく出せないみたい。

楽譜データの音符などは、notes2.h で。
Digisparkで音楽演奏【楽譜編】
https://hello-world.blog.ss-blog.jp/2022-07-04


タグ:RL78/G15
nice!(0)  コメント(0) 

RL78/G15 FPB 自作してみた。 [Arduino]

rl78g15diy-bb.jpg
こんな感じで、RL78/G15をDIP化およびシリアル書き込み周辺の抵抗などを載せ、Arduino Pro Miniなどで使うUSBシリアル変換アダプタを使用してスケッチを書き込むことができました。
(秋月電子通商のAE-UM232Rでも行けました。)

シリアルポートを使用した RL78 デバッグ機能
https://www.renesas.com/jp/ja/document/apn/rl78-debugging-functions-using-serial-port-application-note

rl78com.png

できるだけジャンプワイヤーを使用しなくていいように、DIP化基板に抵抗などを載せました。
rl78g15diy-f.jpg
RL78/G15(R5F12068MSP)の5番(RESET#)のラインを切断し、チップ抵抗 1kΩを挟む。

rl78g15diy-b.jpg
裏面は、電源部にキャパシタ。他、1kΩ、2kΩ(がなかったので2.2kΩ)を接続しました。

PDFには、DTRがない場合はRTSも使えるけど「RTSを使う場合は必ずプロパティの設定変更を行ってください。」とのこと。
他、Arduino IDEのシリアルモニタ等を使う場合は、「74LVC1G126」というパーツが必要らしい。RL78/G15 FPBにも載っている。

Arduino上でのピン番号とのIC上のピンとの対応
rl78g15diy-pin.jpg

Lチカ サンプル

タグ:RL78/G15
nice!(0)  コメント(0) 

RL78/G15 Fast Prototyping Board 買ってみた。 [Arduino]

rl78g15pcb.jpg
Renesas RL78/G15 を使った Arduinoっぽいボードを発見したので購入しました。
マルツで売ってました。

<参考URL>
RTK5RLG150C00000BJ - RL78/G15 Fast Prototyping Board | Renesas
https://www.renesas.com/jp/ja/products/microcontrollers-microprocessors/rl78-low-power-8-16-bit-mcus/rtk5rlg150c00000bj-rl78g15-fast-prototyping-board

RL78/G15 FAST PROTOTYPING BOARD RTK5RLG150C00000BJ ルネサスエレクトロニクス(Intersil・IDT)製|電子部品・半導体通販のマルツ
https://www.marutsu.co.jp/pc/i/43306583/

ホーム · renesas/Arduino Wiki · GitHub
https://github.com/renesas/Arduino/wiki/%E3%83%9B%E3%83%BC%E3%83%A0

ボードマネージャファイル
・RL78/G15-20p Fast Prototyping Board
https://raw.githubusercontent.com/renesas/Arduino/master/hardware/package_index_rl78g15_fpb_p20_bundled.json

<とりあえずサンプル>
スケッチ例あるBlinkはそのままではうごきませんでした。
#define LED_BUILTIN 24
となっているようです。
ボード上に2つLEDがついていて、LED1がArduino上のデジタル7番(IC 2番ピン, P20)で、LED2がArduino上のデジタル4番(IC 1番ピン, P21)となっていました。
#define  LED1_BUILTIN  7
#define  LED2_BUILTIN  4
void setup() {
  pinMode(LED1_BUILTIN, OUTPUT);
  pinMode(LED2_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED1_BUILTIN, HIGH);
  digitalWrite(LED2_BUILTIN, LOW);
  delay(500);
  digitalWrite(LED1_BUILTIN, LOW);
  digitalWrite(LED2_BUILTIN, HIGH);
  delay(500);
}

このスケッチ書き込みに30秒くらいかかる。なんでだろう。


タグ:RL78/G15
nice!(0)  コメント(0) 

CH552でシリアル入力 [Arduino]

先日のスケッチをいじって、CH552のシリアル入力を使ってみました。
シリアル出力は、ちょっと癖があるらしいのですが、入力はそれほどむつかしいことはありませんでした。



ふつうのArduinoとCh55xduinoでちょっと違うところ。
・配列の宣言に __xdata
・関数の宣言と定義が必要 (CとC++の違いらしい)
・PROGMEMのデータの読み取りは "pgm_read_~"なし
・shiftOutがなかった (MSBFIRST、16ビット専用のコードを作ってみた)
・USBSerialは通信速度とか関係なし? (300bpsでも2000000bpsでも送信できた)

以下、拙いソース
// Flowing text string from serial input <<CH552 version>>
// Quadruple Matrix LED Driven by MAX7219 
uint8_t CLK = 15;       // to MAX7219 CLOCK
uint8_t CS  = 16;       // to MAX7219 LOAD(~CS)
uint8_t DAT = 17;       // to MAX7219 DIN
uint8_t BUF[32] = {0};  // matrix LED image [ring buffer]
uint8_t pBUF  = 0;      // display start position in BUF
uint8_t pTEXT = 0;      // start position in TEXT string
uint8_t pCHAR = 4;      // start position in character (left:3or4, right:0)
uint8_t fPROP = 1;      // blanks on the left side of characters (0:no, 1:yes) (for proportional font)
__xdata char  TEXT[256]  = "Hello world!";

static const uint32_t FONT4x8[] PROGMEM = {
  0x00000000, 0x000000BF, 0x00030003, 0xF42FF42F, 0x44EA4B32, 0x2313C8C4, 0xE6996690, 0x00000403, //  !"#$%&'
  0x003C4281, 0x0081423C, 0x00140814, 0x00103810, 0x00008060, 0x00101010, 0x00000080, 0xC0300C03, // ()*+,-./
  0x7E91897E, 0x0082FF80, 0xE291918E, 0x42898976, 0x3826FF20, 0x4F898971, 0x7E898972, 0x01E11907, // 01234567
  0x76898976, 0x4E91917E, 0x00006666, 0x0080E666, 0x18244281, 0x28282828, 0x81422418, 0x0201B10E, // 89:;<=>?
  0x7E81995E, 0xFE1111FE, 0xFF898976, 0x7E818166, 0xFF81817E, 0xFF898989, 0xFF090901, 0x7E8191F2, // @ABCDEFG
  0xFF0808FF, 0x0081FF81, 0x80817F01, 0xFF0814E3, 0xFF808080, 0x061806ff, 0xFF0618FF, 0x7E81817E, // HIJKLMNO
  0xFF11110E, 0x3E4171BE, 0xFF11718E, 0x46899162, 0x01FF0101, 0x7F80807F, 0x3FC0601F, 0xe018e01f, // PQRSTUVW
  0xF70808F7, 0x07F80807, 0xC1B18D83, 0x00FF8181, 0x030C30C0, 0x008181FF, 0x00060106, 0x80808080, // XYZ[\]^_
  0x00010204, 0x609494F8, 0xFE909060, 0x78848448, 0x609090FE, 0x78949458, 0x08FC0A0A, 0x18A4A47E, // `abcdefg
  0xFE0808F0, 0x000000FA, 0x0080807A, 0xFE205088, 0x00007E80, 0x04f804f8, 0xFc0404F8, 0x78848478, // hijklmno
  0xFC242418, 0x182424FC, 0xFC100808, 0x4894A448, 0x087E8888, 0x7C80807C, 0x7C80403C, 0xc020c03c, // pqrstuvw
  0xEC1010EC, 0x0C90907C, 0xC4A4948C, 0x00187E81, 0x000000FF, 0x00817E18, 0x10081008 };           // xyz{|}~

void ledOut( uint16_t, uint16_t, uint16_t, uint16_t );
void refreshLED();

void setup() {
  pinMode( CLK, OUTPUT );
  pinMode( CS , OUTPUT );
  pinMode( DAT, OUTPUT );
  ledOut( 0x0F00, 0x0F00, 0x0F00, 0x0F00 );     // Display Test(0xXF): Normal Operation (0)
  ledOut( 0x0B07, 0x0B07, 0x0B07, 0x0B07 );     // Scan Limit  (0xXB): Display all digits (7)
  ledOut( 0x0A01, 0x0A01, 0x0A01, 0x0A01 );     // Intensity   (0xXA): Luminance (0-F)
  ledOut( 0x0900, 0x0900, 0x0900, 0x0900 );     // Decode Mode (0xX9): No decode (00)
  ledOut( 0x0C01, 0x0C01, 0x0C01, 0x0C01 );     // Shutdown    (0xXC): Normal Operation (0)
}

void loop() {
      /*** Get string from serial ***/ 
  char rx, pRx = 0;                             // Receive data length
  while( USBSerial_available() ) {
    rx = USBSerial_read();
    if( rx == '\n' || rx == '\r' ) break;       // Exit if end of string
    TEXT[pRx++] = rx;                           // Add character
    if( pRx == sizeof(TEXT) - 1 ) break;        // Exit if buffer is full
  }
  if( pRx ) {                                   // if the data is not empty..
    TEXT[pRx] = '\0';                           // terminate a string
    pCHAR = (pTEXT) ? 36 : pCHAR;               // insert spaces to the next string
    pTEXT = 0;                                  // reset display start position
    while( USBSerial_available() ) USBSerial_read();    // discard the rest of the data
  }
      /*** Scroll the text ***/
  char c = TEXT[ pTEXT ];                       // character to display
  refreshLED();
  delay(200);
  if( pCHAR >  4 ) BUF[pBUF] = 0;               // display blank
  if( pCHAR == 4 ) switch( c ) {                // for blank or 5-dot width
      case ' ':  fPROP = 0; pCHAR = 1;         break;
      case 'M':  fPROP = 0; BUF[pBUF] = 0xFF;  break;
      case 'm':  fPROP = 0; BUF[pBUF] = 0xFC;  break;
      case 'W':  fPROP = 0; BUF[pBUF] = 0x1F;  break;
      case 'w':  fPROP = 0; BUF[pBUF] = 0x3c;  break;
      default :  pCHAR--;                       // Move character display start position
  }
  if( pCHAR <  4 ) {
    BUF[pBUF] = FONT4x8[ c-' ' ] >> ( pCHAR * 8 );
    while( !BUF[pBUF] && fPROP ) BUF[pBUF] = FONT4x8[ c-' ' ] >> ( --pCHAR * 8 );   // remove blanks
    fPROP = 0;
  }
  if( !pCHAR-- ) {                              // When finished displaying a character
    fPROP = 1;                                  // revert flag
    if( TEXT[++pTEXT] ) pCHAR = 5;              // If there is a following character
    else { pTEXT = 0;   pCHAR = 36; }           // Reset display start position
  }
  pBUF = ++pBUF %32;                            // Move display start position of ring buffer
}

void ledOut( uint16_t d0, uint16_t d1, uint16_t d2, uint16_t d3 ) {
  uint16_t d[]={ d0, d1, d2, d3 };
  digitalWrite( CS, LOW );
  for(uint8_t n=0; n<4; n++) {
    for (uint8_t i=15; i<16; i--)  {      // shiftOut MSBFIRST 16bit
      digitalWrite( DAT, ( d[n]>>i ) & 1 );
      digitalWrite( CLK, HIGH );
      digitalWrite( CLK, LOW  );
    }
  }
  digitalWrite( CS, HIGH );
}

void refreshLED() {
  uint8_t d[4];
  for(uint8_t m=0; m<8; m++) {            // matrix LED data line
    for(uint8_t b=0; b<8; b++) {          // bit
      for(uint8_t n=0; n<4; n++) {        // Number of LEDs
        d[n] = d[n]<<1 | ((BUF[(b+n*8+pBUF)%32]>>m) & 1);
      }
    }
    ledOut(((m+1)<<8)+d[0], ((m+1)<<8)+d[1], ((m+1)<<8)+d[2], ((m+1)<<8)+d[3] );
  }
}

今のところCh55xduinoは、とりあえずArduino用にスケッチ作ってそれを移植するという感じです。

nice!(0)  コメント(0) 

4連マトリックスLEDで文字列を流す [Arduino]

4連マトリックスLEDで文字列を流してみたいと思います。
とりあえず半角英数・記号のみ。
漢字を扱うことの問題は、フォントの著作権と文字コードです。
ということで英数・記号フォントを自作しました。
diyfontexcel.jpg
・基本4×8ドットをいっぱいに使う
・見栄えとスペースの節約のためにプロポーショナルフォント
・4ドット幅だと表現が厳しい"M","W","m","w"は1ドット追加
としました。



// Quadruple Matrix LED Driven by MAX7219
//  *** flowing text string ***
uint8_t CLK = 13;       // to MAX7219 CLOCK
uint8_t CS  = 10;       // to MAX7219 LOAD(~CS)
uint8_t DAT = 11;       // to MAX7219 DIN
uint8_t BUF[32] = {0};  // matrix LED image [ring buffer]
uint8_t pBUF  = 0;      // display start position in BUF
uint8_t pTEXT = 0;      // start position in TEXT string
uint8_t pCHAR = 4;      // start position in character (left:3or4, right:0)
uint8_t fPROP = 1;      // blanks on the left side of characters (0:no, 1:yes) (for proportional font)
char    TEXT[128]  = "Hello world !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";

static const uint32_t FONT4x8[] PROGMEM = {
  0x00000000, 0x000000BF, 0x00030003, 0xF42FF42F, 0x44EA4B32, 0x2313C8C4, 0xE6996690, 0x00000403, //  !"#$%&'
  0x003C4281, 0x0081423C, 0x00140814, 0x00103810, 0x00008060, 0x00101010, 0x00000080, 0xC0300C03, // ()*+,-./
  0x7E91897E, 0x0082FF80, 0xE291918E, 0x42898976, 0x3826FF20, 0x4F898971, 0x7E898972, 0x01E11907, // 01234567
  0x76898976, 0x4E91917E, 0x00006666, 0x0080E666, 0x18244281, 0x28282828, 0x81422418, 0x0201B10E, // 89:;<=>?
  0x7E81995E, 0xFE1111FE, 0xFF898976, 0x7E818166, 0xFF81817E, 0xFF898989, 0xFF090901, 0x7E8191F2, // @ABCDEFG
  0xFF0808FF, 0x0081FF81, 0x80817F01, 0xFF0814E3, 0xFF808080, 0x061806ff, 0xFF0618FF, 0x7E81817E, // HIJKLMNO
  0xFF11110E, 0x3E4171BE, 0xFF11718E, 0x46899162, 0x01FF0101, 0x7F80807F, 0x3FC0601F, 0xe018e01f, // PQRSTUVW
  0xF70808F7, 0x07F80807, 0xC1B18D83, 0x00FF8181, 0x030C30C0, 0x008181FF, 0x00060106, 0x80808080, // XYZ[\]^_
  0x00010204, 0x609494F8, 0xFE909060, 0x78848448, 0x609090FE, 0x78949458, 0x08FC0A0A, 0x18A4A47E, // `abcdefg
  0xFE0808F0, 0x000000FA, 0x0080807A, 0xFE205088, 0x00007E80, 0x04f804f8, 0xFc0404F8, 0x78848478, // hijklmno
  0xFC242418, 0x182424FC, 0xFC100808, 0x4894A448, 0x087E8888, 0x7C80807C, 0x7C80403C, 0xc020c03c, // pqrstuvw
  0xEC1010EC, 0x0C90907C, 0xC4A4948C, 0x00187E81, 0x000000FF, 0x00817E18, 0x10081008 };           // xyz{|}~

void setup() {
  pinMode( CLK, OUTPUT );
  pinMode( CS , OUTPUT );
  pinMode( DAT, OUTPUT );
  ledOut( 0x0F00, 0x0F00, 0x0F00, 0x0F00 );     // Display Test(0xXF): Normal Operation (0)
  ledOut( 0x0B07, 0x0B07, 0x0B07, 0x0B07 );     // Scan Limit  (0xXB): Display all digits (7)
  ledOut( 0x0A01, 0x0A01, 0x0A01, 0x0A01 );     // Intensity   (0xXA): Luminance (0-F)
  ledOut( 0x0900, 0x0900, 0x0900, 0x0900 );     // Decode Mode (0xX9): No decode (00)
  ledOut( 0x0C01, 0x0C01, 0x0C01, 0x0C01 );     // Shutdown    (0xXC): Normal Operation (0)
}

void loop() {
  char c = TEXT[ pTEXT ];                       // character to display
  refreshLED();
  delay(200);
  if( pCHAR >  4 ) BUF[pBUF] = 0;               // display blank
  if( pCHAR == 4 ) switch( c ) {                // for blank or 5-dot width
      case ' ':  fPROP = 0; pCHAR = 1;         break;
      case 'M':  fPROP = 0; BUF[pBUF] = 0xFF;  break;
      case 'm':  fPROP = 0; BUF[pBUF] = 0xFC;  break;
      case 'W':  fPROP = 0; BUF[pBUF] = 0x1F;  break;
      case 'w':  fPROP = 0; BUF[pBUF] = 0x3c;  break;
      default:   pCHAR--;                       // Move character display start position
  }
  if( pCHAR <  4 ) {
    BUF[pBUF] = pgm_read_dword(FONT4x8 + c-' ') >> ( pCHAR * 8 );       // if you don't use PROGMEM -> FONT4x8[ c-' ' ] 
    while( !BUF[pBUF] && fPROP ) BUF[pBUF] = pgm_read_dword(FONT4x8 + c-' ') >> ( --pCHAR * 8 );   // remove blanks
    fPROP = 0;
  }
  if( !pCHAR-- ) {                              // When finished displaying a character
    fPROP = 1;                                  // revert flag
    if( TEXT[++pTEXT] ) pCHAR = 5;              // If there is a following character
    else { pTEXT = 0;   pCHAR = 36; }           // Reset display start position
  }
  ++pBUF %= 32;                                 // Move display start position of ring buffer
}

void ledOut( uint16_t d0, uint16_t d1, uint16_t d2, uint16_t d3 ) {
  uint16_t d[]={ d0, d1, d2, d3 };
  digitalWrite( CS, LOW );
  for(uint8_t n=0; n<4; n++) {
    shiftOut( DAT, CLK, MSBFIRST, d[n]>>8 );
    shiftOut( DAT, CLK, MSBFIRST, d[n]    );
  }
  digitalWrite( CS, HIGH );
}

void refreshLED() {
  uint8_t d[4];
  for(uint8_t m=0; m<8; m++) {            // matrix LED data line
    for(uint8_t b=0; b<8; b++) {          // bit
      for(uint8_t n=0; n<4; n++) {        // Number of LEDs
        d[n] = d[n]<<1 | ((BUF[(b+n*8+pBUF)%32]>>m) & 1);
      }
    }
    ledOut(((m+1)<<8)+d[0], ((m+1)<<8)+d[1], ((m+1)<<8)+d[2], ((m+1)<<8)+d[3] );
  }
}


タグ:Matrix LED
nice!(0)  コメント(0) 

CH552Eduinoをつくってみた。 [Arduino]

ちいさいものが好きなので、CH552EのテストボードをKiCadで設計してみました。

・メインのCH552Eは裏面に
・リセットボタン・ブートローダボタンはほぼ使う機会がなかったので省略
・USBとの接続ピン(UDP, UDM)(UDPはブートローダにも)はブレットボードには使わない位置へ
・USBとの接続ピン以外はICピン配列順にしたかったけど、リセットピンだけ引き回せず別位置へ
・リセッタブルヒューズなど安全性の配慮はなし
・外部電源非対応(USB type-C only)
・そのかわりに、ちゃんとCC1, CC2に5.1kΩの抵抗はつける

2バージョン作成。
ch552eduino_m_pcb.jpg
ch552eduino_w_pcb.jpg
3Dイメージ
ch552eduino_m_3d.jpg
ch552eduino_w_3d.jpg
これらの基板を発注してしばらく待ちます。

先日、基板が届いたので、チップ抵抗、チップキャパシタ、USB-Cレセプタクルを載せてみました。
できあがりサイズは、USB type-C DIP変換基板とか、USB-TTL変換基板くらいのサイズです。

ch552ge_f.jpg
ch552ge_b.jpg
チップ部品のはんだ付けは、まだまだ難儀しています。
先日の演奏スケッチで動作確認できました。
nice!(0)  コメント(0) 

楽譜再生スケッチを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) 

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