Hey guys,
RIoTboard Piezo Buzzer Test from Luke Marvin on Vimeo.
In this post I was hoping to discuss more about the "division of labour" across the different levels of software. I'm relatively new to kernels and what-not so maybe someone here can lend me a hand.
In my test I have the buzzer connected through a 1k ohm resistor, to PWM 2 and GND.
In my 3.0.35 kernel I have made the following changes as suggested by Eric Nelson (https://community.freescale.com/message/436421):
- I updated the leds-pwm.c driver with the changes made in this commit. https://github.com/boundarydevices/linux-imx6/commit/63b106e30a42e5ee89c4c7d0644e853f013276db
- I updated my /kernel_imx/arch/arm/configs/imx6_android_defconfig file to include the leds-pwm.c driver. "CONFIG_LEDS_PWM=y"
- I added a new platform device to my /arch/arm/mach-mx6/board-mx6solo_RIoTboard.c file using this file as an example. https://github.com/boundarydevices/linux-imx6/blob/boundary-imx_3.0.35_4.1.0/arch/arm/mach-mx6/board-mx6_r.c#L803
- I recompiled my kernel and boot image, programmed the board and booted it up.
Now I have a device located at /sys/class/leds/buzzer which I can echo values into, which then plays a sound.
I wrote the following C file to play the wailing sound from the video.
#include <stdint.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/types.h> #include <linux/delay.h> #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static void pabort(const char *s) { perror(s); abort(); } static int note_fd; static int frequency_fd; static int period_fd; static char *note = "/sys/class/leds/buzzer/note"; static char *frequency = "/sys/class/leds/buzzer/frequency"; static char *period = "/sys/class/leds/buzzer/period"; static char buff; static char stop = ' '; static void play_note(char* f, unsigned int length) { write(frequency_fd,f,sizeof(f)); usleep(length); write(frequency_fd,"0",1); } int main(int argc, char *argv[]) { int ret = 0; char* firstNote = "2000"; unsigned int length = 250000; frequency_fd = open(frequency,O_RDWR); if (note_fd < 0) pabort("lcd reset pin unavailable"); play_note("4096",150000); play_note("2048",150000); play_note("4096",150000); play_note("2048",150000); play_note("4096",150000); play_note("2048",150000); play_note("4096",150000); play_note("2048",150000); close(note_fd); return ret; }
I cross compiled the file on my linux computer.
'/home/riot/android-imx6-jb4.3-1.0.0/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-gcc-4.6.x-google' --sysroot='/home/riot/android-imx6-jb4.3-1.0.0/prebuilts/ndk/8/platforms/android-14/arch-arm' -o wail wail.c
Then I used Dropbox to send the binary to my Windows PC where I upload the file to the board using ADB. Finally I chmod the file to make it executable and I execute it.
Phewf. It works.
Then I whipped up an Android app that has a Buzzer class.
public class Buzzer { InputStream buzzerInputStream; OutputStream buzzerOutputStream; PrintStream buzzerPrintStream; String BUZZER_PATH = "/sys/class/leds/buzzer/frequency"; Handler stopBuzzHandler = new Handler(); Runnable stopBuzzRunnable = new Runnable() { @Override public void run() { buzzerPrintStream.print("0"); } }; public Buzzer() throws IOException { // buzzerInputStream = socket.getInputStream(); buzzerOutputStream = new FileOutputStream(BUZZER_PATH); buzzerPrintStream = new PrintStream(buzzerOutputStream); } public void buzz(int length){ buzzerPrintStream.print("1000"); stopBuzzHandler.postDelayed(stopBuzzRunnable, (long)length); } }
As long as I have chmod'd the file I can access it directly from the Android app and use the buzzer.
In conclusion, here is my plan. Let me know if it sounds reasonable to you guys.
- Modify the pwm-leds.c driver to include a new "attribute" file called wail. When I write a 1 to it, it starts wailing. When I write a 0 to it, it stops.
- Set the permissions of the file at boot time.
- In my Android app, when there is an alarm I write a 1 to the file. Then write a 0 to cancel it.