-
Content Count
218 -
Joined
-
Last visited
-
Days Won
13
Reputation Activity
-
NatureTM got a reaction from artifus in Flashing the missing DCO calibration constants
EDIT: Here's another really nice DCO calibration program. It's part of TinyOS-msp430. http://code.google.com/p/tinyos-msp430/ It's the file called calibrate-dco. As gordon, who discovered it said, "[it] appears to be a quite beefed-up DCO calibration app, with goodies on the side (taking silicon errata into account for various devices when calibrating)." It looks like it's built to be solid and reliable. I skimmed over the code and didn't see anything for calculating SegA checksum, but that usually isn't an issue for most non-critical applications.
EDIT: maxpenna shared another version of the DCO calibration program. This is the one to use if you need a correct SegmentA checksum. It uses the C calibration function. You can get it here http://www.43oh.com/forum/download/file.php?id=292
WARNING: Some of the programs in this thread will erase Segment A and only put back the DCO calibrations. They should not be used with chips that have an ADC12, as this process will destroy the ADC12 calibrations. Some of the programs do not calculate the Segment A checksum, so the integrity of Segment A cannot be verified during runtime after calibration. Still, I've been using it without any problems.
There's been a bit of a discussion in another thread about an idea simpleavr had for adding the dco calibration constants to flash for the Value Line series. I've cobbled together some pieces of TI code and have it working. It seems to work great. Here's how I did it with CCS. I think the people on linux should be able to reproduce the result with a little adaptation.
This requires the TI DCO library I modified in another thread and an external LF crystal like the one with Launchpad.
http://naturetm.com/files/Launchpad%20setDCO%20lib.rar
First, run this to calibrate the constants and write them to flash:
EDIT: 43oh member zeke has made some changes to the code for finer tuning. Check page 2 for his code.
//****************************************************************************** // MSP430F20xx Demo - DCO Calibration Constants Programmer // // NOTE: THIS CODE REPLACES THE TI FACTORY-PROGRAMMED DCO CALIBRATION // CONSTANTS LOCATED IN INFOA WITH NEW VALUES. USE ONLY IF THE ORIGINAL // CONSTANTS ACCIDENTALLY GOT CORRUPTED OR ERASED. // // Description: This code re-programs the F2xx DCO calibration constants. // A software FLL mechanism is used to set the DCO based on an external // 32kHz reference clock. After each calibration, the values from the // clock system are read out and stored in a temporary variable. The final // frequency the DCO is set to is 1MHz, and this frequency is also used // during Flash programming of the constants. The program end is indicated // by the blinking LED. // ACLK = LFXT1/8 = 32768/8, MCLK = SMCLK = target DCO // //* External watch crystal installed on XIN XOUT is required for ACLK *// // // MSP430F20xx // --------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // | | // | P1.0|--> LED // | P1.4|--> SMLCK = target DCO // // A. Dannenberg // Texas Instruments Inc. // May 2007 // Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.42A //****************************************************************************** #include "msp430x20x1.h" #include "DCO_Library.h" unsigned char CAL_DATA[8]; // Temp. storage for constants volatile unsigned int i; int j; char *Flash_ptrA; // Segment A pointer void Set_DCO(unsigned int setting); void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT for (i = 0; i < 0xfffe; i++); // Delay for XTAL stabilization P1OUT = 0x01; // Red LED on P1SEL = 0x10; // P1.4 SMCLK output P1DIR = 0x51; // P1.0,4,6 output j = 0; // Reset pointer Set_DCO(TI_DCO_16MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_12MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_8MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_1MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Flash_ptrA = (char *)0x10C0; // Point to beginning of seg A FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator FCTL1 = FWKEY + ERASE; // Set Erase bit FCTL3 = FWKEY + LOCKA; // Clear LOCK & LOCKA bits *Flash_ptrA = 0x00; // Dummy write to erase Flash seg A FCTL1 = FWKEY + WRT; // Set WRT bit for write operation Flash_ptrA = (char *)0x10F8; // Point to beginning of cal consts for (j = 0; j < 8; j++) *Flash_ptrA++ = CAL_DATA[j]; // re-flash DCO calibration data FCTL1 = FWKEY; // Clear WRT bit FCTL3 = FWKEY + LOCKA + LOCK; // Set LOCK & LOCKA bit P1OUT = 0; while (1) { P1OUT ^= BIT6; // Toggle green LED for (i = 0; i < 0x4000; i++); // SW Delay } } void Set_DCO(unsigned int setting){ volatile unsigned int I; // P1DIR |= BIT0; // P1.0 output BCSCTL1 &= ~XTS; // external source is LF; BCSCTL3 &= ~(LFXT1S0 + LFXT1S1); // watch crystal mode BCSCTL3 |= XCAP0 + XCAP1; // ~12.5 pf cap on the watch crystal as recommended for( I = 0; I < 0xFFFF; I++){} // delay for ACLK startup if(TI_SetDCO(setting) == TI_DCO_NO_ERROR) // if setting the clock was successful, P1OUT |= BIT0; // bring P1.0 high (Launchpad red LED) else while(1); // trap if setting the clock isn't successful }
The green light should start blinking in a few seconds, indicating success. Now we need to modify some linker and header files so CCS knows about the new calibrations.
I'm using the MSP430G2231, so I duplicated the file C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.cmd in that directory, and renamed the duplicate as msp430g2231_mod.cmd. Now I can edit it without affecting the original. Edit msp430g2231_mod.cmd and change the calibration section at the bottom to this:
/************************************************************ * Calibration Data in Info Mem ************************************************************/ CALDCO_16MHZ = 0x10F8; CALBC1_16MHZ = 0x10F9; CALDCO_12MHZ = 0x10FA; CALBC1_12MHZ = 0x10FB; CALDCO_8MHZ = 0x10FC; CALBC1_8MHZ = 0x10FD; CALDCO_1MHZ = 0x10FE; CALBC1_1MHZ = 0x10FF;
Now the linker knows we have calibration data in that section when we use the modified file.
When we create a new project in CCS or modify an existing one, CCS will want to use the default linking file, and the default header. Here's an example about how to configure a project to use the new constants.
First create a new project. Within the project, there should be a file called something like lnk_msp430g2231.cmd. The last line of that file should be something like -l msp430g2231.cmd. Open it, and change the last line to reflect the new linker file so it reads -l msp430g2231_mod.cmd.
Next, add the appropriate header file to the project. Right-click the project folder in the left pane of CCS and click "Add files to project..." In this example, I'm using C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.h. Now we have a copy of the file in the project we can safely edit. Edit the file so the calibration section looks like this:
/************************************************************ * Calibration Data in Info Mem ************************************************************/ #ifndef __DisableCalData SFR_8BIT(CALDCO_16MHZ); /* DCOCTL Calibration Data for 16MHz */ SFR_8BIT(CALBC1_16MHZ); /* BCSCTL1 Calibration Data for 16MHz */ SFR_8BIT(CALDCO_12MHZ); /* DCOCTL Calibration Data for 12MHz */ SFR_8BIT(CALBC1_12MHZ); /* BCSCTL1 Calibration Data for 12MHz */ SFR_8BIT(CALDCO_8MHZ); /* DCOCTL Calibration Data for 8MHz */ SFR_8BIT(CALBC1_8MHZ); /* BCSCTL1 Calibration Data for 8MHz */ SFR_8BIT(CALDCO_1MHZ); /* DCOCTL Calibration Data for 1MHz */ SFR_8BIT(CALBC1_1MHZ); /* BCSCTL1 Calibration Data for 1MHz */ #endif /* #ifndef __DisableCalData */
Now you can begin using the new calibration data in your program. When you #include the msp430g2231.h file, put it in quotes instead of <> to ensure it's loading the modified header local to the project directory.
I tested the constants with a cheap oscilloscope and they seemed correct. My scope doesn't have great accuracy at high frequencies so they might be a little off, but nothing I can detect. It works with my composite video prog, so that's a pretty good sign.
EDIT: Oops! I had an incorrectly named file in these instructions. Corrected.
-
NatureTM got a reaction from hoangnguyen578 in Launchpad TV output
I got my Launchpad to output B/W composite video. It only displays one image without re-flashing though, so it's not extremely useful. The only external components are two resistors and a crystal oscillator. I plan on writing it up on my blog and releasing the source sometime this week, unless I get too busy with school. I wasn't sure if I'd be able to ever get this working, so I'm feelin' pretty good right now!
Proof ;-)
Code for use with an external oscillator:
Launchpad_TV_Out.rar
Code for if you have your DCO configuration constants calibrated:
Launchpad_TV_Out_for_calibrated.rar
EDIT: Here's the writeup!
http://naturetm.com/?p=47
-
NatureTM reacted to oPossum in 16 channel software PWM using a single timer
This is a method of generating multichannel PWM using a single timer.
A linked list of events is used to allow a very efficient ISR and very low CPU usage.
This is the linked list entry structure...
typedef struct { // PWM ISR info struct unsigned time; // Time for on/off action to occur unsigned port_off; // Port pins to turn off unsigned port_on; // Port pins to turn on void *next; // Next entry in linked list } TPWM; // ...and the ISR...
(written in C for clarity, using assembly would reduce the size and execution time by half)
__interrupt void Timer0_A1 (void) { volatile unsigned x = TAIV; // Clear interrupt flag P1OUT &= ~pa->port_off; // Port pins off P2OUT &= ~pa->port_off >> 8; // P1OUT |= pa->port_on; // Port pins on P2OUT |= pa->port_on >> 8; // pa = pa->next; // Next entry in list TACCR1 = pa->time; // Update timer compare time } When an interrupt occurs, the ports are updated, the timer is updated, and the next linked list entry is made the active entry. An interrupt will only occur when port pin(s) have to be changed. Very simple and efficient.
The tradeoff is a rather complex chunk of code to maintain the linked list. The code shown here uses a simple, but rather crude, method of reducing glitches that can occur when the linked list is manipulated. The code will wait for the current pulse to complete before removing the list entry for it. There are better ways to do this, but the code is much more complex due to the many corner cases that must be handled. There is no disruption in the PWM output when PWM values are changed. All PWM outputs are active as long as the timer and global interrupt are enabled.
The PWM period is 2^16 / SMCLK and the resolution is 2^8 / SMCLK (8 bit resolution).
So for a 16 MHz clock:
period = 65,536 / 16,000,000 = 4.096 ms
resolution = 256 / 16,000,000 = 16 us
frequency = 16,000,000 / 65,536 = 244.24 Hz
An interrupt will occur no more than 17 times the base frequency when all 16 channels are active and set to different non-zero/non-max values. So at 16 MHz there will be no more than 4151 interrupts per second. Assuming 100 cycles per interrupt (the C compiler should be able to do better than that) would be 415,100 cycles per second of 16,000,000 or 2.6% CPU usage (worst case).
The resolution can be increased as long as there are not other interrupts that use too many cycles. Consider the worst case scenario of two back-to-back PWM interrupts with another interrupt in between. The maximum time allowed for other interrupts is the PWM resolution minus the PWM ISR time - it has to squeeze in between back-to-back PWM interrupts.
Complete code with test case...
#include "msp430g2553.h" #include "string.h" typedef struct { // PWM ISR info struct unsigned time; // Time for on/off action to occur unsigned port_off; // Port pins to turn off unsigned port_on; // Port pins to turn on void *next; // Next entry in linked list } TPWM; // TPWM pw[17], *pi; // Array and inactive list head volatile TPWM *pa; // Active list entry void pwm_set(const unsigned pin, const unsigned time) { const unsigned mask = 1 << pin; // const unsigned tm = time & 0xFF00; // Limit closeness of entries TPWM *b, *p, *n; // // // -- Try to find existing active entry for this pin for(b = &pw[0], p = b->next; p != &pw[0]; b = p, p = b->next) { if(p->port_off & mask) { // Found it if(p->time == tm) return; // - Time is the same, nothing to do, return... while(pa != p); // Wait for this entry to be active while(pa == p); // Wait for this entry to become inactive // Safe to remove now if(p->port_off == mask) { // - Entry is only used for this pin, remove it b->next = p->next; // Remove link p->next = pi; // Add to inactive list pi = p; // } else { // - Entry is used for multiple pins p->port_off &= ~mask; // Remove this pin from the entry } // break; // Found the pin, so stop searching } // } // // - Update first entry in list if(tm == 0) { // If time is 0, turn off and return pw[0].port_on &= ~mask; // pw[0].port_off |= mask; // return; // } else { // If time is non-zero, turn on pw[0].port_on |= mask; // pw[0].port_off &= ~mask; // if(time == 0xFFFF) return; // If max, no need to turn off, so return } // // // Find where the new turn off entry will go for(b = &pw[0], p = b->next; p != &pw[0]; b = p, p = b->next) if(p->time >= tm) break; // Stop when an entry of >= time is found // if(p->time == tm) { // If same time, use existing entry p->port_off |= mask; // Add this pin return; // All done... } // // n = pi; // Get an entry from the inactive list pi = n->next; // // n->port_off = mask; // Setup new entry n->port_on = 0; // n->time = tm; // // n->next = p; // Insert in to active list b->next = n; // } void pwm_detach(unsigned pin) { const unsigned mask = 1 << pin; TPWM *b, *p; // Try to find existing active entry for this pin for(b = &pw[0], p = b->next; p != &pw[0]; b = p, p = b->next) { if(p->port_off & mask) { // Found it if(p->port_off == mask) { // Entry is only used for this pin, remove it _DINT(); if(pa == p) pa = p->next; b->next = p->next; _EINT(); p->next = pi; pi = p; } else { p->port_off &= ~mask; // Remove this pin from the entry } break; } } pw[0].port_on &= ~mask; // Don't turn on or off pw[0].port_off &= ~mask; } void pwm_init(void) { unsigned n; memset(pw, 0, sizeof(pw)); // Clear entire array pa = &pw[0]; // Active list always begins with first array element pa->next = &pw[0]; // Begin with only 1 entry in list pi = &pw[1]; // First inactive entry is second array element for(n = 1; n < sizeof(pw)/sizeof(TPWM) - 1; ++n) // Link the inactive entries pw[n].next = &pw[n + 1]; // // TACTL = TASSEL_2 + MC_2 + ID_0; // Setup timer, continuous mode, SMCLK/1 TACCTL1 = CCIE; // Enable timer interrupt _EINT(); // Enable interrupts } #pragma vector = TIMER0_A1_VECTOR __interrupt void Timer0_A1 (void) { volatile unsigned x = TAIV; // Clear interrupt flag P1OUT &= ~pa->port_off; // Port pins off P2OUT &= ~pa->port_off >> 8; // P1OUT |= pa->port_on; // Port pins on P2OUT |= pa->port_on >> 8; // pa = pa->next; // Next entry in list TACCR1 = pa->time; // Update timer compare time } // Test case for 2 channels - Launchpad LEDs void main(void) { unsigned n, o; WDTCTL = WDTPW | WDTHOLD; // Disable watchdog DCOCTL = 0; // Run at 16 MHz BCSCTL1 = CALBC1_16MHZ; // DCOCTL = CALDCO_16MHZ; // P1DIR = BIT0 | BIT6; // Enable outputs for LEDs on Launchpad pwm_init(); // Initialize software PWM for(;;-) { pwm_set(0, n); pwm_set(6, o); n += 100; o += 123; __delay_cycles(100000); } } // Test case for all 16 channels void main(void) { unsigned n; unsigned w[16]; unsigned r[16] = { 100, 103, 106, 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, 139, 142, 145 }; WDTCTL = WDTPW | WDTHOLD; // Disable watchdog DCOCTL = 0; // Run at 16 MHz BCSCTL1 = CALBC1_16MHZ; // DCOCTL = CALDCO_16MHZ; // P2SEL = 0; // Allow P2.6 and P2.7 to be used as GPIO P1DIR = P2DIR = 0xFF; // Enable all P1 and P2 pins as output pwm_init(); // Initialize software PWM for(;;-) { for(n = 0; n < 16; ++n) { pwm_set(n, w[n]); w[n] += r[n]; } __delay_cycles(100000); } } Two PWM outputs with the pulse with changing at different rates (lower trace is faster). The two outputs are the Launchpad LEDs.
All 16 channels.
-
NatureTM reacted to oPossum in Fraunchpad Synth - Still Alive
The note envelope is a simple exponential decay. After each cycle of the waveform, the level is multiplied by 65408/65536 (0.99805). Higher frequency notes will decay faster then lower frequency.
The music data is in an array in FRAM, it is not MIDI driven like the previous version
Inspired by this project
main.c
#include "msp430fr5739.h" #include "alive.h" void set_tick(unsigned); unsigned get_tick(void); void synth_init(void); void set_note(int, int, int); int wave[257] = { 0, 804, 1608, 2410, 3212, 4011, 4808, 5602, 6393, 7179, 7962, 8739, 9512, 10278, 11039, 11793, 12539, 13279, 14010, 14732, 15446, 16151, 16846, 17530, 18204, 18868, 19519, 20159, 20787, 21403, 22005, 22594, 23170, 23731, 24279, 24811, 25329, 25832, 26319, 26790, 27245, 27683, 28105, 28510, 28898, 29268, 29621, 29956, 30273, 30571, 30852, 31113, 31356, 31580, 31785, 31971, 32137, 32285, 32412, 32521, 32609, 32678, 32728, 32757, 32767, 32757, 32728, 32678, 32609, 32521, 32412, 32285, 32137, 31971, 31785, 31580, 31356, 31113, 30852, 30571, 30273, 29956, 29621, 29268, 28898, 28510, 28105, 27683, 27245, 26790, 26319, 25832, 25329, 24811, 24279, 23731, 23170, 22594, 22005, 21403, 20787, 20159, 19519, 18868, 18204, 17530, 16846, 16151, 15446, 14732, 14010, 13279, 12539, 11793, 11039, 10278, 9512, 8739, 7962, 7179, 6393, 5602, 4808, 4011, 3212, 2410, 1608, 804, 0, -804, -1608, -2410, -3212, -4011, -4808, -5602, -6393, -7179, -7962, -8739, -9512, -10278, -11039, -11793, -12539, -13279, -14010, -14732, -15446, -16151, -16846, -17530, -18204, -18868, -19519, -20159, -20787, -21403, -22005, -22594, -23170, -23731, -24279, -24811, -25329, -25832, -26319, -26790, -27245, -27683, -28105, -28510, -28898, -29268, -29621, -29956, -30273, -30571, -30852, -31113, -31356, -31580, -31785, -31971, -32137, -32285, -32412, -32521, -32609, -32678, -32728, -32757, -32767, -32757, -32728, -32678, -32609, -32521, -32412, -32285, -32137, -31971, -31785, -31580, -31356, -31113, -30852, -30571, -30273, -29956, -29621, -29268, -28898, -28510, -28105, -27683, -27245, -26790, -26319, -25832, -25329, -24811, -24279, -23731, -23170, -22594, -22005, -21403, -20787, -20159, -19519, -18868, -18204, -17530, -16846, -16151, -15446, -14732, -14010, -13279, -12539, -11793, -11039, -10278, -9512, -8739, -7962, -7179, -6393, -5602, -4808, -4011, -3212, -2410, -1608, -804, 0 }; void main(void) { unsigned osc; const struct event_t *e; WDTCTL = WDTPW + WDTHOLD; CSCTL0 = 0xA500; // Unlock clock registers CSCTL1 = DCORSEL | DCOFSEL1 | DCOFSEL0; // 24 MHz CSCTL2 = 0x0333; // Use DCO clock for ACLK, SMCLK and MCLK CSCTL3 = 0x0000; // Set all clock divider to 1 //CSCTL4 = //CSCTL5 = P1DIR = 0x01; // PWM audio output on P1.0 P1REN = 0x00; // P1OUT = 0x00; // P1SEL0 = 0x01; // Enable Timer A output P1SEL1 = 0x00; // P2DIR = 0x00; // P2REN = 0x00; // P2OUT = 0x00; // P2SEL0 = 0x00; // P2SEL1 = 0x03; // Enable UART UCA0 P3DIR = 0x10; // P3REN = 0x00; // P3OUT = 0x00; // P3SEL0 = 0x10; // SMCLK output P3SEL1 = 0x10; // SMCLK output P4DIR = 0x00; // P4REN = 0x00; // P4OUT = 0x00; // P4SEL0 = 0x00; // P4SEL1 = 0x00; // PJDIR = 0x0F; // 4 LEDs PJREN = 0x00; // PJOUT = 0x00; // PJSEL0 = 0x00; // PJSEL1 = 0x00; // UCA0MCTLW = 1; // 16x oversampling UCA0BRW = 24000000 / 16 / 9600; // Fraunchpad UART //UCA0BRW = 24000000 / 16/ 31250; // Standard MIDI bit rate UCA0CTLW0 = 0x0080; // Use SMCLK for bit rate generator, release reset synth_init(); for(osc = 0, e = tune_still_alive; e->pitch; ++e) { set_note(osc++ & 7, e->pitch, 9000); ++PJOUT; set_tick((e[1].time - e[0].time) * 150); while(get_tick()); } }
alive.h
struct event_t { unsigned time; unsigned pitch; }; static const struct event_t tune_still_alive[] = { 192, 91, 240, 90, 288, 88, 336, 88, 384, 69, 384, 90, 432, 74, 480, 78, 528, 74, 576, 71, 624, 74, 672, 78, 720, 74, 768, 69, 816, 74, 864, 78, 912, 74, 912, 81, 960, 71, 960, 91, 1008, 74, 1008, 90, 1056, 78, 1056, 88, 1104, 74, 1104, 88, 1152, 69, 1200, 74, 1200, 90, 1248, 78, 1296, 74, 1344, 71, 1344, 86, 1392, 74, 1440, 78, 1440, 88, 1488, 74, 1488, 81, 1536, 69, 1584, 74, 1632, 78, 1680, 74, 1728, 71, 1776, 74, 1824, 78, 1872, 74, 1872, 81, 1920, 71, 1920, 88, 1968, 76, 2016, 79, 2016, 90, 2064, 76, 2064, 91, 2112, 71, 2160, 76, 2208, 79, 2208, 88, 2256, 76, 2256, 85, 2304, 69, 2352, 73, 2352, 86, 2400, 79, 2448, 73, 2496, 69, 2496, 88, 2544, 73, 2592, 79, 2592, 81, 2640, 73, 2640, 81, 2688, 69, 2736, 74, 2736, 90, 2784, 78, 2832, 74, 2880, 71, 2928, 74, 2976, 78, 3024, 74, 3072, 69, 3120, 74, 3168, 78, 3216, 74, 3264, 71, 3264, 91, 3312, 74, 3312, 90, 3360, 78, 3360, 88, 3408, 74, 3408, 88, 3456, 69, 3456, 90, 3504, 74, 3552, 78, 3600, 74, 3648, 71, 3696, 74, 3744, 78, 3792, 74, 3840, 69, 3888, 74, 3936, 78, 3984, 74, 3984, 81, 4032, 71, 4032, 91, 4080, 74, 4080, 90, 4128, 78, 4128, 88, 4176, 74, 4176, 88, 4224, 69, 4272, 74, 4320, 78, 4320, 90, 4368, 74, 4368, 86, 4416, 71, 4464, 74, 4512, 78, 4512, 88, 4560, 74, 4560, 81, 4608, 69, 4656, 74, 4704, 78, 4752, 74, 4800, 71, 4848, 74, 4896, 78, 4944, 74, 4992, 71, 4992, 88, 5040, 76, 5088, 79, 5088, 90, 5136, 76, 5136, 91, 5184, 71, 5232, 76, 5280, 79, 5280, 88, 5328, 76, 5328, 85, 5376, 69, 5424, 73, 5472, 79, 5472, 86, 5520, 73, 5520, 88, 5568, 69, 5616, 73, 5616, 81, 5664, 79, 5664, 86, 5712, 73, 5712, 88, 5760, 70, 5760, 89, 5808, 74, 5808, 88, 5856, 77, 5856, 86, 5904, 81, 5904, 84, 6048, 81, 6096, 82, 6141, 89, 6144, 105, 6144, 72, 6144, 77, 6144, 84, 6192, 81, 6192, 96, 6240, 108, 6240, 72, 6240, 77, 6240, 89, 6288, 96, 6336, 103, 6336, 72, 6336, 76, 6336, 88, 6336, 88, 6384, 79, 6384, 86, 6384, 96, 6432, 108, 6432, 72, 6432, 76, 6432, 86, 6480, 84, 6480, 96, 6528, 106, 6528, 70, 6528, 74, 6528, 86, 6528, 86, 6576, 105, 6576, 82, 6576, 84, 6576, 96, 6624, 103, 6624, 70, 6624, 74, 6624, 84, 6672, 76, 6672, 96, 6720, 105, 6720, 72, 6720, 77, 6720, 84, 6720, 89, 6768, 81, 6768, 96, 6816, 101, 6816, 72, 6816, 77, 6816, 81, 6864, 82, 6864, 96, 6909, 89, 6912, 105, 6912, 72, 6912, 77, 6912, 84, 6960, 81, 6960, 96, 7008, 108, 7008, 72, 7008, 77, 7008, 89, 7056, 96, 7104, 103, 7104, 72, 7104, 76, 7104, 88, 7104, 91, 7152, 79, 7152, 89, 7152, 96, 7200, 108, 7200, 72, 7200, 76, 7200, 88, 7248, 86, 7248, 96, 7296, 106, 7296, 70, 7296, 74, 7296, 86, 7296, 86, 7344, 105, 7344, 82, 7344, 88, 7344, 96, 7392, 103, 7392, 70, 7392, 74, 7392, 89, 7440, 76, 7440, 96, 7488, 105, 7488, 72, 7488, 77, 7488, 89, 7488, 89, 7536, 81, 7536, 96, 7584, 101, 7584, 72, 7584, 77, 7584, 91, 7632, 93, 7632, 96, 7680, 103, 7680, 70, 7680, 74, 7680, 91, 7680, 94, 7728, 106, 7728, 79, 7728, 94, 7776, 105, 7776, 70, 7776, 74, 7776, 93, 7824, 103, 7824, 79, 7872, 100, 7872, 72, 7872, 76, 7872, 91, 7872, 91, 7920, 101, 7920, 79, 7968, 103, 7968, 72, 7968, 76, 7968, 89, 8016, 108, 8016, 79, 8016, 91, 8064, 105, 8064, 72, 8064, 77, 8064, 89, 8064, 93, 8112, 108, 8112, 81, 8112, 93, 8160, 103, 8160, 72, 8160, 77, 8160, 88, 8160, 91, 8208, 108, 8208, 81, 8256, 101, 8256, 74, 8256, 77, 8256, 86, 8256, 89, 8304, 81, 8304, 93, 8352, 105, 8352, 74, 8352, 77, 8352, 86, 8400, 81, 8400, 84, 8445, 89, 8448, 106, 8448, 70, 8448, 74, 8448, 86, 8496, 79, 8496, 89, 8496, 98, 8544, 101, 8544, 70, 8544, 74, 8544, 89, 8592, 79, 8592, 88, 8592, 98, 8640, 105, 8640, 69, 8640, 73, 8640, 88, 8688, 79, 8688, 88, 8688, 97, 8736, 103, 8736, 69, 8736, 73, 8736, 74, 8736, 90, 8784, 102, 8784, 79, 8784, 90, 8832, 62, 8832, 69, 8880, 74, 8928, 78, 8976, 62, 8976, 74, 9024, 59, 9024, 71, 9072, 74, 9120, 78, 9168, 59, 9168, 74, 9216, 62, 9216, 69, 9264, 74, 9312, 78, 9360, 62, 9360, 74, 9408, 59, 9408, 71, 9456, 74, 9504, 78, 9552, 59, 9552, 74, 9600, 62, 9600, 69, 9648, 74, 9696, 78, 9744, 62, 9744, 74, 9792, 59, 9792, 71, 9840, 74, 9888, 78, 9936, 59, 9936, 74, 9984, 62, 9984, 69, 10032, 74, 10080, 78, 10128, 62, 10128, 74, 10128, 81, 10176, 71, 10176, 71, 10176, 91, 10224, 74, 10224, 90, 10272, 71, 10272, 78, 10272, 88, 10320, 69, 10320, 74, 10320, 88, 10368, 62, 10368, 69, 10368, 90, 10416, 74, 10464, 78, 10512, 62, 10512, 74, 10560, 59, 10560, 71, 10608, 74, 10656, 78, 10704, 59, 10704, 74, 10752, 62, 10752, 69, 10800, 74, 10848, 78, 10896, 62, 10896, 74, 10944, 59, 10944, 71, 10944, 91, 10992, 74, 10992, 90, 11040, 78, 11040, 88, 11088, 59, 11088, 74, 11088, 88, 11136, 62, 11136, 69, 11184, 74, 11232, 78, 11232, 90, 11280, 62, 11280, 74, 11280, 86, 11328, 59, 11328, 71, 11376, 74, 11376, 88, 11424, 78, 11472, 59, 11472, 74, 11472, 81, 11520, 62, 11520, 69, 11568, 74, 11616, 78, 11664, 62, 11664, 74, 11712, 59, 11712, 71, 11760, 74, 11808, 78, 11856, 59, 11856, 74, 11904, 64, 11904, 71, 11904, 88, 11952, 76, 12000, 79, 12000, 90, 12048, 64, 12048, 76, 12048, 91, 12096, 64, 12096, 71, 12144, 66, 12144, 76, 12192, 67, 12192, 79, 12192, 88, 12240, 76, 12288, 57, 12288, 69, 12288, 85, 12336, 73, 12384, 79, 12384, 86, 12432, 57, 12432, 73, 12432, 88, 12480, 57, 12480, 69, 12528, 59, 12528, 73, 12576, 61, 12576, 79, 12576, 81, 12624, 73, 12624, 81, 12672, 62, 12672, 69, 12720, 74, 12720, 90, 12768, 78, 12816, 62, 12816, 74, 12864, 59, 12864, 71, 12912, 74, 12960, 78, 13008, 59, 13008, 74, 13056, 62, 13056, 69, 13104, 74, 13152, 78, 13200, 62, 13200, 74, 13200, 81, 13200, 86, 13248, 71, 13248, 71, 13248, 91, 13248, 95, 13296, 74, 13296, 90, 13296, 93, 13344, 71, 13344, 78, 13344, 88, 13344, 91, 13392, 69, 13392, 74, 13392, 88, 13392, 91, 13440, 62, 13440, 69, 13440, 90, 13440, 93, 13488, 74, 13536, 78, 13584, 62, 13584, 74, 13632, 59, 13632, 71, 13680, 74, 13728, 78, 13776, 59, 13776, 74, 13824, 62, 13824, 69, 13872, 74, 13920, 78, 13968, 62, 13968, 74, 13968, 81, 13968, 86, 14016, 59, 14016, 71, 14016, 91, 14016, 95, 14064, 74, 14064, 90, 14064, 93, 14112, 78, 14112, 88, 14112, 91, 14160, 59, 14160, 74, 14160, 88, 14160, 91, 14208, 62, 14208, 69, 14256, 74, 14304, 78, 14304, 90, 14304, 93, 14352, 62, 14352, 74, 14352, 86, 14352, 90, 14400, 59, 14400, 71, 14448, 74, 14496, 78, 14496, 88, 14496, 91, 14544, 59, 14544, 74, 14544, 81, 14544, 86, 14592, 62, 14592, 69, 14640, 74, 14688, 78, 14736, 62, 14736, 74, 14784, 59, 14784, 71, 14832, 74, 14880, 78, 14928, 59, 14928, 74, 14976, 64, 14976, 71, 14976, 88, 15024, 76, 15072, 79, 15072, 90, 15120, 64, 15120, 76, 15120, 91, 15168, 64, 15168, 71, 15216, 66, 15216, 76, 15264, 67, 15264, 79, 15264, 88, 15312, 76, 15360, 57, 15360, 69, 15360, 85, 15408, 73, 15456, 79, 15456, 86, 15504, 57, 15504, 73, 15504, 88, 15552, 57, 15552, 69, 15600, 59, 15600, 73, 15600, 81, 15648, 61, 15648, 79, 15648, 86, 15696, 57, 15696, 73, 15696, 88, 15744, 58, 15744, 70, 15744, 89, 15792, 74, 15792, 88, 15840, 81, 15840, 86, 15888, 70, 15888, 77, 15888, 84, 15936, 81, 15984, 77, 16032, 70, 16032, 77, 16032, 81, 16032, 81, 16080, 57, 16080, 77, 16080, 79, 16080, 82, 16128, 65, 16128, 72, 16128, 77, 16128, 81, 16128, 84, 16176, 81, 16224, 72, 16224, 77, 16224, 84, 16224, 89, 16272, 65, 16320, 60, 16320, 72, 16320, 76, 16320, 84, 16320, 88, 16368, 79, 16368, 86, 16416, 72, 16416, 76, 16416, 82, 16416, 86, 16464, 60, 16464, 81, 16464, 84, 16512, 58, 16512, 70, 16512, 74, 16512, 82, 16512, 86, 16560, 81, 16560, 82, 16560, 84, 16608, 70, 16608, 74, 16608, 81, 16608, 84, 16656, 58, 16656, 76, 16704, 65, 16704, 72, 16704, 77, 16704, 81, 16704, 84, 16752, 81, 16800, 72, 16800, 77, 16800, 79, 16800, 81, 16848, 77, 16848, 82, 16896, 65, 16896, 72, 16896, 77, 16896, 77, 16896, 84, 16944, 81, 16992, 72, 16992, 77, 16992, 81, 16992, 89, 17040, 65, 17088, 60, 17088, 72, 17088, 76, 17088, 82, 17088, 91, 17136, 79, 17136, 81, 17136, 89, 17184, 72, 17184, 76, 17184, 79, 17184, 88, 17232, 60, 17232, 77, 17232, 86, 17280, 58, 17280, 70, 17280, 74, 17280, 77, 17280, 86, 17328, 79, 17328, 82, 17328, 88, 17376, 70, 17376, 74, 17376, 81, 17376, 89, 17424, 58, 17424, 76, 17472, 65, 17472, 72, 17472, 77, 17472, 81, 17472, 89, 17520, 81, 17568, 65, 17568, 72, 17568, 77, 17568, 82, 17568, 91, 17616, 60, 17616, 84, 17616, 93, 17664, 58, 17664, 70, 17664, 74, 17664, 86, 17664, 94, 17712, 79, 17712, 86, 17712, 94, 17760, 58, 17760, 70, 17760, 74, 17760, 84, 17760, 93, 17808, 79, 17856, 60, 17856, 72, 17856, 76, 17856, 84, 17856, 91, 17904, 79, 17952, 60, 17952, 72, 17952, 76, 17952, 81, 17952, 89, 18000, 79, 18000, 82, 18000, 91, 18048, 65, 18048, 72, 18048, 77, 18048, 84, 18048, 93, 18096, 81, 18096, 84, 18096, 93, 18144, 64, 18144, 72, 18144, 77, 18144, 82, 18144, 91, 18192, 81, 18192, 89, 18240, 62, 18240, 74, 18240, 77, 18240, 81, 18240, 89, 18288, 81, 18336, 60, 18336, 74, 18336, 77, 18336, 79, 18336, 86, 18384, 77, 18384, 81, 18384, 84, 18432, 58, 18432, 70, 18432, 74, 18432, 77, 18432, 86, 18480, 79, 18480, 79, 18480, 89, 18528, 65, 18528, 70, 18528, 74, 18528, 81, 18528, 89, 18576, 79, 18576, 79, 18576, 88, 18624, 57, 18624, 69, 18624, 73, 18672, 79, 18672, 79, 18672, 88, 18720, 64, 18720, 69, 18720, 73, 18720, 81, 18720, 90, 18768, 79, 18768, 81, 18768, 90, 18816, 62, 18816, 69, 18864, 74, 18912, 78, 18960, 62, 18960, 74, 19008, 59, 19008, 71, 19056, 74, 19104, 78, 19152, 59, 19152, 74, 19200, 62, 19200, 69, 19248, 74, 19296, 78, 19344, 62, 19344, 74, 19392, 59, 19392, 71, 19440, 74, 19488, 78, 19536, 59, 19536, 74, 19584, 62, 19584, 69, 19632, 74, 19680, 78, 19728, 62, 19728, 74, 19776, 59, 19776, 71, 19824, 74, 19872, 78, 19920, 59, 19920, 74, 19968, 62, 19968, 69, 20016, 74, 20064, 78, 20112, 62, 20112, 74, 20160, 71, 20160, 71, 20160, 91, 20184, 91, 20208, 74, 20208, 90, 20256, 71, 20256, 78, 20256, 88, 20304, 69, 20304, 74, 20304, 88, 20352, 69, 20376, 90, 20400, 74, 20448, 78, 20496, 74, 20544, 71, 20592, 74, 20640, 78, 20688, 74, 20736, 69, 20784, 74, 20832, 78, 20880, 74, 20880, 81, 20928, 71, 20928, 91, 20976, 74, 20976, 90, 21024, 78, 21024, 88, 21072, 74, 21072, 88, 21120, 69, 21168, 74, 21216, 78, 21216, 90, 21264, 74, 21264, 86, 21312, 71, 21360, 74, 21408, 78, 21408, 88, 21456, 74, 21456, 81, 21504, 69, 21552, 74, 21600, 78, 21648, 74, 21696, 71, 21744, 74, 21792, 78, 21840, 74, 21888, 71, 21888, 88, 21936, 76, 21984, 79, 21984, 90, 22032, 76, 22032, 91, 22080, 71, 22128, 76, 22176, 79, 22176, 88, 22224, 76, 22272, 69, 22272, 85, 22320, 73, 22368, 79, 22368, 86, 22416, 73, 22416, 88, 22464, 69, 22512, 73, 22560, 79, 22560, 81, 22608, 73, 22608, 81, 22656, 69, 22704, 74, 22704, 90, 22752, 78, 22800, 74, 22848, 71, 22896, 74, 22944, 78, 22992, 74, 23040, 69, 23088, 74, 23136, 78, 23184, 74, 23232, 71, 23232, 91, 23232, 95, 23280, 74, 23280, 90, 23280, 93, 23328, 78, 23328, 88, 23328, 91, 23376, 74, 23376, 88, 23376, 91, 23424, 62, 23424, 69, 23436, 90, 23436, 93, 23472, 74, 23520, 78, 23568, 62, 23568, 74, 23616, 59, 23616, 71, 23664, 74, 23712, 78, 23760, 59, 23760, 74, 23808, 62, 23808, 69, 23856, 74, 23904, 78, 23952, 62, 23952, 74, 24000, 59, 24000, 71, 24000, 91, 24000, 95, 24048, 74, 24048, 90, 24048, 93, 24096, 78, 24096, 88, 24096, 91, 24144, 59, 24144, 74, 24144, 88, 24144, 91, 24192, 62, 24192, 69, 24240, 74, 24288, 78, 24288, 90, 24288, 93, 24336, 62, 24336, 74, 24336, 86, 24336, 90, 24384, 59, 24384, 71, 24432, 74, 24480, 78, 24480, 88, 24480, 91, 24528, 59, 24528, 74, 24528, 81, 24528, 86, 24576, 62, 24576, 69, 24624, 74, 24672, 78, 24720, 62, 24720, 74, 24768, 59, 24768, 71, 24816, 74, 24864, 78, 24912, 59, 24912, 74, 24960, 64, 24960, 71, 24960, 88, 25008, 76, 25056, 79, 25056, 90, 25104, 64, 25104, 76, 25104, 91, 25152, 64, 25152, 71, 25200, 66, 25200, 76, 25248, 67, 25248, 79, 25248, 88, 25296, 76, 25344, 57, 25344, 69, 25344, 85, 25392, 73, 25440, 79, 25440, 86, 25488, 57, 25488, 73, 25488, 88, 25536, 57, 25536, 69, 25584, 59, 25584, 73, 25584, 81, 25632, 61, 25632, 79, 25632, 86, 25680, 57, 25680, 73, 25680, 88, 25728, 58, 25728, 70, 25728, 89, 25776, 74, 25776, 88, 25824, 81, 25824, 86, 25872, 70, 25872, 77, 25872, 84, 25920, 81, 25968, 77, 26016, 70, 26016, 77, 26016, 81, 26016, 81, 26064, 57, 26064, 77, 26064, 79, 26064, 82, 26112, 65, 26112, 72, 26112, 77, 26112, 81, 26112, 84, 26160, 81, 26208, 72, 26208, 77, 26208, 84, 26208, 89, 26256, 65, 26304, 60, 26304, 72, 26304, 76, 26304, 84, 26304, 88, 26352, 79, 26352, 86, 26400, 72, 26400, 76, 26400, 82, 26400, 86, 26448, 60, 26448, 81, 26448, 84, 26496, 58, 26496, 70, 26496, 74, 26496, 82, 26496, 86, 26544, 81, 26544, 82, 26544, 84, 26592, 70, 26592, 74, 26592, 81, 26592, 84, 26640, 58, 26640, 76, 26688, 65, 26688, 72, 26688, 77, 26688, 81, 26688, 84, 26736, 81, 26784, 72, 26784, 77, 26784, 79, 26784, 81, 26832, 65, 26832, 77, 26832, 82, 26880, 65, 26880, 72, 26880, 77, 26880, 77, 26880, 84, 26928, 81, 26976, 72, 26976, 77, 26976, 81, 26976, 89, 27024, 65, 27072, 60, 27072, 72, 27072, 76, 27072, 82, 27072, 91, 27120, 79, 27120, 81, 27120, 89, 27168, 72, 27168, 76, 27168, 79, 27168, 88, 27216, 60, 27216, 77, 27216, 86, 27264, 58, 27264, 70, 27264, 74, 27264, 77, 27264, 86, 27312, 79, 27312, 82, 27312, 88, 27360, 70, 27360, 74, 27360, 81, 27360, 89, 27408, 58, 27408, 76, 27456, 65, 27456, 72, 27456, 77, 27456, 81, 27456, 89, 27504, 81, 27552, 65, 27552, 72, 27552, 77, 27552, 82, 27552, 91, 27600, 60, 27600, 84, 27600, 93, 27648, 58, 27648, 70, 27648, 74, 27648, 86, 27648, 94, 27696, 79, 27696, 86, 27696, 94, 27744, 58, 27744, 70, 27744, 74, 27744, 84, 27744, 93, 27792, 79, 27792, 91, 27840, 60, 27840, 72, 27840, 76, 27840, 84, 27840, 91, 27888, 79, 27936, 60, 27936, 72, 27936, 76, 27936, 81, 27936, 89, 27984, 79, 27984, 82, 27984, 91, 28032, 65, 28032, 72, 28032, 77, 28032, 84, 28032, 93, 28080, 81, 28080, 84, 28080, 93, 28128, 64, 28128, 72, 28128, 77, 28128, 82, 28128, 91, 28176, 81, 28176, 89, 28224, 62, 28224, 74, 28224, 77, 28224, 81, 28224, 89, 28272, 81, 28320, 60, 28320, 74, 28320, 77, 28320, 79, 28320, 86, 28368, 77, 28368, 81, 28368, 84, 28416, 58, 28416, 70, 28416, 74, 28416, 77, 28416, 86, 28464, 79, 28464, 79, 28464, 89, 28512, 65, 28512, 70, 28512, 74, 28512, 81, 28512, 89, 28560, 79, 28560, 79, 28560, 88, 28608, 57, 28608, 69, 28608, 73, 28656, 79, 28656, 79, 28656, 88, 28704, 64, 28704, 69, 28704, 73, 28704, 81, 28704, 90, 28752, 79, 28752, 81, 28752, 90, 28800, 62, 28800, 69, 28848, 74, 28896, 78, 28944, 62, 28944, 74, 28992, 59, 28992, 71, 29040, 74, 29088, 78, 29088, 93, 29136, 59, 29136, 74, 29136, 93, 29184, 62, 29184, 69, 29184, 95, 29232, 74, 29232, 93, 29280, 78, 29280, 90, 29328, 62, 29328, 74, 29328, 86, 29376, 59, 29376, 71, 29424, 74, 29424, 88, 29424, 91, 29472, 78, 29472, 90, 29472, 93, 29520, 59, 29520, 74, 29520, 90, 29520, 93, 29568, 62, 29568, 69, 29616, 74, 29664, 78, 29712, 62, 29712, 74, 29760, 59, 29760, 71, 29808, 74, 29808, 93, 29856, 78, 29856, 93, 29904, 59, 29904, 74, 29904, 93, 29952, 62, 29952, 69, 29952, 95, 30000, 74, 30000, 93, 30048, 78, 30048, 90, 30096, 62, 30096, 74, 30096, 86, 30144, 59, 30144, 71, 30192, 74, 30192, 88, 30192, 91, 30240, 78, 30240, 90, 30240, 93, 30288, 59, 30288, 74, 30288, 90, 30288, 93, 30336, 62, 30336, 69, 30384, 74, 30432, 78, 30480, 62, 30480, 74, 30528, 59, 30528, 71, 30576, 74, 30576, 93, 30624, 78, 30624, 93, 30672, 59, 30672, 74, 30672, 93, 30720, 62, 30720, 69, 30720, 95, 30768, 74, 30768, 93, 30816, 78, 30816, 90, 30864, 62, 30864, 74, 30864, 86, 30912, 59, 30912, 71, 30960, 74, 30960, 88, 30960, 91, 31008, 78, 31008, 90, 31008, 93, 31056, 59, 31056, 74, 31056, 90, 31056, 93, 31104, 62, 31104, 69, 31152, 74, 31200, 78, 31248, 62, 31248, 74, 31296, 59, 31296, 71, 31344, 74, 31392, 78, 31392, 93, 31440, 59, 31440, 74, 31440, 93, 31488, 62, 31488, 69, 31488, 95, 31536, 74, 31536, 93, 31584, 78, 31584, 90, 31632, 62, 31632, 74, 31632, 86, 31680, 59, 31680, 71, 31728, 74, 31728, 88, 31728, 91, 31776, 78, 31776, 90, 31776, 93, 31824, 59, 31824, 74, 31824, 90, 31824, 93, 31872, 62, 31872, 69, 31920, 74, 31968, 78, 32016, 62, 32016, 74, 32064, 59, 32064, 71, 32112, 74, 32112, 93, 32160, 78, 32160, 93, 32208, 59, 32208, 74, 32208, 93, 32256, 62, 32256, 69, 32256, 95, 32304, 74, 32304, 93, 32352, 78, 32352, 90, 32400, 62, 32400, 74, 32400, 86, 32448, 59, 32448, 71, 32496, 74, 32496, 88, 32496, 91, 32544, 78, 32544, 90, 32544, 93, 32592, 59, 32592, 74, 32592, 90, 32592, 93, 32640, 62, 32640, 69, 32688, 74, 32736, 78, 32784, 62, 32784, 74, 32832, 59, 32832, 71, 32880, 74, 32880, 91, 32928, 78, 32928, 93, 32976, 59, 32976, 74, 32976, 93, 33024, 62, 33024, 69, 33072, 74, 33120, 78, 33168, 62, 33168, 74, 33216, 71, 33216, 71, 33264, 74, 33264, 91, 33312, 71, 33312, 78, 33312, 90, 33360, 69, 33360, 74, 33360, 90, 33791, 0 // 176 seconds * 48 * 4 - 1 };
synth.asm
.cdecls C, LIST, "msp430fr5739.h" .text .def set_tick .def get_tick .def synth_init .def set_note .ref wave .bss tick, 2 .bss pwm_out, 2 .bss phase_inc, 6 * 8 ; Level ; Phase increment LSW/MSW (from note table) .bss phase_acc, 4 * 8 ; Phase accumulator LSW/MSW .def phase_inc set_tick: mov R12, &tick reta get_tick: mov &tick, R12 reta synth_init: mov #0x0210, &TA0CTL ; Timer A config: SMCLK, count up mov #749, &TA0CCR0 ; Setup Timer A period for 32000 sps mov #375, &TA0CCR1 ; Setup Timer A compare mov #0x00E0, &TA0CCTL1 ; Setup Timer A reset/set output mode ; mov #phase_inc, R12 ; Clear all phase inc and accum mov #5 * 16, R14 ; Word count clr 0(R12) ; Clear word incd R12 ; Next word dec R14 ; Dec word count jne $ - 8 ; Loop until all words done... ; eint ; Enable interupts bis #0x0010, &TA0CCTL0 ; Enable PWM interupt ; reta ; ; synth_isr: ; mov &pwm_out, &TA0CCR1 ; Output sample ; push R4 ; Wavetable pointer push R5 ; Phase increment / level pointer push R6 ; Phase accumulator pointer push R8 ; Wave sample pointer / next sample push R9 ; Wave sample push R10 ; Voice mix accumulator MSW push R11 ; Voice mix accumulator LSW ; mov #wave, R4 ; Setup wavetable pointer mov #phase_inc, R5 ; Setup phase increment and level pointer mov #phase_acc, R6 ; Setup phase accumulator pointer clr R10 ; Clear voice mix clr R11 ; voice_loop: ; .loop 8 mov @R6+, &MPYS32L ; Get phase acc LSW (fraction) to multiplier mov @R6+, R8 ; Get phase acc MSW (wave table index) ; bit #0xFF00, R8 ; Test phase acc MSB mov.b R8, R8 ; Clear MSB ;jeq no_decay ; jeq $ + 22 mov @R5, &MPY ; Get level mov #0xFF00, &OP2 ; Decay factor mov R8, -2(R6) ; Update phase acc mov &RES1, 0(R5) ; Update level ;no_decay: clr &MPYS32H ; add R8, R8 ; Make word index add R4, R8 ; Add wavetable pointer mov @R8+, R9 ; Get wave sample mov @R8, R8 ; Get next wave sample sub R9, R8 ; Calc delta mov R8, &OP2L ; Multiply by delta bit #0x8000, R8 ; Sign extend delta subc R8, R8 ; inv R8 ; mov R8, &OP2H ; add &RES1, R9 ; Add interpolation to sample mov R9, &MPYS ; Multiply by voice level mov @R5+, &OP2 ; add @R5+, -4(R6) ; Update phase acc addc @R5+, -2(R6) ; add &RES0, R11 ; Update mix addc &RES1, R10 ; ; .endloop ; swpb R10 ; Use MSB of R10 mov.b R10, R10 ; sxt R10 ; Sign extend add R10, R10 ; * 2 add #375, R10 ; Bias to center of PWM range mov R10, &pwm_out ; ; dec &tick ; jc $ + 6 ; clr &tick ; ; pop R11 ; pop R10 ; pop R9 ; pop R8 ; pop R6 ; pop R5 ; pop R4 ; reti ; ; set_note: ; mov R12, R15 ; Voice * 6 add R15, R12 ; (+1 = *2) add R15, R12 ; (+1 = *3) rla R12 ; (*2 = *6) add #phase_inc, R12 ; Add phase inc pointer mov R14, 0(R12) ; Set level cmp #128, R13 ; Out of range note values are note off jhs note_off ; clr R14 ; Clear octave count tst_note: ; cmp #116, R13 ; Within note table? jge get_pi ; Yes... inc R14 ; Inc octave count add #12, R13 ; Add octave to note jmp tst_note ; Check again... get_pi: ; Get phase increment sub #116, R13 ; Adjust for first note in table rla R13 ; MIDI note * 4 rla R13 ; add #notes, R13 ; Add note table pointer mov @R13+, R15 ; Get LSW mov @R13, R13 ; Get MSW tst R14 ; Shifting required? jeq set_phase ; No... shift_phase: ; rra R13 ; Shift phase inc rrc R15 ; dec R14 ; Dec octave count jne shift_phase ; Repeat until zero... set_phase: ; mov R15, 2(R12) ; Set phase inc mov R13, 4(R12) ; reta ; Return ; note_off: ; incd SP ; Discard level clr 0(R12) ; Clear phase inc clr 2(R12) ; .if 0 ; Note: Abrupt return to zero causes poping clr 4(R12) ; Clear level add #phase_acc - phase_inc, R12 ; Phase accum pointer clr 0(R12) ; Clear phase accum clr 2(R12) ; .endif ; reta ; Return ; ; notes ; MIDI Note Frequency .long 3483828 ; 116 G#8 6644.87457275391 .long 3690988 ; 117 A8 7040.00091552734 .long 3910465 ; 118 A#8 7458.62007141113 .long 4142993 ; 119 B8 7902.13203430176 .long 4389349 ; 120 C9 8372.01881408691 .long 4650353 ; 121 C#9 8869.84443664551 .long 4926877 ; 122 D9 9397.27210998535 .long 5219845 ; 123 D#9 9956.06422424316 .long 5530233 ; 124 E9 10548.0823516846 .long 5859077 ; 125 F9 11175.3025054932 .long 6207476 ; 126 F#9 11839.8208618164 .long 6576592 ; 127 G9 12543.8537597656 ; Interrupt Vectors .sect ".int53" ; TA0CCR0 CCIFG0 .short synth_isr ; ; .end ;
-
NatureTM got a reaction from ROFLhoff in Flashing the missing DCO calibration constants
EDIT: Here's another really nice DCO calibration program. It's part of TinyOS-msp430. http://code.google.com/p/tinyos-msp430/ It's the file called calibrate-dco. As gordon, who discovered it said, "[it] appears to be a quite beefed-up DCO calibration app, with goodies on the side (taking silicon errata into account for various devices when calibrating)." It looks like it's built to be solid and reliable. I skimmed over the code and didn't see anything for calculating SegA checksum, but that usually isn't an issue for most non-critical applications.
EDIT: maxpenna shared another version of the DCO calibration program. This is the one to use if you need a correct SegmentA checksum. It uses the C calibration function. You can get it here http://www.43oh.com/forum/download/file.php?id=292
WARNING: Some of the programs in this thread will erase Segment A and only put back the DCO calibrations. They should not be used with chips that have an ADC12, as this process will destroy the ADC12 calibrations. Some of the programs do not calculate the Segment A checksum, so the integrity of Segment A cannot be verified during runtime after calibration. Still, I've been using it without any problems.
There's been a bit of a discussion in another thread about an idea simpleavr had for adding the dco calibration constants to flash for the Value Line series. I've cobbled together some pieces of TI code and have it working. It seems to work great. Here's how I did it with CCS. I think the people on linux should be able to reproduce the result with a little adaptation.
This requires the TI DCO library I modified in another thread and an external LF crystal like the one with Launchpad.
http://naturetm.com/files/Launchpad%20setDCO%20lib.rar
First, run this to calibrate the constants and write them to flash:
EDIT: 43oh member zeke has made some changes to the code for finer tuning. Check page 2 for his code.
//****************************************************************************** // MSP430F20xx Demo - DCO Calibration Constants Programmer // // NOTE: THIS CODE REPLACES THE TI FACTORY-PROGRAMMED DCO CALIBRATION // CONSTANTS LOCATED IN INFOA WITH NEW VALUES. USE ONLY IF THE ORIGINAL // CONSTANTS ACCIDENTALLY GOT CORRUPTED OR ERASED. // // Description: This code re-programs the F2xx DCO calibration constants. // A software FLL mechanism is used to set the DCO based on an external // 32kHz reference clock. After each calibration, the values from the // clock system are read out and stored in a temporary variable. The final // frequency the DCO is set to is 1MHz, and this frequency is also used // during Flash programming of the constants. The program end is indicated // by the blinking LED. // ACLK = LFXT1/8 = 32768/8, MCLK = SMCLK = target DCO // //* External watch crystal installed on XIN XOUT is required for ACLK *// // // MSP430F20xx // --------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // | | // | P1.0|--> LED // | P1.4|--> SMLCK = target DCO // // A. Dannenberg // Texas Instruments Inc. // May 2007 // Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.42A //****************************************************************************** #include "msp430x20x1.h" #include "DCO_Library.h" unsigned char CAL_DATA[8]; // Temp. storage for constants volatile unsigned int i; int j; char *Flash_ptrA; // Segment A pointer void Set_DCO(unsigned int setting); void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT for (i = 0; i < 0xfffe; i++); // Delay for XTAL stabilization P1OUT = 0x01; // Red LED on P1SEL = 0x10; // P1.4 SMCLK output P1DIR = 0x51; // P1.0,4,6 output j = 0; // Reset pointer Set_DCO(TI_DCO_16MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_12MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_8MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_1MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Flash_ptrA = (char *)0x10C0; // Point to beginning of seg A FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator FCTL1 = FWKEY + ERASE; // Set Erase bit FCTL3 = FWKEY + LOCKA; // Clear LOCK & LOCKA bits *Flash_ptrA = 0x00; // Dummy write to erase Flash seg A FCTL1 = FWKEY + WRT; // Set WRT bit for write operation Flash_ptrA = (char *)0x10F8; // Point to beginning of cal consts for (j = 0; j < 8; j++) *Flash_ptrA++ = CAL_DATA[j]; // re-flash DCO calibration data FCTL1 = FWKEY; // Clear WRT bit FCTL3 = FWKEY + LOCKA + LOCK; // Set LOCK & LOCKA bit P1OUT = 0; while (1) { P1OUT ^= BIT6; // Toggle green LED for (i = 0; i < 0x4000; i++); // SW Delay } } void Set_DCO(unsigned int setting){ volatile unsigned int I; // P1DIR |= BIT0; // P1.0 output BCSCTL1 &= ~XTS; // external source is LF; BCSCTL3 &= ~(LFXT1S0 + LFXT1S1); // watch crystal mode BCSCTL3 |= XCAP0 + XCAP1; // ~12.5 pf cap on the watch crystal as recommended for( I = 0; I < 0xFFFF; I++){} // delay for ACLK startup if(TI_SetDCO(setting) == TI_DCO_NO_ERROR) // if setting the clock was successful, P1OUT |= BIT0; // bring P1.0 high (Launchpad red LED) else while(1); // trap if setting the clock isn't successful }
The green light should start blinking in a few seconds, indicating success. Now we need to modify some linker and header files so CCS knows about the new calibrations.
I'm using the MSP430G2231, so I duplicated the file C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.cmd in that directory, and renamed the duplicate as msp430g2231_mod.cmd. Now I can edit it without affecting the original. Edit msp430g2231_mod.cmd and change the calibration section at the bottom to this:
/************************************************************ * Calibration Data in Info Mem ************************************************************/ CALDCO_16MHZ = 0x10F8; CALBC1_16MHZ = 0x10F9; CALDCO_12MHZ = 0x10FA; CALBC1_12MHZ = 0x10FB; CALDCO_8MHZ = 0x10FC; CALBC1_8MHZ = 0x10FD; CALDCO_1MHZ = 0x10FE; CALBC1_1MHZ = 0x10FF;
Now the linker knows we have calibration data in that section when we use the modified file.
When we create a new project in CCS or modify an existing one, CCS will want to use the default linking file, and the default header. Here's an example about how to configure a project to use the new constants.
First create a new project. Within the project, there should be a file called something like lnk_msp430g2231.cmd. The last line of that file should be something like -l msp430g2231.cmd. Open it, and change the last line to reflect the new linker file so it reads -l msp430g2231_mod.cmd.
Next, add the appropriate header file to the project. Right-click the project folder in the left pane of CCS and click "Add files to project..." In this example, I'm using C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.h. Now we have a copy of the file in the project we can safely edit. Edit the file so the calibration section looks like this:
/************************************************************ * Calibration Data in Info Mem ************************************************************/ #ifndef __DisableCalData SFR_8BIT(CALDCO_16MHZ); /* DCOCTL Calibration Data for 16MHz */ SFR_8BIT(CALBC1_16MHZ); /* BCSCTL1 Calibration Data for 16MHz */ SFR_8BIT(CALDCO_12MHZ); /* DCOCTL Calibration Data for 12MHz */ SFR_8BIT(CALBC1_12MHZ); /* BCSCTL1 Calibration Data for 12MHz */ SFR_8BIT(CALDCO_8MHZ); /* DCOCTL Calibration Data for 8MHz */ SFR_8BIT(CALBC1_8MHZ); /* BCSCTL1 Calibration Data for 8MHz */ SFR_8BIT(CALDCO_1MHZ); /* DCOCTL Calibration Data for 1MHz */ SFR_8BIT(CALBC1_1MHZ); /* BCSCTL1 Calibration Data for 1MHz */ #endif /* #ifndef __DisableCalData */
Now you can begin using the new calibration data in your program. When you #include the msp430g2231.h file, put it in quotes instead of <> to ensure it's loading the modified header local to the project directory.
I tested the constants with a cheap oscilloscope and they seemed correct. My scope doesn't have great accuracy at high frequencies so they might be a little off, but nothing I can detect. It works with my composite video prog, so that's a pretty good sign.
EDIT: Oops! I had an incorrectly named file in these instructions. Corrected.
-
NatureTM reacted to ike in Serial Fun
Q. What is that?
A. It's "Serial Fun", a serial LCD using msp430g2211, HD44780 and one resistor.
Q. Why are you doing this, there are many serial LCD on the market?
A. I don't like them. Using PIC16F88 or ATmega for display and using cheap and low power msp430G2xxx for main CPU is just plain stupid.
Q. SparkFun's serial LCD looks better!
A. Yes, you are right. But it cost $24.95 and have to wait for shipping. You may have cheap 16x2 LCD module form ebay for $3.20 and extra MCU msp430g2211, that comes with LaunchPad, so you can have serial LCD right now and is more cheap.
Q. $3.20 for serial LCD? OK, where is the catch?
A. There is no catch. You just need piece of perfboard, 12 pin male header, 1800 Ohm resistor, little bit of wire and LCD module itself.
Q. Schemes in source code and on the picture are different.
A. Yes. Scheme in the source code is how to connect stand alone msp430g2211 to LCD and on the picture is how to connect LaunchPad to LCD.
Q. Your pictures are crap.
A. Yes. I like to work at night and my camera is not so great at artificial lighting. I'll make better pictures and will post it here, but I suggest anyone who has spare LCD module and LaunchPad to assemble this easy project and post picture of it.
Q. Why are you using 1800 Ohm resistor instead of 10k pot?
A. Because when you adjust the pot it's resistance will be 1800 Ohm. I know it's value depends of supply volgate, temperature and manufacturer, but most cheap negative LCD modules needs 1800 Ohm resistor.
Q. How do you power 5.0V LCD module?
A. From Test Point 1, tag as TP1 near USB connector.
Q. What if I have 3.3V LCD module?
A. Power it form pin 1 VCC on the LaunchPad.
Q. You connected BackLight without resistor, it will burn in flames.
A. On cheap LCD modules there is internal 100 Ohm resistor on module connected in series with LED, so it will not burn.
Q. You did not turn-off BackLight because Pin 3 (P1.1) goes to 3.6V not 5.0V, so there is 1.4V voltage when it should be 0V
A. White LED will not turn-on 1.4V.
Q. You are torturing Pin 3 (P1.1) forcing it to sink so much current.
A. It will be OK.
Q. It is time for code review. I don't like your code.
A. You have the source and you are free to improve it. I think that is great project, that will be useful for most of 43ohers and if
you can make it better is good for all of us.
Q. I don't like 9600 Baud connection speed.
A. If you could set DCOCLK to 16MHz and use BCSCTL1, DIVAx Bits 5-4 (Divider for ACLK) to run it at 19200, 38400, 76800 and 153600 bps.(not tested but should be OK)
Q. No I wish slower speed.
A. OK. Change this 2 lines
104 and 208 will give you 4800bps.
208 and 416 will give you 2400bps.
416 and 832 will give you 1200bps and so on...
Q. How can I control it?
A. Just use terminal emulator on your computer, you can use another LaunchPad or stand alone MCU to send serial data to Pin 4 (P1.2). Tiny printf() - C version is a good example how to send data to serial LCD.
Q. You don't use delay after each LCD write.
A. You are right. 9600 bps is so slow and modern LCD are more faster than ones manufactured by Hitachi 30-40 years ago. If you wish you could add some delays here and there.
Q. What about if I have different LCD module like 4x20, not default one 2x16?
A. All standard character LCD modules are supported including 1x8, 2x8, 1x16, 2x16, 2x20, 2x24, 4x16, 4x20.
Q. How?
A. One character which look like space is sacrificed as escape code, just like SparkFun's serial LCD. 0xFE or 254 is interpreted as magical symbol, next symbol is send to LCD as a command, except for 0b 001x xxxx which will change operation mode of LCD module and it will stop working.
To send 0xFE or 254 character in Windows OS, turn on NumLock, hold Alt key and type on the NumPad 254 and then release Alt key.
254 and 0 does nothing.
254 and 1 Clears Display and set DDRAM address to 0.
254 and 2 or 3 Sets DDRAM address 0 in address counter. Also returns display from being shifted to original position. DDRAM
contents remain unchanged.
254 and 4 to 7 Sets cursor move direction and specifies display shift.
254 and 8 to 15 Sets entire display (D) on/off, cursor on/off ©, and blinking of cursor position character (.
254 and 16 to 31 Moves cursor and shifts display without changing DDRAM contents.
254 and 32 to 43 is where fun begins.
Look at this table
For example
254 and 32 is BackLight on, 2 lines, Address (0-15,64-79,16-31,80-95), Rows 16.
254 and 48 is BackLight off, 2 lines, Address (0-15,64-79,16-31,80-95), Rows 16.
254 and 46 is BackLight on, 4 lines, Address (0-19,64-83,20-39,84-103), Rows 20.
254 and 62 is BackLight off, 4 lines, Address (0-19,64-83,20-39,84-103), Rows 20.
Some of the values are invalid like 4 lines, 24 rows is not valid combination, there is no such display. Most common LCD modules 1x16 are actuality 2 lines, 8 rows.
254 and 64 to 127 Sets CGRAM address. CGRAM data is sent and received after this setting. Address 0 of CGRAM for custom graphics.
254 and 128 or bigger is equivalent to 254 and 1 Clears Display and set DDRAM address to 0.
Q. Custom characters?
A. 1.hold Alt key and type on the NumPad 8 and then release Alt or ctrl+@.
2.hold Alt key and type on the NumPad 1 or 9 and then release Alt or ctrl+a.
3.hold Alt key and type on the NumPad 2 and then release Alt or ctrl+b.
4.hold Alt key and type on the NumPad 3 or 11 and then release Alt or ctrl+c.
5.hold Alt key and type on the NumPad 4 or 12 and then release Alt or ctrl+d.
6.hold Alt key and type on the NumPad 5 and then release Alt or ctrl+e.
7.hold Alt key and type on the NumPad 6 or 14 and then release Alt or ctrl+f.
8.hold Alt key and type on the NumPad 7 or 15 and then release Alt or ctrl+g.
Q. OK, but how can I edit them?
A. Best way is to send Alt+254 and then Alt+64. Now send 8x8 bytes and your CGRAM will be programed. Now send Alt+254 and then Alt+1 to switch back to text mode.
Q. I want to edit individual custom characters(CC).
A.
Alt+254,Alt+64, 8 bytes,Alt+254, Alt+1 for CC#1
Alt+254,Alt+72, 8 bytes,Alt+254, Alt+1 for CC#2
Alt+254,Alt+80, 8 bytes,Alt+254, Alt+1 for CC#3
Alt+254,Alt+88, 8 bytes,Alt+254, Alt+1 for CC#4
Alt+254,Alt+96, 8 bytes,Alt+254, Alt+1 for CC#5
Alt+254,Alt+104, 8 bytes,Alt+254, Alt+1 for CC#6
Alt+254,Alt+112, 8 bytes,Alt+254, Alt+1 for CC#7
Alt+254,Alt+120, 8 bytes,Alt+254, Alt+1 for CC#8
New version ver 0.03, now with less bugs, but with more butterflys!
// msp430g2211 LCD HD44780 White BL // +-----------------+ +------------------+ // | VCC |-+-- 3.6V TP1 5.0V-+---|2. VDD/VCC | // | RST |-+ +---|15. A------>|--+ | // | | | | | // | TEST |-----X +-|5. R/W | | // | GND |---- GND-+------------+-|1. VSS/GND | | // | | +-[~~1.8K~~]---|3. VO | | // | | | | | // | P1.0 |----------------------->|4. RS | | // | P1.1 |----------------------->|16. K-[~100~]- + | // | RXD/P1.2 |<-------- 9600 8N1 | | // | P1.3 |----------------------->|6. Enable | // | P1.4 |----------------------->|11. DB4 | // | P1.5 |----------------------->|12. DB5 | // | P1.6 |----------------------->|13. DB6 | // | P1.7 |----------------------->|14. DB7 | // | | | | // | | X----|7. DB0 | // | | X----|8. DB1 | // | | X----|9. DB2 | // | | X----|10. DB3 | // | | | | // | | | | // +-----------------+ +------------------+ // // // // // // // //ver 0.03 //****************************************************************************** #include "msp430g2211.h" #include "stdint.h" //The one true int //------------------------------------------------------------------------------ // Hardware-related definitions //------------------------------------------------------------------------------ #define LCDDataMode BIT0 // LCD RS DataMode #define LCDBackLight BIT1 // LCD BackLight #define UART_RXD BIT2 // RXD on P1.2 (Timer0_A.CCI1A) #define LCDEnable BIT3 // LCD Enable //------------------------------------------------------------------------------ #define toggle P1OUT|= LCDEnable;__no_operation();P1OUT&= ~LCDEnable; // toggle,toggle on the wall #define MAGIC 0xFE //do you belive in magic? //------------------------------------------------------------------------------ // Conditions for 9600 Baud SW UART, SMCLK = 1MHz //------------------------------------------------------------------------------ #define UART_TBIT_DIV_2 52 //(1000000 / (9600 * 2)) #define UART_TBIT 104 //(1000000 / 9600) //------------------------------------------------------------------------------ // Global variables used for UART RX //------------------------------------------------------------------------------ uint8_t rxBuffer; // Received UART character //------------------------------------------------------------------------------ // main() //------------------------------------------------------------------------------ void main(void) { //1. Stop watchdog WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer //2. Set DCOCLK to 1MHz if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF){ _bis_SR_register(LPM4_bits); // If calibration constant is erased, TRAP! } //Set DCOCLK to 1MHz BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation //3. Initialize all GPIO P1OUT = 0x00; // Initialize all GPIO P1SEL = UART_RXD; // Timer function for RXD pins P1DIR = 0xFF & ~UART_RXD; // Set all pins but RXD to output P2OUT = 0x00; P2SEL = 0x00; P2DIR = 0xFF; //4. LCD Init //wait 0.5 seconds for LCD VCC+ to rise __delay_cycles(500000); // 0.5 seconds //4-bit Interface Mode Samsung 6a0069 // 4-bit mode, 5x8, 1/16 duty, 2 lines, display off P1OUT= 0x20; //4-bit mode toggle toggle P1OUT= 0x80; //operational mode: 5x8, 1/16 duty, 2 lines, display off toggle __delay_cycles( 50 ); //////////////////////////////////////////////// //display on P1OUT= 0x00; // toggle P1OUT= 0xC0; // toggle __delay_cycles( 1600 ); /////////////////////////////////////////////////// //display clear P1OUT= 0x00; // toggle P1OUT= 0x10; // toggle __delay_cycles( 1600 ); ///////////////////////////////////////////////// //Entry Mode Set: Increment mode, Entire shift off P1OUT= 0x00; // toggle P1OUT= 0x60; // toggle ////////////////////////////////////////////////// //5. TimerA_UART_init TACCTL1 = SCS + CM1 + CAP + CCIE; // Sync, Neg Edge, Capture, Int TACTL = TASSEL_2 + MC_2; // SMCLK, start in continuous mode uint8_t x=0; //current x uint8_t y=0; //current y uint8_t lines=2; //most common LCD 16x2 uint8_t rows=16; uint8_t CGRAMmode=0; //on boot write to DDRAM uint8_t address=16; //Address of third line uint8_t CommandFlag=0; //CommandFlag uint8_t BackLight=0; //0 means BackLight ON, 2 means BackLight OFF __enable_interrupt(); // Main loop for (; { // Wait for incoming character __bis_SR_register(LPM0_bits);// Go to bed. if(CommandFlag==1){ CommandFlag=0; if((rxBuffer|0x1F)==0x3F){ //0b 001x xxxx is really funny command, outlaw it! //setup //BIT4 - BackLight: 1 = off, 0 = on //BIT3 - Lines: 1 = 4 lines, 0 = 2 lines //BIT2 - Address: 1 = (0-19,64-83,20-39,84-103), 0=(0-15,64-79,16-31,80-95) //BIT1&BIT0 - Rows 00=16, 01=8, 10=20, 11=24 if((rxBuffer&BIT4)==BIT4) {BackLight=LCDBackLight;P1OUT|=LCDBackLight;} //BackLight OFF else {BackLight=0;P1OUT&=~LCDBackLight;} //BackLight ON if((rxBuffer&BIT2)==BIT2) address=20; //20x2, 20x4, 24x2 else address=16; //16x2, 16x4 if((rxBuffer&BIT3)==BIT3) lines=4; //lines=4 else lines=2; //lines=2 switch(rxBuffer & 0x03){ //rows case 0x00: rows=16; break; case 0x01: rows=8; break; case 0x02: rows=20; break; case 0x03: rows=24; break; } } else{ if(rxBuffer>=0x40){ if(rxBuffer>=0x80){rxBuffer=0x01;goto happydragons;}else{CGRAMmode=1;goto saddragons;} } else{ switch (rxBuffer){ case 0x00:break;//This is invalid command, there is nothing wrong to send it to LCD, //but it's better to use it for something else case 0x01:; case 0x02:; case 0x03: happydragons: CGRAMmode=0;x=0;y=0; default: //send command to LCD saddragons: P1OUT= (rxBuffer& 0xF0)|BackLight; toggle P1OUT= (rxBuffer<< 4)|BackLight; toggle }//switch }//else rxBuffer>=0x40 }//else }//if CommandFlag else if (rxBuffer==MAGIC){CommandFlag=1;}//strange things happens here else{ if(CGRAMmode==0){ switch (rxBuffer){ //filter non interestig characters here case 0x0A: break; //break Line feed case 0x0D: goto dragons; //new line http://xkcd.com/292/ default: //print character P1OUT= (rxBuffer& 0xF0) | LCDDataMode|BackLight; toggle P1OUT= (rxBuffer<< 4) | LCDDataMode|BackLight; toggle x++; if (x==rows){ dragons: x=0; y++; if (y==lines)y=0; //I hope that rxBuffer is free and unused switch(y){ case 0: rxBuffer=0x80; break; //0x80 is address of line 1 case 1: rxBuffer=0xC0; break; //0x80+0x40 is address of line 2 case 2: rxBuffer=0x80+address; break; //line 1 + address case 3: rxBuffer=0xC0+address; break; //line 2 + address } //goto new line P1OUT= (rxBuffer& 0xF0)|BackLight; toggle P1OUT= (rxBuffer<< 4)|BackLight; toggle } }//switch }// CGRAMmode if else{ //data in CGRAMmode P1OUT= (rxBuffer& 0xF0) | LCDDataMode|BackLight; toggle P1OUT= (rxBuffer<< 4) | LCDDataMode|BackLight; toggle }//CGRAMmode else }// no MAGIC }//main loop }//main #pragma vector = TIMERA1_VECTOR __interrupt void Timer_A1_ISR(void) { static uint8_t rxBitCnt = 8; static uint8_t rxData = 0; switch (__even_in_range(TAIV, TAIV_TAIFG)) { // Use calculated branching case TAIV_TACCR1: // TACCR1 CCIFG - UART RX TACCR1 += UART_TBIT; // Add Offset to CCRx if (TACCTL1 & CAP) { // Capture mode = start bit edge TACCTL1 &= ~CAP; // Switch capture to compare mode TACCR1 += UART_TBIT_DIV_2; // Point CCRx to middle of D0 } else { rxData >>= 1; if (TACCTL1 & SCCI) { // Get bit waiting in receive latch rxData |= 0x80; } rxBitCnt--; if (rxBitCnt == 0) { // All bits RXed? rxBuffer = rxData; // Store in global variable rxBitCnt = 8; // Re-load bit counter TACCTL1 |= CAP; // Switch compare to capture mode __bic_SR_register_on_exit(LPM0_bits); // Clear LPM0 bits from 0(SR) } } break; } } //------------------------------------------------------------------------------ //END
-
NatureTM reacted to RobG in SoundPad Booster Pack
Coding time, hardware is ready.
BTW, the board can be cut when sockets are not desired, see the left board.
-
NatureTM reacted to oPossum in DIY Mini Launchpad
Make use of the second MCU (and female headers) included with the Launchpad 50 mm x 50 mm board size - low cost from Seeed & iTead Mostly through hole - anyone can build this Populate with components as needed Mounting holes for secure attachment Power, P1.6 & P1.0 LEDs LED enable jumpers Reset & P1.3 switch Coaxial power jack and/or terminal block Optional Microchip MCP1700/1702 voltage regulator 6 pin power/program/debug/serial connector UART line swap jumper Prototype with Launchpad, build permanent project with this.
lp_mini.brd
lp_mini.sch
-
NatureTM got a reaction from bluehash in Ultrasonic range finder
Here's something I had going awhile back. I didn't finish it do to some bug/got bored/meh. The circuits are the same as what gordon posted. My intent was to send the distance data to another uC through serial. Here's the code I had going and a pic. Hopefully I left things in a working state.
PS Don't look at the code if you wanted to figure it out yourself. I think I was pretty close to finished.
#include "msp430g2231.h" //#include #define PIN_RECEIVER BIT4 #define PIN_TRANSMITTER BIT2 // SPI pins for reference, do not affect code: #define PIN_SCLK BIT5 #define PIN_SDO BIT6 #define ADC_MAX 1023 #define MCLK_FREQUENCY 16000000 #define TRANSMITTER_FREQ 24000 #define WDT_DIVIDER 64 #define SPEED_OF_SOUND_IN_PER_SEC 13071.3f #define MINIMUM_DISTANCE_IN 8 #define MAXIMUM_DISTANCE_IN 600 #define PINGS_AVERAGED 1 #define sendPing() TACTL |= MC_1 #define stopTransducer() TACTL &= ~MC_1 const unsigned long WDT_FREQUENCY = MCLK_FREQUENCY / WDT_DIVIDER; const float WDT_TICKS_PER_IN = (MCLK_FREQUENCY / WDT_DIVIDER) / SPEED_OF_SOUND_IN_PER_SEC; char iTransducerCycle = 0; char nTransducerCycles = 7; volatile unsigned long wdtCounter = 0; volatile unsigned long tPing; void setup(){ const unsigned int SONAR_PERIOD = MCLK_FREQUENCY / TRANSMITTER_FREQ; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; WDTCTL = WDTPW + WDTTMSEL + WDTIS1 + WDTIS0; IE1 |= WDTIE; // setup pwm for ultrasound gen TACCTL1 |= OUTMOD_7; TACCR0 = SONAR_PERIOD; TACCR1 = SONAR_PERIOD / 2; TACCTL0 |= CCIE; TACTL |= TASSEL_2; P1DIR |= PIN_TRANSMITTER; P1SEL |= PIN_TRANSMITTER; // setup adc to capture echo ADC10CTL1 |= ADC10SSEL_3 + INCH_4; ADC10CTL0 |= ADC10ON + ENC + ADC10SHT_0; // setup USI USICTL0 |= USIPE6 + USIPE5 + USIMST + USIOE; // Port, SPI master // USICTL1 |= USIIE; // Counter interrupt, flag remains set USICKCTL = USIDIV_7 + USISSEL_2; // SMCLK/128 for 125000 baud @ SMCLK 16MHz USICTL0 &= ~USISWRST; // USI released for operation USICNT |= USI16B; // shift out 16-bits _BIS_SR(GIE); } //void delayMillis(unsigned long milliseconds){ // // todo: add rollover handling // unsigned long wakeTime = wdtCounter + (milliseconds * WDT_FREQUENCY / 1000); // while(wdtCounter < wakeTime); //} unsigned long locatePeak(unsigned long startTime, unsigned long endTime){ unsigned long peakTime = 0; unsigned long conversionTime; unsigned int peakValue = 0; unsigned int analogValue; while(wdtCounter < startTime); while(wdtCounter < endTime){ ADC10CTL0 |= ADC10SC; conversionTime = wdtCounter; while(ADC10CTL1 & ADC10BUSY); analogValue = ADC10MEM; if(analogValue > peakValue){ peakValue = analogValue; peakTime = conversionTime; } } return peakTime; } float wdtTicksToInches(unsigned int ticks){ return ((ticks / WDT_TICKS_PER_IN) / 2);// + 0.5; } float inchesToWdtTicks(float inches){ return(inches * WDT_TICKS_PER_IN * 2); } float getDistance(unsigned long minimumWdtTicks, unsigned long maximumWdtTicks){ unsigned long tStrongestEcho; sendPing(); while(TACTL & MC_1); // wait for ping transmit completion tStrongestEcho = locatePeak(minimumWdtTicks + tPing, maximumWdtTicks + tPing); return wdtTicksToInches(tStrongestEcho - tPing); } void TX_Data(unsigned int data){ while(USICNT & 0x1F); // wait for previous TX completion USISR = data; USICNT += 16; } void main(){ char iPing; float averageDistance; unsigned int distance; unsigned int minimumWdtTicks; unsigned int maximumWdtTicks; setup(); minimumWdtTicks = inchesToWdtTicks(MINIMUM_DISTANCE_IN); maximumWdtTicks = inchesToWdtTicks(MAXIMUM_DISTANCE_IN); while(1){ if(PINGS_AVERAGED > 1){ averageDistance = 0; for(iPing = 0; iPing < PINGS_AVERAGED; iPing++) averageDistance += (getDistance(minimumWdtTicks, maximumWdtTicks) / PINGS_AVERAGED); distance = averageDistance + 0.5; } else distance = getDistance(minimumWdtTicks, maximumWdtTicks) + 0.5; TX_Data(distance); } } #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A0 (void){ if(iTransducerCycle < nTransducerCycles) iTransducerCycle++; else{ tPing = wdtCounter; stopTransducer(); iTransducerCycle = 0; } } #pragma vector=WDT_VECTOR __interrupt void watchdog_timer(void){ wdtCounter++; }
-
NatureTM reacted to bluehash in Free STM32F4 discovery kit in US/Canada
STM32F4 discovery kit giveaway
-
NatureTM got a reaction from PentiumPC in Flashing the missing DCO calibration constants
EDIT: Here's another really nice DCO calibration program. It's part of TinyOS-msp430. http://code.google.com/p/tinyos-msp430/ It's the file called calibrate-dco. As gordon, who discovered it said, "[it] appears to be a quite beefed-up DCO calibration app, with goodies on the side (taking silicon errata into account for various devices when calibrating)." It looks like it's built to be solid and reliable. I skimmed over the code and didn't see anything for calculating SegA checksum, but that usually isn't an issue for most non-critical applications.
EDIT: maxpenna shared another version of the DCO calibration program. This is the one to use if you need a correct SegmentA checksum. It uses the C calibration function. You can get it here http://www.43oh.com/forum/download/file.php?id=292
WARNING: Some of the programs in this thread will erase Segment A and only put back the DCO calibrations. They should not be used with chips that have an ADC12, as this process will destroy the ADC12 calibrations. Some of the programs do not calculate the Segment A checksum, so the integrity of Segment A cannot be verified during runtime after calibration. Still, I've been using it without any problems.
There's been a bit of a discussion in another thread about an idea simpleavr had for adding the dco calibration constants to flash for the Value Line series. I've cobbled together some pieces of TI code and have it working. It seems to work great. Here's how I did it with CCS. I think the people on linux should be able to reproduce the result with a little adaptation.
This requires the TI DCO library I modified in another thread and an external LF crystal like the one with Launchpad.
http://naturetm.com/files/Launchpad%20setDCO%20lib.rar
First, run this to calibrate the constants and write them to flash:
EDIT: 43oh member zeke has made some changes to the code for finer tuning. Check page 2 for his code.
//****************************************************************************** // MSP430F20xx Demo - DCO Calibration Constants Programmer // // NOTE: THIS CODE REPLACES THE TI FACTORY-PROGRAMMED DCO CALIBRATION // CONSTANTS LOCATED IN INFOA WITH NEW VALUES. USE ONLY IF THE ORIGINAL // CONSTANTS ACCIDENTALLY GOT CORRUPTED OR ERASED. // // Description: This code re-programs the F2xx DCO calibration constants. // A software FLL mechanism is used to set the DCO based on an external // 32kHz reference clock. After each calibration, the values from the // clock system are read out and stored in a temporary variable. The final // frequency the DCO is set to is 1MHz, and this frequency is also used // during Flash programming of the constants. The program end is indicated // by the blinking LED. // ACLK = LFXT1/8 = 32768/8, MCLK = SMCLK = target DCO // //* External watch crystal installed on XIN XOUT is required for ACLK *// // // MSP430F20xx // --------------- // /|\| XIN|- // | | | 32kHz // --|RST XOUT|- // | | // | P1.0|--> LED // | P1.4|--> SMLCK = target DCO // // A. Dannenberg // Texas Instruments Inc. // May 2007 // Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.42A //****************************************************************************** #include "msp430x20x1.h" #include "DCO_Library.h" unsigned char CAL_DATA[8]; // Temp. storage for constants volatile unsigned int i; int j; char *Flash_ptrA; // Segment A pointer void Set_DCO(unsigned int setting); void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT for (i = 0; i < 0xfffe; i++); // Delay for XTAL stabilization P1OUT = 0x01; // Red LED on P1SEL = 0x10; // P1.4 SMCLK output P1DIR = 0x51; // P1.0,4,6 output j = 0; // Reset pointer Set_DCO(TI_DCO_16MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_12MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_8MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Set_DCO(TI_DCO_1MHZ); // Set DCO and obtain constants CAL_DATA[j++] = DCOCTL; CAL_DATA[j++] = BCSCTL1; Flash_ptrA = (char *)0x10C0; // Point to beginning of seg A FCTL2 = FWKEY + FSSEL0 + FN1; // MCLK/3 for Flash Timing Generator FCTL1 = FWKEY + ERASE; // Set Erase bit FCTL3 = FWKEY + LOCKA; // Clear LOCK & LOCKA bits *Flash_ptrA = 0x00; // Dummy write to erase Flash seg A FCTL1 = FWKEY + WRT; // Set WRT bit for write operation Flash_ptrA = (char *)0x10F8; // Point to beginning of cal consts for (j = 0; j < 8; j++) *Flash_ptrA++ = CAL_DATA[j]; // re-flash DCO calibration data FCTL1 = FWKEY; // Clear WRT bit FCTL3 = FWKEY + LOCKA + LOCK; // Set LOCK & LOCKA bit P1OUT = 0; while (1) { P1OUT ^= BIT6; // Toggle green LED for (i = 0; i < 0x4000; i++); // SW Delay } } void Set_DCO(unsigned int setting){ volatile unsigned int I; // P1DIR |= BIT0; // P1.0 output BCSCTL1 &= ~XTS; // external source is LF; BCSCTL3 &= ~(LFXT1S0 + LFXT1S1); // watch crystal mode BCSCTL3 |= XCAP0 + XCAP1; // ~12.5 pf cap on the watch crystal as recommended for( I = 0; I < 0xFFFF; I++){} // delay for ACLK startup if(TI_SetDCO(setting) == TI_DCO_NO_ERROR) // if setting the clock was successful, P1OUT |= BIT0; // bring P1.0 high (Launchpad red LED) else while(1); // trap if setting the clock isn't successful }
The green light should start blinking in a few seconds, indicating success. Now we need to modify some linker and header files so CCS knows about the new calibrations.
I'm using the MSP430G2231, so I duplicated the file C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.cmd in that directory, and renamed the duplicate as msp430g2231_mod.cmd. Now I can edit it without affecting the original. Edit msp430g2231_mod.cmd and change the calibration section at the bottom to this:
/************************************************************ * Calibration Data in Info Mem ************************************************************/ CALDCO_16MHZ = 0x10F8; CALBC1_16MHZ = 0x10F9; CALDCO_12MHZ = 0x10FA; CALBC1_12MHZ = 0x10FB; CALDCO_8MHZ = 0x10FC; CALBC1_8MHZ = 0x10FD; CALDCO_1MHZ = 0x10FE; CALBC1_1MHZ = 0x10FF;
Now the linker knows we have calibration data in that section when we use the modified file.
When we create a new project in CCS or modify an existing one, CCS will want to use the default linking file, and the default header. Here's an example about how to configure a project to use the new constants.
First create a new project. Within the project, there should be a file called something like lnk_msp430g2231.cmd. The last line of that file should be something like -l msp430g2231.cmd. Open it, and change the last line to reflect the new linker file so it reads -l msp430g2231_mod.cmd.
Next, add the appropriate header file to the project. Right-click the project folder in the left pane of CCS and click "Add files to project..." In this example, I'm using C:\Program Files (x86)\Texas Instruments\ccsv4\msp430\include\msp430g2231.h. Now we have a copy of the file in the project we can safely edit. Edit the file so the calibration section looks like this:
/************************************************************ * Calibration Data in Info Mem ************************************************************/ #ifndef __DisableCalData SFR_8BIT(CALDCO_16MHZ); /* DCOCTL Calibration Data for 16MHz */ SFR_8BIT(CALBC1_16MHZ); /* BCSCTL1 Calibration Data for 16MHz */ SFR_8BIT(CALDCO_12MHZ); /* DCOCTL Calibration Data for 12MHz */ SFR_8BIT(CALBC1_12MHZ); /* BCSCTL1 Calibration Data for 12MHz */ SFR_8BIT(CALDCO_8MHZ); /* DCOCTL Calibration Data for 8MHz */ SFR_8BIT(CALBC1_8MHZ); /* BCSCTL1 Calibration Data for 8MHz */ SFR_8BIT(CALDCO_1MHZ); /* DCOCTL Calibration Data for 1MHz */ SFR_8BIT(CALBC1_1MHZ); /* BCSCTL1 Calibration Data for 1MHz */ #endif /* #ifndef __DisableCalData */
Now you can begin using the new calibration data in your program. When you #include the msp430g2231.h file, put it in quotes instead of <> to ensure it's loading the modified header local to the project directory.
I tested the constants with a cheap oscilloscope and they seemed correct. My scope doesn't have great accuracy at high frequencies so they might be a little off, but nothing I can detect. It works with my composite video prog, so that's a pretty good sign.
EDIT: Oops! I had an incorrectly named file in these instructions. Corrected.
-
NatureTM got a reaction from dangpzanco in Generating random numbers.
I was looking for example code for RF2500 last night and came across some TI code for using the ADC as a random number generator. The function was in assembly, so I rewrote it in C:
bool getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM & 0x01; }
Pin 1.5 is floating unconnected, and is measured by the adc. The LSB is used as the random bit. There's a twist though. Pin 1.4 is also floating unconnected, and is used as Vref+, so the top end of the range is floating as well. I thought that was pretty clever. Nice, TI!
I wrote a few console programs to help me visualize the randomness. It turned out the generator was biased toward producing 0's. This function used with the previous function seemed to remove the bias:
bool get0BiasRandomBit(){ if(getRandomBit()){ if(getRandomBit()) return 0; else return 1; } else{ if(getRandomBit()) return 1; else return 0; } }
To test for bias, I displayed a meandering line in a serial console. If I get more 0's than 1's, the line should slowly skew to the left or right:
#include "msp430g2231.h" #include "config.h" #include "softserial.h" #include #define CONSOLE_WIDTH 80 bool getRandomBit(); bool get0BiasRandomBit(); void main(){ int linePositon = CONSOLE_WIDTH / 2; char cursorPosition; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; WDTCTL = WDTPW + WDTHOLD; // Stop WDT SoftSerial_init(); _enable_interrupts(); while(1){ for(cursorPosition = 0; cursorPosition < linePositon; cursorPosition++) SoftSerial_xmit('8'); SoftSerial_xmit(' '); cursorPosition++; while(cursorPosition < CONSOLE_WIDTH){ SoftSerial_xmit('8'); cursorPosition++; } if(get0BiasRandomBit()) linePositon++; else linePositon--; if(linePositon < 0) linePositon = CONSOLE_WIDTH + linePositon; else if(linePositon >= CONSOLE_WIDTH - 1) linePositon = linePositon - CONSOLE_WIDTH; } } bool get0BiasRandomBit(){ if(getRandomBit()){ if(getRandomBit()) return 0; else return 1; } else{ if(getRandomBit()) return 1; else return 0; } } bool getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM & 0x01; }
and some example output from this code:
This sends a comma-separated list of random ints to the console:
#include "msp430g2231.h" #include "config.h" #include "softserial.h" #include #include int adcGenRand16(); void reverse(char s[]); void itoa(int n, char s[]); void txString(char string[]); bool getRandomBit(); bool get0BiasRandomBit(); void main(){ int random; char string[7]; DCOCTL = CALDCO_16MHZ; BCSCTL1 = CALBC1_16MHZ; WDTCTL = WDTPW + WDTHOLD; // Stop WDT SoftSerial_init(); _enable_interrupts(); while(1){ random = adcGenRand16(); itoa(random, string); txString(string); } } void txString(char string[]){ int iString = 0; while(string[iString] != 0){ SoftSerial_xmit(string[iString]); iString++; } SoftSerial_xmit(','); SoftSerial_xmit(' '); } bool get0BiasRandomBit(){ if(getRandomBit()){ if(getRandomBit()) return 0; else return 1; } else{ if(getRandomBit()) return 1; else return 0; } } bool getRandomBit(){ ADC10CTL1 |= INCH_5; ADC10CTL0 |= SREF_1 + ADC10SHT_1 + REFON + ADC10ON; ADC10CTL0 |= ENC + ADC10SC; while(ADC10CTL1 & ADC10BUSY); return ADC10MEM & 0x01; } int adcGenRand16(){ char bit; unsigned int random; for(bit = 0; bit < 16; bit++){ random <<= 1; random |= get0BiasRandomBit(); } return random; } /* itoa: convert n to characters in s */ void itoa(int n, char s[]) { int i, sign; if ((sign = n) < 0) /* record sign */ n = -n; /* make n positive */ i = 0; do { /* generate digits in reverse order */ s[i++] = n % 10 + '0'; /* get next digit */ } while ((n /= 10) > 0); /* delete it */ if (sign < 0) s[i++] = '-'; s[i] = '\0'; reverse(s); } /* reverse: reverse string s in place */ void reverse(char s[]) { int i, j; char c; for (i = 0, j = strlen(s)-1; i c = s[i]; s[i] = s[j]; s[j] = c; } }
I guess I got a little sidetracked from my original purpose of getting started with the RF2500, but I had fun.
-
NatureTM got a reaction from frozencarbonite in TA0.0
If you look at the "application information" section of that datasheet, it shows what pins are connected to the timer A hardware. You're looking for TA0.1 (Timer A0, CCR1) under the "function" column. You'll see your only options are P1.2 and P1.6. I usually try to build my design around the hardware, but if that's not an option, you could use interrupts and software to make it work. It would be a matter of toggling the pin appropriately during the CCR0 and CCR1 ISR's.
To use P1.6, change the instances of BIT2 to BIT6 like you did, but use P1.6, not P1.5. If you really want to use P1.5, this might be a good chance to (re)familiarize yourself with interrupts.
-
NatureTM reacted to oPossum in 256 x 192 graphics display using Fraunchpad - preview
A frame buffer for 256x192 pixels requires 6k. That is more than will fit in RAM, so the frame buffer is in the FRAM memory. NTSC video generated using TimerA0 for sync, and SPI with DMA for video.
Graphics library functions:
[*:hf56qo2f]Pixel
[*:hf56qo2f]Line
[*:hf56qo2f]Box
[*:hf56qo2f]Circle
[*:hf56qo2f]Ellipse
[*:hf56qo2f]Quadratic and cubic bezier curve
[*:hf56qo2f]BitBlt up to 24 pixels wide
[*:hf56qo2f]OR, AND, and XOR drawing modes
[*:hf56qo2f]Text with 8 x 12 font
-
NatureTM reacted to oPossum in 32 x 16 text display on TV using Fraunchpad - preview
MIDI data is decoded and displayed. Video output of Fraunchpad is lower right (picture-in-picture), lower left is MIDI data being sent to serial port, top is MIDI player.
Still have work to do on the code, so not posting it yet. The MIDI decode is in hex because I haven't written the itoa() functions yet.
http://www.youtube.com/watch?v=M3jINBajWqI
-
NatureTM reacted to oPossum in Launchpad video oscilloscope
15.7 ksps WOW!
16.6 ms sweep Amazing!
Special limited time offer - only $4.30!
Order now. Operators are standing by.
.cdecls C, LIST, "msp430g2231.h" .text .global _main .bss sync_state, 2 .bss sync_lines, 2 .bss video_state, 2 .bss vid_line, 2 _main ; mov #WDTPW | WDTHOLD, &WDTCTL ; No watchdog ; mov #XT2OFF + 15, &BCSCTL1 ; DCO 16 Mhz mov #0x86, &DCOCTL ; ; mov #0x0280, SP ; Stack pointer ; mov.b #0xF0, &P1DIR ; I/O assignment mov.b #0x50, &P1SEL ; Enable Timer A output, SMCLK output clr.b &P1REN ; clr.b &P1OUT ; ; mov #0x0002, &ADC10AE0 ; Analog in on P1.1 (A1) mov #0x1000, &ADC10CTL1 ; Select A1 ; Configure ADC mov #ADC10SHT_0 | ADC10SR | ADC10ON | ENC, &ADC10CTL0 ; call #video_init ; Begin video ; jmp $ ; ; video_init ; --- Initialize Video Generation --- clr &sync_state ; Init state machine mov #1, sync_lines ; clr &video_state ; mov #1016, &TACCR0 ; Setup Timer A period for 63.5 us mov #75, &TACCR1 ; Setup Timer A compare for video sync mov #0x0210, &TACTL ; Timer A config: SMCLK, count up mov #0x0060, &TACCTL1 ; Setup Timer A set/reset output mode bis #0x0010, &TACCTL0 ; Enable PWM interupt eint ; Enable interupts ret ; ; video_isr ; --- Video ISR --- dec &sync_lines ; Decrement sync lines jne vid_state ; Skip sync if not zero... add &sync_state, PC ; Jump to sync handler... ; - Field 1/3 jmp vid_eq ; Pre Equalizing jmp vid_vsync ; Vertical Sync jmp vid_eq ; Post Equalizing jmp vid_vbi ; VBI jmp vid_active ; Active Video jmp vid_half ; Video half line ; - Field 2/4 jmp vid_eq ; Pre Equalizing jmp vid_vsync ; Vertical Sync jmp vid_eq ; Post Equalizing jmp vid_half ; Video half line jmp vid_vbi ; VBI jmp vid_active ; Active Video clr &sync_state ; Reset sync state ;jmp vid_eq ; Same as first state ; vid_eq ; Equalizing pulses - 6 half lines mov #508, &TACCR0 ; Half line mov #38, &TACCR1 ; Equalizing pulse duration mov #6, &sync_lines ; 6 half lines clr &video_state ; No video generation during sync incd &sync_state ; Next state reti ; ; vid_vsync ; Vertical sync - 6 half lines mov #508 - 75, &TACCR1 ; Sync pulse duration mov #6, &sync_lines ; 6 half lines incd &sync_state ; Next state reti ; ; vid_half ; Video half line - 1 half line mov #508, &TACCR0 ; Half line mov #75, &TACCR1 ; Sync pulse duration mov #1, &sync_lines ; 1 half line incd &sync_state ; Next state clr &video_state ; No video generation during half line and sync reti ; ; vid_vbi ; Vertical blanking interval - 11 lines mov #1016, &TACCR0 ; Full line mov #75, &TACCR1 ; Sync pulse duration mov #11, &sync_lines ; 11 lines incd &sync_state ; Next state reti ; ; vid_active ; Active video - 242 lines mov #242, &sync_lines ; 242 lines incd &sync_state ; Next state mov #2, &video_state ; Generate video clr &vid_line ; Clear video line count jmp vid_field ; Generate video... ; vid_blank_9 ; 9 blank lines mov #9, &sync_lines ; incd &sync_state ; clr &video_state ; reti ; ; vid_state ; -- Active Video Generation add &video_state, PC ; reti ; No active video ;jmp vid_field ; Field ; vid_field ; push R12 ; ; mov &TAR, R12 ; cmp #160, R12 ; jlo $ - 8 ; and #7, R12 ; rla R12 ; add R12, PC ; nop ; nop ; nop ; nop ; nop ; nop ; nop ; ; mov &ADC10MEM, R12 ; Get ADC results bis #ADC10SC, &ADC10CTL0 ; Start new conversion ; cmp #750, R12 ; Limit upper ADC value jlo inrange ; mov #750 - 2, R12 ; ; inrange sub #4, R12 ; Subtract four w/ four cycles per iteration nop ; jc $ - 4 ; inv R12 ; Negate the remainder rla R12 ; Multiply by two add R12, PC ; One cycle granularity computed jump nop ; nop ; nop ; ; bis.b #0x80, &P1OUT ; bic.b #0x80, &P1OUT ; ; pop R12 ; ; reti ; ; ; Interrupt Vectors .sect ".reset" ; .short _main ; .sect ".int09" ; TACCR0 CCIFG .short video_isr ; ; .end ;
-
NatureTM reacted to oPossum in Fraunchpad poly synth
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_init(void); void set_note(int, int, int); static int assign[16]; void note_on(int n, int v) { int i; for(i = 0; i < 16; ++i) { if(assign[i] == -1) { assign[i] = n; set_note(i, n, v); break; } } } void note_off(int n) { int i; for(i = 0; i < 16; ++i) { if(assign[i] == n) { assign[i] = -1; set_note(i, -1, 0); break; } } } void midi_ex(unsigned a, unsigned b, unsigned c) { ++PJOUT; switch(a & 0xF0) { case 0x90: // Note on if(c) { note_on(b, c); break; } // fall thru case 0x80: // Note off note_off(; break; /* case 0xA0: // Note aftertouch break; case 0xB0: // Controller break; case 0xC0: // Program change break; case 0xD0: // Channel aftertouch break; case 0xE0: // Pitch bend break; case 0xF0: // Sysex / Meta break; */ } } void midi(unsigned c) { static const unsigned ps[8] = { 2, 2, 2, 2, 1, 1, 2, 4 }; static unsigned state = 0; static unsigned rs = 0; static unsigned d1 = 0; if(c & 0x80) { // First octect of sequence rs = c; state = ps[(rs >> 4) & 7]; } else { switch(state) { case 0: // Discard break; case 1: // Second and final octet midi_ex(rs, c, 0); break; case 2: // Second octet of three d1 = c; ++state; break; case 3: // Third and final octet midi_ex(rs, d1, c); state = 2; break; //case 4: // Sysex data // break; } } } void main(void) { unsigned n; WDTCTL = WDTPW + WDTHOLD; CSCTL0 = 0xA500; // Unlock clock registers CSCTL1 = DCORSEL | DCOFSEL1 | DCOFSEL0; // 24 MHz CSCTL2 = 0x0333; // Use DCO clock for ACLK, SMCLK and MCLK CSCTL3 = 0x0000; // Set all clock dividers to 1 //CSCTL4 = //CSCTL5 = P1DIR = 0x01; // PWM audio out P1REN = 0x00; // P1OUT = 0x00; // P1SEL0 = 0x01; // Enable Timer A output P1SEL1 = 0x00; // P2DIR = 0x00; // P2REN = 0x00; // P2OUT = 0x00; // P2SEL0 = 0x00; // P2SEL1 = 0x03; // Enable UART UCA0 P3DIR = 0x10; // P3REN = 0x00; // P3OUT = 0x00; // P3SEL0 = 0x10; // SMCLK output P3SEL1 = 0x10; // SMCLK output P4DIR = 0x00; // P4REN = 0x00; // P4OUT = 0x00; // P4SEL0 = 0x00; // P4SEL1 = 0x00; // PJDIR = 0x0F; // 4 LEDs PJREN = 0x00; // PJOUT = 0x0F; // PJSEL0 = 0x00; // PJSEL1 = 0x00; // UCA0CTLW0 = 0x0080; // UCA0BRW = 24000000 / 9600; // Fraunchpad UART //UCA0BRW = 24000000 / 31250; // Standard MIDI bit rate synth_init(); //set_note(0, 69, 700); // 440 Hz test for(n = 0; n < 16; ++n) assign[n] = -1; for(; { if(UCA0IFG & 1) { UCA0IFG &= ~1; n = UCA0RXBUF; midi(n); } } }
;synth.asm .cdecls C, LIST, "msp430fr5739.h" smplrt .equ 32000 ; Sample rate .text .global set_tick .global get_tick .global synth_init .global set_note .bss tick, 2 .bss pwm_out, 2 .bss phase_inc, 6 * 16 ; Phase increment LSW/MSW (from note table) ; Level .bss phase_acc, 4 * 16 ; Phase accumulator LSW/MSW set_tick mov R12, &tick reta get_tick mov &tick, R12 reta synth_init mov #0x0210, &TA0CTL ; Timer A config: SMCLK, count up mov #750, &TA0CCR0 ; Setup Timer A period for 32000 sps mov #375, &TA0CCR1 ; Setup Timer A compare mov #0x00E0, &TA0CCTL1 ; Setup Timer A reset/set output mode ; mov #phase_inc, R12 ; Clear all phase inc and accum mov #5 * 16, R14 ; Word count clr 0(R12) ; Clear word incd R12 ; Next word dec R14 ; Dec word count jne $ - 8 ; Loop until all words done... ; eint ; Enable interupts bis #0x0010, &TA0CCTL0 ; Enable PWM interupt ; reta ; ; synth_isr ; mov &pwm_out, &TA0CCR1 ; Output sample ; push R4 ; Wavetable pointer push R5 ; Phase increment / level pointer push R6 ; Phase accumulator pointer push R7 ; Voice count push R8 ; Wave sample pointer / next sample push R9 ; Wave sample push R10 ; Voice mix accumulator MSW push R11 ; Voice mix accumulator LSW ; mov #sine, R4 ; Get wavetable pointer mov #phase_inc, R5 ; Setup phase increment pointer mov #phase_acc, R6 ; Setup phase accumulator pointer mov #16, R7 ; Setup voice count mov #9, R7 ; clr R10 ; Clear voice mix clr R11 ; voice_loop ; mov @R6+, &MPYS32L ; Get phase acc LSW (fraction) to multiplier clr &MPYS32H ; mov @R6+, R8 ; Get phase acc MSW (wave table index) mov.b R8, R8 ; Clear MSB (use mask for smaller / larger tables) add R4, R8 ; Add wavetable pointer mov @R8+, R9 ; Get wave sample mov @R8, R8 ; Get next wave sample sub R9, R8 ; Calc delta mov R8, &OP2L ; Multiply by delta subc R8, R8 ; Sign extend delta mov R8, &OP2H ; add @R5+, -4(R6) ; Update phase acc addc @R5+, -2(R6) ; add &RES1, R9 ; Add interpolation to sample mov R9, &MPYS ; Multiply by voice level mov @R5+, &OP2L ; add &RES0, R11 ; Update mix addc &RES1, R10 ; dec R7 ; Dec voice count jne voice_loop ; Next voice... ; add #375, R10 ; Bias to center of PWM range mov R10, &pwm_out ; ; dec &tick ; jc $ + 6 ; clr &tick ; ; pop R11 ; pop R10 ; pop R9 ; pop R8 ; pop R7 ; pop R6 ; pop R5 ; pop R4 ; reti ; ; set_note ; push R14 ; Save level mov R12, R14 ; Voice * 6 add R14, R12 ; (+1 = *2) add R14, R12 ; (+1 = *3) rla R12 ; (*2 = *6) add #phase_inc, R12 ; Add phase inc pointer cmp #128, R13 ; Out of range note values are note off jhs note_off ; clr R14 ; Clear octave count tst_note ; cmp #116, R13 ; Within note table? jge get_pi ; Yes... inc R14 ; Inc octave count add #12, R13 ; Add octave to note jmp tst_note ; Check again... get_pi ; Get phase increment sub #116, R13 ; Adjust for first note in table rla R13 ; MIDI note * 4 rla R13 ; add #notes, R13 ; Add note table pointer mov @R13+, R15 ; Get LSW mov @R13, R13 ; Get MSW tst R14 ; Shifting required? jeq set_phase ; No... shift_phase ; rra R13 ; Shift phase inc rrc R15 ; dec R14 ; Dec octave count jne shift_phase ; Repeat until zero... set_phase ; mov R15, 0(R12) ; Set phase inc mov R13, 2(R12) ; pop 4(R12) ; Set voice level reta ; Return ; note_off ; incd SP ; Discard level clr 0(R12) ; Clear phase inc clr 2(R12) ; .if 0 ; Note: Abrupt return to zero causes poping clr 4(R12) ; Clear level add #phase_acc - phase_inc, R12 ; Phase accum pointer clr 0(R12) ; Clear phase accum clr 2(R12) ; .endif ; reta ; Return ; ; notes ; MIDI Note Frequency .if smplrt == 32000 ; 32000 sps .long 3483828 ; 116 G#8 6644.87457275391 .long 3690988 ; 117 A8 7040.00091552734 .long 3910465 ; 118 A#8 7458.62007141113 .long 4142993 ; 119 B8 7902.13203430176 .long 4389349 ; 120 C9 8372.01881408691 .long 4650353 ; 121 C#9 8869.84443664551 .long 4926877 ; 122 D9 9397.27210998535 .long 5219845 ; 123 D#9 9956.06422424316 .long 5530233 ; 124 E9 10548.0823516846 .long 5859077 ; 125 F9 11175.3025054932 .long 6207476 ; 126 F#9 11839.8208618164 .long 6576592 ; 127 G9 12543.8537597656 .endif ; ; .if smplrt == 48000 ; 48000 sps .long 2322552 ; 116 G#8 6644.87457275391 .long 2460658 ; 117 A8 7039.99900817871 .long 2606977 ; 118 A#8 7458.62102508545 .long 2761996 ; 119 B8 7902.13394165039 .long 2926232 ; 120 C9 8372.01690673828 .long 3100235 ; 121 C#9 8869.84348297119 .long 3284585 ; 122 D9 9397.27306365967 .long 3479896 ; 123 D#9 9956.06231689453 .long 3686822 ; 124 E9 10548.0823516846 .long 3906052 ; 125 F9 11175.3044128418 .long 4138318 ; 126 F#9 11839.8227691650 .long 4384395 ; 127 G9 12543.8547134399 .endif ; sine .int 0 .int 804 .int 1608 .int 2410 .int 3212 .int 4011 .int 4808 .int 5602 .int 6393 .int 7179 .int 7962 .int 8739 .int 9512 .int 10278 .int 11039 .int 11793 .int 12539 .int 13279 .int 14010 .int 14732 .int 15446 .int 16151 .int 16846 .int 17530 .int 18204 .int 18868 .int 19519 .int 20159 .int 20787 .int 21403 .int 22005 .int 22594 .int 23170 .int 23731 .int 24279 .int 24811 .int 25329 .int 25832 .int 26319 .int 26790 .int 27245 .int 27683 .int 28105 .int 28510 .int 28898 .int 29268 .int 29621 .int 29956 .int 30273 .int 30571 .int 30852 .int 31113 .int 31356 .int 31580 .int 31785 .int 31971 .int 32137 .int 32285 .int 32412 .int 32521 .int 32609 .int 32678 .int 32728 .int 32757 .int 32767 .int 32757 .int 32728 .int 32678 .int 32609 .int 32521 .int 32412 .int 32285 .int 32137 .int 31971 .int 31785 .int 31580 .int 31356 .int 31113 .int 30852 .int 30571 .int 30273 .int 29956 .int 29621 .int 29268 .int 28898 .int 28510 .int 28105 .int 27683 .int 27245 .int 26790 .int 26319 .int 25832 .int 25329 .int 24811 .int 24279 .int 23731 .int 23170 .int 22594 .int 22005 .int 21403 .int 20787 .int 20159 .int 19519 .int 18868 .int 18204 .int 17530 .int 16846 .int 16151 .int 15446 .int 14732 .int 14010 .int 13279 .int 12539 .int 11793 .int 11039 .int 10278 .int 9512 .int 8739 .int 7962 .int 7179 .int 6393 .int 5602 .int 4808 .int 4011 .int 3212 .int 2410 .int 1608 .int 804 .int 0 .int -804 .int -1608 .int -2410 .int -3212 .int -4011 .int -4808 .int -5602 .int -6393 .int -7179 .int -7962 .int -8739 .int -9512 .int -10278 .int -11039 .int -11793 .int -12539 .int -13279 .int -14010 .int -14732 .int -15446 .int -16151 .int -16846 .int -17530 .int -18204 .int -18868 .int -19519 .int -20159 .int -20787 .int -21403 .int -22005 .int -22594 .int -23170 .int -23731 .int -24279 .int -24811 .int -25329 .int -25832 .int -26319 .int -26790 .int -27245 .int -27683 .int -28105 .int -28510 .int -28898 .int -29268 .int -29621 .int -29956 .int -30273 .int -30571 .int -30852 .int -31113 .int -31356 .int -31580 .int -31785 .int -31971 .int -32137 .int -32285 .int -32412 .int -32521 .int -32609 .int -32678 .int -32728 .int -32757 .int -32767 .int -32757 .int -32728 .int -32678 .int -32609 .int -32521 .int -32412 .int -32285 .int -32137 .int -31971 .int -31785 .int -31580 .int -31356 .int -31113 .int -30852 .int -30571 .int -30273 .int -29956 .int -29621 .int -29268 .int -28898 .int -28510 .int -28105 .int -27683 .int -27245 .int -26790 .int -26319 .int -25832 .int -25329 .int -24811 .int -24279 .int -23731 .int -23170 .int -22594 .int -22005 .int -21403 .int -20787 .int -20159 .int -19519 .int -18868 .int -18204 .int -17530 .int -16846 .int -16151 .int -15446 .int -14732 .int -14010 .int -13279 .int -12539 .int -11793 .int -11039 .int -10278 .int -9512 .int -8739 .int -7962 .int -7179 .int -6393 .int -5602 .int -4808 .int -4011 .int -3212 .int -2410 .int -1608 .int -804 .int 0 ; Interrupt Vectors .sect ".int53" ; TA0CCR0 CCIFG0 .short synth_isr ; ; .end ;
-
NatureTM reacted to RobG in MIDI Light controller
Here's my first light show.
Sorry to disappoint you guys, but a) I do not own any Star Wars media, I am so busy at work and with the kids I hardly have any time for my hobbies.
I know "It's No Good" but it is what it is
-
NatureTM reacted to oPossum in 12 voice polyphonic wavetable synth with G2211
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/MSW .else .bss phase_inc, 2 * 12 ; Phase increment (from note table) .bss phase_acc, 2 * 12 ; Phase accumulator .endif set_tick mov R12, &tick ret get_tick mov &tick, R12 ret synth_init mov #0x0210, &TACTL ; Timer A config: SMCLK, count up ;mov #511, &TACCR0 ; Setup Timer A period for 31250 sps mov #415, &TACCR0 ; Setup Timer A period for 38400 sps mov #256, &TACCR1 ; Setup Timer A compare mov #0x00E0, &TACCTL1 ; Setup Timer A reset/set output mode ; mov #phase_inc, R12 ; Clear all phase inc and accum .if ph32 ; mov #4 * 12, R14 ; Word count .else ; mov #2 * 12, R14 ; Word count .endif ; clr 0(R12) ; Clear word incd R12 ; Next word dec R14 ; Dec word count jne $ - 8 ; Loop until all words done... ; eint ; Enable interupts bis #0x0010, &TACCTL1 ; Enable PWM interupt ret synth_isr push R4 push R5 push R6 push R7 push R8 push R9 mov #sine, R4 ; Get wavetable pointer mov #phase_inc, R5 ; Setup phase increment pointer .if ph32 ; mov #phase_acc + 2, R6 ; Setup phase accumulator pointer .else ; mov #phase_acc, R6 ; Setup phase accumulator pointer .endif ; clr R7 ; Clear sample accumulator mov #12, R8 ; Setup voice count voice_loop ; mov @R6, R9 ; Get phase acc (MSW) swpb R9 ; Swap MSB/LSB mov.b R9, R9 ; Clear MSB add R4, R9 ; Add wavetable pointer mov.b @R9, R9 ; Get wave sample add R9, R7 ; Update sample .if ph32 ; add @R5+, -2(R6) ; Update phase acc addc @R5+, 0(R6) ; add #4, R6 ; Increment phase acc pointer .else ; add @R5+, 0(R6) ; Update phase acc incd R6 ; Increment phase acc pointer .endif ; dec R8 ; Dec voice count jne voice_loop ; Next voice... ; rra R7 ; rra R7 ; rra R7 ; add #16, R7 ; mov R7, &TACCR1 ; Output sample ; dec &tick ; jc $ + 6 ; clr &tick ; ; bic #0x01, &TACCTL1 ; ; pop R9 pop R8 pop R7 pop R6 pop R5 pop R4 reti set_note clr R14 ; Clear octave count cmp #128, R12 ; jhs note_off ; tst_note ; cmp #116, R12 ; Within note table? jge get_pi ; Yes... inc R14 ; Inc octave count add #12, R12 ; Add octave to note jmp tst_note ; Check again... get_pi ; Get phase increment sub #116, R12 ; Adjust for first note in table rla R12 ; MIDI note * 2 .if ph32 ; rla R12 ; MIDI note * 2 (* 4 total) add #notes, R12 ; Add note table pointer mov @R12+, R15 ; Get LSW .else ; add #notes, R12 ; Add note table pointer .endif ; mov @R12, R12 ; Get MSW tst R14 ; Shifting required? jeq set_phase ; No... shift_phase ; rra R12 ; Shift phase inc .if ph32 ; rrc R15 ; .endif ; dec R14 ; Dec octave count jne shift_phase ; Repeat until zero... set_phase ; rla R13 ; Voice * 2 .if ph32 ; rla R13 ; Voice * 2 (* 4 total) add #phase_inc, R13 ; Add phase inc pointer mov R15, 0(R13) ; Set phase inc mov R12, 2(R13) ; .else ; add #phase_inc, R13 ; Add phase inc pointer mov R12, 0(R13) ; Set phase inc .endif ; ret ; Return ; note_off ; rla R13 ; Voice * 2 .if ph32 ; rla R13 ; Voice * 2 (* 4 total) .endif ; mov R13, R12 ; Copy add #phase_inc, R12 ; Phase inc pointer add #phase_acc, R13 ; Phase accum pointer clr 0(R12) ; Clear phase inc clr 0(R13) ; Clear phase accum .if ph32 ; clr 2(R12) ; clr 2(R13) ; .endif ; ret ; Return ; ; notes ; MIDI Note Frequency .if smplrt == 31250 ; 31250 sps .if ph32 ; .long 913264688 ; 116 G#8 6644.875 .long 967570232 ; 117 A8 7040.000 .long 1025104952 ; 118 A#8 7458.620 .long 1086060865 ; 119 B8 7902.133 .long 1150641405 ; 120 C9 8372.018 .long 1219062103 ; 121 C#9 8869.844 .long 1291551308 ; 122 D9 9397.273 .long 1368350945 ; 123 D#9 9956.063 .long 1449717327 ; 124 E9 10548.082 .long 1535922005 ; 125 F9 11175.303 .long 1627252680 ; 126 F#9 11839.822 .long 1724014160 ; 127 G9 12543.854 .else ; .word 13935 ; 116 G#8 6644.726 .word 14764 ; 117 A8 7040.024 .word 15642 ; 118 A#8 7458.687 .word 16572 ; 119 B8 7902.145 .word 17557 ; 120 C9 8371.830 .word 18601 ; 121 C#9 8869.648 .word 19708 ; 122 D9 9397.507 .word 20879 ; 123 D#9 9955.883 .word 22121 ; 124 E9 10548.115 .word 23436 ; 125 F9 11175.156 .word 24830 ; 126 F#9 11839.867 .word 26306 ; 127 G9 12543.678 .endif ; .endif ; ; .if smplrt == 38400 ; 38400 sps .if ph32 ; .word 743216706 ; 116 G#8 6644.875 .word 787410671 ; 117 A8 7040.000 .word 834232546 ; 118 A#8 7458.620 .word 883838595 ; 119 B8 7902.133 .word 936394372 ; 120 C9 8372.018 .word 992075279 ; 121 C#9 8869.844 .word 1051067145 ; 122 D9 9397.273 .word 1113566850 ; 123 D#9 9956.063 .word 1179782981 ; 124 E9 10548.082 .word 1249936527 ; 125 F9 11175.303 .word 1324261621 ; 126 F#9 11839.822 .word 1403006315 ; 127 G9 12543.854 .else ; .word 11341 ; 116 G#8 6645.117 .word 12015 ; 117 A8 7040.039 .word 12729 ; 118 A#8 7458.398 .word 13486 ; 119 B8 7901.953 .word 14288 ; 120 C9 8371.875 .word 15138 ; 121 C#9 8869.922 .word 16038 ; 122 D9 9397.266 .word 16992 ; 123 D#9 9956.250 .word 18002 ; 124 E9 10548.047 .word 19073 ; 125 F9 11175.586 .word 20207 ; 126 F#9 11840.039 .word 21408 ; 127 G9 12543.750 .endif ; .endif ; sine .byte 128 .byte 131 .byte 134 .byte 137 .byte 140 .byte 144 .byte 147 .byte 150 .byte 153 .byte 156 .byte 159 .byte 162 .byte 165 .byte 168 .byte 171 .byte 174 .byte 177 .byte 179 .byte 182 .byte 185 .byte 188 .byte 191 .byte 193 .byte 196 .byte 199 .byte 201 .byte 204 .byte 206 .byte 209 .byte 211 .byte 213 .byte 216 .byte 218 .byte 220 .byte 222 .byte 224 .byte 226 .byte 228 .byte 230 .byte 232 .byte 234 .byte 235 .byte 237 .byte 239 .byte 240 .byte 241 .byte 243 .byte 244 .byte 245 .byte 246 .byte 248 .byte 249 .byte 250 .byte 250 .byte 251 .byte 252 .byte 253 .byte 253 .byte 254 .byte 254 .byte 254 .byte 255 .byte 255 .byte 255 .byte 255 .byte 255 .byte 255 .byte 255 .byte 254 .byte 254 .byte 254 .byte 253 .byte 253 .byte 252 .byte 251 .byte 250 .byte 250 .byte 249 .byte 248 .byte 246 .byte 245 .byte 244 .byte 243 .byte 241 .byte 240 .byte 239 .byte 237 .byte 235 .byte 234 .byte 232 .byte 230 .byte 228 .byte 226 .byte 224 .byte 222 .byte 220 .byte 218 .byte 216 .byte 213 .byte 211 .byte 209 .byte 206 .byte 204 .byte 201 .byte 199 .byte 196 .byte 193 .byte 191 .byte 188 .byte 185 .byte 182 .byte 179 .byte 177 .byte 174 .byte 171 .byte 168 .byte 165 .byte 162 .byte 159 .byte 156 .byte 153 .byte 150 .byte 147 .byte 144 .byte 140 .byte 137 .byte 134 .byte 131 .byte 128 .byte 125 .byte 122 .byte 119 .byte 116 .byte 112 .byte 109 .byte 106 .byte 103 .byte 100 .byte 97 .byte 94 .byte 91 .byte 88 .byte 85 .byte 82 .byte 79 .byte 77 .byte 74 .byte 71 .byte 68 .byte 65 .byte 63 .byte 60 .byte 57 .byte 55 .byte 52 .byte 50 .byte 47 .byte 45 .byte 43 .byte 40 .byte 38 .byte 36 .byte 34 .byte 32 .byte 30 .byte 28 .byte 26 .byte 24 .byte 22 .byte 21 .byte 19 .byte 17 .byte 16 .byte 15 .byte 13 .byte 12 .byte 11 .byte 10 .byte 8 .byte 7 .byte 6 .byte 6 .byte 5 .byte 4 .byte 3 .byte 3 .byte 2 .byte 2 .byte 2 .byte 1 .byte 1 .byte 1 .byte 1 .byte 1 .byte 1 .byte 1 .byte 2 .byte 2 .byte 2 .byte 3 .byte 3 .byte 4 .byte 5 .byte 6 .byte 6 .byte 7 .byte 8 .byte 10 .byte 11 .byte 12 .byte 13 .byte 15 .byte 16 .byte 17 .byte 19 .byte 21 .byte 22 .byte 24 .byte 26 .byte 28 .byte 30 .byte 32 .byte 34 .byte 36 .byte 38 .byte 40 .byte 43 .byte 45 .byte 47 .byte 50 .byte 52 .byte 55 .byte 57 .byte 60 .byte 63 .byte 65 .byte 68 .byte 71 .byte 74 .byte 77 .byte 79 .byte 82 .byte 85 .byte 88 .byte 91 .byte 94 .byte 97 .byte 100 .byte 103 .byte 106 .byte 109 .byte 112 .byte 116 .byte 119 .byte 122 .byte 125 ; Interrupt Vectors .sect ".int08" ; TACCR1 CCIFG, TAIFG .short synth_isr ; ; .end ;
Some code to test it...
// main.c #include "msp430g2211.h" void set_tick(unsigned); unsigned get_tick(void); void synth_init(); void set_note(int, unsigned); void main(void) { unsigned n; WDTCTL = WDTPW + WDTHOLD; BCSCTL1 = XT2OFF + 15; P1DIR = 0xF2; // I/O assignment P1REN = 0x0D; // Pull up resistor for switch and Rxd P1OUT = 0x0F; // Pull up, serial idle high P1SEL = 0x50; // Enable Timer A output, SMCLK output synth_init(); #if 0 set_note(33, 0); // A1 55 Hz set_note(45, 1); // A2 110 Hz set_note(57, 2); // A3 220 Hz set_note(69, 3); // A4 440 Hz set_note(81, 4); // A5 880 Hz set_note(93, 5); // A6 1760 Hz set_note(105, 6); // A7 3520 Hz set_note(117, 7); // A8 7040 Hz #endif #if 0 set_note(69, 0); // A4 440 Hz set_note(70, 1); // set_note(71, 2); // set_note(72, 3); // set_note(73, 4); // set_note(74, 5); // set_note(75, 6); // set_note(76, 7); // set_note(77, 8); // set_note(78, 9); // set_note(79, 10); // set_note(80, 11); // #endif #if 1 n = 57; for(; { set_note(0x7F & n++, 0); set_tick(5000); while(get_tick()); set_note(-1, 0); set_tick(1000); while(get_tick()); } #endif for(;; }
Working on MIDI support so it can play music.
-
NatureTM got a reaction from gatesphere in Need Cooking Help !
Maybe you shouldn't lie to your friends.
Try combining different types of meat. Wrap everything in bacon. Deep fry in oil whenever possible, especially with twinkies and oreos. The goal is to make everything as unhealthy as possible. When making burgers, substitute doughnuts for buns, a very popular dish. Frozen pizza is also very popular. Buy an extra bag of shredded cheese and add that to the frozen pizza. The trick is to cook the pizza half-way and then add the cheese. The secret to flavor is calories. I'm serious about that!
You're welcome.
-
NatureTM reacted to bluehash in FRAM Experimenter's Board coupon code 50% off
Just got this email from our TI representative:
(Thanks TI!)
-
NatureTM got a reaction from xpg in FPGA Larson Scanner
Well, this isn't exactly a microcontroller, but close enough. I had the day off of work today due to rain, so I decided to make my first FPGA project, a Larson Scanner/Cylon Eye/Kitt Light. I was surprised I actually got this working in only a morning worth of work. (Decrement FPGA scariness.)
Code and stuff on http://naturetm.com/?p=197.
-
NatureTM got a reaction from jsolarski in FPGA Larson Scanner
Well, this isn't exactly a microcontroller, but close enough. I had the day off of work today due to rain, so I decided to make my first FPGA project, a Larson Scanner/Cylon Eye/Kitt Light. I was surprised I actually got this working in only a morning worth of work. (Decrement FPGA scariness.)
Code and stuff on http://naturetm.com/?p=197.
-
NatureTM got a reaction from bluehash in FPGA Larson Scanner
Well, this isn't exactly a microcontroller, but close enough. I had the day off of work today due to rain, so I decided to make my first FPGA project, a Larson Scanner/Cylon Eye/Kitt Light. I was surprised I actually got this working in only a morning worth of work. (Decrement FPGA scariness.)
Code and stuff on http://naturetm.com/?p=197.
-
NatureTM got a reaction from zeke in FPGA Larson Scanner
Well, this isn't exactly a microcontroller, but close enough. I had the day off of work today due to rain, so I decided to make my first FPGA project, a Larson Scanner/Cylon Eye/Kitt Light. I was surprised I actually got this working in only a morning worth of work. (Decrement FPGA scariness.)
Code and stuff on http://naturetm.com/?p=197.