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.

MSP430G2231 SPI to DAC help



Hey all, 

I've done some tinkering with Arduino in the past, and this is my first time tinkering with the MSP launchpad. Right now, I'm trying to use my MSP430 to control a DAC (MCP4921) using SPI. 

Right now, I don't have access to an oscilloscope, so it's been a bit hard for me to test much. Until then, I thought I'd ask for some help making sure that my code makes sense. 

First off, according to the datasheet, the DAC works as follows:

  1. The chip select pin is driven low. 
  2. 16 bits total are clocked in - 4 configuration bits, and 12 data bits
  3. the LDAC pin is driven low to send the data from the DAC's input registers to its output registers

In my code, the pin assignments are:

  • P1.0 is a status LED, which just blinks at the beginning of the program. 
  • P1.5 is SCK
  • 1.6 is SDO
  • 1.5 is SCK
  • 1.4 is LDAC
  • 1.1 is CS

Please let me know if you see anything wrong or suspicious, or if I'm using the SPI protocol incorrectly. I've been looking at other examples of SPI protocol using the USI module. Thanks. 

-------

#include <msp430.h>

void setup_GPIO(void);
void blink(void);
void send_dac(unsigned int v);

int LDAC = BIT4;					// pin for LDAC is 1.4
int CS = BIT1; 						// pin for CS is 1.1
int LED1 = BIT0;					// pin for LED1

int main(void){

	WDTCTL = WDTPW | WDTHOLD;		// Stop watchdog timer
	setup_GPIO();
	blink();						// entered main loop

	send_dac(0x4f3);				// 4f3 = 0d1267 --> 1.09810791 V

	blink();
	//for(;;){};

	return 0;
}

void setup_GPIO(void){
	P1OUT = 0x00;			// set P1.0 to low to turn LED off
	P1DIR |= LED1; 			// set P1.0 for LED output

	P1DIR |= CS + LDAC;		// set LDAC and CS to output
	P1OUT |= CS;			// set CS to high, to disable chip selection at beginning

	USICTL0 |= USIPE6 + USIPE5 + USIMST + USIOE; 	// enables SDO and SCK, puts mcu in master mode, allows output
	USICTL1 |= USIIE; // allows interrupts of USI
	USICKCTL |= USIDIV_4 + USISSEL_2;			// div by 4, SMCLK

	USICTL0 &= ~USISWRST;		// USI released for operation
}

void blink(void){
	int j;
	P1OUT = 0x00;
	for (j = 0; j<6; ++j){
		P1OUT ^= 0x01;
		__delay_cycles(200000);
	}
	P1OUT = 0x00;
}

void send_dac(unsigned int v){

	// load register
	USICNT = 0x00;				// clear counter
	USISRH = 0x3F | (v >> 8);	// 0x20 and 4 bits of v
	USISRL = (v << 8) >> 8;		// last 8 bits of v

	// enable chip select to select the dac
	P1OUT &= ~CS;		// enable chip select

	__delay_cycles(0xFFF);	// time for slave to get ready
	// transmit to dac (counter set to 60)
	USICNT |= USI16B  + 0x10;	// also set 16 bit mode
	__delay_cycles(20);

	// disable chip select
	P1OUT |= CS;		// disable chip select

	// latch DAC input registers to output
	P1OUT &= ~LDAC; 	// enable latch
	__delay_cycles(200000);
	P1OUT |= LDAC;		// disable latch
}

  • USISR is a 16bit union if the two bytes USISRH and USISRL, so use it.

    USISR = (0x20<<12) | v;

    __delay_cycles(20) will not be enough if you are running the spi clock at 1/4MHz (4us), you would need 58uS pause.
    __delay_cycles(80); should be enough
  • Hi Lisa!

    There is an interrupt flag you can poll (or use the ISR) for a finished transmission. I would always prefer using this instead of any delay cycles. Furthermore your DAC needs a minimum pulse width for LDAC of 100ns - this is 10MHz. Since you do not configure the clock module, your CPU is running at about 1MHz, so no delay is neded here. Even if it would run at it's full speed of 16MHz, the instructions for setting LDAC low and high will still be longer than 100ns. The time between CS going low and the start of the transmission is 40ns, so no delay required here as well. I would work completely without the delays.

    Lisa Liu said:
    int LDAC = BIT4;                    // pin for LDAC is 1.4
    int CS = BIT1;                      // pin for CS is 1.1
    int LED1 = BIT0;                    // pin for LED1

    You do not have to create some variables for this - simply make a define by writing:

    #define LDAC BIT4   // Pin for LDAC is 1.4
    #define CS   BIT1   // Pin for CS is 1.1
    #define LED1 BIT0   // Pin for LED1

    Dennis

  • Thanks Tony and Dennis for the responses and suggestions.

    What ended up getting it to work was (1) timing the delay better, as you guys suggested, and (2) setting USICKPL.

    If I understand it correctly, setting USICKPL ensures that the bit gets sampled on the rising edge of the clock, after the data bit has been set.

**Attention** This is a public forum