// SPI_On_Uno_Example.ino /// Send a short message over SPI as master or slave on AVR-based Arduino. /// /// Note: This program does not use the Arduino library. The Arduino library /// does not support SPI slave mode on AVR processors. For simplicity, we use the /// hardware registers for both. /// /// When the sketch starts, it prompts the user, using the console, to select /// master or slave. /// /// When the user selects master, the sketch sets the _SS low. /// Then it sends a series of bytes. It's a message that identifies itself /// as an Arduino AVR master. When it's done, it displays the /// byte that it has received from the slave. /// /// When the user selects slave, the sketch will start polling /// for a message from the master. As it receives each, it sends /// out a byte of its message, identifying itself as an AVR slave. /// /// The loop in the slave mode both waits for incoming bytes /// and checks for a transition on _SS from LOW to HIGH. /// That signals an end of transmission. The sketch then /// dumps the bytes it has received from the master. /// /// Pins /// The SPI hardware on the AVR chip is connected to these ICSP pins. /// On the Uno, these pins are also connected to D11, D12, D13. /// /// The ICSP connector is used in all models of Ardunio for SPI. /// /// ICSP pins: /// 1 MISO 2 +VCC /// 3 SCK 4 MOSI /// 5 Reset 6 GND /// /// The _SS line is pin D10 /// /// AVR registers for SPI /// /// AVR processors have 3 registers for SPI. They are known by /// symbols SPCR, SPSR and SPDR /// /// SPCR SPI control registers. /// A program writes to the SPCR to control the SPI. /// Each bit has a special use. Some set parameters for /// data order, clock polarity and phase and clock rate. /// Other bits are to enable the SPI, enable SPI interrupts /// and to set the mode of operation as master or slave. /// /// SPSR SPI status register /// Only one bit is of interest to us, SPIF, the SPI interrupt flag. /// It is set when a transfer is complete. /// /// SPDR SPI data register /// A program writes to this register to load the SPI hardware with a byte to /// transfer. A program reads from this register to retrieve a byte from the /// SPI transfer. /// #define _SS 10 #define BUFFER_SIZE 32 uint8_t masterMessage[BUFFER_SIZE+1] = "|--- Message from master Uno --|"; uint8_t slaveMessage[BUFFER_SIZE+1] = "|--- Message from slave Uno --|"; uint8_t inputBuffer[BUFFER_SIZE]; uint16_t inputBufferCounter; uint16_t outputBufferCounter; bool transmissionActiveFlag; /// true during a transmission bool slaveEnabledFlag; /// true when user has started slave mode bool iAmMaster; bool iAmSlave; bool oldSelected; void setup() { transmissionActiveFlag = false; slaveEnabledFlag = false; iAmMaster = false; iAmSlave = false; Serial.begin ( 115200 ); while ( !Serial ) ; // wait for port to open showMenu(); } void loop() { loopSerial(); loopSPI(); } /// Display user choices. void showMenu() { Serial.println ( F( "SPI_On_Uno_Example.ino") ); if ( iAmSlave ) { // In slave mode. The only thing the user can do is to stop it. Serial.println ( F( "Listening in slave mode") ); Serial.println ( F( "S:Stop slave mode" ) ); } else { // Not in slave mode. Serial.println ( F("S:Start listening in slave mode") ); Serial.println ( F("M:Send a message in master mode") ); } } /// Check for user input and obey void loopSerial() { if ( Serial.available() ) { uint8_t clu = Serial.read(); switch ( clu ) { case 'S': if ( iAmSlave ) { SPCR = 0; // Turn off SPI hardware iAmSlave = false; } else { startSlave(); } break; case 'M': masterSend(); break; } showMenu(); } } void loopSPI() { if ( iAmSlave ) { if ( SPSR & 1<0 || inputBufferCounter>= BUFFER_SIZE ) { /// Slave was deselected. Dump data and restart. SPCR = 0; reportInputBuffer(); startSlave(); } // if ( !oldSelected && selected ) // Serial.println ( "became selected" ); oldSelected = selected; } } } void startSlave() { // Implicitly data order is most significant bit(msb) first and // Clock is low when idle and // clock sample on leading edge, setup on trailing pinMode ( _SS, INPUT ); pinMode ( MISO, OUTPUT ); // Enable the SPI, without master and interrupt bits // Implicitly data order is msb first and // Clock is low when idle and // clock sample on leading edge, setup on trailing SPCR = 1 << SPE; oldSelected = false; outputBufferCounter = 0; inputBufferCounter = 0; transmissionActiveFlag = false; SPDR = slaveMessage[outputBufferCounter++]; iAmSlave = true; Serial.println ( "Listening as Slave" ); } void masterSend() { Serial.println (); Serial.println ( F("Sending messge as master" ) ); outputBufferCounter = 0; inputBufferCounter = 0; SPCR = 0; pinMode ( _SS, OUTPUT ); pinMode ( MISO, INPUT ); pinMode ( MOSI, OUTPUT ); pinMode ( SCK, OUTPUT ); // Enable the SPI in master mode. digitalWrite ( _SS, LOW ); digitalWrite ( _SS, HIGH ); digitalWrite ( _SS, LOW ); SPCR = 1 << SPE | 1 << MSTR; for ( outputBufferCounter = 0; outputBufferCounter < BUFFER_SIZE; outputBufferCounter++ ) { SPDR = masterMessage[outputBufferCounter]; while(!(SPSR & (1<