Adding velocity sensitive note presses was a desirable feature. There seemed to be two acceptable approaches: find buttons with double action, or use an accelerometer. A Freescale Semiconductor MMA8452Q with breakout board was purchased from Sparkfun. The chip has a 1.6V - 3.6 interface voltage and uses I2C as the protocol for communication. In order to do some initial testing, the accelerometer was wired to a plain Arduino and the sample code provided by sparkfun was tested and worked correctly. Although the device uses I2C, the standard arduino wire library can not be used as it is powered with 3.3v and the wire library expects 5v of input. It would be possible to use a logic level converter but I did not want to introduce more hardware. Sparkfun has a few files on the accelerometer page that are supposed to facilitate the devices use without modification. Using their sample code, the device reported values and worked correctly.
I spent a large amount of time reading over various data sheets for the accelerometer in order to learn how to set and read its registers for the proper frequency, g forces, and values. Various other references also described some of the built in features such as tap detection, high pass filtering, and transient detection however none of these appeared to be helpful for my work. The accelerometer was sending appropriate data and it appeared all was well. I integrated the needed sample code chunks into the Rainboard code but started having intermittent issues. The code would work sometimes, but not all the time. I spent a couple days trying to debug the issue but was not getting very far. In order to determine if the issue was a conflict with other portions of my code, I started modifying the sample code with my Rainboard code to see if the sample code would then fail. I managed to get the sample code to fail but still had trouble identifying the cause. If known working code was uploaded to the device and the device was re-flashed with known bad code, the bad code would work. However, if the device was unplugged (allowed to fully power down) the bad code would not work. I deduced that the issue was occurring during the initial setting of the accelerometer registers which resulted in bad code working until the registers were wiped by a power loss.
Determining that I had to power off the device between each code test allowed me to find a distinct way to create bad and good code: insert a delay statement while setting up the registers for the accelerometer. The odd thing about the delay statement was that even a delay of time zero created bad code. I took the good and bad code and dumped assembly versions. After looking step by step through the assembly I could not determine what was causing the issue. The problem was so time consuming that I thought it would be more effective to order a logic analyzer to aid in debugging. I put the accelerometer aside for a couple days until the hardware logic analyzer arrived. The use of the analyzer confirmed that the code with a delay was not performing correctly as it seemed to miss several of the instructions within the program. Not finding much help on the internet, I eventually found a new I2C library that was being developed and converted my code to use it. This solved the register setting problem and I was able to continue with using accelerometer data.
In order to detect hit velocity only the axis orthogonal to the playing surface needs to be used. In order to determine the relation between button press and velocity the twenty values before and after a button press were printed each time a button was pressed. Significant values appeared one or two samples before the button press and between five and ten samples after the press. Several different methods of filtering the data were attempted. Using the average value for the samples did not give very good results. The magnitudes did not appear overly related to the velocity of press. The jerk value (first derivative of the acceleration) was also tried and gave reasonable results. The calculation that appeared to give the best result was taking an average of the absolute values starting from two samples before the button press and three samples after. The end result is that the value calculated represents the sum of vertical force oscillation in both directions of the Rainboards surface. The harder the initial force, the larger the summed absolute acceleration force is. This number is then converted into a midi velocity value using two variables for minimum velocity and sensitivity. It was also considered that applying forces at different points on the board would create different values for the same force intensity, however the simple approach works satisfactory.
The accelerometer has a number of data collection frequency settings ranging from 800hz to 12.5hz. The speed chosen was 200hz as it allows for fine grained data but does not consume too much cpu time. There are two ways to determine if new data is available from the accelerometer: checking status via I2C or via an interrupt pin. The I2C connection is much to slow to poll every loop so it was not used. The interrupt was an decent idea but I did not want to worry about concurrency. To alleviate the issue, I polled the pin that the accelerometer used to send the interrupt using optimizing pin reading code rather than having an interrupt be fired. The data received from the accelerometer is stored in a ring buffer with twenty elements.