Jump to content
43oh

MSP430 with 8051-based bus


Recommended Posts

Hi guys!

 

I've been working on a program that will read a byte from an AT computer keyboard, and print it on a 16x2 LCD display.

I'm also working on a function that will read the visible portion of the display, and save it in an I2C EEPROM.

 

Using RobG's I2C code, I was able to successfully interface an HD44780 display to my '2231, via a PCF8574 port expander.

Since I now have a bidirectional 8-bit parallel bus, I will connect a W83C43 keyboard controller to it, thus enabling a very large input range to my micro.

 

The schematic:

Link to post
Share on other sites

I made a VT100 terminal back in 1996 with an AT keyboard but I used a Motorola 68000 and a 640x480 LCD panel.

 

I think it's a great project to do. :thumbup:

 

By the way, don't you have to change the A0/A1/A2 connections so that the Flash memory and the port expander don't conflict?

Link to post
Share on other sites
By the way, don't you have to change the A0/A1/A2 connections so that the Flash memory and the port expander don't conflict?

 

Nope, the address for the EEPROM starts with 0xA (1010), while the address for the expander starts with 0x4 (0100). :D

The next three bits are a sub address (this is where the A0/A1/A2 come in for the expander, the pins on the EEPROM are unused), and the last bit defines whether the operation is a read or write.

Link to post
Share on other sites

If I wanted an external interrupt to wake my micro, perform an action, and fall asleep again, would I do this?

#pragma vector=PORT1_VECTOR
       __interrupt void PORT1_ISR(void) {

  _BIC_SR_IRQ(LPM3_bits);                 // Clear LPM3 bits from 0(SR)

  readKeybd();
   sendData(charData);

  P1IFG = 0; // clear interrupt

  _BIS_SR(LPM3_bits + GIE);               // Enter LPM3
}

Link to post
Share on other sites

Does this answer your question?

  P1DIR &= ~KINT;
 P1OUT |= KINT;
 P1REN |= KINT;
 P1IES |= KINT;
 P1IFG &= ~KINT;
 P1IE |= KINT;

set as input,

output positive,

enable pull-up,

negative edge,

interrupt enable.

 

Does "P1IFG &= ~KINT;" mean "KINT" sets the P1 interrupt flag?

Link to post
Share on other sites
Does "P1IFG &= ~KINT;" mean "KINT" sets the P1 interrupt flag?

 

Nope. It means clear the P1.0 Interrupt Flag.

 

P1DIR &= ~KINT; // set P1.0 as input
P1OUT |= KINT;  // set P1.0 HIGH
P1REN |= KINT;  // enable P1.0 internal pullup resistor
P1IE |= KINT;  // enable P1.0 interrupt 
P1IES |= KINT;  // set P1.0 interrupt detection to Hi/Lo edge transition
P1IFG &= ~KINT; // clear P1.0 interrupt flag 

 

And then in your ISR

 

#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void) 
{
 readKeybd();
 sendData(charData);

 P1IFG &= ~KINT; // clear P1.0 interrupt

 

IMHO, I think that you should avoid low power modes until you've tested out the ISR. LPModes are trixy little buggers and need to be treated carefully.

 

Take a look at this sample usage from MSP430 Microcontroller Basics, page 201:

Listing 6.6: Part of program timintC2.c to toggle LEDs using interrupts from Timer_A. The device enters low-power mode 0 between interrupts.

 

// ----------------------------------------------------------------

__enable _interrupt (); // Enable interrupts (intrinsic)

 

for (;;) { // Loop forever doing nothing

__low_power_mode_0 (); // Enter low power mode LPM0

} // Interrupts do the work

}

 

// ----------------------------------------------------------------------

// Interrupt service routine for Timer A channel 0

// Processor returns to LPM0 automatically after ISR

// ----------------------------------------------------------------------

#pragma vector = TIMERA0_VECTOR

__interrupt void TA0_ISR (void)

{

P2OUT

Link to post
Share on other sites

BTW, I found an example in MSP430 Microcontroller Basics that may be just what you're looking for. It's on page 217,218.

 

Listing 7.1: Program butled4.c in C to light LED1 when button B1 is pressed using

interrupts and low-power mode 4.

// butled4.c - press button B1 to light LED1

// Responds to interrupts on input pin , LPM4 between interrupts

// Olimex 1121 STK board , LED1 active low on P2.3,

// button B1 active low on P2.1

// J H Davies , 2006 -11 -18; IAR Kickstart version 3.41A

// ----------------------------------------------------------------------

#include // Specific device

#include // Intrinsic functions

// ----------------------------------------------------------------------

void main (void)

{

WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

P2OUT_bit.P2OUT_3 = 1; // Preload LED1 off (active low!)

P2DIR_bit.P2DIR_3 = 1; // Set pin with LED1 to output

P2IE_bit.P2IE_1 = 1; // Enable interrupts on edge

P2IES_bit.P2IES_1 = 1; // Sensitive to negative edge (H->L)

 

do {

P2IFG = 0; // Clear any pending interrupts ...

} while (P2IFG != 0); // ... until none remain

 

for (;;) { // Loop forever (should not need)

__low_power_mode_4 (); // LPM4 with int'pts , all clocks off

} // (RAM retention mode)

}

 

// ----------------------------------------------------------------------

// Interrupt service routine for port 2 inputs

// Only one bit is active so no need to check which

// Toggle LED , toggle edge sensitivity , clear any pending interrupts

// Device returns to low power mode automatically after ISR

// ----------------------------------------------------------------------

#pragma vector = PORT2_VECTOR

__interrupt void PORT2_ISR (void)

{

P2OUT_bit.P2OUT_3

Link to post
Share on other sites
  • 5 weeks later...

Ok, I've left off interrupts for now, working on other aspects of my program. I keep running into trouble, though.

Partway through the code, the 'g2231 I'm working with will reset. The problem is elusive, recurring, and doesn't always happen in the same spot, and only changes location when I change the code, no matter how slight. Sometimes it will reset very close to the beginning of the code, other times it will happen halfway through.

 

The code:

    #include "msp430g2231_mod.h"
 //  #include "msp430g2211.h"

   #define SDA BIT7
   #define SCL BIT0
   #define EN BIT5      // display ENABLE
   #define RS BIT4      // display RS pin connected here
   #define RW BIT3      // display R/W pin connected here
   #define A2 BIT2
   #define CS BIT1
   #define KINT BIT6

   #define MEMRD 0xA1     // EEPROM
   #define MEMWR 0xA0     // EEPROM
   #define P1RD 0x41      // port expander 1 read  // display databus connected here
   #define P1WR 0x40      // port expander 1 write // display databus connected here
   #define FAILURE -1
   #define SUCCESS 0
   #define error "MEMREAD ERROR! " // for error reporting

   void sendByte(void);
   void receiveByte(void);
   void sendAck(void);
   void receiveAck(void);
   void start(void);
   void stop(void);

   unsigned char txData = 0;
   unsigned char rxData = 0;
   unsigned int address = 0; // 12 bit address, upper 4 bits should be 0s.
   unsigned char charData = 0;
   int bitCounter = 0;

// Nuetron's copied and modified functions
   void sendStr(void);
   void sendStr(char string[], char info, int size);
   int readStr(void);
   int readPort(void);
   int writePort(char data);
   int writeCharLCD(char data, bool rs);
   int readStrLCD(void);

   void sendData(char data){ writeCharLCD(data, 1); }
   void sendInstruction(char data){ writeCharLCD(data, 0); }
   void clearDisplay(void){
     sendInstruction(0x01);
     __delay_cycles(2000); }
   void initDisplay(void){
     sendInstruction(0x38);
     sendInstruction(0x0E);
     clearDisplay();
     sendInstruction(0x06); }

   bool ackFlag;
   bool kintFlag;

   char dispBuffer[32]; // Display buffer

    void main(void) {

       WDTCTL = WDTPW + WDTHOLD;
       BCSCTL1 = CALBC1_1MHZ;
       DCOCTL = CALDCO_1MHZ;

       P1OUT |= EN|RS|RW|A2|CS;
       P1DIR |= EN|RS|RW|A2|CS;
       P1OUT |= SCL;
P1DIR |= SCL;
       // Set up KINT
   P1DIR &= ~KINT; // set P1.0 as input
   P1OUT |= KINT;  // set P1.0 HIGH
   P1REN |= KINT;  // enable P1.0 internal pullup resistor

       initDisplay();
       initDisplay(); // My display seems to reqire two initializations...

address = 0;
for(int t=0; t < 5; t++){
readStr();
sendStr();
__delay_cycles(2500000);
}
readStrLCD();
   }

   void sendStr(void) {
 sendInstruction(0x80);
        for(int charIndex = 0; charIndex < 32; charIndex++) {
   if(dispBuffer[charIndex] < 0x20){
     sendStr(error, '<', 15);
     break;
   }
   if(dispBuffer[charIndex] > 0x7F){
     sendStr(error, '>', 15);
     break;
   }
   if(charIndex == 16)
     sendInstruction(0xC0);
          sendData(dispBuffer[charIndex]);
        }
   }
   void sendStr(char string[], char info, int size) {
 sendInstruction(0x80);
        for(int charIndex = 0; charIndex < size; charIndex++) {
          sendData(string[charIndex]);
        }
 sendData(info);
   }

int readStr(void) {
       start();
       txData = MEMWR;
       sendByte();
       receiveAck();
       if(!ackFlag)
           return FAILURE;
       txData = address;
       sendByte();
       receiveAck();

       start();
       txData = MEMRD;
       sendByte();
       receiveAck();
       if(!ackFlag)
           return FAILURE;
for(int c=0; c < 32; c++){
receiveByte();
       sendAck();
dispBuffer[c] = rxData;
address++;
}
       stop();
       return SUCCESS;
   } // */
   int writeStr(void) {
     int c[2];
     for(c[0]=0; c[0] < 2; c[0]++) {
       start();
       txData = MEMWR;
       sendByte();
       receiveAck();
       if(!ackFlag)
           return FAILURE;
       txData = address;
       sendByte();
       receiveAck();
       if(!ackFlag)
           return FAILURE;
if(!c[0])
  sendInstruction(0x80);
if(c[0])
  sendInstruction(0xC0);
while(c[1] < 32){
  if(c[1] == 16)
    break;
       txData = dispBuffer[c[1]];
       sendByte();
       receiveAck();
       if(!ackFlag)
           return FAILURE;
address++;
c[1]++;
}
       stop();
     }
       return SUCCESS;
}

   int writeCharLCD(char data, bool rs) {
       start();
       txData = P1WR;
       sendByte();
       receiveAck();
       if(!ackFlag)
           return FAILURE;
       txData = data;
       sendByte();
       receiveAck();
       if(!ackFlag)
           return FAILURE;
       stop();
       rs ? (P1OUT |= RS) : (P1OUT &= ~RS);
P1OUT &= ~RW;
P1OUT &= ~EN;
__delay_cycles(50);
P1OUT |= EN;
       return SUCCESS;
   }
   int readStrLCD(void) {
       sendInstruction(0x80);
       writePort(0xFF);
P1OUT |= RW|RS;
P1OUT &= ~EN;
__delay_cycles(25);
readPort();
P1OUT |= EN;
__delay_cycles(100);
       return SUCCESS;
   }

int writePort(char data) {
   start();
   txData = P1WR;
   sendByte();
   receiveAck();
   if(!ackFlag)
     return FAILURE;
   txData = data;
   sendByte();
   receiveAck();
   if(!ackFlag)
     return FAILURE;
   stop();
   return SUCCESS;
}

int readPort(void) {
   start();
   txData = P1RD;
   sendByte();
   receiveAck();
   if(!ackFlag)
       return FAILURE;
   receiveByte();
   sendAck();
   stop();
   charData = rxData;
   return SUCCESS;
}

   // required
   // send byte to slave
   void sendByte(void) {
       P1DIR |= SDA;
bitCounter = 0;
       while(bitCounter < 8) {
           (txData & BIT7) ? (P1OUT |= SDA) : (P1OUT &= ~SDA);
           P1OUT |= SCL;
           txData <<= 1;
           P1OUT &= ~SCL;
    bitCounter++;
       }
       P1OUT |= SDA;
       P1DIR &= ~SDA;
   }
   // required
   // receive byte from slave
   void receiveByte(void) {
     bitCounter = 0;
       while(bitCounter < 8) {
           P1OUT |= SCL;
           rxData <<= 1;
           if(P1IN & SDA) {
               rxData |= BIT0;
           }
           P1OUT &= ~SCL;
    bitCounter++;
       }
   }
   // required
   // send master's ACK
   void sendAck(void) {
       P1DIR |= SDA;
       P1OUT &= ~SDA;
       P1OUT |= SCL;
       P1OUT &= ~SCL;
       P1OUT |= SDA;
       P1DIR &= ~SDA;
   }
   // required
   // receive slave's ACK
   void receiveAck(void) {
       P1OUT |= SCL;
       (P1IN & SDA) ? (ackFlag = false) : (ackFlag = true);
       P1OUT &= ~SCL;
   }
   // required
   // start condition
   void start(void) {
       P1OUT |= SCL;
       P1DIR |= SDA;
       P1OUT &= ~SDA;
       P1OUT &= ~SCL;
       P1OUT |= SDA;
       P1DIR &= ~SDA;

   }
   // required
   // stop condition
   void stop(void) {
       P1DIR |= SDA;
       P1OUT &= ~SDA;
       P1OUT |= SCL;
       P1OUT |= SDA;
       P1DIR &= ~SDA;
   }

As you can see here, I have the optimizations turned all the way up.

post-2374-135135511611_thumb.jpg

And here, you can see how much data the program occupies.

post-2374-135135511616_thumb.jpg

 

Am I just using too much data memory? (In other words, would I need a higher memory capacity uC to run this code?)

 

P.S: If it will help, I am using IAR Kickstart.

Link to post
Share on other sites

Thanks. As it turns out, it needed a lot more RAM for what I was trying to do.

 

Here are the results from the build for a 'G2252, which has twice the RAM that a 'G2231 has:

post-2374-135135511934_thumb.jpg

 

So, now that I know the 'G2252 will handle it, shall I order some samples from TI? Or would using USI be simpler and easier?

Link to post
Share on other sites

The USI is definitely simpler:post-2374-135135512251_thumb.jpg

A lot of this code was taken from a TI example, and heavily modified to reflect my previous compilation:

#include "msp430g2231_mod.h"


#define LED1 BIT7
#define LED2 BIT6
#define EN BIT5      // display ENABLE
#define RS BIT4      // display RS pin connected here
#define RW BIT3      // display R/W pin connected here
#define A2 BIT2
#define CS BIT1
#define KINT BIT0

#define MEMRD 0xA1     // EEPROM
#define MEMWR 0xA0     // EEPROM
#define P1RD 0x41      // port expander 1 read  // display databus connected here
#define P1WR 0x40      // port expander 1 write // display databus connected here
#define fail 0
#define success 1

#define hello_world "Hello! This     works!"

char buffer = 0;

void init_disp(void);
void wrLCD(char data, bool rs);
void sendStr(char string[]);
int tx_Data(char data);
int rx_Data(void);
/*
*  ======== main ========
*/
void main(void)
{
 BCSCTL1 = CALBC1_1MHZ;
 DCOCTL = CALDCO_1MHZ;

 P1OUT = 0xFF;
 P1REN |= 0xC1;
 P1DIR = 0xFE;
 P2OUT = 0xC0;
 P2DIR = 0xC0;

 USICTL0 = USIPE7 | USIPE6 | USIMST | USIOE | USISWRST;
 USICKCTL = USIDIV_4 + USISSEL_2 + USICKPL;
 USICTL1 = USII2C;
 USICTL0 &= ~USISWRST;

 init_disp();
 sendStr(hello_world);
}
void init_disp(void){
P1OUT &= ~RW + ~RS;
for(int t=0; t<2; t++){
	while(tx_Data == fail){
		tx_Data(0x38);
		P1OUT &= ~EN;
		P1OUT |= EN;
		tx_Data(0x0E);
		P1OUT &= ~EN;
		P1OUT |= EN;
		tx_Data(0x01);
		P1OUT &= ~EN;
		P1OUT |= EN;
		__delay_cycles(2000);
		tx_Data(0x06);
		P1OUT &= ~EN;
		P1OUT |= EN;
		__delay_cycles(200000);
	}
}
}
void wrLCD(char data, bool rs){
tx_Data(data);
rs ? (P1OUT |= RS) : (P1OUT &= ~RS);
P1OUT &= RW;
P1OUT &= ~EN;
P1OUT |= EN;
}
void sendStr(char string[]) {
wrLCD(0x80, 0);
for(int str = 0; string[str]; str++){
	if(str == 16){
		wrLCD(0xC0, 0);
	}
	if(str == 32){
		break;
	}
	wrLCD(string[str], 1);
}
}
int tx_Data(char data) {
P2OUT |= LED1;                // Turn led on, cycle starting...
   USISRL = 0x00;                // Generate Start Condition...
   USICTL0 |= USIGE+USIOE;
   USICTL0 &= ~USIGE;
   USISRL = P1WR;                   // Address is 0x40
   USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
   USICTL0 &= ~USIOE;               // SDA = input
   USICNT |= 0x01;                  // Bit counter=1, receive (N)Ack bit
   USICTL0 |= USIOE;                // SDA = output
   if (USISRL & 0x01)               // If Nack received...
     { // Send stop...
     USISRL = 0x00;
     USICNT |=  0x01;               // Bit counter=1, SCL high, SDA low
     USISRL = 0xFF;                 // USISRL = 1 to release SDA
     USICTL0 |= USIGE;              // Transparent latch enabled
     USICTL0 &= ~(USIGE+USIOE);     // Latch/SDA output disabled
     return fail;
   }
   else
     { // Ack received, TX data to slave...
     USISRL = data;                 // Load data byte
     USICNT |=  0x08;               // Bit counter = 8, start TX
     }
   USICNT |=  0x01;                 // Bit counter=1, SCL high, SDA low
   USISRL = 0xFF;                   // USISRL = 1 to release SDA
   USICTL0 |= USIGE;                // Transparent latch enabled
   USICTL0 &= ~(USIGE+USIOE);       // Latch/SDA output disabled
   P2OUT &= ~LED1;                  // Turn led off, cycle finished
   return success;
}
int rx_Data(void){
buffer = 0;
P2OUT |= LED2;                   // Turn led on, cycle starting...
   USISRL = 0x00;                   // Generate Start Condition...
   USICTL0 |= USIGE+USIOE;
   USICTL0 &= ~USIGE;
   USISRL = P1RD;                   // Address is 0x41
   USICNT = (USICNT & 0xE0) + 0x08; // Bit counter = 8, TX Address
   USICTL0 &= ~USIOE;               // SDA = input
   USICNT |= 0x01;                  // Bit counter=1, receive (N)Ack bit
   USICTL0 |= USIOE;                // SDA = output
   if (USISRL & 0x01)               // If Nack received...
     { // Send stop...
     USISRL = 0x00;
     USICNT |=  0x01;               // Bit counter=1, SCL high, SDA low
     USISRL = 0xFF;                 // USISRL = 1 to release SDA
     USICTL0 |= USIGE;              // Transparent latch enabled
     USICTL0 &= ~(USIGE+USIOE);     // Latch/SDA output disabled
     return fail;
   }
   else
     { // Ack received, RX data from slave...
	USICTL0 &= ~USIOE;           // SDA = input --> redundant
	USICNT |=  0x08;             // Bit counter = 8, RX data
	buffer = USISRL;             // The data in USISRL stored in buffer for later use
     }
   USICNT |=  0x01;                 // Bit counter=1, SCL high, SDA low
   USISRL = 0xFF;                   // USISRL = 1 to release SDA
   USICTL0 |= USIGE;                // Transparent latch enabled
   USICTL0 &= ~(USIGE+USIOE);       // Latch/SDA output disabled
   P2OUT &= ~LED2;                  // Turn led off, cycle finished
   return success;
}

Does anyone see any errors my compiler wouldn't catch?

Link to post
Share on other sites
  • 3 weeks later...

Ok, I've got to settle on one thing and stop changing my mind! :problem:

 

I think I have finally decided what kind of bus system I will use; an 8bit parallel bus, fashioned after the 8051 (Intel) timing.

It will have the standard RD and WR control lines, as well as the address and data buses.

The schematic:post-54-135135491542_thumb.jpg

Keyboard&LCD.sch

Link to post
Share on other sites

Do these make more sense?post-2374-135135516155_thumb.png

Something I forgot to mention earlier: to build this parallel bus, I had to switch to an MSP with more I/O.

post-2374-13513551616_thumb.pngpost-2374-135135516165_thumb.pngpost-2374-135135516436_thumb.png

And here is the current under-construction program:

#include "msp430g2252.h"

#define RD BIT7
#define WR BIT6
#define CK BIT2
#define G BIT1
#define DIR BIT0

#define hello_world "Malfunction!*Need Input!"

void init_disp(void);
void wrLCD(char data, bool rs);
void sendStr(char string[]);
void setAddr(char addr);
bool line = 0;

void main(void){
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;

P1OUT = 0xFF;
P1DIR = 0xFF;
P2OUT = 0xFF;
P2DIR = 0xFF;

init_disp();
sendStr(hello_world);

}

void wrLCD(char data, bool rs){
rs ? (setAddr(0x80)) : (setAddr(0x00));
P1OUT = data;
P2OUT &= ~WR;
P2OUT |= WR;
}

void init_disp(void){
setAddr(0x00);
for(int t=0; t<2; t++){
	P1OUT = 0x38;
	P2OUT &= ~WR;
	P2OUT |= WR;
	P1OUT = 0x0E;
	P2OUT &= ~WR;
	P2OUT |= WR;
	P1OUT = 0x01;
	P2OUT &= ~WR;
	P2OUT |= WR;
	__delay_cycles(2000);
	P1OUT = 0x06;
	P2OUT &= ~WR;
	P2OUT |= WR;
	__delay_cycles(200000);
}
}

void sendStr(char string[]) {
wrLCD(0x80, 0);
line=0;
for(int str=0; (str < 32) && string[str]; str++){
	if(!line && ((string[str] == '*') || (str == 16))){ //
		wrLCD(0xC0, 0);
		line=1;
		str++;
	}
	wrLCD(string[str], 1);
}
}

void setAddr(char addr){
P1OUT = addr;
P2OUT &= ~CK;
P2OUT |= CK;
}

 

And here's the build so far:post-2374-135135516442_thumb.jpg

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...