Maker Pro
Maker Pro

SPI freezes

thebignoob

Aug 18, 2014
1
Joined
Aug 18, 2014
Messages
1
Hello,
I have an issue with spi that freezes. I'm using atmega88 with nrf24l01 but when i try to test spi communication i get stuck.
I initialize spi based on atmel specifications:
Code:
DDRB |= (1<<DDB5) | (1<<DDB3) | (1<<DDB2) |(1<<DDB1);
SPCR |= (1<<SPE)|(1<<MSTR);

And when I try to test out writing to spi (and print out to terminal ) i get stuck looping... ( i have usart initialized and used without any problems)
Code:
char spi_rw(unsigned char x)
{
    SPDR = x;   
    //get stuck in this while loop
    while(!(SPSR & (1<<SPIF)));
    //printing to terminal after get's out of loop but never go out   
    return SPDR;
}

I'm trying to read STATUS register:
Code:
uint8_t get_reg(uint8_t reg)
{   

    _delay_us(10);
    CLEARBIT(PORTB, 2);    //CSN low so nrf start listen for command
    _delay_us(10);
    spi_rw(R_REGISTER + reg);   
    _delay_us(10);
    reg = spi_rw(NOP);
    _delay_us(10);
    SETBIT(PORTB, 2);    //CSN IR_High nrf do nothing now
    return reg;   
}

I try calling get_reg(STATUS) and passing it to usart to print out resultand I get nowhere since code stuck in while loop.

P.S. i use this simple functions to set and clear bits
Code:
#define BIT(x) (1<<(x))
#define SETBITS(x,y) ((x)|=(y)))
#define CLEARBITS(x,y) ((x) &=(~(y)))
#define SETBIT(x,y) SETBITS((x), (BIT((y))))
#define CLEARBIT(x,y) CLEARBITS((x), (BIT((Y))))

Thanks in advance, any help would be greatly appreciated.
 

OLIVE2222

Oct 2, 2011
690
Joined
Oct 2, 2011
Messages
690
No idea about you code, I don't have C programming skills. However google a bit for "nrf24l01 avr studio" working codes will pop's up.
Also if it's your first SPI code get a free sample of a SPI DAC or digital potentiometer so you can "debug with a multimeter" !
 

Harald Kapp

Moderator
Moderator
Nov 17, 2011
13,700
Joined
Nov 17, 2011
Messages
13,700
You mean this loop?
while(!(SPSR & (1<<SPIF)));​

Your error lies with the NOT operation:
SPSR & (1 <<SPIF) will mask all other bits except SPIF. The result is:
SPIF=0: SPSR & (1<<SPIF) = 0x00 /* stay in the loop as serial transfer is not complete (SPIF == 0) */
SPIF=1: SPSR & (1<<SPIF) = 0x80 /* exit the loop here as serial transfer is completed (SPIF == 1) */
Negating this results in:
SPIF=0: !(SPSR & (1<<SPIF)) = 0xFF
SPIF=1: !(SPSR & (1<<SPIF)) = 0x7F
Both expressions are <> 0 and therefore the loop will not exit.

Use instead:
while((SPSR | (1<<SPIF)) == 0x00);​
 

Harald Kapp

Moderator
Moderator
Nov 17, 2011
13,700
Joined
Nov 17, 2011
Messages
13,700
Sorry, I mixed up "!" and "~" .
This part looks actually correct.

My C is a bit rusty. Are you sure that using "SPSR actually reads the contents of the status register? If SPSR is defined as the address of the status register (i.e. 0x..), then using SPSR this way may operate on the address, not on the register contents. Depending on the version of AVR-GCC/AVR-LIBC or any other compiler you may use it may be required to use an inp() statement like inp/SPSR) to actually access the register's contents.

It may also help to define SPSR as "volatile". This tells the compiler that the contents of this register may change at runtime and prevents over-optimization (without volatile the compiler does not foresee potential future changes in SPSR and may "optimize" the code to the level of uselessness).
 
Top