DaveC3
- 9th May 2008, 15:40
I have seen some questions about using a port expanders, here is a version that works for the MCP23017, I am using MicroChip's USB boot loader. This program simply sets the 23017's PortA as inputs and PortB as outputs (driving LEDs). It also send the PortA value to the PC via USB.
define LOADER_USED 1 ' USB Boot loader
define RESET_ORG 800h
define INTERRUPT_ORG 808h
DEFINE OSC 48
DEFINE I2C_SCL PORTA,1
DEFINE I2C_SDA PORTA,0
Define I2C_SLOW 1 'At this clock speed this needed to be added to make it work.
'define SHIFT_PAUSEUS 200
ADCON1 = $F 'port A digital
CMCON = 7 'PortA Digital
USBBufferSizeMax con 16 ' maximum buffer size
USBBufferSizeTX con 16 ' input
USBBufferSizeRX con 16 ' output
' the USB buffer...
USBBuffer Var Byte[USBBufferSizeMax]
USBBufferOut Var Byte[USBBufferSizeMax]
USBBufferCount Var Byte
Addr var byte
j var byte
i var byte
'================================================= =====================================
' Port A Registers (8 Bit Mode)
IODIRA con $00 ' Direction Bit Control Reg
IOBITSA con %11111111 ' Direction Bit Settings Reg (0 = output, 1 = input)
IPOLA con $01 ' Interrupt Polarity Control Reg
GPINTENA con $02 'Interrupt Enable Reg
DEFVALA con $03
INTCONA con $04
IOCONA con $05 ' I/O Configuration Reg
IOCONSETA con %10111000 ' IOCON register setting
GPPUA con $06 ' Pull-Up Control Reg
INTFA con $07 ' Interrupt Flag Register
INTCAPA con $08
GPIOA con $09 ' General Purpose I/O
IOLATA con $0A ' Output Latch Reg
'Port B Registers (8 Bit Mode)
IODIRB con $10 ' Port B Direction Bit Control Address
IOBITSB con %00000000 ' Port B Direction Bit Settings (0 = output, 1 = input)
IPOLB con $11 ' Interrupt Polarity Control
GPINTENB con $12 ' Interrupt Enable Reg
DEFVALB con $13
INTCONB con $14
IOCONB con $15 ' I/O Configuration Reg
IOCONSETB con %10111000 ' IOCON register setting
GPPUB con $16 ' Pull-Up Control Reg
INTFB con $17 ' Interrupt Flag Register
INTPOLB con $18
GPIOB con $19 ' General Purpose I/O Reg
IOLATB con $1A ' Output Latch Reg
'================================================= =======================================
' Port A Reguisters (16 Bit Mode)
IODIRA16 con $00
IODIRB16 con $01
IOCONA16 con $0A
IOCONB16 con $0B
GPIOA16 con $12
GPIOB16 con $13
OLATA16 con $14
OLATB16 con $15
IO_EXP0WR con $4E ' MCP23017 Write
IO_EXP0RD con $4F ' MCP23017 Read
IO_DAT var byte ' MCP23017 Data read
IO_DAT_OLD var byte
Out_Dat var byte
' Interrupt definition
' ====================
' USB interrupt used to keep USB connection alive
INCLUDE "DT_INTS-18.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP interrupts
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler USB_INT, _DoUSBService, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
usbinit ' initialise USB...
USBService ' keep connection alive
UIE = $7F
UEIE = $9F
@ INT_ENABLE USB_INT
gosub InitMPC23017
gosub ReInitPortA
goto Programstart
' ************************************************** **********
' * Sub-routines *
' ************************************************** **********
DoUSBService: 'Keeps USB alive
usbservice
@ INT_RETURN
' ************************************************** **********
' * receive data from the USB bus *
' ************************************************** **********
DoUSBIn:
USBBufferCount = USBBufferSizeRX ' RX buffer size
'USBService ' keep connection alive
USBIn 1, USBBuffer, USBBufferCount, DoUSBIn ' read data, if available
return
' ************************************************** **********
' * wait for USB interface to attach *
' ************************************************** **********
DoUSBOut:
USBBufferCount = USBBufferSizeTX ' TX buffer size
'USBService ' keep connection alive
USBOut 1, USBBufferout, USBBufferCount, DoUSBOut ' if bus available, transmit data
return
InitMPC23017:
Pause 100
'############# PORTA
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$0] 'PortA inputs
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOLATA,$FF] 'PortA = 0
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IPOLA,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[DEFVALA,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF] 'pull-ups enabled
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[INTCONA,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPINTENA,$FF] 'interupt on change
'############## PORTB
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOCONB,IOCONSETB]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IODIRB,0]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOLATB,$FF]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IPOLB,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[DEFVALB,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[INTCONB,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPINTENB,0]
return
ReInitPortA:
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$FF]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF] 'pull-ups enabled
return
' ************************************************** **********
' * main program loop - remember, you must keep the USB *
' * connection alive with a call to USBService every couple *
' * of milliseconds or so... *
ProgramStart:
'gosub DoUSBIn
'gosub DoUSBOut
i2cwrite PortA.0,PortA.1,IO_EXP0wr,[gpioa]
i2cread PortA.0,PortA.1,IO_EXP0rd,[IO_dat]
if IO_DAT_OLD != io_dat then
'''' usbbufferout(0) = io_dat
for j = 0 to 15
usbbufferout(j) = io_dat
next j
gosub dousbout
out_dat = io_dat
io_dat_old = io_dat
endif
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[gpioB,out_dat]
PAUSE 250
''i2cwrite PortA.0,PortA.1,IO_EXP0WR,[gpioB,0]
''PAUSE 250
goto ProgramStart
end
Thanks
Dave
define LOADER_USED 1 ' USB Boot loader
define RESET_ORG 800h
define INTERRUPT_ORG 808h
DEFINE OSC 48
DEFINE I2C_SCL PORTA,1
DEFINE I2C_SDA PORTA,0
Define I2C_SLOW 1 'At this clock speed this needed to be added to make it work.
'define SHIFT_PAUSEUS 200
ADCON1 = $F 'port A digital
CMCON = 7 'PortA Digital
USBBufferSizeMax con 16 ' maximum buffer size
USBBufferSizeTX con 16 ' input
USBBufferSizeRX con 16 ' output
' the USB buffer...
USBBuffer Var Byte[USBBufferSizeMax]
USBBufferOut Var Byte[USBBufferSizeMax]
USBBufferCount Var Byte
Addr var byte
j var byte
i var byte
'================================================= =====================================
' Port A Registers (8 Bit Mode)
IODIRA con $00 ' Direction Bit Control Reg
IOBITSA con %11111111 ' Direction Bit Settings Reg (0 = output, 1 = input)
IPOLA con $01 ' Interrupt Polarity Control Reg
GPINTENA con $02 'Interrupt Enable Reg
DEFVALA con $03
INTCONA con $04
IOCONA con $05 ' I/O Configuration Reg
IOCONSETA con %10111000 ' IOCON register setting
GPPUA con $06 ' Pull-Up Control Reg
INTFA con $07 ' Interrupt Flag Register
INTCAPA con $08
GPIOA con $09 ' General Purpose I/O
IOLATA con $0A ' Output Latch Reg
'Port B Registers (8 Bit Mode)
IODIRB con $10 ' Port B Direction Bit Control Address
IOBITSB con %00000000 ' Port B Direction Bit Settings (0 = output, 1 = input)
IPOLB con $11 ' Interrupt Polarity Control
GPINTENB con $12 ' Interrupt Enable Reg
DEFVALB con $13
INTCONB con $14
IOCONB con $15 ' I/O Configuration Reg
IOCONSETB con %10111000 ' IOCON register setting
GPPUB con $16 ' Pull-Up Control Reg
INTFB con $17 ' Interrupt Flag Register
INTPOLB con $18
GPIOB con $19 ' General Purpose I/O Reg
IOLATB con $1A ' Output Latch Reg
'================================================= =======================================
' Port A Reguisters (16 Bit Mode)
IODIRA16 con $00
IODIRB16 con $01
IOCONA16 con $0A
IOCONB16 con $0B
GPIOA16 con $12
GPIOB16 con $13
OLATA16 con $14
OLATB16 con $15
IO_EXP0WR con $4E ' MCP23017 Write
IO_EXP0RD con $4F ' MCP23017 Read
IO_DAT var byte ' MCP23017 Data read
IO_DAT_OLD var byte
Out_Dat var byte
' Interrupt definition
' ====================
' USB interrupt used to keep USB connection alive
INCLUDE "DT_INTS-18.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP interrupts
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler USB_INT, _DoUSBService, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
usbinit ' initialise USB...
USBService ' keep connection alive
UIE = $7F
UEIE = $9F
@ INT_ENABLE USB_INT
gosub InitMPC23017
gosub ReInitPortA
goto Programstart
' ************************************************** **********
' * Sub-routines *
' ************************************************** **********
DoUSBService: 'Keeps USB alive
usbservice
@ INT_RETURN
' ************************************************** **********
' * receive data from the USB bus *
' ************************************************** **********
DoUSBIn:
USBBufferCount = USBBufferSizeRX ' RX buffer size
'USBService ' keep connection alive
USBIn 1, USBBuffer, USBBufferCount, DoUSBIn ' read data, if available
return
' ************************************************** **********
' * wait for USB interface to attach *
' ************************************************** **********
DoUSBOut:
USBBufferCount = USBBufferSizeTX ' TX buffer size
'USBService ' keep connection alive
USBOut 1, USBBufferout, USBBufferCount, DoUSBOut ' if bus available, transmit data
return
InitMPC23017:
Pause 100
'############# PORTA
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$0] 'PortA inputs
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOLATA,$FF] 'PortA = 0
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IPOLA,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[DEFVALA,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF] 'pull-ups enabled
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[INTCONA,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPINTENA,$FF] 'interupt on change
'############## PORTB
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOCONB,IOCONSETB]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IODIRB,0]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOLATB,$FF]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IPOLB,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[DEFVALB,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[INTCONB,0]
'i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPINTENB,0]
return
ReInitPortA:
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IOCONA,IOCONSETA]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[IODIRA,$FF]
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[GPPUA,$FF] 'pull-ups enabled
return
' ************************************************** **********
' * main program loop - remember, you must keep the USB *
' * connection alive with a call to USBService every couple *
' * of milliseconds or so... *
ProgramStart:
'gosub DoUSBIn
'gosub DoUSBOut
i2cwrite PortA.0,PortA.1,IO_EXP0wr,[gpioa]
i2cread PortA.0,PortA.1,IO_EXP0rd,[IO_dat]
if IO_DAT_OLD != io_dat then
'''' usbbufferout(0) = io_dat
for j = 0 to 15
usbbufferout(j) = io_dat
next j
gosub dousbout
out_dat = io_dat
io_dat_old = io_dat
endif
i2cwrite PortA.0,PortA.1,IO_EXP0WR,[gpioB,out_dat]
PAUSE 250
''i2cwrite PortA.0,PortA.1,IO_EXP0WR,[gpioB,0]
''PAUSE 250
goto ProgramStart
end
Thanks
Dave