News:

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

Main Menu

Very strange behaviour of HRSOUT2

Started by TimB, Jun 19, 2023, 12:13 PM

Previous topic - Next topic

TimB


This is not an official anomaly report as I'm not sure where the issue is

I have an interrupt driven serial buffer for Usart1 and Usart2 code below

If I issue the command Hrsout2 1 my terminal will get 1. If I issue Hrsout2 aRX1DataBuffer#2 I will get 62 odd bytes out

Now after struggling with this 4+ hours I'm suspecting the issue is that banks are not being selected properly

Looking at the asm difference between the 2 lines I see

    movlb 2
    movf aRX1DataBuffer#2,W,1
    rcall __hrsout2__ 

and

    movlw 1
    rcall __hrsout2__

My hrsout code is

'-------------------------------------------------------------------------------

    #Disable HRSOut2

    Dim bInterruptTemp2 as byte

__hrsout2__:

    INTCONbits_GIE = 0
    bInterruptTemp2 = WREG
    aTX2RingBuffer[bTX2EndBuffPntr] = bInterruptTemp2                            ' Load the data into the buffer
    Inc bTX2EndBuffPntr                                                         ' Inc the pointer
    If bTX2EndBuffPntr >= cTX2BuffSize Then                                     ' Check for roll round
        bTX2EndBuffPntr = 0
    EndIf
    PIE3bits_TX2IE = 1                                                          ' Always enable TX interrupts
    INTCONbits_GIE = 1

    Return

I'm thinking that the pointers are not being addressed properly. So just running in a big loop

Any ideas how to fix this?

Thanks

Tim


TimB

Ok it seems it was definatly a ram bank issue

I added reset_bank to the usart buffer code and it fixed it


    INTCONbits_GIE = 0
    reset_bank
    bInterruptTemp = WREG

top204

I'll take a look at it.

What device? I need the device name because things change all the time in them, and SFRs especially move around in them dreadfully from device to device.

TimB


Hi Les

It is the Pic18f27Q10

I doubt you will want all the code but if I can help I will email what ever is needed

top204

#4
I've made some checks and the USART2 is working OK with the 18FxxQ10 devices.

I have just noticed that your code is disabling the compiler's HRsout2 libraries, and creating code to replace them.

A call to a compiler library routine will not alter RAM banks before it, because it assumes (correctly) that the library code itself will reset and alter RAM banks, then reset the RAM bank before returning. So if the variable "bInterruptTemp2" is in any other RAM bank, its RAM bank may not have been set correctly, and the Reset_Bank directive will have reset the compiler's banking mechanism and seen that the "bInterruptTemp2" variable needs its RAM bank altered.

The Return command will reset RAM banks if its previous variable was in a different RAM bank.

TimB


Thanks

I will add code to save and restore the banks

Tim

top204

#6
There is no need to save-restore RAM banks Tim.

The library subroutines all use compiler variables that always reside in Access RAM, or low RAM. So if in doubt where the first variable or SFR resides in RAM, use the Set_Bank directive. For example:

Set_Bank bInterruptTemp

Or use the Reset_Bank directive, as you did.

Then the compiler will alter the following RAM banks for you because it has been forced to alter it to suit the variable/SFR first used, or has been reset, so it will look at the variable/SFR and alter the RAM bank to suit it, and the library call mechanism will be happy. The Return command will reset the RAM bank for you, so the library call mechanism is kept happy with that as well. :-)

In an assembler library subroutine, you will often see a Movlb mnemonic or alterations to the STATUS bits as the first instruction/s, so the progran knows where an SFR or variable is located, because the library subroutine is not in the flow of the BASIC program itself. The compiler uses a special call mechanism when calling a library, so that it does not waste too much code memory changing RAM banks before every call, because it assumes the library will change RAM banks itself, and always return with the RAM bank reset.



TimB


Ok thanks Les

I did see you say Return would reset the ram bank but was not sure if it would in this instance, where I'm overriding built in commands. Thanks for the reassurance.

Tim



top204

#8
You are very welcome Tim.

A sure fire way to make sure RAM banks are manipulated, regardless of where a label is or what RAM bank has been set before it, is to use Sub-EndSub. I initially added this mechanism, so that the compiler always knew where the start and end of a standard subroutine was, and that the name was not just another label name, but a subroutine name, so RAM banks could be manipulated more robustly.

For example, the nonsense code listing below shows what will happen to the assembler code, even though the RAM banks are out of bank 0 and are the same and are just next to each other, and the HRsout2 call does not reset RAM banks because it knows the dedicated compiler library subroutine will set/reset the RAM bank within itself:

    #Disable HRSOut2
    Dim MyByte As Byte At $0400     ' Create a variable outside of RAM bank 0
'-------------------------------------------------------------------------
' The main program starts here
'
Main: 
    MyByte = 10         ' Load a variable outside of RAM bank 0, so that the RAM bank must be manipulated
    HRSOut2 "1"
    Stop
Sub __hrsout2__()
    MyByte = 20         ' Load the same variable, but even though they are in the same RAM bank and next to each other, the bank will be altered for it
EndSub

Looking at the assembler code, it can be seen, the compiler knows that "__hrsout2__" is a subroutine, so it will manipulate the RAM bank upon entry and exit, and just like a subroutine, it is placed in the code where it is written in the listing:

Main
F1_000035 equ $ ; in [TEST_18F25K20.BAS] MyByte = 10
    movlb 0x04        <------------------------------------ Alter the RAM bank for MyByte
    movlw 10
    movwf MyByte,1
F1_000036 equ $ ; in [TEST_18F25K20.BAS] HRsout2 "1"
    movlw 49
    rcall __hrsout2__        <------------------------------------ Call the library subroutine, but because it is a dedicated library do not alter the RAM bank
F1_000037 equ $ ; in [TEST_18F25K20.BAS] Stop
_pblb__2
    bra _pblb__2
;---------------------------------------------
F1_000038 equ $ ; in [TEST_18F25K20.BAS] Sub __hrsout2__()
__hrsout2__
F1_000039 equ $ ; in [TEST_18F25K20.BAS] MyByte = 20
    movlb 0x04        <------------------------------------ Alter the RAM bank for MyByte because the compiler knows it is a subroutine and the variable is not in RAM bank 0
    movlw 20
    movwf MyByte,1
F1_000040 equ $ ; in [TEST_18F25K20.BAS] EndSub
    movlb 0x00        <------------------------------------ Reset the RAM bank before returning
    return 0 ; EndSub

The use of Sub-EndSub for compiler library subroutines, was also one of the reasons I changed their names, so they could be used as subrotuine labels in the BASIC listing, instead of having to wrap them in Asm-EndAsm or precede them with a "@" character.

I am currently looking into a method where a compiler library routine can be wrapped in Proc-EndProc, and the procedure will only be used in the program if the command that calls the routine is used (easier said than done). This mechanism will also be useful when I start on the ARM compiler, so I can create library routines in the Positron high-level language and test them in the BASIC listing as though they are part of the compiler and only added into the program when a BASIC command is used, then use the assembler code generated as a true library subroutine for the alpha and beta compiler versions etc...