This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADC + microSD Card

Other Parts Discussed in Thread: MSP430F5529

Hello,

My name is William.

I am writing a code for a datalogger using the internal ADC (12 bits) of the MSP430F5529 LaunchPad. My goal is to get the samples and fill an array (a buffer) then store these samples in the sd card, and repeat the process (acquire samples ; fill buffer ; store onto micro SD Card). I am using the FatFs library.

Before to trying store the different samples onto the sd, I wrote equal samples (just the first one) with a loop and a interruption service routine by timer (10seconds), to measure the performance of the saving, reaching good speeds when the array size was set to 1024 (2048 bytes - array of short int).

The problem happens when I put the get_adc function inside the loop. If I set the array size as large as when the get_adc function was before the file initialization, the file is opened but the MSP doesn't write anything on it. It just works with small arrays (size around 50) with bad performance (too slow).

I checked the memory allocation in the CCS and the RAM use sounds good to me (around 10%).

Do you think the facts I am putting the microcontroller at Low Power Mode (LPM0) and using an interruption in the sample acquiring routine may affect the file that was opened before even if the stack data are restored after coming back from ISR?

Below is the code of the ADC samples acquiring. The main function is not here but it basically opens the file, and goes into a while loop that calls the adc functions to get the actual sample and writes into the SD Card while the timer overflow didn't happen. When the timer counter overflows, an ISR is called, closing the file and unmounting the card.

Thank you in advance. 

ADC CODE:

#include <adc.h>
#include <stdio.h>
#include "funcoes.h"


unsigned short int indiceVetor; /* indice para o vetor de resultados */

int adc_init(void)

{
	 unsigned short int contador;
	 indiceVetor = 0;
	 for(contador=0;contador < COMPRIMENTO_VETOR_RESULTADOS;contador++)
	 {
		 vetorResultados[contador] = 0;
	 }

	/* Setting Pin 6.0 as ADC Input */
	GPIO_setAsPeripheralModuleFunctionOutputPin(
	        GPIO_PORT_P6,
	        GPIO_PIN0
	        );

	// Initialize ADC12 with ADC12’s built-in oscillator
	ADC12_A_init (ADC12_A_BASE, ADC12_A_SAMPLEHOLDSOURCE_SC, ADC12_A_CLOCKSOURCE_ADC12OSC, ADC12_A_CLOCKDIVIDER_1);

	//Switch ON ADC12
	ADC12_A_enable(ADC12_A_BASE);

	// Setup sampling timer to sample-and-hold for 16 clock cycles
	ADC12_A_setupSamplingTimer (ADC12_A_BASE,
	ADC12_A_CYCLEHOLD_64_CYCLES,
	ADC12_A_CYCLEHOLD_4_CYCLES,
	ADC12_A_MULTIPLESAMPLESDISABLE);  /* atenção */

	// Configure the Input to the Memory Buffer with the specified Reference Voltages
	ADC12_A_configureMemoryParam param = {0};
	param.memoryBufferControlIndex = ADC12_A_MEMORY_0;
	param.inputSourceSelect = ADC12_A_INPUT_A0;
	param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
	param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
	param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
	ADC12_A_configureMemory(ADC12_A_BASE ,&param);

	ADC12_A_setReferenceBufferSamplingRate(ADC12_A_BASE, ADC12_A_MAXSAMPLINGRATE_200KSPS);
	ADC12_A_clearInterrupt(ADC12_A_BASE, ADC12IFG0);
	ADC12_A_enableInterrupt(ADC12_A_BASE, ADC12IE0);

	return 0;
}

int get_adc (void)
{

	while (1)
	{

		// Start a single conversion, no repeating or sequences.
		ADC12_A_startConversion (ADC12_A_BASE,
				ADC12_A_MEMORY_0,
				ADC12_A_SINGLECHANNEL);

		// Wait for the Interrupt Flag to assert at LPM0

        __bis_SR_register(LPM0_bits + GIE);

        if(indiceVetor <= COMPRIMENTO_VETOR_RESULTADOS)
        {
        	vetorResultados[indiceVetor] = resultadoGlobal;
			indiceVetor++;
        }
        else
        {
        	return 0;
        }

		ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12IFG0);

	}
}

#pragma vector=ADC12_VECTOR
__interrupt void ADC12_A_ISR(void)                    /* Flag ADC12IFG0 gerou a interrupção, indicando que deve ser executada ISR ADC_A_ISR */
{
		switch(__even_in_range(ADC12IV,34))
	    {
	    case  0: break;       //Vector  0:  No interrupt
	    case  2: break;       //Vector  2:  ADC overflow
	    case  4: break;       //Vector  4:  ADC timing overflow
	    case  6:              //Vector  6:  ADC12IFG0
	    	resultadoGlobal = (ADC12_A_getResults(ADC12_A_BASE,ADC12_A_MEMORY_0)); 	/* pegando os resultados e colocando na variável temporária de resultado */
	        //Exit active CPU
	        __bic_SR_register_on_exit(LPM0_bits);
	        break;
	    case  8: break;       //Vector  8:  ADC12IFG1
	    case 10: break;       //Vector 10:  ADC12IFG2
	    case 12: break;       //Vector 12:  ADC12IFG3
	    case 14: break;       //Vector 14:  ADC12IFG4
	    case 16: break;       //Vector 16:  ADC12IFG5
	    case 18: break;       //Vector 18:  ADC12IFG6
	    case 20: break;       //Vector 20:  ADC12IFG7
	    case 22: break;       //Vector 22:  ADC12IFG8
	    case 24: break;       //Vector 24:  ADC12IFG9
	    case 26: break;       //Vector 26:  ADC12IFG10
	    case 28: break;       //Vector 28:  ADC12IFG11
	    case 30: break;       //Vector 30:  ADC12IFG12
	    case 32: break;       //Vector 32:  ADC12IFG13
	    case 34: break;       //Vector 34:  ADC12IFG14
	    default: break;
	    }
}

  • > if(indiceVetor <= COMPRIMENTO_VETOR_RESULTADOS)
    This looks suspicious-- my guess is that you're storing past the end of vetorResultados[], and overwriting something else.

    It may be that when the array is small it is allocated elsewhere, and overwriting whatever follows it isn't noticeable.

    The notion of closing the file and dismounting the SDcard in a timer ISR (any ISR, really) is generally quite hazardous. I suggest you find a way to pass the timeout condition to main(), so it can close the file synchronously with everything else.
  • Hi Bruce, Thanks for answering.

    The array has been filled correct. The problem is right when I try to write the arrays in the SDcard. If I just get the first sample array it is okay but if I get different sample arrays until timeout condition occurs then the file stays with 0kB.

    I just did what you suggested but unfortunately the problem still remains. It seems my ADC function with LPM and ADC Interruptions is crashing the file system object but I have no idea why as interruptions save the data before to run the ISR and restore it after the code execution.

    Below is the main code

     int main(void)
     {
    	WDTCTL = WDTPW+WDTHOLD;                                 /* Stop watchdog timer */
        initCLK();                                              /* Inicia os Clocks*/   /* clock default mclk = 1MHz */
        myACLK = UCS_getACLK();                                 /* Guarda na variável myACLK o valor com o qual o ACLK está rodando */
        mySMCLK = UCS_getSMCLK();                               /* Guarda na variável mySMCLK o valor com o qual o SMCLK está rodando */
        myMCLK = UCS_getMCLK();                                 /* Guarda na variável myMCLK o valor com o qual o MCLK está rodando */
        unsigned int int_size;                                  /* Variável para guardar tamanho da amostra a ser gravada */
        __enable_interrupt(); 					            	/* enabling interrupts */
    
        adc_init();								                /* altera variável global do vetor de resultados */
        get_adc();
        int_size = sizeof(vetorResultados);
    	fat_init();                                             /* mount, set directory to read from, assign file */
    	/* fat depois de ad */
    	iniciarTimer();
    
      	/* loop infinito que será interrompido pela interrupção via timer de 10 segundos */
    	do {
    	     errCode1 = f_write(&file, (void*) vetorResultados, int_size , bytesWritten);
                 adc_init();  /* TI E2E: HERE THE PROBLEM BEGINS */		       /* altera variável global do vetor de resultados */
                 get_adc();
    
    
           }
    	while(!back);
    
    	errCode1 = f_close(&file);			       /* close the file */
    	errCode1 = f_mount(0,0);                               /* desmonta o cartão SD */
    	while(1);
    }
    
    /*Interrupção via Timer */
    
    #pragma vector=TIMER0_A1_VECTOR    /* vetor que guarda o resultado da interrupção */
    __interrupt void ISR_dezSegundos(void)  /* rotina da interrupção */
    {
    	switch(__even_in_range(TA0IV,14))
    	{
    		case 0:  break;
    		case 2:  break;
    		case 4:  break;
    		case 6:  break;
    		case 8:  break;
    		case 10: break;
    		case 12: break;
    		case 14:
    			back = 1;
    			break;
    		default: break;
    
    	}
    }

  • OK, but if vetorResultados is really of size (1+COMPRIMENTO_VETOR_RESULTADOS), as get_adc() claims, then adc_init() is not properly initializing it all.

    Also, is bytesWritten really a pointer? Is it initialized properly?
  • Now I get it!! A lot of time wasted because of this mistake. Thank you very much. 

    The array was not properly initializing as you said. 

    bytesWritten is a pointer, all fine with this variable.

    Now I'm making some changes in the code to improve the ADC conversion time performance. I'm not sure if it is well optimized.

    #include <adc.h>
    #include <stdio.h>
    #include "funcoes.h"
    
    
    
    int adc_init(void)
    
    {
    	/* Setting Pin 6.0 as ADC Input */
    	GPIO_setAsPeripheralModuleFunctionOutputPin(
    	        GPIO_PORT_P6,
    	        GPIO_PIN0
    	        );
    
    	// Initialize ADC12 with ADC12’s built-in oscillator
    	ADC12_A_init (ADC12_A_BASE, ADC12_A_SAMPLEHOLDSOURCE_SC, ADC12_A_CLOCKSOURCE_MCLK, ADC12_A_CLOCKDIVIDER_1);
    
    	//Switch ON ADC12
    	ADC12_A_enable(ADC12_A_BASE);
    
    	// Setup sampling timer to sample-and-hold for 1 clock cycles
    	ADC12_A_setupSamplingTimer (ADC12_A_BASE,
    	ADC12_A_CYCLEHOLD_4_CYCLES,
    	ADC12_A_CYCLEHOLD_4_CYCLES,
    	ADC12_A_MULTIPLESAMPLESENABLE);  /* atenção */
    
    	// Configure the Input to the Memory Buffer with the specified Reference Voltages
    	ADC12_A_configureMemoryParam param = {0};
    	param.memoryBufferControlIndex = ADC12_A_MEMORY_0;
    	param.inputSourceSelect = ADC12_A_INPUT_A0;
    	param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
    	param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    	param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    	ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    	ADC12_A_setReferenceBufferSamplingRate(ADC12_A_BASE, TAXA_DE_AMOSTRAGEM_AD_12_BITS);   /* configurar em adc.h */
    	ADC12_A_clearInterrupt(ADC12_A_BASE, ADC12IFG0);
    	ADC12_A_enableInterrupt(ADC12_A_BASE, ADC12IE0);
    
    	return 0;
    }
    
    int get_adc (void)
    {
    	unsigned short int indiceVetor=0; /* indice para o vetor de resultados */
    	ADC12_A_clearInterrupt(ADC12_A_BASE, ADC12IFG0);
    	zerar_vetor(vetorResultados);
    	while (1)
    	{
    		/* colocar zerarvetor aqui? */
    
    		// Start a single conversion, no repeating or sequences.
    		ADC12_A_startConversion (ADC12_A_BASE,
    				ADC12_A_MEMORY_0,
    				ADC12_A_SINGLECHANNEL);
    
    		// Wait for the Interrupt Flag to assert at LPM0
            __bis_SR_register(LPM0_bits + GIE);
    
            if(indiceVetor < COMPRIMENTO_VETOR_RESULTADOS)
            {
            	vetorResultados[indiceVetor] = resultadoGlobal;
    			indiceVetor++;
    			if(indiceVetor==COMPRIMENTO_VETOR_RESULTADOS)
    			{
    				return 0;
    			}
            }
     		ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12IFG0);
    
    	}
    }
    
    unsigned int zerar_vetor(short int vetorResultados[COMPRIMENTO_VETOR_RESULTADOS])
    {
    	unsigned short int contador;
    	for(contador=0;contador < COMPRIMENTO_VETOR_RESULTADOS;contador++)
    	{
    		vetorResultados[contador] = 0;
    	}
    
    	return 0;
    
    }
    
    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12_A_ISR(void)                    /* Flag ADC12IFG0 gerou a interrupção, indicando que deve ser executada ISR ADC_A_ISR */
    {
    		switch(__even_in_range(ADC12IV,34))
    	    {
    	    case  0: break;       //Vector  0:  No interrupt
    	    case  2: break;       //Vector  2:  ADC overflow
    	    case  4: break;       //Vector  4:  ADC timing overflow
    	    case  6:              //Vector  6:  ADC12IFG0
    	    	resultadoGlobal = (ADC12_A_getResults(ADC12_A_BASE,ADC12_A_MEMORY_0)); 	/* pegando os resultados e colocando na variável temporária de resultado */
    	        //Exit active CPU
    	        __bic_SR_register_on_exit(LPM0_bits);
    	        break;
    	    case  8: break;       //Vector  8:  ADC12IFG1
    	    case 10: break;       //Vector 10:  ADC12IFG2
    	    case 12: break;       //Vector 12:  ADC12IFG3
    	    case 14: break;       //Vector 14:  ADC12IFG4
    	    case 16: break;       //Vector 16:  ADC12IFG5
    	    case 18: break;       //Vector 18:  ADC12IFG6
    	    case 20: break;       //Vector 20:  ADC12IFG7
    	    case 22: break;       //Vector 22:  ADC12IFG8
    	    case 24: break;       //Vector 24:  ADC12IFG9
    	    case 26: break;       //Vector 26:  ADC12IFG10
    	    case 28: break;       //Vector 28:  ADC12IFG11
    	    case 30: break;       //Vector 30:  ADC12IFG12
    	    case 32: break;       //Vector 32:  ADC12IFG13
    	    case 34: break;       //Vector 34:  ADC12IFG14
    	    default: break;
    	    }
    }
    
    

    Once again, thank you very much.

**Attention** This is a public forum