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.
