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.
Dear Sirs,
I need assistence in solving in C a problem related to the MCU MSP430F2274.
I would like to know if is possible to assign as components of an 8 bit array the pins of 2 different ports and treat it as if it were a single port.
For example:
DBPORT <-- [P4.6 ; P4.5 ; P4.4 ; P4.3 ; P2.3 ; P2.2 ; P2.1 ; P2.0 ]
DBPORT = 0x25 must be
[P4.6 ; P4.5 ; P4.4 ; P4.3 ; P2.3 ; P2.2 ; P2.1 ; P2.0]
0 0 1 0 0 1 0 1
I'm using IAR EW 4.21
Thank's in advance.
Silvio V.
There's no way to split a singleton (byte/word value) into two separate part on completely different addresses.
There are C extensions that allow sub-dividing a byte/word into fractions of bits.
You can, however, write two macros which allow easy handling of the data.
#define DBPORT_IN (((P4IN&0x78)<<1)|(P2IN&0x0f))
#define DBPORT_OUT(x) do{P4OUT = (P4OUT&0x87)|((x&0xf0)>>1); P2OUT=((P2OUT&0xf0)|(x&0x0f))}while(0)
With these macros, the desired bits are read with
val = DBPORT_IN;
and written with
DBPORT_OUT(val);
The do/While construct ansures that you can safely use the macro in an if construct
if(x) DBPORT_OUT(y);
While this solution makes it easy to handle your weird port setup, it produces significanly more code than a simple read/write to a full 8 bit port. And is much slower, because two 'helper' registers and some AND/SHIFT/OR operations are required before the result can be written to the destination (either way), compared to a simple move x to y assembly instruction.
Alternatively, you can write two functions to do the job, but even if you define them as inline functions, the compiler cannot optimize the resulting code nearly as good as it can be done using these macros.
Thankyou very much!
I have a problem whit this solution...
When i use
DBPORT_OUT(0x38); // 0x38 is only an example...
or if I do something like that:
void doSomething(unsigned char k) {
........
DBPORT_OUT(k);
........
}
in building I have an error at DBPORT_OUT(): expected a ";"
Why that?
I think you need another ";"
#define DBPORT_OUT(x) do{P4OUT = (P4OUT&0x87)|((x&0xf0)>>1); P2OUT=((P2OUT&0xf0)|(x&0x0f)) ; }while(0)
YUUUP!!!!
YOU ARE THE MAN!!! :D
Now I can use this code:
//######################## DESCRIPTION ########################//
//
// Function (hoped): Init Display and Write the Character "A"
//
//
// MSP430F2274 DISLPAY LCD : 8bit mode
// --------------- ---------------
// | | | |
// | P4.6|-------|DB7 |
// | P4.5|-------|DB6 |
// | P4.4|-------|DB5 |
// | P4.3|-------|DB4 |
// | | | |
// | P2.3|-------|DB3 |
// | P2.2|-------|DB2 |
// | P2.1|-------|DB1 |
// | P2.0|-------|DB0 |
// | | | |
// | P3.2|-------|E |
// | P3.1|-------|RW |
// | P3.0|-------|RS(DI) |
// | | | |
// --------------- ---------------
//
// DEVELOPED USING:
// - TI ez430-F2013 WITH AMB8423 TargetBoard
// (AMB8423 is pin to pin compatible with RF2500 Target Board, only
// difference in RF circuit)
// - Newhaven 8x1 Character Display NHD-0108CZ-FSW-GBW-3V3
// - BreadBox with many wires :p
// - IAR 4.21
//
// DISPLAY DATASHEET:
// http://www.newhavendisplay.com/specs/NHD-0108CZ-FSW-GBW-3V3.pdf
//
//################################################################//
#include "msp430x22x4.h"
#define DBPORT_IN (((P4IN&0x78)<<1)|(P2IN&0x0f))
#define DBPORT_OUT(x) do{P4OUT = (P4OUT&0x87)|((x&0xf0)>>1); P2OUT=((P2OUT&0xf0)|(x&0x0f)); }while(0)
#define MSB3 (0x40) //BIT6 USED ON PORT 4 => P4.6
#define MSB2 (0x20) //BIT5 USED ON PORT 4 => P4.5
#define MSB1 (0x10) //BIT4 USED ON PORT 4 => P4.4
#define MSB0 (0x08) //BIT3 USED ON PORT 4 => P4.3
#define LSB3 (0x08) //BIT3 USED ON PORT 2 => P2.3
#define LSB2 (0x04) //BIT2 USED ON PORT 2 => P2.2
#define LSB1 (0x02) //BIT1 USED ON PORT 2 => P2.1
#define LSB0 (0x01) //BIT0 USED ON PORT 2 => P2.0
#define E (0x04) //BIT2 USED ON PORT 3 => P3.2
#define RW (0x02) //BIT1 USED ON PORT 3 => P3.1
#define DI (0x01) //BIT0 USED ON PORT 3 => P3.0
void lcdBusy();
void lcdInit();
void sendCommand(unsigned char k);
void sendChar(unsigned char c);
void sendString(unsigned char *str);
void main() {
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer to prevent time out reset
P4SEL &= ~(MSB3 | MSB2 | MSB1 | MSB0); //P4.6-3 are GPIO
P4DIR |= (MSB3 | MSB2 | MSB1 | MSB0); //P4.6-3 are OUTPUT
P4OUT &= ~(MSB3 | MSB2 | MSB1 | MSB0); //P4.6-3 reset
P2SEL &= ~(LSB3 | LSB2 | LSB1 | LSB0); //P2.3-0 are GPIO
P2DIR |= (LSB3 | LSB2 | LSB1 | LSB0); //P2.3-0 are OUTPUT
P2OUT &= ~(LSB3 | LSB2 | LSB1 | LSB0); //P2.3-0 reset
P3SEL &= ~(E | RW | DI); //P3.2-0 are GPIO
P3DIR |= (E | RW | DI); //P3.2-0 are OUTPUT
P3OUT &= ~(E | RW | DI); //P3.2-0 reset
lcdInit();
sendChar('A');
}
void lcdInit() {
sendCommand(0x30); //WakeUP #1
lcdBusy();
sendCommand(0x30); //WakeUP #1
lcdBusy();
sendCommand(0x30); //WakeUP #1
lcdBusy();
sendCommand(0x30); //Function set: 1 Line, 8-bit, 5x8 dots
lcdBusy();
sendCommand(0x01); //Clear Display
lcdBusy();
sendCommand(0x10); //Set Cursor
lcdBusy();
sendCommand(0x0F); //Display on, Curson blinking
lcdBusy();
sendCommand(0x06); ///Entry mode, auto increment with no shift
lcdBusy();
}
void sendCommand(unsigned char k) {
DBPORT_OUT(k); //Function set: 2 Line, 8-bit, 5x7 dots
P3OUT &= ~(RW | DI); //RW=0 -> write - DI=0 -> instruction
P3OUT |= (E); //set enable
P3OUT &= ~(E); //reset enable : falling trigger
lcdBusy(); //Wait for LCD to process the command
}
void sendChar(unsigned char c) {
DBPORT_OUT(c); //Function set: 2 Line, 8-bit, 5x7 dots
P3OUT &= ~(RW); //RW=0 -> write
P3OUT |= (DI); //DI=0 -> data
P3OUT |= (E); //set enable
P3OUT &= ~(E); //reset enable : falling trigger
lcdBusy(); //Wait for LCD to process the command
}
void sendString(unsigned char *str) {
while(*str) //till string ends
sendChar(*str++); //send characters one by one
}
void lcdBusy() {
volatile unsigned char i,j;
for(i=0;i<50;i++) {
for(j=0;j<255;j++){
__no_operation;
}
}
}
Unlikely my code don't on the display :( ... I think it's a problem of the target board... no idea! :(
Hi Silvio,
have a look at 'My Files' here http://e2e.ti.com/members/1371069/files/default.aspx . I've posted some 'driver' routines for standard 16x2 character LCD dispalys there. Maybe you can put them to good use. Use the macros DBPORT_OUT from Jens-Miachael for data processing
Rgds
aBUGSworstnightmare
eltury said:I think you need another ";"
Argh! Of course you're right. Looks like I'm not typo-proof.
I actually tested this macro before I posted it (not for functionality, but to test whether the precompiler can support two macros with the same name, one with () and one without), but since the editor here does its own things if you copy/paste something, I just retyped it - and missed the ';'.
So what's wrong...
First, lcdBusy will not exactly work as intended. Since I and J are local variables and never referenced outside the function (i.e. a reference to them given as parameter to an external function), the 'volatile' keyword will most likely be ignored. This means that the compiler can still decide whether to unroll or partially unroll the for loops. IN any case, the __no_operation will be executed 12750 times (which is 12.750ms @1Mhz MCLK), but you don't know whether the loop check for I is also executed as often (adding another 60ms to the execution time) or less often. If MCLK is faster than 1MHz, the delay times are slower.
If you need a delay, it's best to set up a timer and use it as delay counter. It's the only reliable delay source. Set up a timer to be sourced with 1MHz (ACLK or SMCLK) and use one of the capture-compare register to the required delay in microseconds (TACCR2 =TAR+delay;). Then make a while(!(TACCR2&CCRIFG)); The code will (busy-)wait until the given number of microseconds have passed. Maybe a bit stretched if an IRQ happens near the end of the delay and hasn't finished when the delay ends.
In your init function, the first delay might be too short (depending on your MCLK), the other ones are much too long (won't hurt). Also, you call lcdBusy() inside commandSet(), which is superfluous, and after every command in your init function, which is much too long for most commands (38 microseconds required, which is an estimated factor of 1000 less than what you wait).
Silvio Vallorani said:P3OUT |= (E); //set enable
P3OUT &= ~(E); //reset enable : falling trigger
Between these two lines, one NOP should be placed, depending on MCLK. It should be okay up to 5MHz but above it could violate the timing requirements. Since E in your setup is bit 3 and therefore not available through the constant generator, the bit set/clear operation takes 5 MCLK cycles, but if the code is ever reused with bit 1,2or4, 4MHz will be the critical limit. Your current code seems to run on DCO default speed, which is much below that, but if you expand your project later and use an external crystal...
Other than this, I cannot see anything wrong with your code.
**Attention** This is a public forum