0
\$\begingroup\$

I am pretty new to embedded work, so I am just trying to pick things up on a small scale. So, for the reason, I have an accelerometer connected to my MSP430FR6989 Launchpad. At the minute, all I want to do is write one ADC sample from ADC12MEM0 into FRAM, but I have been running into issues (mainly, when I look at the FRAM registers I don't see any change), and I am hoping someone can point out my mistake. I imagine I am being quite stupid somewhere.

My (whole) code below is a mix of my own, and things hacked together from example code from the TI website.

#include <msp430.h> 

#define WRITE_SIZE      1

#define ENABLE_PINS         0xFFFE      // Required for inputs and outputs
#define ACLK                0x0100      // Timer A ACLK clock source
#define UP                  0x0010      // Timer A in UP mode
#define TAIFG               0x0001      // Used to look at the Timer A Interrput FlaG
// #define LED_ON              0x0001      // Used for the red LED

unsigned int data;

/***************************
 * Function Prototype
 **************************/
void adc_setup(void);                   // Used to setup ADC12 peripheral
void FRAMWrite(void);                   // Prototype for writing to FRAM

#if defined(__TI_COMPILER_VERSION__)
#pragma PERSISTENT(FRAM_write)
// unsigned long FRAM_write[WRITE_SIZE] = {0};
unsigned int FRAM_write[WRITE_SIZE] = {0};
#elif defined(__IAR_SYSTEMS_ICC__)
__persistent unsigned int FRAM_write[WRITE_SIZE] = {0};
#elif defined(__GNUC__)
unsigned int __attribute__((persistent)) FRAM_write[WRITE_SIZE] = {0};
#else
#error Compiler not supported!
#endif

main()
{
    ADC12MEM0 = 0x00;
    unsigned char intervals = 0;        // Used to count the number of 40000's
    WDTCTL = WDTPW | WDTHOLD;
    PM5CTL0 = ENABLE_PINS;
    P1DIR = 0x0001;                     
    P1OUT = 0x0000;                     // Turns LED off

    adc_setup();                        // Calls function to set up ADC12

    /******************************
     * Set up the timer to count up
     ******************************/
    TA0CCR0 = 40000;                    // The number we want to count to
    TA0CTL = ACLK | UP;                 // Clock is in UP mode

    // __bis_SR_register(LPM0_bits | GIE); // LPM0, ADC12_ISR will force exit
    // _BIS_SR(LPM0_bits | GIE);
    _BIS_SR(LPM0_bits | GIE);


    while(1)
    {
        // Checks to see if the counter has reached 40000 - TAIFG register chances from 0 to 1
        P1OUT = 0x0000;                     // Turns the LED off
        if(TA0CTL & TAIFG)
        {
            intervals = intervals + 1;      // Increments interval counter
            TA0CTL = TA0CTL & (~TAIFG);     // Reset counter



            if(intervals == 1)             
            {
                intervals = 0;              // Reset intervals counter
                /*
                 * Add code here to enable and start ADC
                 */
                // P1OUT = BIT0;
                ADC12CTL0 = ADC12CTL0 | ADC12ENC | ADC12SC;

                // FRAMWrite();

            }
        }
    }
}

/******************************
 * Configure the ADC peripheral
 ******************************/
void adc_setup(void)
{
    /*
     * Code here for ADC setup.
     * Required #defines & code assigned to specific registers
     */
    #define ADC12_SHT_16        0x0200          // 16 clock cycles for sample and hold
    #define ADC12_ON            0x0010          // Used to turn ADC12 peripheral on
    #define ADC12_SHT_SRC_SEL   0x0200          // Select source for sample and hold
    #define ADC12_12BIT         0x0020          // Selects 12-bit resolution
    #define ADC12_P92           0x000A          // Use P9.2 for the analogue input

    // Turn on the ADC peripheral, and set the Sample and Hold time
    ADC12CTL0 = ADC12_SHT_16 | ADC12_ON;

    // This instruction selects the sample and hold clock source. This is done
    // in ADC12CTL1
    ADC12CTL1 = ADC12_SHT_SRC_SEL;

    // Next we want to set the ADC resolution. This is done in ADC12CTL2
    ADC12CTL2 = ADC12_12BIT;

    // Specify analogue input pin
    ADC12MCTL0 = ADC12_P92;

    ADC12IER0 |= ADC12IE0;                  // Enable ADC conv complete interrupt
}


#pragma vector=ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
    switch(__even_in_range(ADC12IV, ADC12IV_ADC12RDYIFG))
        {
            case ADC12IV_NONE:        break;    // Vector  0:  No interrupt
            case ADC12IV_ADC12OVIFG:  break;    // Vector  2:  ADC12MEMx Overflow
            case ADC12IV_ADC12TOVIFG: break;    // Vector  4:  Conversion time overflow
            case ADC12IV_ADC12HIIFG:  break;    // Vector  6:  ADC12BHI
            case ADC12IV_ADC12LOIFG:  break;    // Vector  8:  ADC12BLO
            case ADC12IV_ADC12INIFG:  break;    // Vector 10:  ADC12BIN
            case ADC12IV_ADC12IFG0:             // Vector 12:  ADC12MEM0 Interrupt
                P1OUT = BIT0;                   // Turn on LED
                unsigned int i = 0;
                for ( i= 0; i< WRITE_SIZE; i++)
                {
                    FRAM_write[i] = ADC12MEM0;
                }

                // Exit from LPM0 and continue executing main
                // __delay_cycles(10000);
                __bic_SR_register_on_exit(LPM0_bits);
                ADC12IER0 = 0x0000;                 // Disable interrupts
                break;
            case ADC12IV_ADC12IFG1:   break;    // Vector 14:  ADC12MEM1
            case ADC12IV_ADC12IFG2:   break;    // Vector 16:  ADC12MEM2
            case ADC12IV_ADC12IFG3:   break;    // Vector 18:  ADC12MEM3
            case ADC12IV_ADC12IFG4:   break;    // Vector 20:  ADC12MEM4
            case ADC12IV_ADC12IFG5:   break;    // Vector 22:  ADC12MEM5
            case ADC12IV_ADC12IFG6:   break;    // Vector 24:  ADC12MEM6
            case ADC12IV_ADC12IFG7:   break;    // Vector 26:  ADC12MEM7
            case ADC12IV_ADC12IFG8:   break;    // Vector 28:  ADC12MEM8
            case ADC12IV_ADC12IFG9:   break;    // Vector 30:  ADC12MEM9
            case ADC12IV_ADC12IFG10:  break;    // Vector 32:  ADC12MEM10
            case ADC12IV_ADC12IFG11:  break;    // Vector 34:  ADC12MEM11
            case ADC12IV_ADC12IFG12:  break;    // Vector 36:  ADC12MEM12
            case ADC12IV_ADC12IFG13:  break;    // Vector 38:  ADC12MEM13
            case ADC12IV_ADC12IFG14:  break;    // Vector 40:  ADC12MEM14
            case ADC12IV_ADC12IFG15:  break;    // Vector 42:  ADC12MEM15
            case ADC12IV_ADC12IFG16:  break;    // Vector 44:  ADC12MEM16
            case ADC12IV_ADC12IFG17:  break;    // Vector 46:  ADC12MEM17
            case ADC12IV_ADC12IFG18:  break;    // Vector 48:  ADC12MEM18
            case ADC12IV_ADC12IFG19:  break;    // Vector 50:  ADC12MEM19
            case ADC12IV_ADC12IFG20:  break;    // Vector 52:  ADC12MEM20
            case ADC12IV_ADC12IFG21:  break;    // Vector 54:  ADC12MEM21
            case ADC12IV_ADC12IFG22:  break;    // Vector 56:  ADC12MEM22
            case ADC12IV_ADC12IFG23:  break;    // Vector 58:  ADC12MEM23
            case ADC12IV_ADC12IFG24:  break;    // Vector 60:  ADC12MEM24
            case ADC12IV_ADC12IFG25:  break;    // Vector 62:  ADC12MEM25
            case ADC12IV_ADC12IFG26:  break;    // Vector 64:  ADC12MEM26
            case ADC12IV_ADC12IFG27:  break;    // Vector 66:  ADC12MEM27
            case ADC12IV_ADC12IFG28:  break;    // Vector 68:  ADC12MEM28
            case ADC12IV_ADC12IFG29:  break;    // Vector 70:  ADC12MEM29
            case ADC12IV_ADC12IFG30:  break;    // Vector 72:  ADC12MEM30
            case ADC12IV_ADC12IFG31:  break;    // Vector 74:  ADC12MEM31
            case ADC12IV_ADC12RDYIFG: break;    // Vector 76:  ADC12RDY
            default: break;


        }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Some questions to help you debugging: Do you know if the ADC is running and getting samples correctly? Are you sure the FRAM_write variable is located in FRAM? It is defined as #pragma PRESISTENT, which by the default linker file is placed in the .data section located in SRAM. How fast is your main clock? If faster than 8MHz the FRAM controller needs to add wait states to access FRAM. I would start by checking that the ADC i running as it should. You can also try just to write an incremented value to FRAM_write to check that it's writable. \$\endgroup\$ – Peter Karlsen Sep 26 '19 at 10:58
  • 1
    \$\begingroup\$ It's great you are configuring the control registers manually. It's a good way to get to know the inner workings of the MCU. TI has a driverlib that makes configuration and use of the internal functional blocks much easier. It saves a lot of time searching for the "make it all run" bit in the configuration. \$\endgroup\$ – Peter Karlsen Sep 26 '19 at 11:01
  • 1
    \$\begingroup\$ You might want to have a look at the FRAM guide from TI. ti.com/lit/an/slaa628/slaa628.pdf \$\endgroup\$ – Peter Karlsen Sep 26 '19 at 11:03
  • 1
    \$\begingroup\$ You should u suffix all your constants. I believe this is a 16 bit MCU, so your hex constants, as written, are dangerous. 0xFFFE for example is type unsigned int but 0x0100 is type int. \$\endgroup\$ – Lundin Sep 26 '19 at 12:51
  • 1
    \$\begingroup\$ FRAM_write should likely be declared as volatile, see this. \$\endgroup\$ – Lundin Sep 26 '19 at 12:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.