Touch, Shake & Whine
Musical instrument with touchpad & accelerometer.
This project uses a Nintendo DS touchpad and a Freescale MMA7260 3D accelerometer to make music.
A PWM signal is used to drive a piezo buzzer. A cheap Nintendo DS resistive touchpad is setup as a keypad with 24 hotspots (6 by 4). Each hotspot corresponds to a musical note, two octaves in this case, so it is possible to play tunes on the touchpad. Two of the three outputs of a Freescale MMA7260 3D accelerometer mounted on a demo board are available to modulate the period and the pulswidth of the PWM signal. LED1 blinks under Ticker control just to show that the program is running.
Touching, shaking, rotating, tilting etc. of the whole setup will make it whine or sing, depending on your musical skills. Play it as a musical instrument with natural vibrato or just shake it to create annoying noises.
This project demonstrates:
- the use of a resistive touchpad
- the use of a 2D accelerometer
- the use of PWM for smooth frequency generation
- on-the-fly pin function switching
- mbed "base" class extension
Have fun!
CPV (September 15, 2009)
Hardware
|
- The touchpad can be found on eBay for about $2,-.
|
|
| Schematic, click to enlarge | The accelerometer sits on the pcb that comes out from under the the touchpad. The black circular object is the buzzer |
Software
Right-click the project to import to, select "Import Library..." and use the following details:
- Library SVN URL: http://mbed.co.uk/projects/cookbook/svn/touchpad/trunk
- Library Name: touchpad
View the library
Binary
/* mbed touchpad & accelerometer experiments. CPV, 14/09/2009 */ #include "mbed.h" #include "touchpad.h" #include "accelerometer.h" #include "my_pwm_out.h" // Pin definitions. #define ACC0 p20 #define ACC1 p19 #define X0 p18 #define Y0 p17 #define X1 p16 #define Y1 p15 // Some global objects. DigitalOut led1(LED1); Ticker timer1; // Sample clock. Ticker timer2; // "keyboard" scan clock. Ticker timer3; // LED clock. Touchpad tp(X0,X1,Y0,Y1); Accelerometer2D acc(ACC0,ACC1,10); MyPwmOut buzzer(p21); // Subclassed from PwmOut. float DutyCycle = 0.0; // No sound. int Period = 1136; // in us => 880 Hz. int FlagUpdateSound = 0; // Periods in us. const int freq[4][6] = { { 1607, 1517, 1432, 1351, 1276, 1204 }, { 1136, 1073, 1012, 956, 902, 851 }, { 804, 758, 716, 676, 638, 602 }, { 568, 536, 506, 478, 451, 426 }, }; void sample(void) { tp.tick(); acc.tick(); } void scan_keyboard(void) { if (tp.hotspot()>0) { int x = tp.get_hotspot_x(); int y = tp.get_hotspot_y(); Period = freq[y][x]*(1.0+acc.read(0)/64000.0); DutyCycle = 0.5 + acc.read(1)/32000.0; FlagUpdateSound = 1; } else { if (DutyCycle!=0.0) { DutyCycle = 0.0; FlagUpdateSound = 1; } } } void toggle_led(void) { if (led1==1) led1 = 0; else led1 = 1; } int main() { printf("\n"); printf("-=o Touch, Shake & Whine o=-\n"); printf("\n"); printf("mbed touchpad & 2D accelerometer demo\n"); printf("\n"); printf("A buzzer is driven by a PWM signal to generate musical notes.\n"); printf("A touchpad is used as a keypad, divided in a 6 by 4 matrix.\n"); printf("The position on the touchpad determines the note played by the\n"); printf("buzzer. A 2-axis accelerometer is used to modulate the frequency\n"); printf("and the duty-cycle of the PWM signal.\n"); printf("A blinking LED shows that the system is running.\n"); printf("\n"); printf("Touch & shake the circuit to make it whine.\n"); printf("\n"); printf("Demonstrates:\n"); printf("- the use of a resistive touchpad\n"); printf("- the use of a 2D accelerometer\n"); printf("- the use of PWM for smooth frequency generation\n"); printf("- on-the-fly pin function switching\n"); printf("- mbed \"base\" class extension\n"); printf("\n"); printf("CPV, 14/09/2009\n"); printf("\n"); printf(" -end-\n\n"); led1 = 1; // LED on. timer1.attach_us(&sample,1000); // Sample every 1 ms. timer2.attach_us(&scan_keyboard,10000); // Scan the touchpad every 10 ms. timer3.attach_us(&toggle_led,500000); // Toggle the LED every 500 ms. while (1) { if (FlagUpdateSound==1) { // Only update period & duty-cycle when new data is available. FlagUpdateSound = 0; buzzer.set(Period/1000000.0,DutyCycle); } } }
Development Log
- Driving the touchpad requires four analog inputs that can be reconfigured as digital outputs. This requires defining pins on the fly instead of globally as is done in most examples. The pins are created on the stack, I don't know what the overhead for this is, but it works fine.
- It turned out that the PwmOut functions reset their output when the period is changed, i.e. a pulse is being missed every time the period is changed. This resulted in very audible interference from the touchpad & accelerometer sample routines. I decided to derive a class from PwmOut, MyPwmOut, that provides a function to update the period and the pulsewidth at the same time. Deriving is easy, but implementing pin independent functions is a bit more complicated because there is no documentation about what is available to a class. PwmOut itself is derived from Base, but what is in Base? It was therefore necessary to probably reinvent the wheel with respect to pin and PWM information. Figuring out the PWM clock for period and pulsewidth calculations, what pin is it on and so what registers to use? Nothing really complicated, but it is a shame not to have access to what the class already knows.
- When doing PWM, make sure to use the LER register!
- The accelerometer outputs are filtered with a simple integer IIR, the touchpad outputs are filtered by a box filter. These filters are implemented as a separate class.


