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.

Long dead time between SPI byte transmissions

Other Parts Discussed in Thread: MSP430F47187

I'm using the MSP430F47187 with the 23LC1024 SRAM chip, trying to maximize data transmission rates through SPI to the SRAM.  Basically I'm transmitting 12 bytes at a time - first byte is the command, next three are the address, and finally the last eight are the data but I'm noticing a relatively long dead time between each byte tranmission (roughly 3x the time it takes to transmit one byte).  Is in something configurable in the MSP430 that I'm missing, or is that the nature of the chips?  Here's the code I'm using:

(oh I'm using a 32kHz cyrstal, which translate to 1MHz on SMCLK)

void main(void)
{
	// Setup leds
	P4OUT = 0x00;
	P4DIR = 0xFF;

	InitSram();

	// Test Data
	char * testData [4] = {0xAB, 0xCD, 0xEF, 0x12};
	char * dataRcvd [4] = {0x00, 0x00, 0x00, 0x00};

	while(1)
	{
		// Begin test
		LED_OUTPUT &= ~(LED_YELLOW | LED_BLUE | LED_GREEN | LED_RED);

		dataRcvd[0] = 0x00;
		dataRcvd[1] = 0x00;
		dataRcvd[2] = 0x00;
		dataRcvd[3] = 0x00;

		LED_OUTPUT |= LED_YELLOW;
		// Write to SRAM
		WriteBlock(0, testData, 8);
		LED_OUTPUT &= ~LED_YELLOW;

		// Wait for it
		DelayOneSecond();

		// Read it back and confirm
		ReadBlock(0, dataRcvd, 8);

		// Test!
		LED_OUTPUT &= ~(LED_YELLOW | LED_BLUE | LED_GREEN | LED_RED);
		if (	testData[0] == dataRcvd[0] &&
				testData[1] == dataRcvd[1] &&
				testData[2] == dataRcvd[2] &&
				testData[3] == dataRcvd[3]
		)
		{
			LED_OUTPUT |= LED_GREEN;
		}
		else
		{
			LED_OUTPUT |= LED_RED;
		}

		DelayOneSecond();
		DelayOneSecond();
		DelayOneSecond();

	}  // end while(1)

sram.h:

#ifndef SRAM_H_
#define SRAM_H_

#include <msp430f47187.h>
#include "sensor_types.h"

/**
 * Available modes of operation as found in the status register
 */
#define BYTE_MODE		0x00
#define SEQUENTIAL_MODE		0x40
#define PAGE_MODE   		0x80

/**
 * The maximum address available on the chip
 * Attempts to read or write above this address will roll over back to that start
 *
 * Actual number of values is XXXXX, but in our case we are using a zero indexed value,
 * so the max address is XXXXX - 1.
 */
#define MAX_SRAM_ADDR		131071

/**
 * The chip select pin, located on Port 3
 */
#define SRAM_CHIP_SELECT	BIT2

/**
 * The SRAM HOLD pin located on Port 2
 */
#define SRAM_HOLD			BIT0

/**
 * A structure that holds a voltage and current sample pair for storage
 */
typedef struct
{
	uint16_t voltage;
	uint16_t current;
} WaveformData_t;

/**
 * Available instructions that may be sent to the SRAM
 */
enum SRAM_CMDS
{
	SRAM_WRITE_STATUS 		= 0x01,
	SRAM_WRITE_DATA			= 0x02,
	SRAM_READ_DATA			= 0x03,
	SRAM_READ_STATUS		= 0x05,
};

#define SRAM_WRITE_MODE		SRAM_WRITE_STATUS
#define SRAM_READ_MODE		SRAM_READ_STATUS

/**
 * Initialize all gpio, ports, and state variables used to control the SRAM
 */
void InitSram();

/**
 * Read back the status register from the SRAM chip
 *
 * STATUS REGISTER
 * |  7   |  6   | 5 | 4 | 3 | 2 | 1 |  0   |
 * | MODE | MODE | 0 | 0 | 0 | 0 | 1 | HOLD |
 *
 * Only the 7, 6 and 0 bit are writable
 */
uint8_t ReadSramStatus();

/**
 * Write a new value to the status register which controls the data mode and hold functionality
 */
void WriteSramStatus(uint8_t newStatus);

/**
 * Read a data block from the SRAM chip starting at the supplied address
 */
WaveformData_t * ReadData(uint16_t address);

/**
 * Write a data block to the SRAM chip starting at the supplied address
 */
void WriteData(uint16_t address, WaveformData_t * newData);

#endif /* SRAM_H_ */

sram.c:

#include "sram.h"

uint8_t rval;
uint8_t mode;
/* Pull the select down */
#define CS_LOW() P3OUT &= ~SRAM_CHIP_SELECT
/* Pull select up */
#define CS_HIGH() P3OUT |= SRAM_CHIP_SELECT

#define TESTDATA	0x32

uint8_t RWData(uint8_t value)
{

	while ((UC1IFG & UCB1TXIFG) == 0)
		;

	UCB1TXBUF = value;

	while ((UC1IFG & UCB1RXIFG) == 0)
		;

	return UCB1RXBUF;
}

uint8_t GetMode(void) {

    RWData((uint8_t) SRAM_READ_MODE); // 0x05
    uint8_t mode = RWData(0xFF);  // Just read slave data

    return mode;
}

void SetMode(uint8_t mode) {
    RWData((uint8_t) SRAM_WRITE_MODE); // 0x01
    RWData(mode);
}

/**
 * Initialize all gpio, ports, and state variables used to control the SRAM
 * The SRAM chip uses the UCB1 SPI port located on Port 2
 *
 * 		p2.0	->	~HOLD
 * 		p2.1	->	SI
 * 		p2.2	->	SO
 * 		p2.3	->	SCK
 *
 * 		p3.2	->	~CS
 */
void InitSram()
{
    /* Initialize SPI */
    P2SEL |= BIT1 | BIT2 | BIT3;
    P2DIR |= BIT0;		// As ouput
    P2OUT |= BIT0;		// Set HOLD high

    P3OUT |= SRAM_CHIP_SELECT;   // Set CS High
    P3DIR |= BIT2;    // As output

    // configure USI - SPI Mode 1 @ 4MHz, clocked off SMCLK
    UCB1CTL1 |= UCSWRST;
    UCB1CTL0 |= UCSYNC + UCMST + UCMSB + UCMODE_0 + UCCKPH;
    UCB1CTL0 &= ~UCCKPL;
    UCB1CTL1 |= UCSSEL_2;//+UCSWRST;
    // Original clock setting
    UCB1BR0 |= 0x01;
    UCB1BR1 |= 0x00;
    UCB1CTL1 &= ~UCSWRST;

	CS_LOW();						// Must set CS low in order to write the read/write mode register
	SetMode(SEQUENTIAL_MODE);
	CS_HIGH();						// Set it high terminate read/write operation

	CS_LOW();
	mode = GetMode();
	CS_HIGH();

	CS_LOW();
	RWData(SRAM_WRITE_DATA);
	RWData(0);						// Address location 0
	RWData(0);						// Address location 0
	RWData(0);
	RWData('x');					// Write data
	RWData('y');					// Write data
	RWData('z');					// Write data

	CS_HIGH();

	CS_LOW();
	RWData(SRAM_READ_DATA);
	RWData(0);
	RWData(0);
	RWData(0);
	rval = RWData(0xFF);			// Write 0xFF (dummy data) to read back value
	rval = RWData(0xFF);
	rval = RWData(0xFF);
	CS_HIGH();

}  // end InitSram

/**
 * Read a data block from the SRAM chip starting at the supplied address
 */
int ReadBlock(uint16_t address, char *buf, uint16_t size)
//int ReadBlock(uint16_t address, uint8_t *buf, uint16_t size)
{
	int i;

	CS_LOW();

	RWData(SRAM_READ_DATA);

	RWData(0);
	RWData(address >> 8);
	RWData(address);

	for (i = 0; i < size; i++)  
		buf[i] = RWData(0xFF);

	CS_HIGH();
	return(i);
}

/**
 * Write a data block to the SRAM chip starting at the supplied address
 */
int WriteBlock(uint16_t address, char* buf, uint16_t size)
//int WriteBlock(uint16_t address, uint8_t buf, uint16_t size)
{
	int i;

	CS_LOW();

	RWData(SRAM_WRITE_DATA);
	RWData(0);
	RWData(address >> 8);
	RWData(address);

	for (i = 0; i < size; i++)
		//RWData(buf[i]);
		RWData(TESTDATA);
	//RWData(buf);

	CS_HIGH();

	return(i);
}

Any ideas if this is doable?

Thanks.

  • With UCB1BR=1, sending (exchanging) a byte will take 8 clocks. This is more or less 2x instructions. After you send each byte, you're awaiting/fetching the Rx byte, returning from RWData, loading a new parameter, calling RWData, and testing UC1IFG again before sending the next byte. This could easily take 24 clocks.

    If you want it to run faster, you should probably use DMA. There's overhead -- setting ~3 registers as I recall -- but it will replace all the storing, the fetching, the IFG testing, as well as the timing mismatches that waste cycles here and there, so the SPI will never be waiting on your program to feed it.

    If you're unfamiliar with the DMA, it will probably take an hour or two to put it all together, but that will still be less time than it will take to carve up your functions to optimize them.

**Attention** This is a public forum