#define SPI_EEPROM_WREN 0x6
#define SPI_EEPROM_RDSR 0x5
#define SPI_EEPROM_WRITE 0x2
#define SPI_EEPROM_READ 0x3

#define SELECT_EEPROM PORTB &= ~(1<<PB0)  	// Low
#define DESELECT_EEPROM PORTB |= (1<<PB0)  	// High
#define nop()  __asm__ __volatile__("nop")

static inline void SPI_SendByte(const uint8_t Byte) {
	SPDR = Byte;
	while (!(SPSR & (1 << SPIF)));
}

static inline uint8_t SPI_ReceiveByte(void) {
	SPDR = 0x00;
	while (!(SPSR & (1 << SPIF)));
	return SPDR;
}

static inline uint8_t SPI_TransferByte(const uint8_t Byte) {
	SPDR = Byte;
	while (!(SPSR & (1 << SPIF)));
	return SPDR;
}

void read_SPIeeprom (uint16_t addr, void *data, uint8_t size) {
	SELECT_EEPROM;
	nop(); nop();
	SPI_SendByte(SPI_EEPROM_READ);	
	SPI_SendByte((uint8_t)(addr >> 8));
	SPI_SendByte((uint8_t)(addr));
	for (uint8_t x=0; x<size; x++)
		*(uint8_t*)(data++) = SPI_TransferByte(0);
	nop(); nop();
	DESELECT_EEPROM;
}

void write_SPIeeprom (uint16_t addr, void *data, uint8_t size) {
	SELECT_EEPROM;
	nop(); nop();
	SPI_SendByte(SPI_EEPROM_WREN);
	DESELECT_EEPROM;
	nop(); nop();
	SELECT_EEPROM;
	nop(); nop();
	SPI_SendByte(SPI_EEPROM_WRITE);
	SPI_SendByte((uint8_t)(addr >> 8));
	SPI_SendByte((uint8_t)(addr));
	for (uint8_t x=0; x<size; x++)
		SPI_SendByte(*(uint8_t*)(data++));
	DESELECT_EEPROM;
	_delay_ms(6);
}