I've been using the ADC and it can convert the voltage reading from an external source. I'm getting number values from ADCMEM0 ranging from 20 to 120. I'm trying to transfer these values using I2C but for some reason they won't work.
I've tried implementing examples such as the an example file TI provide called, eusci_b_i2c_ex3_masterTxMultiple.c. Implementing it as it is, causes the program to get stuck at line 318 in eusci_b_i2c.c, which I don't understand why as the way the interrupts are handled is very complicated. I also used this resource but it's for another MSP430 model and the interrupts for it are different, which I also don't know how to implement.
Another question I have is that, do I send the ADC result one byte at a time? Or do I specify a certain amount of time where the MSP430 reads in data and stores it, and then transmits it?
Here is the code with the second resource:
//i2c implementation using the TI_I2C functions, gets stuck in the //interrupt at the end of the definitions file #include <msp430.h> #include <driverlib.h> #include "TI_USCI_I2C_master.h" #include <stdio.h> #include <math.h> unsigned int ADC_Result = 0; unsigned char SlaveAddress = 0xC0; unsigned char char_ADC_result[1] = {0}; unsigned long long numbin_watch,numbin = 0; int length = 0; int numbinArray[10]; int count = 0; long long convert(int num) { long long numbin = 0; int rem; long long i = 1; while (num!=0) { rem = num % 2; num /= 2; numbin += rem * i; i *= 10; } return numbin; } int lengthOfInt(unsigned long long numbin){ int count = 0; while (numbin != 0) { numbin /= 10; count++; } return count; } int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop WDT // Configure GPIO P1DIR |= BIT0; // Set P1.0/LED to output direction P1OUT &= ~BIT0; // P1.0 LED off // Configure ADC A9 pin SYSCFG2 |= ADCPCTL9; // Configure Pins for I2C //P5SEL0 |= BIT2 | BIT3; // I2C pins, select pin P5.2 for SDA and pin P5.3 for SCL // Disable the GPIO power-on default high-impedance mode to activate // previously configured port settings PM5CTL0 &= ~LOCKLPM5; __enable_interrupt(); //worked without this, uncomment to test with it // Configure ADC10 ADCCTL0 |= ADCSHT_2 | ADCON; // ADCON, S&H=16 ADC clks----ADCSHTx : 0000b = 4 ADCCLK cycles 0001b = 8 ADCCLK cycles 0010b = 16 ADCCLK cycles 0011b = 32 ADCCLK cycles ADCCTL1 |= ADCSHP | ADCSSEL_0 | ADCCONSEQ_2; // ADCCLK = MODOSC; sampling timer ADCCONSEQ_2 = Repeat-single-channel ---- remove it for single channel ADCCTL2 |= ADCRES_1 ; // 10/8-bit conversion results ADCRES_1 = 10 bit////ADCRES_0 = 8 bit ADCMCTL0 |= ADCINCH_9 | ADCSREF_0; // A9 ADC input select; pin 8.1 use this for mic setup ADCIFG &= ~0x01; //clear interrupt flag ADCIE |= ADCIE0; // Enable ADC conv complete interrupt // // Configure USCI_B0 for I2C mode // UCB0CTLW0 |= UCSWRST; // put eUSCI_B in reset state // UCB0CTLW0 |= UCMODE_3 | UCMST; // I2C master mode, SMCLK // //UCB0CTLW0 |= UCSLA10 | UCSSEL_2; // slave has 7 bit address, source clock is SMCLK // UCB0BRW = 0x8; // baudrate = SMCLK / 8 // UCB0CTLW0 &=~ UCSWRST; // clear reset register // UCB0IE |= UCTXIE0 | UCNACKIE; // transmit and NACK interrupt enable TI_USCI_I2C_transmitinit(SlaveAddress,0x01); // init transmitting with USCI and config while(1) { ADCCTL0 |= ADCENC | ADCSC; // Sampling and conversion start, could use ACCTL0 = 0x03 __bis_SR_register(LPM0_bits | GIE); // LPM0, ADC_ISR will force exit LOW POWER MODE 0 //__no_operation(); // For debug only if (ADC_Result < 0x00F){ P1OUT &= ~BIT0; // Clear P1.0 LED off } else{ P1OUT |= BIT0; // Set P1.0 LED on } char_ADC_result[0] = ADC_Result; __delay_cycles(5000); while ( TI_USCI_I2C_notready() ); // wait for bus to be free //if ( TI_USCI_I2C_slave_present(SlaveAddress) ) // slave address may differ from //{ // initialization //while ( TI_USCI_I2C_notready() ); // wait for bus to be free TI_USCI_I2C_transmit(1,char_ADC_result); // start transmitting //} //__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 //LPM0; // Remain in LPM0 until all data is TX'd } } // ADC interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = ADC_VECTOR __interrupt void ADC_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(ADCIV,ADCIV_ADCIFG)) { case ADCIV_NONE: break; case ADCIV_ADCOVIFG: break; case ADCIV_ADCTOVIFG: break; case ADCIV_ADCHIIFG: break; case ADCIV_ADCLOIFG: break; case ADCIV_ADCINIFG: break; case ADCIV_ADCIFG: ADC_Result = ADCMEM0; __bic_SR_register_on_exit(LPM0_bits); // Clear CPUOFF bit from LPM0 break; default: break; } }
Here is the code for the example TI provides :
//uses TI board-specific i2c example, gets stuck in an interrupt again, line 318 in esci_b_i2c.c #include <msp430.h> #include <driverlib.h> #include "Board.h" #define SLAVE_ADDRESS 0xC0 #define CS_SMCLK_DESIRED_FREQUENCY_IN_KHZ 1000 //Target frequency for SMCLK in kHz #define CS_SMCLK_FLLREF_RATIO 30 //SMCLK/FLLRef Ratio unsigned int ADC_Result = 0; // Pointer to TX data uint8_t TXData = 0; uint8_t TXByteCtr; int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop WDT // Configure GPIO P1DIR |= BIT0; // Set P1.0/LED to output direction P1OUT &= ~BIT0; // P1.0 LED off // Configure ADC A9 pin SYSCFG2 |= ADCPCTL9; //Set DCO FLL reference = REFO CS_initClockSignal( CS_FLLREF, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1 ); //Set Ratio and Desired MCLK Frequency and initialize DCO CS_initFLLSettle( CS_SMCLK_DESIRED_FREQUENCY_IN_KHZ, CS_SMCLK_FLLREF_RATIO ); //Set ACLK = VLO with frequency divider of 1 CS_initClockSignal( CS_ACLK, CS_VLOCLK_SELECT, CS_CLOCK_DIVIDER_1 ); //Set SMCLK = DCO with frequency divider of 1 CS_initClockSignal( CS_SMCLK, CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1 ); //Set MCLK = DCO with frequency divider of 1 CS_initClockSignal( CS_MCLK, CS_DCOCLKDIV_SELECT, CS_CLOCK_DIVIDER_1 ); // Configure Pins for I2C , SCL 5.3, SDA 5.2 GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_UCB0SCL, GPIO_PIN_UCB0SCL, GPIO_FUNCTION_UCB0SCL ); GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_UCB0SDA, GPIO_PIN_UCB0SDA, GPIO_FUNCTION_UCB0SDA ); /* * Disable the GPIO power-on default high-impedance mode to activate * previously configured port settings */ PMM_unlockLPM5(); EUSCI_B_I2C_initMasterParam param = {0}; param.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK; param.i2cClk = CS_getSMCLK(); param.dataRate = EUSCI_B_I2C_SET_DATA_RATE_400KBPS; param.byteCounterThreshold = 0; param.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP; EUSCI_B_I2C_initMaster(EUSCI_B0_BASE, ¶m); //Specify slave address EUSCI_B_I2C_setSlaveAddress(EUSCI_B0_BASE, SLAVE_ADDRESS ); //Set Master in receive mode EUSCI_B_I2C_setMode(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_MODE ); //Enable I2C Module to start operations EUSCI_B_I2C_enable(EUSCI_B0_BASE); EUSCI_B_I2C_clearInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT ); //Enable master Receive interrupt EUSCI_B_I2C_enableInterrupt(EUSCI_B0_BASE, EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT ); // Configure ADC10 ADCCTL0 |= ADCSHT_2 | ADCON; // ADCON, S&H=16 ADC clks----ADCSHTx : 0000b = 4 ADCCLK cycles 0001b = 8 ADCCLK cycles 0010b = 16 ADCCLK cycles 0011b = 32 ADCCLK cycles ADCCTL1 |= ADCSHP | ADCSSEL_0 | ADCCONSEQ_2; // ADCCLK = MODOSC; sampling timer ADCCONSEQ_2 = Repeat-single-channel ---- remove it for single channel ADCCTL2 |= ADCRES_1 ; // 10/8-bit conversion results ADCRES_1 = 10 bit////ADCRES_0 = 8 bit ADCMCTL0 |= ADCINCH_9 | ADCSREF_0; // A9 ADC input select; pin 8.1 use this for mic setup ADCIFG &= ~0x01; //clear interrupt flag ADCIE |= ADCIE0; // Enable ADC conv complete interrupt while(1) { ADCCTL0 |= ADCENC | ADCSC; // Sampling and conversion start, could use ACCTL0 = 0x03 __bis_SR_register(LPM0_bits | GIE); // LPM0, ADC_ISR will force exit LOW POWER MODE 0 //__no_operation(); // For debug only if (ADC_Result < 0x00F){ P1OUT &= ~BIT0; // Clear P1.0 LED off } else{ P1OUT |= BIT0; // Set P1.0 LED on } __delay_cycles(1000); // Delay between transmissions TXByteCtr = 1; // Load TX byte counter TXData = ADC_Result; while (EUSCI_B_I2C_SENDING_STOP == EUSCI_B_I2C_masterIsStopSent(EUSCI_B0_BASE)); EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B0_BASE, TXData++); //__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts // Remain in LPM0 until all data // is TX'd // Increment data byte } } // ADC interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = ADC_VECTOR __interrupt void ADC_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(ADCIV,ADCIV_ADCIFG)) { case ADCIV_NONE: break; case ADCIV_ADCOVIFG: break; case ADCIV_ADCTOVIFG: break; case ADCIV_ADCHIIFG: break; case ADCIV_ADCLOIFG: break; case ADCIV_ADCINIFG: break; case ADCIV_ADCIFG: ADC_Result = ADCMEM0; __bic_SR_register_on_exit(LPM0_bits); // Clear CPUOFF bit from LPM0 break; default: break; } } //------------------------------------------------------------------------------ // The USCIAB0TX_ISR is structured such that it can be used to transmit any // number of bytes by pre-loading TXByteCtr with the byte count. Also, TXData // points to the next byte to transmit. //------------------------------------------------------------------------------ #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=USCI_B0_VECTOR __interrupt #elif defined(__GNUC__) __attribute__((interrupt(USCI_B0_VECTOR))) #endif void USCIB0_ISR(void) { switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG)) { case USCI_NONE: // No interrupts break; break; case USCI_I2C_UCALIFG: // Arbitration lost break; case USCI_I2C_UCNACKIFG: // NAK received (master only) //resend start if NACK EUSCI_B_I2C_masterSendStart(EUSCI_B0_BASE); break; case USCI_I2C_UCTXIFG0: // TXIFG0 // Check TX byte counter if (TXByteCtr) { EUSCI_B_I2C_masterSendMultiByteNext(EUSCI_B0_BASE, TXData++); // Decrement TX byte counter TXByteCtr--; } else { EUSCI_B_I2C_masterSendMultiByteStop(EUSCI_B0_BASE); // Exit LPM0 __bic_SR_register_on_exit(CPUOFF); } break; default: break; } }
Suggestions for other solutions are welcome or any other resources I should read to try and get this to work would be very helpful. Thank you in advance for your time and for reading.