EmbedEd
/
mbed_theremin
xypad theremin for LPC1768
Revision 0:8ee38453bad9, committed 2016-03-13
- Comitter:
- exopiped
- Date:
- Sun Mar 13 01:12:40 2016 +0000
- Child:
- 1:aa184d2eb2e3
- Commit message:
- Rebuilt from original code from April 2014
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MODDMA.lib Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/code/MODDMA/#97a16bf2ff43
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,68 @@ +/* + ** debug.cpp -- a few handy debug functions + */ +#include "mbed.h" +#include "debug.h" +#include "string.h" + + RawSerial rs(USBTX, USBRX); + + static char debug_hexnyb(char); + + void debug_putstr(char *sptr) + { + int j,len; + + len = strlen(sptr); + if (len>64) len = 64; + for (j=0;j<len;j++) { + debug_putch(sptr[j]); + } + } + + int debug_putch(char ch) { + return rs.putc(ch); + } + + void debug_hexbyte(char inch) + { + char lonyb,hinyb; + + lonyb = inch & 0x0F; + hinyb = (inch >> 4) & 0x0F; + (void)debug_putch(debug_hexnyb(hinyb)); + (void)debug_putch(debug_hexnyb(lonyb)); + } + + char debug_hexnyb(char inval) + { + switch (inval) { + case 0 ... 9: + return (char)(0x30 | inval); + case 10 ... 15: + return (char)(0x37 + inval); + } + return ('.'); + } + +void debug_hexshort(short inval) + { + char loch,hich; + + loch = inval & 0xFF; + hich = (inval>>8) & 0xFF; + debug_hexbyte(hich); + debug_hexbyte(loch); + } + +void debug_crlf(void) + { + (void)debug_putch(0x0D); + (void)debug_putch(0x0A); + } + +void debug_space(void) + { + (void)debug_putch(0x20); + } +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,12 @@ +/* + * debug.h -- simple debug interface + */ +#ifndef DEBUG_H +#define DEBUG_H +void debug_putstr(char *sptr); +int debug_putch(char ch); +void debug_hexbyte(char); +void debug_hexshort(short inval); +void debug_crlf(void); +void debug_space(void); +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dma.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,141 @@ +/* + * dma.cpp + * Send a buffer repeatedly to the DAC using DMA. + */ +#include "mbed.h" +#include "note.h" +#include "MODDMA.h" +#include "dma.h" + +int buffer[2][DMA_BUFSIZE]; + +AnalogOut sig(p18); // analog output object ( uses pin 18) + +MODDMA dma; +MODDMA_Config *conf0, *conf1; + +int *dma_get_bufptr(int bufno) +{ + return buffer[bufno]; +} + +void dma_init(void) { + + // Prepare the GPDMA system for buffer0. + conf0 = new MODDMA_Config; + conf0 + ->channelNum ( MODDMA::Channel_0 ) + ->srcMemAddr ( (uint32_t) &buffer[0] ) + ->dstMemAddr ( MODDMA::DAC ) + ->transferSize ( 512 ) + ->transferType ( MODDMA::m2p ) + ->dstConn ( MODDMA::DAC ) + ->attach_tc ( &TC0_callback ) + ->attach_err ( &ERR0_callback ) + ; // config end + + + // Prepare the GPDMA system for buffer1. + conf1 = new MODDMA_Config; + conf1 + ->channelNum ( MODDMA::Channel_1 ) + ->srcMemAddr ( (uint32_t) &buffer[1] ) + ->dstMemAddr ( MODDMA::DAC ) + ->transferSize ( 512 ) + ->transferType ( MODDMA::m2p ) + ->dstConn ( MODDMA::DAC ) + ->attach_tc ( &TC1_callback ) + ->attach_err ( &ERR1_callback ) + ; // config end + + +// +// By default, the Mbed library sets the PCLK_DAC clock value +// to 24MHz. One wave cycle in each buffer is DMA_BUFSIZE +// (512) points long. The sample rate of the output is to be +// WAVE_SAMPLE_RATE (22050) samples per second, regardless of. +// wave frequency. So the DACCNTVAL will be 24000000/22050 +// or 1088. +// + + LPC_DAC->DACCNTVAL = 1088; // for 22050 sample rate + +// +// the wave templates will be one dma buffer long, so the +// lowest frequency that can be produced is +// WAVE_SAMPLE_RATE/DMA_BUFSIZE = 22050/512 = 43 Hz +// the highest frequency wave that can be produced is +// roughly half the sample rate, or 11025 Hz. +// +} + +void dma_enable(void) +{ + // Prepare first configuration. + if (!dma.Prepare( conf0 )) { + error("Doh!"); + } + + // Begin (enable DMA and counter). Note, don't enable + // DBLBUF_ENA as we are using DMA double buffering. + LPC_DAC->DACCTRL |= (3UL << 2); +} + +void dma_disable(void) +{ + + // Finish the DMA cycle by shutting down the channel. + dma.Disable((MODDMA::CHANNELS)conf0->channelNum()); + dma.Disable((MODDMA::CHANNELS)conf1->channelNum()); + +} + +// Configuration callback on TC +void TC0_callback(void) { + + dma.Disable((MODDMA::CHANNELS)conf0->channelNum()); + + if (note_active()) { + // Notify note.cpp that it is time to refill buffer[0] + note_set_bufno(0); + + // Swap to buffer1 + dma.Prepare( conf1 ); + + // Clear DMA IRQ flags. + if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); + } else { + dma.Disable((MODDMA::CHANNELS)conf1->channelNum()); + } +} + +// Configuration callback on Error +void ERR0_callback(void) { + error("Oh no! My Mbed EXPLODED!"); +} + +// Configuration callback on TC +void TC1_callback(void) { + + // Finish the DMA cycle by shutting down the channel. + dma.Disable((MODDMA::CHANNELS)conf1->channelNum()); + + if (note_active()) { + // Notify note.cpp that it is time to refill buffer[1] + note_set_bufno(1); + + // Swap to buffer0 + dma.Prepare( conf0 ); + + // Clear DMA IRQ flags. + if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); + } else { + dma.Disable((MODDMA::CHANNELS)conf0->channelNum()); + } +} + +// Configuration callback on Error +void ERR1_callback(void) { + error("Oh no! My Mbed EXPLODED!"); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dma.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,17 @@ +#ifndef DMA_H +#define DMA_H + +#define DMA_BUFSIZE 512 +#define DAC_POWER_MODE (1<<16) + +void dma_init(void); +void dma_enable(void); +void dma_disable(void); +int *dma_get_bufptr(int bufno); +void TC0_callback(void); +void ERR0_callback(void); +void TC1_callback(void); +void ERR1_callback(void); + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/envlp.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,111 @@ +/* + * envlp.c -- manage the note's envelope state machine + */ +#include "mbed.h" +#include "debug.h" +#include "touch.h" +#include "jswitch.h" +#include "envlp.h" +/* + * sound envelope follows ADSR pattern + * (Attack, Decay, Sustain, Release) + * three parameters below control the envelope shape + * It should be easy to consider these default values + * and modify the code below to set the variables + * envlp_attack_bufs, envlp_release_bufs, + * and envlp_release_delta dynamically, + * depending upon external inputs + */ +#define ATTACK_BUFFERS_MIN 2 +#define ATTACK_BUFFERS_MAX 20 +#define ATTACK_BUFFERS 5 // attack buffers +#define DECAY_BUFFERS_MIN 1 +#define DECAY_BUFFERS_MAX 40 +#define DECAY_BUFFERS ATTACK_BUFFERS/2 // decay buffers +#define RELEASE_DELTA_MIN 1 +#define RELEASE_DELTA_MAX 128 +#define RELEASE_DELTA 8 // inverse release duration param + +/* + * local envelope functions + */ +static void envlp_set_attack_bufs(void); +static void envlp_set_decay_bufs(void); +static void envlp_set_release_delta(void); + +/* + * local envelop veriables + */ +static int envlp_attack_bufs; +static int envlp_decay_bufs; +static int envlp_release_delta; + +void envlp_init(void) +{ + envlp_attack_bufs=ATTACK_BUFFERS; + envlp_decay_bufs=DECAY_BUFFERS; + envlp_release_delta=RELEASE_DELTA; +} + +void envlp_update(void) +{ + envlp_set_attack_bufs(); + envlp_set_decay_bufs(); + envlp_set_release_delta(); +} + +void envlp_set_attack_bufs() +{ + unsigned char js_val; + + js_val = js_read((JS_UP | JS_DOWN)); + if (js_val & JS_UP) { + if (envlp_attack_bufs < ATTACK_BUFFERS_MAX) { + envlp_attack_bufs++; + } + } else if(js_val & JS_DOWN) { + if (envlp_attack_bufs > ATTACK_BUFFERS_MIN) { + envlp_attack_bufs--; + } + } +} + +int envlp_get_attack_bufs(void) +{ + return envlp_attack_bufs; +} + +void envlp_set_decay_bufs(void) +{ + if (envlp_attack_bufs>1) { + envlp_decay_bufs = envlp_attack_bufs/2; + } else { + envlp_decay_bufs = 1; + } +} + +int envlp_get_decay_bufs(void) +{ + return envlp_decay_bufs; +} + +void envlp_set_release_delta(void) +{ + unsigned char js_val; + + js_val = js_read((JS_LEFT | JS_RIGHT)); + if (js_val & JS_LEFT) { + if (envlp_release_delta < RELEASE_DELTA_MAX) { + envlp_release_delta++; + } + } else if(js_val & JS_RIGHT) { + if (envlp_release_delta > RELEASE_DELTA_MIN) { + envlp_release_delta--; + } + } +} + +int envlp_get_release_delta(void) +{ + return envlp_release_delta; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/envlp.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,16 @@ +#ifndef ENVLP_H +#define ENVLP_H +/* + * envlp.h -- Functions which help note.cpp produce + * an ADSR (Attack,Decay,Sustain,Release) envelope + */ +#define ENVLP_MAX (0x1FF) + +void envlp_init(void); +void envlp_update(void); +int envlp_get_attack_bufs(void); +int envlp_get_decay_bufs(void); +int envlp_get_release_delta(void); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2c.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,59 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MBED_I2C_API_H +#define MBED_I2C_API_H + +#include "device.h" + +#if DEVICE_I2C + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct i2c_s i2c_t; + +enum { + I2C_ERROR_NO_SLAVE = -1, + I2C_ERROR_BUS_BUSY = -2 +}; + +void i2c_init (i2c_t *obj, PinName sda, PinName scl); +void i2c_frequency (i2c_t *obj, int hz); +int i2c_start (i2c_t *obj); +int i2c_stop (i2c_t *obj); +int i2c_read (i2c_t *obj, int address, char *data, int length, int stop); +int i2c_write (i2c_t *obj, int address, const char *data, int length, int stop); +void i2c_reset (i2c_t *obj); +int i2c_byte_read (i2c_t *obj, int last); +int i2c_byte_write (i2c_t *obj, int data); + +#if DEVICE_I2CSLAVE +void i2c_slave_mode (i2c_t *obj, int enable_slave); +int i2c_slave_receive(i2c_t *obj); +int i2c_slave_read (i2c_t *obj, char *data, int length); +int i2c_slave_write (i2c_t *obj, const char *data, int length); +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jswitch.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,77 @@ +/* + * jswitch.cpp -- debounces and reads pins 12 + * (SW_DOWN), 13(SW_LEFT),14(SW_CENTER),15(SW_UP), + * and 16(SE_RIGHT) of the mbed 40 pin dip board + */ +#include "mbed.h" +#include "debug.h" +#include "jswitch.h" + +#define JS_BLANKING_MSEC 333 + +DigitalIn js_down(p12); +DigitalIn js_left(p13); +DigitalIn js_center(p14); +DigitalIn js_up(p15); +DigitalIn js_right(p16); + +Timer js_timer; + +static unsigned char js_oldest=0; +static unsigned char js_older=0; +static unsigned char js_old=0; +static unsigned char js_now=0; +static unsigned char js_official=0; +static int js_msec=0; + +void js_init(void) +{ + js_official = 0; + js_now = 0; + js_old = 0; + js_older = 0; + js_oldest = 0; + js_timer.start(); +} +/* + * js_debounce -- button presses will not be reported + * any more that once every 333 msec. + */ +void js_debounce(void){ + if ((js_timer.read_ms()-js_msec)>JS_BLANKING_MSEC) { + if (js_official==0) { + js_oldest = js_older; + js_older=js_old; + js_old=js_now; + js_now = ( (js_center << 4) + | (js_up << 3) + | (js_down << 2) + | (js_left << 1) + | js_right ); + js_official|=(js_now&js_old&js_older&js_oldest); + if (js_official>0) { + js_msec=js_timer.read_ms(); +// debug_hexbyte(js_official); + } + } else { + js_now=0; + js_old=0; + js_older=0; + js_oldest=0; + } + } +} +/* + * js_read -- reads buttons indicated by the mask. + * once read the masked button indications are cleared + */ +unsigned char js_read(unsigned char mask) +{ + unsigned char retval; + + retval = js_official & mask; + js_official &= ~retval; + return retval; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jswitch.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,16 @@ +/* + * jswitch.h -- header for jswitch.cpp, which reads the + * joystick pins, and provides debounced version + * of the pins to js_read() caller. + */ + #ifndef JSTICK_H + #define JSTICK_H + #define JS_CENTER 0x10 + #define JS_UP 0x04 + #define JS_DOWN 0x08 + #define JS_LEFT 0x01 + #define JS_RIGHT 0x02 + void js_init(void); + void js_debounce(void); + unsigned char js_read(unsigned char mask); + #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,33 @@ +/* + * main.cpp + * Sending digital note waveforms out the onboard DAC + * in responses to touches on an XY pad(resistive touchscreen) + * X changes audio volume.. Y changes audio frequency + * Varies from forty Hz to 1047 Hz (C6) + */ +#include "mbed.h" +#include "debug.h" +#include "dma.h" +#include "wave.h" +#include "note.h" +#include "jswitch.h" +#include "touch.h" +#include "envlp.h" + +int main(void) +{ + js_init(); // initialize joystick + envlp_init(); // initialize envelope parameters + wave_init(); // starts with default wave type + touch_init(); // initialize touchscreen controller + note_init(); // initialize note production + + while (1==1) { + js_debounce(); // debounce joystick + envlp_update(); // update envelope parameters + wave_update(); // update waveform choice + note_update(); // update note or start a new one + wait_ms(2); // lower limit on loop timing + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/87f2f5183dfb \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/note.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,279 @@ +/* + * note.cpp -- manage production of notes in response to + * touch screen input + */ +#include "mbed.h" +#include "InterruptIn.h" +#include "debug.h" +#include "dma.h" +#include "envlp.h" +#include "wave.h" +#include "touch.h" +#include "jswitch.h" +#include "note.h" + +DigitalOut led2(LED2); // lit during NOTE_RELEASE state + +typedef enum {NOTE_ATTACK,NOTE_DECAY,NOTE_SUSTAIN,NOTE_RELEASE,NOTE_OFF} NOTE_STATE; + +static void note_start(void); +static void note_state_machine(void); +static void note_fill_buf(void); +static void note_attack(void); +static bool note_attack_done(void); +static bool note_decay_done(void); +static void note_release(void); +static bool note_release_done(void); +static bool note_released(void); +static void note_end(void); + +static unsigned note_freq=0; // frequency in Hz +static NOTE_STATE note_state=NOTE_OFF; +static int note_bufno= NIL; // NIL or index of dma buffer +static int note_attack_bufcount; +static int note_attack_delta; +static int note_attack_bufs; +static int note_decay_bufs; +static int note_decay_bufcount; +static int note_decay_delta; +static int note_release_delta; +static int note_first_bufval; +static int note_last_bufval; +static int note_release_numerator; +static int note_release_denominator; + +void note_init(void) +{ + note_freq = 0; + note_state = NOTE_OFF; + note_bufno = NIL; + note_attack_bufcount=0; + note_decay_bufcount=0; + dma_init(); +} + +void note_start(void) +{ + if (wave_type_changed()) { + wave_type_incr(); + } + wave_reset(); + note_freq = touch_frequency(); + note_attack_bufs=envlp_get_attack_bufs(); + debug_hexshort((short)note_attack_bufs); + debug_putch(' '); + note_decay_bufs=envlp_get_decay_bufs(); + note_release_delta = envlp_get_release_delta(); + note_release_numerator = ENVLP_MAX - note_release_delta; + note_release_denominator = ENVLP_MAX; + debug_hexshort((short)note_release_numerator); + debug_crlf(); + + // fill first two buffers + note_attack(); + note_set_bufno(0); + note_state_machine(); + note_fill_buf(); + note_set_bufno(1); + note_state_machine(); + note_fill_buf(); + dma_enable(); +} + +void note_end(void) +{ + dma_disable(); + note_state=NOTE_OFF; + note_bufno=NIL; + led2 = 0; +} + +/* + * note_update + * update the frequency and attenuation factor for the + * current note. If the current envelope first and last + * add up to less than 2, end the note. + * otherwise check to see if it is time to fill a dma buffer. + * if so fill the one specified by note_fillbuf. + */ + +void note_update(void) +{ + // execute note state machine + note_state_machine(); + + // if dma buffer sent, refill it + if(note_bufno!=NIL) { + note_fill_buf(); + } + + // handle presence or absence of touch + if (touch_debounce()) { + wait_ms(10); // wait 10 msec if touch present + if (note_released() || !note_active()) { + note_start(); + } + } else { + if (note_active()) { + if (!note_released()) { + note_release(); + } + } + } +} + +void note_state_machine(void) +{ + // execute state machine that manages envelope + + switch (note_state) { + case NOTE_ATTACK: + if (note_attack_done()) { + note_state = NOTE_DECAY; + } + note_freq = touch_frequency(); + break; + + case NOTE_DECAY: + if(note_decay_done()) { + note_state = NOTE_SUSTAIN; + } + note_freq = touch_frequency(); + break; + + case NOTE_SUSTAIN: + note_freq = touch_frequency(); + break; + + case NOTE_RELEASE: + if (note_release_done()) { + note_end(); + break; + } + break; + case NOTE_OFF: + default: + break; + } +} + +/* + * note_fill_buf + * Use the first and last buffer envelope values, and the + * wave values returned by wave_nextval() to compute the + * envelop-modified wave values, and then apply the changes + * necessary to output the values to the DAC data register. + */ +void note_fill_buf(void) +{ + int j,start_env,end_env,env_val,wave_val,buf_val,amplitude; + int *bufptr=NULL; + + bufptr = dma_get_bufptr(note_bufno); + start_env = note_first_bufval; + end_env = note_last_bufval; + amplitude = touch_amplitude(); + + for (j=0;j<DMA_BUFSIZE;j++) { + env_val=start_env+(end_env - start_env)*j/DMA_BUFSIZE; + wave_val = wave_nextval(note_freq); + buf_val = wave_val * env_val / ENVLP_MAX; + buf_val=amplitude*buf_val/TOUCH_MAX_AMPLITUDE; + bufptr[j]= DAC_POWER_MODE | ((buf_val << 6) & 0xFFC0); + } + note_bufno = NIL; // buffer is filled + switch (note_state) { + case NOTE_ATTACK: + note_attack_bufcount++; + break; + case NOTE_DECAY: + note_decay_bufcount++; + break; + case NOTE_RELEASE: + note_first_bufval = note_last_bufval; + note_last_bufval = + note_first_bufval * note_release_numerator + / note_release_denominator; + break; + case NOTE_SUSTAIN: + case NOTE_OFF: + default: + ; + } +} + +/* + * note_release + * touch has been lifted, note begins to decay + */ +void note_release(void) +{ + led2 = 1; + note_state = NOTE_RELEASE; +} +/* + * note_released + * return true if note has been released + * but not yet ended + */ +bool note_released(void) +{ + return (note_state == NOTE_RELEASE); +} +bool note_active(void) +{ + return (note_state < NOTE_OFF); +} +/* + ** note_set_bufno + * Set the index of the dma buffer to fill. + * + */ +void note_set_bufno(int bufno) +{ + note_bufno = bufno; +} + +void note_attack(void) +{ + note_state = NOTE_ATTACK; + note_attack_bufcount = 0; + note_attack_delta = ENVLP_MAX / note_attack_bufs; + note_first_bufval=note_attack_bufcount*note_attack_delta; + note_last_bufval=note_first_bufval + note_attack_delta; +} + +bool note_attack_done(void) +{ + if (note_attack_bufcount >= note_attack_bufs) { + note_decay_bufcount = 0; + note_decay_delta = (ENVLP_MAX >> 1) / note_decay_bufs; + note_first_bufval = note_last_bufval; + return true; + } else { + note_first_bufval=note_attack_bufcount*note_attack_delta; + note_last_bufval=note_first_bufval+note_attack_delta; + } + return false; +} + +bool note_decay_done(void) +{ + if (note_decay_bufcount >= note_decay_bufs) { + note_first_bufval = note_last_bufval; + return true; + } else { + note_last_bufval=note_first_bufval - note_decay_delta; + if (note_last_bufval < 0) { + note_last_bufval=0; + } + } + return false; +} + +bool note_release_done(void) +{ + if (note_first_bufval < 25) return true; + return false; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/note.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,14 @@ +#ifndef NOTE_H +#define NOTE_H +/* + * note.h + * Start, update, release or end note, and fill dma buffers for + * one note at a time. + */ +#define NIL (-1) + +void note_init(void); +void note_update(void); +bool note_active(void); +void note_set_bufno(int bufno); +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/switch.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,10 @@ +/* + * jstick.h -- header for jstick.cpp, which reads the + * joystick pins, and provides debounced version + * of the pins to js_read() caller. + */ + #ifndef JSTICK_H + #define JSTICK_H + void js_init(void); + bool js_debounce(void); + #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/touch.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,322 @@ +/* + * touch.cpp -- touch screen monitor + */ +#include "mbed.h" +#include "debug.h" +#include "touch.h" + +#define NIL (-1) +/* + * Connecting the touch screen + * STMPE610 MODE pin is tied low for I2C interface + * STMPE610 A0 pin tied low for I2C address 0x41 + * (0x82 when shifted left 1) + * STMPE610 A0 pin tied high for I2C address 0x44 + * (0x88 when shifted left 1) + * + * I2C works on board pins 9 and 10. (SDA, SDL) + * ( STMPE610 pins SDAT and SCLK ) + * + * Setting up the touch screen + * + * Disable Touch Screen and A/D clock -- SYS_CTRL2 + * Set TSC_OFF bit high, ADC_OFF bit high + * + * ConfigureTouch Screen -- TSCFG register + * Set up for 4 sample averaging + * Touch detect delay of 1 msec + * Settling time of 1 msec + * + * Touchscreen Window -- WDW_TR_X, WDW_TR_Y, WDW_BL_X, WDW_BLY + * Set up for full screen ( default condition ) + * + */ + +typedef enum {TOUCH_NOTOUCH,TOUCH_DEBOUNCE,TOUCH_PRESENT} TOUCH_STATE; + + +#define TSC_ADDR 0x82 // (i2c address for touchscreen)<<1 + +// CHIP_ID register +#define CHIP_ID 0x00 // 16 bit register + +// ID_VER register +#define ID_VER 0x02 // 8 bit register + +// SYS_CTRL1 Reset control register +#define SYS_CTRL1 0x03 +#define SOFT_RESET 0x02 + +// SYS_CTRL2 clock control register +#define SYS_CTRL2 0x04 +#define ADC_OFF 0x01 +#define TSC_OFF 0x02 +#define GPIO_OFF 0x04 + +// ADC_CTRL registers +#define ADC_CTRL1 0x20 +#define ADC_CTRL2 0x21 + +// Interrupt control, enable and status registers +#define INT_CTRL 0x09 +#define INT_EN 0x0A +#define INT_STA 0x0B + +// TSC_CTRL touchscreen control register +#define TSC_CTRL 0x40 +#define TSC_TOUCH_DET 0x80 // 1 when touch detected else 0 +#define TSC_TRACK_MASK 0x70 // 0 => no window tracking +#define TSC_OP_MOD_MASK 0x0E // 0 => XYZ acquisition +#define TSC_EN_MASK 0x01 // enable touchscreen + +// TSC_CFG touchscreen config register +#define TSC_CFG 0x41 +#define TSC_AVG4 0x80 +#define TSC_DLY_1MS 0x20 +#define TSC_STL_1MS 0x03 + +#define TSC_I_DRIVE 0x58 +#define MAMP_50 0x01 + +// FIFO_TH touchscreen fifo threshold register +#define FIFO_TH 0x4A + +// TSC_DATA_X X data register +#define TSC_DATA_X 0x4D + +// TSC_DATA_Y Y data register +#define TSC_DATA_Y 0x4F + +// FIFO_STA touchscreen fifo control-status register +#define FIFO_STA 0x4B +#define FIFO_OFLOW 0x80 +#define FIFO_FULL 0x40 +#define FIFO_EMPTY 0x20 +#define FIFO_TRGD 0x10 +#define FIFO_RESET 0x01 + +// TSC_DATA touchscreen data register +#define TSC_DATA 0xD7 + +// GPIO_AF -- GPIO Alternate FunctionRegister +#define GPIO_AF 0x17 + +DigitalOut led4(LED4); + +i2c_t touch_ctrl; // i2c interface struct for touch screen + +static bool touch_present(void); +static void touch_compute_params(void); + +static char tsc_reset[2]={SYS_CTRL1, SOFT_RESET}; +static char clox_on[2]={SYS_CTRL2,0x00}; +static char adc_ctrl1[2]={ADC_CTRL1,0x49}; +static char adc_ctrl2[2]={ADC_CTRL2,0x01}; +static char gpio_af[2]={GPIO_AF,0}; +static char fifo_clear[2]={FIFO_STA,0x01}; +static char fifo_operate[2]={FIFO_STA,0x00}; +static char touch_int_en[2]={INT_EN,0x02};//enable FIFO_TH int +static char clr_intrupts[2]={INT_STA,0xFF}; +static char ena_intrupt[2]={INT_CTRL,0x02}; +static char tsc_cfg[2]={TSC_CFG,( TSC_AVG4 + | TSC_DLY_1MS + | TSC_STL_1MS )}; +static char tsc_enable[2]={TSC_CTRL,3}; +static char tsc_ctrl=TSC_CTRL; +static char tsc_i_drive[2]={TSC_I_DRIVE,MAMP_50}; +static char fifo_th[2]={FIFO_TH,1}; +static char fifo_ctrl_sta=FIFO_STA; +static char tsc_data=TSC_DATA; + +static int touch_audio_freq = 1000; +static int touch_audio_amplitude = 0; +static char touch_status=0; // result of reading TSC_CTR +static char fifo_status=0; // result of reading FIFO_CTRL_STA + +short touch_x,touch_y; + +// used by state machine that debounces touch detection +TOUCH_STATE touch_state=TOUCH_NOTOUCH; +#define GOOD_TOUCH_COUNT 8 +#define NO_TOUCH_COUNT 8 + +bool touch_init(void) +{ + char chipid[2]; + + i2c_init(&touch_ctrl,p28,p27); + i2c_frequency(&touch_ctrl,100000); + wait_ms(1); + + // read chip id + i2c_write(&touch_ctrl,TSC_ADDR,CHIP_ID,2,0); + i2c_read(&touch_ctrl,TSC_ADDR,chipid,2,1); + wait_ms(1); + + // reset touch screen chip + i2c_write(&touch_ctrl,TSC_ADDR,tsc_reset,2,1); + wait_ms(5); + + i2c_write(&touch_ctrl,TSC_ADDR,tsc_i_drive,2,1); + wait_ms(1); + + // turn on ADC and TSC clocks + i2c_write(&touch_ctrl,TSC_ADDR,clox_on,2,1); + wait_ms(3); + + // enable touch interrupt + i2c_write(&touch_ctrl,TSC_ADDR,touch_int_en,2,1); + wait_ms(1); + + // 80 clock cycles for ADC conv, 12 bit ADC, internal ref + i2c_write(&touch_ctrl,TSC_ADDR,adc_ctrl1,2,1); + wait_ms(2); + + // ADC clock = 3.25 MHz + i2c_write(&touch_ctrl,TSC_ADDR,adc_ctrl2,2,1); + wait_ms(1); + + // 4 sample averaging and 1ms delays + i2c_write(&touch_ctrl,TSC_ADDR,tsc_cfg,2,1); + wait_ms(1); + + // gpio alt function register to 0 + i2c_write(&touch_ctrl,TSC_ADDR,gpio_af,2,1); + wait_ms(1); + + // FIFO threshold not zero + i2c_write(&touch_ctrl,TSC_ADDR,fifo_th,2,1); + wait_ms(1); + + // FIFO Reset + i2c_write(&touch_ctrl,TSC_ADDR,fifo_clear,2,1); + wait_ms(1); + + // FIFO out of reset + i2c_write(&touch_ctrl,TSC_ADDR,fifo_operate,2,1); + wait_ms(1); + + // enable touchscreen, no window tracking, x,y mode + i2c_write(&touch_ctrl,TSC_ADDR,tsc_enable,2,1); + wait_ms(1); + + i2c_write(&touch_ctrl,TSC_ADDR,clr_intrupts,2,1); + wait_ms(1); + + i2c_write(&touch_ctrl,TSC_ADDR,ena_intrupt,2,1); + wait_ms(1); + + touch_state = TOUCH_NOTOUCH; + return true; +} + +bool touch_debounce(void) +{ + static int debounce_count=0; + + switch (touch_state) { + case TOUCH_NOTOUCH: + if (touch_present()) { + debounce_count=0; + touch_state = TOUCH_DEBOUNCE; + } + break; + + case TOUCH_DEBOUNCE: + if (touch_present()) { + if (++debounce_count > GOOD_TOUCH_COUNT) { + touch_state = TOUCH_PRESENT; + } + } else { + touch_state = TOUCH_NOTOUCH; + } + break; + + case TOUCH_PRESENT: + if (touch_present()) { + touch_compute_params(); + return true; + } else { + touch_state = TOUCH_NOTOUCH; + } + break; + + } + return false; +} + +int touch_frequency(void) +{ + return touch_audio_freq; +} + +int touch_amplitude(void) +{ + return touch_audio_amplitude; +} +void touch_compute_params(void) +{ + if(0>touch_get_xy(&touch_x,&touch_y)) return; + touch_audio_freq = TOUCH_MIN_FREQUENCY + + (TOUCH_MAX_FREQUENCY - TOUCH_MIN_FREQUENCY) + * touch_y/0xFFF; + touch_audio_amplitude = TOUCH_MAX_AMPLITUDE*touch_x/0xFFF; +// debug_hexshort((short)touch_audio_freq); +// debug_putch(','); +// debug_hexshort((short)touch_audio_amplitude); +// debug_crlf(); +} + +bool touch_present(void) +{ + i2c_init(&touch_ctrl,p28,p27); // sync i2c routines + i2c_frequency(&touch_ctrl,100000); // 100kHz clock + + i2c_write(&touch_ctrl,TSC_ADDR,&tsc_ctrl,1,0); + i2c_read(&touch_ctrl,TSC_ADDR,&touch_status,1,1); + + if ((touch_status & TSC_EN_MASK)==0) { // i2c error + led4=1; // disables screen + wait_ms(10); + touch_init(); // re-init fixes + return false; + } else if ((touch_status & TSC_TOUCH_DET)>0) { + return true; + } + return false; +} + +int touch_get_xy(short *x,short *y) +{ + unsigned char packed_xy[3]; + + if(i2c_write(&touch_ctrl,TSC_ADDR,&fifo_ctrl_sta,1,0)<0) + return NIL; + if(i2c_read(&touch_ctrl,TSC_ADDR,&fifo_status,1,1)<0) + return NIL; + while ((fifo_status & FIFO_EMPTY)!=FIFO_EMPTY ) { + if (i2c_write(&touch_ctrl,TSC_ADDR,&tsc_data,1,0) < 0) + return NIL; + if(i2c_read(&touch_ctrl,TSC_ADDR,(char *)packed_xy,3,1)<0) + return NIL; + if(i2c_write(&touch_ctrl,TSC_ADDR,&fifo_ctrl_sta,1,0)<0) + return NIL; + if(i2c_read(&touch_ctrl,TSC_ADDR,&fifo_status,1,1)<0) + return NIL; + } + if(i2c_write(&touch_ctrl,TSC_ADDR,clr_intrupts,2,1)<0) + return NIL; + *x = (short)(packed_xy[0]<<4) + | (short)((packed_xy[1] & 0xF0)>>4); + *y = 0xFFF -((short)((packed_xy[1] & 0x0F)<<8) + | (short)(packed_xy[2])); + // 0xFFF or 0x000 is some kind of glitch + if (*x==0xFFF && *y==0xFFF) return NIL; + if (*x==0 && *y==0) return NIL; +// debug_hexshort(*x); +// debug_putch(','); +// debug_hexshort(*y); +// debug_crlf(); + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/touch.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,14 @@ +/* + * touch.h -- interface definition for touch screen monitor + */ +#ifndef TOUCH_H +#define TOUCH_H +#define TOUCH_MAX_AMPLITUDE 255 +#define TOUCH_MAX_FREQUENCY 1047 +#define TOUCH_MIN_FREQUENCY 43 +bool touch_init(void); +int touch_get_xy(short *x,short *y); +bool touch_debounce(void); +int touch_frequency(void); +int touch_amplitude(void); +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wave.cpp Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,108 @@ +/* + * wave.cpp -- wave templates for use in Digital + * Theremin demo program + */ +#include "mbed.h" +#include "dma.h" +#include "jswitch.h" +#include "wave.h" + +// Default wave type is the SAW +static int wavetype = WAVE_TYPE_DEFAULT; +// Next wave type requested +static bool next_wavetype=false; +// The wave template buffer size is DMA_BUFSIZE +static int waveform[1+WAVE_TYPE_LAST - WAVE_TYPE_FIRST][DMA_BUFSIZE]; +// Accumulated phase +static unsigned accum_phi = 0; + +/* + * the phase accumulator ranges between 0 and 99999. + * corresponding to 0 and 2*pi radians. The frequency + * supplied to the wave_nextval() function determines the + * magnitude of the change in the phase accumulator value, + * according to the formula: + * delta-phase = 100000*frequency/WAVE_SAMPLE_RATE + * The next value of phase_accumulator is: + * (phase_accumulator + delta-phase) % 100000 + * phase_accumulator is converted to wave table index using + * the formula: + * index = (DMA_BUFSIZE - 1)*phase_accumulator/0xFFFF + */ + +void wave_init(void) +{ + int j; + + accum_phi = 0; + wavetype = WAVE_TYPE_DEFAULT; + + for (j=0;j<DMA_BUFSIZE;j++) { + waveform[WAVE_TYPE_SAW][j] = j; + } + + for (j=0;j<DMA_BUFSIZE;j++) { + if (j<DMA_BUFSIZE/2) { + waveform[WAVE_TYPE_SQUARE][j] = DMA_BUFSIZE; + } else { + waveform[WAVE_TYPE_SQUARE][j] = 0; + } + } + + for (j=0;j<DMA_BUFSIZE;j++) { + if (j<DMA_BUFSIZE/2) { + waveform[WAVE_TYPE_TRIANGLE][j] = 2*j; + } else { + waveform[WAVE_TYPE_TRIANGLE][j] + =DMA_BUFSIZE-2*(j-DMA_BUFSIZE/2); + } + } +} + +void wave_reset(void) +{ + accum_phi=0; +} +/* + * wave_nextval + * delta-phase = 100000*frequency/WAVE_SAMPLE_RATE + * The next value of phase_accumulator is: + * (phase_accumulator + delta-phase) % 100000 + * phase_accumulator is converted to wave table index using + * the formula: + * index = DMA_BUFSIZE * phase_accumulator / 100000 + */ +int wave_nextval(unsigned freq) +{ + unsigned delta_phi,index; + + delta_phi= 100000*freq/WAVE_SAMPLE_RATE; + accum_phi = (accum_phi + delta_phi)%100000; + index = ((DMA_BUFSIZE - 1) * accum_phi)/100000; + return waveform[wavetype][index]; +} + +void wave_update(void) +{ + unsigned char js_val; + + js_val = js_read(JS_CENTER); + if ((js_val & JS_CENTER)==JS_CENTER) { + next_wavetype = true; + } +} + +bool wave_type_changed(void) +{ + return next_wavetype; +} + +void wave_type_incr(void) +{ + next_wavetype = false; + wavetype = 1+wavetype; + if (wavetype > WAVE_TYPE_LAST) { + wavetype = WAVE_TYPE_FIRST; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wave.h Sun Mar 13 01:12:40 2016 +0000 @@ -0,0 +1,19 @@ +#ifndef WAVE_H +#define WAVE_H + +#define WAVE_TYPE_FIRST 0 +#define WAVE_TYPE_SAW 0 +#define WAVE_TYPE_TRIANGLE 1 +#define WAVE_TYPE_SQUARE 2 +#define WAVE_TYPE_LAST 2 +#define WAVE_TYPE_DEFAULT WAVE_TYPE_SAW +#define WAVE_SAMPLE_RATE 22050 + +void wave_init(void); +void wave_reset(void); +void wave_update(void); +int wave_nextval(unsigned freq); +bool wave_type_changed(void); +void wave_type_incr(void); +#endif +