I2C and SPI, which one to bash!

Thread Starter

geoffers

Joined Oct 25, 2010
488
Hi all,

Yet more questions I'm afraid! I'm trying to design a circuit at the moment, I would like to use ic's and modules attached to one pic that use I2C and SPI.

I will have 3 I2C chips and a SPI radio module running, I think I probably know the answer but its best to ask first I feel! Most pic's have the I2C and spi in one module, I would like to use the smallest pic I can, (8pin) but am gussing pull ups for I2C would mess up SPI coms?

The good news is I still have 4 io left if I use the I2C module. Has any bit bashed SPI or I2C? which might be easier? As I want to use 3 I2C devices I guess I will want to write a routine for the SPI (1 device) anyone know of any pitfalls or problems I might encounter?

Cheers Geoff
 

shteii01

Joined Feb 19, 2010
4,644
Is the same set of pins used for I2C and SPI?

I have worked with Arduino Due, it has one set of pins for I2C, second set of pins for SPI.
 

ErnieM

Joined Apr 24, 2011
8,377
You should have little trouble finding "soft" solutions for either bus, so pick the one that looks easier to you to implement in software and reserve the hardware for the other.

First time I did I2C was on a device that had no module. Happened to be a Basic Stamp, so there's one place to find examples.

One thing to state: most I2C code (for both soft and hard solutions) I've seen tend to ignore the ACK status bit tat informs you the transfer was successful.
 

JohnInTX

Joined Jun 26, 2012
4,787
Neither is particularly hard to do if you are coding the master talking to a slave but if you have to choose, use the hardware SSP module for I2C and bit-bang the SPI.

SPI master is easier to do in bit bang. Once the SPI slave is selected, just fire away with clock and data, receiving one byte for each you send.

I2C has port-direction changes (to detect ACK) and you must monitor SCL for stretches by the slave and be ready for unexpected NAKs etc.

As a slave, bit banging either is a pain. You can do it but either SPI or I2C would require careful programming probably using interrupts (for detecting SS/ for SPI / S-P for I2C) to keep things manageable.

One thing to state: most I2C code (for both soft and hard solutions) I've seen tend to ignore the ACK status bit tat informs you the transfer was successful.
I've seen that too and I'm not sure what they are doing. NAK is used for many things not the least of which is knowing you have actually addressed a particular slave and if its happy with the data transfer. Peevish of me, but those are useful things to know - its also I2C spec.

Just my own experiences - YMMV
 
Last edited:

ErnieM

Joined Apr 24, 2011
8,377
I2C has port-direction changes (to detect ACK) and you must monitor SCL for stretches by the slave and be ready for unexpected NAKs etc.
While a slave *may* pull the clock down to give itself some extra time to process info... nothing requires a slave to do such and most do not need this time.

If you are building the system you can pick parts that don't need this time, have one less thing to worry about, and skip the test in your code (like 2 or 3 extra statements were gonna kill you anyway).
 

Thread Starter

geoffers

Joined Oct 25, 2010
488
Thanks Guys, I've been looking at the data sheet and think I will bit bang the spi port:) Shall post my code when I get it sorted!
 

Markd77

Joined Sep 7, 2009
2,806
Some PICs don't support i2c master mode. Here's something I bashed together a while ago, I used it for storing in serial EEPROM, the project is unfinished, but this bit works on PIC16F819 (yes, the TRIS command still works):
Rich (BB code):
i2c_store_32_bytes
	bcf INTCON, GIE
	call i2c_start
	movlw b'10100000'		;control byte for write
	movwf i2c_buffer
	call i2c_sendbyte
	movlw b'00000000'		;address high byte
	movwf i2c_buffer
	call i2c_sendbyte
	movlw b'00000000'		;address low byte
	movwf i2c_buffer
	call i2c_sendbyte	
	
	movlw d'32'
	movwf d1
saveloop
	movf INDF, W
	movwf i2c_buffer
	call i2c_sendbyte
	incf FSR, F
	decfsz d1, F
	goto saveloop
	call i2c_stop
	return



i2c_start
	bsf PORTB, 2			;scl high
	call delay5us
bcf PORTB, 3
	movlw b'00000010'		;sda low
	TRIS PORTB
	call delay5us
	bcf PORTB, 2			;scl low
	return



i2c_stop
bcf PORTB, 3
	movlw b'00000010'		;sda low
	TRIS PORTB
	bsf PORTB, 2			;scl high
	call delay5us
	movlw b'00001010'		;sda high
	TRIS PORTB
	call delay5us			;??
	return

i2c_sendbit
	movlw b'00000010'		;assume 0 bit sda low
	btfsc i2c_buffer, 7
	movlw b'00001010'		;bit is 1 sda high
bcf PORTB, 3
	TRIS PORTB
	call delay5us
	bsf PORTB, 2			;scl high
	call delay5us
	bcf PORTB, 2			;scl low
	movlw b'00001010'		;release sda
	TRIS PORTB
	return

i2c_receivebit				;result in STATUS, C
	movlw b'00001010'		;bit is 1 sda high
	TRIS PORTB
	call delay5us
	bsf PORTB, 2			;scl high
	call delay5us
	bcf STATUS, C		;assume sda low
	btfsc PORTB, 3
	bsf STATUS, C		;sda high
	bcf PORTB, 2			;scl low
	return

i2c_send_ack				;result in STATUS, C
	movlw b'00000010'		;bit is 0 sda low
bcf PORTB, 3
	TRIS PORTB
	call delay5us
	bsf PORTB, 2			;scl high
	call delay5us
	bcf PORTB, 2			;scl low
	movlw b'00001010'		;release sda
	TRIS PORTB
	return



i2c_sendbyte
	movlw d'8'
	movwf count
i2c_sendbyte_loop
	call i2c_sendbit
	rlf i2c_buffer, F
	decfsz count, F
	goto i2c_sendbyte_loop

	call i2c_receivebit		;ack bit, ignore it
	return

i2c_receivebyte
	movlw d'8'
	movwf count
i2c_receivebyte_loop
	call i2c_receivebit			;result in STATUS, C
	rlf i2c_buffer, F			;move into buffer
	decfsz count, F
	goto i2c_receivebyte_loop
	btfsc flags, send_ack
	goto ack_send
	call i2c_receivebit		;ack bit, ignore it
	return
ack_send
	call i2c_send_ack
	return
 

ErnieM

Joined Apr 24, 2011
8,377
Some PICs don't support i2c master mode. Here's something I bashed together a while ago, I used it for storing in serial EEPROM, the project is unfinished, but this bit works on PIC16F819 (yes, the TRIS command still works):

It looks like some formatting got lost, I don't see any place where you control SDA and SCL with TRIS. (Is "TRIS PORTB" an undefined macro?)

TRIS is the only way to control these lines as you are simulating an open collector output. To do that you make the Port (or preferably the LATCH if available) a low, then use TRIS to set the pin as output (to pull it low) or as an input to let the resistors pull it high.

Driving either line high will be trouble for the slave when it tries to pull the line low.
 

Markd77

Joined Sep 7, 2009
2,806
I should have qualified it a bit, clock is on pin 3, data on pin 2. Because I was only using one master and I knew that the EEPROM wouldn't be doing any clock stretching I used only normal output on the clock pin, but the data pin uses TRIS to switch it between input and output low. The TRIS instruction (not a macro) continues to be included in a lot of PICs even though it isn't mentioned in the datasheet any more.
It's a lot faster to write:
movlw x
TRIS PORTB
than:
movlw x
banksel TRISB
movwf TRISB
banksel PORTA
 

WBahn

Joined Mar 31, 2012
30,062
Hi all,

Yet more questions I'm afraid! I'm trying to design a circuit at the moment, I would like to use ic's and modules attached to one pic that use I2C and SPI.

I will have 3 I2C chips and a SPI radio module running, I think I probably know the answer but its best to ask first I feel! Most pic's have the I2C and spi in one module, I would like to use the smallest pic I can, (8pin) but am gussing pull ups for I2C would mess up SPI coms?

The good news is I still have 4 io left if I use the I2C module. Has any bit bashed SPI or I2C? which might be easier? As I want to use 3 I2C devices I guess I will want to write a routine for the SPI (1 device) anyone know of any pitfalls or problems I might encounter?

Cheers Geoff
I haven't bit banged SPI but I have both bit-banged SPI master and slave and implemented them in digital logic in both FPGAs and on ASICs. Both are pretty straight forward. My feeling is that I2C would be a bit harder because it has to deel with collision detection and arbitration. They way it does it is pretty simple, but it still adds to the complexity somewhat.
 

ErnieM

Joined Apr 24, 2011
8,377
@Mark: Be that as it may you should never actively drive SCL or SDA high.

@WBahn: collision detection and arbitration are not issues in a single master system.
 

WBahn

Joined Mar 31, 2012
30,062
@Mark: Be that as it may you should never actively drive SCL or SDA high.

@WBahn: collision detection and arbitration are not issues in a single master system.
I guess I'm not seeing where it was specified that this was a single master system. For that matter, I didn't see where it was indicated that it was reasonable to assume that none of the devices would stretch the clock.

Since I haven't used I2C much, it may well be that something in the OP's description implies a constraint that makes these reasonable assumptions, but I don't see it.
 

djsfantasi

Joined Apr 11, 2010
9,163
I guess I'm not seeing where it was specified that this was a single master system. For that matter, I didn't see where it was indicated that it was reasonable to assume that none of the devices would stretch the clock.

Since I haven't used I2C much, it may well be that something in the OP's description implies a constraint that makes these reasonable assumptions, but I don't see it.
See post 10
 

WBahn

Joined Mar 31, 2012
30,062
Post 10 was not made by the op. <grin>

However, post 1 doesn't not indicate any other bus masters, just slaves requiring different buses.
Post #1 doesn't indicate any bus masters one way or another. Again, it's been well over a decade since I tinkered even briefly with I2C, so maybe this is an unreasonable reading, but when he says he has three chips that use I2C that we wants to connect to his PIC, couldn't one of those be a bus master that he has no control over?
 

WBahn

Joined Mar 31, 2012
30,062
I would like to use the smallest pic I can, (8pin) but am gussing pull ups for I2C would mess up SPI coms?
I don't see where using pullups on SPI pins would cause problems as long as the pullups are strong enough to get the line HI in time. And if you reconfigure the pins to drive active HI when the port is SPI, then the presence of pullup resistors will be largely immaterial.

If you did share port pins, how are you planning to do the context switching so that the other devices know when they can assert signals on the lines? With SPI this is easy, of course since you have explicit chip enable pins for each device. But with I2C how are you going to ensure that the bus activity when communicating with the SPI device won't be seen by one of the I2C devices as a message addressed to it?
 

ErnieM

Joined Apr 24, 2011
8,377
...when he says he has three chips that use I2C that we wants to connect to his PIC, couldn't one of those be a bus master that he has no control over?
While it is not completely impossible to do things that way it is extremely unlikely.

Masters on the bus tend to be microcontrollers, with a single controller you have a single master system.
 

JohnInTX

Joined Jun 26, 2012
4,787
But with I2C how are you going to ensure that the bus activity when communicating with the SPI device won't be seen by one of the I2C devices as a message addressed to it?
You can probably get away with it as long as any transitions on the shared SDA line are done only when SCL is low to avoid generating Start/stoP conditions on the I2C bus. The SPI bus and connected devices would have to use that clocking scheme. The connected I2C devices should ignore everything on the bus until Start is detected and an address is sent.

That said, sharing the bus is something to be done with care and attention paid to pullups etc. and plenty of testing in all modes. Keep in mind that not all I2C devices implement the complete I2C spec and may behave badly when things are not just so on the bus.

IMHO, it would be impractical or impossible to do a multi-master configuration with a composite I2C/SPI bus.
 

Thread Starter

geoffers

Joined Oct 25, 2010
488
I didn't expect so many response's to this!

Just to confirm a few things, I'm planning to have 3 slave I2C devices and one slave SPI, I'm still not sure how to go about it? Its going to take me a while to write a spi routine so if I think I can 'get away?!' with mixing things I might?

My main concern was the pull ups, I2C needs them spi doesn't. My inital plan was to use the mssp module on a 12f1822, configure it for I2C for the I2C stuff then reconfigure for spi when needed, if I do write a routine it will be for spi!

John, you said sharing the bus is possible if you make sure a transition on the sda/sci pin only occurs while scl/sck (they are shared to) is low. I've had a look at the data sheet and there a different clock options, change on rising/falling edge, if I have it on the falling edge would this avoid messing up any I2C stuff while using the mssp module for both?

Thanks for all the input, Geoff
 
Top