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 CCS Technical Support

Problem with INT_RDA and INT_TBE on PIC16F88

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



Joined: 26 Feb 2012
Posts: 9
Location: Pretoria

View user's profile Send private message

Problem with INT_RDA and INT_TBE on PIC16F88
PostPosted: Mon Aug 13, 2012 1:21 am     Reply with quote

Hi,
I have question, can we enable both interrupt for serial receive buffer (INT_RDA) and serial empty buffer (INT_TBE) at the same time on PIC16f88 ?

My problem is when I use this code below:
Code:
 
enable_interrupts(INT_TBE);
enable_interrupts(INT_RDA);
 


My PIC crashes; if I remove one of the above line, it works normally.

Do you have any solution to my problem ? I'm using CCS PCWHD 3.134 Exclamation
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Mon Aug 13, 2012 1:37 am     Reply with quote

well, if that's all the code in your program.. who knows what's going on.

Perhaps you should post a short compilable example like everyone is requested to do when posting?

Aside from that, I've used both RDA and TBE successfully. But then again, I had full ISR's and proper routines to support them.

-Ben
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Aug 13, 2012 2:06 pm     Reply with quote

Nobody CAN help you if you dont post code - a LOT more code - including
the ISRS, PIC setup / INIT code and any external factors we should know about how you use external devices.


There is not enough to decide anything from what you posted.
Chapre



Joined: 26 Feb 2012
Posts: 9
Location: Pretoria

View user's profile Send private message

PostPosted: Wed Aug 15, 2012 5:36 am     Reply with quote

Hi thanks for your reply, here's my full code, the problem reside on my initialisations (the 2 last functions, "void initialize() " and "void main()").
If I comment out "enable_interrupts(INT_TBE)" everything works perfectly but if uncommented my PIC crashes when the program reaches that line.

I'm using PCWHD v4.130

Code:

#include <LCD.h>
#include "flex_lcd.c"
#define KEYMAP_SIZE 16
#define MAP_INTERVAL 70
#define MENU_ITEMS 3
#define BREAKER_TIMEOUT 43

// --- global values ------------
unsigned int16 adc_value=0;
signed int active_menu=0;
int1 update_request=0;

signed int8 cursor=0;signed int8 cursor2=0;
unsigned char serial_val;unsigned int16 break_counter=0;
char line1[KEYMAP_SIZE]={0};char line2[KEYMAP_SIZE]={0};
int data_in_couter=0;int data_out_couter=0;

char menus[MENU_ITEMS][16]={"Editor","ADC QLB","Tools"};
unsigned char key=0;
unsigned int16 keys[16]={37652,65408,61952,58944,53887,51520,49408,44992,43328,41856,56128,47424,40384,35392,38912,36520};

int1 data_out=0;int1 data_in=0;

//--------- addon functions ------------------
void clearDisplay()
{
   lcd_send_byte(0,1);
   delay_ms(2);
}

void lcd_setcursor_vb(short visible, short blink)
{
   lcd_send_byte(0, 0xC|(visible<<1)|blink);
}

void clearLine(char line[])
{
   int i=0;
   for(i=0;i<KEYMAP_SIZE;i++)
   {
      line[i]=0;
   }
}
int1 isKeyPressed()
{
   adc_value = read_adc();
   if (adc_value>20000){return 1;}
   else{return 0;}
}

//--- keymap compute and calculate
//    the key pressed given an ADC value
unsigned char keyMap(unsigned int16 val)
{
   int8 i;
   for (i=0;i<KEYMAP_SIZE;i++)
   {
      unsigned int16 sum1= (keys[i]-MAP_INTERVAL);
      unsigned int16 sum2= (keys[i]+MAP_INTERVAL);
      if (sum1<val && sum2>val)
      {
         if (i<10){return (48+i);}
         if (i>=10 &&i <14){return (55+i);}
         if (i==14){return '*';}
         if (i==15){return '#';}
      }
   }
   return 0;
}

//---- when key '1' is held break_counter increment which will be used by
//     other subroute to exit while loops or a given task
void programBreaker()
{
if (adc_value>64000){break_counter=break_counter+1;}
else{ break_counter=0;}
}

//------------- read keypad and return value -----------
unsigned char readKey()
{
   unsigned char val;
   adc_value = read_adc();
   if (adc_value>20000)
   {
      unsigned char val;
      val=keyMap(adc_value);
      if (val!=0){delay_ms(200);return val;}
      else{return 0;}
   }
   else
   {
      return 0;
   }
}

//------------- editor (sub menu) ----------------------

//-- display update
void updateDisplay()
{
   clearDisplay();
   lcd_gotoxy(1,2);
   printf(lcd_putc,"%s",line2);
   lcd_gotoxy(1,1);
   printf(lcd_putc,"%s",line1);
}

//-- internal processing
void editor()
{
   lcd_setcursor_vb(1,1);
   delay_ms(2);
   while(TRUE)
   {
     
      adc_value = read_adc();
      programBreaker();
      key=keyMap(adc_value);
      if(update_request==1)
      {
         updateDisplay();
         update_request=0;
      }
      if (key!=0)
      {
         while(isKeyPressed()){;}
         switch(key)
         {
         case '*':
            if(line1[cursor]!=0){line1[cursor]=0;}
            else
            {
               cursor=cursor-1;
               if (cursor<0){cursor=0;}
               line1[cursor]=0;
            }
            updateDisplay();
            break;
         case '#':   
            printf("%s",line1);

            break;
         default:
            line1[cursor]=key;
            cursor=cursor+1;
            if (cursor>(KEYMAP_SIZE-1)){cursor=(KEYMAP_SIZE-1);}
            updateDisplay();
         }
      }
      if(break_counter>BREAKER_TIMEOUT){break_counter=0;break;}
   }
}

//------------- this function displays ADC key values --
void updateADC()
{
   while(TRUE)
   {
      adc_value = read_adc();
      programBreaker();
      lcd_putc("\fADC = ");
      printf(lcd_putc,"%5Lu\n",adc_value);
      printf(lcd_putc,"Breaker = %5Lu",break_counter);
      delay_ms(100);
      if(break_counter>BREAKER_TIMEOUT){break_counter=0;break;}
   }
}
//---------------- main menu ----------------

//-- display update
void updateMenu()
{
      int size=sizeof(menus[active_menu]);
     
      int x_step = 7-(size/2);
     
      lcd_putc("\fMAIN MENU");
     
      lcd_gotoxy(x_step,2);
      printf(lcd_putc,"%s",menus[active_menu]);
      delay_ms(150);
      if (active_menu!=0){lcd_gotoxy(1,2);lcd_putc('<');}
      if (active_menu!=(MENU_ITEMS-1)){lcd_gotoxy(16,2);lcd_putc('>');}
}
//-- internal processing
signed int mainMenu()
{

   unsigned char val=0;
   updateMenu();
   while(TRUE)
   {
      val=readKey();
      if (val!=0)
      {
         if (val == '#'){ active_menu=active_menu+1;if (active_menu>=MENU_ITEMS){active_menu=MENU_ITEMS-1;} }
         if (val == '*'){ active_menu=active_menu-1;if (active_menu<0)          {active_menu=0;}            }
         if (val == '0'){ clearDisplay();return active_menu;}
         updateMenu();
      }
   }
}

//--------- display a welcome message -----------------
void welcome()
{
   clearDisplay();
   delay_ms(500);
   lcd_putc("\fCHAPRE SOFT\n");
   lcd_putc("            2012");
   delay_ms(2200);
   clearDisplay();
   delay_ms(100);
}

//--------- interupts --------------------

#int_timer1
void timerUpdate()
{
   if (data_in==1)
   {
      data_in_couter=data_in_couter+1;
      if(data_in_couter>=3)
      {
         data_in=0;
         data_in_couter=0;
         output_low(PIN_A3);
      }
   }
   if (data_out==1)
   {
      data_out_couter=data_out_couter+1;
      if (data_out_couter>=3)
      {
         data_out=0;
         data_out_couter=0;
         output_low(PIN_A2);
      }
   }
}

#INT_TBE
void serial_out_interrupt ( )
{
   data_out=1;
   output_high(PIN_A2);
}
#int_rda
void serial_in_interrupt ( )
{
   //disable_interrupts(int_rda);
   serial_val=getc ();
   line2[cursor2]=serial_val;
   cursor2=cursor2+1;
   if( cursor2>=(KEYMAP_SIZE) ){cursor2=0;}
   update_request=1;
   //int1 data_out=0;
   data_in=1;
   output_high(PIN_A3);
}

//--------- initialisations ---------------

void initADC()
{
   setup_adc_ports(sAN0|VSS_VDD);
   setup_adc( ADC_CLOCK_INTERNAL );
   set_adc_channel( 0 );
   delay_us(10);
}

void initialize()
{
   delay_ms(1);
   setup_oscillator(OSC_4MHZ);

   delay_ms(1);

  setup_comparator (NC_NC_NC_NC);
  delay_ms(1);
  SET_TRIS_A(0b11110011);
  SET_TRIS_B(0b11111111);
  delay_ms(1);
  initADC();
  delay_ms(1);
  setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );
   delay_ms(1);
   
   enable_interrupts(int_rda);
   enable_interrupts(int_timer1);
   enable_interrupts(INT_TBE);
   enable_interrupts(global);
}

//--------- main fuction ---------------
void main()
{
   lcd_init(); 
   delay_ms(10);
   initialize();
   delay_ms(1);
   delay_ms(1);
   line2[0]='4';
   delay_ms(10);
   welcome();
}
bkamen



Joined: 07 Jan 2004
Posts: 1615
Location: Central Illinois, USA

View user's profile Send private message

PostPosted: Wed Aug 15, 2012 10:39 am     Reply with quote

what do you mean by "crashes"?

freaks out doing unexpected things? Locks up? resets?
_________________
Dazed and confused? I don't think so. Just "plain lost" will do. :D
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Aug 15, 2012 11:53 am     Reply with quote

comments:

SET_TRIS_A(0b11110011);
SET_TRIS_B(0b11111111);

You might want to declare #use fastio_a (b)
as I'm not sure how the compiler reacts to the above if you
"mix and don't match".


Where is your #use RS232 directive ??
baud setting ?

and what PIC ??

your lcd.h is ???

there is still much missing info here that could relate to your problem
( whatever the actual "problem" may be )

Very Happy Very Happy Very Happy Very Happy
Chapre



Joined: 26 Feb 2012
Posts: 9
Location: Pretoria

View user's profile Send private message

PostPosted: Wed Aug 15, 2012 1:28 pm     Reply with quote

Thanks for the reply, here's my LCD.h, the device I'm using is PIC16f88.
Code:

#include <16F88.h>
#device adc=16

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC                    //Internal RC Osc
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES NOIESO                   //Internal External Switch Over mode disabled

#use delay(internal=4Mhz)

#use rs232(baud=19200,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8,errors)
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Aug 15, 2012 4:05 pm     Reply with quote

now we are starting to get somewhere

the specific:

Quote:

My PIC crashes;


can you explain how you know this?

also the ONLY place where i see that you activate the
int_TBE is this single instance:

printf("%s",line1);

SO......
if you disable and forget about the int_TBE and just manually add

printf("%s",line1);
data_out=1;
output_high(PIN_A2);


you get the same same effect as with the interrupt handler
BUT no int_tbe required
Chapre



Joined: 26 Feb 2012
Posts: 9
Location: Pretoria

View user's profile Send private message

PostPosted: Wed Aug 15, 2012 6:12 pm     Reply with quote

Quote:
My PIC crashes;

I mean my PIC goes crazy, I have an 16x2 LCD connected, I drive it using flex_LCD;

when Int_TBE not enabled, everything is ok, I see all my initialization messages on the LCD and the program runs correctly.

but if I enable Int_TBE (enable_interrupts(INT_TBE); I get nothing on the display, nothing is working anymore, it's like the pic freezes to an unknown state with random voltage value on the I/O pins.

I tried using a 5 seconds delay before enabling Int_TBE with the code
Code:
delay_ms(5000);
enable_interrupts(INT_TBE);

my program will start normally and then will exactly crash after 5 sec when it's executing the commend "enable_interrupts(INT_TBE)"


Yes I can do without int_TBE by doing it manually as you pointed out; but I'm designing a communication protocol and I'm required to explicitly demonstrate the use of RS232 transmit buffer empty interrupt.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Aug 15, 2012 7:16 pm     Reply with quote

1- what does this produce in your .LST file for asm code ???

#INT_TBE
void serial_out_interrupt ( )
{
data_out=1;
output_high(PIN_A2);
}

2-

Quote:

required to explicitly demonstrate ....


you are one unlucky fellow - i have done a fairly large number of
programs for hire - and never once had to demonstrate any more than that the finished work - performed the tasks required of it.
- the HOW was always up to me ......

all too often i have run in to a problem with one or another aspects of the compiler - and had to work around it. what i proposed to you is a perfectly valid work around - that , so long as you have hidden nothing odd, will work.

you should understand however that the way you coded it - IF it were to work right - that the "#int_tbe" would be taken after the VERY first char sent by your lonely printf () -
and i was surprised that you would want it to work that way.

NORMALLY the int_TBE is used with a background rs-232 transmission scheme - not the way you are trying to purpose it.
i have never used it any other way myself.

BTW: EX_STISR.C in the ccs examples shows how it would ordinarily be used.

you can also try this:
Code:

   clear_interrupt(int_tbe);
   clear_interrupt(INT_RDA);

   enable_interrupts(int_rda);
   enable_interrupts(int_timer1);
   enable_interrupts(INT_TBE);
   enable_interrupts(global);

to see if it brings any joy
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Wed Aug 15, 2012 7:38 pm     Reply with quote

TBE stands for Transmit Buffer Empty. Its purpose is to allow the processor to give the UART a character to transmit so that the processor can then "run off and do something else". When the UART has finished transmitting that character - guess what - the transmit buffer is then indeed empty and this interrupt can then be used to "tap the processor on the shoulder" so that the processor can give the UART another character to transmit.

May I ask you a question? What will happen to the processor if you ENABLE the TBE interrupt but you haven't done the UART the courtesy of giving it some characters to transmit?

When you are able to answer this question, you will understand why your program is doing what it is doing.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Thu Aug 16, 2012 12:53 am     Reply with quote

Also a second part to newguy's comment (which is spot on). The transmit buffer is empty. What needs to be done in the IRQ to stop if being empty?.

This relates to a series of hardware IRQ's:

INT_RDA, _must_ always read a character
INT_RB, _must_ always read port B.
etc. etc..

Look at ex_stisr.c, which shows how to use INT_TBE. Note when the interrupt is enabled, when it is disabled, and what is done in the ISR.

Best Wishes
Chapre



Joined: 26 Feb 2012
Posts: 9
Location: Pretoria

View user's profile Send private message

PostPosted: Fri Aug 17, 2012 4:12 am     Reply with quote

Thanks, I looked at the "ex_stisr.c"; I understand I was using the wrong approach with INT_TBE.
I will be then using the manual way pointed out by asmboy.
Good day!
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