I would like the positron to have a function for accessing pin registers.

Started by atomix, Oct 10, 2022, 10:53 AM

Previous topic - Next topic

atomix

Device 18F46K22
Declare Xtal 64

Dim p As LATC.4

For PRODL = 0 to 9
    p =~ p
Next

' Need a new feature - PinReg
PRODH = PinReg(p, PORT)    ' converted by the compiler to  PRODH = PORTC.4
PRODH = PinReg(p, TRIS)    ' converted by the compiler to  PRODH = TRISC.4
PinReg(p, TRIS)  = 1       ' converted by the compiler to  TRISC.4 = 1
PinReg(p, ANSEL) = 1       ' converted by the compiler to  ANSELC.4 = 1

' or
PRODH = PORT##PinBase(p)    ' PinBase(p) = C.4 and converted by the compiler to  PRODH = PORTC.4

' or
PRODH = PORT##$regexp(p, "\w+?([a-z]\.\d)")    ' return matches[1] and converted by the compiler to  PRODH = PORTC.4

I will be very grateful to you Les !!!    8)

Frizie

Not sure, but maybe is your variablename too short.
Try making variablename longer than 'p'
Ohm sweet Ohm | www.picbasic.nl

keytapper

Ignorance comes with a cost


Yasin


top204

In order to use a variable as a variable's bit index, it must use the variable's address and bit masking, and Ors and Ands to alter the state of a bit, and that is what the GetBit, and Loadbit commands do. Remember, a port and an SFR are just a variable sitting in a RAM slot just like user variables!

So what you require can be performed with:

    Dim bPinNumber As Byte 
    Dim tPinState As Bit
   
'-------------------------------------------------------------------------------------------------------
' The main program starts here
' Toggle each pin of PORTB
'
Main:
    tPinState = 1                                       ' Set the initial pin state to high
    Low PORTB                                           ' Set all of PORTB output low
    Do                                                  ' Create a loop
        For bPinNumber = 0 To 7                         ' Create a loop for each pin of PORTB
            LoadBit(PORTB, bPinNumber, tPinState)       ' Load the Port's bit with the contents of tState
            DelayMS 255                                 ' Create a delay to see the pin's state alter
            LoadBit(PORTB, bPinNumber, ~tPinState)      ' Load the Port's bit with the contents of complemented tState
            DelayMS 255                                 ' Create a delay to see the pin's state alter
        Next                                            ' Close the pin loop
    Loop                                                ' Do it forever
     
    Byteout = GetBit(PORTB, 2)                          ' Read bit-2 of PORTB

The above program, toggles each pin of PORTB using variables for the bit number and its state. And also reads the state of a bit from a variable, Port or SFR.

Or the program listing below to sequentially set each pin high then low:

    Dim bPinNumber As Byte 
    Dim tPinState As Bit
   
'-------------------------------------------------------------------------------------------------------
' The main program starts here
' Sequenctially set each pin of PORTB on then off
'
Main:
    tPinState = 1                                       ' Set the initial pin state to high
    Low PORTB                                           ' Set all of PORTB output low
    Do                                                  ' Create a loop
        For bPinNumber = 0 To 7                         ' Create a loop for each pin of PORTB
            LoadBit(PORTB, bPinNumber, tPinState)       ' Load the Port's bit with the contents of tState
            DelayMS 255                                 ' Create a delay to see the pin's state alter           
        Next                                            ' Close the pin loop
        tPinState = ~tPinState                          ' Complement a pin's state for the next loop
    Loop                                                ' Do it forever

Or the program listing below to read each pin of a Port using a variable index:

    Dim bPinNumber As Byte 
    Dim tPinState As Bit
   
'-------------------------------------------------------------------------------------------------------
' The main program starts here
' Read each pin of PORTB and transmit the pin's state to a serial terminal
'
Main:
    Input PORTB                                         ' Set all of PORTB as an input
    Do                                                  ' Create a loop
        For bPinNumber = 0 To 7                         ' Create a loop for each pin of PORTB
            tPinState = GetBit(PORTB, bPinNumber)       ' Read a pin from PORTB          
            HRSOutLn "Pin ", Dec bPinNumber, " = ", Dec tPinState  ' Transmit the state as ASCII
            DelayMS 100                                 ' A small delay
        Next                                            ' Close the pin loop
    Loop                                                ' Do it forever

You can use the preprocessor and give the LoadBit and GetBit commands different names and formats to more suit your program's requirements. but they do the job nicely.

For a fixed constant as the bit number, a pre-processor meta-macro can be used to represent Variable.Constant Bit Number.

atomix

Yes, I know about LoadBit and GetBit commands, but that's not what I need.

For example, there is a library and the user declares a pin (necessarily as LAT) and it is used in the library.

$define pin_Lib LATC.4
or
Dim pin_Lib As LATC.4

But inside the library, it can be used to work with this pin as:
1) analog input (need to change the registers TRIS, ANSEL and use ANx channel)
2) digital input (need to change the registers TRIS, ANSEL and use PORT)
3) digital output (the fastest possible work)

Therefore, I need to convert the constant to the case I need:
  LATC.4 -> PORTC.4
  LATC.4 -> TRISC.4
  LATC.4 -> ANSELC.4

That is, I need to convert:
  XXXC.4 -> YYYC.4

top204

That is a very niche mechanism for very niche circumstances and a command could not be created for it because of the many differences in all of the devices on all of their SFRs. Imagine the logistics of it!

The principle can be performed with the pre-processor using its meta-macros. For example, the code listing below, for a PIC18F25K20 device, will also alter the ANSEL SFRs for a specific "PORT.Pin" or "LAT.Pin" or "TRIS.Pin":

'---------------------------------------------------------------
' Setup a collection of peripherals based upon a Port and Pin to use
' Input     : pPort holds the port for the peripheral
'           : pPinNum holds the pin number of the port
' Output    : None
' Notes     : Must use the Port and SFR names for parameters as in the device's .def files
'           : These have a preceding underscore to the name. i.e. _PORTA or _PORTB or _LATA etc...
'           : This is so the preprocessor knows what they are and can distinguish them
'           : This setup is for a PIC18Fx5K20 device family.
'
$define SetUp_Periph(pPort, pPinNum)                       '                        
    $if pPort = _PORTA Or pPort = _LATA Or pPort = _TRISA  '
        PORTA.pPinNum = 0                                  '
        TRISA.pPinNum = 1                                  '
        ANSEL = pPinNum.Byte0                              '
        ANSELH = pPinNum.Byte1                             '
    $elseif pPort = _PORTB Or pPort = _LATB Or pPort = _TRISB  '
        PORTB.pPinNum = 0                                  '
        TRISB.pPinNum = 1                                  '
        ANSEL = pPinNum.Byte0                              '
        ANSELH = pPinNum.Byte1                             '
    $elseif pPort = _PORTC Or pPort = _LATC Or pPort = _TRISC  '
        PORTC.pPinNum = 0                                  '
        TRISC.pPinNum = 1                                  '
        ANSEL = pPinNum.Byte0                              '
        ANSELH = pPinNum.Byte1                             '
    $elseif pPort = _PORTD Or pPort = _LATD Or pPort = _TRISD  '
        PORTD.pPinNum = 0                                  '
        TRISD.pPinNum = 1                                  '
        ANSEL = pPinNum.Byte0                              '
        ANSELH = pPinNum.Byte1                             '
    $endif

'-------------------------------------------------------------------------------------------------------
' The main program starts here
'
Main:
    SetUp_Periph(_PORTC, 3)

Note that not all ADC SFRs use a bit-wise mechanism, and a lot of them use a value and not a bit prepresenting a "Port.Pin". This changes from device to device. Some of the earlier devices and most of the 14-bit core devices do not even have that mechanism, and a fixed bunch of pins have to be set as analoque with the remaining pins set as digital.

So, again, the logistics of creating a niche command are astronomic in scale and would take months of doing nothing else except reading datasheets and making detailed information on "all" devices, old, present and new, and "all" SFRs on them, and writing routines for every single device!!! And some devices would simply not be suitable for it.

However, with a meta-macro, it can be changed depending on the device it is used for by the writer of the library or code it is used in.

atomix

Thanks for the detailed answer.

Or maybe then add regular expressions to the preprocessor - $regexp:

PRODH = PORT##$regexp(p, 1, "\w+?([a-z]\.\d)")    ' return matches[1] and converted by the compiler to  PRODH = PORTC.4
This can be used in many other cases, the preprocessor is sorely lacking in text modification functionality.

atomix

So far I've come up with this solution.

pin_reg.png

atomix

Les add an alias for the subroutine: __conv_pin_to_reg_bitmask_ => PinReg

So that it can be used for other uses.

Dim pn As Pin = Pin_C3

PinReg(pn)                        'call __conv_pin_to_reg_bitmask_
PRODH = WREG

For PRODL = 7 DownTo 0
    INDF0 = INDF0 ^ PRODH         'fast toggle pin
Next

atomix

So far I've come up with this solution #2.

Les: Comment on the post above

'----------------------------------------
$define PinRet
$define PinConv(P1,P2)                  '
    $defeval _PinE  $eval P1            '
    $defeval _PinP  $eval _PinE / 8    '
    $defeval _PinN  $eval _PinE & 7    '
    $if _PinP = 0                      '
        $defeval PinRet P2##A.##_PinN  '
    $endif                              '
    $if _PinP = 1                      '
        $defeval PinRet P2##B.##_PinN  '
    $endif                              '
    $if _PinP = 2                      '
        $defeval PinRet P2##C.##_PinN  '
    $endif                              '
    $if _PinP = 3                      '
        $defeval PinRet P2##D.##_PinN  '
    $endif                              '
    $if _PinP = 4                      '
        $defeval PinRet P2##E.##_PinN  '
    $endif                              '
    $if _PinP = 5                      '
        $defeval PinRet P2##F.##_PinN  '
    $endif

$define pinLib1    Pin_C3
$define pinLib2    Pin_D3

PinConv(pinLib1, PORT)  :  $defeval pn1 PinRet
PinConv(pinLib2, TRIS)  :  $defeval pn2 PinRet

PRODL.4 = pn1
PRODL.5 = pn2


top204

I will add an enabler for some of the newer library routines, such as "__conv_pin_to_reg_bitmask_". i.e. #Enable

However, nothing more will be added to the pre-processor. It works as standard preprocessors do, and I can see no reason to go into the code for hours and hours and make changes that could make it faulty, for a niche operation. :-)

That is why the IDEs have plugin mechanisms, so any changes to a program's listing can be performed by a plugin before the compiler and pre-processor see the standard code.


atomix

Thank you Les for all your work.

I will no longer suggest making changes to the preprocessor.

I'm just trying to make the Positron more advanced and make it easier to write code.