Page 1 of 1

SetAllDigital() for J and K series with SE support

Posted: Tue Jun 07, 2011 6:45 pm
by Jerry Messina
Here's an updated version of SetAllDigital() with support for many of the J and K series parts and the SE compiler.

EDIT: check the SetDigitalIO wiki page for the latest version

I tried to cover some of the odd-ball ones like those that have non-access bank registers and parts that have shared overlaying register addresses, but the list is far from complete. I didn't really change the standard F series parts.

There are two new macros... read_sfr() and write_sfr() that should allow this to work with the SE compiler even for registers that are located outside of Bank 0. If you're using the SE compiler, set '#option SWORDFISH_SE = true', either in this file or before including it.

I did this as a separate module, but you could always incorporate it into utils.bas (where the current one resides)

SetDigitalIO.bas (edited from original):

Code: Select all

{
****************************************************************************
* Name    : SetAllDigital                                                  *
* Purpose : Switches device pins from analog to digital                    *
* Version : 1.6                                                            *
* Notes   :                                                                *
*         : 1.6 - change 18FxxK22 (rickado)                                *
*         :       correct 18F1230/1330 comparator setting                  *
*         : 1.5 - add 18F4xK22 (rickado)                                   *
*         : 1.4 - add write_sfr()/read_sfr() macros and add'tl devices     *
*         :       add #option SWORDFISH_SE                                 *
*         : 1.3 - add fix for ADSHR shared SFR registers (certain J series)*
*         : 1.2 - add 18FxxK20, K22, K50, K80, and K90 series              *
*         : 1.1 - add 18F46J50                                             *
****************************************************************************
}
module SetDigitalIO

// set this option true if building with the SE compiler
#option SWORDFISH_SE = false

//
// these macros are used to read and write SFR's that are located in the upper
// bank (bank 15), but are not part of the access bank
//
// since SE does not contain code to set the bank select register, setting
// #option SWORDFISH_SE true will enable the write_sfr()/read_sfr() macros to
// generate a MOVFF instruction so that setting the BSR is not required
//
public macro write_sfr(sfr, val)
  #if (SWORDFISH_SE)
    WREG = val
    asm
        movff wreg, sfr
    end asm
  #else
    sfr = val
  #endif
end macro

public macro read_sfr(sfr, bvar)
  #if (SWORDFISH_SE)
    asm
        movff sfr, bvar
    end asm
  #else
    bvar = sfr
  #endif
end macro

//
// set all analog IO pins to digital function
//
public sub SetAllDigital()

  dim ADSHR as WDTCON.4         // alternate register address bit present on certain devices

  // devices are grouped by datasheet where appropriate

  // 4 channels
  #if _device in (18F1230, 18F1330)
    ADCON1 = $00
    CMCON = $00         // changed V1.6

  // 5 channels, ANSEL...
  #elseif _device in (18F2331, 18F2431)
    ANSEL0 = $00

  // 9 channels, ANSEL...
  #elseif _device in (18F4331, 18F4431)
    ANSEL0 = $00
    ANSEL1.0 = 0

  // 7 channels, bit field...
  #elseif _device in (18F1220, 18F1320)
    ADCON1 = $7F

  // J10/J15 family...
  #elseif _device in (18F65J10, 18F65J15, 18F66J10, 18F66J15, 18F67J10, 18F85J10, 18F85J15, 18F86J10, 18F86J15, 18F87J10)
    ADCON1 = $0F
    CMCON = 0

  // J11 family...
  #elseif _device in (18F63J11, 18F64J11, 18F65J11, 18F83J11, 18F84J11, 18F85J11)
    ADCON1 = $0F
    CMCON = 0

  // J11 family... (shared SFR addresses)
  #elseif _device in (18F66J11, 18F67J11, 18F86J11, 18F87J11)
    // registers $0F5A - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J16 family... (shared SFR addresses)
  #elseif _device in (18F66J16, 18F86J16)
    // registers $0F5A - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J50 family... (shared SFR addresses)
  #elseif _device in (18F65J50, 18F66J50, 18F67J50, 18F85J50, 18F86J50, 18F87J50)
    // registers $0F40 - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J55 family... (shared SFR addresses)
  #elseif _device in (18F66J55, 18F86J55)
    // registers $0F40 - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J50 family...
  #elseif _device in (18F24J50, 18F25J50, 18F26J50, 18F44J50, 18F45J50, 18F46J50)
    // registers $0EC0 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $FF)
    write_sfr(ANCON1, $1F)
    CM1CON = 0
    CM2CON = 0

  // J53 family...
  #elseif _device in (18F26J53, 18F27J53, 18F46J53, 18F47J53)
    // registers $0EB0 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $FF)
    write_sfr(ANCON1, $1F)
    CM1CON = 0
    CM2CON = 0

  // 18FxxK20 family
  #elseif _device in (18F23K20, 18F24K20, 18F25K20, 18F26K20, 18F43K20, 18F44K20, 18F45K20, 18F46K20)
    ANSEL = $00
    ANSELH = $00
    CM1CON0 = 0
    CM2CON0 = 0

  // 18FxxK22 family
  // 18F1xK22
  #elseif _device in (18F13K22, 18F14K22)
    // registers $0F53 - $0F5F are not part of the access bank
    ANSEL = $00
    ANSELH = $00
    CM1CON0 = 0
    CM2CON0 = 0
    VREFCON1 = $00              // added V1.6

  // 18F2xK22/18F4xK22
  #elseif _device in (18F23K22, 18F24K22, 18F25K22, 18F26K22)
    // registers $0F38 - $0F5F are not part of the access bank
    write_sfr(ANSELA, $00)
    write_sfr(ANSELB, $00)
    write_sfr(ANSELC, $00)
    CM1CON0 = %00001000         // changed V1.6
    CM2CON0 = %00001000
    VREFCON1 = $00              // added V1.6

  #elseif _device in (18F43K22, 18F44K22, 18F45K22, 18F46K22)    // added V1.5
    // registers $0F38 - $0F5F are not part of the access bank
    write_sfr(ANSELA, $00)
    write_sfr(ANSELB, $00)
    write_sfr(ANSELC, $00)
    write_sfr(ANSELD, $00)
    write_sfr(ANSELE, $00)
    CM1CON0 = %00001000         // changed V1.6
    CM2CON0 = %00001000
    VREFCON1 = $00              // added V1.6

  // 18F87K22 family
  #elseif _device in (18F65K22, 18F66K22, 18F67K22, 18F85K22, 18F86K22, 18F87K22)
    // registers $0F16 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $00)
    write_sfr(ANCON1, $00)
    write_sfr(ANCON2, $00)
    CM1CON = 0
    CM2CON = 0
    CM3CON = 0
    CVRCON = $00                // added V1.6

  // 18FxxK50 family
  #elseif _device in (18F13K50, 18F14K50)
    // registers $0F53 - $0F5F are not part of the access bank
    ANSEL = $00
    ANSELH = $00
    CM1CON0 = 0
    CM2CON0 = 0

  // 18FxxK80 family
  #elseif _device in (18F25K80, 18F26K80, 18F45K80, 18F46K80, 18F65K80, 18F66K80)
    // registers $0E41 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $00)
    write_sfr(ANCON1, $00)
    write_sfr(CM1CON, $00)
    write_sfr(CM2CON, $00)

  // 18FxxK90 family
  #elseif _device in (18F65K90, 18F66K90, 18F67K90, 18F85K90, 18F86K90, 18F87K90)
    // registers $0EF4 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $00)
    write_sfr(ANCON1, $00)
    write_sfr(ANCON2, $00)
    write_sfr(CM1CON, $00)
    write_sfr(CM2CON, $00)
    write_sfr(CM3CON, $00)

  // 8 - 13 channels - 0 comp
  #elseif _comparator = 0
    ADCON1 = $0F

  // assume default is ok...
  #else
    ADCON1 = $0F
    CMCON = $07
  #endif
end sub

end module

I haven't tested all of the various chips, so beware. I did run a few of them through the simulator, though, to do a basic check.

Posted: Wed Jun 08, 2011 6:15 am
by ta1dr
Hi Jerry
thansk for share

Posted: Thu Jun 09, 2011 1:41 am
by Rickado
You missed me out :(


// 18F4xK22 family
#elseif _device in (18F43K22, 18F44K22, 18F45K22, 18F46K22)
// registers $0F38 - $0F5F are not part of the access bank
write_sfr(ANSELA, $00)
write_sfr(ANSELB, $00)
write_sfr(ANSELC, $00)
write_sfr(ANSELD, $00)
write_sfr(ANSELE, $00)

Posted: Thu Jun 09, 2011 10:35 am
by Jerry Messina
Thanks Rickado, I sure did.

I updated the original post to add those in (now v1.5).

I'm sure there's a lot more out there, too, so if anyone's got some (or any corrections), feel free to pipe up.

Posted: Fri Jun 10, 2011 2:12 am
by Rickado
In the Pic18F2x/4xk22 series
CMxCON0 => 0 has nothing to do with analog=> digital Input/output
I know this is not the case with all pics.
By default CMxCON0 = %00001000 =>comparator disabled
Putting bit3 (CxSP) => 0 puts the comparator in low power low speed mode when enabled. (CMxCON0.7=1)
:? if this is any advantage. May be a disadvantage.

In the Pic18F2x/4xk20 series CMxCON0 = %00000000 by default.

Posted: Fri Jun 10, 2011 12:27 pm
by Jerry Messina
In the Pic18F2x/4xk22 series
CMxCON0 => 0 has nothing to do with analog=> digital Input/output
It doesn't?
18.2.4 COMPARATOR OUTPUT
SELECTION
The output of the comparator can be monitored by
reading either the CxOUT bit of the CMxCON0 register
or the MCxOUT bit of the CM2CON1 register. In order
to make the output available for an external connection
,
the following conditions must be true:
CxOE bit of the CMxCON0 register must be set
• Corresponding TRIS bit must be cleared
CxON bit of the CMxCON0 register must be set
The way I read that, the comparator output overrides the PORT data, so to be sure the port function is ordinary digital IO you have to ensure the comparator is off. Does it work some other way?

In any case, setting it to the default (%00001000) is probably a better choice

Posted: Sat Jun 11, 2011 11:51 pm
by Rickado
With the PIC18(L)F2X/4XK22 series you'll also have to ensure the DACOE bit = 0.

22.6 DAC Voltage Reference Output
The DAC can be output to the DACOUT pin by setting
the DACOE bit of the VREFCON1 register to ‘1’.
Selecting the DAC reference voltage for output on the
DACOUT pin automatically overrides the digital output
buffer and digital input threshold detector functions of
that pin.

Posted: Tue Jun 14, 2011 4:08 am
by Rickado
Jerry (for the PIC18F2X/4XK22 series) you'll have to add

VREFCON.5 = 0 or VREFCON = 0

because if bit.5 = 1, it overrides digital output ie overrides the PORT data output.

See Section 22.6 DAC Voltage Reference Output of the K22 series datasheet.

Also For the 18F1230 and 18F1330 devices I see you have Enabled the comparators.
CMCON = $07 when by default they are disabled.

Is there a reason for this?

Posted: Tue Jun 14, 2011 9:46 am
by Jerry Messina
Thanks Rickado.

The K22 series certainly has a number of features that need taking care of! There are a number of parts that have a similar feature to the K22 "DAC" output, although it's usually called a Comparator Voltage Reference Module.
Also For the 18F1230 and 18F1330 devices I see you have Enabled the comparators.
CMCON = $07 when by default they are disabled.

Is there a reason for this?
You're right, on the F1230/F1330 CMCON should be set to $00. For the regular 'F' series parts, I just copied what was already in SetAllDigital() and didn't really verify what was existing.

This is a great example of why you really have to read the datasheet for each and every device, and can't trust just copying code. Microchip didn't make life easy if you tend to switch parts around a lot, that's for sure!

[original post edited to add changes]

Posted: Sun Sep 29, 2013 3:13 pm
by Jerry Messina
Here's an updated version of SetDigitalIO (V1.7) that has support for some new devices, such as the 2x/4xK50 and the J94/J99 series. This list should be current as of MPLAB V8.92

As always, if you notice anything out of whack, please point it out.

Code: Select all

{
****************************************************************************
* Name    : SetAllDigital                                                  *
* Purpose : Switches device pins from analog to digital                    *
* Version : 1.7                                                            *
* Notes   :                                                                *
*         : 1.7 - add 18F2xK50/4xK50                                       *
*         :       add J94/J99 series                                       *
*         :       add check for _IsCompilerSE define                       *
*         :       move ADSHR definition since not all devices have WDTCON  *
*         : 1.6 - change 18FxxK22 (rickado)                                *
*         :       correct 18F1230/1330 comparator setting                  *
*         : 1.5 - add 18F4xK22 (rickado)                                   *
*         : 1.4 - add write_sfr()/read_sfr() macros and add'tl devices     *
*         :       add #option SWORDFISH_SE                                 *
*         : 1.3 - add fix for ADSHR shared SFR registers (certain J series)*
*         : 1.2 - add 18FxxK20, K22, K50, K80, and K90 series              *
*         : 1.1 - add 18F46J50                                             *
****************************************************************************
}
Module SetDigitalIO

// set this option true if building with the SE compiler
#if defined(_IsCompilerSE) and (_IsCompilerSE = true)
  #option SWORDFISH_SE = true
#endif
#option SWORDFISH_SE = false

//
// these macros are used to read and write SFR's that are located in the upper
// bank (bank 15), but are not part of the access bank
//
// since the SE compiler does not contain code to set the bank select register, 
// setting #option SWORDFISH_SE true will enable the write_sfr()/read_sfr() macros
// to generate a MOVFF instruction so that setting the BSR is not required
//
Public Macro write_sfr(sfr, val)
  #if (SWORDFISH_SE)
    WREG = val
    Asm
        movff wreg, sfr
    End Asm
  #else
    sfr = val
  #endif
End Macro

Public Macro read_sfr(sfr, bvar)
  #if (SWORDFISH_SE)
    Asm
        movff sfr, bvar
    End Asm
  #else
    bvar = sfr
  #endif
End Macro

//
// set all analog IO pins to digital function
//
Public Sub SetAllDigital()
  // devices are grouped by datasheet where appropriate

  // 4 channels
  #if _device in (18F1230, 18F1330)
    ADCON1 = $00
    CMCON = $00         // changed V1.6

  // 5 channels, ANSEL...
  #elseif _device in (18F2331, 18F2431)
    ANSEL0 = $00

  // 9 channels, ANSEL...
  #elseif _device in (18F4331, 18F4431)
    ANSEL0 = $00
    ANSEL1.0 = 0

  // 7 channels, bit field...
  #elseif _device in (18F1220, 18F1320)
    ADCON1 = $7F

  // J10/J15 family...
  #elseif _device in (18F65J10, 18F65J15, 18F66J10, 18F66J15, 18F67J10, 18F85J10, 18F85J15, 18F86J10, 18F86J15, 18F87J10)
    ADCON1 = $0F
    CMCON = 0

  // J11 family...
  #elseif _device in (18F63J11, 18F64J11, 18F65J11, 18F83J11, 18F84J11, 18F85J11)
    ADCON1 = $0F
    CMCON = 0

  // J11 family... (shared SFR addresses)
  #elseif _device in (18F66J11, 18F67J11, 18F86J11, 18F87J11)
    Dim ADSHR As WDTCON.4         // alternate register address bit present on certain devices
    // registers $0F5A - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J16 family... (shared SFR addresses)
  #elseif _device in (18F66J16, 18F86J16)
    Dim ADSHR As WDTCON.4         // alternate register address bit present on certain devices
    // registers $0F5A - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J50 family... (shared SFR addresses)
  #elseif _device in (18F65J50, 18F66J50, 18F67J50, 18F85J50, 18F86J50, 18F87J50)
    Dim ADSHR As WDTCON.4         // alternate register address bit present on certain devices
    // registers $0F40 - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J55 family... (shared SFR addresses)
  #elseif _device in (18F66J55, 18F86J55)
    Dim ADSHR As WDTCON.4         // alternate register address bit present on certain devices
    // registers $0F40 - $0F5F are not part of the access bank
    ADSHR = 1
    ANCON0 = $FF
    ANCON1 = $FF
    ADSHR = 0
    CM1CON = 0
    CM2CON = 0

  // J50 family...
  #elseif _device in (18F24J50, 18F25J50, 18F26J50, 18F44J50, 18F45J50, 18F46J50)
    // registers $0EC0 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $FF)
    write_sfr(ANCON1, $1F)
    CM1CON = 0
    CM2CON = 0

  // J53 family...
  #elseif _device in (18F26J53, 18F27J53, 18F46J53, 18F47J53)
    // registers $0EB0 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $FF)
    write_sfr(ANCON1, $1F)
    CM1CON = 0
    CM2CON = 0

  // J94 family...       // added V1.7
  #elseif _device in (18F65J94, 18F66J94, 18F67J94, 18F85J94, 18F86J94, 18F87J94, 18F95J94, 18F96J94, 18F97J94)
    // registers $0DFA - $0F5F are not part of the access bank
    write_sfr(ANCON1, $00)
    write_sfr(ANCON2, $00)
    write_sfr(ANCON3, $00)
    write_sfr(CM1CON, 0)
    write_sfr(CM2CON, 0)
    write_sfr(CM3CON, 0)

  // J99 family...       // added V1.7
  #elseif _device in (18F66J99, 18F86J99, 18F96J99)
    // registers $0DFA - $0F5F are not part of the access bank
    write_sfr(ANCON1, $00)
    write_sfr(ANCON2, $00)
    write_sfr(ANCON3, $00)
    write_sfr(CM1CON, 0)
    write_sfr(CM2CON, 0)
    write_sfr(CM3CON, 0)

  // 18FxxK20 family
  #elseif _device in (18F23K20, 18F24K20, 18F25K20, 18F26K20, 18F43K20, 18F44K20, 18F45K20, 18F46K20)
    ANSEL = $00
    ANSELH = $00
    CM1CON0 = 0
    CM2CON0 = 0

  // 18FxxK22 family
  // 18F1xK22
  #elseif _device in (18F13K22, 18F14K22)
    // registers $0F53 - $0F5F are not part of the access bank
    ANSEL = $00
    ANSELH = $00
    CM1CON0 = 0
    CM2CON0 = 0
    VREFCON1 = $00              // added V1.6

  // 18F2xK22/18F4xK22
  #elseif _device in (18F23K22, 18F24K22, 18F25K22, 18F26K22)
    // registers $0F38 - $0F5F are not part of the access bank
    write_sfr(ANSELA, $00)
    write_sfr(ANSELB, $00)
    write_sfr(ANSELC, $00)
    CM1CON0 = %00001000         // changed V1.6
    CM2CON0 = %00001000
    VREFCON1 = $00              // added V1.6

  #elseif _device in (18F43K22, 18F44K22, 18F45K22, 18F46K22)    // added V1.5
    // registers $0F38 - $0F5F are not part of the access bank
    write_sfr(ANSELA, $00)
    write_sfr(ANSELB, $00)
    write_sfr(ANSELC, $00)
    write_sfr(ANSELD, $00)
    write_sfr(ANSELE, $00)
    CM1CON0 = %00001000         // changed V1.6
    CM2CON0 = %00001000
    VREFCON1 = $00              // added V1.6

  // 18F87K22 family
  #elseif _device in (18F65K22, 18F66K22, 18F67K22, 18F85K22, 18F86K22, 18F87K22)
    // registers $0F16 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $00)
    write_sfr(ANCON1, $00)
    write_sfr(ANCON2, $00)
    CM1CON = 0
    CM2CON = 0
    CM3CON = 0
    CVRCON = $00                // added V1.6

  // 18FxxK50 family
  #elseif _device in (18F13K50, 18F14K50)
    // registers $0F53 - $0F5F are not part of the access bank
    ANSEL = $00
    ANSELH = $00
    CM1CON0 = 0
    CM2CON0 = 0

  #elseif _device in (18F24K50, 18F25K50)       // added V1.7
    // registers $0F53 - $0F5F are not part of the access bank
    write_sfr(ANSELA, $00)
    write_sfr(ANSELB, $00)
    write_sfr(ANSELC, $00)
    CM1CON0 = 0
    CM2CON0 = 0

  #elseif _device in (18F45K50)                 // added V1.7
    // registers $0F53 - $0F5F are not part of the access bank
    write_sfr(ANSELA, $00)
    write_sfr(ANSELB, $00)
    write_sfr(ANSELC, $00)
    write_sfr(ANSELD, $00)
    write_sfr(ANSELE, $00)
    CM1CON0 = 0
    CM2CON0 = 0

  // 18FxxK80 family
  #elseif _device in (18F25K80, 18F26K80, 18F45K80, 18F46K80, 18F65K80, 18F66K80)
    // registers $0E41 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $00)
    write_sfr(ANCON1, $00)
    write_sfr(CM1CON, $00)
    write_sfr(CM2CON, $00)

  // 18FxxK90 family
  #elseif _device in (18F65K90, 18F66K90, 18F67K90, 18F85K90, 18F86K90, 18F87K90)
    // registers $0EF4 - $0F5F are not part of the access bank
    write_sfr(ANCON0, $00)
    write_sfr(ANCON1, $00)
    write_sfr(ANCON2, $00)
    write_sfr(CM1CON, $00)
    write_sfr(CM2CON, $00)
    write_sfr(CM3CON, $00)

  // 8 - 13 channels - 0 comp
  #elseif _comparator = 0
    ADCON1 = $0F

  // assume default is ok...
  #else
    ADCON1 = $0F
    CMCON = $07
  #endif
End Sub

End Module

Posted: Sun Sep 29, 2013 4:02 pm
by bitfogav
Thank you for the update Jerry.

Re: SetAllDigital() for J and K series with SE support

Posted: Sat Jan 25, 2014 2:24 pm
by Jerry Messina
Just an FYI -

I updated the SetDigitalIO wiki page with the code for V1.7 shown above

Re: SetAllDigital() for J and K series with SE support

Posted: Sun Apr 12, 2015 1:39 pm
by Jerry Messina
I added a setting for the K series devices with slew rate control, and changed them to default to normal rate (the chips power up in slow rate). Can be overridden via option.

SetDigitalIO V1.8 wiki page

Re: SetAllDigital() for J and K series with SE support

Posted: Sat Jun 17, 2017 1:48 pm
by Jerry Messina
I updated the SetDigitalIO wiki page with V2.3

I also added a simple example showing how to use the SetAllAnalog() and SetAnalogPort() routines

Version 2.3 changes:
- add support for 18LFxxK50 devices
- add missing 18LF4xK22 to analog pin definitions