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.

MSP430 and SPI Memory

Other Parts Discussed in Thread: MSP430G2452

Hi, Please help with memory MR25H10. It's MRAM but communication should be the same as other SPI memory (EEPROM, Flash...). Do not know where my mistake? Thank you.

#include <msp430g2452.h>

#define MR25H10_DIR P2DIR
#define MR25H10_OUT P2OUT

#define MR25H10_HOLD    BIT0
#define MR25H10_SCK        BIT1
#define MR25H10_SI        BIT2
#define MR25H10_WP        BIT3
#define MR25H10_SO        BIT4
#define MR25H10_CS        BIT5

#define Write_enable             00000110
#define Write_disable             00000100
#define Read_status_register     00000101
#define Write_status_register    00000001
#define Read_data_bytes            00000011
#define Write_data_bytes        00000010
#define Enter_sleep_mode        10111001
#define Exit_sleep_mode            10101011

unsigned char MR25H10_ReadData;

void MR25H10_Init(void);
void MR25H10_Pulse(void);
void MR25H10_Write_bytes(unsigned char WriteBytes);
void MR25H10_Write_data (unsigned char Adress, unsigned char Write_Data);
void MR25H10_Read(unsigned char Adress);

void MR25H10_Init(void)
{
    MR25H10_OUT &= ~(MR25H10_SCK|MR25H10_SI|MR25H10_SO|MR25H10_CS);
    MR25H10_DIR |=(MR25H10_SCK|MR25H10_SO|MR25H10_CS|MR25H10_SI);
}

void MR25H10_Pulse(void)                                //Only for pin test
{
        MR25H10_OUT |= MR25H10_SCK;                        //Pulse rising edge
        __delay_cycles(1000);
        MR25H10_OUT &= (~MR25H10_SCK);                    //Pulse falling edge
        __delay_cycles(1000);
}

void MR25H10_Write_bytes(unsigned char WriteBytes)
{
       unsigned char W_BitCount;

       for(W_BitCount=0;W_BitCount<8;W_BitCount++)
          {
                if((WriteBytes<<W_BitCount)&0x80)
                  {
                        MR25H10_OUT |= MR25H10_SI;            //SI high
                    __delay_cycles(50);
                  }
                       else
                       {
                           MR25H10_OUT &= (~MR25H10_SI);        //SI low
                       __delay_cycles(50);
                       }
               MR25H10_OUT &= (~MR25H10_SCK);                //Pulse falling edge
               __delay_cycles(50);
               MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge
               __delay_cycles(50);

          }
}

void MR25H10_Write_data (unsigned char Adress, unsigned char Data_for_write)
{
    MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
    __delay_cycles(50);
    MR25H10_Write_bytes(Write_enable);                    //Write enable instruction
    MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
    __delay_cycles(50);
    MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
    __delay_cycles(50);
    MR25H10_Write_bytes(Write_data_bytes);                //Send write instruction
    MR25H10_Write_bytes(Adress);                        //Send address
    MR25H10_Write_bytes(Data_for_write);                //Send data
    MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
    __delay_cycles(50);
}

void MR25H10_Read(unsigned char Adress)
{
    unsigned char R_BitCount;
    MR25H10_ReadData = 0;

    MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
    __delay_cycles(50);
    MR25H10_Write_bytes(Write_enable);                    //Write enable instruction
    MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
    __delay_cycles(50);
    MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
    __delay_cycles(50);
    MR25H10_Write_bytes(Read_data_bytes);                //Send read instruction
    MR25H10_Write_bytes(Adress>>8);
    MR25H10_Write_bytes(Adress);                        //Send address

       for(R_BitCount=0;R_BitCount<8;R_BitCount++)
       {
         MR25H10_ReadData<<=1;
         MR25H10_OUT &= (~MR25H10_SCK);                    //Pulse falling edge
         __delay_cycles(50);
         MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge
         __delay_cycles(50);

         if(P2IN&MR25H10_SO)
         {
             MR25H10_ReadData++;
         }
         else
         {
           _NOP();
         }

       }

              MR25H10_OUT |= MR25H10_CS;                    //Chip select high = disable
              __delay_cycles(50);
              return(MR25H10_ReadData);
}























  • Marek Prochazka said:
    #define Write_enable             00000110
    #define Write_disable             00000100
    #define Read_status_register     00000101
    #define Write_status_register    00000001
    #define Read_data_bytes            00000011
    #define Write_data_bytes        00000010
    #define Enter_sleep_mode        10111001
    #define Exit_sleep_mode            10101011

    looks like you're defining some binary commands here. In that case you need to define them in decimal or hex:

    #define Write_data_bytes        2

    or

    #define Write_data_bytes        0x2

    otherwise it's equivalent to this:

    #define Write_data_bytes        10

    or this:

    #define Write_data_bytes        0xa

    and then that's a different command which wouldn't be recognized by the memory device.

  • Hi, thank you very much. Unfortunately, it still does not work, I deleted the delay and rewrite binary to hex but still nothing. I function "Init" well?

    #include <msp430g2452.h>

    #define MR25H10_DIR P2DIR
    #define MR25H10_OUT P2OUT

    #define MR25H10_HOLD    BIT0
    #define MR25H10_SCK        BIT1
    #define MR25H10_SI        BIT2
    #define MR25H10_WP        BIT3
    #define MR25H10_SO        BIT4
    #define MR25H10_CS        BIT5

    #define Write_enable             0x06
    #define Write_disable             0x04
    #define Read_status_register     0x05
    #define Write_status_register    0x01
    #define Read_data_bytes            0x03
    #define Write_data_bytes        0x02
    #define Enter_sleep_mode        0xB9
    #define Exit_sleep_mode            0xAB

    unsigned char MR25H10_ReadData;

    void MR25H10_Init(void);
    void MR25H10_Pulse(void);
    void MR25H10_Write_bytes(unsigned char WriteBytes);
    void MR25H10_Write_data (unsigned char Adress, unsigned char Write_Data);
    void MR25H10_Read(unsigned char Adress);

    void MR25H10_Init(void)
    {
        MR25H10_OUT &= ~(MR25H10_SCK|MR25H10_SI|MR25H10_SO|MR25H10_CS);
        MR25H10_DIR |=(MR25H10_SCK|MR25H10_SO|MR25H10_CS|MR25H10_SI);
    }

    void MR25H10_Pulse(void)                                //Only for pin test
    {
            MR25H10_OUT |= MR25H10_SCK;                        //Pulse rising edge
            __delay_cycles(1000);
            MR25H10_OUT &= (~MR25H10_SCK);                    //Pulse falling edge
            __delay_cycles(1000);
    }

    void MR25H10_Write_bytes(unsigned char WriteBytes)
    {
           unsigned char W_BitCount;

           for(W_BitCount=0;W_BitCount<8;W_BitCount++)
              {
                    if((WriteBytes<<W_BitCount)&0x80)
                      {
                            MR25H10_OUT |= MR25H10_SI;            //SI high
                      }
                           else
                           {
                               MR25H10_OUT &= (~MR25H10_SI);        //SI low
                           }
                   MR25H10_OUT &= (~MR25H10_SCK);                //Pulse falling edge
                   MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge

              }
    }

    void MR25H10_Write_data (unsigned char Adress, unsigned char Data_for_write)
    {
        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Write_enable);                    //Write enable instruction
        MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Write_data_bytes);                //Send write instruction
        MR25H10_Write_bytes(Adress);                        //Send address
        MR25H10_Write_bytes(Data_for_write);                //Send data
        MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
    }

    void MR25H10_Read(unsigned char Adress)
    {
        unsigned char R_BitCount;
        MR25H10_ReadData = 0;

        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Write_enable);                    //Write enable instruction
        MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Read_data_bytes);                //Send read instruction
        MR25H10_Write_bytes(Adress>>8);
        MR25H10_Write_bytes(Adress);                        //Send address

           for(R_BitCount=0;R_BitCount<8;R_BitCount++)
           {
             MR25H10_ReadData<<=1;
             MR25H10_OUT &= (~MR25H10_SCK);                    //Pulse falling edge
             MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge

             if(P2IN&MR25H10_SO)
             {
                 MR25H10_ReadData++;
             }
             else
             {
               _NOP();
             }

           }

                  MR25H10_OUT |= MR25H10_CS;                    //Chip select high = disable
                  return(MR25H10_ReadData);
    }
























  • Ok, the next problem is that you're not using the built in SPI module which would do a lot of low level work for you. Instead you're trying to implement SPI comms yourself.

    For example here:

    Marek Prochazka said:
    void MR25H10_Write_bytes(unsigned char WriteBytes)
    {
           unsigned char W_BitCount;

           for(W_BitCount=0;W_BitCount<8;W_BitCount++)
              {
                    if((WriteBytes<<W_BitCount)&0x80)
                      {
                            MR25H10_OUT |= MR25H10_SI;            //SI high
                      }
                           else
                           {
                               MR25H10_OUT &= (~MR25H10_SI);        //SI low
                           }
                   MR25H10_OUT &= (~MR25H10_SCK);                //Pulse falling edge
                   MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge

              }
    }

    Your SCK will be totally unsuitable-- the low duty cycle will be very short but high ducty cycle will be long because you're doing this without any pause in the middle:

    Marek Prochazka said:
                   MR25H10_OUT &= (~MR25H10_SCK);                //Pulse falling edge
                   MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge

    . And even if the duty cycle was good enough for the memory to clock in the serial data, you will totally miss the response coming back from it. You can't read like this from SPI because reading happens synchronously with writing-- if you're writing 8bits then you write 1 bit and receive 1 bit at the same SCK cycle and if you need to send 8 bits and then receive 8 from the device then you really have to send 8 bits and then another 8 dummy bits and read all that comes back while sending dummy bits.

    Either way you really should use the built in SPI functionality and study the SPI comms standard. Please read this:

    http://www.ti.com/lit/ug/slau144i/slau144i.pdf

    pages 447-460.

  • Oh and by the way in your function :

    void MR25H10_Read(unsigned char Adress)

    Even if your implementation of SPI was fine, it would not read data but rather count how many 1s was in the last received byte.

    And hey, it's a "void" function and you're trying to return something at the end of it?? :)

  • Thank you very much for your interest. Thus, as I do with those bits? I do not want to use an external module, I want to try this.

    I take from this example:  http://www.codeforge.com/read/186889/FM25L256.c__html

    #include <msp430g2452.h>

    #define MR25H10_DIR P2DIR
    #define MR25H10_OUT P2OUT

    #define MR25H10_HOLD    BIT0
    #define MR25H10_SCK        BIT1
    #define MR25H10_SI        BIT2
    #define MR25H10_WP        BIT3
    #define MR25H10_SO        BIT4
    #define MR25H10_CS        BIT5

    #define Write_enable             0x06
    #define Write_disable             0x04
    #define Read_status_register     0x05
    #define Write_status_register    0x01
    #define Read_data_bytes            0x03
    #define Write_data_bytes        0x02
    #define Enter_sleep_mode        0xB9
    #define Exit_sleep_mode            0xAB

    unsigned char MR25H10_ReadData;

    void MR25H10_Init(void);
    void MR25H10_Pulse(void);
    void MR25H10_Write_bytes(unsigned char WriteBytes);
    void MR25H10_Write_data (unsigned char Adress, unsigned char Write_Data);
    unsigned char MR25H10_Read(unsigned char Adress);

    void MR25H10_Init(void)
    {
        MR25H10_OUT &= ~(MR25H10_SCK|MR25H10_SI|MR25H10_SO|MR25H10_CS);
        MR25H10_DIR |=(MR25H10_SCK|MR25H10_SO|MR25H10_CS|MR25H10_SI);
    }

    void MR25H10_Pulse(void)                                //Only for pin test
    {
            MR25H10_OUT |= MR25H10_SCK;                        //Pulse rising edge
            __delay_cycles(1000);
            MR25H10_OUT &= (~MR25H10_SCK);                    //Pulse falling edge
            __delay_cycles(1000);
    }

    void MR25H10_Write_bytes(unsigned char WriteBytes)
    {
           unsigned char W_BitCount;

           for(W_BitCount=0;W_BitCount<8;W_BitCount++)
              {
                    if((WriteBytes<<W_BitCount)&0x80)
                      {
                            MR25H10_OUT |= MR25H10_SI;            //SI high
                      }
                           else
                           {
                               MR25H10_OUT &= (~MR25H10_SI);        //SI low
                           }
                   MR25H10_OUT &= (~MR25H10_SCK);                //Pulse falling edge
                   __delay_cycles(150);
                   MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge
                   __delay_cycles(150);

              }
    }

    void MR25H10_Write_data (unsigned char Adress, unsigned char Data_for_write)
    {
        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Write_enable);                    //Write enable instruction
        MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Write_data_bytes);                //Send write instruction
        MR25H10_Write_bytes(Adress);                        //Send address
        MR25H10_Write_bytes(Data_for_write);                //Send data
        MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
    }

    unsigned char MR25H10_Read(unsigned char Adress)
    {
        unsigned char R_BitCount;
        MR25H10_ReadData = 0;

        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Write_enable);                    //Write enable instruction
        MR25H10_OUT |= MR25H10_CS;                            //Chip select high = disable
        MR25H10_OUT &= (~MR25H10_CS);                        //Chip select low = enable
        MR25H10_Write_bytes(Read_data_bytes);                //Send read instruction
        MR25H10_Write_bytes(Adress>>8);
        MR25H10_Write_bytes(Adress);                        //Send address

           for(R_BitCount=0;R_BitCount<8;R_BitCount++)
           {
             MR25H10_ReadData<<=1;
             MR25H10_OUT &= (~MR25H10_SCK);                    //Pulse falling edge
             __delay_cycles(150);
             MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge
             __delay_cycles(150);

             if(P2IN&MR25H10_SO)
             {
                 MR25H10_ReadData++;
             }
             else
             {
               _NOP();
             }

           }

                  MR25H10_OUT |= MR25H10_CS;                    //Chip select high = disable
                  return(MR25H10_ReadData);
    }
























  • I still advise you to use USCI functionality. But if you really want to do it the hard way then try this:

    void MR25H10_Write_bytes(unsigned char WriteBytes)
    {
           unsigned char W_BitCount;

           for(W_BitCount=0;W_BitCount<8;W_BitCount++)
              {

                   MR25H10_OUT &= (~MR25H10_SCK);                //Pulse falling edge
                   __delay_cycles(150);


                    if((WriteBytes<<W_BitCount)&0x80)
                      {
                            MR25H10_OUT |= MR25H10_SI;            //SI high
                      }
                           else
                           {
                               MR25H10_OUT &= (~MR25H10_SI);        //SI low
                           }

                   MR25H10_OUT |= MR25H10_SCK;                    //Pulse rising edge
                   __delay_cycles(150);

              }
    }

    And then experiment with the two "__delay_cycles(150);" calls changing 150 to all sorts of values until you get a more or less square waveform (you'll more than likely need different amount of delayed cycles in each of the functions-- maybe 130 in the first one and 170 in the second one for example). Without an oscilloscope that will be a nightmare.

    Oh yes, and that's of course only if your memory device works on that clock polarity. Maybe it clocks out new bit on falling edge? In that case you'll need to redo your code again whereas with USCI that would just be a setting bit.

    And also if you're using anything else in that code (some other interrupts for example) then your SCK will go awry again. Well, try it if you wish and let me know but that's the hard way :).

  • The signal is rectangular. in datasheet:   inputs     are    captured     on    the     rising    edge    of     the     clock    and     data     outputs    occur    on    the     falling     
    edge    of     the     clock.   

  • Oh, sorry by

    Arturs Elksnis said:
    square waveform

    I meant a waveform with 50/50% duty cycle.

    You're right, of course it's square :).

    An oscilloscope would help you though getting the duty cycles right.

  • Oh, and if the data output occurs on falling edge then of course in your "MR25H10_Read" function you need to read the bit after you make the edge fall. Well there's a few combinations to try out. How do you verify what gets sent and what comes back from the memory?

    Good luck.

  • I use UART:

              if(Read_value == 7)
              {

                  MR25H10_Write_data (0x80,0x05);  //Write "0x05" to adress 0x80
              }

              if(Read_value == 9)
              {
                  MR25H10_Read(0x80);
                  Transmit(MR25H10_ReadData);  //Read from adress 0x80
              }

    But value read from MCU to UART is 0

  • Marek Prochazka said:
    I do not want to use an external module,

    The 2452 you're using has a built-in 'USI' module that does the clock timing and biit shifting for you. It is not an 'external 'module.

    The key to success in embedded programming is using the available hardware as much a spossible and do only the really necessary part in software. There have been projects that sent he CPU to sleep after initialization. And the embedded hardware was doing all the work by itself.

    The 2453 even has an USCI module that makes all this even more convenient. Just stuff the bytes in the output reister and read them form input register.

    However, doing htings in software will teach you a lot. And somethimes, it is the only way, e.g. if the hardware funcitonality isn't available at the pin you're needing it. Or if you need more instances than available in hardware.

**Attention** This is a public forum