CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Global Interrupts being disabled with lcd_putc function call

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jonwte



Joined: 21 May 2012
Posts: 3

View user's profile Send private message

Global Interrupts being disabled with lcd_putc function call
PostPosted: Mon May 21, 2012 11:05 am     Reply with quote

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: 19369

View user's profile Send private message

PostPosted: Mon May 21, 2012 12:54 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 21, 2012 1:43 pm     Reply with quote

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: 19369

View user's profile Send private message

PostPosted: Mon May 21, 2012 2:21 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 21, 2012 4:12 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon May 21, 2012 4:23 pm     Reply with quote

Printing a const string worked... thanks!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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