ECE2049: Embedded Computing in Engineering Design C Term Spring 2018 Lecture #19: Using SPI The LCD Screen and DAC Reading for Today: User's Manual Ch 35, Davies 101.5, DAC datasheet Reading for Next Class: -- Lab #3 (on web): Due NOW! Lab #4 (on web): Report due Friday 3/2/2018! (at 9 a.m. in class) HW #5 (on web): Due Tueday 2/27 (in class) Last Class: >> Serial vs. Parallel interfaces >> USCI are parallel-to-serial and serial-to-parallel converters >> Asynchronous UART mode for asynchronous serial comms Serial Peripheral Interface Bus (SPI) >> Used primarily for synchronous serial comms between a CPU and peripherals within the box = off-chip but on same PCB >> Unlike Asynchronous Serial comms like (RS-232), usually SPI sends or receives data Most Significant Bit (MSB) first!! (But, can be selectable in MSP430) --> Synchronous = shared clock (supplied by master) = Higher transfer speeds (~Mbps) MSP430 (master) SIMO SOMI GND SCLK some SPI device (slave) CS >> We'll be using 3 wire connection SIMO = Slave In/Master Out data line SOMI = Slave Out/Master In data line SCLK = Serial Clock (SCK in MSP430 USCI) (Plus, CS = Chip Select)
>> To use SPI the programmer must... 1) Enable USCI for SPI mode Including SELecting SPI data pins and SCLK pin for Function mode (= 1) 2) Select data format 3) Setup synchronous clock Then programmer must... 4) Select peripheral using its chip select (CS) Plus asserting any other digital IO/control lines that external device requires -- For LCD this is labeled SPI CS -- The LCD also needs to be turned turned on (LCD Power Control) and enabled
Let's look at the Sharp LCD Display... //*************************************************************** // HAL_MSP-EXP430F5529_Sharp96x96.h - Prototypes for the // Sharp96x96 LCD display driver. There is no output from // Sharp96x96 LCD. // *************************************************************** // // Pin definitions for LCD driver // //*************************************************************** /* * Power P6.5 // Digital IO * DISP P1.6 // Digital IO * CS P6.6 // Digital IO * MOSI P3.0 // Function mode USCI B0 * SCLK P3.2 // Function mode USCI B0 */ #define PORT_SPI_SEL #define PORT_SPI_DIR #define PORT_DISP_SEL #define PORT_DISP_DIR #define PORT_DISP_OUT #define PORT_CS_SEL #define PORT_CS_DIR #define PORT_CS_OUT #define PORT_PWR_SEL #define PORT_PWR_DIR #define PORT_PWR_OUT P3SEL P3DIR P1SEL P1DIR P1OUT P6SEL P6DIR P6OUT P6SEL P6DIR P6OUT #define PIN_SPI_MOSI #define PIN_SPI_SCLK #define PIN_PWR #define PIN_DISP #define PIN_CS #define SPI_REG_CTL0 #define SPI_REG_CTL1 #define SPI_REG_BRL #define SPI_REG_BRH #define SPI_REG_IFG #define SPI_REG_STAT #define SPI_REG_TXBUF #define SPI_REG_RXBUF BIT0 BIT2 BIT5 BIT6 BIT6 UCB0CTL0 UCB0CTL1 UCB0BR0 UCB0BR1 UCB0IFG UCB0STAT UCB0TXBUF UCB0RXBUF #define SPI_CLK_SRC (UCSSEL SMCLK) #define SPI_CLK_TICKS 0
void Sharp96x96_Init(void) { // Configure SCLK and MOSI for peripheral function mode = 1 PORT_SPI_SEL = (PIN_SPI_MOSI PIN_SPI_SCLK); // LCD is powered using a GPIO pin, configure it as output PORT_PWR_SEL &= ~PIN_PWR; PORT_PWR_DIR = PIN_PWR; // Drive the power pin high to power the LCD PORT_PWR_OUT = PIN_PWR; // Configure the LCD display enable signal DISP, // Drive it high to enable the LCD PORT_DISP_SEL &= ~PIN_DISP; PORT_DISP_DIR = PIN_DISP; PORT_DISP_OUT = PIN_DISP; // Configure the display Chip Select as an output PORT_CS_SEL &= ~PIN_CS; PORT_CS_DIR = PIN_CS; // Initialize the chip select in a deasserted state PORT_CS_OUT &= ~PIN_CS; // ------------------------------------------------------ // Now configure UCSIB0 to function as our SPI controller // Disable the module before we can configure it SPI_REG_CTL1 = UCSWRST; // Reset the controller config parameters SPI_REG_CTL0 &= ~(UCCKPH UCCKPL UC7BIT UCMSB); / SPI_REG_CTL1 &= ~UCSSEL_3; // Reset the clock configuration // Select SMCLK for our clock source SPI_REG_CTL1 = SPI_CLK_SRC; // Set SPI clock frequency (which is the same frequency as // SMCLK so this can apparently be 0) // Set the low byte then set the high byte SPI_REG_BRL = ((uint16_t)spi_clk_ticks) & 0xFF; SPI_REG_BRH = (((uint16_t)spi_clk_ticks) >> 8) & 0xFF; // Configure for SPI master, synchronous, 3 wire SPI, // MSB first, capture data on first edge, // and inactive low polarity SPI_REG_CTL0 = (UCMST UCSYNC UCMODE_0 UCMSB UCCKPH); } // Re-enable the module s0 it can be used SPI_REG_CTL1 &= ~UCSWRST; SPI_REG_IFG &= ~UCRXIFG; // clear interrupt flag
Next program should... 5) Send or Receive data to/from the peripheral -- This code polls transfer complete bits to determine when data transfer complete (interrupts not enabled here... they could be) -- Also, reading from an SPI device often requires addresses or command words be sent. These will all be device specific The LCD uses the TI grlib in addition to device specific files It's a bit hidden in the demo code but to eventually the MSP430 must send data to the LCD one byte at a time and the transmission would be achieve by a function like the following where uccmddata is the byte currently being sent. write_spi(unsigned char uccmddata) { // Put byte to send in transmit TX buffer SPI_REG_TXBUF =uccmddata; } /* Wait for the TX buffer to empty */ while(!(spi_reg_ifg & UCTXIFG)) no_operation();
The LCD Screen's functions are already wrapped for us -- Sharp96x96_Init() is called at the beginning of our configdisplay() function which is called at the beginning of our demo project write_spi() functionality is buried underneath higher-level grlib functions like GrStringDrawCentered() So how do we deal with other SPI devices from scratch?? -- First thing we need to do is figure out how to use the device of interest! -- Our Lab Board has the MCP4921 SPI DAC Overview of a Digital-to-Analog Convert (DAC) >> Converts integer value to a voltage >> MCP4921 is 12-bit DAC that outputs voltages rail-to-rail (0 to Vcc)
>> DAC performs the inverse operation of an ADC Ex: Consider a the following DAC what is the value of the output voltage? >> To use SPI to run the DAC the programmer must... 1) Enable USCI for SPI mode 2) Select data format 3) Setup synchronous clock Isn't that what the LCD had to do to use SPI? Can't we just use that set up? >> YES! That's the whole idea behind SPI