Electronic – SPI not working on ATtiny441

avrmicrocontrollerspi

I've been tearing out my hair for a while on this. I'm just trying to do a basic SPI transaction — sending one byte — on the ATtiny441 but I'm getting nothing on the SCK and MOSI lines. First, here are my fuse settings and pinout (in red):
Extended fuse bits
High fuse bits
Low fuse bits
Pinout
Probably the most useful information here is that I'm using the 8MHz internal oscillator, and not dividing by 8. Note that I'm remapping the SPI pins so that I can leave my logic analyzer on while programming with the default pins.

Here's my main.c file:

#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>

#define SCK         3
#define MOSI        1
#define CSN         2

uint8_t data = 0;
uint8_t reg = 0;


int main(void)
{
    PRR = 0; // turn off power reduction
    REMAP |= (1<<SPIMAP); // remap SPI pins
    // set SCK, MOSI, CSN as outputs:
    DDRA = (1<<SCK) | (1<<MOSI) | (1<<CSN); 
    // enable SPI, set as master, use f_clkIO/16 (500kHz):
    SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);
    reg = SPSR;
    reg = SPDR;

    while(1)
    {
        PORTA &= ~(1 << CSN); // clear CSN
        SPDR = data++; // send byte
        while( !(SPSR & (1<<SPIF)) ); // wait for flag to set
        PORTA |= (1 << CSN); // set CSN
        _delay_ms(10);
    }

    return 0;
}

I'm reading the SPSR and SPDR registers before the while loop at the recommendation of Atmel's AVR151 app note (page 11).

When I run the code the CSN line stays low, along with SCK and MOSI, suggesting that it's getting stuck in the while( !(SPSR & (1<<SPIF)) ); section waiting for the SPIF to set. When I comment out this line, the CSN line goes low for ~25us then back high, which is expected. I tried manually setting the outputs high on SCK and MOSI, too, to make sure it's not a pin connection problem and they worked fine.

Question: Does anyone see the error in my ways? I feel like there's one small, stupid error somewhere.

Edit: I also want to mention that I tried it with and without the clock divider (by 8) fuse bit set, and with and without remapping the SPI pins from the default location (i.e. programming, removing programming leads, attaching logic probe leads).

Best Answer

Eureka! Turns out the SPIMAP bit is incorrectly mapped!

/usr/local/CrossPack-AVR-20131216/avr/include/avr/iotn441.h:377:0: note: this is the
location of the previous definition
 #define SPIMAP 0
 ^

(It should be bit 1.) Therefore, the line remapping the SPI pins was failing! This is corrected by placing a #define SPIMAP 1 in the #define section.

EDIT: As Martin pointed out, I am indeed using an old version of avr-libc. I was using the latest version of CrossPack, which is dated back almost 4 years from today. The newest version has this bug fixed.