View previous topic :: View next topic |
Author |
Message |
ralpok
Joined: 21 Dec 2005 Posts: 25
|
Programming issue |
Posted: Fri May 11, 2007 6:26 pm |
|
|
The Basics:
CCS Compiler Version 4.027
Target PIC 184685
Debug Mode
Target Voltage 5V
Traget Oscillator 20mhz
I am having a problem where my array of floats is not getting cleared. When I dug into the assembly I found the attached code. I then used the debugger to look at all the associated memory addresses and 5F, 5E, and 5D are cleared but 60 is not. I also an unfamiliar with what the 'X' means in front of the 60. I also checked all the other memory addresses that had a value 60 in them (i.e. 160, 260, 360 ... f60) and none of them were cleared either. Some help in understanding what the assembly is doing will be helpful and any advice as to why when I "watch" this varaible right after I clear it does it still have a value to it?
Code: |
.................... myFuelSurfaceTable.percent[0] = 0;
01062: CLRF x60
01064: CLRF 5F
01066: CLRF 5E
01068: CLRF 5D
|
Thanks,
Chris |
|
|
RossJ
Joined: 25 Aug 2004 Posts: 66
|
|
Posted: Fri May 11, 2007 6:54 pm |
|
|
Data memory in many PIC families is banked, as opposed to being in one continuous address range. What this means is that a separate register (bank select) controls which bank of memory is accessed whe an instruction accesses a particular address. In the PIC18 instruction set, some instructions only contain the lower 8 bits (others like MOVFF contain the full address). If a banked access is used, the compiler shows this as xnn since only the nn parts (lower 8 bits) is indicated by the instruction. The MOVLB instruction loads the bank selection register with a literal value and is the most common instruction for controlling this register used by the compiler.
One other thing to consider is that some parts of memory are designated as 'access' memory. Essentially this is a small part of memory which can be accessed without depending on the current bank selection. Many instructions contain an 'a' bit which indicates whether an instruction accesses memory directly in the access bank or anywhere else with the help of the bank selection register.
In your example, I suspect that 5D-5F are being addressed via the access memory, while x60 is not, and depends on the current BSR. Possibly the compiler hasn't allowed for one variable to cross this threshold, and thus hasn't set the correct bank. Look at the preceeding instructions for a MOVLB instruction, and compare the bank with the .sym file's statement as to where your variable has been placed.
Also, you might find it helpful to look at a proper disassembly which shows the instruction binary as well. Then you can compare it with the datasheet for a better understanding of the difference between the instructions with and without an 'x'. I use MPLAB to do this, and import the .cof file.
If you suspect that the compiler is at fault here, it would be a good idea to try using the latest version since you are a little behind the times (current version is 4.035.
/Cheers, Ross. |
|
|
ralpok
Joined: 21 Dec 2005 Posts: 25
|
|
Posted: Mon May 14, 2007 10:04 am |
|
|
RossJ,
Thanks for your reply. It was very helpful in helping me understand how the PIC was working. Unfortunately it didn't solve the problem. I have updated to CCS compiler 4.035 and am experiencing the same problem.
While running my code in the problematic sections I looked at the BSR register. What I found was that it was set to 1 instead of 0. This didn't seem to make sense with the rest of the code around it, especially breaking the variable up across 2 different banks for the clearing of the following variable. Checking the RAM directly shows that 5D-5F and 160 got cleared and 060 did not.
Code: |
.................... myFuelSurfaceTable.percent[0] = 0;
01062: CLRF x60
01064: CLRF 5F
01066: CLRF 5E
01068: CLRF 5D
|
I also did a quick search through my .lst file for a movlb and the only values that got loaded into this register were 0 and F, which adds to my confusion as to why this register had a 1 in it.
Another thing that is confusing is when I assign the value through another variable then it works correctly like below. Also, are these instuction special because they don't seem to make use of the bank adressing scheme that we discussed above.
Code: |
.................... myFuelSurfaceTable.percent[1] = frequency[1];
0106A: MOVFF 3C,64
0106E: MOVFF 3B,63
01072: MOVFF 3A,62
01076: MOVFF 39,61
|
and then when I assign it using a constant it once again maps to the wrong bank and ends up in bank 1 instead of bank 0.
Code: |
.................... myFuelSurfaceTable.percent[2] = 0.2222;
0107A: MOVLW 66
0107C: MOVWF x68
0107E: MOVLW 88
01080: MOVWF x67
01082: MOVLW 63
01084: MOVWF x66
01086: MOVLW 7C
01088: MOVWF x65
|
I apologize in advance for my ignorance and am very much appreciative of your help. |
|
|
ralpok
Joined: 21 Dec 2005 Posts: 25
|
|
Posted: Mon May 14, 2007 3:05 pm |
|
|
Found a way to hack around it.... but if anybody can give me a full explination as to why it wasn't working I would apreciate it.
The Hack is in the decleration:
Code: | volatile struct fuelSurfaceTable myFuelSurfaceTable;
#locate myFuelSurfaceTable=0x100 |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon May 14, 2007 3:15 pm |
|
|
If possible, post a small test program that shows the problem.
Show all variable declarations. The test program should be able
to be copied and pasted into MPLAB and compiled without errors. |
|
|
ralpok
Joined: 21 Dec 2005 Posts: 25
|
|
Posted: Mon May 14, 2007 4:12 pm |
|
|
So.. I tried to make a small test program displaying the problem and it worked without showing the issue, and then I went back to a .zip of the project that was displaying the problem (had it saved from when I sent the issue to CCS tech help) and it also behaved properly. I don't know if my call to #locate fixed the issue or what but all in all I am going to call this issue a mystery that I don't think will be solved at this point.
Thanks for the attempt at help PCM and all the help you give around the forums.
Ralpok |
|
|
RossJ
Joined: 25 Aug 2004 Posts: 66
|
|
Posted: Tue May 15, 2007 6:33 pm |
|
|
Ralpok,
You are correct in your assumption about MOVFF. If you take a look at the instruction set summary in the data sheet, you will see many instructions contain 8 bits marked 'ffff ffff'. This represents the instructions that can only address a 256 byte page, with the help of the 4 bit BSR. MOVFF is the only instruction to have a 12 bit address (both source and destination) and thus does not depend on the BSR (and similarly doesn't need the option of addressing access memory either). So MOVFF can move any byte to any other byte of data memory (in two machine cycles), and is the instruction used by CCS when copying a variable from one fixed address to another.
Regarding how BSR came to have the value 1, remember it is just a SFR which happens to have a purpose made instruction for optimisation (MOVLB). So any instruction which modifies the BSR as a SFR could be responsible (including indirect accesses). Even faulty memory accesses could do it (you observed 0x160 being modified in error).
Another possible reason is that the LST file doesn't actually contain all the generated code! Cases I know of include certain types of switch statements and constant array lookups. There are probably others. You may find a call or jump instruction to an address not present in the LST file. I use MPLAB to import the COF file and view the disassembly listing when I need to see this code. So there might be a BSR modification in some code not shown in the LST file.
I tried to reproduce your problem (admittedly using an 18F2620), but was not successful. The compiler doesn't seem to care if large variables are split over the boundary of access memory. But it does appear to correctly insert MOVLB instuctions as required. So there must be something in the surrounding code which is causing the compiler to screw up.
If you think this is a fault in the compiler, it's in everyone's interest to try and see it through to a resolution. From what you have described, there is little doubt that it is a fault in the compiler. The question is under what circumstances it is triggered, and whether CCS has fixed it intentionally or otherwise) in a later version. If you have trouble reproducing the problem with the latest version, go back to a version you know the fault occurs in. Bugs like this can seem to be fixed in new compiler releases, but in fact the problem simply didn't occur because of differences in other parts of the generated code.
If you have submitted something to CCS, contact them to find out if they have pinned down this problem, before wasting time investigating this any further.
/Ross. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 15, 2007 6:37 pm |
|
|
Quote: |
Another possible reason is that the LST file doesn't actually contain
all the generated code. |
To see all the generated code, edit the .H file for your PIC and comment
out the #nolist statement near the top of the file. Example:
Quote: |
//// Standard Header file for the PIC18F4685 device /////
#device PIC18F4685
// #nolist
|
Then re-compile and look at the .LST file. |
|
|
Jim Hearne
Joined: 22 Dec 2003 Posts: 109 Location: West Sussex, UK
|
|
Posted: Wed May 16, 2007 9:57 am |
|
|
Quote: | To see all the generated code, edit the .H file for your PIC and comment
out the #nolist statement near the top of the file. Example: |
It seems to be a good idea to do this with any .lst files you send to CCS for investigation.
They couldn't find the memset bug in v4.032 until i sent in listings with #nolist commented out.
Jim |
|
|
ralpok
Joined: 21 Dec 2005 Posts: 25
|
|
Posted: Wed May 16, 2007 10:09 am |
|
|
No word from CCS for the moment.
Okay... so it doesn't seem to reappear if I change the code to fit as a small example but I have been able to reproduce it with the updated compiler and I am going to try and give you guys all the information about the system. This is compiled and run with the #nolist commented out.
Included here is: basic code that gets executed,and the entire code base, screen shot of the debugging. If you want a look at any parts of the .lst file let me know, I did a quick search and didn't find anything new about setting the BSR register. I would have posted the entire .lst file but didn't want to due to protecting CCS's IP since the comments have all their code in it. Thanks in advance for everyone's help on this topic!
Image Hosting
the variable decleration:
Code: |
volatile struct debugSurfaceTable mydebugSurfaceTable;
|
the basic code that gets executed:
Code: |
void basicInit()
{
float debug = 0;
can_init();
delay_ms(10);
output_low(PIN_C6);
output_low(PIN_C5);
//Start with setup for calibration
//Large Probe
output_high(PIN_A0);
//Small Probe
output_low(PIN_A1);
//for in the shop debugging
//gStartCal = 0;
//output_high(PIN_A0);
//Small Probe
//output_high(PIN_A1);
//Interrupt every 104.8 ms
Setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
Enable_interrupts(INT_TIMER1);
Enable_interrupts(INT_EXT);
Enable_interrupts(GLOBAL);
Ext_Int_Edge(0,H_TO_L);
mydebugSurfaceTable.frequency[0] = 5.80;
mydebugSurfaceTable.frequency[1] = 5.719;
mydebugSurfaceTable.frequency[2] = 5.63875;
mydebugSurfaceTable.frequency[3] = 5.4775;
mydebugSurfaceTable.frequency[4] = 5.31625;
mydebugSurfaceTable.frequency[5] = 5.155;
mydebugSurfaceTable.frequency[6] = 4.9937;
mydebugSurfaceTable.frequency[7] = 4.8325;
mydebugSurfaceTable.frequency[8] = 4.671;
mydebugSurfaceTable.frequency[9] = 4.51;
mydebugSurfaceTable.percent[0] = 0;
mydebugSurfaceTable.percent[1] = 0.1111;
mydebugSurfaceTable.percent[2] = 0.2222;
mydebugSurfaceTable.percent[3] = 0.3333;
mydebugSurfaceTable.percent[4] = 0.4444;
mydebugSurfaceTable.percent[5] = 0.5555;
mydebugSurfaceTable.percent[6] = 0.6666;
mydebugSurfaceTable.percent[7] = 0.7777;
mydebugSurfaceTable.percent[8] = 0.8888;
mydebugSurfaceTable.percent[9] = 0.9999; **BREAK POINT**
}
void main()
{
basicInit();
while(1);
// TODO: USER CODE!!
}
|
Last edited by ralpok on Wed May 16, 2007 10:14 am; edited 1 time in total |
|
|
ralpok
Joined: 21 Dec 2005 Posts: 25
|
|
Posted: Wed May 16, 2007 10:12 am |
|
|
The entire code base
Code: |
#include <18F4685.h>
#device ICD=TRUE
#device adc=10
#fuses HS,NOWDT,PUT,NOLVP,BROWNOUT
#use delay(clock=20000000)
#include <can-18xxx8_1Meg_Full_ID.c>
#define FULL_debug_COUNT 5142.0
#define debug_RANGE 804.0
#define NUM_INTERRUPT_OVERFLOWS 20
#define MS_PER_INTERRUPT 104.8
#define CAL_INT_OVERFLOW 30
#define NUM_SURFACE_POINTS 10
#define debug_PROBE_FREQ_SCALER 2.569
struct debugSurfaceTable
{
float percent[NUM_SURFACE_POINTS];
float frequency[NUM_SURFACE_POINTS];
};
volatile int32 gTimerOverFlow = 0;
volatile int32 gdebugLevelCount = 0;
volatile float gCalibrteThreshold = 0.8;
volatile int gSetShortSensor = 0;
volatile int gStartCal = 1;
volatile float gSmallFullPnt = 7.46;
//volatile float gCalShortFull = 7.4;
volatile float gProbeOffset = 0;
volatile int gCalPeriod = 0;
//Values Set by Avacs
volatile float gLargeEmtpyPnt = 6.935;
void ProcessPWM();
void calibrateSurfaceTable(float);
float getPercentFromFqy(float fqy);
//#org 0x0100, 0x01ff
float frequency[10];
volatile struct debugSurfaceTable mydebugSurfaceTable;
//#locate mydebugSurfaceTable=0x100
#int_ext
void debugLevelSensor ()
{
gdebugLevelCount++;
}
#Int_TIMER1
void TIMER1_isr()
{
gTimerOverFlow++;
//This will flag every 104.8 ms * 100
if (gTimerOverFlow >= NUM_INTERRUPT_OVERFLOWS)
{
ProcessPWM();
gTimerOverFlow = 0;
gdebugLevelCount = 0;
}
}
void basicInit()
{
float debug = 0;
can_init();
delay_ms(10);
output_low(PIN_C6);
output_low(PIN_C5);
//Start with setup for calibration
//Large Probe
output_high(PIN_A0);
//Small Probe
output_low(PIN_A1);
//for in the shop debugging
//gStartCal = 0;
//output_high(PIN_A0);
//Small Probe
//output_high(PIN_A1);
//Interrupt every 104.8 ms
Setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
Enable_interrupts(INT_TIMER1);
Enable_interrupts(INT_EXT);
Enable_interrupts(GLOBAL);
Ext_Int_Edge(0,H_TO_L);
mydebugSurfaceTable.frequency[0] = 5.80;
mydebugSurfaceTable.frequency[1] = 5.719;
mydebugSurfaceTable.frequency[2] = 5.63875;
mydebugSurfaceTable.frequency[3] = 5.4775;
mydebugSurfaceTable.frequency[4] = 5.31625;
mydebugSurfaceTable.frequency[5] = 5.155;
mydebugSurfaceTable.frequency[6] = 4.9937;
mydebugSurfaceTable.frequency[7] = 4.8325;
mydebugSurfaceTable.frequency[8] = 4.671;
mydebugSurfaceTable.frequency[9] = 4.51;
mydebugSurfaceTable.percent[0] = 0;
mydebugSurfaceTable.percent[1] = 0.1111;
mydebugSurfaceTable.percent[2] = 0.2222;
mydebugSurfaceTable.percent[3] = 0.3333;
mydebugSurfaceTable.percent[4] = 0.4444;
mydebugSurfaceTable.percent[5] = 0.5555;
mydebugSurfaceTable.percent[6] = 0.6666;
mydebugSurfaceTable.percent[7] = 0.7777;
mydebugSurfaceTable.percent[8] = 0.8888;
mydebugSurfaceTable.percent[9] = 0.9999;
}
void main()
{
basicInit();
while(1);
// TODO: USER CODE!!
}
void ProcessPWM()
{
float debugLeft;
float measuredFreq;
char percent[8];
// int x;
//Num msec = NUM_INTERRUPT_OVERFLOWS * MS_PER_INTERRUPT
//freq = num cycles/ num msec (in Khz)
measuredFreq = gdebugLevelCount / (NUM_INTERRUPT_OVERFLOWS * MS_PER_INTERRUPT);
gCalPeriod++;
if (gStartCal)
{
//make sure that the debug is at least at a level that can
//allow it to be properly calibrated
if ((measuredFreq < (gLargeEmtpyPnt - gCalibrteThreshold)) && !gSetShortSensor)
{
//Turn on the small probe for the calibration
//Large Probe
output_low(PIN_A0);
//Small Probe
output_high(PIN_A1);
gSetShortSensor = 1;
}
else
{
gStartCal = 0;
//Return to normal debug reading
//Large Probe
output_high(PIN_A0);
//Small Probe
output_high(PIN_A1);
if (gSetShortSensor)
{
//Return to normal debug reading
//Large Probe
output_high(PIN_A0);
//Small Probe
output_high(PIN_A1);
calibrateSurfaceTable(measuredFreq);
gSetShortSensor = 0;
}
}
}
else
{
debugLeft = getPercentFromFqy(measuredFreq);
percent[0] = debugLeft * 100.0;
can_putd(0x00600002,percent,1,1,TRUE,FALSE);
}
if (gCalPeriod >= CAL_INT_OVERFLOW)
{
gStartCal = 1;
gCalPeriod = 0;
//Turn on the large probe to make sure you have enough to calibrate
//Large Probe
output_high(PIN_A0);
//Small Probe
output_low(PIN_A1);
}
}
float getPercentFromFqy(float fqy)
{
int ndx;
int i;
float debug1;
float debug2;
float debug3;
float debug4;
//if it is past the endpoint, return endpoint
if (mydebugSurfaceTable.frequency[0] < fqy)
{
return mydebugSurfaceTable.percent[0];
}
//if it is past the endpoint, return endpoint
if (mydebugSurfaceTable.frequency[NUM_SURFACE_POINTS - 1] > fqy)
{
return mydebugSurfaceTable.percent[NUM_SURFACE_POINTS - 1];
}
//if you get lucky, return the exact PWM
for (ndx = 0; ndx < NUM_SURFACE_POINTS; ndx++)
{
if (mydebugSurfaceTable.frequency[ndx] == fqy)
{
return mydebugSurfaceTable.percent[ndx];
}
}
//interpolate
for (i = 0; i < NUM_SURFACE_POINTS && mydebugSurfaceTable.frequency[i] > fqy; i++);
debug1 = mydebugSurfaceTable.percent[i - 1];
debug2 = mydebugSurfaceTable.percent[i] - mydebugSurfaceTable.percent[i - 1];
debug3 = fqy - mydebugSurfaceTable.frequency[i - 1];
debug4 = mydebugSurfaceTable.frequency[i] - mydebugSurfaceTable.frequency[i - 1];
return (debug1 + debug2 * (debug3 / debug4));
}
void calibrateSurfaceTable(float shortProbeFreq)
{
float max, delta;
signed int ndx;
max = shortProbeFreq - debug_PROBE_FREQ_SCALER;
delta = (max - mydebugSurfaceTable.frequency[0]) / 9.0;
mydebugSurfaceTable.frequency[9] = max;
for (ndx = 8; ndx >=0; ndx--)
{
mydebugSurfaceTable.frequency[ndx] = mydebugSurfaceTable.frequency[ndx + 1] - delta;
}
}
|
|
|
|
|