|
|
View previous topic :: View next topic |
Author |
Message |
matt_at_hanbay
Joined: 06 Jul 2007 Posts: 15 Location: Montreal Canada
|
Program doesn't function after meaningless changes to code. |
Posted: Fri Jul 06, 2007 2:33 pm |
|
|
I'll try to make this clear and concise. I have a program that runs on a 16f886, compiler/program size/ram use as follows:
CCS PCM C Compiler, Version 4.042, 38188 06-Jul-07 15:42
Filename: MPA.lst
ROM used: 2609 words (32%)
Largest free fragment is 2048
RAM used: 55 (15%) at main() level
98 (27%) worst case
Stack: 7 worst case (3 in main + 4 for interrupts)
It works as expected. In my program I use the EUART to perform SPI, I also have compiler and port B triggered interrupts. If I declare one more variable anywhere in my code, then my program compiles happily, but fails to function properly, as if it's stuck in an infinite loop or continuously reseting. Inside my comparator interrupt service routine I call a function that uses SPI, if i remove this call, the program once again functions as expected.
So, two seemingly completely different scenarios both cause my program to fail. Any ideas of what could be the source of my nightmare?
Thanks in advance for all help.
-Matt |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 06, 2007 2:41 pm |
|
|
Check if your code is writing past the end of an array and thus changing
some other variable that the compiler places in that RAM location.
Also look for any other type of accidental overwriting of variables, such
as with the memcpy() function, or by casting a variable to a larger type
than it really is, and then writing to the casted variable.
The reason why your program fails when you add one variable is that
it may shift the allocation address of a critical variable so that it's now
in a RAM location that's being over-written, as given above.
Also check out the trouble-shooting links in this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=30368&start=1 |
|
|
matt_at_hanbay
Joined: 06 Jul 2007 Posts: 15 Location: Montreal Canada
|
|
Posted: Sat Jul 07, 2007 11:29 am |
|
|
PCM, thanks for the reply. I don't think am currently using any arrays, but I'll look through the code to see if I may be over writing a nother variable. Do you happen to have any ideas regarding the SPI call in the interrupt causing the same problem? Hmmm maybe that is where the problem code is, so by removing it, I remove the source of the problem. I really hope this resolves the problem. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Jul 07, 2007 11:51 am |
|
|
Quote: | as if it's continuously reseting. |
You can prove if it's continuously resetting by putting a printf statement
at the start of the program.
Code: | printf("Start\n\r"); |
If it is, then read all the links that I provided on "random resets".
The most important thing is probably to make sure you have a 100 nF
bypass capacitor (0.1 uF) on all Vdd pins.
Quote: |
as if it's stuck in an infinite loop |
It could be continuously re-entering an interrupt service routine.
Some interrupts such as INT_RB, require special handling to clear
the cause of the interrupt. In the case of INT_RB, you have to read
PortB while inside the isr. If you don't do this, you will get continuous
INT_RB interrupts.
This is also the case for the comparator interrupt. The data sheet tells
you how to clear the interrupt condition. This must be done in the isr:
Quote: | The mismatch condition persists until either the CMxCON0
register is read or the comparator output returns to the
previous state. |
Quote: | I also have compiler and port B triggered interrupts. |
What do you mean by a "compiler" triggered interrupt ? |
|
|
matt_at_hanbay
Joined: 06 Jul 2007 Posts: 15 Location: Montreal Canada
|
|
Posted: Tue Jul 10, 2007 10:30 am |
|
|
PCM, again thank you for your reply. I have just now had an opportunity to spend more time on this problem. From you previous post, using a printf to detect resets... a good idea, unfortunately this project doesn't have any type serial interface, I may add one for development, but all io pins are currently being used.
We have at least 0.1uF caps on all ICs, and I have just verified that I clear the comparator interrupt by reading C1OUT.
" compiler and port B triggered interrupts." should be "comparator and port B triggered interrupts". Sorry for that.
While working on this project, I wrote two methods for SPI, one is done -using bit-banging in software, and the other uses the hardware eusart. I found that by using the manual spi, my problem goes away. This would suggest that my gremlin is somewhere in my eusart code correct? The HW code is a little funny, because the ADC that is being written to, expects msb first, whereas the eusart sends lsb first. Here is the chunk of relevent code, maybe someone can see the error I am missing:
Once again, any insight would be great.
Code: |
/***************************************************************************
* this is a little helper function that reverses the bit-order in a byte
* it is used because the hardware euart sends lsb 1st, but ADC and DAC expect msb
* first.
***************************************************************************/
int reverse_bits(int input)
{
int reversed_input,i=0; //variable to store the reversed version of input
for(i=0;i<8;i++)
{
if(bit_test(input,7-i))
{
bit_set(reversed_input,i);
}
else
{
bit_clear(reversed_input,i);
}
}
return reversed_input;
}
/***************************************************************************
* This function will write a 16-bit long integer to the EUSART when it is setup up in
* synchronous half-duplex mode. This is used to by the WRITE_TO_DAC function
****************************************************************************/
void WRITE_LONG_TO_SPI(long L)
{
#ifdef manual_spi
/* for now, manually pump out bits on the SPI pins*/
int i; //variable for our 'for' loop
//loop through the bits, output high/low depending on if that bit is set
//start with msb
for(i=0;i<16;i++)
{
if((L>>(15-i) & 1) == 1) //check if msb is high, if yes, then set data pin high
{
output_high(SPI_DATA_PIN);
}
else //otherwise, set dat pin low
{
output_low(SPI_DATA_PIN);
}
delay_us(SYNC_PERIOD_US/2); //delay for half a period, so data has a chance to affect SPI input pins on other chip
output_high(SPI_CLK_PIN); //send rising edge of clock signal, data should now be read in by other chip
delay_us(SYNC_PERIOD_US/2); //delay for half a period, to be sure that data has a chance to be input by other chip
output_low(SPI_CLK_PIN); //send falling edge of click sig
}
#else
/*this code will use the synchronous usart to send the data*/
/*first we need to set up the baud rate generator through the SPBRG register*/
/*desired baud rate = Fosc/(4*(SPBRG] +1)), so if we want 50us=20khz 8mhz/(4(n+1)) n~100*/
SPBRG = 20; //set for ~20khz baud = 100
SCKP = 1; //want data to change on the falling edge of the clock
// set for synchronous master mode
SYNC = 1; //sync opporation
SPEN = 1; //enable eusart
CSRC = 1; //set as master
//disable receiving on the synch serial
SREN = 0; //we want to transmit
CREN = 0;
//enable tx mode
TXEN = 1;
//now we actually get to send the data
TXREG = reverse_bits((int)(L>>8)); //send the high byte first, but reverse the bits so we send msb first(as required by DAC)
/*wait for the TXIF bit to go high, showing that the TXREG is empty, so we can load in next byte to send*/
while(TXIF) //first wait for TXIF to go low, showing that TXREG has been loaded
{}
//then wait for it to be high, showing that TXREG has been emptied
while(!TXIF)
{
}
//now we load next byte into TXREG
TXREG = reverse_bits((int)L); //put low byte of L into the buffer, with it's bits reversed
//finally we need to busy-wait for the data to be sent, so that we don't clear the chip-enable line too early
while(!TRMT)
{
}
#endif
}
|
-Matt |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jul 10, 2007 11:25 am |
|
|
Quote: | while(TXIF) {}
//then wait for it to be high, showing that TXREG has been emptied
while(!TXIF) {
}
//now we load next byte into TXREG
TXREG = reverse_bits((int)L); //put low byte of L into the buffer, with it's bits reversed
//finally we need to busy-wait for the data to be sent, so that we don't clear the chip-enable line too early
while(!TRMT) |
You have three loops that have no timeouts. If your code is locking up
in the hardware USART section, the first thing I would look at is those
three loops.
Try adding a software timeout to each one. If the code stops locking up,
then you know that it's in those loops. Then you can start to narrow it
down. |
|
|
matt_at_hanbay
Joined: 06 Jul 2007 Posts: 15 Location: Montreal Canada
|
|
Posted: Tue Jul 10, 2007 12:27 pm |
|
|
Thanks, I'll try that. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Jul 10, 2007 3:28 pm |
|
|
Your software SPI driver has the clock signal low when not active while the hardware solution with the UART has the clock signal high when inactive, i.e. the software driver is working in SPI-mode 1 and the hardware variant in SPI-mode 3. If this poses a problem for the device connected to your SPI bus should be determined from the data sheet.
Quote: | Stack: 7 worst case (3 in main + 4 for interrupts) | 4 stack levels for your interrupt is a lot. This suggests your interrupt code is large and complex. Always keep the interrupts as short as possible.
Your function for reversing the bits is ok, but not the most optimal implementation. Just for fun you could have a look at http://www.ccsinfo.com/forum/viewtopic.php?t=23364. Here several methods are compared (it can be done 15 times faster with less RAM and ROM). |
|
|
matt_at_hanbay
Joined: 06 Jul 2007 Posts: 15 Location: Montreal Canada
|
|
Posted: Thu Jul 12, 2007 12:07 pm |
|
|
PCM, it looks like you were correct. Adding a software timeout resolved the issue.
ckielstra, you are correct regarding the depth of my interrupts. My comparator interrupt is the main culprit. This routine runs when the supply voltage to the instrument goes below a certain threshold. It's job is to save the current configuration to eeprom before all power is lost. Nothing else matters after this interrupt has been executed, so i am not so worried about the length/complexity of this routine. You have a good point though. I will be sure to add code to disable all interrupts at the beginning of the comparator isr.
Thanks also for the link to the bit-reversal code. I wanted something that was clear and simple for developing... but I will be sure to replace it with a better one as long as I don't have to put in the effort to create it.
Once again, thanks for all the help. Progress is good now, but I'll be sure to post if something else comes up, you guys have been very helpful.
-Matt |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jul 12, 2007 4:58 pm |
|
|
Quote: | I will be sure to add code to disable all interrupts at the beginning of the comparator isr. | You don't have to disable the interrupts, the PIC hardware already does this for you on entering the interrupt handler. The interrupts stay disabled until you exit the isr with the RETFIE instruction. |
|
|
matt_at_hanbay
Joined: 06 Jul 2007 Posts: 15 Location: Montreal Canada
|
|
Posted: Fri Jul 13, 2007 7:52 am |
|
|
Quote: | You don't have to disable the interrupts, the PIC hardware already does this for you on entering the interrupt handler. The interrupts stay disabled until you exit the isr with the RETFIE instruction. |
Right, I think I know that. Thanks for the reminder.
I also swapped in more efficient bit-reversal algorithm, specifically the one that uses direct bit access to set/clear the bits of the int. It is nice to know that the code will be smaller/faster now. |
|
|
|
|
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
|