EmbeddedRelated.com

MSP430 SPI-Master IO without interrupt

Guenther Klenner March 23, 2013 Coded in C++ for the TI MSP430
/**
 * @file SPI.h
 * Control's for the SPI
*/

#ifndef FILE_SPI_H
#define FILE_SPI_H

class SPI
{
public:

	/**
	 * @brief   Init for SPI
	 * @details
	 * @param   void
	 * @return  void
	 */
	static void _Init(void);

	/**
	 * @brief   Send data to Display
	 * @details
	 * @param   unsigned char msg - Message send to Display
	 * @return  void
	 */
	static void LCD_DataOut(unsigned char msg);

	/**
	 * @brief   Send data to Display
	 * @details Display mode must be set
	 * @param   char* msg - Message send to Display
	 * @param   int Length - Length of message send to Display
	 * @return  void
	 */
	static void LCD_DataOut(char *msg, int Length);

	/**
	 * @brief   Send command to Display
	 * @details
	 * @param   unsigned char msg - Message send to Display
	 * @return  void
	 */
	static void LCD_CommOut(unsigned char msg);

private:
	typedef enum {ModeIdle, ModeLCD, ModeMem} SPI_Modes;
	static SPI_Modes SPI_Mode;
	/**
	 * It configures SPI in a mode to communicate to the selected device
	 * @param Mode This defines the mode to configure.
	 */
	static void ConfigSPI(SPI_Modes Mode);

	/**
	 * It performs data exchange via SPI for a given number of inputs and outputs
	 * @param TX	pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
	 * @param RX	pointer to receive buffer or 0
	 * @param IOcount total number of receive and transmit bytes
	 */
	static void DoSPI_IO(char* TX, char* RX, int IOcount);

};

#############################################

/**
 * @file SPI.c
 * Control's for the SPI
*/

#include "SPI.h"
#include "msp430.h"

#define ArrayLength(array) (sizeof(array)/sizeof(array[0]))
/// Macro to set a bit y in variable x
#define SETB(x,y)       (x |= (1 << y))
/// Macro to reset a bit y in variable x
#define CLRB(x,y)       (x &= ~(1 << y))

	SPI::SPI_Modes SPI::SPI_Mode;

	/**
	 * @brief   Init for SPI
	 * @details
	 * @param   void
	 * @return  void
	 */
	void SPI::_Init(void)
	{
		SPI_Mode = ModeIdle;
	}

	/**
	 * @brief   Send data to Display
	 * @details Display mode must be set
	 * @param   unsigned char msg - Message send to Display
	 * @return  void
	 */
	void SPI::LCD_DataOut(unsigned char msg) //Data Output Serial Interface
	{
		ConfigSPI(ModeLCD);
		CLRB(P3OUT,4);			//Chip Select = Active, CS = 0
		SETB(P2OUT,7);				//A0 = Data, A0 = 1
	    /* Software delay for selection line to settle */
	    __delay_cycles(25);

		while (UCBUSY & UCB0STAT);	// Wait until SPI is no longer busy
		UCB0TXBUF = msg;				// Transmit Message
		while (UCBUSY & UCB0STAT);  // Wait until SPI is no longer busy

		SETB(P3OUT,4);				//after 1 byte, Chip Select = inactive, CS =1
	}

	/**
	 * @brief   Send data to Display
	 * @details Display mode must be set
	 * @param   char* msg - Message send to Display
	 * @param   int Length - Length of message send to Display
	 * @return  void
	 */
	void SPI::LCD_DataOut(char *msg, int Length) //Data Output Serial Interface
	{
		ConfigSPI(ModeLCD);
		CLRB(P3OUT,4);			//Chip Select = Active, CS = 0
		SETB(P2OUT,7);				//A0 = Data, A0 = 1
	    /* Software delay for selection line to settle */
	    __delay_cycles(25);
		DoSPI_IO(msg, 0, Length);
		SETB(P3OUT,4);				//after 1 byte, Chip Select = inactive, CS =1
	}

	/**
	 * @brief   Send command to Display
	 * @details Display mode must be set
	 * @param   unsigned char msg - Message send to Display
	 * @return  void
	 */
	void SPI::LCD_CommOut(unsigned char msg) //Command Output Serial Interface
	{
		ConfigSPI(ModeLCD);
		CLRB(P3OUT,4);				//Chip Select = Active, CS = 0
		CLRB(P2OUT,7);				//A0 = Command, A0 = 0
	    /* Software delay for selection line to settle */
	    __delay_cycles(25);

		while (UCBUSY & UCB0STAT);	// Wait until SPI is no longer busy
		UCB0TXBUF = msg;				// Transmit Message
		while (UCBUSY & UCB0STAT);	// Wait until SPI is no longer busy

		SETB(P3OUT,4);				//after 1 byte, Chip Select = inactive, CS = 1

	}
	/**
	 * It configures SPI in a mode to communicate to the selected device
	 * @param Mode This defines the mode to configure.
	 */
	void SPI::ConfigSPI(SPI_Modes Mode)
	{
		if(SPI_Mode == Mode)
			return;
		switch(Mode)
		{
		case ModeLCD:
			/*******************************************************
			 * 			USCI - SPI configuration for LCD				   *
			 *******************************************************/

		    UCB0CTL1 = UCSWRST;                      	// **Reset USCI state machine**
			// UCMST = Master Mode Selected
			// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
			// ~UCCKPL = The inactive state is low.
			// UCMSB = MSB first
			// UCSYNC = Synchronous mode
			// 8 bit data, 3 pin SPI
			UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;

			UCB0CTL1 |= UCSSEL_2;                     // SMCLK clock source
		    UCB0BR0 |= 0x03;                          // SPI Clk = SMCLK / 3 = 1 MHz
		    UCB0BR1 = 0;
		    UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
		    break;

		case ModeMem:
			/*******************************************************
			 * 			USCI - SPI configuration for Memory				   *
			 *******************************************************/

		    UCB0CTL1 = UCSWRST;                      	// **Reset USCI state machine**
			// UCMST = Master Mode Selected
			// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
			// ~UCCKPL = The inactive state is low.
			// UCMSB = MSB first
			// UCSYNC = Synchronous mode
			// 8 bit data, 3 pin SPI
			UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;

			UCB0CTL1 |= UCSSEL_2;                     // SMCLK clock source
		    UCB0BR0 |= 0x01;                          // SPI Clk = SMCLK / 1 = 3 MHz
		    UCB0BR1 = 0;
		    UCB0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
		    break;

		case ModeIdle:
		default:
			Mode = ModeIdle;
			break;
		}
		SPI_Mode = Mode;
	}

	/**
	 * It performs data exchange via SPI for a given number of inputs and outputs
	 * @param TX	pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
	 * @param RX	pointer to receive buffer or 0
	 * @param IOcount total number of receive and transmit bytes
	 */
	void SPI::DoSPI_IO(char* TX, char* RX, int IOcount)
	{
		volatile int dummy = 0x81;
		if((TX == 0) && (RX == 0)) return;

		while(IOcount > 0)
		{
			if(UCB0IFG & UCTXIFG)
			{
				if(TX == 0)
					UCB0TXBUF = dummy;	// dummy write
				else
				{
					UCB0TXBUF = *TX++;
					IOcount--;
				}
			}
			if(UCB0IFG & UCRXIFG)
			{
				if(RX == 0)
					dummy = UCB0RXBUF;	// dummy read
				else
				{
					*RX++ = UCB0RXBUF;
					IOcount--;
				}
			}
		}
		while (UCBUSY & UCB0STAT);	// Wait until SPI is no longer busy
		dummy = UCB0RXBUF;	// dummy read to empty any remaining data in RX buffer
	}