/* Daya Bay gas system digital bubbler readout Based on EMP1 Rocket Lab program toss the original Rocket Lab code was written by Vassilios Papathanakos Department of Physics, Princeton University This new program is created on Feb. 5, 2008, C. Lu Use sequence of channels instead of single-channel method to run the ADC. 3/28/2008 C. Lu So far maximum 8 channels can be readout by this mode, couldn't make 16 channels work in this sequence of channels mode. Therefore readout 16 channrls has to be completed in 2 steps, 8 channels/step. This code has been tested with real bubblers. 3/31/2008 C. Lu Total data points are 250, only record the time mark at beginging of each record line. Wait(100) used between two data points. 9/9/2008 C. Lu Removed the data transfer from RAM to flash memory. 12/1/2008 C. Lu Write data to flash memory immediately, thus to utilize 48kB flash memory. Add flash_writeByte to each data record. 1/10/2009 C. Lu */ #include #include #include #define __FLASH__ #define __HW_v_2_1__ /* START type definitions for convinience with microcontrollers */ typedef unsigned char BYTE; /* 8 bits */ typedef unsigned short WORD; /* 16 bits */ typedef unsigned long LONGWORD; /* 32 bits */ /* for dividing a WORD into two BYTEs */ typedef union _WORD_BYTE { WORD w; BYTE b[2]; } WORD_BYTE; #define FLASH_DATA 0x5000 // Data copy in Flash starts here (0d20480) #define FLASH_COUNT 0xF000 // counter for the iteration # // The following block of code sets up a "structure" // for storing data from the digital bubbler. #pragma bitfields = reversed #pragma pack(8) struct bubbl { // bubbler data storage allocation unsigned int time; unsigned int chan1; unsigned int chan2; unsigned int chan3; unsigned int chan4; unsigned int chan5; unsigned int chan6; unsigned int chan7; unsigned int chan8; unsigned int chan9; unsigned int chan10; unsigned int chan11; unsigned int chan12; unsigned int chan13; unsigned int chan14; unsigned int chan15; unsigned int chan16; /* short time; short chan1; short chan2; short chan3; short chan4; short chan5; short chan6; short chan7; short chan8; short chan9; short chan10; short chan11; short chan12; short chan13; short chan14; short chan15; short chan16; // unsigned int time1; */ }; BYTE *addr_seg, *addr_byte; // #define NDATA 252 // Number of samples stored, was 252 #define BYTES_PER_RECORD 34 // 17 one-word data items; #define NDATA 960 // Total 1000 events plus 2 extra records as start and stop signs. // Seems we don't need this initialization any more struct bubbl *init_data(void) { // Initialize data storage // struct bubbl *data = (struct bubbl *)malloc(NDATA * (size_t) sizeof(struct bubbl)); // Allocate space struct bubbl *data = (struct bubbl *)malloc((size_t) sizeof(struct bubbl)); // Allocate space return data; } // Wait for 6*n+11 cycles void wait(unsigned int n) { for (unsigned int i = n; i > 0; i--) ; return; } //display a value on LEDs void display(unsigned int value, unsigned int waitTime) { P1OUT = 16*(value & 0xF); wait(waitTime); return; } /* Routines to inerface with the FLASH on a msp430x161x chip Created on 2005-09-16 by Neelesh Arora for the Rocket Lab of Physics Department, Princeton University */ BYTE COUNT; // Following functions courtesy of http://msp430.info /************************************************************************************************* Function : flash_writeByte Parameter : *dst : address within the FLASH page value : BYTE that has to be written to FLASH Date : 08.09.2001 / 17.11.2002 / 22.11.2002 Description : this function writes a byte to an address in FLASH memory warning: in FLASH only zeros can be written. if a bit value needs to be set to one from zero, the whole page has to be erased, thus setting all bits to one. then the value can be written correctly. this function does not perform the necessary FLASH page erase. *************************************************************************************************/ void flash_writeByte(BYTE *dst, BYTE value) { FCTL2 = FWKEY | FSSEL0 | 1; //clock source is MCLK, divisor is 20 do { _NOP(); } while(FCTL3 & 0x0001); // wait for BUSY to reset FCTL3 = FWKEY; // reset the LOCK bit to enable program/erase FCTL1 = FWKEY | WRT; // set WRT for single acces *dst = value; // do the write as a byte return; } /************************************************************************************************* Function : flash_eraseFLASH Parameter : *seg : any address within the FLASH page that is to be erased Date : 08.09.2001 / 19.11.2002 Description : this function erases a FLASH page *************************************************************************************************/ void flash_eraseFLASH(BYTE *seg) { FCTL2 = FWKEY | FSSEL0 | 1; //clock source is MCLK, divisor is 20 do { _NOP(); } while(FCTL3 & 0x0001); // wait for BUSY to reset FCTL3 = FWKEY; // reset the LOCK bit to enable program/erase FCTL1 = FWKEY | ERASE; // set single segment erase function *seg = 0xFF; // do a dummy write to start erase FCTL3 = FWKEY | LOCK; // lock the flash again return; } // End of functions from http://msp430.info // END of FLASH related functions // Data acquisition and copy to flash memory immediately void take_data(struct bubbl *data) { TACTL = TACTL | TACLR | MC_2; // reset Timer A // write start signature at the begining data[0].time = 0x2222; data[0].chan8 = 0x2222; data[0].chan7 = 0x2222; data[0].chan6 = 0x2222; data[0].chan5 = 0x2222; data[0].chan4 = 0x2222; data[0].chan3 = 0x2222; data[0].chan2 = 0x2222; data[0].chan1 = 0x2222; data[0].chan16 = 0x2222; data[0].chan15 = 0x2222; data[0].chan14 = 0x2222; data[0].chan13 = 0x2222; data[0].chan12 = 0x2222; data[0].chan11 = 0x2222; data[0].chan10 = 0x2222; data[0].chan9 = 0x2222; for (int j = 0; j < 34; j++) { addr_byte = (BYTE *)(FLASH_DATA + j); char x = *(((char *)data) + j); flash_writeByte(addr_byte, x); } ///// display(1,20000); //// display(0,200); for (int i = 1; i < NDATA ; i++) { // Take data for NDATA * records // Pull down P4 port P4.0 to 0 V, which controls 2 MAXIM 4674 multiplexers. // 8 switches of 2 MAXIM 4674 connect 8 channels of MSP430F1611 inputs to first 8 channels of bubblers, #1 - #8. // record them into structure data TBCCTL0 = TBCCTL0 & 0x0; //P4.0 pin down // TBCCTL1 = TBCCTL1 & 0x0; //P4.1 pin down // TBCCTL2 = TBCCTL2 & 0x0; //P4.2 pin down // TBCCTL3 = TBCCTL3 & 0x0; //P4.3 pin down data[0].time = TAR; // Get time // Choose the input channel for each ADC12MEM. I only can make 8 channels work in sequence of channels mode for now. ADC12MCTL0 = ADC12MCTL0 | INCH_0 | CSTARTADD_0; // start from the first channel ADC12MCTL1 = ADC12MCTL1 | INCH_1; // setup the correlation between input channel and ADC12MCTLx ADC12MCTL2 = ADC12MCTL2 | INCH_2; ADC12MCTL3 = ADC12MCTL3 | INCH_3; ADC12MCTL4 = ADC12MCTL4 | INCH_4; ADC12MCTL5 = ADC12MCTL5 | INCH_5; ADC12MCTL6 = ADC12MCTL6 | INCH_6; ADC12MCTL7 = ADC12MCTL7 | INCH_7 | EOS; ADC12CTL0 = ADC12CTL0 & (0xFFFF - ENC); // Disable conversions ADC12CTL0 = ADC12CTL0 | MSC; // set multiple conversion ADC12CTL1 = ADC12CTL1 | CONSEQ_1; // set sequence-of-channels mode ADC12IE = 0x07; // set the converstion interrupt flag on for the last channel #7 ADC12CTL0 = ADC12CTL0 | ENC; // Enable conversions ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion display(2,2); /////////// while (!(ADC12IFG & 1)) ; // Wait for conversion to finish // record them into structure data data[0].chan8 = ADC12MEM0; data[0].chan7 = ADC12MEM1; data[0].chan6 = ADC12MEM2; data[0].chan5 = ADC12MEM3; data[0].chan4 = ADC12MEM4; data[0].chan3 = ADC12MEM5; data[0].chan2 = ADC12MEM6; data[0].chan1 = ADC12MEM7; ADC12IFG = 0x00; // reset the flag // Pull up P4 port P4.0 to 2.75V that controls 2 MAXIM 4674 analog multiplexers. // Connect MSP430F1611 8 inputs to channel 9-16 of bubblers. TBCCTL0 = TBCCTL0 | OUT; //P4.0 pin up // TBCCTL1 = TBCCTL1 | OUT; //P4.1 pin up // TBCCTL2 = TBCCTL2 | OUT; //P4.2 pin up // TBCCTL3 = TBCCTL3 | OUT; //P4.3 pin up // Choose the input channel for each ADC12MEM. I only can make 8 channels work in sequence of channels mode for now. ADC12MCTL0 = ADC12MCTL0 | INCH_0 | CSTARTADD_0; // start from the first channel ADC12MCTL1 = ADC12MCTL1 | INCH_1; // setup the correlation between input channel and ADC12MCTLx ADC12MCTL2 = ADC12MCTL2 | INCH_2; ADC12MCTL3 = ADC12MCTL3 | INCH_3; ADC12MCTL4 = ADC12MCTL4 | INCH_4; ADC12MCTL5 = ADC12MCTL5 | INCH_5; ADC12MCTL6 = ADC12MCTL6 | INCH_6; ADC12MCTL7 = ADC12MCTL7 | INCH_7 | EOS; ADC12CTL0 = ADC12CTL0 & (0xFFFF - ENC); // Disable conversions ADC12CTL0 = ADC12CTL0 | MSC; // set multiple conversion ADC12CTL1 = ADC12CTL1 | CONSEQ_1; // set sequence-of-channels mode ADC12IE = 0x07; // set the converstion interrupt flag on for the last channel #7 ADC12CTL0 = ADC12CTL0 | ENC; // Enable conversions ADC12CTL0 = ADC12CTL0 | ADC12SC; // Start conversion while (!(ADC12IFG & 1)) ; // Wait for conversion to finish data[0].chan16 = ADC12MEM0; data[0].chan15 = ADC12MEM1; data[0].chan14 = ADC12MEM2; data[0].chan13 = ADC12MEM3; data[0].chan12 = ADC12MEM4; data[0].chan11 = ADC12MEM5; data[0].chan10 = ADC12MEM6; data[0].chan9 = ADC12MEM7; ADC12IFG = 0x00; // reset the flag // wait(500); // wait for a while, was 100 // write the data to flash memory immediately for (int j = 1; j < 35; j++) { addr_byte = (BYTE *)(FLASH_DATA + (34*i + j)); char x = *(((char *)data) + j); flash_writeByte(addr_byte, x); } } //write stop signature at the end data[0].time = 0x3333; data[0].chan8 = 0x3333; data[0].chan7 = 0x3333; data[0].chan6 = 0x3333; data[0].chan5 = 0x3333; data[0].chan4 = 0x3333; data[0].chan3 = 0x3333; data[0].chan2 = 0x3333; data[0].chan1 = 0x3333; data[0].chan16 = 0x3333; data[0].chan15 = 0x3333; data[0].chan14 = 0x3333; data[0].chan13 = 0x3333; data[0].chan12 = 0x3333; data[0].chan11 = 0x3333; data[0].chan10 = 0x3333; data[0].chan9 = 0x3333; for (int j = 0; j < 34; j++) { addr_byte = (BYTE *)(FLASH_DATA + (34 * NDATA + j)); char x = *(((char *)data) + j); flash_writeByte(addr_byte, x); } return; } void arm(void) { // Prepare for counting bubbles when arming button is pressed P6SEL = 0x36; // Setup port P6.4 for A/D ADC12CTL0 = ADC12CTL0 | SHT0_11; // Set sampling time ADC12CTL0 = ADC12CTL0 | ADC12ON; // Turn the A/D converter on ADC12CTL1 = ADC12CTL1 | SHP; // Use the sampling timer TACTL = TASSEL_1; // Select ACLK as the clock source TACTL = TACTL | ID_3; // Divide input clock by 8, in our case divide ACLK by 8 TACCTL0 = CM_1; // Select capture at rising edge TACCTL0 = TACCTL0 | SCS; // Synchronize the capture source TACCTL0 = TACCTL0 | CAP; // Select capture mode TACTL = TACTL | TACLR | MC_2; // Timer_A clear. Setting this bit resets TAR, the TACLK (not ACLK) divider // Continuous mode: the timer counts up to 0FFFFh return; } // Initialize the crystal-oscillator-driven clocks void init_clock(void) { BCSCTL1 = XT2OFF; // Turn XT2 off, select LF for crystal (watch crystal, 2^15Hz), and no divider for ACLK wait(5000) ; // Delay 0.523 s to ensure start of the oscillator return; } // Initialize ports P1 and P4, P1 for ADC, P4 for switch void init_io(void) { P1SEL = 0x0; // Setup P1.x for I/O P1DIR = 0xF0; // Setup P1.5-7 for output P4SEL = 0x7F; // Setup P4.1-7 for I/O P4DIR = 0x7F; // Setup P4.1-7 for output return; } // copy 8KB data (byte-by-byte) from RAM to FLASH, and update FLASH counter /* void copyData2Flash(int btw, struct bubbl *data) { // erase 16 flash segments (==8KB) BYTE *addr_seg, *addr_byte; for (int i=0; i<16; i++) { addr_seg=(BYTE *)(FLASH_DATA + (0x2000*(COUNT-1)) + (0x0200*i)); if (addr_seg > (BYTE *)0xEFFF) //No more fresh memory above 0xFFFF BYTE { for(int i=0; i<20; i++) { display(6,500); display(9,300); } return; //program stops } else flash_eraseFLASH(addr_seg); //Otherwise it is OK, erase the fresh memory } display(5,100); //flash 1-st and 3-rd lights briefly to indicate flash memory ready. int displayValue = 5; for (int i=0; i= (BYTE)(0x01) && COUNT <= (BYTE)(0x05)) return(1); else {for(int i=0; i<10; i++){ display(15,5000); display(0,3000); } return(0); } } */ // // int main(void) { WDTCTL = WDTPW + WDTHOLD ; // Give the password, and stop the watchdog timer __disable_interrupt(); // Disable all maskable interrupts init_io(); // Initialize ports P1.4:7 for I/O and P4.0:3 for switches init_clock(); // Initialize the crystal-oscillator-driven clocks U1TXBUF = 0xB4; for(int i=0; i<10; i++){ display(15,1000); // flesh all 4 lights display(0,1000); } display(8,20000); display(4,20000); display(2,20000); display(1,20000); arm(); // prepare to acquire data display(1,5000); struct bubbl *data = init_data(); // Allocate and initialize RAM for data storage // display(0,1000); display(2,5000); // Erase flash memory first, from 04000h to 04610h is used for main caode, erase start // from 05000h (20480d). for (int i=0; i<85; i++) { addr_seg=(BYTE *)(FLASH_DATA + (0x0200*i)); if (addr_seg > (BYTE *)0xEFFF) //No more flash memory above 0xFFFF BYTE { for(int i=0; i<20; i++) { display(5,500); display(10,300); } } else /* { for(int i=0; i<20; i++) { display(6,500); display(9,300); } } */ flash_eraseFLASH(addr_seg); //Otherwise it is OK, erase the fresh memory } // Start to take data COUNT = 1; display(6,20000); display(0,200); take_data(data); // acquire samples display(15,20000); // display(0,200); // Signal PC ready to transfer data via UART port, CGL 2/29/2008 /* volatile unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 |= XTS; // ACLK= LFXT1 = HF XTAL do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0xFF; i > 0; i--); // Time for flag to set } while ((IFG1 & OFIFG)); // OSCFault flag still set? */ U1TXBUF = 0xA3; // set U1TXBUF all 8 bits 1 to signal PC the data is ready to go // display(1,20000); BCSCTL2 |= SELM_3; // MCLK= LFXT1 (safe) // P5SEL |= 0xA; // P5.1,3 SPI option select // P5DIR |= 0xB; // P5.0,1,3 output direction // P5OUT &= ~0x1; // FS reset ME2 |= USPIE1; // Enable USART1 SPI U1CTL |= CHAR + SYNC + MM; // 8-bit SPI Master **SWRST** U1TCTL = CKPH + CKPL + SSEL0 + STC; // Inv. delayed, ACLK, 3-pin U1BR0 = 0x2; // ACLK/2 for baud rate U1BR1 = 0x0; // ACLK/2 for baud rate U1MCTL = 0x0; // Clear modulation U1CTL &= ~SWRST; // Initialize USART state machine CCTL0 = CCIE; // CCR0 interrupt enabled CCR0 = 111; // Clock period of CCR0 TACTL = TASSEL_1 + MC_1; // ACLK, Up-mode // U1RXBUF = 0xFF; /* if (U1TXBUF == 0xA3){ display(1,20000); display(2,20000); display(4,20000); display(8,20000); } */ // U1TXBUF is set as 0xFF, waiting for PC to read, CGL 2/29/2008 /* // CGL following two lines 2/29/2008 WDTCTL = WDTPW + WDTNMI ; // Give the password, and select the function for the RST/NMI pin, same as press the buttun RUN __enable_interrupt(); // enable all maskable interrupts */ return 0; }