|
|
View previous topic :: View next topic |
Author |
Message |
hello188
Joined: 02 Jun 2010 Posts: 74
|
Ways to view variable allocation to memory? |
Posted: Fri Oct 19, 2012 10:37 pm |
|
|
Hi, I am using PIC18F47J53 TX1 module. with following buffered TX routine.
Code: |
#define T1_BUFFER_SIZE 64
uint8_t t1_buffer[T1_BUFFER_SIZE];
uint8_t t1_next_in = 0;
uint8_t t1_next_out = 0;
|
Code: | void bputc1(char c) {
short restart;
int ni;
restart=t1_next_in==t1_next_out;
t1_buffer[t1_next_in]=c;
ni=(t1_next_in+1) % T1_BUFFER_SIZE;
while(ni==t1_next_out);
t1_next_in=ni;
if(restart){
RED_DEBUG_PORT = !RED_DEBUG_PORT;
//Enable TX
_DE1_PORT = 1;//ENABLE DRIVER
//Disable RX
disable_interrupts(INT_RDA);
disable_interrupts(INT_TIMER4);
disable_interrupts(INT_TIMER5);
RCSTA1_CREN = 0;
delay_us(10);//Adjust accordingly
enable_interrupts(int_tbe);
}
}
|
Code: |
void send_bytes1(uint8_t array[], uint8_t length){
uint8_t i;
for(i=0; i<length; i++) bputc1(array[i]);
}
|
Code: | #INT_TBE
void serial_isr() {
bus_idle_timer = 0;
if(t1_next_in!=t1_next_out){
TXREG1 = t1_buffer[t1_next_out];
t1_next_out=(t1_next_out+1) % T1_BUFFER_SIZE;
}else{
//Finished sending Command. Start the Slave Response timer
//TX_complete = 1;
disable_interrupts(INT_TBE);
set_timer5(-48000);//1ms
clear_interrupt(INT_TIMER5);
enable_interrupts(INT_TIMER5);
RX1_buffer_idx = 0;
while(!TXSTA1_TRMT);//Wait until transmission has finished
_DE1_PORT = 0;
RCSTA1_CREN = 1;
clear_interrupt(INT_RDA);
enable_interrupts(INT_RDA);
}
} |
After certain point, or from the start of the program, the send_byte() routine wouldn't trigger INT_TBE, failing to send out bytes. The problem was that, t1_next_out became 97(over the 63 which is the maximum buffer index). No where else in the code touches this variable other than the part of the code above.
The cause of it, I think is from 2)
1) I am using hot insertion of the module(hardware with programmed PIC), onto 24V powered backplane. I suspect program memory or ram corruption while insertion? I programmed same program onto another identical hardware and the t1_next_out doesn't get corrupted. but for this particular board, it does get corrupted(I managed to design the code so that I can observe it using USB). I am not exactly sure if it is software problem or hardware problem from hot inserting. Can hot insertion corrupt program/data memory or program counter? I am using voltage superviser from microchip that has power up delay of reset line. So, I don't think the error might be from the powering up glitch.
2) If it is program problem, what I am suspecting is over-indexing of some array that I declared. If so, are there ways to know at which physical memory location the compiler located the variables??
I am very confused, because the same code works on some hardware and not on others.
Any advice from experts??
Thank you.
[/code] |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Sat Oct 20, 2012 12:42 am |
|
|
The sym file shows the locations of the variables.
The 'odds' are they are in the order declared, unless the chip is relatively tight on memory, which would suggest it was t1_buffer overflowing.
However I think there is a potential problem with the logic.
If you interrupt in the period between where you have added a character to the buffer, but have not yet updated the pointer, the INT_TBE, could decide that the buffer is empty (since the counter has not been updated), and go to the 'off' state, but since next_in==next_out in the external code, was evaluated before the character was added, bputc, wouldn't re-enable the interrupt, and the code would be hung. This fault is in CCS's example as well. It only happens in the very low probability that an interrupt occurs in that exact moment, but can cause problems. For most users there is an immediate recovery, when the next byte is sent, but you seem to actually be switching operating modes from TX to RX when the buffer is seen to be empty and potentially then getting completely hung....
There are several solutions, but possibly the simplest is to disable_interrupts(GLOBAL); on the line before evaluating next_in==next_out, and then re-enable this after t1_next_in=ni; is executed. This ensures the pointers are updated _before_ the interrupt occurs.
You'd have to enable the interrupt also if the buffer was full.
Best Wishes |
|
|
hello188
Joined: 02 Jun 2010 Posts: 74
|
|
Posted: Sat Oct 20, 2012 2:45 am |
|
|
OK. I found the problem. I failed to initialize the a variable that is used as an index to some array resulting in memory corruption. I am wondering, If I do not initialize variable, does it load as some random value everytime the CPU starts up?? For example, at one time, it may read as 0x88, and the other times, it may read as some other value??
Thank you for your feedback. Now, I can make my code more error tight.
Basically, I have to disable only INT_TBE until the pointer was updated since that is the place where it checks the pointer.
Is disable_interrupts() and enable_interrupts() function atomic? In other words, does it take only single instruction cycle and the interrupt is disable on the following cycle??
If not, at least on the C source code, would the interrupt be disabled by the time the next code in line starts to execute??
Thanks. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Sat Oct 20, 2012 4:11 am |
|
|
Interrupts are only actually serviced on the first clock of an instruction.
disable_ints and enable_ints, update the flag before the first clock of the next instruction, so interrupts are stopped/started immediately.
The RAM contents on power on, are defined in the data sheet as 'x' (unknown). However many cells will tend to initialise to a fairly constant value. So a sort of 'dartboard' value, rather than truly random.
Best Wishes |
|
|
|
|
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
|