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
	}

Stepper motor controller for precise movement

Amit Karna March 2, 20131 comment Coded in C++ for the x86
/*
 * IBM-PC Parallel Printer Port Data & Status Registers
 * ====================================================
 *        7   6   5   4   3   2   1   0   I/O Port
 *      +---+---+---+---+---+---+---+---+ ========
 * Data | C8| C7| C6| C5| C4| C3| C2| C1| Base = 278/378/3BC Hex
 *      +---+---+---+---+---+---+---+---+           +---+
 */
#include<sys/io.h>
#include<unistd.h>
#include<stdlib.h>
#include<math.h>	//for floor()
#include<iostream>
using namespace std;

#define BASEPORT 0x378 //SPP - Standard Parallel port base address

class stepper
{
	private:
		long delay;	//delay betn each step
		float pi;	//constant
		float acf, lcf;	//angle and length correction factors in percentage
		float r, c;	// radius and circumerence of wheel
		float ns;		
		int nfsc, nhs;	
		float residue;
		// number of total steps, full step cycles and number of half steps
		float step_rating;	//number of steps per revolution
		float speed;	//speed of stepper in cm/sec
		float l,w;	//length and width of robocar	
	public:
		stepper(float spd);
	
		void specification();
		
		void length2steps(float len, int& nfsc, int& nhs);//conversion
		void angle2steps(float angle, int& nfsc, int& nhs);//conversion
		void move(int nfsc, int nhs, int leftw, int rightw); //move
				
		void fwd(float len);	//length in cm
		void bkwd(float len);	//length in cm
			
		void righturn(float degree, int degree_of_freedom);	//number of degree turns
		void lefturn(float degree, int degree_of_freedom);	//  -- do --
};

stepper:: stepper(float spd=7)
{	
	speed=spd;
	l=18;		//length of car
	w=17-2;		//width of car
	acf=-2;		//angle correction factor in percentage
	lcf=-4;		//angle correction factor in percentage
	pi=3.14159;	//costant
	step_rating=200.5;	//step rating
	r=3.448;		//radius of wheel in cm
	c=2*pi*r;	//circumference
	residue=0;
	//speed being in cm/s
	delay=long(1/(step_rating/c*speed)*1000*1000);	//in microsecond
}

void stepper::specification()
{	
	cout<<"\n\n\n\t\tF R O N T I E R\n";
	cout<<"\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
	cout<<"\n\n\nDesigned by: Amit Kumar Karna";
	cout<<"\n\n\nMission: Vitrubio, Technozion'06 @ NIT Warangal";
	cout<<"\n\n\nROBOCAR specifications...";
	cout<<"\nDimensions = "<<l<<"cm x"<<w<<"cm";
	cout<<"\nWheel Dia = "<<2*r<<"cm";
	cout<<"\nStepper motor:  12V-0.33A \t"<<step_rating<<" steps/revolution";
	cout<<"\nLength n Angle correction factors: "<<lcf<<"% & "<<acf<<"% respectively";
	cout<<"\nSpeed selected : "<<speed<<"cm/sec";
	cout<<"\ndelay between each step = "<<delay/1000.0<<"ms";
	cout<<endl<<endl<<endl;
}

void stepper::length2steps(float len, int& nfsc, int& nhs)//conversion
{
	ns=step_rating/c*len+residue;
	nfsc=int(ns/4);
	nhs=int(floor((ns-nfsc*4)/0.5));	//rounding
	if(nhs==8)	//may result after rounding
		nhs=7;
	residue=ns-(nfsc*4+nhs*0.5);
}

void stepper::angle2steps(float angle, int& nfsc, int& nhs)//conversion
{
	float arclen=(pi*w)/360.0*angle;
	length2steps(arclen, nfsc, nhs);
}

void stepper::move(int nfsc, int nhs, int leftw, int rightw) //move	
{
   int i;
   int cnt;
   outb(0x00, BASEPORT);
   if(leftw==1 && rightw==1)
   {	
	for(i=0; i<nfsc; i++)
	{
		outb(0x59, BASEPORT);
		usleep(delay);
		outb(0x6A, BASEPORT);
		usleep(delay);
		outb(0xA6, BASEPORT);
		usleep(delay);
		outb(0x95, BASEPORT);
		usleep(delay);
		if(i%50==0 && i!=0)
			outb(0x81, BASEPORT);	//one half step - as a compensation
	}
	//sequence after 5 i.e. 0100 is 1 for half step
	//sequence after 9 i.e. 1001 is 8 for half step
       for(i=0; i<1; i++)	//dummy loop to use break;
       {
	cnt=0;
	if(nhs==0)
		break;	
	outb(0x81, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0xA9, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x28, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x6A, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x42, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x56, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x14, BASEPORT);
	if(++cnt==nhs)
		break;	
	//max of 7 half steps only possible
       }
   }
   else if(leftw==-1 && rightw==-1)
   {
	for(i=0; i<nfsc; i++)
	{
		outb(0x95, BASEPORT);
		usleep(delay);
		outb(0xA6, BASEPORT);
		usleep(delay);
		outb(0x6A, BASEPORT);
		usleep(delay);
		outb(0x59, BASEPORT);
		usleep(delay);
		if(i%50==0 && i!=0)
			outb(0x81, BASEPORT);	//one half step - as a compensation
	}
	//sequence after 5 i.e. 0100 is 1 for half step
	//sequence after 9 i.e. 1001 is 8 for half step
       for(i=0; i<1; i++)	//dummy loop
       {
	cnt=0;
	if(nhs==0)
		break;	
	outb(0x81, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0xA9, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x28, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x6A, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x42, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x56, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x14, BASEPORT);
	if(++cnt==nhs)
		break;	
       }
   }   
   else if(leftw==-1 && rightw==1)	//left turn 2 wheels
   {
	
	for(i=0;i<nfsc;i++)
	{
		outb(0x99, BASEPORT);
		usleep(delay);
		outb(0xAA, BASEPORT);
		usleep(delay);
		outb(0x66, BASEPORT);
		usleep(delay);
		outb(0x55, BASEPORT);
		usleep(delay);
	}
	//sequence after 5 i.e. 0100 is 1 for half step
	cnt=0;
      for(i=0; i<1; i++)
      {
	if(nhs==0)
		break;	
	outb(0x11, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x99, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x88, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0xAA, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x22, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x66, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x44, BASEPORT);
	if(++cnt==nhs)
		break;	
	//max of 7 half steps only possible
      }
   }
   else if(leftw==1 && rightw==-1)	//right turn with 2 wheels
   {
	for(i=0;i<nfsc;i++)
	{
		outb(0x55, BASEPORT);
		usleep(delay);
		outb(0x66, BASEPORT);
		usleep(delay);
		outb(0xAA, BASEPORT);
		usleep(delay);
		outb(0x99, BASEPORT);
		usleep(delay);
	}
	//sequence after 5 i.e. 0100 is 1 for half step
	cnt=0;
      for(i=0; i<1; i++)
      {
	if(nhs==0)
		break;	
	outb(0x44, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x66, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x22, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0xAA, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x88, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x99, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x11, BASEPORT);
	if(++cnt==nhs)
		break;	
	//max of 7 half steps only possible
      }
   }
   else if(leftw==0 && rightw==1) //left turn with one wheel
   {
	
	for(i=0;i<nfsc;i++)
	{
		outb(0x09, BASEPORT);
		usleep(delay);
		outb(0x0A, BASEPORT);
		usleep(delay);
		outb(0x06, BASEPORT);
		usleep(delay);
		outb(0x05, BASEPORT);
		usleep(delay);
	}
	//sequence after 5 i.e. 0100 is 1 for half step
	cnt=0;
      for(i=0; i<1; i++)
      {
	if(nhs==0)
		break;	
	outb(0x01, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x09, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x08, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x0A, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x02, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x06, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x04, BASEPORT);
	if(++cnt==nhs)
		break;	
	//max of 7 half steps only possible
      }
   }
   else if(leftw==1 && rightw==0) //right turn with one wheel
   {
	for(i=0;i<nfsc;i++)
	{
		outb(0x50, BASEPORT);
		usleep(delay);
		outb(0x60, BASEPORT);
		usleep(delay);
		outb(0xA0, BASEPORT);
		usleep(delay);
		outb(0x90, BASEPORT);
		usleep(delay);
	}
	//sequence after 5 i.e. 0100 is 1 for half step
	cnt=0;
      for(i=0; i<1; i++)
      {
	if(nhs==0)
		break;	
	outb(0x40, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x60, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x20, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0xA0, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x80, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x90, BASEPORT);
	if(++cnt==nhs)
		break;
	outb(0x10, BASEPORT);
	if(++cnt==nhs)
		break;	
	//max of 7 half steps only possible
      }
   }
   outb(0x00, BASEPORT);
}		

void stepper::fwd(float len=0)
{
	float tlen=len;
	if(len==0)
		return;
	tlen=tlen+tlen*lcf/100;
	length2steps(tlen, nfsc, nhs);
	cout<<"\nMoving forward by "<<len<<"cms... \t[\t"<<nfsc<<"  "<<nhs<<"  ]"<<endl;
	move(nfsc, nhs, 1, 1);//leftw=1 & rightw=1
}

void stepper::bkwd(float len=0)
{
	float tlen=len;
	if(len==0)
		return;
	tlen=tlen+tlen*lcf/100;
	length2steps(tlen, nfsc, nhs);
	cout<<"\nMoving backward by "<<len<<"cms... \t[\t"<<nfsc<<"  "<<nhs<<"  ]"<<endl;
	move(nfsc, nhs, -1, -1);//leftw=-1 & rightw=-1
}

void stepper::lefturn(float angle, int dof=2)	//degree of freedom
{
	float tangle=angle;
	tangle=tangle*2/dof;
	tangle=tangle+tangle*acf/100;
	angle2steps(tangle, nfsc, nhs);
	cout<<"\nTaking left turn by "<<angle<<"degrees... [\t"<<nfsc<<"  "<<nhs<<"  ]"<<endl;
	if(dof==1)
		move(nfsc, nhs, 0, 1);	//leftwheel=off, rightwheel=on
	else
		move(nfsc, nhs, -1, 1);
}

void stepper::righturn(float angle, int dof=2)
{
	float tangle=angle;
	tangle=tangle*2/dof;
	tangle=tangle+tangle*acf/100;
	angle2steps(tangle, nfsc, nhs);
	cout<<"\nTaking right turn by "<<angle<<"degrees... [\t"<<nfsc<<"  "<<nhs<<"  ]"<<endl;
	if(dof==1)
		move(nfsc, nhs, 1, 0); //leftwheel=on, rightwheel=off
	else
		move(nfsc, nhs, 1, -1);
}

main()
{
	system("clear");
	if(ioperm(BASEPORT,3,1))
	{
		cout<<"\nThe parallel port accessing error!";
		exit(1);
	}
	float speed; 		//in cm/s
	float len, la, ra;	//in cm
	float angle;
	long wait=10000;
	
	//cout<<"\nEnter speed in cm/s (eg. 10cm/s) : ";
	//cin>>speed;	

	speed=10;
	stepper sm(speed);	 

	sm.specification();
	cout<<"\nScanning the problem...";usleep(wait);
	cout<<"...";usleep(wait);cout<<"...";usleep(wait);cout<<"...";cout<<"Done!";
	cout<<"\n\n\nStarting the voyage...\n\n\n";
	
	float l1=20, l2=28.284;
	float a1=45, a2=90, a3=135;

	int i;
	
	for(i=0; i<3; i++)
	{
		sm.fwd(l1);
		usleep(wait);
		sm.lefturn(a3);
		usleep(wait);
		sm.fwd(l2);
		usleep(wait);
		sm.righturn(a3);
	}
}