Tips and tricks (5)

Previous T&T

This trick does not deal with interrupts for a change!
The problem arose when I wanted to run two SPI driven modules (RTC and SDCard) from the same SPI port, using different Slave Select lines. While both modules where running perfectly using PORTB2, PORTB3, PORTB4 and PORTB5, respectively SS, MOSI, MISO and CLK.

The problem became even more confusing when I realised that each module taken individually could not be initialized while using an other PIN than PORTB2.

Thanks to the hints proposed by nkcelectronics’ post from Arduino forum, I solved this tricky problem. In fact, some SPI devices do not respect the pull up specifications, so that a LOW state exists while initializing the SPI port. Which corresponds to this firstly enigmatic line from the ATMEGA documentation:

If SS is configured as an input and is driven low while MSTR is set, MSTR will be cleared, and SPIF in SPSR will become set.”

An option for solving this problem is to set (Physically) the SS line HIGH. You can achieve that by setting the correponding PINxn as an input line in the Direction Data Register (DDRx) and driving externally this line HIGH, or by setting the SS PINn as an ouput line in the DDRx, and to set its level to HIGH prior to setting the SPI Control Register (SPCR) for enabling in master mode.

The code below is a minimalist approach to initializing SPI for any Chip Enable line, using the second option.

	// Input pin
	DDRB  &= ~(1 << _pin_miso); 
	// Ouput pins
	DDRB  |=  ((1 << _pin_def_cs) | (1 << _pin_cs) | (1 << _pin_mosi) | (1 << _pin_clock)); 
	// Set CS high before setting the SPI Control Register (SPCR) to Master mode
	PORTB  |=  (1 << _pin_def_cs);
	// Enable SPI as master
	SPCR |= ((1 << SPE) | (1 << MSTR)); 
	// Dummy read registers to clear previous results
	uint8_t clr;
	clr	= SPSR; 
	clr = SPDR;

Where _pin_def_cs is a constant which is set to PINB2. Then, this pin (PINB2) can be used at your convenience for anything else than SPI .

Next T&T

Leave a Reply

You must be logged in to post a comment.