//
// Programming the Flash and use memory segments
// By PEK '2004
//
// Compiler: GCC
// MCU: ATtiny2313
// Clock:
//
// Include the following line to the linker, enabling the new
// memory segment at address 0x0200:
// -Wl,--section-start=.memsection=0x0200
//
// The header-file boot.h included with the libraries for GCC didn't
// work properly with ATtiny2313. Cause of that I wrote my own
// flash programming functions with inline-assembler below.
//

#include <avr/io.h>

// Problems with COFF generation to simulate other memory sections in
// AVRStudio. Due to this problem the memory section below is not
// used during simulation, to have all code in the same segment.

// Use this row during binary generation for the circuit 
#define MEM_SECTION __attribute__ ((section (".memsection")))

// Use this row during simulation with AVRStudio
//#define MEM_SECTION

// Declaration of functions
void page_erase(uint8_t page) MEM_SECTION;
void page_fill(uint8_t address, uint16_t data) MEM_SECTION;
void page_write(uint8_t page) MEM_SECTION;

int main(void)
{	
	uint8_t i;

	// Erase page 2
	page_erase(0x02);
	
	for(i = 0; i < 8; i+=2)
	{
		// File temporary buffer with data
		page_fill(i, 0x5533);
		
		// Write to page 2
		page_write(0x02);
	}
	
	while(1);	// Loop forever
	
	return 1;
}

// Erase page (64 pages in ATtiny2313)
void page_erase(uint8_t page)
{
	uint16_t address = (uint16_t)page << 5;
	
	asm volatile
	(
		"movw r30, %2\n\t"
		"sts %0, %1\n\t"
		"spm\n\t"
		: "=m" (SPMCSR)
		: "r" ((uint8_t)0x03), "r" ((uint16_t)address)
		: "r30", "r31"
	);
}

// Fill temporary buffer with data (16 words / page in ATtiny2313)
void page_fill(uint8_t address, uint16_t data)
{
	asm volatile
	(
		"movw  r0, %3\n\t"
		"movw r30, %2\n\t"
		"sts %0, %1\n\t"
		"spm\n\t"
		"clr  r1\n\t"
		: "=m" (SPMCSR)
		: "r" ((uint8_t)0x01), "r" ((uint16_t)address), "r" ((uint16_t)data)
		: "r0", "r30", "r31"
	);
}

// Write word in temporary buffer to Flash
void page_write(uint8_t page)
{
	uint16_t address = (uint16_t)page << 5;
	
	asm volatile
	(
		"movw r30, %2\n\t"
		"sts %0, %1\n\t"
		"spm\n\t"
		: "=m" (SPMCSR)
		: "r" ((uint8_t)0x05), "r" ((uint16_t)address)
		: "r30", "r31"
	);
}
