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.

working of spi in msp430 f2013

Other Parts Discussed in Thread: MSP430F2012

Hi

I am trying to understand how the spi buffer works between reading and writing. How does the msp430 distinguish between read and write operations when using the spi mode. There is a common register USISRL for both read and write buffering. So if I want to read a byte then I do

USICTL0 &= ~USIIFG; // Clear the interrupt flag

USICNT = 0x08;

while(USIIFG & USICTL0 != 0x01);

and to write I do

USICTL0 &= ~USIIFG; // Clear the interrupt flag

USISRL = 0xAB; //Where 0xAB is the data to be TXed.

USICNT = 0x08;

while(USIIFG & USICTL0 != 0x01);

 

What happens to the contents of the USISRL register ? Does it clock in a bit into the register for every bit it clocks out ?

Thank You

 

 

  • homer123 said:
    How does the msp430 distinguish between read and write operations when using the spi mode.

    It doesn't. SPI doesn't. At every clock pulse, a bit is sent and a bit is received.

    If you're master, then you start clocking by writing something. And once you have sent the data you wrote, you also have received the same amount. If you don't write, you don't receive. If oyu only want to receive, you'll have to make dummy writes of a don't care value.

    Being an SPI master is the most easy job of all, once you understood how SPI works (read-by-write, input/output buffering etc.). It' smuch easier to handle than UART or I2C and the basic hardware is just a simple, cheap circuit. That's why it is so popular.

    Slave operation is, however, very difficult and better left to the pros. It's best bought with the peripheral chip (sensor, memory etc.). If you need to do it on an MSP, be prepare to forget about good programming style and learn how to write tight, efficient, deterministic assembly code and how to count processor cycles.
    As a slave, you will be clocked and at each clock you'll receive a bit but also send a bit. If you didn't prepare something in time for being written, the master will receive '1' bits from you and will not be able to determine whether you actually wrote 0xff or didn't write anything at all.
    Being an SPi slave is not an easy job (it's the most difficult thing of all!) because you'll have to be ready when the clock pulse comes. The master knows no mercy. If the call comes, be ready or die.

  • I always assumed that the USI register worked like this:

    http://en.wikipedia.org/wiki/File:SPI_8-bit_circular_transfer.svg

    The data loaded into the register is transferred out as new data is transferred in.  So a transaction usually looks something like:
    Write USISRL      // output data
    Start transaction  // if master
    Wait for complete
    Read USISRL    // input data

    If you're used to the USCI peripheral I can see how this wouldn't be expected as it has one buffer for TX and one buffer for RX.

     

    -memoryleak

  • Hi

    Thank you both for the information. That clears it up.

     

    Have any one here used the C25LC640A    spi based 64k eeprom. I am trying to write and read from it using the msp430 and that is where I ran into problems. My code is attached below. I am first trying to write enable the chip and checking if the write enable bit is set in the status register before I start writing to it.

    Any feedback on the code is much appreciated.

     

    Thank You

    Karthik K

     

     

    #include <msp430f2012.h>



    //Instruction set

    #define READ     0x03            //Read data from memory array begining at selected address
    #define WRITE     0x02            //Write data to memory array begining at selected address
    #define WRDI    0x04            //Reset the write enable latch (disable write operations)
    #define WREN    0x06            //Set the write enable latch (enable write operations)
    #define RDSR    0x05            //Read status register
    #define WDSR    0x01            //Write status register

    /******************************************************
    // Individual Functions
    ******************************************************/

    void Delay(unsigned int Value)              // Variable Delay Function
    {
      volatile unsigned int j=0;
      for (j=Value;j>0;j--);
    }

    void SysInit(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog
      BCSCTL1 = CALBC1_1MHZ + DIVA_3;           // Set DCO, ACLK Divide by 8
      DCOCTL = CALDCO_1MHZ;
    }

    void PortInit(void)
    {
      P1DIR = 0x63;                                //P1.5 is SCLK, P1.6 = SDO, P1.7 = SDI, P1.1=CS, P1.0 = LED
      P1OUT |= 0x00;                                //Turn on LED   
    }


    void SPI_Init(void)
    {
    //    _DINT();
    // SPI Master Mode
    // USIMST=1  USIIFG=0 (Operate)  USIIFL=1 (Idle)
      USICTL0 = USIPE7+USIPE6+USIPE5+USIMST+USISWRST;  // Port & USI mode setup; Hold at reset
      USICTL1 |= USIIE;                               // Counter interrupt, flag remains set
      USICKCTL = USIDIV_7 + USISSEL_2;          // Setup USI clocks: SCLK = SMCLK/2
      USICTL0 &= ~USISWRST;                     // Enable USI i.e release reset
      //USICNT = 0x00;
      //_EINT();
    }

    void SPI_write_enable()
    {
        P1OUT &= ~CS;
        USISRL        =     WREN;
        USICTL1        &=    ~USIIFG;
        USICNT        =    0x08;
        while((USICTL1 & USIIFG) != 0x01);
        P1OUT |= CS;       
    }

    char SPI_read_status_register()
    {
        char value;
       
        P1OUT &= ~CS;                    //Enable slave
        USISRL = RDSR;                    //Load transmit buffer with op code
                                        //for reading status register
        USICTL1 &= ~USIIFG;                 //Clear the interrupt flag
        USICNT=0x08;                    //Tx the data

        while((USICTL1 & USIIFG) != 0x01);        //Wait for Tx completion

        USICTL1        &=    ~USIIFG;         //Clear the interrupt flag
        USISRL = 0xFF;
        USICNT=0x08;                    //Read 8 bits
        while((USICTL1 & USIIFG) != 0x01);        //Wait for Rx completion
       
        value = USISRL;
       
        return value;
    }   

    //*************************************************
    // Main program
    //*************************************************

    void main ()
    {
    //unsigned int i;
    char status_reg1;
    char status_reg2;

    SysInit();
    PortInit();
    SPI_Init();
    status_reg1 = SPI_read_status_register();
    SPI_write_enable();
    status_reg2  = SPI_read_status_register();
    }

  • homer123 said:
    USISRL        =     WREN;
        USICTL1        &=    ~USIIFG;
        USICNT        =    0x08;
        while((USICTL1 & USIIFG) != 0x01);
       


    I'm not familiar with the USI SPI, but shouldn't you configure the SPI before you start the transfer?
    -> set USICNT before you write to USISRL

    On the other SPIs, the write to the output register immediately starts the transfer.

    But I may be wrong and since our fileserver is down at the moment, I cannot look at the datasheet.

    Also, at the end of the status register read, you do not release CS.

    Then check the datasheet of the chip. It might be that settign the write bit only enables write as long as CS isn't released. So you may have to
    - pull CS,
    - set write bit,
    - do the write,
    - release CS.

    Many slaves consider being deselected as reset condition for the entire transfer protocol, no matter at which point it was before.

    One more thing:
    Your Delay() function is flakey at best. Making the local variable volatile does not prevent the compiler from optimizing the whole loop away. The compiler KNOWS that nobody else but this very function has a reference to this variable, since its reference is never passed to any function nor is it a global variable. So the volatile keyword is void.
    You need to put a volatile operation such as __no_operation() into the loop, so at least this one is executed the given number of times. (the loop itself can still be unrolled, depending on the optimisation settings)

  • (Sorry, this is a tad late but may help others)

    Although MSP430x2xx Family User's Guide SLAU144B does not say state this for Master mode, I notice the USIOE (pg 10-3) is not explicitly enabled 

    USICTL0 = USIPE7+USIPE6+USIPE5+USIMST+USISWRST+USIOE; // Port & USI mode setup

    (By the way, USISWRST may default to already enabled and just requires to be disabled.)

     

    Re USICNT Jens-Michael

    It seems the USISR transfers out on the clock following the USICNT load, so it the statements are in the correct order.

    Although correct, I'm not sure that releasing CS at the end is the problem here,

    but since an INT has been triggered, that should be cleared:

        // Read Slave's returned Status Register byte
        USISRL = 0xFF;                                 // Now load transmit buffer with dummy '1's
        USICNT = 8;                                       // Count for 8 bits
        while((USICTL1 & USIIFG) != 0x01); // Wait for 
        USICTL1 &= ~USIIFG;                       // Clear USI interrupt flag

        value = USISRL;                                // Store USISR low byte content
       
        return value;

    }

    Also USIIFG is cleared automagically when USICNT is loaded (pg 10-15), so the explicit clearing statement

    USICTL1 &= ~USIIFG;             // Clear USI interrupt flag

    is not required (provided USIFGCC in the upper byte of USICNT is 0, which it is here).

**Attention** This is a public forum