SPI /SS acts as INPUT configured as OUTPUT using DebugWire

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

Continueing my quest to get the enc28j60 working on the atmega328p..

Yesterday I found some weirdness on the SPI pins (MOSI idle high) that didn't appear to be a problem really.

Today I found something that IS a problem. To me this looks to be a silicon bug, but maybe I'm just missing something, please your thoughts.

I still have the loopback setup, miso connected to mosi (and sometimes Vcc and sometimes GND, to simulate various situations), first the SPI thing must work really well before I start again with the enc28j60.

This works, if I output the results on some leds. But I need to be able to debug properly, so using DebugWire.

It appears everytime I output a byte (write to SPDR), the code hangs. Further investigation makes clear the SPIF bit in SPSR is never set. Hmmm, looks very much like the problem here:

https://www.avrfreaks.net/index.p...

And indeed, it appears the MSTR bit is cleared, SPI is in slave mode, and that explains the lot.

BUT my /SS (aka PORTB2) is OUTPUT. I checked this with the debugger, but also by simply setting the port ON and then indeed it goes "ON".

Also very interesting, when I turn PORTB2 ON, the MSTR bit is no longer cleared and it works.

So to summerise:

- /SS is set to output (like sheet says)
- SPI works when in normal running mode
- SPI goes to slave when run in DebugWire mode, unless /SS is set HIGH

To me that looks like some internal multiplexer is (incorrectly) overriden by DebugWire mode.

Any thoughts, experiences?

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

Providing you have made /SS an output, the AVR will not go haywire.

You must do this before setting SPE bit in SPCR. Otherwise noise on SS input pin will cause haywireability.

If you can provide a minimal example where debugWIRE exhibits a problem, please post it here.

Then I and others can try it for ourselves.

David.

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

Fair enough to not trust such a report immediately, I wouldn't too.

So I went and made a maximal-stripped-down version of the code, which I will quote.

The interesting thing is that this code doesn't show the behaviour, it doesn't go to slave mode in debugwire mode. So, I hear you think: bug in your code, but it's not that simple. I kept adding back code until the phenomenon appeared, and that was a surprise.

The only difference between the two sets of code (difference in RED)

DDRB = 0;
DDRB |= _BV(0) | _BV(2) | _BV(3) | _BV(5);//set /CS, /SS, MOSI and SCK to OUTPUT

Don't ask me why I do it this way, it's only clear from the complete context of the program, normally these two line are not adjacent.

So, the problem is, that the /SS is an input, if only for only a few cycles. BUT that shouldn't be a problem, because the SPI subsystem is not yet enabled at this point. In normal running mode, this doesn't give a problem.

When I disable SPE before enabling it, the problem is gone. This should not be necessary after a RESET imho.

My conclusion: the problem is caused by SPI not being turned off by RESET, and that may be caused by:
- bug in avarice, which I use for debugwire
- bug in avr dragon
- bug in avr-gcc, although less likely

At least not a bug in the atmega.

So, from now on I'll first disable SPE before I enable it, just to be sure, unless no more debugging is necessary.

Source code in next message, if you want to try yourself.

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

eriksl wrote:
BUT my /SS (aka PORTB2) is OUTPUT. I checked this with the debugger, but also by simply setting the port ON and then indeed it goes "ON".
That confirms nothing. Setting PB2 in PORTB when it is an input will enable the internal pull-up resistor. This will read high on a scope or meter.

If you put an external pull-up on SS (say 100K), you can be sure that it's an output by setting PB2 in PORTB low. If it's an output, you will read low on the external pin. If it's an input, you will read high due to the external pullup.

Quote:
Also very interesting, when I turn PORTB2 ON, the MSTR bit is no longer cleared and it works.
That is consistent with normal operation of the SPI peripheral.

Quote:
Further investigation makes clear the SPIF bit in SPSR is never set.
Are you sure? How are you determining this?

The behaviour of the SPI peripheral when SS is an input is to facilitate a multi-master system:

In the datasheet, Atmel wrote:
If the SS pin is driven low by peripheral circuitry when the SPI is configured as a Master with the SS pin defined as an input, the SPI system interprets this as another master selecting the SPI as a slave and starting to send data to it. To avoid bus contention, the SPI system takes the following actions:
    1. The MSTR bit in SPCR is cleared and the SPI system becomes a Slave. As a result of the SPI becoming a Slave, the MOSI and SCK pins become inputs. 2. The SPIF Flag in SPSR is set, and if the SPI interrupt is enabled, and the I-bit in SREG is set, the interrupt routine will be executed.
So MSTR gets cleared, and SPIF gets set.

However, if you have an ISR servicing SPIE, SPIF will be cleared by hardware before you can test for it. The ISR will run, that's how you know that SPIF was set in the first place.

So I ask again:

Quote:
Further investigation makes clear the SPIF bit in SPSR is never set.
Are you sure? How are you determining this?

Quote:
So, the problem is, that the /SS is an input, if only for only a few cycles. BUT that shouldn't be a problem, because the SPI subsystem is not yet enabled at this point.
Again, are you sure? How are you determining this? Have you tested SPE at this point to see if it is enabled?

Quote:
When I disable SPE before enabling it, the problem is gone.
This suggests that in fact you are enabling it somewhere earlier in your code.
Quote:
This should not be necessary after a RESET imho.
Correct. The datasheet is clear on that:
19.5.1   SPCR – SPI Control Register
       Bit            7       6        5    4    3    2    1    0
       0x2C (0x4C)   SPIE    SPE     DORD MSTR CPOL CPHA SPR1 SPR0 SPCR
       Read/Write    R/W     R/W      R/W  R/W  R/W  R/W R/W  R/W
       Initial Value  0       0        0    0    0    0    0    0

Quote:
My conclusion: the problem is caused by SPI not being turned off by RESET, and that may be caused by:
- bug in avarice, which I use for debugwire
- bug in avr dragon
- bug in avr-gcc, although less likely
I would add:
- bug in your code, SPE gets set early on.

Quote:
Source code in next message, if you want to try yourself.
Post the source of your minimal test code, the one that included:
 DDRB = 0; 

Also post the .lss. Dollars to doughnuts you'll see where SPE gets set before SS becomes an input.

JJ

///////////////////////////////////////////////////////////////////////

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Yes sorry, I forgot to include the code. Here it comes. If you read it, you will see most of your questions and objections being answered/cleared.

#include 
#include 
#include 
#include 
#include 

static void sleep()
{
	uint8_t i;

	for(i = 0; i < 100; i++)
		_delay_ms(1);
}
/*
 * B0 = alternative master /SS ("/CS"), pin on B2 is not used
 * B2 = /SS for slave operation, not used
 * B3 = MOSI
 * B4 = MISO
 * B5 = SCK
 * D6 = activity led
 */

int main(void)
{
	cli();

	uint8_t	spdr, spcr, spsr, t;	// DEBUGGING

	PRR =		(1 << PRTWI)	|	// I2C
				(1 << PRTIM2)	|	// timer2
				(1 << PRTIM0)	|	// timer0
				(0 << 4)		|
				(1 << PRTIM1)	|	// timer1
				(0 << PRSPI)	|	// spi
				(1 << PRUSART0)	|	// usart0
				(1 << PRADC);		// adc / analog comperator

	//	pin		spi		i/o
	//	b0 		/cs
	//	b1				oc1a
	//	b2 		/ss		oc1b
	//	b3		mosi
	//	b4		miso
	//	b5		sck
	//	d3				oc2b
	//	d5				oc0b
	//	d6				oc0a

	DDRB = 0;
	DDRB |= _BV(0) | _BV(2) | _BV(3) | _BV(5);		//	set /CS, /SS, MOSI and SCK to OUTPUT
	DDRB &= ~(_BV(4));								//	ensure MISO is INPUT

	PORTB = _BV(0);	//	set /CS idle, HIGH
	
	DDRD = _BV(6);	// D6 = activity led = output

	spcr = SPCR;

	SPCR = 0x00;

	spcr = SPCR;

	SPCR = (0 << SPIE)	|
			(1 << SPE)	|
			(0 << DORD)	|
			(1 << MSTR)	|
			(0 << CPOL)	|
			(0 << CPHA)	|
			(1 << SPR1)	|
			(1 << SPR0);

	spcr = SPCR;

	sei();

	for(;;)
	{
		spcr = SPCR;	// debugging
		spsr = SPSR;	// debugging

		SPDR = 0x55;

		for(;;)
		{	
			spcr = SPCR;	// debugging
			spsr = SPSR;	// debugging

			if(spsr & _BV(SPIF))
				break;
		}

		spdr = SPDR;		// debugging
		spsr = SPSR;		// debugging

		PORTB |= _BV(0);	// B0 = /CS = LOW

		sleep();			//	sleep 100 ms
		PIND |= _BV(6);		//	show activity (or lack of), toggle D6
	}
}

[/code]

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

joeymorin wrote:
That confirms nothing. Setting PB2 in PORTB when it is an input will enable the internal pull-up resistor. This will read high on a scope or meter.

Unless you take the debugger and read out the DDR register... Also please read the complete story. It's not about B2 never being an input. It's about B2 never being an input AFTER SPI has been enabled. And I am pretty sure about that (see code, also I read the DDR register from the debugger).

Quote:
Quote:
Further investigation makes clear the SPIF bit in SPSR is never set.
Are you sure? How are you determining this?

The code TESTS on this, see the source code. Also determined in the debugger.

Quote:

The behaviour of the SPI peripheral when SS is an input is to facilitate a multi-master system:

Please don't quote from the datasheet like I've never read it. The portion on SPI I know by heart, I've read it about 100 times last week. And I understand it as well. From what I told, you should have known that.

Quote:

However, if you have an ISR servicing SPIE, SPIF will be cleared by hardware before you can test for it.

Where do you see the SPIE being enabled? And don't you think the debugger would also jump into the ISR (which isn't even there...)

Quote:

etc. etc. even more assumptions about me being less than thorough.

Quote:

I would add:
- bug in your code, SPE gets set early on.

- bug in joeymorin, not reading message thorougly, making false assumptions.

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

BWT FYI, the problem can be solved by first turning SPI OFF (SPCR = 0x00) and then on again (SPCR = 01010011b).

Right after a RESET this should not be necessary and indeed, in normal running mode, this IS NOT necessary it just works.

But in DebugWire mode, the cpu gets incompletely reset, SPI is still on when entering the user code, so it need to be turned off before it can be turned on (in master mode, when /SS might have been low for maybe only one tick). Yes SPI is on/enabled, AFTER RESET, while in DebugWire, I checked this with the debugger.

Problem is clear, case closed for me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
   PORTB = _BV(0);   //   set /CS idle, HIGH

Surely this sets /CS idle and SS active. And anything else on PORTB.

      PORTB |= _BV(0);   // B0 = /CS = LOW

Seriously, you should take a little care with the honesty / accuracy of your comments. Yes, I know that it may be the way that your mind works. In which case, ignore my whingeing. After all, the comments are for your benefit. If they happen to make sense to your readers, that is a bonus!

As a silly question. Is your code resetting properly? If you have BOOTRST or some wayward code, you can reach location zero without a valid RESET state.

David.

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

Quote:
please read the complete story.
Quote:
Please don't quote from the datasheet like I've never read it. The portion on SPI I know by heart, I've read it about 100 times last week. And I understand it as well. From what I told, you should have known that.
How should I know what your understanding is? Read your first two posts again. There's nothing in there that suggests you have a deep understanding of SPI. The story as posted was incomplete, which is why the questions were asked.

Quote:
etc. etc. even more assumptions about me being less than thorough.
We can only go on what you'd told us, which wasn't much. No code posted, so we can only guess and speculate. If you were thorough, show it. Until then, all suggestions are reasonable.

If you've spent more than a few minutes reading posts on this forum, you know the drill.

And by the way:

Quote:
but maybe I'm just missing something, please your thoughts.
But now all we get from you is defensiveness and snark. I'm out.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

Me forgetting to post the code was my fault, I apologise for that.

But besides that, you assume I've done next to nothing myself, which, yes, I find insulting. Yes I know that's an exception here.

I may not have given every mm of data or source code, from my post you should have had an impression of the amount of effort I've spent and that I am not just saying things, but that I CHECKED all of these.

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

david.prentice wrote:

   PORTB = _BV(0);   //   set /CS idle, HIGH

Surely this sets /CS idle and SS active. And anything else on PORTB.


Which is entirely intentional. But nicely spotted.

Quote:

As a silly question. Is your code resetting properly? If you have BOOTRST or some wayward code, you can reach location zero without a valid RESET state.

I think that is exactly what is happing. Going to DebugWire mode, which is done from a running cpu, seems to not do a proper RESET but simply jump to the RESET vector. I don't know if that's the fault of the avr dragon, avarice or something else.

If it's something of avarice that would explain why many people, using avr studio etc. don't encounter the problem.

I am not using boot loaders, BOOTRST etc.

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

eriksl wrote:
you assume I've done next to nothing myself
I've made no such assumption. You simply hadn't provided any evidence to suggest what work you had done.

Questions of the form "I can't figure this out. I've concluded it can't be 'A'" are going to solicit responses of the form "How have you concluded that?"

Quote:
which, yes, I find insulting.
No insult was or is intended.

Assumptions help no-one. The only assumption we could draw from your OP is that you had a problem with SPI, that you were asking for help, and that you had done some work. What that work had been was not clear. So, how exactly is asking you what it was an insult?

Quote:
should have had an impression of the amount of effort I've spent and that I am not just saying things, but that I CHECKED all of these.
Rubbish. Details matter. Impressions are irrelevant. I find it amusing that you feel free to accuse me of assuming that you've done no work, but in the same breath suggest that I should be able to assume what work you have done, and what level of expertise you have.

If anything, and absent information to the contrary, an OP's previous threads can be used to gauge his level of experience and expertise:

eriksl wrote:
I am new to the SPI-on-atmega
...
I am debugging a SPI problem and it strikes me that MOSI is idle HIGH.
...
I don't expect it to be idle HIGH.
What does this let me assume? That you're new to SPI-on-atmega, perhaps? Or am I to conclude that in the 21 hours since you posted the above that you have become the goto atmega SPI expert...?

What else?

Well, perhaps that you haven't commited the datasheet to memory, since a casual glance at the timing diagram reveals that MOSI idles high.

And yet:

Quote:
Please don't quote from the datasheet like I've never read it.
Strange.

We can't assume you are an expert. You must demonstrate you are. A few minutes of browsing these fora easily reveals a sad history of ghost-chasing because of assumptions made and basic questions not asked. Nobody here likes to chase ghosts.

I'm afraid I'm at a loss to understand how any of my questions could possibly have insulted you. Since they did though I apologise.

In future you may wish to consider being more gracious when responding to those from whom you have solicited free advice. They will care more about your problem. Getting defensive, making unsupported assertions, and attempting to elevate yourself by belittling others... these things are generally met with the sound of crickets.

Good luck with your project.

JJ

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]