|
|
View previous topic :: View next topic |
Author |
Message |
jonwte
Joined: 21 May 2012 Posts: 3
|
Global Interrupts being disabled with lcd_putc function call |
Posted: Mon May 21, 2012 11:05 am |
|
|
PIC: 16F1518
Power: 5V
Clock: 16mHz
Compiler: IDE, PCB, PCM, PCH Version 4.132
I am having issues with my interrupts being disabled when I am writing to an LCD. I have an LCD as well as a 4 character 7-segment display. The 7-segment display characters all use the same data lines and I just activate one character at a time but I do this fast enough so that it appears all four character are on. I do this in Timer 0 which is interrupting at a 1mS period. Everything works fine until I write to my LCD. When I do this, the global interrupt enable bit is cleared and my 7-segment display flickers. I checked the .LST file and verified that the GIE bit is being cleared when I write to the LCD.... BCF 0B.7. How can I keep the interrupts from being disabled?
Code: |
#include <16F1518.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES WDT_SW //No Watch Dog Timer, enabled in Software
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES BORV25 //Brownout reset at 2.5V
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(internal=16000000)
#use FIXED_IO( A_outputs=PIN_A7,PIN_A6,PIN_A5,PIN_A4,PIN_A3,PIN_A2,PIN_A1,PIN_A0 )
#use STANDARD_IO(B)
#use STANDARD_IO(C)
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=PC,errors)
#define DIG4_7SEG PIN_B0
#define DIG1_7SEG PIN_B1
#define DIG2_7SEG PIN_B2
#define DIG3_7SEG PIN_B3
#define LCD_RS_PIN PIN_C0
#define LCD_RW_PIN PIN_C1
#define LCD_ENABLE_PIN PIN_B5
#define LCD_DATA4 PIN_C2
#define LCD_DATA5 PIN_C3
#define LCD_DATA6 PIN_C4
#define LCD_DATA7 PIN_C5
#define IDLE_SCREEN_TIME 15000 //15 seconds
#include "lcd_driver.c"
short displayOnce;
int16 displayCnt;
int errCode[4];
void SevenSegment(int);
#int_TIMER0
void TIMER0_isr(void)
{
int digit;
output_low(DIG1_7SEG);
output_low(DIG2_7SEG);
output_low(DIG3_7SEG);
output_low(DIG4_7SEG);
if(digit == 3)
digit = 0;
else
digit++;
sevenSegment(errCode[digit]);
if(digit==0)
output_high(DIG1_7SEG);
else if(digit==1)
output_high(DIG2_7SEG);
else if(digit==2)
output_high(DIG3_7SEG);
else if(digit==3)
output_high(DIG4_7SEG);
displayCnt++;
}
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16|RTCC_8_bit); //1 ms overflow
disable_interrupts(INT_TIMER0);
disable_interrupts(GLOBAL);
displayOnce = 0;
displayCnt = 0;
delay_ms(100);
lcd_init();
errCode[0] = 10;
errCode[1] = 10;
errCode[2] = 10;
errCode[3] = 10;
delay_ms(3000);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(TRUE)
{
if(displayCnt<IDLE_SCREEN_TIME/2 && displayOnce == 0){
printf(PC,"System Idle\r\n");
printf(lcd_putc,"\f\a System Idle");
displayOnce = 1;
}
else if(displayCnt>=IDLE_SCREEN_TIME/2 && displayOnce == 1){
printf(lcd_send_char,"\f\a Waiting for\n User Input");
displayOnce=0;
}
if(displayCnt>=IDLE_SCREEN_TIME){
displayCnt = 0;
displayOnce = 0;
}
errCode[0] = 0;
errCode[1] = 0;
errCode[2] = 0;
errCode[3] = 0;
}
}
void SevenSegment(int num)
{
switch(num)
{
case 0:
// .GFEDCBA
output_a(0b00111111);
break;
case 1:
// .GFEDCBA
output_a(0b00000110);
break;
case 2:
// .GFEDCBA
output_a(0b01011011);
break;
case 3:
// .GFEDCBA
output_a(0b01001111);
break;
case 4:
// .GFEDCBA
output_a(0b01100110);
break;
case 5:
// .GFEDCBA
output_a(0b01101101);
break;
case 6:
// .GFEDCBA
output_a(0b01111101);
break;
case 7:
// .GFEDCBA
output_a(0b00000111);
break;
case 8:
// .GFEDCBA
output_a(0b01111111);
break;
case 9:
// .GFEDCBA
output_a(0b01100111);
break;
case 10: //dash -
// .GFEDCBA
output_a(0b01000000);
break;
default: //error E
// .GFEDCBA
output_a(0b01111001);
break;
}
}
|
LCD Driver
Code: |
void LCD_TOGGLE_ENABLE(void) {
output_high(LCD_ENABLE_PIN);
delay_ms(1);
output_low(LCD_ENABLE_PIN);
}
void lcd_send_char(int c)
{
output_low(LCD_RS_PIN);
output_bit(LCD_DATA7,c & 0x80);
output_bit(LCD_DATA6,c & 0x40);
output_bit(LCD_DATA5,c & 0x20);
output_bit(LCD_DATA4,c & 0x10);
output_high(LCD_RS_PIN);
output_low(LCD_RW_PIN);
LCD_TOGGLE_ENABLE();
output_bit(LCD_DATA7,c & 0x08);
output_bit(LCD_DATA6,c & 0x04);
output_bit(LCD_DATA5,c & 0x02);
output_bit(LCD_DATA4,c & 0x01);
LCD_TOGGLE_ENABLE();
}
void lcd_send_cmd(int c)
{
output_low(LCD_RS_PIN);
output_bit(LCD_DATA7,c & 0x80);
output_bit(LCD_DATA6,c & 0x40);
output_bit(LCD_DATA5,c & 0x20);
output_bit(LCD_DATA4,c & 0x10);
output_low(LCD_RS_PIN);
output_low(LCD_RW_PIN);
LCD_TOGGLE_ENABLE();
output_bit(LCD_DATA7,c & 0x08);
output_bit(LCD_DATA6,c & 0x04);
output_bit(LCD_DATA5,c & 0x02);
output_bit(LCD_DATA4,c & 0x01);
LCD_TOGGLE_ENABLE();
}
void lcd_init(void)
{
output_low(LCD_RS_PIN);
output_low(LCD_RW_PIN);
output_low(LCD_ENABLE_PIN);
output_low(LCD_DATA4);
output_low(LCD_DATA5);
output_low(LCD_DATA6);
output_low(LCD_DATA7);
delay_ms(50);
LCD_TOGGLE_ENABLE();
delay_ms(50);
LCD_TOGGLE_ENABLE();
delay_ms(5);
LCD_TOGGLE_ENABLE();
delay_ms(5);
output_high(LCD_DATA5); //sending 0x2
LCD_TOGGLE_ENABLE();
delay_ms(5);
lcd_send_cmd(0x28); //function set
lcd_send_cmd(0x10); //display off
lcd_send_cmd(0x0C); //display clear
lcd_send_cmd(0x06); //cursor display shift
lcd_send_cmd(0x01); //display clear
lcd_send_cmd(0x02); //home command
}
void lcd_gotoXY(int pos, int line)
{
int addr;
if(line == 2)
addr = 0x40;
else
addr = 0x00;
addr = 0x80|(addr + pos - 1);
lcd_send_cmd(addr);
}
void lcd_clear(void)
{
lcd_send_cmd(0x01); //clear display
}
void lcd_goHome(void)
{
lcd_send_cmd(0x02); //go home
}
void lcd_putc(char ch)
{
switch(ch)
{
case '\a':
lcd_goHome();
break;
case '\f':
lcd_clear();
break;
case '\n':
lcd_gotoXY(1,2);
break;
default:
lcd_send_char(ch);
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19447
|
|
Posted: Mon May 21, 2012 12:54 pm |
|
|
Look for a thread entitled "Global interrupts disabled mysteriously".
The problem was that printf, looks if it accesses any variable that is also used in an ISR, and if so, disables GIE, to avoid it changing during the print. You can disable this, by copying all variables used in the ISR to a local copy for use in the printf.
As a separate comment, 'digit', needs to be a static variable in your ISR.
Best Wishes |
|
|
jonwte
Joined: 21 May 2012 Posts: 3
|
|
Posted: Mon May 21, 2012 1:43 pm |
|
|
I have looked at that thread. However, I don't know if that is the issue. I am not using any variable in my ISR that I pass to printf. It doesn't appear to be the printf that is disabling the GIE bit. If I simply call lcd_putc or lcd_send_char, looking thru the .LST file, both of these calls disable the GIE bit. Also, when I use printf to send data out of my UART, the GIE bit is not being disabled. It appears the issue is somewhere in my LCD driver code. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19447
|
|
Posted: Mon May 21, 2012 2:21 pm |
|
|
So, start by trying with the flex_lcd driver instead.
99.99% reliable, already known to work LCD code.
There are several things in your code that are 'dubious'. For instance, your bit outputs, should be using:
output_bit(LCD_DATA7,(c & 0x08)!=0);
and the same for every other bit. Output_bit accepts a 0, or 1 for the last parameter. You are assuming that a non zero value will cast to a 0 or 1, but the compiler's behaviour on this has changed at times in the past, and will probably change again. It may well be that the implicit cast gets affected if the scratch area changes.
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon May 21, 2012 4:12 pm |
|
|
I stripped down the program and looked at the .LST file. When printf
has a constant string embedded in it, the compiler puts in code to read
the string from flash memory, using the PMxxx registers. This is the
code that disables the GIE bit.
Code: |
#include <16F1518.h>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
void lcd_send_char(char c)
{
putc(c);
}
//=======================================
void main()
{
printf(lcd_send_char, "\f\a Waiting for\n User Input");
while(1);
} |
To see this code, you have to comment out the #nolist statement in
the 16F1518.h file. Then re-compile and you will see it in the .LST file:
Code: |
0019: MOVF INTCON,W
001A: MOVWF @@21
001B: BCF INTCON.GIE <== disables global interrupts
001C: MOVLB 03
001D: BSF PMCON1.-
001E: BSF PMCON1.RD
001F: NOP
0020: NOP
0021: MOVF PMDATL,W
.
.
.
|
But if you change the code to declare a 'const' string and then pass that
argument to the printf(), then it doesn't use the flash-memory-access
code. It puts the string in sequential RETLW statements, which is the
more usual way for CCS to do it. In this case, it doesn't disable interrupts.
Code: |
void main()
{
const char str1[] = "\f\a Waiting for\n User Input";
printf(lcd_send_char, "%s", str1);
while(1);
}
|
Here is the first part of the .LST file for the string:
Code: |
0003: RETLW 0C
0004: RETLW 07
0005: RETLW 20
0006: RETLW 20
0007: RETLW 57
0008: RETLW 61
0009: RETLW 69
.
.
.
|
So if it's important to you that interrupts not be disabled by the compiler
then the 2nd method can be used as a work-around. |
|
|
jonwte
Joined: 21 May 2012 Posts: 3
|
|
Posted: Mon May 21, 2012 4:23 pm |
|
|
Printing a const string worked... thanks! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|