2 Replies Latest reply on Sep 20, 2014 6:43 AM by tushar panda

    Piezo Buzzer Control: Kernel, User Space or Android level?

    mukelarvin_price

      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.

      Photo 2014-09-19, 10 42 13 AM.jpg


      In my 3.0.35 kernel I have made the following changes as suggested by Eric Nelson (https://community.freescale.com/message/436421):


      1. I updated the leds-pwm.c driver with the changes made in this commit. https://github.com/boundarydevices/linux-imx6/commit/63b106e30a42e5ee89c4c7d0644e853f013276db
      2. I updated my /kernel_imx/arch/arm/configs/imx6_android_defconfig file to include the leds-pwm.c driver. "CONFIG_LEDS_PWM=y"
      3. 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
      4. 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.

      1. 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.
      2. Set the permissions of the file at boot time.
      3. In my Android app, when there is an alarm I write a 1 to the file. Then write a 0 to cancel it.