Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Freaky C30 problems

Status
Not open for further replies.

futz

Active Member
This is so strange... :confused: I'm trying to get an LCD working on my dsPIC30F4013. Here's a code snip
Code:
int main(void)
{
	TRISA=3;
	TRISB=5;
	TRISD=7;
If I single step thru that in the Simulator and watch the results in the Watch window I get
Code:
TRISA 0x0000
TRISB 0x0005
TRISD 0x0007
What happened to TRISA? Why didn't it change?

And when I do
Code:
	PORTA=3;
	PORTB=5;
	PORTD=7;
in the Watch window I get
Code:
PORTA 0x0000
PORTB 0x0000
PORTD 0x0007
I've tried with LATA/LATB too. Seems like I can't change Ports A or B at all.
 
Last edited:
Well PORTA only has one bit (bit11) that is valid. So that appears to be normal.
How is PORTB configured? Is it set to digital mode and not ADC mode?
 
After much searching and reading and getting nowhere, I finally had a look at the assembler code the compiler is outputting. Looks fine. It seems the problem is a totally broken simulator. There are people over at the Microchip forums saying there are big problems simulating 24H chips too. Many bugs to be stomped.

I kinda sorta had an idea that might be it from the start, cuz the LCD almost works. It appears that my char array pointer is out to lunch though, because the LCD just prints junk. And without a proper debugger or simulator, not to mention that I'm a newb at C again because of too many years gone by without using it, I'm having a tough time finding the problem.
 
Last edited:
kchriste said:
Well PORTA only has one bit (bit11) that is valid. So that appears to be normal.
Really!?!?!? That's why the bitfield mouseover only shows one then? That's interesting. I was wondering about that. Umm... Why? I haven't read the entire datasheet yet. :p

Anyway, I'm only using that one bit. The code snip was a test - not values that would actually be in there.

How is PORTB configured? Is it set to digital mode and not ADC mode?
Yes, ADPCFG=0. And all outputs.
 
It should be:
ADPCFG = 0xFFFF;
To change the port to digital. Yes, it is opposite to other chips. :rolleyes:
 
kchriste said:
If you haven't already, download the dsPIC30F Family Reference Manual:
https://www.electro-tech-online.com/custompdfs/2008/03/70046E-1.pdf
Yes, I have it. I just dug thru the 4013 datasheet and, believe it or not, nowhere in there do they say how to set the bits for ADPCFG. There's nothing. I was misreading stuff about TRIS bits and thinking they meant ADPCFG.

The proper settings ARE in the 30F Family Reference Manual. Now I'll just keep em both open while programming. :D

Thanks Kchriste!
 
Yeah, you need both the family reference manual and the dsPIC specific manual. THey both have mutually exclusive information.
 
Yep the ADCPFG (H/L on some models) trips up 90% of the first-timers. For days. I have no idea why they made this register default to analog functionality with digital function disabled.

On models with 2 ADCs, you must be certain that neither has the pin in analog mode since that'll disable the digital.

I've worked quite a bit with the 33F series. IMHO it is a better chip! Faster, much lower power, DMA controller.
 
Hehehe!!! :D She LIVES! Finally got enough C pounded back into my head to get the LCD working on dsPIC30F4013. :p

I was SO tempted to put some inline assembler in there (SO much easier to do some things than in C), but they make it so difficult in C30 that I dropped the idea after some experimentation. I used to program PC's with Borland C/C++. Inline assembler is totally easy with Borland's compiler. With C30, not so much.

dspic_lcd002sm.jpg
 
Last edited:
Congratulations,

Just for fun, these are routines I wrote in C18 for an LCD. How do they compare to yours?

Mike.
Code:
//wait for the LCD to finish last command.
void WaitLCDBusy(void){
    LCD_TRIS_BUSY = 1;              //set pin to input
    LCD_RS = 0;                     //Command
    LCD_RW = 1;                     //We want to read
    LCD_E=1;                        //enable LCD interface
    while(LCD_BUSY);                //wait for busy to clear
    LCD_E=0;                        //disable LCD interface
    LCD_TRIS_BUSY = 0;              //restore pin to output
}

//Send a command to the LCD
void WriteCommand(unsigned char command){
    WaitLCDBusy();                  //wait until not busy
    LCD_RS = 0;                     //setup to send command
    WriteNibble(command);           //write the high nibble
    WriteNibble(command<<4);        //then the low nibble
}

//Send a character to the LCD
void WriteChar(unsigned char chr){
    WaitLCDBusy();                  //wait until not busy
    LCD_RS=1;                       //Setup to send character
    WriteNibble(chr);               //write the high nibble
    WriteNibble(chr<<4);            //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command){
    LCD_RW=0;                       //we want to write
    LCDPORT &= 0x0F;                //clear the data bits
    LCDPORT |= (command & 0xf0);    //or in the new data
    LCD_E = 1;                      //enable the LCD interface
    LCD_E = 0;                      //disable it
}
 
Pommie said:
Just for fun, these are routines I wrote in C18 for an LCD. How do they compare to yours?
Well, mine are still pretty unpolished. Pretty much a port of my 16F/18F asm code.

I haven't figured out a way to do precise delays in C, so my delays are way too long (to be on the safe side). Delays are the reason I was wanting to do inline assembly. I'll figure something out eventually, like adding a R/W line and checking for busy. I have to do something, because if I turn up the wick on this chip it's way too fast to run without some delays (120MHz top end).

My LCD is pinned as follows:
D4 - RB9
D5 - RB10
D6 - RB11
D7 - RB12
RS - RA11
E - RD9

Code:
void WaitLCDBusy(void){}
I don't have busy checking yet.

Hmm... What to post... Oh what the hell. I'll just post it all! :D
Code:
#include "p30f4013.h"

_FOSC(FRC)					//osc
_FWDT(WDT_OFF)
_FBORPOR(MCLR_EN & PWRT_OFF)			//MCLR enable & power-up timers off
_FGS(CODE_PROT_OFF)

void lcd_line1(void);				//function prototypes
void lcd_line2(void);
void lcd_cmd(unsigned char);
void lcd_char(char);
void e_togg(void);
void delay(void);
void del_5ms(void);
void lcd_init(void);
void lcd_string();

char sentence[16] = "dsPIC 30F4013";
char *senpoint = sentence;

int main(void)
{
	ADPCFG=0xffff;
	TRISA=0;				//PORTs all outputs
	TRISB=0;
	TRISD=0;
	LATA=0;
	LATB=0;
	LATD=0;
	delay();
	delay();
	delay();
	delay();
	lcd_init();
	delay();
	lcd_string();
	for(;;){}
	return 0;
}

void lcd_string(void)
{
	while(*senpoint != '\0')
	{
		lcd_char(*senpoint);
		senpoint++;
	}
}	

void lcd_line1(void)
{
	lcd_cmd(0x80);
}

void lcd_line2(void)
{
	lcd_cmd(0xc0);
}		

void lcd_cmd(unsigned char letter)
{
	LATB = letter;				//put char in PORTB
	del_5ms();
	PORTB = PORTB << 5;			//shift over to output high 4 bits on RB9,10,11,12
	LATAbits.LATA11 = 0;			//RS low
	del_5ms();
	e_togg();				//latch the data
	PORTB = PORTB << 4;			//shift over to output low 4 bits
	LATAbits.LATA11 = 0;			//RS low
	e_togg();				//latch it
}

void lcd_char(char letter)
{
	LATB = letter;				//put char in PORTB
	del_5ms();
	PORTB = PORTB << 5;			//shift over to output high 4 bits on RB9,10,11,12
	LATAbits.LATA11 = 1;			//RS high
	del_5ms();
	e_togg();				//latch the data
	PORTB = PORTB << 4;			//shift over to output low 4 bits
	LATAbits.LATA11 = 1;			//RS high
	e_togg();				//latch it
}

void e_togg(void)
{
	LATDbits.LATD9=1;
	del_5ms();
	LATDbits.LATD9=0;
}

void lcd_init(void)
{
	LATB = 0x0600;				//send 3
	e_togg();
	delay();
	LATB = 0x0600;
	e_togg();
	del_5ms();
	LATB = 0x0600;
	e_togg();
	del_5ms();
	LATB = 0x0400;				//send 2 - set 4-bit mode
	e_togg();
	del_5ms();
	lcd_cmd(0x28);				//set 4-bit mode and 2 lines
	del_5ms();
	lcd_cmd(0x10);				//cursor move & shift left
	del_5ms();
	lcd_cmd(0x06);				//entry mode = increment
	del_5ms();
	lcd_cmd(0x0d);				//display on - cursor blink on
	del_5ms();
	lcd_cmd(0x01);				//clear display
	delay();
}

void delay(void)
{
	int var1,var2;
	for(var1=0;var1!=10;var1++)
	{
		for(var2=0;var2!=10000;var2++);
	}
}

void del_5ms(void)
{
	int var1,var2;
	for(var1=0;var1!=10;var1++)
	{
		for(var2=0;var2!=2000;var2++);
	}
}
 
Last edited:
I added an R/W line and implemented busy-checking last night. Wow! That IS fast and nice, and unlike delays it doesn't have to be modified every time I change clock speed. Should have done that long ago.

Now to rewrite some sections so it's more useful instead of being just a test... :)

Thanks everyone for your help. :D

EDIT: Here's the code:
Code:
#include "p30f4013.h"

_FOSC(FRC)				//osc
_FWDT(WDT_OFF)
_FBORPOR(MCLR_EN & PWRT_OFF)		//MCLR enable & power-up timers off
_FGS(CODE_PROT_OFF)			//Code Protection off

void lcd_line1(void);			//function prototypes
void lcd_line2(void);
void lcd_cmd(unsigned char);
void lcd_char(char);
void e_togg(void);
void lcd_init(void);
void lcd_string();
void lcd_busy(void);

char sentence[16] = "dsPIC 30F4013";
char *senpoint = sentence;

#define	E		LATDbits.LATD9
#define	RS		LATAbits.LATA11
#define RW		LATCbits.LATC14
#define	busyflag	PORTBbits.RB12
#define RW_TrisBit	TRISCbits.TRISC14
#define D7_TrisBit	TRISBbits.TRISB12

int main(void)
{
	ADPCFG = 0xffff;		//all digital
	TRISA = 0;			//PORTs all outputs
	TRISB = 0;
	TRISC = 0;
	TRISD = 0;
	RW = 0;				//set R/W low
	E = 0;				//set E low
	lcd_busy();			//wait for LCD to settle
	lcd_init();
	lcd_string();			//send string to LCD
	for(;;){}			//spin forever
	return 0;
}

void lcd_string(void)
{
	while(*senpoint != '\0')
	{
		lcd_char(*senpoint);
		senpoint++;
	}
}	

void lcd_busy(void)
{
	RW_TrisBit = 1;			//make R/W input (read)
	D7_TrisBit = 1;			//make D7 input
	RS = 0;				//set RS low
	RW = 1;				//set R/W high
	E = 1;				//set E high
	while(busyflag);		//wait for busy flag to go low
	E = 0;				//set E low
	RW = 0;				//set R/W low
	TRISB = 0;			//make D7 output
	RW_TrisBit = 0;			//make R/W output (write)
}	
	
void lcd_line1(void)
{
	lcd_cmd(0x80);
}

void lcd_line2(void)
{
	lcd_cmd(0xc0);
}		

void lcd_cmd(unsigned char letter)
{
	LATB = letter;			//put char in PORTB
	lcd_busy();
	PORTB = PORTB << 5;		//shift over to output high 4 bits on RB9,10,11,12
	RS = 0;				//RS low
	e_togg();			//latch the data
	PORTB = PORTB << 4;		//shift over to output low 4 bits
	RS = 0;				//RS low
	e_togg();			//latch it
}

void lcd_char(char letter)
{
	LATB = letter;			//put char in PORTB
	lcd_busy();
	PORTB = PORTB << 5;		//shift over to output high 4 bits on RB9,10,11,12
	RS = 1;				//RS high
	e_togg();			//latch the data
	PORTB = PORTB << 4;		//shift over to output low 4 bits
	RS = 1;				//RS high
	e_togg();			//latch it
}

void lcd_init(void)
{
	LATB = 0x0600;			//send 3
	e_togg();
	lcd_busy();
	LATB = 0x0600;
	e_togg();
	lcd_busy();
	LATB = 0x0600;
	e_togg();
	lcd_busy();
	LATB = 0x0400;			//send 2 - set 4-bit mode
	e_togg();
	lcd_busy();
	lcd_cmd(0x28);			//set 4-bit mode and 2 lines
	lcd_busy();
	lcd_cmd(0x10);			//cursor move & shift left
	lcd_busy();
	lcd_cmd(0x06);			//entry mode = increment
	lcd_busy();
	lcd_cmd(0x0d);			//display on - cursor blink on
	lcd_busy();
	lcd_cmd(0x01);			//clear display
	lcd_busy();
}

void e_togg(void)
{
	E=1;
	E=0;
}
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top