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.

MSP430F248 SPI to EEPROM

Other Parts Discussed in Thread: MSP430F248

2/28/11 - Updated code in reply below

 

Hello, I'm currently trying to interface my MSP430F248 with a CAT25256 EEPROM. Right now I'm attempting set the WEL (Write enable) bit on the EEPROM's status register by sending the appropriate command. I enable the EEPROM by setting CS low and then load the command (WR_EN) into UCA0TXBUF. Then I do the same with RD_SR, which attempts to read the EEPROM status register.

I'm assuming since I'm not receiving anything on the UCA0RXBUF then it is not transmitting either. Its my first time attempting this MSP and SPI, so I'm not sure where I might have a mistake. Thanks for looking.

The code I have is below:

 

#include "msp430f248.h"

 

#define WR_EN 0x06

#define WR_DI 0x04

#define RD_SR 0x05

#define WR_SR 0x01

#define READ 0x03

#define WRITE 0x02

 

unsigned char temp;

void MemWrite(unsigned char);

unsigned char MemRead(unsigned char);

 

void main(void)

{

WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer

P3SEL |= 0x31;                             // P3.0,4,5 USCI_A0 option select

P3DIR |= 0x08;      // P3.3 Chip select

P3OUT |= 0x08; // Disable EEPROM

UCA0CTL0 |= UCMSB + UCMST + UCSYNC;  // 3-pin, 8-bit SPI master, Mode (0,0)

UCA0CTL1 |= UCSSEL_2;                     // SMCLK

UCA0BR0 |= 0x02;

UCA0BR1 = 0;

UCA0MCTL = 0;

UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**

 

P3OUT &= ~0x08; // Enable EEPROM

MemWrite(WR_EN); // Write enable command

P3OUT |= 0x08; // Disable EEPROM

 

P3OUT &= ~0x08; // Enable EEPROM

MemWrite(RD_SR); // Read status Register of EEPROM to ensure WEL bit is set

MemWrite(0xAA); // Write dummy values to push EEPROM status into UCA0RXBUF

P3OUT |= 0x08; // Disable EEPROM

}

 

void MemWrite(unsigned char TXdata)

{

while (!(IFG2 & UCA0TXIFG));            // USCI_A0 TX buffer ready?

UCA0TXBUF = TXdata;

while (!(IFG2 & UCA0RXIFG));            // USCI_A0 RX buffer ready?

temp = UCA0RXBUF;

IFG2 &= ~UCA0RXIFG;

}

 

  • Hi Thomas,

    this application note http://focus.ti.com/mcu/docs/litabsmultiplefilelist.tsp?sectionId=96&tabId=1502&literatureNumber=slaa405a&docCategoryId=1&familyId=342 uses a SPI flash memory and has a complete set of functions for dealing with the device.

    Maybe you should have a look at the app not to get jump-started with your SPI EEPROM.

    Rgds
    aBUGSworstnightmare 

  • Thomas Su said:

    while (!(IFG2 & UCA0RXIFG));            // USCI_A0 RX buffer ready?

    Are you saying that program control gets stuck right here?  Like an infinite loop?

    If so, your code doesn't look like it should cause this problem.  Any chance your C startup (code before "main") is configuring USCI A0?  Do your tools have an option to configure USCI A0 as std output or something?  If so, you would need to set UCSWRST before starting to configure USCI A0.  Above this statement:

    UCA0CTL0 |= UCMSB + UCMST + UCSYNC;  // 3-pin, 8-bit SPI master, Mode (0,0)

    As it stands now, your code is assuming UCSWRST is set when "main" gets control.  (It's a reasonable assumption, but I'm struggling to explain your observations.)

    Or are you just not getting back the expected values from the EEPROM?

    Jeff

  • I think I have managed to read values from the EEPROM. All I get is 0xFF but I guess its better than nothing. One of the problems was that I was writing an 8-bit address instead of a 16-bit address

    The main is the only code I have running, but I have added in UCSWRST in just in case.

    Seems like the problem now is I cannot write to the EEPROM. I think the problem is either in the WRITE ENABLE or possibly the Write Protect (WP) pin. I've tried different setups with no avail...

    I've updated my code to:

     

     

    void main(void)

    {

    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

    InitSPI();

    addr=0x00;

    P3OUT &= ~0x08;

    MemWrite(WR_EN); // Write enable command

    P3OUT |= 0x08;

     

    // Write to EEPROM

    P3OUT &= ~0x08; // Enable EEPROM

    MemWrite(WRITE); // Send WRITE Cmd

    MemWrite(addr>>8); // Send 1st addr byte

    MemWrite(addr); // Send 2nd addr byte

    MemWrite(0xAA); // Send Data

    P3OUT |= 0x08; // Disable EEPROM

     

    // Read EEPROM

    P3OUT &= ~0x08; // Enable EEPROM

    MemWrite(READ); // Send READ cmd

    MemWrite(addr>>8);

    MemWrite(addr);

    temp = MemWrite(0); // Send dummy data

    P3OUT |= 0x08;

    }

     

    void InitSPI()

    {

    P3SEL |= 0x31;                             // P3.0,4,5 USCI_A0 option select

    P3DIR |= 0x0C; // P3.2 Write Protect, P3.3 Chip select

    P3OUT |= 0x0C; // Disable EEPROM & write protect pin

    UCA0CTL1 |= UCSWRST;

    UCA0CTL0 |= UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master, mode (0,0)

    UCA0CTL1 |= UCSSEL_2; // SMCLK

    UCA0BR0 |= 0;

    UCA0BR1 = 0;

    UCA0MCTL = 0;

    UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**

    }

     

    char MemWrite(char TXdata)

    {

    while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?

    UCA0TXBUF = TXdata;

    while (!(IFG2 & UCA0RXIFG)); // USCI_A0 RX buffer ready?

    IFG2 &= ~UCA0RXIFG; // Reset UCA0RXIFG

    return UCA0RXBUF;

    }

     

  • SPI itself is bi-directional synchronous. That means you receive while you're transmitting. To get something, you have to send something. So the SPI hardware controls the clock timing (in master mode) by the trasnmitter and simultaneously receives something in return (whether you want it or not)

    The other thing is that the SPI hardware (or mroe exactly: the USCI module, including SPI, I2C and UART) is double buffered. That means an 'empty' TXBUF does not mean you're done sending. I tonly means that you can put the next value in. But the previous one is maybe still in the sending process.

    Depending on the software logic, it allows maximum throughput (no wait times between bytes) but it makes this logic more complex.

    So you need to make more and nested tests for the IFGs if you're going to make it really work.

    For your simple setup, however, an even more simplified version of your MemWrite should do well:

    UCA0TXBUF = TXdata; // start the transfer (since there is nothing sending, TXBUF s immediately empty again)
    while (!(IFG2 & UCA0RXIFG));            // wait until something receives. This also means that sending is completed
    temp = UCA0RXBUF;  // read the result, this also clears RXIFG. And since it is clear after reset, ther ei sno need to ever clear it manually or check for it before starting the next transfer.

     

  • Hi Thomas,

    Another thought for you.  Be sure you have the clock polarity and phase settings correct.  Many devices are Mode (0, 0) in Motorola's view of SPI clocking.  However, TI has reversed the meaning of the phase setting so 0 = 1 and 1 = 0.

    For example, a Mode (0, 0) SPI peripheral requires TI settings CKPL = 0 and CKPH = 1.

    Jeff

  • When I debug my code, the UCA0RXBUF does not clear automatically. Not sure why?

    But Jeff is correct, my clock phase was incorrect, seems to be writing fine now! Thank you all.

  • Thomas Su said:
    When I debug my code, the UCA0RXBUF does not clear automatically. Not sure why?

    Sure? Teh debugger won't halt the hardware module, especially in slave mode (when the clock is provided from the master and not derived from an internal, debugger-controlled clock).

    So when you step through the code, read RXBUF and then proceed to the line that checks for the flag, it is likely that just another byte has already arrived before the slow JTAG connection has read the register content. The debugger often proves useless when realtime events are part of the equation.

  • Thank you for the explanation. I'll go ahead and remove the manual reset of the flag from my code.

  • Hi, dude. I can't write into and read from the CAT25256 EEPROM right even with your code. Seems like every time I read from the RXBUF, the value is NULL. Can you please send me your exact code that is working ? Thank you very much.

  • Hi, I am having the same problem as Shawn and i am also getting NULL value all the time in RXBUF.

    So could you please give me your exact code with complete correction.

    Thanx in Advance.

  • Pankil Sheth said:
    i am also getting NULL value all the time in RXBUF.

    You can't get NULL value. You'll always get a number from 0 to 255. Each is as valid as any other.

    If a zero is not what you expected, then you have a problem in soft- or hardware.

    The only hardware problem would be that you can shorted your SOMI line to GND somehow. Maybe because the slave isn't powered and so its output pins is low.

    In software, well, if you no peer is there (talking to the void) or the port pins are not configured properly, you should get 255. (which can as well be a valid response).

    So it is more likely, that your high-level protocol is misinterpreting data or not handling the SPI transfer properly.
    Or you never send and receive something and RXBUF contains the initial 0 from power-on. (which is not a guaranteed initial value, but the most likely one)

    Remember, RXBUF always contains a value. RXIFG tells you whether a new value has arrived. And is automatically cleared when you read RXBUF the first time after new data has arrived.

    Also don't forget that the debugger doesn't stop the world turning. It stops the CPU, and (depending on MSP and configuration) it may also stop some clocks, but it doesn't freeze teh peripherlas. Interrupts are still coming in, datta arrives, maxbe much data, that overwrites each other whiel the debugger waits for you to press a key.
    There are things that break when you use a breakpoint (or single stepping).

**Attention** This is a public forum