Atmega128 SPI don't understand

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

hello,

 

i'm just starting with SPI interface on the atmega128, but i don't see why this simple code is not working, i tested on the hardware and checked the result with a logic analyzer. the first thing i notice was that the clock (PB1) has not a nice pulse train. perhaps i have to include something ?

the green line is the clock

the yellow line is the MOSI

 

Last Edited: Mon. Jul 15, 2019 - 07:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For master operation, the / SS pin (PB0) should be an output to prevent unintended slave operation.

 

    DDRB = (1 << DDB2) | (1 << DDB1) | (1 << DDB0);

 

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

of course, thanks. but it will not change my problem. the pulstrain still don't look good.

the high clock pulse are between the 1 and the 6 ms. 

i think this is de basis for the rest, when this is not ok the rest wil also be not ok.

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

first, it is better to remove the initialization parts outside the while 1 loop. they only need to be done 1 time and not for each byte you want to transmit.

second, if you run at 1MHz internal RC(default if no fuses are changed) then you have clk/16 gives 16us per clock pulse. What happens if you speed up your logic analyzer by a big factor?

It seems to me that you have a way to low samping rate to be able to see all the clock pulses.

you can try 2 things... put the SPI clock at its lowest value being SCK/128 with 1MHz that will give a clock pulse every 128us or 0.128ms or you speed up your analyzer by a big factor(multiples of 10 as you are not even close to missampling)

 

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

thanks for your reaction, i'm just back from a 3 days job, so i reed this now for the first times.

i'm gonna check this tomorrow.

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

i increase the sample rate of the logic analyzer (to 1Mhz), and it works like expected.

thank you

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

here i am again,

there is something new what i don't understand. i have connected a 23LC1024 (extended RAM with SPI) to the ATMEGA 128

 

i have prog a simple code, just to see or i receive something from the 23LC1024. so i'm gonna read out the mode register where the settings are

for: byte, page and sequential mode.

if i watch the datasheet from the 23 LC1024 then i see that the contain of the mode register is coming after the send byte, but then i already closed the transmission, so i'm not gonna see the contain of the mode register (i watch with the logicanalyzer).

do i need to send a extra (dumy)byte more and how ?

 

#define F_CPU 1000000UL // 1 MHz int osc
#include <avr/io.h>



int main(void)
{
    DDRB = (1<<DDB2)|(1<<DDB1)|(1<<DDB0); // Set MOSI and SCK and SS output, all others input
    
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0); // Enable SPI, Master, set clock rate fck/128
    
    while (1)
    {        
        PORTB &= ~(1 << PINB0); // make SS pin = 0

        SPDR = 0b00000101;  // read moderegister        
        while(!(SPSR & (1<<SPIF))); // Wait for transmission complete

        PORTB |= (1 << PINB0); // make SS pin = 1
                
    }
}

 

 

 

 

 

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

Yes, you just write/read another byte over SPI before setting SS high. The MOSI data (i.e. data from master to slave) in that 2nd byte is irrelevant according to the timing diagram. That is inherent to SPI and often called "dummy byte".

/Jakob Selbing

Last Edited: Fri. Jul 19, 2019 - 11:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Normally for SPI you have a generic routine like:

uint8_t SPi_transfer(uint8_t data) {
    SPDR = data;
    while(!(SPSR & (1<<SPIF))); // Wait for transmission complete
    return SPDR;
}

This has the capability to send, receive or send and receive (actually it always does both but sometimes either what you send or what gets returned do not matter). So then you use:

    while (1)
    {        
        PORTB &= ~(1 << PINB0); // make SS pin = 0

        SPI_transfer(0b00000101);  // read moderegister        
        SPI_transfer(0xFF); // "dummy"/"stuffing" byte

        PORTB |= (1 << PINB0); // make SS pin = 1
                
    }

In fact you might want to catch the response so something like:

uint8_t mode;
...
    while (1)
    {        
        PORTB &= ~(1 << PINB0); // make SS pin = 0

        SPI_transfer(0b00000101);  // read moderegister        
        mode = SPI_transfer(0xFF); // "dummy"/"stuffing" byte
        
        send_to_debug_device(mode);

        PORTB |= (1 << PINB0); // make SS pin = 1
                
    }

"debug device" could just be latching it to port pins that have 8 LEDs attached, or it could be sending it to a UART or it could be printing it on an LCD (or some other observational technique you can think of).

 

The point is that "mode" has got the reading back into your code so you can use it in whatever way you see fit.

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

edit: posted this whyle i did not read yet the post here above from clawson

 

ok,...and indeed, now i receive 0b01000000 (sequential mode (who is default setting))

thanks for your help.

Last Edited: Fri. Jul 19, 2019 - 12:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i get a error on:  SPI_transfer

is that a alias for SPDR ?

 

edit: no of course because then you also don,t need:

(!(SPSR & (1<<SPIF))); // Wait for transmission complete

perhaps i have to include something

Last Edited: Fri. Jul 19, 2019 - 12:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As per #9

 

Normally for SPI you have a generic routine like:

uint8_t SPI_transfer(uint8_t data) {
    SPDR = data;
    while(!(SPSR & (1<<SPIF))); // Wait for transmission complete
    return SPDR;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

trixo wrote:
i get a error on:  SPI_transfer
Ah my bad. I mis-typed above:

uint8_t SPi_transfer(uint8_t data) {
    SPDR = data;
    while(!(SPSR & (1<<SPIF))); // Wait for transmission complete
    return SPDR;
}

should have been:

uint8_t SPI_transfer(uint8_t data) {
    SPDR = data;
    while(!(SPSR & (1<<SPIF))); // Wait for transmission complete
    return SPDR;
}

Of course you can call the function what you like. The key thing is that when you deal with SPI every operation is a send and a receive. Some folks are tempted to write separate functions for SPI_send() and SPI_receive() but really only something like SPI_transfer() or SPI_exchange() really makes sense as it can be used for send/receive/both.

 

In Codevision for example they provide an SPI function for you and there they just call it spi() - simple as that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
 while (1)     {        
        PORTB &= ~(1 << PINB0); // make SS pin = 0

        SPI_transfer(0b00000101);  // read moderegister        
        SPI_transfer(0xFF); // "dummy"/"stuffing" byte

        PORTB |= (1 << PINB0); // make SS pin = 1
                
    }

above: this is the part witch i have copy paste in my program, 

 

#define F_CPU 1000000UL // 1 MHz int osc
#include <avr/io.h>



int main(void)
{
    DDRB = (1<<DDB2)|(1<<DDB1)|(1<<DDB0); // Set MOSI and SCK and SS output, all others input
    
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0); // Enable SPI, Master, set clock rate fck/128
    
        while (1)
        {
            PORTB &= ~(1 << PINB0); // make SS pin = 0

            SPI_transfer(0b00000101);  // read moderegister
            SPI_transfer(0xFF); // "dummy"/"stuffing" byte

            PORTB |= (1 << PINB0); // make SS pin = 1
            
        }
    
}

and when i compile this i wil receive a error:  undefined reference to 'SPI_transfer'

what does the SPI_transfer exectly ? because i don't also see: 

while(!(SPSR & (1<<SPIF))); // Wait for transmission complete

no more.

 

anyway thanks for all your help, i appreciate it a lot.

 

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

trixo wrote:
i wil receive a error:  undefined reference to 'SPI_transfer'
Well did you add:

uint8_t SPI_transfer(uint8_t data) {
    SPDR = data;
    while(!(SPSR & (1<<SPIF))); // Wait for transmission complete
    return SPDR;
}

to your code outside the body of any other function?

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

no, nowhere,  i,m gonna check this tomorow.

 

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

and it is working (of course).