News:

Let's find out together what makes a PIC Tick!

Main Menu

indirect adressing error in interrupt

Started by pjmylle, Jun 20, 2023, 05:59 PM

Previous topic - Next topic

pjmylle

Hi

My name is Pieter-Jan Mylle and this is my first post on this forum.
Sorry for the spelling mistakes if there are any present, my native language is Dutch.

I'm investigating this bug for a while now but only pinpointed it now.
I used an outdated version of the compiler which had a simular bug, but just the opposite of this one (the IRP bit was not set when storing the variables with context restore in memory locations greater than 255).
So I bought the new version of the positron compilers.

My situation:
micro: 16f886
Uart tx buffer starts at location 0x4E
Interrupt context_store variables are located at 0x115.
When the context clear interrupt is called, the IRP bit is set in the status reg for indirect adressing the context_store variables (as this is located in memory address > 255) using the INDF and FSR reg.
When the program comes at the point for reading the array, the correct location is send to the FSR reg, but the IRP bit is not reset (as the array memory location is less than 255). This results in the program reading the wrong memory location. In this screenshot, just when txreg is read, the statusbit IRP is still set (status.7).
isr problem 1.png
isr problem 2.png 


And yes, my code is still under construction, it is now build just to send out 5 bytes of data through the serial port using interupts every 250ms.
In the screenshots, it was sending the second byte of the array (memory location 0x4F).

My hex and asm file is attached (had to rename the extension to .txt) and the code can be read and simulated with the PIC simulator IDE (or programmed into a microcontroller).
Compiler version is "Code Produced by the Positron8 Compiler. Version 4.0.3.3"

If necessary I can post the bas files.

Yes, I can solve this by manually manipulating the IRP bit, but this is something for the compiler to do correctly.

Thanks in advance
Pjmylle

TimB


Hello pjmylle

Well done on your English its better than mine!

Can you post the interrupt code (in basic)


pjmylle

Well it looks like the padding is off.
The debug variables are IO pins which I used for debugging with the logic analyser, same for the delayus. This helped me identify which interrupt was handled at what time.

ANd I see an error in my RX routine (the array pointer is incremented before storing the data), but the problem lies in the TX routine.
And my code is still work in progress, just got a little messed up searching for that bug.

Isr:
   Context Save
   debug1 = 1
   If ADif = 1 Then
debug2 = 1
DelayUS 10
debug2 = 0
   GoTo skipadc
'If (ADCON0 & $h3C) = %00110100 Then                    'buttons on AN13
If ADClock1 = 1 Then
   keyVal = ADRESH
KeyRDY = 1
ADClock1 = 0
ElseIf ADClock2 = 1 Then
ampVal.HighByte = ADRESH
ampVal.LowByte = ADRESL
ADCdone = 1
ADClock2 = 0
EndIf
      skipadc: 
      ADif = 0
   EndIf
   
   If RXif = 1 Then  'rxif is creared when rcreg is read
debug2 = 1
DelayUS 20
debug2 = 0
      If RCSTA.2 = 1 Then 'frame error
         dummy = RCREG
      Else
         If RXcount < (RXsize-1) Then
            Inc RXcount
            RXbuf[RXcount] = RCREG
         Else
            dummy = RCREG
         EndIf
         RXdone = 0
      EndIf
   EndIf
   
   If TXie = 1 Then
      'toggle indicator
      If TXif = 1 Then
      'Toggle indicator
debug2 = 1
DelayUS 30
debug2 = 0
      If TXcounter < (TXcount - 1) And TXcount > 0 Then
         Inc TXcounter
         TXREG = TXbuf[TXcounter]                     
      Else
         TXdone = 1 'final byte
         TXie = 0
      EndIf
      TXif = 0
      EndIf
   EndIf
   
   If SSPif = 1 Then
debug2 = 1
DelayUS 40
debug2 = 0     
      SSPif = 0
   EndIf

' If IOC = 1 Then

' ioc = 0
' EndIf
   
   If T0IF = 1 Then                                    '5ms interval timer
      TMR0 = 100
      timebase0 = 1
debug2 = 1
DelayUS 50
debug2 = 0     
Inc CT1
If CT1 = 50 Then '250msec interval critical timer
   CT1 = 0
   timebase1 = 1
   If VbatCounter > 0 Then Dec VbatCounter
EndIf

     
      If CT2 = 3 Then
         If ADClock2 = 0 Then          'no adc is in progress
            ADCON1 = 0              'adresh = result
   ADCON0 = %11110101      'select push buttons (AN13)
   Inc CT2                 'in the next timer interrupt the code below will be called
   ADClock1 = 1
   EndIf
ElseIf CT2 = 4 Then       
         ADCON0.1 = 1            'start a conversion
         CT2 = 0
      ElseIf CT2 < 3 Then
         Inc CT2
      EndIf
      T0IF = 0
   EndIf
   debug1 = 0
Context Restore

TimB


I would try adding this line just after the context save line or even "If TXie = 1 Then"

reset_bank

If it is an issue with bank selection then that should resolve it


pjmylle

Thank you for the assistance.

Unfortunatly the command "reset_bank" only resets status.5 and status.6 bit.
Also the status.7 is still set at the moment the array is interacted with.
isr problem 3.png

pjmylle

#5
This is an error in the compiler it seems.
In not interrupted code, it acts normal and sets the status.7 bit is the memory location is above 255.
Then after using the INDF command, this bit is cleared again
Here I just created an array that is at memory location 0X115.
Before reading from this array, the IRP bit is set.
When reading from a memory location lower than 255, this bit is not cleared before using the INDF command.
isr problem 4.png
So when in the interrupt code, the IRP bit gets set (by the context store routine) and using the indirect addressing (by utilising arrays), this status.7 bit is not cleared as the compiler assumes that this bit is always cleared (hence it clears it after setting it).

pjmylle

Just tested the ISR code with an array read from a memory location above 255 and below or equal to 255.
When the array is read on line 6455 the IRP bit is not set before because of the lower memory region.
On line 6462 it is set to read the higher region of memory and resets it after the INDF command. This proves my previous explanation.
So the fix for this bug is just resetting the STATUS.7 bit after the context save.

pjmylle

Also the status.7 bit should be resetted after the context restore before the retfie command.

TimB


I use interrupts in every prog I write mostly 18F but I do use 16F devices and have not seen this issue. So I seriously suspect its not the issue you think it is

Handling banking is complex but Les has shown time and time again he knows what he is doing.

The compiler tracks what bank swapping is needed and removes unessesary code to change banks every time a variable is addressed. Providing the rules are stuck to. I know because I broke the rules.

Also its no use posting asm #5 that is not even from the asm from the interrupt routine.


If you can explain what you are trying to code I can offer advice. BTW Please do not use delays in an interrupt. Stick to simple code, jumping back into routines that may already be running is a bad idea.









tumbleweed

I don't see anywhere that the IRP bit is being reset after the context save either, so I agree with the OP.

QuoteAlso the status.7 bit should be resetted after the context restore before the retfie command.
The STATUS register is saved in SSAVE as part of the ISR entry and restored right before the retfie, so that should put things back the way they were before the interrupt.

pjmylle

Yes indeed, the STATUS reg is restored in the context restore. It wouldn't matter if the IRP bit is resetted in the context restore as the STATUS reg is restored anyway. Resetting the IRP bit after the contect save makes my ISR works as intended with reading and writing from arrays in the lower memory region.
So the fix for this problem is resetting STATUS.7 after the context save.

The reason this issue was hard to find is because of the situation. The context save registers must be in an memory location above 255, and you must use arrays in the ISR which are located in memory location lower or equal to 255. I only found out because my ISR was sending out 00 instead the the data I put in the TX array. Once I removed some unused variables at the time the issue went away.

The reason was once I had enough variables, the compiler adds the context save registers after the user's variables. And it doesn't matter if I define my variables used in the ISR first and place the ISR at the start of my program, the compiler always puts the INTERRUPT CONTEXT STORAGE last. You can check this in your asm files.

QuoteAlso its no use posting asm #5 that is not even from the asm from the interrupt routine
This was from the ISR code. Line 6469 is only used in my ISR code. TXdone is resetted when initializing the transmit and set when completed.

QuoteBTW Please do not use delays in an interrupt.
This was for debugging purposes only. So I could see with the logic analyser when each interrupt section was executed at what time (I was currently debugging on hardware). So I could be very sure that the problem lies within my TX interrupt.

Kind regards
PJM