|
|
View previous topic :: View next topic |
Author |
Message |
bignick270
Joined: 11 Sep 2008 Posts: 44
|
complex int rda help |
Posted: Sat Nov 08, 2008 3:30 pm |
|
|
Hey guys,
I have a board with two pics running on it and I need to run communication between them.
I am having trouble thinking through my int_rda function.
The main pic (16f877a) sends out two different sets of data. The first set of data consist of a fixed 4 bytes with the first byte being 0xCC which I planned on using as a header byte.
The second packet is sent out in burst of 6 bytes. The total amount of bytes depends on how much data has came into the pic. Pretty much I ran out of memory on the main pic so as data comes in off a antenna it is packed and sent to the other pic. The first byte in the 6 byte packet is a 0xFF which I had planned for a header byte. The total amount of data does not transmit at once because it is being transmitted as it is received. There is about a 540 us delay between the data transmissions.
I have uploaded a picture to savefile.com (can be downloaded through the link below, no spam) which shows the image from the logic analyzer of the communication going from the pic16f877a to the pic16f886 in order to get a better idea of what I am trying to say.
http://www.savefile.com/files/1877224.
The baud rate of communication is 38400.
Any idea would be nice.
I have not got too far with the code on the second chip yet, I ran into a lot of timing issues receiving the multiple packets.
I know I need to keep int rda short and thats why I need help with planning it out. |
|
|
Ttelmah Guest
|
|
Posted: Sat Nov 08, 2008 4:10 pm |
|
|
This would be a classic target for a state machine.
Key thing you need to learn, is that sometimes things that look 'long' in human terms, can be very short in computer terms, while other things that look 'short' to us, can be surprisingly long.
Now (for instance), array accesses are quite slow. Similarly, maths is slow. However simple 'if' tests, or switch statements, are really quick.
Code: |
//Totally imaginary....
int8 buffer[200]
int8 buffer_in=0,buffer_out=0;
int8 small_buff[3];
int1 small_msg_received=false;
int1 long_msg_received=false;
#int_rda
void serial_rx(void) {
int8 received;
static int8 state=0;
received=getc();
switch(state) {
case 0:
//Here identify a header byte
//access the local 'received' variable, rather than using an array
if (received==0xCC) {
state=1;
break; //get out ASAP
}
if (received==0xFF) {
state=4;
}
break;
case 1:
small_buff[0]=received; //accessing an array with a _fixed_ index
//avoids the big overhead
state++;
case 2
small_buff[1]=received;
state++;
break;
case 3:
small_buff[2]=received; //last byte
state=0;
small_message_received=true;
break;
case 4:
//Now the start of receiving a 'long' message
}
}
|
Now, it is not clear from your description, how you know when a 'long' message is complete. Hence I have stopped at the first byte of receiving this.
Now, this looks huge, _but_ the key is that in computer terms, it is fast. the code simply loads the byte to a temporary variable, then does a jump (using a lookup table), to the required handler. This saves the byte where required, sets a flag if needed, updates the jump address, and exits. The whole thing, on any path shown, only takes about a dozen instructions!...
You must _not_ have a 'default' entry on the jump table. If you do, the code for the jump becomes much less efficient. Also, if you access an array entry with a variable, the code for this, will immediately add another dozen or so instructions to this 'route'. So, by 'knowing' what instructions are slow, an efficient way of handling the data can be generated.
Best Wishes |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Sat Nov 08, 2008 7:06 pm |
|
|
I don't necessarily have a ending frame byte...I could add those in as well.
Thanks for the response. |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Tue Nov 11, 2008 2:47 pm |
|
|
I went by Ttelmah suggestion and no luck.
Here is the code I came up with from his suggestion... Please excuse the code, it is very messy right now. I have spent a lot of time trying to get this code working. I have successfully set up the Int_rda on the other processor on the board, this one is giving me big problems for some reason. I also have tried basic int_rda function but it never goes into the branch in the main function.
Code: |
#int_rda
void RDA_isr(void)
{
switch(state)
{
case 0:
//Here identify a header byte
//access the local 'received' variable, rather than using an array
if (received==0xCC)
{
state=1;
//break; //get out ASAP
}
else if (received==0xFF)
{
state=4;
// break;
// i = 0;
}
break;
//get the status updates
case 1:
status0=received; //accessing an array with a _fixed_ index
if(received != 0xCC)
{
//avoids the big overhead
state = 2;
//putc(status[0]);
}
else
state = 0;
break; //??
case 2:
status1=received;
if(received != 0xCC)
{
state = 3;
// putc(status[1]);
}
else
state = 0;
break;
case 3:
status2=received; //last byte
if(received != 0xCC)
{
state=0;
statdat=1;
//putc(status[2]);
}
else
state = 0;
break;
///we doen with the the status update
case 4:
//Now the start of receiving a 'long' message
msg[0] = received;
if(received != 0xFF)
{
state= 5;
//i++;
}
break;
case 5:
msg[1] = received;
if(received != 0xFF)
{
state = 6;
//i++;
}
break;
case 6:
msg[2] = received;
if(received != 0xFF)
{
state = 7;
//i++;
}
break;
case 7:
msg[3] = received;
if(received != 0xFF)
{
state = 8;
//i++;
}
break;
case 8:
msg[4] = received;
if(received != 0xFF)
{
tagdat = 1;
state = 0;
}
break;
}
}
|
I can go in and echo the received data back out the tx pin and it looks like it came in fine when looking at it on the logic analyzer but it will not go into the loop in my main.
Here is my main. There are a few functions as well but I will not paste them since there is no reason.
Code: |
void main()
{
static int j;
static int8 zone;
OUTPUT_LOW(RESET); //keeps MCLR active on 877a unless turned low
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_32);
setup_spi(SPI_SS_DISABLED);
setup_comparator(NC_NC_NC_NC);
enable_interrupts(GLOBAL);
i = 0;
b = 0;
bu = 0;
total3 = 0;
total4 = 0;
zone = 0;
state = 0;
statdat = 0;
tagdat = 0;
startup(); //this function drives lights on and off..start up sequence
enable_interrupts(INT_RDA); //turn int rda on after lights becuase it will mess up the light sequence.
while(1)
{
if(statdat == 1)
{
statdat = 0;
zeroch();
databreak(); //breaks the 3 rx bytes down into workable values
if(ch1 == 1)
{
ch1_clear();
delay_us(25);
OUTPUT_HIGH(ch1G);
}
else if(ch1 == 0)
{
ch1_clear();
delay_us(25);
}
else
{
ch1_clear();
delay_us(25);
OUTPUT_HIGH(ch1R);
}
if(ch2 == 1)
{
//ch1_clear();
ch2_clear();
delay_us(25);
OUTPUT_HIGH(ch2G);
}
else if(ch2 == 0)
{
ch2_clear();
delay_us(25);
}
else
{
ch2_clear();
delay_us(25);
OUTPUT_HIGH(ch2R);
}
if(ch3 == 1)
{
ch3_clear();
//ch2_clear();
delay_us(25);
OUTPUT_HIGH(ch3G);
}
else if(ch3 == 0)
{
ch3_clear();
delay_us(25);
}
else
{
ch3_clear();
delay_us(25);
OUTPUT_HIGH(ch3R);
}
if(ch4 == 1)
{
ch4_clear();
//ch3_clear();
delay_us(25);
OUTPUT_HIGH(ch4G);
}
else if(ch4 == 0)
{
ch4_clear();
delay_us(25);
}
else
{
ch4_clear();
delay_us(25);
OUTPUT_HIGH(ch4R);
}
if((line_led == 1) && batt_led == 0)
{
if(system_pwr == 1) //light go green
{
line_clear();
OUTPUT_HIGH(lineG);
}
else if(system_pwr == 2) //light go orange
{
line_clear();
OUTPUT_HIGH(lineG);
OUTPUT_HIGH(lineR);
}
else //light go red
{
line_clear();
OUTPUT_HIGH(lineR);
}
}
else
{
if(system_pwr == 1) //light go green
{
line_clear();
OUTPUT_HIGH(battG);
}
else if(system_pwr == 2) //light go orange
{
line_clear();
OUTPUT_HIGH(battG);
OUTPUT_HIGH(battR);
}
else //light go red
{
line_clear();
OUTPUT_HIGH(battR);
}
}
if(comm_led == 1)
{
comm_clear();
OUTPUT_HIGH(commG);
}
else
{
comm_clear();
OUTPUT_HIGH(commR);
}
if(line_led == 1)
{
batt_clear();
OUTPUT_HIGH(battR);
}
else
{
batt_clear();
OUTPUT_HIGH(battG);
}
}
else if(tagdat == 1)
{
putc(0xDD); //lets me know if we went into this branch
tagdat = 0;
//we need to check zone number first off to know where to place the data
zone = msg[2] & 0x60;
zone >>= 5;
if(zone == 2)
{
checkch3(); //we have info on buffer for channel 3 so we store
//sending out some information to see if anything stored
putc(channel3[0]);
putc(channel3[1]);
putc(channel3[5]);
putc(channel3[6]);
putc(channel3[10]);
putc(channel3[11]);
}
}
else
{
OUTPUT_HIGH(ch1R);
OUTPUT_HIGH(ch2R);
OUTPUT_HIGH(ch3R);
OUTPUT_HIGH(ch4R);
}
}
}
| [/code] |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Tue Nov 11, 2008 2:55 pm |
|
|
Also I have updated the link above with a new picture of sample data coming in.
Hopefully the link will remain working for a few days. It is a direct link to the file on savefile.com so I do not know how long it will work.
If it fails then the indirect link to download is http://www.savefile.com/files/1881927 |
|
|
Guest
|
|
Posted: Tue Nov 11, 2008 3:11 pm |
|
|
Do you mean that the while(1) loop doesn't start? You could use an LED
to see where the program hangs, or trace its path through the code. It
can take some time, especially when you have a decent amount of code,
but it will point you right to the problem.
Place an output_high(PIN_B0), or whatever pin is connected to an LED,
before a point that you believe might be the problem. Really, you can
place it anywhere for the first attempt. Make sure no other statements
change the LED. Then run the program. If the LED turns on, you know
the code has made it that far. Cut and paste the output to some point
further along in the code. If the LED doesn't turn on, the code doesn't
get that far, so cut and paste the statement to an earlier point in the
code. Repeat until you find your error.
Also, I would recommend starting out with a very small minimal while(1)
loop. Something simple that only verifies that the state machine
functions properly. The less code there is, the easier it will be to debug.
It also makes it more likely that other people will help you, as no one
wants to read 5 pages of code to find one bug. |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Tue Nov 11, 2008 3:28 pm |
|
|
Alright so I commented out all the code under the if(statdat == 1) and
under the else if(tagdat == 1) and added code to turn a led on for one
the first if statement and then added another led light for the second
statement. None of them came on.
Then I added another led to turn on right before the while statement and
when I programmed the chip there was no light.
So maybe I am thinking it is crashing in the int_rda? |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Tue Nov 11, 2008 3:34 pm |
|
|
Update:
The last led control i added was after I enabled int_rda which nothing
worked. Just now I moved to right before the int_rda is enabled and the
led came on.
Oh and by the way I have the errors tag in my #use rs232 command so
it should not be locking up right?
I do not know if I previously put the chip number on here but it is the PIC16F886. |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Tue Nov 11, 2008 4:10 pm |
|
|
Okay so when I was eliminating comments from the code I deleted the
receive = getc(); from the int_rda which is what caused the lock up but it
was there earlier when the full code wasn't working so it was just
something I overlooked but it is not the main problem. |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Tue Nov 11, 2008 4:34 pm |
|
|
Ok so I am getting the leds to come on from the for loops in the code but
I check and there are other leds being turned on too when it's not told to
do so in the code ????
When I try to use putc to put tx the data once inside the for loop to see it
on the logic analyzer I am getting a long break... Something must be
causing a crash correct especially to have the other lights turn on and off
without any code controlling them. |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 12, 2008 6:17 am |
|
|
Some little comments.
First, I'd empty the hardware receive buffer, after enabling the other chip, and before enabling the interrupt. Though the code shouldn't 'mind' getting garbage data, if the other chip has been held disabled, the serial RX line will have been floating, and probably low at some points. Data will then have been received.
Second, though you have used my suggestion of avoing the array acesses, it doesn't look from your code, as if this is really needed.The 'point' about this, is to reduce time in the interrupt, when timing really is critical. A 38400bps, each character will take at least 260uSec to send. This is not _that_ fast. You have not said what clock rate the processor is running, but even at 4MHz, 260 instructions ar available in this time.
Third comment. _copy_ your received data ASAP, then clear the status bit. Though the timing is not that 'tight', once data has been seen, what happens if another header arrives before the main has finished processing the received data?. Outputting all the data could take aver 1.8mSec. Time for another seven characters to have arrived. Similarly, there are delays, and unknown times (how long does zeroch take for example), in the other main code paths.
Best Wishes |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Wed Nov 12, 2008 7:26 am |
|
|
I thought I had the processor clock speed in a previous reply but I am sorry for that, I am running at 8Mhz. zeroch is a basic function that sets four outputs to low...should not be too many clock cycles involved in that one. |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Wed Nov 12, 2008 8:09 am |
|
|
I maybe thinking about this in a more complicated way but to clear the hardware UART buffer do I use a pointer to that memory address and set it to 0. For the PIC16F886 the address for the RXREG is 0x1A.
int8 *RXREG = 0x1A;
then to clear i use
*RXREG = 0x00;
Would that work? |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 12, 2008 9:37 am |
|
|
#byte RXREG=0x1A
To clear it, you need to read it.
Read it twice, and the hardware buffer will be empty. So, something like:
dummy=RXREG;
dummy=RXREG;
If you want to be 'flashy', you can also program a bit, to correspond to the receive buffer full bit, and then do:
while (RXFULL) dummy=RXREG;
Once this is done, clear the interrupt (it will have been set if any data was there), and then enable the interrupt.
Best Wishes |
|
|
bignick270
Joined: 11 Sep 2008 Posts: 44
|
|
Posted: Wed Nov 12, 2008 3:49 pm |
|
|
I have reduced my code as small as possible and I can not shake the problem. I have tried to clear the receive register but my interrupt routine will not run if i do.
From the logic analyzer it looks like the set of 4 bytes of data comes in fine until it hits the packet with 6 bytes which is part of the long sequence then it craps out so to speak.
That is the point where random led lights will come on and off and sometimes the processor will completely reset. I will attach the complete source code here for you guys to look through...i have spent two too many days on this.
Code: |
#include <16F886.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES PUT //Power Up Timer
#FUSES MCLR //Master Clear pin used for I/O
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOCPD //No EE protection
#FUSES BROWNOUT //No brownout reset
#FUSES NOLVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOWRT //Program memory not write protected
#FUSES BORV21 //Brownout at 2.1V
#FUSES NOIESO //Internal External switch over mode disabled
#FUSES NOFCMEN //Disable Fail-safe clock monitor
#use delay(clock=8000000)
#use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7, bits=8, errors)
//B4 -> LED2 'LINE'
//B5 -> LED2 'LINE'
// B2 -> LED3 'BATT'
// B3 -> LED3 'BATT'
// B0 -> LED4 'COMM'
// B1 -> LED4 'COMM'
// A3 -> LED5 'CH1'
// A5 -> LED5 'CH1'
//C4 -> LED6 'CH2'
//C5 -> LED6 'CH2'
// C0 -> LED7 'CH3'
// C1 -> LED7 'CH3'
// A6 -> LED8 'CH4'
// A7 -> LED8 'CH4'
#define ch1R PIN_A5
#define ch1G PIN_A3
#define ch2R PIN_C5
#define ch2G PIN_C4
#define ch3R PIN_C1
#define ch3G PIN_C0
#define ch4R PIN_A7
#define ch4G PIN_A6
#define commR PIN_B1
#define commG PIN_B0
#define battR PIN_B3
#define battG PIN_B2
#define lineR PIN_B5
#define lineG PIN_B4
#define reset PIN_C3
#define getit 225
#byte RXREG = 0x1A
//go for globals
static int8 msg[85] = {0};
#locate msg = 0x20
int8 status[3] = {0};
//manually locate data locations for 2 channel memory
static int8 channel3[95] = {0};
#locate channel3 = 0x110 //bank three
static int8 channel4[95] = {0};
#locate channel4 = 0x190 //bank four
static int1 statdat;
static int1 tagdat;
static int8 state;
static int8 received;
//try to implement the int rda from the message board - -state machine it
#int_rda
void RDA_isr(void)
{
received = getc();
switch(state)
{
case 0:
if(received == 0xCC)
{
state = 1;
output_high(ch1G);
//output_low(ch1G);
}
else if(received == 0xFF)
{
state = 4;
output_high(ch2G);
}
else
{
state = 0;
}
break;
case 1:
status[0] = received;
state = 2;
//output_high(ch2G);
break;
case 2:
status[1] = received;
state = 3;
// output_high(ch3G);
break;
case 3:
status[2] = received;
state = 0;
statdat = 1;
// output_high(ch4G);
break;
case 4:
msg[0] = received;
state = 5;
//output_high(ch2G);
output_high(ch3G);
break;
case 5:
msg[1] = received;
state = 6;
//output_high(ch3G);
break;
case 6:
msg[2] = received;
state = 7;
//output_high(ch4G);
break;
case 7:
msg[3] = received;
state = 8;
//output_high(ch1R);
break;
case 8:
msg[4] = received;
state = 0;
tagdat = 1;
output_high(ch4G);
break;
}
}
void startup()
{
OUTPUT_HIGH(lineG);
delay_ms(getit);
OUTPUT_LOW(lineG);
OUTPUT_HIGH(battG);
delay_ms(getit);
OUTPUT_LOW(battG);
OUTPUT_HIGH(commG);
delay_ms(getit);
OUTPUT_LOW(commG);
//this is the horizontal status lights
OUTPUT_HIGH(ch1G);
delay_ms(getit);
OUTPUT_LOW(ch1G);
OUTPUT_HIGH(ch2G);
delay_ms(getit);
OUTPUT_LOW(ch2G);
OUTPUT_HIGH(ch3G);
delay_ms(getit);
OUTPUT_LOW(ch3G);
OUTPUT_HIGH(ch4G);
delay_ms(getit);
OUTPUT_LOW(ch4G);
//go red same way
//this is vertical status lights
OUTPUT_HIGH(lineR);
delay_ms(getit);
OUTPUT_LOW(lineR);
OUTPUT_HIGH(battR);
delay_ms(getit);
OUTPUT_LOW(battR);
OUTPUT_HIGH(commR);
delay_ms(getit);
OUTPUT_LOW(commR);
//this is the horizontal status lights
OUTPUT_HIGH(ch1R);
delay_ms(getit);
OUTPUT_LOW(ch1R);
OUTPUT_HIGH(ch2R);
delay_ms(getit);
OUTPUT_LOW(ch2R);
OUTPUT_HIGH(ch3R);
delay_ms(getit);
OUTPUT_LOW(ch3R);
OUTPUT_HIGH(ch4R);
delay_ms(getit);
OUTPUT_LOW(ch4R);
//go orange...both pins active
//this is vertical status lights
OUTPUT_HIGH(lineG);
OUTPUT_HIGH(lineR);
delay_ms(getit);
OUTPUT_LOW(lineG);
OUTPUT_LOW(lineR);
OUTPUT_HIGH(battG);
OUTPUT_HIGH(battR);
delay_ms(getit);
OUTPUT_LOW(battG);
OUTPUT_LOW(battR);;
OUTPUT_HIGH(commG);
OUTPUT_HIGH(commR);
delay_ms(getit);
OUTPUT_LOW(commG);
OUTPUT_LOW(commR);
//this is the horizontal status lights
OUTPUT_HIGH(ch1G);
OUTPUT_HIGH(ch1R);
delay_ms(getit);
OUTPUT_LOW(ch1G);
OUTPUT_LOW(ch1R);
delay_ms(getit);
OUTPUT_HIGH(ch2G);
OUTPUT_HIGH(ch2R);
delay_ms(getit);
OUTPUT_LOW(ch2G);
OUTPUT_LOW(ch2R);
OUTPUT_HIGH(ch3G);
OUTPUT_HIGH(ch3R);
delay_ms(getit);
OUTPUT_LOW(ch3G);
OUTPUT_LOW(ch3R);
OUTPUT_HIGH(ch4G);
OUTPUT_HIGH(ch4R);
delay_ms(getit);
OUTPUT_LOW(ch4G);
OUTPUT_LOW(ch4R);
putc(0xaa);
}
void main()
{
static int8 dummy;
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_32);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
enable_interrupts(GLOBAL);
OUTPUT_LOW(RESET); //keeps MCLR active on 877a unless turned low
state = 0;
statdat = 0;
tagdat = 0;
startup();
enable_interrupts(INT_RDA);
while(1)
{
if(statdat == 1)
{
statdat = 0;
putc(status[0]);
putc(Status[1]);
putc(status[2]);
}
else if(tagdat == 1)
{
// output_high(ch3R);
putc(msg[0]);
tagdat = 0;
}
else
{
//this is just a temporary branch to run until data comes in then i test again.
if(dummy<250)
{
dummy = dummy + 1;
}
else
{
dummy = 0;
}
//putc(state);
}
}
}
|
Timing:
According to my logic analyzer printout.
The time between bytes is about 160us.
The time between a status packet (the one that starts with 0xCC) and the beginning of the data packet (starts with 0xFF) is about 1.3 ms. |
|
|
|
|
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
|