Keyboard Piano (creating tones) using GR-KURUMI

Original Location: http://japan.renesasrulz.com/gr_user_forum_japanese/b/weblog/archive/2013/05/20/kurumi-tone.aspx

Owner: Okamiya Yuuki May 20, 2013

I created a piano with a PC-keyboard, piezoelectric speaker and KURUMI. I was able to perform a tune using a 10-keypad via TeraTerm. KURUMI lights up as I play do-re-mi!



When you create a sketch, make sure you select the section indicated in the red box below.
For example, when using TeraTerm as the terminal software, the program will be executed when a port is specified after TeraTerm starts up. Alternately, the program will not run before the port is specified.

Copy and build the following to run the program.

#include <RLduino78.h>
#define BLACK 0
#define RED 1
#define GREEN 2
#define YELLOW 3
#define BLUE 4
#define PINK 5
#define SKY 6
#define WHITE 7

#define PIN_BZ 2

#define LED_R 22
#define LED_G 23
#define LED_B 24

int melody[] = { 1319, 523, 587, 659, 698, 784, 880, 988, 1047, 1175};
void ledKurumi(int);

void setup()
{
   Serial.begin(9600);
   pinMode(LED_R , OUTPUT); //LED RED
   pinMode(LED_G , OUTPUT); //LED GREEN
   pinMode(LED_B , OUTPUT); //LED BLUE

   //DO RE MI
   tone(PIN_BZ, melody[1]);
   delay(200);
   tone(PIN_BZ, melody[2]);
   delay(200);
   tone(PIN_BZ, melody[3]);
   delay(200);
  noTone(PIN_BZ);
}

void loop()
{
   int iNum;

   noTone(PIN_BZ);
   ledKurumi(BLACK);
   while(!Serial.available());
   char cNum = Serial.read();
   Serial.println(cNum);
   if ( (cNum < '0') || (cNum > '9') ){    //from char to int (0-9)
      iNum = 0; //illegal
   } else {
      iNum = (int)( cNum - '0' );
   }
   ledKurumi(iNum);
   tone(PIN_BZ, melody[iNum]);
   delay(200);
}

void ledKurumi(int color)
{
   switch(color){
      case BLACK:
         digitalWrite(LED_R, HIGH);
         digitalWrite(LED_G, HIGH);
         digitalWrite(LED_B, HIGH);
         break;
   case RED:
        digitalWrite(LED_R, LOW);
        digitalWrite(LED_G, HIGH);
        digitalWrite(LED_B, HIGH);
        break;
   case GREEN:
        digitalWrite(LED_R, HIGH);
        digitalWrite(LED_G, LOW);
        digitalWrite(LED_B, HIGH);
        break;
   case YELLOW:
        digitalWrite(LED_R, LOW);
        digitalWrite(LED_G, LOW);
        digitalWrite(LED_B, HIGH);
        break;
   case BLUE:
       digitalWrite(LED_R, HIGH);
       digitalWrite(LED_G, HIGH);
       digitalWrite(LED_B, LOW);
       break;
   case PINK:
       digitalWrite(LED_R, LOW);
       digitalWrite(LED_G, HIGH);
       digitalWrite(LED_B, LOW);
       break;
   case SKY:
       digitalWrite(LED_R, HIGH);
       digitalWrite(LED_G, LOW);
       digitalWrite(LED_B, LOW);
       break;
   case WHITE:
      digitalWrite(LED_R, LOW);
      digitalWrite(LED_G, LOW);
     digitalWrite(LED_B, LOW);
     break;
 case 8:
      digitalWrite(LED_R, LOW);
      digitalWrite(LED_G, HIGH);
      digitalWrite(LED_B, HIGH);
      break;
  case 9:
      digitalWrite(LED_R, HIGH);
      digitalWrite(LED_G, LOW);
      digitalWrite(LED_B, HIGH);
      break;
   default:
      digitalWrite(LED_R, HIGH);
      digitalWrite(LED_G, HIGH);
      digitalWrite(LED_B, HIGH);
      break;
   }
}


COMMENTS

Fujita Nozomu

By “buzzer” do you mean piezoelectric speaker?

Okamiya Yuuki

Oops. Yes, you’re right! I fixed the wording.

Carcon 999

I have a question about the spec for the TONE function.
When I change PIN3 to an output pin, a pulse is output from that pin as well when using TONE.
Serial.begin(9600);
pinMode(LED_R , OUTPUT); //LED RED
pinMode(LED_G , OUTPUT); //LED GREEN
pinMode(LED_B , OUTPUT); //LED BLUE
pinMode(3 , OUTPUT);

Carcon 999

Using the above sample,
pinMode(3 , OUTPUT); <- By adding just this line,
A TONE pulse is output from both PIN2 and PIN3.
* Sorry. I didn’t mean to say that I switched PIN2 to PIN3. My explanation got erased somehow…

Fujita Nozomu

TO01, which can be assigned to PIN3, is used as the tone timer, as defined by
#define TONE_TIMER PWM_PIN_3 in
gr_common/include/RLduino78_mcu_depend.h.

The problem is that function

static void _startTimerChannel(uint8_t u8TimerChannel, uint16_t u16TimerMode, uint16_t u16Interval, bool bPWM, bool bInterrupt,

which is called by 

void tone(uint8_t u8Pin, unsigned int u16Frequency, unsigned long u32Duration) in gr_common/RLduino78/cores/RLduino78_basic.cpp, 

is coded so that the timer is output as usual, regardless of the value of argument bPWM.

if (bPWM == true) {
TOM0.tom0 |= (1 << u8TimerChannel);// Timer output mode setting
} else {
TOM0.tom0 &= ~(1 << u8TimerChannel);// Timer output mode setting
}
TOL0.tol0 &= ~(1 << u8TimerChannel);// Timer output level setting
TO0.to0 &= ~(1 << u8TimerChannel);// Timer output setting
TOE0.toe0 |= (1 << u8TimerChannel);// Timer output enable setting
TS0.ts0 |= (1 << u8TimerChannel);// Timer output operation enable setting

Fujita Nozomu

Since timer unit 0 channel 4 is used as Servo,
gr_common/include/RLduino78_mcu_depend.h:
#define SERVO_CHANNEL 4 // TM04
It interferes with PWM_PIN_9 and the same problem occurs. (PWM_PIN_9 と被る の意味が良くわかりません。何がPIN_9と被る?)


Fujita Nozomu

Unit 0 on GR-KURUM has 8 timers. Among those timers, channel 0 is used for the PWM Mater (masterでしょうか) channel (?) and 5 other channels are used to support each hardware PWM pin. (8 timers となっていますけど、以下は6timersの話しか出てこないです。)

gr_common/include/RLduino78_mcu_depend.h:
#define PWM_PIN_3 1 // TO1
#define PWM_PIN_5 2 // TO2
#define PWM_PIN_6 7 // TO7
#define PWM_PIN_9 4 // TO4
#define PWM_PIN_10 3 // TO3

If some pins are not used for PWM, the corresponding timer channel could be used for something else (supposedly). Currently, channels 1 and 4 are reserved exclusively as PWM for Tone and Servo.
#define TONE_TIMER PWM_PIN_3
#define SERVO_CHANNEL 4 // TM04

Channel 6 is used for software PWM.
#define SW_PWM_TIMER 6

Channel 5 is hard coded for the microsecond timer.

gr_common/RLduino78/cores/RLduino78_timer.c:
TT0.tt0 |= 0x0020; // Microsecond timer operation stop
TMR05.tmr05 = IT_CLOCK_MODE; // Microsecond timer operation mode setting
TDR05.tdr05 = INTERVAL_MICRO; // Microsecond timer frequency setting
TO0.to0 &= ~0x0020; // Microsecond timer output setting
TOE0.toe0 &= ~0x0020; // Microsecond timer output enable setting

The pins and timer channels used for hardware PWM correspond with each other, so that the corresponding timer channel of a pin that is not used for hardware PWM can be used for another purpose.

The timers used for Tone, Servo, software PWM and microsecond timer function as simple interval timers. The channels of those timers should be selectable by the user. However, the library currently in use requires the section after gr_common to be rewritten.

Adding the function or changing the specification so that each timer channel could be changed by the user would allow users the freedom to assign pins as they wish.

Example:
SetToneTimer(6); // Hardware PWM uses 5 timer channels, software PWM uses no timer channels, so the remaining timer channel 6 can be assigned to Tone.

Fujita Nozomu

Above I said, “It interferes with PWM_PIN_9 and the same problem occurs.” But that doesn’t occur.

Fujita Nozomu

Above I said “…is coded so that the timer is output as usual, regardless of the value of argument bPWM.”
Correction: “…is coded so that the timer is output as usual, regardless of the value of argument bInterrupt.


Okaymiya Yuuki

Renesas Night is coming up really soon. Fujita-san, thank you for your post. I haven’t had time to confirm it yet, please give me a little more time.

Fujita Nozomu

I have a suggestion for the post indicating that, “When I change PIN3 to an output pin, a pulse is output from that pin as well when using TONE.” (by Carcon 999

Try the changing the following:

gr_common/RLduino78/cores/RLduino78_basic.cpp
TOL0.tol0 &= ~(1 << u8TimerChannel);// Timer output level setting
TO0.to0 &= ~(1 << u8TimerChannel);// Timer output setting
TOE0.toe0 |= (1 << u8TimerChannel);// Timer output enable setting
To 
if (bInterrupt == true) {
TO0.to0 &= ~(1 << u8TimerChannel);// Timer output setting
TOE0.toe0 &= ~(1 << u8TimerChannel);// Timer output disable setting
} else {
TOL0.tol0 &= ~(1 << u8TimerChannel);// Timer output level setting
TO0.to0 &= ~(1 << u8TimerChannel);// Timer output setting
TOE0.toe0 |= (1 << u8TimerChannel);// Timer output enable setting
}


Carcon 999

Fujita-san: thank you very much.
I am happy to finally know that the cause of the LEDs not working properly on my board is related to TONE.
No rush, but please let me know when you figure out if the library can be used to resolve the problem.
※藤田さん中の人みたいですね。(笑) どういう意味でしょうか?


Okamiya Yuuki
I apologize for the confusion. The disturbance of D3 PWM output by tone may be due to the spec, but I didn’t expect that it would affect the port output as well. I will check out Fujita-san’s corrections and report back.

Okamiya Yuuki
I just checked and it looks like Fujita-san’s corrections are good.
Probably at least the starred (☆ ) items below will operate, but I will make an update after further evaluation.
By the way, further back Carcon 999-san’s comments got cut off. I think this is due to "<<" being mistaken as restricted characters. It happened to me as well. << are two-byte characters.

☆if (bInterrupt == true) {
TO0.to0 &= ~(1 <<u8TimerChannel);// Timer output setting
☆ TOE0.toe0 &= ~(1 << u8TimerChannel);// Timer output disable setting
☆} else {
TOL0.tol0 &= ~(1 << u8TimerChannel);// Timer output level setting
TO0.to0 &= ~(1 << u8TimerChannel);// Timer output setting
☆ TOE0.toe0 |= (1 << u8TimerChannel);// Timer output enable setting
☆}
The problem is generated because the timer for creating the tone uses TIO1, yet TIO01 is also assigned to PIN2 PWM. Although the timer should be set so that it does not output to the port when a tone is created, it was still set to output to the port. So when the corresponding port is enable, the timer for creating the tone will be output to that port as well.

Fujita Nozomu
About “<<" being mistaken as restricted characters:
You can avoid this by writing &lt;&lt;
But you can write # "&lt;" in single-byte characters…

Carcon 999

So that is where I went wrong… I need to be careful about ’<<’ (two-bytes). I don’t use those characters that often, maybe I was in a hurry that day.