/** test_adc app: This app uses the CC2511's analog-to-digital converter (ADC) to read the voltages on all 6 analog inputs and measure the voltage of the Wixel's VDD (3V3) line. The results are reported to the computer either in CSV format or as a bar graph. == Parameters == input_mode: Specifies whether to enable internal pull-down resistors, enable internal pull-up resistors, or just let the analog lines float. 1 = Pull-ups 0 = Float (default) -1 = Pull-downs bar_graph: Specifies whether to print out a bar graph or not. 1 = Print a bar graph (default, requires you to use a terminal program that supports VT100 commands) 0 = Print the 7 readings on a single line, separated by commas. report_period_ms: Specifies the number of milliseconds to wait between reports to the computer. The default is 40. */ #include #include #include #include #include #include ISR(T1,0); #define T1CCTL0_IM 0x40 // Channel 1 Interrupt mask #define T1CCTL1_IM 0x40 // Channel 1 Interrupt mask #define T1CTL_CH0IF 0x20 // Timer 1 channel 0 interrupt flag #define T1CCTL2_IM 0x40 // Channel 2 Interrupt mask #define T1CCTL2_CMP 0x38 #define T1CCTL2_CMP0 0x08 #define T1CCTL2_CMP1 0x10 #define T1CCTL2_CMP2 0x20 #define T1CCTL2_MODE 0x04 // Capture or compare mode #define T1CCTL2_CAP 0x03 #define T1CCTL2_CAP0 0x01 #define T1CCTL2_CAP1 0x02 // P2DIR (0xFF) - Port 2 Direction #define P2DIR_PRIP0 0xC0 #define P2DIR_0PRIP0 0x40 #define P2DIR_1PRIP0 0x80 #define P2DIR_DIRP2 0x1F #define P2DIR_PRIP0_0 (0x00 << 6) #define P2DIR_PRIP0_1 (0x01 << 6) #define P2DIR_PRIP0_2 (0x02 << 6) #define P2DIR_PRIP0_3 (0x03 << 6) #define MAX_BUF_SZ 32 #define DATA_AQU_TIME 10 // 10 msecs for now. Ideally need 50msec #define COOLOFF_PERIOD 6000 // 3 secs #define BIT0 0x01 #define BIT1 0x02 #define BIT2 0x04 // RX data which is not in dma.c DMA_CONFIG XDATA radioRxConfig; /* PARAMETERS *****************************************************************/ int32 CODE param_report_period_ms = 100; uint32 DATA volatile triggerTime = 0; uint32 DATA volatile captureWindow = 0; /* VARIABLES ******************************************************************/ // A big buffer for holding a report. This allows us to print more than // 128 bytes at a time to USB. uint8 XDATA report[1024]; // The length (in bytes) of the report currently in the report buffer. // If zero, then there is no report in the buffer. uint16 DATA reportLength = 0; // The number of bytes of the current report that have already been // send to the computer over USB. uint16 DATA reportBytesSent = 0; uint16 DATA volatile timer1Count = 0; uint16 DATA volatile tries = 0; uint16 DATA volatile doneDeal = 0; uint16 DATA volatile a = 0; void initDSM(void) __reentrant { // As per Twoway design guide, select the following and use // In twoway, Alt 2 location was used. However, in our design, // we need to use Alt 1 location. // P1SEL = 0x02; // Select Port 1_2 as output PERCFG = 0x40; // Alternative 2 loc Port 1: 2 (0), 1 (1), 0 (2) // Bit 6 is Timer 1 I/O location: 0 --> Alt 1 // Since 0 is the reset value, we dont have to do // anything here. So comment it out... P2SEL = 0x80; // Timer 1 has priority over USART P1DIR = 0x02; // Direction is output: In our case all // unused ports are output ports T1CTL = (T1CTL & ~0x03); // Set mode (timer) to 00 ==> Suspend T1CNTL = 0x00; // Clear Timer 1 counter by writing any value // Set Sample rate by writing to T1CC0 T1CC0H = 0x25; // Timer 1 capture/compare value high T1CC0L = 0x22; // Timer 1 capture/compare value low // 0x2522 = 3249 // This value should be equivalent of 396 usecs // Which is TODO.. T1CTL = T1CTL & ~0x10; T1CCTL0 = (T1CCTL0 | 0x04); // Set Timer 1 channel 0 to compare mode T1CCTL0 = T1CCTL0 & ~T1CCTL0_IM; // Disable interrupt on channel 0 T1CCTL1 = T1CCTL1 & ~T1CCTL1_IM; // Disable interrupt on channel 1 T1CCTL2 = T1CCTL2 & ~T1CCTL2_IM; // Disable interrupt on channel 2 T1CC1L = 0; // Load first sample as 0000 T1CC1H = 0; T1CTL = (T1CTL | 0x02); // Set to modulo mode 0000 to T1CC0 T1CCTL1 = (T1CCTL1 & ~0x07); // Timer 1 channel 1 compare control clear bit 0 1 & 2 } void enableDSM(void) __reentrant { EA = 0; T1CNTL = 0x00; // Clear Timer 1 counter by writing any value T1CC1L = 0; // Load first sample as 0000 T1CC1H = 0; IEN1 = (IEN1 & ~0x11111101); // Enable T1 int mask T1IE = 1; // Enable Timer1 interrupt mask OVFIM = 1; // Enable Overflow interrupt EA = 1; // Enable interrupt T1CCTL1 = (T1CCTL1 | 0x38); // Set to DSM Mode which will trigger DSM } #pragma save #pragma nooverlay void disableDSM(void) { EA = 0; // Temporarily disable interrupts T1CTL &= ~0x03; // Set mode (timer) to 00 ==> Suspend T1CCTL1 &= ~0x07; // Timer 1 channel 1 compare control clear bit 0 1 & 2 // which is no Capture when CMP is still not set to // 111. When set to 111, DSM will start OVFIM = 0; // Disable Overflow interrupt and Timer 1 interrupt T1CCTL1 = (T1CCTL1 & ~T1CCTL1_IM); T1CCTL1 = (T1CCTL1 & ~0x38); // Disable DSM Mode IEN1 = (IEN1 & ~0x00000010); // Disable Timer 1 Interrupt T1IE = 0; // Disable Timer1 interrupt EA = 1; // But leave global interrupt enabled setting IEN0.EA=1 } #pragma restore ISR(T1,0) { timer1Count++; EA = 0; // Clear Timer 1 channel 0 interrupt flag. The clearing has to be like this // to avoid loosing other Timer 1 interrupts (writing 1 to T1CTL[7:4] has // no effect as these are R/W0 accessible). This has to be done for W0 // accessible interrupt flags. T1CTL = (~T1CTL_CH0IF & 0xF0) | (T1CTL & 0x0F); // No need to clear IRCON T1 interrupt flag as it will be // reset by hardware EA = 1; } // // ISR to handle DMA interrupt // // void setUnusedPortsAsOutputPorts() __reentrant { P1SEL = 0x00; // 0 --> Gen purpose I/O P2SEL = 0x00; // 0 --> Gen purpose I/O // Since reset value is 0 // nothing may have to be done here. P1DIR = 0xFF; // Set all ports as output P2DIR = 0x1F; // Set all ports as output } // Initilizes I/O Ports void initPort0_0to3AsGPIOInput(void) __reentrant { // P0 = 0xFF; // Reset the Port 0 CX // Clear interrupt flags for P0 // P0IFG &= ~(BIT0 | BIT1 | BIT2); // Interrupt status flag so dont write // P0IF = 0; // Corresponds to IRCON (CPU int reg) CX // Port 0 // P0_0 ADC AI Analog Input (ADC) X // P0_1 ADC AI Analog Input (ADC) Y // P0_2 ADC AI Analog Input (ADC) Z // Is it P0SEL |= ???? or POSE &= // P0SEL &= ~(BIT0 | BIT1 | BIT2); P0SEL = 0x00; // Select all ports as GPIO // Here, we are setting rest of P0 ports // as GPIO also, when selecting dir P0DIR // select it as o/p pins // Dont leave them undefined // refer to page 87 sec 12.4.2 P0DIR = 0xF8; // Set rest as output refer page 86 CX } void updateLeds() { usbShowStatusWithGreenLed(); LED_YELLOW(0); LED_RED(0); } // This gets called by puts, printf, and printBar to populate // the report buffer. The result is sent to USB later. void putchar(char c) { report[reportLength] = c; reportLength++; } #if 0 void sendReportIfNeeded() { static uint32 lastReport; uint8 bytesToSend; // Create reports. if (getMs() - lastReport >= param_report_period_ms && reportLength == 0) { lastReport = getMs(); reportBytesSent = 0; LED_RED_TOGGLE(); printf("\x1B[0;0H"); // VT100 command for "go to 0,0" putchar('\r'); putchar('\n'); printf("timer1Count %5d \r\n", timer1Count); } // Send the report to USB in chunks. if (reportLength > 0) { bytesToSend = usbComTxAvailable(); if (bytesToSend > reportLength - reportBytesSent) { // Send the last part of the report. usbComTxSend(report+reportBytesSent, reportLength - reportBytesSent); reportLength = 0; } else { usbComTxSend(report+reportBytesSent, bytesToSend); reportBytesSent += bytesToSend; } } } #endif void main() { systemInit(); usbInit(); initPort0_0to3AsGPIOInput(); setUnusedPortsAsOutputPorts(); initDSM(); triggerTime = getMs(); while(1) { boardService(); updateLeds(); usbComService(); // sendReportIfNeeded(); if (doneDeal == 2) continue; if (getMs() - triggerTime > COOLOFF_PERIOD) { captureWindow = triggerTime = getMs(); tries++; if (tries < 10) enableDSM(); else doneDeal = 1; } // Check if time period falls within 50 msecs of the trigger point // if so start ADC which is followed by DMA. Else stop data acquisition // and enable trigger. if (doneDeal < 2 && captureWindow && ((getMs() - captureWindow) > DATA_AQU_TIME)) { // Time has expired (more than DATA_AQU_TIME.. disableDSM(); doneDeal = 2; } if (!doneDeal && timer1Count > 0 && timer1Count < 1024) { for (a = 0; a < timer1Count; a++) { delayMs(100); LED_RED_TOGGLE(); } timer1Count = 0; } } }