How to simply enable the SPI in ATmega328P using register.

Hi,

I tried to enable the SPI in ATmega328P, through arduino code.
First I simply try to enable the SPI as master mode. As per the 328P datasheet when we enable the SPI as master then clock will automatically comes from D13 th pin. Is this correct ?.

void setup(){
DDRB = 0b00101000; // Pin B5 and B3 as output; clock and MOSI
SPCR = 0b11010000; // SPIE,SPE, MSTR is set as one.
}

void loop(){
;
}

After uploading this into nano. I hooked the probe Chinese logic analyzer D13 th PIN and use Pulse view software for analyzing purpose. But I din't get any clock signal.

Note : Capturing time is 1M Samples 1Mhz speed selected in Pulse view tool.

My doubt is in port B6 and B7 is external clock. So In this case I used to enable the MOS and SCK 0b00101000 so this higher bit may disable the clock... is this correct ?.

please update me why I can't get the clock ?.

You're not sending any data, so the clock doesn't do anything.

Why are you changing the registers directly? What's wrong with the SPI library that comes with Arduino?

Pieter

You're not sending any data, so the clock doesn't do anything.

Why are you changing the registers directly? What's wrong with the SPI library that comes with Arduino?

Pieter

No No First of all I am Arduino lover. But I want to access the register directly. that is why. please guide me what is the next step in SPI. the above two lines is enabling the SPI ?. or any other is need ?.

I’m not at all offended that you’re not using the SPI library, it’s just that it’s much easier, and in most cases, it’s all you need. :slight_smile:

The easiest way to figure it out is by reading the source code of the SPI library, because all it does is manipulating those same registers.

You could always use the code in the datasheet:

/* The following code examples show how to initialize the SPI as a Master and how to perform a simple transmission. DDR_SPI in the examples must be replaced by the actual Data Direction Register controlling the SPI pins. DD_MOSI, DD_MISO and DD_SCK must be replaced by the actual data direction bits for these pins. E.g. if MOSI is placed on pin PB5, replace DD_MOSI with DDB5 and DDR_SPI with DDRB. */


void SPI_MasterInit(void)
{
  /* Set MOSI and SCK output, all others input */
  DDR_SPI = (1 << DD_MOSI) | (1 << DD_SCK);
  /* Enable SPI, Master, set clock rate fck/16 */
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
}
void SPI_MasterTransmit(char cData)
{
  /* Start transmission */
  SPDR = cData;
  /* Wait for transmission complete */ 
  while (!(SPSR & (1 << SPIF)))
    ;

}

The clock line is only driven when data is being sent. You need to load data into the spi data register and set the bit to tell it to send it.

void SPI_MasterTransmit(char cData)
{
  /* Start transmission */
  SPDR = cData;
  /* Wait for transmission complete */ 
  while (!(SPSR & (1 << SPIF)))
    ;

}

Acutly the above code what does ?.
And can I pass the char into this function ?.
What does exactly the while condition ?.

SureshKumar2610:

void SPI_MasterTransmit(char cData)

{
 /* Start transmission /
 SPDR = cData;
 /
Wait for transmission complete */
 while (!(SPSR & (1 << SPIF)))
   ;

}




Acutly the above code what does ?.

It starts the transmission by copying the data into the SPI Data Register. It waits for the transmission to complete by waiting for the Interrupt Flag in the Status Register to be set.

SureshKumar2610:
And can I pass the char into this function ?.

You MUST pass a data character into the function.

SureshKumar2610:
What does exactly the while condition ?.

It repeats doing nothing (’;’) until the Interrupt Flag is set to 1.

char data[]={'S','U','R','E','S','H'};

void setup(){
DDRB = 0b00101000; // Pin B5 and B3 as output; clock and MOSI
SPCR = 0b11010000; // SPIE,SPE, MSTR is set as one.
}

void SPI_MasterTransmit(char cData)
{
  /* Start transmission */
  SPDR = cData;
  /* Wait for transmission complete */ 
  while (!(SPSR & (1 << SPIF)))
    ;
}

void loop(){
 for(int count = 0; count<=5; count ++){
      
       SPI_MasterTransmit(data[count]);
       
       }
}

What is wrong in this code ?. I used logic analyzer to see the reaction. Clock is ok. But the data is not changing. Logic analyzer speed set 1m samples and 1mhz in pulseview

SureshKumar2610:
What is wrong in this code ?. I used logic analyzer to see the reaction. Clock is ok. But the data is not changing. Logic analyzer speed set 1m samples and 1mhz in pulseview

You are setting SPIE (SPI Interrupt Enable) but you are not declaring an interrupt handler for it.
Are you looking for the data on the right pin? MOSI is Pin 11 on the Arduino UNO.

@OP

As you are interested to program SPI Interface using register level instruction, the following diagram might be helpful for you.
spi328xe.png
Figure-1: Communication between two UNOs over SPI Port

With the help of the following codes, the Master sends 4-byte data to the Slave using the SPI Port.

#include<SPI.h>
byte myData[4] = {0x98, 0x45, 0x7A, 0xCD}; //to be transfeered to slave
#define SS 10  //Slave Select Line

void setup()
{
  Serial.begin(9600);

  SPI.begin();        //PB2 - PB4 are converted to SS/(OUT-H), MOSI(OUT-L), MISO(IN), SCK(OUT-L)
  bitSet(SPCR, 4);    //UNO_1 is Master
  SPI.setBitOrder(MSBFIRST);  //bit transmission order
  SPI.setDataMode(SPI_MODE1); //CPOL and CPHA (Clock polarity; Clock phase)
  SPI.setClockDivider(SPI_CLOCK_DIV128); //data rate = fosc/128 = 125 kbit
  bitClear(SPCR, 7);  //local SPI interrupt is disable

  digitalWrite(SS, LOW);  //must be LOW to select the slave

  //SPI.transfer(myData, sizeof(myData));

  for (int i = 0; i < 4; i++)
  {
    SPDR = myData[i];//SPI.transfer(0x34);//(myData[i]);
    while (bitRead(SPSR, 7) != HIGH)//SPIF is cleared when SPSR is read
      ;
  }


  SPI.end();
}

void loop()
{

}

With the help of the following codes, the Slave UNO receives 4-byte data from Master over SPI Port and presents them in its Serial Monitor.

#include<SPI.h>
#define SS 10

byte myData[4];

void setup()
{
  Serial.begin(9600);
  SPI.begin();                //PB2 - PB4 are converted to SS/, MOSI, MISO, SCK
  pinMode(SS, INPUT);
  bitClear(SPCR, 4);          //UNO-2 is Slave
  SPI.setBitOrder(MSBFIRST);  //bit transmission order
  SPI.setDataMode(SPI_MODE1); //
  SPI.setClockDivider(SPI_CLOCK_DIV128);  //data rate = fosc/128 = 125 kbit
  bitClear(SPCR, 7);   //local SPI interrupt is disable
  for (int i = 0; i < 4; i++)
  {
    while (bitRead(SPSR, 7) != HIGH)  //checkibg SPIF bit for LH condition
      ;
    myData[i] = SPDR;                 //SPIF falg get cleared
    Serial.print(myData[i], HEX);
  }

  Serial.println();
  SPI.end();
}

void loop()
{

}

spi328xe.png

You are setting SPIE (SPI Interrupt Enable) but you are not declaring an interrupt handler for it.
Are you looking for the data on the right pin? MOSI is Pin 11 on the Arduino UNO.

Arduino Nano(same pin)

Yes I am looking my data out through MOSI pin,
How to set the interrupt handler. Ok, then Without SPIE can I transfer data ?. What is the purpose of the the SPIE.(after finishing data transfer this bit will set ? Correct ?)

Interrupt handler means ?. SPIF need to set and clear process ?.

johnwasser:
You are setting SPIE (SPI Interrupt Enable) but you are not declaring an interrupt handler for it.
Are you looking for the data on the right pin? MOSI is Pin 11 on the Arduino UNO.

Ok then without interrupt bit can we send and receive the data ?.

johnwasser:
You could always use the code in the datasheet:

What a novel concept :wink:

Ok. Got it. There is nothing to set the interrupt register in data sheet example.
I will try and update this.

How can one emphasize enough, read the datasheet.

When configured as a Master, the SPI interface has no automatic control of the SS line. This must be
handled by user software before communication can start. When this is done, writing a byte to the SPI
Data Register starts the SPI clock generator, and the hardware shifts the eight bits into the Slave. After
shifting one byte, the SPI clock generator stops, setting the end of Transmission Flag (SPIF). If the SPI
Interrupt Enable bit (SPIE) in the SPCR Register is set, an interrupt is requested. The Master may
continue to shift the next byte by writing it into SPDR, or signal the end of packet by pulling high the Slave
Select, SS line. The last incoming byte will be kept in the Buffer Register for later use.

Reading further,

When a serial transfer is complete, the SPIF Flag is set. An interrupt is generated if SPIE in SPCR is set
and global interrupts are enabled. If SS is an input and is driven low when the SPI is in Master mode, this
will also set the SPIF Flag. SPIF is cleared by hardware when executing the corresponding interrupt
handling vector. Alternatively, the SPIF bit is cleared by first reading the SPI Status Register with SPIF
set, then accessing the SPI Data Register (SPDR).

You do not do anything. In fact the SPIF flag is read only so you can't do anything.