User data on SPI Flash

Technical discussions around xCORE processors (e.g. xcore-200 & xcore.ai).
User avatar
rp181
Respected Member
Posts: 395
Joined: Tue May 18, 2010 12:25 am

User data on SPI Flash

Post by rp181 »

With the standard connections for system Flash, Can I store my own data to the Flash, by referencing the ports as standard ports?
User avatar
octal
XCore Addict
Posts: 228
Joined: Thu Jan 27, 2011 3:30 pm
Location: Argenteuil - France

Post by octal »

User avatar
boeserbaer
Active Member
Posts: 51
Joined: Fri Jan 29, 2010 4:36 pm

Post by boeserbaer »

Look at flash.h and flashlib.h They describe the different routines for accessing the flash. there are separate routines for both the data and boot image. I wound up writing my own though, because I wanted to be able to manage individual sectors on the flash. As far as I can tell, the data sector routines use 32k or 64k (I can't remember which) as the minimum erase/write size. I wanted to use the 4k sectors my flash supports.

regards mike
User avatar
boeserbaer
Active Member
Posts: 51
Joined: Fri Jan 29, 2010 4:36 pm

Post by boeserbaer »

I didn't read your question well enough.

These are the routines I use:

Code: Select all

void spi_shutdown() {
	// need clock ticks in order to stop clock blocks
	timer t;
	unsigned int time;

	printuint(0);
	SPI.spiCLK <: 0;
	t :> time;
	time += M41T93_BIT_TIME;

	for (int i=0;i<16;i++)
	{
		t when timerafter ( time ) :> void;
		time += M41T93_BIT_TIME;
		SPI.spiCLK <: 1;
		t when timerafter ( time ) :> void;
		time += M41T93_BIT_TIME;
		SPI.spiCLK <: 0;
	}
	printuint(1);
	stop_port(SPI.spiMOSI);
	printuint(2);
	stop_port(SPI.spiMISO);
	printuint(3);
	stop_port(SPI.spiCLK);
	printuint(4);
	stop_clock(SPI.spiClkblk);
	printuint(5);
}

void spi_init( unsigned rate,
		unsigned clk_div,
		unsigned clk_delay,
		unsigned clk_pad_delay,
		unsigned miso_pad_delay,
		unsigned mosi_pad_delay) {

	timer t;
	unsigned int time;

	set_port_use_off(SPI.spiCLK);
	set_port_use_on(SPI.spiCLK);
//	stop_port(SPI.spiMOSI);
//	stop_port(SPI.spiMISO);
//	stop_port(SPI.spiCLK);
//	stop_clock( SPI.spiClkblk);
	configure_out_port(SPI.spiMOSI, SPI.spiClkblk, 0);
	configure_clock_src(SPI.spiClkblk, SPI.spiCLK);
//printuint(1);
	configure_out_port(SPI.spiMOSI, SPI.spiClkblk, 0);
//printuint(2);
	configure_in_port(SPI.spiMISO, SPI.spiClkblk);
//printuint(3);
	set_clock_fall_delay(SPI.spiClkblk, clk_delay); // need to understand this better
	set_clock_rise_delay(SPI.spiClkblk, clk_delay); // need to understand this better
	//	set_pad_delay(spi1_sclk, 5);
	set_pad_delay(SPI.spiMISO, miso_pad_delay);
	set_pad_delay(SPI.spiMOSI, mosi_pad_delay);
//	start_port(SPI.spiCLK);
//printuint(4);
	start_clock(SPI.spiClkblk);
//printuint(5);
	SPI.spiCLK <: 0;
	t :> time;
	time += M41T93_BIT_TIME;
//printuint(6);
	for (int i=0;i<8;i++)
	{
		t when timerafter ( time ) :> void;
		time += M41T93_BIT_TIME;
		SPI.spiCLK <: 1;
		t when timerafter ( time ) :> void;
		time += M41T93_BIT_TIME;
		SPI.spiCLK <: 0;
	}
//printuint(7);
	clearbuf(SPI.spiMISO);
//printuint(8);
	clearbuf(SPI.spiMOSI);

//printuint(9);
}


void  spi_in_bytes(unsigned addr, unsigned outLen, unsigned char outData[],unsigned inLen, unsigned char inData[], unsigned enableSS, unsigned disableSS) {
	// MSb-first bit order - SPI standard
	unsigned bitTime = AT_25DF_041_BIT_TIME/2;
	timer t;
	unsigned int time;
	unsigned x;

	unsigned j=0;

	SPI.spiSS <: disableSS;
	rtc_ss <: disableSS;
	SPI.spiCLK <: 0;
	if (outLen >0)
	{
		t :> time;
		time += bitTime;
		x = bitrev(outData[j++]) >> 24;
		SPI.spiMOSI <: x;
		t when timerafter ( time ) :> time;
		time += bitTime;
		SPI.spiCLK <: 1;
		t when timerafter ( time ) :> time;
		time += bitTime;
		time += bitTime;
		SPI.spiCLK <: 0;
		switch(addr){
		case FLASH:
			SPI.spiSS <: enableSS;
			break;
		case RTC:
			rtc_ss <: enableSS;
			break;
		}
		// it requires only 7 more clocks to finish the first word
		for (int i=0;i<7;i++)
		{
			t when timerafter ( time ) :> time;
			time += bitTime;
			SPI.spiCLK <: 1;
			t when timerafter ( time ) :> time;
			time += bitTime;
			SPI.spiCLK <: 0;
		}
		SPI.spiMISO :> void;
		for(;j<outLen;j++)
		{
			time += bitTime;
			x = bitrev(outData[j]) >> 24;
			SPI.spiMOSI <: x;
			for (int i=0;i<8;i++)
			{
				t when timerafter ( time ) :> time;
				time += bitTime;
				SPI.spiCLK <: 1;
				t when timerafter ( time ) :> time;
				time += bitTime;
				SPI.spiCLK <: 0;
			}
			SPI.spiMISO :> void;
		}
		//one last clock cycle required
		time += bitTime;
		t when timerafter ( time ) :> time;
		time += bitTime;
		SPI.spiCLK <: 1;
		t when timerafter ( time ) :> time;
		time += bitTime;
		SPI.spiCLK <: 0;
	}
	else
	{
		switch(addr){
		case FLASH:
			SPI.spiSS <: enableSS;
			break;
		case RTC:
			rtc_ss <: enableSS;
			break;
		}
	}
	clearbuf(SPI.spiMISO);

	t :> time;
	time += bitTime;

	for(j=0;j<inLen;j++)
	{
		for (int i=0;i<8;i++)
		{
			t when timerafter ( time ) :> time;
			time += bitTime;
			SPI.spiCLK <: 1;
			t when timerafter ( time ) :> time;
			time += bitTime;
			SPI.spiCLK <: 0;
		}
		SPI.spiMISO :> x;
		inData[j] =  (bitrev(x) >> 24);
	}
	SPI.spiSS <: disableSS;
	rtc_ss <: disableSS;
}

void spi_out_bytes(unsigned addr, unsigned len, unsigned char data[], unsigned enableSS, unsigned disableSS)  {
	// MSb-first bit order - SPI standard
	unsigned bitTime = AT_25DF_041_BIT_TIME/2;
	timer t;
	unsigned int time;
	unsigned x;
	unsigned j=0;

	SPI.spiSS <: disableSS;
	rtc_ss <: disableSS;
	SPI.spiCLK <: 0;
	t :> time;
	time += bitTime;
	x = bitrev(data[j++]) >> 24;
	SPI.spiMOSI <: x;
	t when timerafter ( time ) :> time;
	time += bitTime;
	SPI.spiCLK <: 1;
	t when timerafter ( time ) :> time;
	time += bitTime;
	time += bitTime;
	SPI.spiCLK <: 0;
	switch(addr){
	case FLASH:
		SPI.spiSS <: enableSS;
		break;
	case RTC:
		rtc_ss <: enableSS;
		break;
	}
	// it requires only 7 more clocks to finish the first word
	for (int i=0;i<7;i++)
	{
		t when timerafter ( time ) :> time;
		time += bitTime;
		SPI.spiCLK <: 1;
		t when timerafter ( time ) :> time;
		time += bitTime;
		SPI.spiCLK <: 0;
	}
	SPI.spiMISO :> void;
	for(;j<len;j++)
	{
		time += bitTime;
		x = bitrev(data[j]) >> 24;
		SPI.spiMOSI <: x;
		for (int i=0;i<8;i++)
		{
			t when timerafter ( time ) :> time;
			time += bitTime;
			SPI.spiCLK <: 1;
			t when timerafter ( time ) :> time;
			time += bitTime;
			SPI.spiCLK <: 0;
		}
		SPI.spiMISO :> void;
	}
	//one last clock cycle required
	time += bitTime;
	t when timerafter ( time ) :> time;
	time += bitTime;
	SPI.spiCLK <: 1;
	t when timerafter ( time ) :> void;

	SPI.spiCLK <: 0;
	SPI.spiSS <: disableSS;
	rtc_ss <: disableSS;
}

void writeEnable()
{
	unsigned char cData[1];

	cData[0] = WRITE_ENABLE_CMD;
	spi_out_bytes(FLASH,1,cData, 0, 1);
}

void writeDisable()
{
	unsigned char cData[1];

	cData[0] = WRITE_DISABLE_CMD;
	spi_out_bytes(FLASH,1,cData, 0, 1);
}

void sectorUnprotect(unsigned addr)
{
	unsigned char cData[4];

	writeEnable();
	cData[0] = SECTOR_UNPROTECT_CMD;
	uintToChar(cData, addr, 1,3);
	spi_out_bytes(FLASH,4,cData, 0, 1);
	writeDisable();

}

void sectorProtect(unsigned addr)
{
	unsigned char cData[4];

	writeEnable();
	cData[0] = SECTOR_PROTECT_CMD;
	uintToChar(cData, addr, 1,3);
	spi_out_bytes(FLASH,4,cData, 0, 1);
	writeDisable();

}

unsigned char statusRegister()
{
	unsigned char outData[1];
	unsigned char inData[1];

	outData[0] = READ_STATUS_CMD;
	spi_in_bytes (FLASH, 1,outData,1,inData, 0, 1);

	return inData[0];
}

unsigned erase4k(unsigned addr)
{
	unsigned char cData[4];
	timer t;
	unsigned int time;
	unsigned elapsedTime = 0;

	cData[0] = ERASE_4k_CMD;
	uintToChar(cData, addr, 1,3);
	sectorUnprotect(addr);
	writeEnable();
	spi_out_bytes(FLASH,4,cData, 0, 1);
	// add timeout
	t :> time;
	time += 10000;  //100us
	while (((statusRegister() & READY_BUSY_STATUS ) > 0) && (elapsedTime < ERASE_4k_TIME));
	{
		t when timerafter ( time ) :> void;
		time += 10000;  //100us
		elapsedTime += 100;
	}
	sectorProtect(addr);
	return elapsedTime;
}

unsigned writeArray (unsigned len, unsigned char cData[], unsigned addr)
{
	unsigned char cOutData[260];
	timer t;
	unsigned int time;
	unsigned elapsedTime = 0;

	if (len <= 256)
	{
		cOutData[0] = WRITE_ARRAY_CMD;
		uintToChar(cOutData, addr, 1,3);
		for (int i=0;i<len;i++)
			cOutData[i+4] = cData[i];

		sectorUnprotect(addr);
		writeEnable();
		spi_out_bytes(FLASH,4+len,cOutData, 0, 1);
		t :> time;
		time += 10000;  //100us
		while (((statusRegister() & READY_BUSY_STATUS ) > 0) && (elapsedTime < WRITE_PAGE_TIME));
		{
			t when timerafter ( time ) :> void;
			time += 10000;  //100us
			elapsedTime+100;
		}
		sectorProtect(addr);
		return elapsedTime;
	}
	else
	{
		return 0xffffffff;
	}
}

void readArray (unsigned len, unsigned char cData[], unsigned addr)
{
	unsigned char cOutData[4];

	cOutData[0] = READ_ARRAY_CMD;
	uintToChar(cOutData,addr,1,3);
	spi_in_bytes(FLASH, 4, cOutData, len, cData, 0, 1);
}
Last edited by octal on Tue Mar 22, 2011 8:42 pm, edited 2 times in total.
Reason: Added [code][/code] tag arround sources
User avatar
boeserbaer
Active Member
Posts: 51
Joined: Fri Jan 29, 2010 4:36 pm

Post by boeserbaer »

I am glad I posted the above code, as I just noticed a flaw:

I use the enableSS and disableSS values to enable and disable the chip selects for an RTC and the onboasrd flash chip. The RTC uses a 4bit port shared with some status lines, and the calling routine bit masks the enableSS and disableSS values. The flash CS line is on a 1 bit port, and I should have just used a one or zero, or had separate enable disable values for each. Actually I can assume that if I am dealing with the flash the RTC is already disabled, and vice versa.
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm

Post by Folknology »

Hi boeserbaer

For long code postings it often worth using a service like https://gist.github.com/ or others. The reason I suggest this one is because github is where Xcore opensource code is now so its useful to have an account there as its free. It makes the thread more readable that way.

here is an Example I've used before.

P.S. for small snippets of code you can use the built in "" feature here.

regards
Al