Help on how to integrate ATTiny167 with Winbond Serial Flash

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All,

 

I'm new to AVR and I'm using ATTiny167 for my project. I chose this chip due as it contains 2 modules USI and SPI. I'm planning to use the USI for I2C communication and SPI for Serial flash communication.

 

What I am trying to do is to get the manufacturer ID for the serial flash. Serial flash instruction starts with the leading edge and the data is return at the trailing edge.

  1. I tried changing the clock polarity to enable the switchover from instruction to data. It only works for the first data but I have extra bit for the second data.
  2. Because of this I try to flip the clock polarity after the first data but I end with extra bit on the second data as well.

 

Is there a way I can transition between instruction and data in SPI using the SPI module?

Scopeshot of the SCK and MOSI is as attached.

 

I use back the reference code provided in the datasheet, code as below:

 

 

int main(void)
{
DDRB = 0xFF;
SPI_MasterInit();
PORTA |=(1<<DD_SS);
GetManufacturerID();
/* Replace with your application code */
while (1)
{
}
}

void GetManufacturerID(void)
{
PORTA &= ~(1<<DD_SS);
SPI_MasterTransmit(0x9F);
SPI_MasterTransmit(0x00);
SPCR &= ~(1<<CPOL);
SPI_MasterTransmit(0x00);
PORTA |=(1<<DD_SS);

}
void SPI_MasterInit(void)
{
/* Set MOSI and SCK output, all others input */
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);

/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0) |(1<<CPOL);
}
uint8_t SPI_MasterTransmit(uint8_t cData){

/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
return SPDR;
}

 

Attachment(s): 

This topic has a solution.
Last Edited: Mon. Dec 4, 2017 - 02:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zhiling0229 wrote:
SPI for Serial flash communication.

So what "Serial Flash" are you using?

 

Give a link.

 

Is there a way I can transition between instruction and data in SPI using the SPI module?

SPI has no concept of "instruction" or "data" - it is just a means of transferring bits & bytes

 

 

How to properly post source code: http://www.avrfreaks.net/comment... - also how to embed images so that they are visible in the post:

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
SPCR &= ~(1<<CPOL);

Why would you ever change the polarity of an SPI transfer part way through a communication? SPI devices have a fixed use of polarity and phase. There are 4 possible settings. You set the AVR to the right CPOL/CPHA before you start (the one that matches what it says in the SPI device datasheet) and then you leave it there. You don't change during a communication.

 

What has given you the idea that it needs to be switched to differentiate command/data?

 

The fact is that most SPI attached devices run some kind of "state machine". It always starts by sending some 1 byte "command" and then the device will know to then expect another 0/1/2/3/4... bytes after that as part of the command (often address and then data). You the user don't have to do anything to make the switch from sending command to sending data. You just send it the complete 1/2/3/4/5/... bytes that the command expects to use and once it has consumed N bytes to activate the given command it will return back to the "waiting for new command byte state.

 

In case things ever get "out of sync" usually (for SPI) the action of taking chip select inactive then active again is enough to not only reset the per byte bit counter but also to return it to the "waiting for next command" mode.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Why would you ever change the polarity of an SPI transfer part way through a communication? ... What has given you the idea that it needs to be switched to differentiate command/data?

My thoughts exactly!

 

I guess knowing what device it actually is, and having a datasheet link, might throw some light ...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Awneil,Clason,

 

Thanks for the feedback. The serial flash that is use is Winbond W25Q80 with the link as below:

 

https://cdn-shop.adafruit.com/da...

 

 

Can you advice how can i achieve the clock signal as shown below?

 

I have a correct scope which comes from a universal flash programmer which has the correct transition between instruction and data A 

 

 

Scope from ATTiny167 with 3 transmit without any polarity change

 

void GetManufacturerID(void)
{
	PORTA &= ~(1<<DD_SS);
	SPI_MasterTransmit(0x9F);
	SPI_MasterTransmit(0x00);
	SPI_MasterTransmit(0x00);
	PORTA |=(1<<DD_SS);

}

 

Last Edited: Fri. Nov 24, 2017 - 12:56 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It looks as if your 25Qxx device is much the same as any 25Cxx eeprom. Just with different width of location counter.
Untested. I am not at a PC.
.
I suggest that you look at library code for 25xxxx devices. Study how it works. Compare with your datasheet,
Personally, I would write a software test suite and report results to a Serial Terminal.
You could report with an LED. e.g. blink N times to indicate a value.
.
I find a Logic Analyser is easier to follow than a scope trace. A LA is cheaper and smaller than a scope. You only need a scope if the hardware is faulty.
.
The neat formatted code is easier to study. This costs you nothing. Your eyes/brain is the best debugging tool.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
A LA is cheaper and smaller than a scope

Only if it's a small, cheap logic analyser!

 

 

One of these is neither cheaper nor smaller than a scope:

https://www.tek.com/logic-analyz...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have a library code that you can share for 25XXXX? It is great if you guys can give me some pointers 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David has already given you good pointers in #6

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi All,

 

After tinkering with the SPI module for sometime it is base on conclusive evidence with a digital analyzer / oscilloscope that it is not possible to integrate a NOR serial flash SPI programming to the SPI module. 

Whoever who wish to explore using the SPI module for Atmel with NOR serial flash programming, please run through the thread here first. 

 

It will only work with customization which can be achieved with USI communication. I have attached the USI code here:

 


void WriteSPIInstruction(uint8_t data)
{
	// load USI Data Register with data to transmit
	USIDR = data;	
	// transmit the byte (8 bits)
	for(char i=0; i<7; i++)
	{
		USICR = (1<<USIWM0)	| (1<<USITC); // toggle clock pin
		// USICLK is data register clock which puts the next bit in the D0 pin
		USICR = (1<<USIWM0) | (1<<USICLK)|(1<<USITC);
	}
	
	USICR = (1<<USIWM0)	| (1<<USITC); // toggle clock pin
}

void ReadSPIFirstData()
{
	// transmit the byte (8 bits)
	USICR = (1<<USIWM0)	| (1<<USITC); // toggle clock pin
	
	for(char i=0; i<7; i++)
	{
		USICR = (1<<USIWM0) | (1<<USICLK)|(1<<USITC);
		// USICLK is data register clock which puts the next bit in the D0 pin
		USICR = (1<<USIWM0)	| (1<<USITC); // toggle clock pin
	}
}

uint8_t ReadSPISecondData()
{
	uint8_t firstData;
	// transmit the byte (8 bits)
	for(char i=0; i<8; i++)
	{
		USICR = (1<<USIWM0)	| (1<<USITC); // toggle clock pin
		// USICLK is data register clock which puts the next bit in the D0 pin
		USICR = (1<<USIWM0) | (1<<USICLK)|(1<<USITC);
		
		if(i==0){
			firstData = USIDR & 0xFF;
		}				
	}
	
	return firstData;
}

int ReadSPIThirdData()
{
	int secondThirdData;
	// transmit the byte (8 bits)
	for(char i=0; i<8; i++)
	{
		USICR = (1<<USIWM0)	| (1<<USITC); // toggle clock pin
		// USICLK is data register clock which puts the next bit in the D0 pin
		USICR = (1<<USIWM0) | (1<<USICLK)|(1<<USITC);
		
		if(i==0){
			secondThirdData = USIDR & 0xFF;			
		}
	}
	
	USICR = (1<<USIWM0)	| (1<<USITC); // toggle clock pin	
	USICR = (1<<USIWM0) | (1<<USICLK)|(1<<USITC);
	
	LEDIndicator(USIDR);
	secondThirdData = (secondThirdData << 8) | (USIDR & 0xFF);
	return (secondThirdData & 0xFFFF);
}

 

Since SPI module is a dead end. I'm dropping ATTiny167 and reverting it to ATTiny85 which is more cost effective for my design. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Go on.  The SPI module in a Tiny167 is exactly the same as in regular Mega.  e.g. You have a macro for chip-select/de-select and a function for spi transfer:

 

#define CS_ACTIVE() PORTA &= ~(1<<SS)
#define CS_IDLE()   PORTA |=  (1<<SS)

uint8_t spi(uint8_t c)
{
    SPDR = c;
    while((SPSR & (1<<SPIF)) == 0) ;
    return SPDR;
}

uint16_t read_ID(void)    //from Fig29 in datasheet
{
    CS_ACTIVE();
    spi(0x90);            //instruction
    spi(0x00);            //3 dummies
    spi(0x00);
    spi(0x00);
    uint8_t manfr = spi(0x00); //should be 0xEF
    uint8_t model = spi(0x00); //device code
    CS_IDLE();
    return (manfr<<8) | model;
}

Whether you use SPI, USI or bit-bang the principle is the same.  i.e. single transfer function.   copy the timing diagram in the datasheet.

 

I don't have a W25Q80.   I probably have a W25Q128 somewhere.

I do have a Tiny167 on a DIP adapter.    It is painful to use breadboards (for me) 

 

You can do the same exercise for reading blocks of memory,   writing blocks, ...

 

Untested.   The above code was typed directly into the Browser.

 

David.

Last Edited: Mon. Dec 4, 2017 - 09:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David

 

I have tested that already. It does not work. If you look at my code above is the same as what you have written 

Is a pity Atmel has no FAE, if not i will request the FAE to come to my company to take a look.

 

void GetManufacturerID(void)
{
	PORTA &= ~(1<<DD_SS);
	SPI_MasterTransmit(0x9F);
	SPI_MasterTransmit(0x00);
	SPI_MasterTransmit(0x00);
	PORTA |=(1<<DD_SS);

}
uint8_t SPI_MasterTransmit(uint8_t cData){

/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
return SPDR;
}

 

Last Edited: Thu. Dec 7, 2017 - 03:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zhiling0229 wrote:
Is a pity Atmel has no FAE, if not i will request the FAE to come to my company to take a look.

Microchip Technology Inc

Microchip

Contact Us

http://www.microchip.com/about-us/contact-us

...

 

Technical Support

....

Additional technical help is available through the sales representative, our local Microchip FAEs or CAEs.

Some sales reps are engineers.

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

zhiling0229 wrote:

David

 

I have tested that already. It does not work. If you look at my code above is the same as what you have written 

Is a pity Atmel has no FAE, if not i will request the FAE to come to my company to take a look.

 

 

I was intrigued by your comment.  So I wrote a program on some real hardware:

#define CS          PD5      //25Q EEPROM on my board
#define CS_OUTPUT() DDRD  |=  (1<<CS)
#define CS_ACTIVE() PORTD &= ~(1<<CS)
#define CS_IDLE()   PORTD |=  (1<<CS)

void spi_init(void)
{
    PORTB |= (1 << PB2); //deselect SS
    //       (1<<SCK) |  (1<<MOSI) |    (1<<SS);
    DDRB = (1 << PB5) | (1 << PB3) | (1 << PB2);
    SPCR = (1 << SPE) | (1 << MSTR);
    SPSR;               //clear flags
    SPDR;               //clear buffer
}

uint8_t spi(uint8_t c)
{
    SPDR = c;
    while ((SPSR & (1 << SPIF)) == 0) ;
    return SPDR;
}

uint16_t read_RDID(void)    //from Fig29 in datasheet
{
    CS_ACTIVE();
    spi(0x90);            //instruction
    spi(0x00);            //3 dummies
    spi(0x00);
    spi(0x00);
    uint8_t manfr = spi(0x00); //should be 0xEF
    uint8_t model = spi(0x00); //should be 0x13
    CS_IDLE();
    return (manfr << 8) | model;
}

uint32_t read_JEDEC(void)    //from Fig33 in datasheet
{
    CS_ACTIVE();
    spi(0x9F);               //instruction
    uint32_t manfr = spi(0x00); //should be 0xEF
    uint8_t type = spi(0x00);  //should be 0x40
    uint8_t capacity = spi(0x00); //should be 0x14
    CS_IDLE();
    return (manfr << 16) | (type << 8) | capacity;
}

void setup()
{
    Serial.begin(9600);
    Serial.println("");
    Serial.println("Read Manufactuter ID on 25Qxxx EEPROM");
    spi_init();
    CS_IDLE();
    CS_OUTPUT();
    Serial.print("Read Manufacturer / Device ID (90h) fig29 : 0x");
    Serial.println(read_RDID(), HEX);
    Serial.print("Read JEDEC ID (9Fh) fig33                 : 0x");
    Serial.println(read_JEDEC(), HEX);
}

void loop()
{
}

It worked just fine on the particular A25L025 chip that was already mounted on Uno.

Note that the code is set up for ATmega328P.   You would just change the defines for your ATtiny167.

 

The Serial print functions should work on a Tiny Arduino Core.   But you can equally well use regular printf().

 

The most important point is that God created functions to return values.   I suggest that you study your C Textbook.

But it also shows how you can copy the timing diagrams from the datasheet.

 

Of course your void functions can never return a value.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi David,

 

My questions revolves around handling the transition between positive edge to negative from instruction to data. 

What i'm saying is if you use the spi instruction function you will get 3 sets of 8 bit clock signal (24 bits), however in the serial flash case it will be (23 bits as one clock shares the instruction and data) as shown below:

 

You might argue that regardless 24 or 23 it will get the same data, which I did not manage obtain (is not the code problem as i'm monitoring the output data with the logic analyzer which you see from the previous slides)

 

Anyway i'm dropping this ATTiny167 from the board design and moving on with some other micro controllers in the market. I'm sharing my findings with the world. If you don't think it is right and it works even with ATTiny167, then i guess other people who follow this will be able to utilize this information to continue to develop their solution.

 

No need to share your sarcasm here as we are all learning something new everyday.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you’ve missed how spi works. There is no change of clock edge - data out is clocked on one edge and data in is clocked on the other. This is how it works.
In the section of the timing diagram you’ve highlighted, the slave device outputs the data on the falling edge of 7 and the master clocks in that bit on the rising edge of 8. you need the setup time. This behaviour is not specific to that chip. I’d say you’ve grasped onto a non-problem. You probably had cpha set incorrectly.

Last Edited: Wed. Dec 13, 2017 - 07:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The red circled area shows that the DI line can change on the falling edge but must be stable for the rising edge of SCK.
Likewise, DO is stable at the rising edge. This means SPI mode #0 i.e. the regular default.
.
This is the standard convention for timing diagrams i.e. to show when lines are stable..
.
My main point was to show how to translate a timing diagram into C statements. This applies to any new hardware chip. But of course 25xxxx chips have been on the market for 30 odd years.
.
David.