Jump to content

NatureTM

Members
  • Content Count

    218
  • Joined

  • Last visited

  • Days Won

    13

Everything posted by NatureTM

  1. You're welcome! I bet using a midi GUI on a computer to create patterns is going to make your life a lot easier. In addition to just programming "notes," it will be really easy to send things like curves and LFO's to your controller using some decent midi software. Your hardware design seems very expandable. What is the zero crossing detector used for?
  2. Hmm... Wow we are off topic; I like it! Reminds me of my brain. I was thinking Portman > Fisher no matter what generation. If Jabba didn't have such an eye for fashion, I don't know that we'd even be talking about Leia.
  3. Working but in need of debugging/improvement: -- Pong -- Stroboscopic guitar tuner (done, but on a breadboard. want brighter LED's) Partially working: -- Display driver for Sure 0832 LED Matrix (scrolls string entered by terminal, need to expand functionality, add multidisplay support) -- ultrasonic rangefinder with serial interface based on this: http://www.kerrywong.com/2011/01/22/a-sensitive-diy-ultrasonic-range-sensor/ I get too many erroneous readings, but generally working. Tossing around in my head: -- MSP430 - based HDD clock using laptop hard drive. -- Something with the bunch of ultrasonic transmitters/receivers I built: I think I'd like to attach 2 or 3 receivers to an rf2500 dev board and use it to bi/triangulate the position of a transmitter. Sortof a local area positioning system. Not sure if it's feasible without dsp (filtering out echos, etc.) Not sure if I need higher resolution time measurements for this vs rangefinding. I won't be entering anything in this month's POTM though, end of semester cram time, going on vacation around the 20th.
  4. By, "it just doesn't work," I assume you mean the echo is still working, but it's not storing to the array correctly. I think what might be happening is that you send a character from terminal, the program moves into that while loop, stores the character to array index 0, and then the loop is repeats. If there isn't already another character waiting, SoftSerial_read() returns -1, the loop exits, and nbr is reinitialized to 0. Next time you send a char, you just overwrite the character you already have in array index 0, when you wanted to place it into array index 1. I actually have some code for something similar. while(1){ while(SoftSerial_empty()){ // software wait for serial // do something } // we got a char while(dispStr[stringIndex - 1] != 13){ // keep adding characters to the array until we get char 13 (line feed) if ( !SoftSerial_empty() ) { while((c=SoftSerial_read()) != -1) { SoftSerial_xmit((uint8_t)c); dispStr[stringIndex] = c; stringIndex++; } } } dispStr[stringIndex - 1] = 0; // terminate string with null char (replace line feed) stringIndex = 0; } You could replace "while(dispStr[stringIndex - 1] != 13)" with "while(stingIndex < 16)". There are some ways to clean this example up, but it was just something I had thrown together for another project. I does work for me.
  5. Hey EngIP, I think you can just declare those arrays as const to put them in flash. ie const unsigned char THrz[12] = {12,5,4,3,2,1,3,3,3,3,3,3};
  6. My few-month-old OCZ Vertex 2 boot SSD failed last night. :-( It looks from the support forums like it's somewhat of a common problem. Luckily I run weekly backups, but it's still a hassle. Just a little warning in case anyone was in the market for one: this is probably a product where it's worth spending the extra money to get Intel or some other big name, at least until the technology matures a little. I might have to set up a linux dev environment for msp430 while I wait for RMA. Thanks for listening to me vent!
  7. It's really strange that it worked fine, and then it didn't later, even though you didn't make any changes. I'd be looking close at the pcb for a short as someone else mentioned. Maybe the board got bumped and bent a pin, or a loose flake of metal/solder is bridging a connection. Running an old toothbrush over the pcb could dislodge a hard-to-see flake of metal.
  8. I actually was thinking about doing a midi controller like the KORG Kaoss. I was going to use an old laptop trackpad. I hit some bumps along the way, and gave up on it a little too quick. If you were to use the new captouch stuff with your own pcb, that would be pretty impressive.
  9. Hi Hiatus138, I like your enthusiasm. I look forward to seeing what you bring to the community. Welcome!
  10. What's that supposed to mean??? I could have won with Jar-Jar Binks!!!
  11. Well, we're into sharing. Kidding, she would be mad if she knew I said that! Thanks blue!
  12. I went to a white elephant "The Office" watching party last Thursday. I gave my TVOut demo with the emergency broadcast system screen as my white elephant gift. Anyway, it got me looking at the code again. I realized it would be really easy to increase the resolution now that we have chips with greater than 2K flash. I pretty much changed two lines of code, created some new images, and uploaded it to an MSP430G2452 with 8K. The resolution is now 192x240. It's still a funky aspect ratio limited by code space and USI frequency, but I expect to get it to do 384x240 when I get my hands on one of the new 16K chips. I also realized I had some really goofy code due to a misunderstanding of pointers. I fixed that, and it no longer needs to compile as C++. /* Monochrome NTSC composite video output for TI's Launchpad. * * Schmatic: * 470 * P1.2 SYNC --------/\/\/\--------| * |----- RCA jack Signal * 220 | * P1.6 VOUT --------/\/\/\--------| * * Launchpad GND ------------------------ RCA jack GND * * * By: NatureTM * more info on naturetm.com */ #include #define TACCR0 TA0CCR0 #define TACCR1 TA0CCR1 #define TACCTL0 TA0CCTL0 #define TACCTL1 TA0CCTL1 #define TIMERA0_VECTOR TIMER0_A0_VECTOR #define TIMERA1_VECTOR TIMER0_A1_VECTOR // Image file #include "teh_real_nature.h" //#include "gina_close.h" //#include "gina_wide.h" //#include "ebs2.h" #define SYNC BIT2 #define VOUT BIT6 //#define NS_TICK 62.5 // NS = nanoseconds #define TICKS_HSYNC 72 #define TICKS_SHORT_SYNC 38 #define TICKS_HBLANK 163 #define TICKS_SCANLINE 1017 #define TICKS_HALF_SCANLINE 508 #define TICKS_RIGHT_EDGE 973 #define ROW_HEIGHT 1 // in scanlines #define WORDS_SCANLINE 12 unsigned int* currentRowPtr; unsigned int imageOffset; unsigned int scanline = 0; char imageLine; char subRowCounter; unsigned int sleep; int main(){ DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; WDTCTL = WDTPW + WDTHOLD; // Stop WDT _BIS_SR(GIE); //enable interrupts USICKCTL = USIDIV1 + USISSEL1 + USISSEL0;// + USICKPL; // USI Clock = SMCLK / 4 USICNT = USI16B; // 16 bit shift out USICTL0 |= USIMST; // Use internal clock source USICTL0 &= ~USISWRST; // Clear USI reset bit (enable USI) USICTL0 |= USILSB; // USISR output LSB first USICTL0 |= USIGE; TACTL |= MC_0; // Stop timer A TACTL |= TASSEL1; // TASrc = SMClk = MClk TACTL &= ~TASSEL0; TACTL |= TACLR; // Clear the timer CCR0 = TICKS_SCANLINE; // Scanline timing - CCR0 triggers hSync CCR1 = TICKS_HSYNC; // End of hSync TACTL |= MC_1; // Up mode, Start TACCTL0 |= CCIE; // Enable Timer A CCR0 interrupt TACCTL1 |= OUTMOD_3; // TimerA reset sync pin on CCR0 TACCTL1 |= CCIE; // Enable Timer A CCR1 interrupt P1SEL = SYNC; // Allow timerA to set sync pin low on beginning of scanline P1DIR = SYNC + VOUT + BIT5; } // vsync broad sync pulse section void vSyncTripleBroad(){ int count; for(count = 0; count < 3; count++){ while(TAR < TICKS_HALF_SCANLINE - TICKS_HSYNC){} P1OUT = SYNC; while(TAR < TICKS_HALF_SCANLINE){} P1OUT = 0; while(TAR < TICKS_SCANLINE - TICKS_HSYNC){} P1OUT = SYNC; while(TAR > TICKS_SCANLINE - TICKS_HSYNC){} P1OUT = 0; } } // vsync short sync pulse section void vSyncTripleShort(){ int count; for (count = 0; count < 3; count++){ while(TAR < TICKS_SHORT_SYNC){} P1OUT = SYNC; while(TAR < TICKS_HALF_SCANLINE){} P1OUT = 0; while(TAR < TICKS_HALF_SCANLINE + TICKS_SHORT_SYNC){} P1OUT = SYNC; while(TAR > TICKS_HALF_SCANLINE + TICKS_SHORT_SYNC){} P1OUT = 0; } } // This ISR is run at the beginning of every scanline and keeps track of which // scanline we are on. At the beginning of a frame, it handles vSync output in // software. Next, it hands over control of the sync pin to TimerA, allowing // hsync timing to be done in hardware. #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A0 (void){ // software vSync if(scanline == 0){ P1OUT = 0; P1SEL = 0; // let software control P1.5 instead of TACCR0 vSyncTripleShort(); vSyncTripleBroad(); vSyncTripleShort(); scanline = 8; // vSync takes several scanlines P1SEL = SYNC; // let TimerA handle hSync } // visible area starts/vBlank over else if(scanline == 21){ scanline++; TACCTL1 |= CCIE; // Start drawing picture subRowCounter = 0; imageOffset = 0; } else if(scanline < 263){ scanline++; } // bottom of screen, get ready for vSync else{ TACCTL1 &= ~CCIE; // Stop drawing picture scanline = 0; } } // After vSync, this ISR begins USI output of the image. #pragma vector=TIMERA1_VECTOR __interrupt void Timer_A1 (void){ int wordCounter = 0; TAIV = 0; // Clear TimerA's interrupt vector register; USICTL0 |= USIOE; // USI output enabled USICTL0 |= USIPE6; // Port 1.6 USI data out while (TAR < TICKS_HBLANK){} do{ USICNT |= 16; USISR = currentRowPtr[wordCounter]; wordCounter++; // software delay allowing full USI shift out sleep = 0; while(sleep < 2) sleep++; _nop(); _nop(); _nop(); _nop(); _nop(); _nop(); _nop(); }while(wordCounter < WORDS_SCANLINE); if(subRowCounter == ROW_HEIGHT){ subRowCounter = 0; imageOffset += WORDS_SCANLINE; } subRowCounter++; currentRowPtr = (unsigned int*)image + imageOffset; while(TAR < TICKS_RIGHT_EDGE){} // Wait for edge of screen USICTL0 &= ~(USIPE6 + USIOE); // Release control of video pin to software } It needs to be flashed in CCS under Debug mode (without optimizations.) Compiling in Release mode with optimizations leads to distorted video. It probably could be fixed for release mode or mspgcc by tweaking the software delay toward the bottom. Changing that "sleep" variable to volatile might just be enough (a thought I had just now, not tested.) Files, demo images, and information on how to create your own images available on my bloggity-bloggy-blog. I find the word blog amusing. http://naturetm.com/?p=147
  13. I don't know a lot about it, but you'll need to start with some sources of "randomness," and the more the better. Ones that come into my head right away are using a timer, internal temperature sensor or some other adc input, and floating input pin states. You could xor those together and use that to seed your random C function.
  14. Yay! Thanks for organizing this bluehash, and thanks to the other participants. Also, thanks to George Lucas and John Williams! Oh, thanks TI as well. I'm excited to do some wireless stuff.
  15. I chose asm for the original calibration function just because it was the first ti example code for setting the dco that I found. I wasn't aware of the C function at the time. Since the C routine is both more accurate and friendlier with linux, the C function should be better. Thanks for your contribution.
  16. Welcome! Sounds like a good first msp430 project, or actually a nice project in general.
  17. MystBoy had this comment in the April 2011 POTM thread, but I didn't feel like it would be appropriate for me to talk about my project in that thread during voting. Feel free to work off of what I have! The midi receiver code by itself is fairly small and could lead to some interesting projects with physical instruments (solonoids plucking strings, hitting bells), stage-lighting, using midi patterns to control some other system, etc. I don't really have the tools, fabrication skills, or experience to do most of this stuff. For someone with a little experience on the physical side of things, it might not be too difficult to go way beyond what I've done with my little synth.
  18. NatureTM

    Atlas project

    Very exciting. Maybe it's too early to ask, but do you have a price target? As a college student, I base a lot of what I purchase on cost. It's why I got into msp430/Launchpad in the first place, and why a lot of my projects use cheap/minimal external parts. I know most people aren't in my situation, so it's maybe not such a big deal to others, but if it costs as much as an fpga dev kit, I think I'd have to go for that. Nobody posted his comment as I was writing this. :cry: Nevermind :cry:
  19. NatureTM

    Anyone notice ...

    I guess since we're on the geeky tangent, I suggest "Warp Core." Core like the CPU.
  20. NatureTM

    Anyone notice ...

    plaid -- spaceballs reference I think.
  21. I really like it. I wasn't familiar with the game and thought it was pretty cool. It's a good example for the RGB led's and hooking up multiple analog sources. There aren't a ton of MSP430 projects out there compared to other platforms, and I think this one should get a little attention. It's the kind of thing that beginners and beyond might find inspiring.
  22. My submission is a polyphonic midi synth. It's the one I posted in the forums awhile ago, with some revisions to make it polyphonic. It was developed on a g2231, so it will work with the original 2K msp's. I still consider it a work-in-progress, but in a usable state. For the DAC, I chose the MCP4725. I picked this one because it was the cheapest DAC-on-a-breakout from SparkFun. http://www.sparkfun.com/products/8736 I used some TI I2C example code to communicate with it. Since the I2C communications are using the USI, I needed a different way to get the serial MIDI data from the MIDI controller. I set up TimerA in capture mode, and triggered it on both rising and falling edges in the midi data. From that I could see how long the MIDI line was in a given state and thus how many 0's or 1's I got. (TimerA ticks in state / TimerA ticks per bit = number of bits.) My previous code using the USI was a mess, so I was happy to try something different. For the synth part, I have a function that takes the frequency and position within the wave, and returns an amplitude. To mix for polyphony, I just average the amplitudes of several of the waves and send the average to the DAC. The synth sounds pretty cruddy. There's several reasons for this, but it mostly boils down to a need for more free CPU time. A faster chip or more efficient code would help. I have ideas for the latter, but I may just take a completely different approach for the synth altogether. I think I'll start concentrating more on the actual sound, and less on seeing what I can squeeze from the chip. There are functions for square, triangle, and sawtooth waves, however all but square are too computationally expensive for polyphony. The code requires a calibrated DCO. Here's the code -- you might want to copy/paste it into a bigger window (I really need to learn how to make a library): #include "msp430g2231.h" #include #define MCLK_FREQUENCY 16000000 #define MIDI_FREQUENCY 31250 #define PIN_MIDI_DATA BIT2 #define PIN_SPEAKER BIT4 #define MIDI_CHANNEL 0 // MIDI is 1-indexed so setting this to 0 is midi channel 1 #define MAX_POLYPHONY 7 #define WDT_DIVIDER 64 #define SCALE_SIZE 12 #define number_of_bytes 2 const unsigned long WDT_FREQUENCY = MCLK_FREQUENCY / WDT_DIVIDER; const unsigned int synthNotes[sCALE_SIZE] = {9956, 10548, 11175, 11840, 12544, 13290, 14080, 14917, 7902, 8372, 8869, 9397}; const unsigned int TICKS_PER_BIT = MCLK_FREQUENCY / MIDI_FREQUENCY; unsigned int wdtCounter = 0; char MST_Data[number_of_bytes] = {0x00, 0x00}; char SLV_Addr = 0xC0; char byteCount, Transmit = 0; volatile char I2C_State = 0; char newVelocity; char newNote; int noteIndex = 0; unsigned int wdtPeriodNotes[MAX_POLYPHONY]; unsigned int tNotes[MAX_POLYPHONY] = {0}; char notes[MAX_POLYPHONY] = {0}; char velocities[MAX_POLYPHONY] = {0}; bool midiRXBitState = true; char partialMidiData = 0xFF; bool haveNewMidiByte = false; char newMidiByte; void waitForMidiLoop(); void handleNoteOn(); void handleNoteOff(); void updateWaveTimes(); void synthProcess(); void mixToOutputArray(); void handleNoteEvent(); void shiftLeft(char index); void updateSynth(bool on); char getNoteIndex(char note); void addBits(unsigned int stateCount, bool state); void updateADC(void); void Setup_USI_Master_TX (void); void main(){ DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; WDTCTL = WDTPW + WDTTMSEL + WDTIS1 + WDTIS0; IE1 |= WDTIE; TACTL |= TASSEL_2; // TACLK = SMCLK P1SEL |= PIN_MIDI_DATA; // Timer A compare input TACCTL1 |= CCIE + CAP + CM_3; // enable capture and interrupt on rising and falling edge TACCTL0 |= CCIE; // enable timeout interrupt TACCR0 = 9 * TICKS_PER_BIT; // should never have more than 8 bits P1OUT |= 0xC0; P1REN |= 0xC0; P1DIR = BIT0 + PIN_SPEAKER + BIT6 + BIT7; I2C_State = 0; // wasn't init'ing properly??? TACTL |= MC_1; // start Timer A _EINT(); // enable interrupts while(1){ waitForMidiLoop(); if(newMidiByte == (0x90 | MIDI_CHANNEL)){ haveNewMidiByte = false; handleNoteOn(); P1OUT ^= BIT0; } else if(newMidiByte == (0x80 | MIDI_CHANNEL)){ haveNewMidiByte = false; handleNoteOff(); } else haveNewMidiByte = false; } } void waitForMidiLoop(){ while(!haveNewMidiByte){ synthProcess(); } } // ################################################## // ################# Synth Stuff #################### void synthProcess(){ if(noteIndex){ updateWaveTimes(); if(haveNewMidiByte) return; mixToOutputArray(); if(haveNewMidiByte) return; // if(!I2C_State){ updateADC(); // } } } // basicly tracks our position within the waveform void updateWaveTimes(){ static unsigned int lastWdt = 0; char iNote; if(lastWdt != wdtCounter){ unsigned int wdtDelta = wdtCounter - lastWdt; lastWdt = wdtCounter; for(iNote = 0; iNote < noteIndex; iNote++){ tNotes[iNote] += wdtDelta; if(tNotes[iNote] >= wdtPeriodNotes[iNote]){ tNotes[iNote] = tNotes[iNote] - wdtPeriodNotes[iNote]; } } } } unsigned int triangle(unsigned int position, unsigned int wavelength){ unsigned int halfWavelength = wavelength / 2; if(position <= halfWavelength) return 0x0FFF * (unsigned long)position / halfWavelength; else return 0x0FFF - (0x0FFF * (unsigned long)(position - halfWavelength) / halfWavelength); } unsigned int sawtooth(unsigned int position, unsigned int wavelength){ return (unsigned long)position * 0x0FFF / wavelength; } // use this one for velocity sensitivity //unsigned int square(unsigned int position, unsigned int wavelength, char velocity){ // if(position > wavelength >> 1) // return 0x001F * velocity; // else // return 0; //} unsigned int square(unsigned int position, unsigned int wavelength){ if(position > wavelength >> 1) return 0x0FFF; else return 0; } // A fast but lo-fi digital mixer. void mixToOutputArray(){ char iSum; unsigned int sum = 0; for(iSum = 0; iSum < noteIndex; iSum++) sum += square(tNotes[iSum], wdtPeriodNotes[iSum]); // using waveforms other than square takes extra cpu time and can lead to unexpected results, // but they're there to mess with. (you may miss midi events and get crudd(y/ier) sound) // sum += triangle(tNotes[iSum], wdtPeriodNotes[iSum]); // sum += sawtooth(tNotes[iSum], wdtPeriodNotes[iSum]); // use this one for velocity sensitivity // sum += square(tNotes[iSum], wdtPeriodNotes[iSum], velocities[iSum]); // Hack to keep the volume more level if(noteIndex == 1) sum /= 2; else sum /= noteIndex; MST_Data[0] = 0x000F & (sum >> 8); MST_Data[1] = 0x00FF & sum; } unsigned int midiNoteToWdtPeriod(char midiNote){ return (WDT_FREQUENCY / (synthNotes[midiNote % 12] >> ((127 - midiNote) / 12))); } #pragma vector=WDT_VECTOR __interrupt void watchdog_timer(void){ wdtCounter++; } // ############################################### // ################# MIDI stuff ################## void handleNoteOn(){ do{ waitForMidiLoop(); if(newMidiByte & 0x80) break; newNote = newMidiByte; haveNewMidiByte = false; waitForMidiLoop(); if(newMidiByte & 0x80) break; newVelocity = newMidiByte; haveNewMidiByte = false; handleNoteEvent(); }while(1); } void handleNoteOff(){ do{ waitForMidiLoop(); if(newMidiByte & 0x80) break; newNote = newMidiByte; haveNewMidiByte = false; newVelocity = 0; handleNoteEvent(); }while(1); } void handleNoteEvent(){ if(newVelocity != 0){ // add a new note when the poly cache is full, replacing the oldest if(MAX_POLYPHONY == noteIndex){ shiftLeft(0); notes[MAX_POLYPHONY - 1] = newNote; velocities[MAX_POLYPHONY - 1] = newVelocity; wdtPeriodNotes[MAX_POLYPHONY - 1] = midiNoteToWdtPeriod(newNote); } // add a new note else{ notes[noteIndex] = newNote; velocities[noteIndex] = newVelocity; wdtPeriodNotes[noteIndex] = midiNoteToWdtPeriod(newNote); noteIndex++; } } else if(getNoteIndex(newNote) < MAX_POLYPHONY){ shiftLeft(getNoteIndex(newNote)); noteIndex -= 2; if(noteIndex >= 0){ noteIndex++; } else{ noteIndex = 0; // set DC offset to zero when no notes MST_Data[0] = 0; MST_Data[1] = 0; updateADC(); } } } // Shift all notes to the right of index left by one, // overwriting index and freeing a spot at the end of // the array void shiftLeft(char index){ int i; for(i = index; i < MAX_POLYPHONY - 1; i++){ notes[i] = notes[i + 1]; velocities[i] = velocities[i + 1]; wdtPeriodNotes[i] = wdtPeriodNotes[i + 1]; } } char getNoteIndex(char note){ int i; for(i = 0; i < MAX_POLYPHONY; i++) if(notes[i] == note) return i; return MAX_POLYPHONY + 1; } // add a new bit to the incomplete midi data variable void shiftInMSB(bool state){ if(state){ partialMidiData >>= 1; partialMidiData |= BIT7; } else{ partialMidiData >>= 1; } } // add the new midi data to the incomplete midi data variable void addBits(unsigned int stateCount, bool state){ while(stateCount > TICKS_PER_BIT / 2){ if(!(partialMidiData & BIT0)){ // are we shifting out the start bit? // if(haveNewMidiByte) // while(1); // catch when we miss midi data (for debugging) shiftInMSB(state); newMidiByte = partialMidiData; // if((newMidiByte != 0xFE) && (newMidiByte != 0xFF)) if(newMidiByte != 0xFE) haveNewMidiByte = true; partialMidiData = 0xFF; } else shiftInMSB(state); stateCount -= TICKS_PER_BIT; } } // CCR1 capture interrupt. Triggers on both edges, adds fresh midi data #pragma vector=TIMERA1_VECTOR __interrupt void CCR1_interrupt(void){ TAR = 0; TACCTL0 &= ~CCIFG; unsigned int tEdge = TACCR1; midiRXBitState = PIN_MIDI_DATA & P1IN; TAIV = 0; addBits(tEdge, !midiRXBitState); } // Like a timeout to add midi data if there's new data, but no edge in too long #pragma vector=TIMERA0_VECTOR __interrupt void CCR0_interrupt(void){ // don't add data if no partial data received, unless the new is all 0's if((partialMidiData != 0xFF) || !midiRXBitState) addBits(9 * TICKS_PER_BIT, midiRXBitState); // in case we captured an edge during this ISR, don't re-add these bits // in the CCR1 ISR TACCR1 = 0; } // ############################################################ // ###################### I2C ADC Stuff ####################### void updateADC(void){ Setup_USI_Master_TX(); USICTL1 |= USIIFG; // Set flag and start communication } void Data_TX (void){ USISRL = MST_Data[byteCount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack byteCount++; } void Setup_USI_Master_TX (void) { _DINT(); byteCount = 0; Transmit = 1; USICTL0 = USIPE6+USIPE7+USIMST+USISWRST; // Port & USI mode setup USICTL1 = USII2C+USIIE; // Enable I2C mode & USI interrupt USICKCTL = USIDIV_3+USISSEL_2+USICKPL; // USI clk: SCL = SMCLK/128 USICNT |= USIIFGCC; // Disable automatic clear control USICTL0 &= ~USISWRST; // Enable USI USICTL1 &= ~USIIFG; // Clear pending flag _EINT(); } // I2C handler for ADC adapted from TI example code. This runs pretty quick, // so hopefully it doen't clash with Midi input interrupts. #pragma vector = USI_VECTOR __interrupt void USI_TXRX (void) { switch(__even_in_range(I2C_State,14)) { case 0: // Generate Start Condition & send address to slave byteCount = 0; USISRL = 0x00; // Generate Start Condition... USICTL0 |= USIGE+USIOE; USICTL0 &= ~USIGE; USISRL = SLV_Addr; USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address I2C_State = 2; // next state: rcv address (N)Ack break; case 2: // Receive Address Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit I2C_State = 4; // Go to next state: check (N)Ack break; case 4: // Process Address Ack/Nack & handle data TX USICTL0 |= USIOE; // SDA = output if (USISRL & 0x01) // If Nack received... { // Send stop... USISRL = 0x00; USICNT |= 0x01; // Bit counter=1, SCL high, SDA low I2C_State = 14; // Go to next state: generate Stop } else { // Ack received, TX data to slave... USISRL = MST_Data[byteCount]; // Load data byte USICNT |= 0x08; // Bit counter = 8, start TX I2C_State = 10; // next state: receive data (N)Ack byteCount++; } break; case 10: // Receive Data Ack/Nack bit USICTL0 &= ~USIOE; // SDA = input USICNT |= 0x01; // Bit counter = 1, receive (N)Ack bit I2C_State = 12; // Go to next state: check (N)Ack break; case 12: // Process Data Ack/Nack & send Stop USICTL0 |= USIOE; if (byteCount == number_of_bytes){// If last byte USISRL = 0x00; I2C_State = 14; // Go to next state: generate Stop USICNT |= 0x01; } // set count=1 to trigger next state else{ Data_TX(); // TX byte } break; case 14:// Generate Stop Condition USISRL = 0x0FF; // USISRL = 1 to release SDA USICTL0 |= USIGE; // Transparent latch enabled USICTL0 &= ~(USIGE+USIOE); // Latch/SDA output disabled I2C_State = 0; // Reset state machine for next xmt break; } USICTL1 &= ~USIIFG; // Clear pending flag } The right side of the image looks cut off. [Right-click -> view image] to see the whole thing. NOTE: There should be about a 190K resistor between the DAC and the amp in the schematic. Not entirely necessary, but will scale the DAC output down to something more reasonable for the LM386
  23. About to enter mine. I figured today was the deadline, but just read at the top of the post that the 21st was the deadline. I figured it was today since it's a week before the end of the month. Is the 21st a misprint?
×
×
  • Create New...