SPI Implementation with A3BU

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,

 

I'm wondering if I can get input on my SPI code. I'm using an Xmega256A3BU

 

I've posted the code I have so far. I've used what I could find on this forum, in particular Torby's SPI code.

The test in the code is for the on-board SPIC to send a byte to SPID, and shine an LED if the number that SPID receives matches the original number.

 

#define F_CPU 2000000UL
#include <asf.h>
#include <util/delay.h>
#include <avr/io.h>

/****************************
SPI Pin Macros
****************************/

// #define SS		PIN4_bm
// #define MOSI	PIN5_bm
// #define MISO	PIN6_bm
// #define SCK		PIN7_bm

#define SS		4
#define MOSI	5
#define MISO	6
#define SCK		7

/*********************************
SPI Initialisation: Port C Master
**********************************/

void SPI_Master_Init(void) {

	PORTC_DIRCLR = (1<<MISO);
	PORTC_DIRSET = (1<<SCK) | (1<<MOSI) | (1<<SS);
	PORTC_OUTSET = (1<<SCK) | (1<<MOSI) | (1<<SS);
	SPIC_CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_PRESCALER_DIV64_gc | SPI_MODE0_bm;
}

/*********************************
SPI Initialisation: Port D Slave
**********************************/

void SPI_Slave_Init(void) {

	PORTD_DIRSET = (1<<MISO);
	PORTD_DIRCLR = (1<<SCK) | (1<<MOSI) | (1<<SS);
	PORTD_OUTCLR = (1<<SS);
	SPID_CTRL = SPI_ENABLE_bm;
}

/*********************************
SPI Data Transfer
**********************************/

uint8_t SPI_Data_Transfer(uint8_t data) {

	SPIC_DATA = data;
	while(!(SPIC_STATUS & SPI_IF_bm)){}
	return SPIC_DATA;
}

/*********************************
Main Function
**********************************/

int main (void)
{
	PORTR_DIRSET = PIN0_bm;			// Prepare LED0 as an output for successful SPI transfer
	board_init();

	SPI_Master_Init();
	SPI_Slave_Init();

	uint8_t Master_Data = 0x11;		// Test number for SPI exchange

	PORTC_OUTCLR = (1<<SS);
	_delay_ms(20);
	SPI_Data_Transfer(Master_Data);		// Send test number from SPIC to SPID
	_delay_ms(20);
	PORTC_OUTSET = (1<<SS);

	if (SPID_DATA == Master_Data) {		// Shine LED0 if slave-received number matches test number
		PORTR_OUTCLR = PIN0_bm;
	}

}

 

Really all help is appreciated. Thanks

Attachment(s): 

This topic has a solution.
Last Edited: Tue. Aug 8, 2017 - 01:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
	
_delay_ms(20);				// Wait for slave to receive number
	

Huh?  The Slave is done Rx'ing when the Master is done Tx'ing.

Greg Muth

Portland, OR, US

Xplained Boards mostly

Atmel Studio 7.0 on Windows 10

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh yes, that makes sense. Thank you.

 

On another note, the SPI data received is always 0x00.

I've read that this could be because the MISO pin is configured as an analog pin instead of digital, but for the AVR they appear to default as digital.

Does anyone have any experience with this? Even Atmel's example SPI code gave back zeros.

Last Edited: Sat. Aug 5, 2017 - 06:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

Still wondering if I can get some feedback.

I tried some example code that I found from this website, and modified it to fit the A3BU, but still receive zeros. There's a picture of my setup attached.

#include <avr/io.h>

int main(void)
{
	PORTR.DIRSET = PIN0_bm;
	uint8_t tx_byte;
	uint8_t rx_byte;
	
	/* Configure GPIO */
	PORTC.DIR = 0x40;          // MISO output; MOSI, SCK, SS inputs
	PORTD.DIR = 0xB0;          // MOSI, SCK, SS outputs; MISO input
	PORTD.OUTSET = 0x10;       // de-assert SS pin (active low)
	
	/* Configure SPI on PORTC and PORTD */
	SPIC.CTRL = 0x40;          // spi slave, spi mode 0
	SPID.CTRL = 0x50;          // spi master, spi mode 0
	
	/* Flush slave receive buffer */
	while(SPIC.STATUS & 0x80) {
		rx_byte = SPIC.DATA;   // flush spi receive buffer
	}
	
	/* Flush master receive buffer */
	while(SPID.STATUS & 0x80) {
		rx_byte = SPID.DATA;   // flush spi receive buffer
	}
	
	tx_byte = 0;
	SPIC.DATA = 0;
	while(1) {
		
		///// SPI Master operation /////
		PORTD.OUTCLR = 0x10;          // assert SS pin (active low)
		SPID.DATA = tx_byte + 1;      // increment received data and send (prior int flag auto cleared)
		while(!(SPID.STATUS & 0x80)); // wait for transmit complete
		PORTD.OUTSET = 0x10;          // de-assert SS pin
		
		tx_byte = SPID.DATA;          // store character received from slave (int flag auto cleared)
		////////////////////////////////
		
		////// SPI Slave operation /////
		rx_byte = SPIC.DATA;          // grab received byte
		SPIC.DATA = rx_byte;          // send back to the master
		////////////////////////////////
		
		if (rx_byte == 0) {           // shine LED if received byte is zero
			PORTR.OUTCLR = PIN0_bm;
		}
	}
}

 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
SPID.DATA = tx_byte + 1;      // increment received data and send (prior int flag auto cleared)

Some C guru will see it differently......but would this not send 1 always as tx_byte starts at 0 and not explicitly incremented? (ie tx_byte++ would increment and save tx_byte)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the message.

 

That might be right, but I'm not sure. I set tx_byte = 5 just to clear any doubt, and the result was the same.

Strange. I really don't know what I'm missing. The hardware looks okay and I've tried three separate code examples

Last Edited: Mon. Aug 7, 2017 - 05:51 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I have the same board but no time right now. If I get some time I will try the code.

 

One thing I would change would be to start with a printable char like 0x21 (! 33 decimal) and add a UART output so that you can print out the received data on a terminal, when the char reaches 0x7E (- 126 decimal) in tx_byte then it would wrap down to 0x21.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code in #1 looks fine to me. I am guessing that board_init() will turn off the LED.
I assume that you have connected all SPIC and SPID pins to the same bus.
.
I only have A1 and A4 xmegas. What board do you have?
Life is always easier if you have an LCD or Terminal to display human readable results but an LED is better than nothing.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

daisy148 wrote:
On another note, the SPI data received is always 0x00.
Could simply be that some mistake in the electronics means MISO is tied low.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
some mistake in the electronics means MISO is tied low.

So what does an oscilloscope (or logic analyser) show?

 

Failing that, can the pin be set high & low when using it just as a basic GPIO ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think I have the same board but no time right now. If I get some time I will try the code.

That would be great, thanks so much!

I only have A1 and A4 xmegas. What board do you have?

It's the Xmega256A3BU Xplained Eval. board

Could simply be that some mistake in the electronics means MISO is tied low.

Failing that, can the pin be set high & low when using it just as a basic GPIO ?

Ah! It's weird, but on SPID which is shared with the USART I can't set the pins high or low. I can for SPIC, but not SPID.

 

Last Edited: Mon. Aug 7, 2017 - 04:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I managed to get the SPIC working with a sensor. It reads the right ID. Thanks a lot for the help there.

Only thing is SPID. 

I haven't seen this before, but to set the ports (SS PD4, MOSI PD5, MISO PD6, SCK PD7), it's actually reversed.

This sets them so that I get a voltage on the pins

PORTD.DIRSET = 0b00001111;
PORTD.OUTSET = 0b00001111;

and then, setting the following command

SPID.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_PRESCALER_DIV64_gc | SPI_MODE_0_gc;

clears the voltage away

Last Edited: Mon. Aug 7, 2017 - 07:47 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

but to set the ports (SS PD4, MOSI PD5, MISO PD6, SCK PD7), it's actually reversed.

There is something strange happening there, both SPIs are on the top 4 bits of the ports,

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

...and if you had looked at the diagram for the board......

 

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I still don't quite get it.. has Port D been in Usart Master SPI mode? I took it for granted that it would default to normal SPI mode (with the pins of 4, 5, 6, and 7).

 

Edit: Ah, okay I think I got it. Port D seems to only works with Usart in master SPI mode, since the normal SPI is used for USB, and the chip pins don't match the header pins.

 

I got the a3bu to work with both Port C and Port D, woo. SPIC was pretty straight-forward, but SPID took initializing the Usart as MSPIM.

I've attached functional code for SPIC, and SPID.

 

Attachment(s): 

Last Edited: Tue. Aug 8, 2017 - 02:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Port D been in Usart Master SPI mode? I took it for granted that it would default to normal SPI mode

None of the above, the pins deafult to inputs at power up until you initiliase them.

 

Did you download and looked up XMEGA-A3BU_XPLAINED_Design_Documentation_rev2.PDF? Do you understand why " set the ports (SS PD4, MOSI PD5, MISO PD6, SCK PD7), it's actually reversed."

 

If I tell you then it will go in one eye and out the other, if you look up the above it is possible that something will stick between the eyes. wink

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm definitely seeing it now. That taught me not to necessarily think the chip pins match the header pins.

Again, thanks for originally pointing out the screenshot of the schematic. That led me to the solution.