Multiple I2C masters on Bus

hamtech

Member
I have two separate 20X2 boards. One receives MSF and displays it on a LCD display in a serial mode only.
I have a second 20X2 board built before, that displays different time zones, reading the current time from a DS1307 chip and adding the time difference to the region it is currently displaying on a OLED display. The timezone clock works entirely using I2C.

What I would like to do, is use I2C from the MSF clock board to set the time every minute on the DS1307 residing on the second board (time zone) to keep it accurate, sharing the i2C bus, effectively using two I2C masters (but not at the same time of course). I intended to use to pull up inputs to each 20X2 chips as flags to signal the software when one board was writing to the I2C bus, so that no bus contention would take place. However on power up the SDA and SCL outputs on the MSF 20X2 chip are both low and when I connect them to the bus they drag it down and the time zone clock does not then work . There are pull up resistors on the IC2 bus on the TZ board and this works ok until I connect the MSF 20X2's SDA and SCL to the bus. When I do it stops the TZ clock .

Am I trying somehting that is not allowed or am I doing it wrong. I would like to write/read to the DS1307 from either 20X2 chip on the same bus, is this allowed?? Is there a way? I have worked out flagging oftware to stop both writing at the same time but I am stymied by the MSF 20X2 chip SDA and SCL be low and affecting the bus....

Any help much appreciated.
 
Last edited by a moderator:

Buzby

Senior Member
... I am stymied by the MSF 20X2 chip SDA and SCL be low and affecting the bus....
So am I.

It sounds like the MSF code is driving the lines low when not communicating, not leaving them floating like it should.
( Most I2C slaves will continue working with both lines low, but it's not recommended. )

Please post the MSF code and we'll have a look.

Cheers,

Buzby
 

inglewoodpete

Senior Member
Having two i2c masters is a fairly rare and often difficult configuration to use.

I suggest you configure one of the 20X2s as a slave so that you only have one master. You may need to use a handshake wire between the two 20X2s so that the slave can get promt attention from the master when it needs it. Alternatively, regularly the poll the slave 20X2 to determine when it needs attention.
 

hippy

Ex-Staff (retired)
The pulling down of SDA/SCL may be a result of however you are configuring the MSF 20X2. The SDA/SCL pins of the 20X2 should be input at reset by default so shouldn't affect the bus and issuing a HI2CSETUP command early on should ensure they are I2C bus compatible.

In theory it should be possible to have two or more PICAXE masters on the bus and as long as only one is communicating at a time it should work, and even if more than one communicates it should still be electrically safe.

Making the MSF 20X2 an I2C Slave and having the 'time zone' PICAXE read the DS1307 and the MSF 20X2 via I2C would be an elegant solution but two masters should also work with appropriate synchronisation.

I've never actually tried it though !
 

hamtech

Member
I am using code supplied by G6EJD which I have modfied to add secs but largely it is his code.

At the end the end of the code he writes to the RTC, I am not doing that and it is ignored, as it assumes only one board. Anyway see if the code helps understand what is happening. I have added 2 x 10K resistors tp plus 5v on the MSF board SDA and SCL lines and it is still showing low on SDA and SCL with out being connected to anything, ie. the pins are being driven low. The MSF clock is running OK though.

Thanks.

HT

Code:
' Using the PVR Electronics  MSF Receiver
' Output from receiver is inverted.

   ' ********************
   ' ***** Symbols *****
   ' ********************
   
  symbol LCD = c.3
   symbol BAUD = N2400
   symbol Line1 = 128
   symbol Line2 = 192
   symbol Line3 = 148
   symbol Line4 = 212
   symbol carrier_on = 1 ' input pin state for carrier on
   symbol carrier_off = 0 ' ditto off
   symbol bit_time = w0 '(b0 b1)
   symbol address = w0
   symbol parity_test = w0
   symbol temp_word = w1 '(b2 b3)
   symbol ADVal = w0
   symbol year = b4
   symbol month = b5
   symbol day = b6
   symbol dofw = b7
   symbol hours = b8
   symbol mins = b9
   symbol secs = b10
   symbol bitA = b11
   symbol bitB = b12
   symbol i = b13
   symbol tempL = b14
   symbol nbits = b14
   symbol tempH = b15
   symbol rt_sec = b16
   symbol rt_mins = b17
   symbol rt_hours = b18
   symbol rt_day = b19
   symbol rt_date = b20
   symbol rt_month = b21
   symbol rt_year = b22
   symbol parity = b23
   symbol rx_parity = b24
   symbol parity_result = b10
   symbol parity_flag = b25
   symbol bobsecs = b26
   symbol press_adjust = 180
   symbol samples = 10
   
   
  ' ***************************
   ' ***** Initialisation *****
   ' ***************************
   init:
   dirsB = 255 'setup Port-BG as outputs
   Pause 1000
   SerOut LCD, BAUD,(254,1) 'Clear LCD
   Pause 50 'Wait for screen to clear
   'bobsecs = 00
   
  ' *********************************
   ' *** Main loop - Display data ****
   ' *********************************
   
  main:
   gosub initialise ' all relevant variables
   
serout lcd, baud,(254,133,":",#bobsecs)
serout lcd, baud, (254,148, "Waiting for sync")
serout lcd, baud, (254,212, "  Bob's MSF Clock")
   wait_for_start:
   do
   gosub receive_sec0
   loop while bit_time <= 42
   ' Found SEC-00, denoted by start bit ~ 500mS
   bobsecs=bobsecs+1
   serout lcd, baud, (254,140, " In Sync")
   serout lcd, baud, (254,148,"                 ")
   gosub wait_for_data
   gosub read_year
   gosub read_month
   gosub read_day
   gosub read_dofw
   gosub read_hour
   gosub read_mins
   ' gosub display_pressure
   ' gosub display_humidity
   goto wait_for_start

   wait_for_data: ' Now skip 16-bits to get to bit-17 the start of the data for YEAR
   for i = 0 to 15
   gosub receive_sec
   next i
   return

   read_year:
   year = 0
   for i = 1 to 8
   year = year * 2
   gosub receive_sec
   year = year + bitA AND $3F
   next i
   BCDTOASCII year,tempH, tempL
   serout LCD,BAUD,(254,201,"-20",tempH, tempL)
   return

   read_month:
   month = 0
   for i = 1 to 5
   month = month * 2
   gosub receive_sec
   month = month + bitA AND $1F
   next i
   BCDTOASCII month,tempH, tempL
   serout LCD,BAUD,(254,198,"-",tempH, tempL)
   return
   
  read_day:
   day = 0
   for i = 1 to 6
   day = day * 2
   gosub receive_sec
   day = day + bitA AND $3F
   next i
   BCDTOASCII day,tempH, tempL
   serout LCD,BAUD,(254,196,tempH, tempL)
   return
   
  read_dofw:
   dofw = 0
   for i = 1 to 3
   dofw = dofw * 2
   gosub receive_sec
   dofw = dofw + bitA AND $07
   next i
   serout LCD,BAUD,(254,192)
   if dofw = $00 then serout LCD,BAUD,("Sun") endif
   if dofw = $01 then serout LCD,BAUD,("Mon") endif
   if dofw = $02 then serout LCD,BAUD,("Tue") endif
   if dofw = $03 then serout LCD,BAUD,("Wed") endif
   if dofw = $04 then serout LCD,BAUD,("Thu") endif
   if dofw = $05 then serout LCD,BAUD,("Fri") endif
   if dofw = $06 then serout LCD,BAUD,("Sat") endif
   serout LCD,BAUD,(254,128)
   return

   read_hour:
   hours = 0
   for i = 1 to 6
   hours = hours * 2
   gosub receive_sec
   hours = hours + bitA
   next i
   return

   read_mins:
   mins = 0
   for i = 1 to 7
   mins = mins * 2
   gosub receive_sec
   mins = mins + bitA
   next i
   parity = 0
   ' Now receive bits 52(1), 53(2), 54(3), 55(4), 56(5), 57(6), 58(7) and 59(8)
   gosub receive_sec 'Skip BIT-52B
   gosub receive_sec 'Skip BIT-53B
   gosub receive_sec 'Get BIT-54B
   parity = parity OR bitB
   parity = parity * 2 ' shift parity bit in to parity word
   gosub receive_sec 'Get BIT-55B
   parity = parity OR bitB
   parity = parity * 2' shift parity bit in to parity word
   gosub receive_sec 'Get BIT-56B
   parity = parity OR bitB
   parity = parity * 2' shift parity bit in to parity word
   gosub receive_sec 'Get BIT-57B
   parity = parity OR bitB ' no shift neded for LSB bit in to parity word
   'serout LCD,BAUD,("PB=",#parity)
   ' Parity variable now has the 4 parity bits in the lower nibble.
   gosub receive_sec 'Get BIT-58B 
  gosub receive_sec 'Get BIT-59B
   gosub read_RTC
   if hours <= $23 AND mins <= $59 AND parity_flag <> "*" then
   rx_parity = parity / 8 AND $01
   parity_test = year
   gosub test_parity
   if parity_result = 1 then 'result is ODD
   rx_parity = parity / 4 AND $01 ' Move the year parity bit down
   parity_test = month * 256 + day
   gosub test_parity
   if parity_result = 1 then 'result is ODD
   rx_parity = parity / 2 AND $01
   parity_test = dofw
   gosub test_parity
   if parity_result = 1 then
   rx_parity = parity AND $01
   parity_test = hours * 256 + mins
   gosub test_parity
   if parity_result = 1 then
   if hours = rt_hours AND mins = rt_mins then
   gosub write_RTC
   rx_parity = "*" ' Indicates all tests passed, RTC was updated
   parity_flag = "*" ' Indicate on display that time was received correctly
   endif
   else
   rx_parity = "i" ' Indicates all test passed but not yet on a 30-min boundary e.g. 00, 30 etc
   endif
   endif
   endif 
  endif
   endif
   if rx_parity <> "*" AND rx_parity <> "i" then
   rx_parity = "!"
   endif
   rx_parity = mins // 05 'Only allow time to be updated if on a 5-min boundary
   if rx_parity = 0 then
   parity_flag = "!"
   endif
   BCDTOASCII hours,tempH,tempL
   serout LCD,BAUD,(254,128,tempH,tempL,":")
   BCDTOASCII mins, tempH,tempL
   serout LCD,BAUD,(tempH,tempL)
   'gosub display_RTC
   return
   
  display_RTC:
   gosub read_RTC
   BCDTOASCII rt_hours, tempH, tempL
   serout LCD,BAUD,(254,140,tempH, tempL,":")
   BCDTOASCII rt_mins, tempH, tempL
   serout LCD,BAUD,(tempH, tempL,"Hr",parity_flag,254,128)
   return

   test_parity:
   nbits = 0
   for i = 1 to 16
   parity_result = parity_test AND %00000001
   if parity_result = 1 then
   nbits = nbits + 1
   endif
   parity_test = parity_test / 2
   next i
   parity_result = nbits + rx_parity AND $01
   return

   receive_sec0:
   bitA = 0
   bitB = 0
   if pinc.0 = carrier_off then goto receive_sec0
   bit_time = 0
   do
   pause 8 ' Ideally 10 but 8 takes account instruction delays, determined by a test of this section.
   bit_time = bit_time + 1
   loop while pinc.0 = carrier_on
   gosub Flash_LED
   return
   
  receive_sec:
   serout lcd, baud,(254,133,":",#bobsecs)
   if pinc.0 = carrier_off then goto receive_sec
   Pause 160
   bitA = pinc.0 & $01
   Pause 100
   bitB = pinc.0 & $01
   gosub Flash_LED
   'gosub display_RTC
   Pause 275
   serout lcd, baud,(254,133,":",#bobsecs)
   inc bobsecs
   if bobsecs = 60 then let bobsecs = 0
   serout lcd, baud,(254,133,":0 ")
   end if

   return
   
  initialise:
   year = 0
   month = 0
   day = 0
   dofw = 0
   hours = 0
   mins = 0 
  parity_flag = "!"
   SerOut LCD,BAUD,(254,1)
   Pause 400
   return
   '
   ' END initialise
   
  Flash_LED:
   High b.2
   Pause 40
   Low b.2
   Return

   write_RTC:
   ' Time has to be sent in BCD format to the clock
   i2cslave %11010000, i2cslow, i2cbyte
   'Format is 'secs,mins,hours,day, date,month,year, control - control byte is $10
   rt_sec = 0
   writei2c 0, (00,mins,hours,rt_day,rt_date,rt_month,rt_year,$10)
   return
   
  read_RTC:
   ' Format is secs,mins,hours,day,date,month,year
   i2cslave %11010000, i2cslow, i2cbyte
   readi2c 0, (rt_sec,rt_mins,rt_hours) ',rt_day,rt_date,rt_month,rt_year)
   return
   
  ' END OF PROGRAMME
 

oracacle

Senior Member
so if i read it right you want the MSF to re-write the rtc every minuite and then the other 20x2 to take the time do some maths with it and display the results, could you not just right to the second 20x2 when you write the the rtc then ask the the second 20x2 to get its info from the scratch pad.

providing you write the rtc first to keep that accurate the time delay between the msf writing the rtc and the 20x2 will pretty small and most likely unoticable.
 

Buzby

Senior Member
Code:
init:
   dirsB = 255 'setup Port-BG as outputs
This is setting all pins on port B to outputs, which drives them to 0v.

Pins 7 and 5 of port B are the SCL and SDA.

Either replace the 255 with the correct value to leave pins 7 and 5 as inputs, or better still, recode to use hi2c comms.
 

hamtech

Member
Hi Buzby

Thanks for your interest in my problem.

Not quite sure how I would do that using hi2c comms , would be prerable if only I knew how, can you give me a steer on what you mean please.
 

hamtech

Member
Removing the DIRSB 255 has got rid of the low on the SDA and SCL pins of the 20X2. I wil press on , thank you all for your valuable help.

HT
 

Buzby

Senior Member
Download a program like this,

Do
Pause 1000
Loop

This will leave all the pins at inputs.

Then check the SDA/SDC lines again, they should both be high due to the pullup resistors.

EDIT : Sorry, I misread your post. I thought it said 'not got rid of the low'
 

hippy

Ex-Staff (retired)
Just move the "i2cslave %11010000, i2cslow, i2cbyte" to the top of the program, or use the equivalent "hi2csetup i2cmaster, %11010000, i2cslow, i2cbyte".

This will turn on I2C comms ready for when you use that, and unaffected by other commands that would otherwise affect the SDA and SCL pins.
 
Top