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.

SPI unreliable at speed on MSP430G2553

Other Parts Discussed in Thread: MSP430G2553

I am trying to talk to a high-speed serial FRAM part (an FM25V20, lovely device) from a MSP430G2553. Data transfer to and from the RAM device is the major bottleneck on my application, so I want it to be as fast as possible. Unfortunately I'm finding that if I run the MSP430 at above 8MHz I appear to get corrupt transfers. Also some rather weird behaviour that doesn't mean much to me (see below).

I'm doing SPI in hardware in what I think is three-wire mode --- SCLK/MISO/MOSI/CS. The FRAM part says it runs up to 40MHz, so I wouldn't have thought there'd be any problem running it at the maximum speed of the MSP430. The two parts are on breadboard, with the wires connecting them about 30-40mm. Is this fast enough for that to be a problem?

I've spent a lot of time staring at my code and scratching my head; any chance someone could have a glance over and tell me if there's anything obviously wrong?

To set up the MSP430 clocks:

 ; set MCLK to precalibrated 16MHz from the DCO
clr.b &DCOCTL
mov.b &CALBC1_16MHZ, &BCSCTL1
mov.b &CALDCO_16MHZ, &DCOCTL
 ; SMCLK (used for SPI) is MCLK/1.
mov.b #DIVS_0|DIVM_0, &BCSCTL2

To initialise the USCI module:

  SPI_MODE_3 = UCCKPL

  bis.b #RAM_CS, &P1DIR                      ; RAM chip select
  bis.b #RAM_CS, &P1OUT                      ; set chip select high
  bis.b #RAM_SOMI|RAM_SIMO|RAM_SCLK, &P1SEL  ; assign pins to peripheral
  bis.b #RAM_SOMI|RAM_SIMO|RAM_SCLK, &P1SEL2

  bis.b #UCSWRST, &UCB0CTL1                  ; Reset USCI
  bis.b #SPI_MODE_3|UCMSB|UCMST|UCMODE0|UCSYNC, &UCB0CTL0 ; USCI to SPI mode
  bis.b #UCSSEL_2, &UCB0CTL1                 ; SMCLK
  mov.b #0, &UCB0BR0                         ; divider, low byte
  mov.b #0, &UCB0BR1                         ; divider, high byte
  bic.b #UCSWRST, &UCB0CTL1                  ; Reenable USCI

To actually do a transfer:

.macro FRAM_W XMIT
mov.b \XMIT, &UCB0TXBUF ; write outgoing
1:
bit.b #UCB0TXIFG, &IFG2
jnc 1b ; wait for transmission
.endm
.macro FRAM_RW XMIT, RECV
mov.b \XMIT, &UCB0TXBUF ; write outgoing
1:
bit.b #UCB0TXIFG, &IFG2
jnc 1b ; wait for transmission
1:
bit.b #UCB0RXIFG, &IFG2
jnc 1b ; wait for reception
mov.b &UCB0RXBUF, \RECV
.endm
readword:
bic.b #RAM_CS, &P1OUT ; enable FRAM
FRAM_W #READ ; opcode
FRAM_W #0x00 ; top byte of address
swpb rSRC
FRAM_W rSRC ; middle byte of address
swpb rSRC
FRAM_W rSRC ; low byte of address
 FRAM_RW #0, rMT ; read low byte
FRAM_RW #0, rMEM ; read high byte
swpb rMEM
bis rMT, rMEM
bis.b #RAM_CS, &P1OUT ; disable FRAM
ret

I'm very confused about they way the clocks are behaving. If I set MCLK to 16MHz, then use DIVS_1 in BCSCTL2 to try and make SMCLK 8MHz, nothing works. (Instant corrupt transfer.) Likewise, if I use DIVS_0 in BCSCTL2 and then set the divider in the USCI unit itself --- UCB0BR0 and UCB0BR1 --- then nothing works. If I set MCLK to 8MHz and leave the dividers at 1, it works fine (if slowly). (I don't actually understand UCB0BRx; the manual says that the SPI clock speed is BRCLK/UCB0BRx, except the value which seems to work most often is the default, which is zero...)

If I set MCLK to 12MHz, and the dividers both to 1, then it mostly works --- my code partially runs before it gets a corrupt transfer and dies. But it will frequently die at precisely the same place several times in a row! Which is really weird.

Also, if anyone has any advice on how to speed up the readword routine above, I'd be very grateful; I'm doing a zillion very rapid, very small random access transfers and it needs to be as fast as humanly possible. I'm sure it must be possible to pipeline the xmit/recv code more...

  • I notice someone having almost exactly this problem on a PIC:

    http://www.microchip.com/forums/m420176.aspx

    The solution there is that the PIC has this thing called 'slew rate', which as far as I can tell rounds the edges of the SPI clock and data pulses to reduce electrical noise. This totally screws up high-speed SPI, and defaults to on.

    Does the MSP430 do anything similar? A quick glance at the documentation doesn't show anything...

  • Hi David,

    You need to consider the SPI timing requirements of the two devices to determine the max SPI clk frequency where you will be getting valid data. On the G2553 datasheet on p. 33 you will find diagrams and tables of the SPI timing requirements of the MSP430.

    While you can source fUSCI at up to fSystem, this does not mean that you'll get valid data at that speed. The number you are looking for is fUCxCLK (you can see the period of this in the diagrams on p. 33) - this depends on things like the setup and hold timings required for valid data.

    You can calculate fUCxCLK for your particular system with this equation - some of the values come from your SPI master MSP430 datasheet, and some come from the requirements of your slave:

    fUCxCLK = 1/(2*tLO/HI)

    Where: tLO/HI >= max(tVALID,MO(USCI) + tSU,SI(Slave), tSU,MI(USCI) + tVALID,SO(Slave))

    So for example, if you had two G2553 SPI modules talking to each other, one as the master and one as the slave, the numbers look like this:

    tLO/HI = max(20ns+15ns, 75ns+50ns) = max(35ns,125ns) = 125ns.

    fUCxCLK = 1/(2*125ns) = 1/250ns= 4MHz.

    So that means that for two G2553 devices talking to each other you have to use USCBxBRx settings to set your SPI clock no higher than 4MHz to ensure valid communication. You'll need to do this same calculation but using the slave timings for your particular slave device.

    As a rule of thumb, I think most of the MSP430 USCI modules you'll get somewhere near this 4MHz number if you calculate them communicating with another MSP430, though the best thing to do is to calculate with the specs for your slave. One of the features of the eUSCI (enhanced USCI) module found on some parts is that it can support higher speeds.

    Regards,

    Katie

  • Hmm. Okay, so looking at the FM25V20 datasheet (which, naturally, not only uses different names for everything, but measures everything in such a different way that it's really hard to map to the G2553 datasheet), I see:

    tSU (which I think is tSU,SI) = 5ns
    tODV (which I think is tVALID,SO) = 9ns

    So that makes tLO/HI = max(20ns+5ns, 75ns+9ns) = max(25ns, 84ns) = 84ns, and fUCxCLK = 1/(2*84ns) = 1/168ns = 6MHz.

    All I can say is, bah. Obviously I got lucky when running it at 8MHz, and it's also obvious that to improve performance I definitely need a LRU data cache to reduce the number of FRAM accesses.

    Any ideas on how to get a 6MHz clock out of the 16MHz MCLK?

  • David Given said:
    Does the MSP430 do anything similar?

    No, but line capacitance may do a similar thing you your signal.

    Now I didn't have problems with 4MHz SPI on a 1611 and 16MHz on a 5438. So maybe the problem is somewhere else...

    UCBR0 should be 1, not 0. FBitClock is FBRCLK/UCBRx, which is undefined for UCBRx=0 (division by zero). I'm nort sure what happens internally if you do.

    Setting DCO to 16MHz is, well, I don't knwo whether it should be done. To get 16MHz average, the DCO will have to run witha frequency above and one below 16MHz. (modulation). And the 'above' is above the specs then. maybe this has been taken into account when generating the calibration values. maybe not, I don't know. Also, the DCO drifts with temperature and VCC. And since 16MHz is the specified maximum, I'd consider this risky. (not to mention that it requires VCC>=3.3V)

    The 'corrupt' tranfer you see might be because of a device reset.
    What about the watchdog? Did you disable it or do you feed it?

**Attention** This is a public forum