PDA

View Full Version : Strange register interaction on 18F2431



HenrikOlsson
- 26th December 2014, 16:57
Hi guys,
I've been banging my head against the wall for a couple of days now and I just can't seem to figure this out. Needless to say I need some fresh eyes and ideas so if you have a minute, bare with me.

Background:
Working on my DC servo motor control code for a 18F2431. I've got a bunch of user settings stored in EEPROM which are changeable via a serial terminal - nothing fancy. All of a sudden I notice that one of the settings, namely the one for the digital encoder filter on the 18F2431 (DFLTCON register) isn't displayed properly even after a fresh reprogram of the code and "stock" EEPROM data.

Basically I've got this

EE_EncFilter DATA BYTE 48
Enc_Filter VAR BYTE
READ EE_EncFilter, Enc_Filter
DFLTCON = Enc_Filter

The read part is obviously in a subroutine where I read all the other variables stored in EEPROM. The problem is that when my PIC starts and I "print" all the settings the value in DFLTCON is NOT 48 and I've spent days trying to figure out what the heck is going on. And now comes the fun part....

When the program starts it calls a subroutine named ResetServo which does a bit of housekeeping to set everyhing up. I do not (and I repeat DO NOT) write to DFLTCON in this subroutine, yet the value changes while execting that subroutine. I've tracked it down to the following, and most of what I show now is for debug purposes:

HSEROUT["A-", DEC EncFilter," ", DEC DFLTCON,13,10]
GOSUB DoServo ' Run servo loop to update everything and set the PWM.
HSEROUT["B-", DEC EncFilter," ", DEC DFLTCON,13,10]
op_Fault_Output = 1 ' Reset the fault output.
HSEROUT["C-", DEC EncFilter," ", DEC DFLTCON,13,10]

' This is the offending line. Whenever this is commented out
' the overwriting of DFLTCON stops. WTF??
PTCON1.7 = 1 ' Turn on PWM timebase.

HSEROUT["D-", DEC EncFilter," ", DEC DFLTCON,13,10]
op_Enable_Output = 1 ' Enable bridge drive
HSEROUT["E-", DEC EncFilter," ", DEC DFLTCON,13,10]
BlinkPattern = Pattern_OK

RETURN
Now, all the HSEROUT stuff is just me trying to figure when and where DFLTCON changes, hence the letters A to E.
I can call the ResetServo routine manually over the serial console and if I do that, as the code is shown above, here's what I get for a couple of "resets" (with comments is red):

A-48 63 (My variable is 48 but DFLTCON is NOT 48 for some reason and the bloody thing is being changed.....)
B-48 63
C-48 63
D-48 65
E-48 67
Servo RESET!
Y-Encoder filter: 2.5MHz (Here I'm using the console to change the setting BACK to the default 48)
A-48 48
B-48 48
C-48 48 (At this point both my variable and DFLTCON IS 48 as it should)
D-48 50 (But now it's changed.)
E-48 52 (And it's changed again)
Servo RESET!
A-48 53 (and it's changed)
B-48 53
C-48 53
D-48 53
E-48 55
Servo RESET!
A-48 56
B-48 56
C-48 56
D-48 56
E-48 58
Servo RESET!
A-48 59
B-48 59
C-48 59
D-48 59
E-48 61
Servo RESET!
A-48 62
B-48 62
C-48 62
D-48 64
E-48 65
Servo RESET!

As you can see, my variable (Enc_Filter) stays intact but the content of DFLTCON is somehow changing.

Oh, you're overwriting it somewhere in an ISR or whatever I here you say....
My code base consists of multiple files and I've searched for DFLTCON thru each and every one of them. I'm writing to DFLTCON at exactly TWO places. One is at start up, where I'm reading the value stored in EEPROM into my variable (Enc_Filter) and writing that to DFLTCON. The other is in the code for the console where I can change the value as shown above. That's it. Yet the content of DFLTCON is somehow changing "on its own".

Now, if I comment out the line where I'm enabling the PWM timebase (PTCON1.7 = 1) the problem dissapears (or is masked) and whatever is written to DFLTCON at startup (or when Enc_Filter is changed) stays there:

A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
Setttings saved
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!
A-48 48
B-48 48
C-48 48
D-48 48
E-48 48
Servo RESET!

I can't for the life of me see why writing to PTCON1.7 in itself would cause this. I would have thought it was something in the subroutine DoServo (which isn't exectued when the PWM timebase isn't running) that's ACTUALLY causing it. However, (as you can see) I AM Calling DoServo manually between outputs 'A' and 'B' in the code above and DFLTCON is NEVER changed at that point so nothing in DoServo is accidently accessing DFLTCON as far as I can see.

On top of that I've tried calling DoServo in a loop, from my Main routine (ie, the timebase isn't running and therefor the ISR that's normally calling DoServo isn't executed) but DoServo is called at 1ms intervals anyway but again, DFLTCON is left alone at whatever value it's set to. It's ONLY when that line (PTCON1.7=1) is "enabled" that the problem occurs.

Any ideas what might be going on here?

/Henrik.

EDIT: Oh, and remember, it's not the variable in RAM that's changing (like an array accessed outside its bounds or something).
The variable stays intact, it's the actual SFR at location F60h that's changing. I've crossreferenced the datasheet against the MPASM .INC file and the adresses for DFLTCON and PTCON1 both seems correct.

richard
- 26th December 2014, 21:15
PTCON1.7 = 1 seem to point to an issue with your pwm timebase interrupt , what does that look like any asm code in it, maybe incorrect banksel
if you disable interrupts does the problem persist ?
can you make a simplified cut down version that still demonstrates the problem

Demon
- 26th December 2014, 22:08
...
can you make a simplified cut down version that still demonustrates the problem

My usual suggestion, plus, check out the datasheet at the registers just before the messed up one. Anything stand out? Do you use those? Maybe want to display those as well to see if your register is just not the tip that is visible of a larger problem.

Without having a chip to try your code, what about config fuses? Some features multiplex, maybe you've got another feature doing stuff you're not expecting.

Funky stuff, wish I could help.

Robert

HenrikOlsson
- 27th December 2014, 13:09
Hi guys,
Thank you for your replies!

Richard,
Untill now the interrupts have always been enabled though obviously the PWM timebase interrupt isn't generated if the timebase isn't running. What I've done since yesterday is to add code to main routine which once every 1600ms prints the content of DFLTCON, this doesn't work if the PWM timebase isn't on because the 1600ms "tick" is based on that. When the program starts the DFLTCON is set to what is stored in EEPROM (as expected) then the ResetServo routine is called, where DFLTCON somehow gets changed, and then is stays at that value for as long as I leave it on. I've left it for 20min, and at an interrupt rate of 1500Hz that's 1.8 million interrupts, the content of DFLTCON stayed intact.

After those 20 minutes I manually called the ResetServo via the serial console, as Before the content of DFTLCON changed while that routine executed and then it reamains at that new value - whatever it is.

None of the other 20 values I can change via the serial console is misbehaving as far as I've been able to tell - it's only the setting for DFLTCON and again, it's not my variable that's changing it's the actual SFR.

What I've also tried is adding something like the following to main loop:

If DFLTCON <> EncFilter THEN 'DFTLCON is the SFR, EncFilter is my variable.
Toggle PortC.2
DFLTCON = EncFilter ' Force DFLTCON back to correct value
ENDIF
I've yet to see PortC.2 toggle anytime EXCEPT when ResetServo is called and DFLTCON is NOT written to (by me) from that routine at all - yet it changes.

At this point I'm tempted to just add DFLTCON = EncFilter at the end of the ResetServo subroutine and then just forget about it but there's something strange going on and I don't like it.

The actual interrupt code is a mix between PBP and ASM, it's all "treated" as pure ASM interrupts and I've manually examined the generated .lst file to figure out which system variables needs saving and restoring. The interrupt code itself has NOT been changed at all. With that said agree that it has to be something.....

/Henrik.

richard
- 27th December 2014, 13:42
the only time I have experienced anything similar was trying to use a LAT pin in the I2COUT command . i2c worked ok but other code got wrecked seemingly at random .
dt sorted for me , reason is a lot of commands like i2c etc set the tris reg by adding a fixed offset to the port address works fine for PORTX fails miserably for LATX . its not a trap I will fall into again .
I wonder if the problem could be tracked with source level debugger , it would probable be a tedious exercise though .

pedja089
- 27th December 2014, 13:52
As I mention in PM to HenrikOlsson,
MPLAB X have breakpoint on variable(ram location) read or write. That would pinpoint instruction that overwrite DFLTCON.
Also that could be up to MPASM version used. I had problem with DT_HID, but Darrel find out that ASM generated bad ram address for USB registers.
And there is allways option that there is bug in PBP.

richard
- 27th December 2014, 14:09
just a thought about using pbp code in isr declared as "asm" in dt_ints , I have stopped doing it if I'm dealing with word sized (addition subtraction comparisons ) I found it sets or resets pbp internal regs and causes no end of random glitches , byte sized things seem ok but never mult/div of course . caveat emptor

HenrikOlsson
- 27th December 2014, 17:37
Hi guys,
First of all, thank you again for your time and your replies, I do appreciate them!

I rolled my codebase back to where I started the other day. Verified that it didn't misbehave (which it didn't) and started to reimplement the changes made.
I made small changes and verified between each one that it still worked as expected (and with worked I mean the issue with the DFLTCON register).

I'm now pretty much at the state I was in before and it's still working as expected. Obviously there is SOMETHING wrong with my "other" code but I have been unable to figure out what it is that makes it behave the way it does.

The biggest change implemented was to remove Darrels EE_Vars routine in favour for using "standard" DATA, READ, WRITE - this to save program space. I can not find any difference between the current implementation and what I used up until this morning. Yet, this works and the other doesn't.

pedja089,
Yes, thank you for your PM. Over the years I've tried to get MPLAB X going for the sole purpose of being able to do source level debug at the hardware level. Needless to say I haven't been able to get it going. This would have been THE PERFECT time to use it and I would still VERY MUCH like to be able to figure out what the heck is going on.

Richard,
I'm not using DT-Ints at all but of course you're correct. PBP uses it's system variables so if/when you use PBP in an ISR those system variables needs to be saved/restored which is what DT-INTS does (when declared as a PBP type interrupt).
The drawback is that it saves and restores ALL the system variables even though the code in the ISR might only use one or two. What I've done is to look at the generated assembly listing for the ISR and then added code to save and restore only those system variables that gets used by the PBP code actually IN the ISR. I'm fully aware of the "danger" in this, and any change to the ISR code will force me to again look at the generated .lst file to see if any more system variables needs to be handled. With that said, the interrupt code wasn't touched at all when the issue with DFLTCON being overwritten occured so I can't see how it may have anything to do with it.

I've got three interrupt sources and the code for each is very short and simple.
* My PCPWM timebase interrupt service routine does not use any PBP system variables.
* My QEI rollover interrupt service rouitne does not use any PBP system variables.
* My USART receive interrupt serive routine uses T1, FSR0H and FSR0L so I'm saving and restoring those (one WORD and two BYTE variables).

It's not something I recommend doing.

I have a feeling the problem is still hiding in there somewhere just waiting to re-surface when I least expect it. I'll make sure to keep you updated!

/Henrik.

pedja089
- 27th December 2014, 18:36
I hope that you are solve problem...
If problem still persist, I could try to set up MPLAB X for you using TeamViewer.
Good Luck.