View previous topic :: View next topic |
Author |
Message |
Chapre
Joined: 26 Feb 2012 Posts: 9 Location: Pretoria
|
Problem with INT_RDA and INT_TBE on PIC16F88 |
Posted: Mon Aug 13, 2012 1:21 am |
|
|
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 |
|
|
bkamen
Joined: 07 Jan 2004 Posts: 1615 Location: Central Illinois, USA
|
|
Posted: Mon Aug 13, 2012 1:37 am |
|
|
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
|
|
Posted: Mon Aug 13, 2012 2:06 pm |
|
|
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
|
|
Posted: Wed Aug 15, 2012 5:36 am |
|
|
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
|
|
Posted: Wed Aug 15, 2012 10:39 am |
|
|
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
|
|
Posted: Wed Aug 15, 2012 11:53 am |
|
|
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 )
|
|
|
Chapre
Joined: 26 Feb 2012 Posts: 9 Location: Pretoria
|
|
Posted: Wed Aug 15, 2012 1:28 pm |
|
|
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
|
|
Posted: Wed Aug 15, 2012 4:05 pm |
|
|
now we are starting to get somewhere
the specific:
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
|
|
Posted: Wed Aug 15, 2012 6:12 pm |
|
|
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
|
|
Posted: Wed Aug 15, 2012 7:16 pm |
|
|
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
|
|
Posted: Wed Aug 15, 2012 7:38 pm |
|
|
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: 19537
|
|
Posted: Thu Aug 16, 2012 12:53 am |
|
|
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
|
|
Posted: Fri Aug 17, 2012 4:12 am |
|
|
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! |
|
|
|