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.

MSP430F2619 with SD MMC

Other Parts Discussed in Thread: MSP430F2619, CSD

Hi

I am using a MSP430F2619 with IAR to make a data logger : I measure 3 voltages (from ADCXMEMO) which are written to a SD card. A user can ask those data to be sent thru the serial port. There are two interruptions : Timer A0 to increment seconds (a led is blinking each second) and USCIAB0RX to listen to the serial port if data is coming. I am using a library provided by Texas Instruments to access a MultiMediaCard (slaa281b). If I do not use the SD MMC card it is stable. If I use the SD MMC card, it hangs few hours later (but the led still blinks) ... I do not see what could be the problem ? and how to locate it ... I attach the code.

Thanks for any hint to help me to debug it.

Cheers Karim

 

#include "msp430x26x.h"
#include "msp430.h"
#include "hal_hardware_board.h"
#include "mmc.h"
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <intrinsics.h>

#define LENFORCOM 200
#define FREQ 120  // acquire every FREQ seconds
#define LENFORPARAMETERS 30
#define NUMBEROFPARAMETERS 10

unsigned int seconds=0,min=0,h=0,day=0,month=0,year=0;
unsigned int daysInMonth[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
unsigned char com[LENFORCOM]={ 0 };
short mode=1;
unsigned int m=0, okbeg=0,okend=0;


// for sd mmc
unsigned long cardSize = 0;
unsigned char status = 1;
unsigned int timeout = 0;
unsigned long numblocks=0;
unsigned long totalBlocks;

// timer initialisation
void initTimer()
{
  P1DIR |= 0x01;                            // P1.0 output
  TACTL = TASSEL_1 + MC_1 + ID_3;           // Timer A mode control: 1 - Up to CCR0 clock source=ACLK  input divider: /8
  CCTL0 = CCIE;                             // CCR0 interrupt enabled
  TACCR0 = 4000 ;                           // wake up every second
}

// initialisation uart 115200 bauds 8-N-1
void init_rs1_115200()
{
  P1DIR |= 0x01;  
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO
  DCOCTL = CALDCO_1MHZ;
  P3SEL = 0x30;                             // P3.4,5 = USCI_A0 TXD/RXD
  UCA0CTL1 |= UCSSEL_2;                     // SMCLK
  UCA0BR0 = 8;                              // 1MHz 115200
  UCA0BR1 = 0;                              // 1MHz 115200
  UCA0MCTL = UCBRS2 + UCBRS0;               // Modulation UCBRSx = 5
  UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  IE2 |= UCA0RXIE;                          // Enable USCI_A0 RX interrupt
}

// function to send a character on serial port
void snd_rs1(unsigned char cara)
{
  while ((IFG2&UCA0TXIFG)==0);
  UCA0TXBUF=cara;
}

// function to send a string on serial port
void str_rs1(unsigned char* cara)
{
  int k=0;
  do {snd_rs1(cara[k]);k++;} while (cara[k]!=0);
}

// initialisation of ADC 12bits
void init_ADC(void)
{
  P6SEL = 0x08;                             // Enable A/D channel inputs
  ADC12CTL0 = ADC12ON+MSC+SHT0_2;           // Turn on ADC12, set sampling time
  ADC12CTL1 = SHP+CONSEQ_1;                 // Use sampling timer, single sequence
  ADC12MCTL0 = INCH_0;                      // ref+=AVcc, channel = A0
  ADC12MCTL1 = INCH_1;                      // ref+=AVcc, channel = A1
  ADC12MCTL2 = INCH_2+EOS;                  // ref+=AVcc, channel = A2, end seq.
  ADC12CTL0 |= ADC12SC;
  ADC12CTL0 |= ENC;                         // Enable conversions
  //P6DIR &= 0x08;                            // P6.0, i/p
}

void initSDMMC()
{
  unsigned char ch[200];
 
  memset(ch,0,sizeof(ch));
  // MMC/SD-card
  while (status != 0)                       // if return in not NULL an error did occur and the
    // MMC/SD-card will be initialized again
  {
    status = mmcInit();
    timeout++;
    if (timeout == 150)                      // Try 50 times till error
    {
      snprintf (ch,sizeof(ch),"No MMC/SD-card found!! %x\n", status);
      str_rs1(ch);   
      break;
    }
  }
 
  while ((mmcPing() != MMC_SUCCESS));      // Wait till card is inserted
}

// function to take data
void mesures(unsigned short *val)
{
  ADC12CTL0|=ADC12SC; // start conversion
  do {} while ((ADC12CTL1 & 1)!=0);
  val[0] = ADC12MEM0;                   // Move results, IFG is cleared
  val[1] = ADC12MEM1;                   // Move results, IFG is cleared
  val[2] = ADC12MEM2;                   // Move results, IFG is cleared       
}

void acquisition()
{
  unsigned short T,H,Ct;
  float temp, Vtemp, Vhum,hum,Vcurrent,current;
  unsigned short results[3];    
  unsigned char chaine [200], buffer[512];
 
  mesures(results);  
  // temperature
  T=results[0];
  Vtemp=((float)T*3.3/4095);
  temp= Vtemp/0.04;  //sensibilite capteur 40mV/°c
  // Humidity
  H=results[1];
  Vhum=((float)H*3.3/4095);
  hum=(Vhum+0.5)*(0.9237-0.0041*temp+0.00004*temp*temp)/(0.0305+0.000044*temp-0.0000011*temp*temp); //humi=f(temp)
  // Current
  Ct=results[2];
  Vcurrent=((float)Ct*3.3/4095);
  current=(Vcurrent-2.5)/0.20833;       // mesure de courant
 
  snprintf(chaine,sizeof(chaine),"%d-%d-%d %2d:%2d:%2d \t temperature= %.3f \t humidity=%.3f \t current=%.3f\n",year,month,day,h,min,seconds,temp,hum,current);
  //str_rs1(chaine);   
 
 
  // store to mmc
  initSDMMC();
  memset(buffer,0,sizeof(buffer));
  mmcReadSector(0, buffer);   
  //str_rs1(buffer);
  numblocks=atoi(buffer);
  numblocks++;
  if ( numblocks > totalBlocks )
    numblocks=0;
  memset(buffer,0,sizeof(buffer));
  snprintf(buffer,sizeof(buffer),"%ld",numblocks);
  //str_rs1(buffer);
  mmcWriteSector(0, buffer);
  memset(buffer,0,sizeof(buffer));
  snprintf(buffer,sizeof(buffer),"%d-%d-%d %2d:%2d:%2d \t temperature= %.3f \t humidity=%.3f \t current=%.3f\n",year,month,day,h,min,seconds,temp,hum,current);
  mmcWriteSector(numblocks, buffer);
  mmcGoIdle();     
}

void acquisitionOnlySerial()
{
  unsigned short T,H,Ct;
  float temp, Vtemp, Vhum,hum,Vcurrent,current;
  unsigned short results[3];    
  unsigned char chaine [200];
 
  mesures(results);  
  // temperature
  T=results[0];
  Vtemp=((float)T*3.3/4095);
  temp= Vtemp/0.04;  //sensibilite capteur 40mV/°c
  // Humidity
  H=results[1];
  Vhum=((float)H*3.3/4095);
  hum=(Vhum+0.5)*(0.9237-0.0041*temp+0.00004*temp*temp)/(0.0305+0.000044*temp-0.0000011*temp*temp); //humi=f(temp)
  // Current
  Ct=results[2];
  Vcurrent=((float)Ct*3.3/4095);
  current=(Vcurrent-2.5)/0.20833;       // mesure de courant
 
  snprintf(chaine,sizeof(chaine),"|%d-%d-%d %2d:%2d:%2d \t temperature= %.3f \t humidity=%.3f \t current=%.3f\n",year,month,day,h,min,seconds,temp,hum,current);
  str_rs1(chaine);   
}
/////////////////////////////////////////////////
void main(void)
{
  unsigned int nb[LENFORPARAMETERS],j,k;
  unsigned char parameters[NUMBEROFPARAMETERS][LENFORPARAMETERS],ch[200],buffer[512];
  unsigned int newFREQ;
  unsigned long i,nbb,lines;
 
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
 
  // initialisations
  init_rs1_115200();
  init_ADC();
  initTimer();
 
  initSDMMC();
  // Read the Card Size from the CSD Register
  cardSize =  mmcReadCardSize();
  memset(ch,0,sizeof(ch));
  snprintf(ch,sizeof(ch),"%ld\n",cardSize);
  str_rs1(ch);  
 
  totalBlocks=cardSize/512;
  memset(ch,0,sizeof(ch));
  snprintf(ch,sizeof(ch),"%ld\n",totalBlocks);
  str_rs1(ch);
 
  numblocks=0;
  memset(buffer,0,sizeof(buffer));
  snprintf(buffer,sizeof(buffer),"%ld",numblocks);
  mmcWriteSector(0, buffer);
  mmcGoIdle();
  ////////////////  main loop ////////////////////////
  while(1)
  { 
    _BIS_SR(LPM0_bits + GIE);                // Enter LPM0 w/ interrupt
   
    if ( FREQ <61 )
    {
      if ( seconds%FREQ == 0)
        acquisition();
    }
    else if ( FREQ > 60 )
    {
      newFREQ=FREQ/60;
      if ( min > 0 && min%newFREQ == 0 && seconds == 0)
        acquisition();
    }
   
    switch(mode)
    {
    case 0 :
      {
        if ( okbeg == 1 && okend == 1 )
        {
          k=0;
          for (j=0; j<LENFORPARAMETERS;j++)
            nb[j]=0;
          for (j=0; j<NUMBEROFPARAMETERS;j++)
            memset(&parameters[j][0],0,sizeof(parameters[j]));
         
          str_rs1(com);
          for (j=0;j<strlen(com); j++)
          {
            if (com[j] != ';' && com[j] != '\0')
            {
              if ( k>0)
                parameters[k][j-nb[k-1]]=com[j];
              else
                parameters[k][j]=com[j];
            }
            else
            {
              nb[k]=j+1;
              if (k > 0)
                parameters[k][j-nb[k-1]]='\0';
              else
                if (com[j] != ';')
                  parameters[k][j]=com[j];
              k++;
            }
          }
         
          for (j=0;j<=k;j++)
          {
            str_rs1(parameters[j]);
            str_rs1("\r\n---\r\n");
          }
         
          memset(ch,0,sizeof(ch));
          snprintf(ch,sizeof(ch),"got %d parameters\n",k);
          str_rs1(ch);
          // traitement
          // k = number of values [com;val1;val2;...]
          if ( strcmp(parameters[0],"st")==0 && k==6)  // [st;y;m;d;h;min;secs] set time
          {
            str_rs1("\r\n set time \r\n");
            year=atoi(parameters[1]);
            month=atoi(parameters[2]);
            day=atoi(parameters[3]);
            h=atoi(parameters[4]);
            min=atoi(parameters[5]);
            seconds=atoi(parameters[6]);
           
            // leap year
            if ( year%4 == 0 && year%100 != 0 || year%400 == 0 )
              daysInMonth[2] = 29;
            else
              daysInMonth[2] = 28;
           
            str_rs1("\r\n new time set \r\n");
          }
          if ( strcmp(parameters[0],"re")==0 && k==1)  // [re;1] read mmc card
          {
            str_rs1("\r\n readmmc \r\n");
            initSDMMC();
            memset(buffer,0,sizeof(buffer));
            mmcReadSector(0, buffer);
            nbb=atoi(buffer);
            str_rs1(buffer);
           
            for (i = 1; i < nbb; i++)
            {
              memset(buffer,0,sizeof(buffer));
              mmcReadSector(i, buffer);    // read a size Byte big block beginning at the address.
              str_rs1(buffer);
            }
            mmcGoIdle();
            str_rs1("\r\n readmmc done\r\n");
          }
          if ( strcmp(parameters[0],"gt")==0 && k==1)  // [gt;1] get time
          {
            memset(buffer,0,512);
            snprintf(buffer,sizeof(buffer),"%d-%d-%d %2d:%2d:%2d\n",year,month,day,h,min,seconds);
            str_rs1(buffer);
          }
          if ( strcmp(parameters[0],"rs")==0 && k==1)  // [rs;1]  reset numblocks to 0
          {
            initSDMMC();
            numblocks=0;
            memset(buffer,0,sizeof(buffer));
            snprintf(buffer,sizeof(buffer),"%ld",numblocks);
            mmcWriteSector(0, buffer);
            mmcGoIdle();
          }
          if ( strcmp(parameters[0],"rl")==0 && k==1)  // [rl;N]   read last N lines from SD MMC
          {
            str_rs1("\r\n readmmc last lines \r\n");
            initSDMMC();
            memset(buffer,0,sizeof(buffer));
            mmcReadSector(0, buffer);
            nbb=atoi(buffer);
            str_rs1(buffer);
            lines=atoi(parameters[1]);
           
            for (i = nbb-lines; i < nbb; i++)
            {
              memset(buffer,0,sizeof(buffer));
              mmcReadSector(i, buffer);    // read a size Byte big block beginning at the address.
              str_rs1(buffer);
            }
            mmcGoIdle();
            str_rs1("\r\n readmmc last lines done\r\n");
          }
         
          if ( strcmp(parameters[0],"ac")==0 && k==1)  // [ac;1] force acquisition and sends to serial port
          {
            acquisitionOnlySerial();
          }
          // fin traitement
         
          k=0;
          for (j=0; j<LENFORPARAMETERS;j++)
            nb[j]=0;
          for (j=0; j<NUMBEROFPARAMETERS;j++)
            memset(&parameters[j][0],0,sizeof(parameters[j]));
          mode=1;
          okbeg=0;
          okend=0;
          memset(com,0,LENFORCOM);
          *com='\0';
          m=0;
        }
       
       
        if ( m >= LENFORCOM )
        {
          memset(com,0,LENFORCOM);
          *com='\0';
          m=0;
        }
        break;
      }
    default: break;
    }
  }
}// end of main

// Timer A0 interrupt service routine
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
  P1OUT ^= 0x01;                            // Toggle P1.0
  seconds++;
  if (seconds==60)
  {
    seconds=0;
    min++;
  }
  if (min==60)
  {
    min=0;
    h++;
  }
  if (h==24)
  {
    h=0;
    day++;
  }
  if ( day == daysInMonth[month]  )
  {
    month++;
    day=1;
  }
  if ( month == 12 )
  {
    month=1;
    year++;
    // leap year
    if ( year%4 == 0 && year%100 != 0 || year%400 == 0 )
      daysInMonth[2] = 29;
    else
      daysInMonth[2] = 28;
  }
 
  _BIC_SR_IRQ(LPM0_bits);
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USC0RX_ISR(void)
{
  while (!(IFG2&UCA0RXIFG));  
  if ( UCA0RXBUF == '[' )
    okbeg=1;
  if ( UCA0RXBUF == ']' )
    okend=1;
  if ( okbeg == 1 &&  UCA0RXBUF != ']'  &&  UCA0RXBUF != '[')
  {
    com[m]=UCA0RXBUF; 
    m++;
    mode=0;
  }
  _BIC_SR_IRQ(LPM0_bits);
}

  • In hal_MMC_hardware_board.h, I use the following settings

    // SPI port definitions              // Adjust the values for the chosen
    #define SPI_PxSEL         P5SEL      // interfaces, according to the pin
    #define SPI_PxDIR         P5DIR      // assignments indicated in the
    #define SPI_PxIN          P5IN       // chosen MSP430 device datasheet.
    #define SPI_PxOUT         P5OUT
    #define SPI_SIMO          0x02
    #define SPI_SOMI          0x04
    #define SPI_UCLK          0x08

    //----------------------------------------------------------------------------
    // SPI/UART port selections.  Select which port will be used for the interface
    //----------------------------------------------------------------------------
    //#define SPI_SER_INTF      SER_INTF_USART1  // Interface to MMC
    #define SPI_SER_INTF      SER_INTF_BITBANG  // Interface to MMC

  • You're not the first one experiencing this.
    Some MMC/SD cards tend to cease operation after some time (hours).
    The code must be altered to deal with the card no longer responding. It needs reinitialisation then.

    The TI library has almost no error management. Except for the init procedure (which is also not really complete) it always assumes success in all operations. And crashes/hangs if something is not working as expected.

    I put the init code into a state machine running in a timer interrupt. It detects card insertion and starts the init procedure as soon as a card is inserted, it detects removal and handles re-init if the card fails.
    And all of the TI library functions have been extended with failsafe checks to avoid lockup.

    There is another thread (in fact there are several, but one is fairly exhaustive) about MMC/SD cards and SPI. I think I published a flow diagram or at least a detailed description of the init process there. Also, some others have reported the failure after sometime and their solution there. Use the search function (and be patient while trying to do so)

  • Thanks !

    Well I even loose serial communication ... The plan is to put this datalogger underwater for many months :-)

    I will try to find the solution using the search function. Meanwhile, I was trying to use

    #define SPI_SER_INTF      SER_INTF_USCIB1

    instead of

    SER_INTF_BITBANG

    ( the port 5 is used)

    Cheers

    Karim

  • karim bernardet said:
    Meanwhile, I was trying to use
    #define SPI_SER_INTF      SER_INTF_USCIB1
    instead of
    SER_INTF_BITBANG

    I don't think it is the MSP side which is failing. It's the card which stops responding to a valid communication.
    I don't exactly remember how the one with the similar problem solved it. Re-initializing the card? card power cycle? Well, you'll see if you find the thread.

  •  I found your thread about the initialisation steps (05-28-2010) but not the one with the solution. Could it be the sd code lost in a while loop ?

  • karim bernardet said:
    I found your thread about the initialisation steps (05-28-2010) but not the one with the solution

    Could be further down the thread, or in another thread started near this one (I remember there were several).
    In any case not older than March - I started here in March :)

    karim bernardet said:
    Could it be the sd code lost in a while loop ?

    Definitely. There are many loops in this library which simply expect that something will happening the 'normal' way. If it doesn't, then these loops may loop forever. No timeout, no maximum loop count, often not even an error code check. e.g. 'wait for the status, then wait for the data token' - even if the status indicates that there will be no data token. Ever.

  • Many thanks. It works now using timeour in the while.

     

    Cheers

     

    Karim

  • hello all.,

    i am trying to log internal temprature of cc430 to a mmc card. After programming, when i try to see the logged data in mmc via PC or desktop. it ask for formatting the disk.

    what could be the problem.. how can i see the logged data in mmc card?

    Thanks

  • which file system does the above code support?
    whether it is fat(default), fat32, exfat ?
    reply
  • The code simply writes a text stream to the MMC card. Starting at sector 1, while sector 0 gets a counter to the last block written to.
    If you open the card with a raw sector reader (not using any file system driver), you will be able to see the written content.
    I'm using this method for logging too. In one project, the timecode determines the absolute position in the card memory (1-year cyclic log), in other projects, data is just sequentially written.
    Think of it not as a storage device but rather as an extended memory chip.

**Attention** This is a public forum