PDA

View Full Version : I2C and the MAX7318, need help with address space past $2E



ecoli-557
- 22nd August 2013, 22:26
Hello All-
The project is a 16x16 audio matrix switch in which I have to connect any 1 of 16 25v intercom masters with any of 16 25 volt speakers.
I am runniing it on a 18F2620 under PBP3 GOLD. I have a large motherboard with 16 'slots' and into each 'slot' I put a daughter card which contains a MAX7318 which is configured to be outputs and uses I2C.
I am writing to a MAX7318 port expander which looks like a good part in that it will allow up to 64 8 bit ports as either inputs or outputs. It uses a nift 3 pin address scheme in which you tie the 3 pins to +5, GND, SCL, or SDA to get to all of the addressses.
My code works well for the 1st 8 bit block ($20-$2E) but when I try to write to the next address block $30-$3E it does not work.
What DOES work is if I address my 8 cards to be $A0-$AE I can get to them and turn on relays.
Now for even more, the addressing in this space does not work out to be linear like it did with the $20. I have to address the cards to be in this order to be lionear (one after the other); $A0, $A8, $A4, $AC, $A2, $AA, $A6, $AE.
What is interesting is that I am off by $40 and if you look at the low order byte of the $Ax addresses, they look like the low order is backwards - Huh?

I have the work around to get the proper relays to fire with the proper inputs but what I don't understand is why do I have to do this?
Board design looks fine and I could not find any errata on the MAX part.

Code is cut and paste for the important parts:
#CONFIG
__CONFIG _CONFIG1H, _OSC_INTIO67_1H ;Osc=INT, Port on RA6,Port on RA7
__CONFIG _CONFIG2L, _PWRT_ON_2L & _BOREN_ON_2L & _BORV_1_2L
;Power Up Timer is ENABLED
;Brown Our Reset is ENABLED
;BOR is just under MAXIMUM (0)
__CONFIG _CONFIG2H, _WDT_OFF_2H ;Watchdog Timer is DISABLED
__CONFIG _CONFIG3H, _MCLRE_ON_3H & _PBADEN_OFF_3H ;MCLR pin 1 is now RESET

;PORTB A/D is DISABLED (digital on reset)
__CONFIG _CONFIG4L, _LVP_OFF_4L & _STVREN_ON_4L & _XINST_OFF_4L
;Low VOltage Programming OFF
;Stack Overflow is ENABLED
;Enhanced CPU is DISABLED
__CONFIG _CONFIG5L, _CP0_ON_5L & _CP1_ON_5L & _CP2_ON_5L & _CP3_ON_5L
;Code Protect Block 0, 1, 2, 3
#ENDCONFIG

'---------------------------------------------------------------------------------------
'Define the oscillator and setup the INCLUDE files
DEFINE OSC 8 '8 MHz oscillator, internal
INCLUDE "DT_INTS-18.bas" 'Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" 'Include if using PBP interrupts

'---------------------------------------------------------------------------------------
'OKAY, Lets set up the registers.....
T1CON = %00000000 'DISABLES timer1
INTCON = %11100000 'DISABLES INT0 pin
CMCON = %00000111 'Comparators are OFF
OSCCON = %01110000 'set register for 8mhz
ADCON0 = %00000000 'A2D is DISABLED
ADCON1 = %00001111 'All PORTA and PORTB bits are digital
'---------------------------------------------------------------------------------------
'Direction registers
'Direction Registers
TRISA = %11011000 'PORTA for bit3,4,6,7 as INPUTS, resr OUTPUTS
TRISB = %00111111 'PORTB for bits 7,6 as OUTPUTS, rest are INPUTS
TRISC = %11110111 'PORTC for bits 3 as OUTPUT, rest INPUTS
'----------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------
'Assembly routine for the heartbeat LED, serial input, all courtesy from the Man - D.T.!
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
; INT_Handler RX2_INT, _Get_char, PBP, yes
INT_Handler TMR0_INT, _ToggleHeartBeat, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
T0CON=%10000101 'TMR0 enabled, 16 bit mode, use CLK0 (internal)
'Low to High transition, use prescaler of 1:64
@ INT_ENABLE TMR0_INT ;enable Timer 0 interrupts
;@ INT_ENABLE RX2_INT ;Enable Serial port input interrupt
'--------------------------------------------------------------------------------------

'-----------------------------------------------------------------------------------------
'Additional I/O Definitions
error var PORTB.6 'ERROR output, ACTIVE HIGH (LED)
heart var PORTA.0 'Heartbeat to know we are online - ACTIVE HIGH
LED1 VAR PORTB.7 'Network/ err activity LED1, ACTIVE HIGH
LED2 VAR PORTA.5 'Network/ err activity LED2, ACTIVE HIGH
LED3 VAR PORTA.2 'Network/ err activity LED3, ACTIVE HIGH
LED4 VAR PORTA.1 'Network/ err activity LED4, ACTIVE HIGH
GO var PORTA.6 'This is the strobe to process the command from the 1220
' not used var PORTA.4
' not used var PORTB.4
All_Off var PORTC.1 'Turns OFF all relays
In_Audio var PORTC.6 'Indicated the device number is the audio SOURCE
Out_Audio var PORTC.7 'Indicated the device number is the audio OUTPUT (relay)
Broad var PORTC.0 'Sets up a broadcast, all OTHER outputs not input will turn ON
Reset var PORTC.5 'Clears the IN and OUT registers
' not used var PORTC.2
Act var PORTA.7 'Bit used for 1=OFF, 0=ON (low active)
idata var PORTC.4 'I2C data pin - put 4.7k pullup!
iclock var PORTC.3 'I2C clock pin - put 4.7k pullup!
'---following used for testing ONLY-----------------
TX_out var PORTB.5
RX_in var PORTA.3
define SER2_BITS 8
'------------------------------------------------------------------------------------------
in_port1 con 0 'INPUT port 1 register on MAX7318
in_port2 con 1 'INPUT port 1 register on MAX7318
out_port1 con 2 'OUTPUT port 1 register on MAX7318
out_port2 con 3 'OUTPUT port 2 register on MAX7318
inv_port1 con 4 'INVERT port 1 register on MAX7318
inv_port2 con 5 'INVERT port 2 register on MAX7318
confg_port1 con 6 'CONFIGURATION port 1 register on MAX7318
confg_port2 con 7 'CONFIGURATION port 2 register on MAX7318
'------------------------------------------------------------------------------------------
'Variable List
errcnt var byte 'Loop counter variable to hold the error LEDs on for a bit
ireg var byte 'Port register on the MAX 7318
DEV var byte 'This is the TEMP variable from the 1220
Rly var byte 'Variable for the RELAY on which to perform the action
Daughter var byte 'Variable which is the audio daughterboard
in_h var byte 'MSB of the MAX7318 for the relay
in_l var byte 'LSB of the MAX7318 for the relay
invar var byte 'Var which hold the INPUT audio source
outvar var byte 'Var which holds the relay out for the MAX7318
inport var word 'Var which holds the bit value for the output relay
outboard var byte 'Var which holds the I2C address of the requied output channel
My_Flags var byte 'Var which holds various flags
Cmd var My_Flags.0 'Command flag, 1 means we have already had a CLOCK

'---------------------------------------------------------------------------------------------
'Subroutines here

PortInit:
'Now set up all possible MAX7318s with both ports as OUTPUTS & turn OFF
'There can be a possible 16 MAX7318 port expanders.
'So, we need 16 address locations starting at$20
'I can set up the direction register with one command as it operates on the register called out
'The MAX7318s take up 2 address so, we need 32 addresses for up to 16 devices due to bit 0 being R/W
'in the address then it AUTOMATCALLY address the next register in the pair

for outboard=$20 to $3E step 2 'Counter to get all 16 devices
ireg=confg_port1
i2cwrite idata,iclock,outboard,ireg,[0,0],errled_I2C 'Set the config reg and make all bits OUTPUTS
ireg=out_port1
pause 10 'A pause that refreshes and gives the part to send an ACKNOWLEDGE
i2cwrite idata,iclock,outboard,ireg,[0,0],errled_I2C 'Ensure outputs are OFF (active HIGH)
pause 10 'A pause that refreshes and gives the part to send an ACKNOWLEDGE
next outboard
return

Lkup_in:
'This is where we resolve the needed relay out to an actual port address in low and high byte configuration.
'The high order byte is inverted due to a board layout mistake.
lookup2 invar,[0,1,2,4,8,16,32,64,128,32768,16384,8192,4096,2048, 1024,512,256],inport
in_h=inport.highbyte
in_l=inport.lowbyte
return

Lkup_out:
'This subroutine will look up the correct board address for the I2C communication
lookup outvar,[0,$20,$22,$24,$26,$28,$2A,$2C,$2E,$30,$38,$34,$3C, $32,$3A,$36,$3E],outboard
return
Ser_in:
'This subroutine is used to get data in as a debugging tool
serin2 rx_in, 84, [WAIT("$"),dec2 invar,dec2 outvar]
return

Ser_out:
'This subroutine is used to get data out to a terminal for debugging
serout2 tx_out, 84,["Input Source= ",dec2 invar, " Output board= ",dec2 outvar," Output addr= ",HEX2 outboard,$0D]
return

All_Rly_Off: for outboard=$20 to $3E step 2 'Counter to get all 16 devices
ireg=out_port1
i2cwrite idata,iclock,outboard,ireg,[0,0],errled_I2C 'Turn OFF all outputs
pause 10 'A pause that refreshes and gives the part to send an ACKNOWLEDGE
next outboard
return


Broadcast:
'This subroutine takes ONE input and broadcasts to the other outputs
gosub Lkup_in 'Get source of broadcast
outvar=invar 'Get the address of the source channel
gosub Lkup_out 'Get source board's address
ireg=2 'We want the output register
outvar=outboard 'Equate the originating address to var OUT
for outboard=$20 to $3E step 2 'Setup ALL 16 boards
if outvar=outboard then 'Check to make sure we don't broadcast to ourselves
i2cwrite idata,iclock,outboard,ireg,[0,0],errled_I2C 'If we are the source, Reset the outputs
else
i2cwrite idata,iclock,outboard,ireg,[in_h,in_l],errled_I2C 'Set the output
endif
pause 10 'A pause that refreshes and gives the part to send an ACKNOWLEDGE
next outboard 'Get the next output address
outboard=0 : outvar=0 'Clears the outboard var
return

Clearvar: invar=0 : outvar=0 : inport=0 : outboard=0
return

ErrLed:
'We get here when there has been an error
ErrLed_I2C: High error : high led1 'Indicates an I2C err
return

' The MAX 7318's are addressed such as:
'Board Number - BD1 BD2 BD3 BD4 BD5 BD6 BD7 BD8 BD9 BD10 BD11 BD12 BD13 BD14 BD15 BD16
'Board Addr space- 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E

'################################################# ############################################
'# Hookay Boyz, We are going to start this Pig!
'################################################# ############################################
init: invar=0 : outvar=0 'Sets vars to zero
gosub PortInit 'Sets up the port xpanders and turns OFF the outputs
low error : low led1 : low led2 : low led3 : low led4

'test: gosub ser_in
' if in=0 AND out=0 then
' gosub all_rly_off
' goto test
' endif
' if in<>0 AND out=0 then
' gosub Broadcast
' goto test
' endif
' gosub lkup_in
' gosub lkup_out
' ireg=2
' i2cwrite idata,iclock,outboard,ireg,[in_h,in_l],errled_I2C 'Set the outputs
' gosub ser_out
' goto test

Start:
dev=0
if cmd=1 and go=0 then goto start 'We are on the same command sequence, so wait for GO to go high
if cmd=1 and go=1 then cmd=0 'Go is inactive so reset the cmd bit
if go=0 then 'GO is LOW active
Cmd=1 'Set the bit to let us know we are on the SAME command sequence
' if Reset=0 then gosub Clearvar 'Go clear all the input and output registers
If all_off=0 then
gosub all_rly_off 'Turn OFF ALL relays
' serout2 tx_out, 84,["All Relays shut OFF",$0D,$0B,$0A]
goto start
endif
dev= (~PORTB) & %00011111 'INVERTS portB then stripsoff high 3 bits and save in var DEV
if In_Audio=0 then invar=dev 'Device points to audio INPUT
if out_audio=0 then outvar=dev 'Device points to relay on which to ACT
' serout2 tx_out, 84,["Device= ",dec2 dev," Broadcast= ", bin1 broad," All Off= ",bin1 all_off," In= ",bin1 in_audio," Out= ",bin1 out_audio, " Active= ", bin1 act," Invar= ",dec2 invar, " Outvar= ", dec2 outvar,$0D,$0B,$0A]
Broadcst: if invar <> 0 and outvar = 0 and broad = 0 then
gosub broadcast 'Go broadcast
outboard=0 : outvar=0 'Clears the outboard var
' serout2 tx_out, 84,["Broadcast Input Source= ",dec2 invar, " Output board= ",dec2 outvar,$0D,$0B,$0A]
goto start
endif
SingleON: if invar <> 0 AND outvar <> 0 and Act=0 then 'Check to see if we have set BOTH in and out and MODE=0
gosub lkup_in 'Go get the relay needed high and low byte
gosub lkup_out 'Go get the reqd board address
ireg=2 'We need the output1 register
' serout2 tx_out, 84,["Single Channel Input Source= ",dec2 invar, " Output board= ",dec2 outvar," Board Addr= ",hex2 outboard,$0D,$0B,$0A]
i2cwrite idata,iclock,outboard,ireg,[in_h,in_l],errled_I2C 'Set the outputs
gosub clearvar 'Clears vars for next operation
goto start
endif
SingleOFF: if invar =0 AND outvar <> 0 and Act=1 then 'Check to see if we have set BOTH in and out and MODE=0
gosub lkup_out 'Go get the reqd board address
ireg=2 'We need the output1 register
i2cwrite idata,iclock,outboard,ireg,[0,0],errled_I2C 'Reset the outputs
gosub clearvar 'Clears vars
goto start
endif
endif
goto Start

Any help would be appreciated but I cannot see where the problem is especially when the lookup table works for the 1st 8 cards!
I have searched this venerable forum but no one seems to have tried the Max part.

Ideas?

ecoli-557
- 22nd August 2013, 22:27
Sorry guys, I didn't submit in good form.....

ecoli-557
- 27th August 2013, 22:07
Found It!
I was somehow reversing the address bits from the sheet for the x30 address space! Sheesh was a moron!
The following works like a champ:
Lkup_out:
'This subroutine will look up the correct board address for the I2C communication
lookup outvar,[0,$20,$22,$24,$26,$28,$2A,$2C,$2E,$30,$32,$34,$36, $38,$3A,$3C,$3E],outboard
return