Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by oPossum

  1. Here is an extended version of the Fraunchpad synth MIDI parser. This handles all MIDI messages. It uses tables and a state machine for decode and dispatch. A channel bitmask is used to allow one or more channels to be handled. // MIDI message handler function typedef typedef void(*pfnMIDI)(unsigned cmd, unsigned d1, unsigned d2); // Dummy function for unhandled and undefined MIDI messages static void midiNone(unsigned cmd, unsigned d1, unsigned d2) {} static void midiNoteOff(unsigned cmd, unsigned d1, unsigned d2) { } static void midiNoteOn(unsigned cmd, unsigned d1, unsigned d2) {
  2. Responding to all channels is intentional - I don't want to have to edit MIDI files to get all notes to play. I just turn off channel 10 (percussion) and let the synth play everything else. A future version may be multitimbral and respond to program change messages on a per channel basis. Thanks for the reminder about RTC. Easy fix to handle them... void midi(unsigned c) { static const unsigned ps[8] = { 2, 2, 2, 2, 1, 1, 2, 4 }; // Initial state for message static unsigned state = 0; static unsigned rs = 0; static unsigned d1 = 0; if(c & 0x80) {
  3. The way the parser handles running status and note on messages is not clear, so here is an explanation... --- Running status allows the first octet of a MIDI message to be ommited if it is the same as the last message. For example, this sequence of three messages: 0x80 0x11 0x22 / 0x80 0x33 0x44 / 0x80 0x55 0x66 Can be sent as: 0x80 0x11 0x22 0x33 0x44 0x55 0x66 --- MIDI messages begin with an octet that has the msb set (0x80 to 0xFF). All folowing octets will not have the msb set (0x00 to 0x7F). Most messages are two or three octets long. The ex
  4. Here is synth.asm rewritten in C. I briefly tested it and is seems to work properly. It can only do 3 voices - the asm code can do 9 (should do 16 - not sure why it is running slow). // synth.c #include "msp430fr5739.h" #include "string.h" static unsigned tick = 0; static unsigned sample = 0; static struct TVOICE { unsigned long pi; unsigned vl; union { unsigned long l; struct { unsigned l; unsigned h; } w; } pa; } voices[16]; void set_tick(unsigned n) { tick = n; } unsigned get_tick(void) { return tick; } void synth_init
  5. I really like the one with the terminal blocks - had not seen that style before in such a tiny supply. I have a few of the one shown bottom left. They are held together with a single screw and usually no glue. Great if you want to mod it. Many of these small regulated switching supplies use a TL431 (or clone) to set the output voltage. It is usually in a SOT-23 or TO-92 package. Find the TL431 and the two resistors that set the threshold voltage and you can easily convert a 5V supply to a 3.3V supply by changing one or both of the resistors. Some use a fixed Zener instead of the adjustable
  6. Unfortunately the 8 blue LED are split across two ports. I use the four on port J to show MIDI message activity. Each time a message is parsed the port is incremented, so the LED are a binary count of MIDI messages. C code: main() - Setup clocks and ports. Check for UART rx and send to MIDI parser. midi() - Parse serial data into MIDI messages. midi_ex() - Dispatch MIDI message note_on() - Find a free voice and assign the note to it note_off() - Find the note assignment and turn the voice off Asm code: synth_init() - Initialize the synthesis hardware (Ti
  7. 16 voices of 16 bit x 257 interpolated wavetable - derived from this code for the Launchpad. PWM output, but could easily be adapted to use IIC DAC. This is preliminary and eXperimental. The CPU core seems to be running slower than it should and I don't yet know why. Right now it is limited to 9 voices. The 9600 bps UART on the dev board was used for this demo, but standard MIDI can also be used - just change the bit rate divisor and wire up the usual opto circuit for MIDI. This is part of a larger project I am working on. //main.c #include "msp430fr5739.h" void synth
  8. The .if/.endif are equivalent to #if/#endif in C. They are assembler directives that allow conditional assembly. In this case it allows the code for NEC style repeating codes to be easily disabled when it is not needed. I have tweaked the DCO value to be more accurate for the specific chip I am using. The calibration in flash is close, but tweaking it got the clock even closer to 1.00 MHz. The firmware enables SMCLK output on P1.4 so the clock frequency can be checked and adjusted if desired. Having a precise clock is usually not necessary for sending IR, but it is very desirable for I
  9. Integrated MSP430FR5739 : 16KB FRAM / 1KB SRAM 16-Bit RISC Architecture up to 8-MHz 2x Timer_A Blocks, 3x Timer_B Block 1x USCI (UART/SPI/IrDA/I2C ) Blocks, 16Ch 10-Bit ADC12_B, 16Ch Comp_D, 32 I/Os 3 axis accelerometer NTC Thermister 8 Display LED's Footprint for additional through-hole LDR sensor 2 User input Switches Connections Connection to MSP-EXP430F5438 Connection to most Wireless Daughter Cards (CCxxxx RF) MSP-EXP430FR5739 Experimenter Board
  10. The capture software (IR Scope) presents a graphic representation of the captured IR signal as previously shown. It also saves the capture to a text file. The text file has a three line header followed by the on and off durations. The first line identifies the file as an ir capture with file format revision 0. The second line is the IR carrier frequency. The third line is the count of on/off durations that follow. An on duration is a positive integer followed by an optional cycle count. An off duration is a negative integer. The contents of the text file are simply reformatted for us
  11. You want the address of bam, not what is stored at bam __asm(" mov.w #bam, R9 "); // R9 = &bam[0] (3 cycles)
  12. PWM audio output on P1.6. Uses NCO with 16 or 32 bit precision. No interpolation due to lack of hardware multiplier on G2211. ; synth.asm .cdecls C, LIST, "msp430g2211.h" smplrt .equ 38400 ; Sample rate ph32 .equ 0 ; Use 32 bit phase .text .global set_tick .global get_tick .global synth_init .global set_note .bss tick, 2 .if ph32 .bss phase_inc, 4 * 12 ; Phase increment LSW/MSW (from note table) .bss phase_acc, 4 * 12 ; Phase accumulator LSW
  13. This would have to be an unsigned long long to do 35 bits. CCS doesn't support long long, so the best you can do is use unsigned long for 32 bits. void shiftOut(unsigned char val) {
  14. It is explained in SLAU132E. Code is dynamically generated so there is no source code for it (other than the source code of the C/C++ compiler itself). The advantage on an intrinsic is that is can go down to 1 cycle. The disadvantage is possible code bloat due to code being generated for each use of __delay_cycles(). Using a delay function when possible may reduce code size relative to the intrinsic.
  15. The lowest and highest codes returned by the ADC are 1/2 LSB wide as Rob has explained. This is necessary to ensure that those codes represent VrefLow and VrefHigh +/- 1/2 LSB. Averaging will give you an average reading - nothing more. It does not provide more ENOB or "filter out the noise." One huge flaw in the Atmel app note is the lack of attention to quantization error. You can't just filter it out. If you want 10 ENOB use a SAR ADC with 12 bits. The ENOB will always be less than the physical bit count. Using a SAR ADC for a DMM is a poor choice. It should be dual slope or
  16. The minimum is 20 cycles as shown in the sample code. The overhead is 20, so it is not possible to do less. Lower numbers will give 65536 + N cycles.
  17. CCS has an intrinsic delay, but it requires a constant value. So you can do this: __delay_cycles(1234); but not this: unsigned x = 1234; __delay_cycles(x); The usual way to do a simple delay is something like this: unsigned x = 1234; while(--x); in assembly: mov #1234, R12 dec R12 jne $ - 2 That has three cycle granularity. One cycle for the dec, and two cycles for the conditional jump. To make a delay with one cycle granularity, two techniques can be combined. The first is to make the simple delay loop decrement the count by the number of cycles in the l
  18. Circuit construction on a protoboard.
  19. It has 2 I/O on port 2. Pins 12 and 13.
  20. Switch open == MSP430 port pin configured as input Switch closed == MSP430 port pin configured as output and driven low
  21. ; Reverse bit order in R12 mov.b R12, R13 rlc R12 rrc R13 rlc R12 rrc R13 rlc R12 rrc R13 rlc R12 rrc R13 rlc R12 rrc R13 rlc R12 rrc R13 rlc R12 rrc R13 rlc R12 rrc R13 rlc R12 mov.b R12, R12 or R13, R12 swpb R12
  22. pop R9 Nice optimization. Down to 9 words!
  23. Excellent! I think this would work to fix up the address... inc R9 ; Must be next word bic #1, R9 ; Must be word aligned The second line may not be needed - the PC may not have a lsb that is writeable. PutStr ; { Mike McLaren } 14 words mov.w @SP, R9 ; copy return addr to R9 bump mov.b @R9+, R12 ; copy string char to R12 tst.b R12 ; end of string? jz exit ; yes, branch, else call #Put232 ; output
  24. The MSP430 could calculate the carrier frequency and durations as explained in the previous post, but there is no need for it to do that. All it has to do is send the IR pulse count to the PC and let the PC do the calculations and display the results. Doing this in real time requires that each count be sent in less than the 100 microsecond gate time. The lowest standard bit rate that can do this is 115.2 kbps. The MSP430 assembly code to do this is explained in this thread. The rest of the code is setup, reading the Timer and driving the status LED. The main loop executes in exactly 100 cycles
  25. Discussion in this thread has lead me to a smaller version of the code. This is smaller, but takes a few more cycles overall. putc or #0x0100, R12 ; Stop bit mov #0x02, R15 ; Serial out bitmask jmp bit_start ; ; bit0 rra R12 ; Bit 0/3/6 jc bit0h ; bic.b R15, &P1OUT ; 9/35/61 nop ; rra R12 ; Bit 1/4/7 jc bit1h
  • Create New...