EEVblog Electronics Community Forum

Electronics => Projects, Designs, and Technical Stuff => Topic started by: MrAureliusR on September 03, 2013, 07:51:34 pm

Title: Need help with SPI on AVR
Post by: MrAureliusR on September 03, 2013, 07:51:34 pm
Hi there. I'm making my first foray into SPI communication between chips. I'm using an ATmega32A and a Microchip 25AA640A Serial EEPROM. At this point, I'm literally just trying to get communication working. I'm trying to send junk data back and forth. My C is okay, I definitely am a learner though. Here's the code I've written (keep in mind, I'm trying to keep it basic -- please feel free to point out the many obvious errors I've made  :-+ )

Code: [Select]
#include <avr/io.h>

int main(void)
{
int data; // declaring junk variable

DDRB |= (1<<4)|(1<<5)|(1<<7); // I'm fairly sure I've got these pins right, setting MOSI, SCLK and SS as outputs
DDRB &= (~1<<6); // and setting MISO as an input

SPCR |= (1<<SPE); // enable SPI
SPCR |= (1<<SPIE); // not sure if both of these are necessary as the correct fuse bit is set
SPCR |= (1<<MSTR); // setting the ATmega as master
SPCR |= (0<<CPOL)|(0<<CPHA); // setting clock polarity and phase
SPCR |= (1<<SPR0)|(1<<SPR1); // setting oscillator frequency (currently clk/128)

data = 00000110; // write enable on the 25AA640A?? I picked this at random, but also because it's supposed to be the write enable byte

    while(1)
    {
        SPDR = data;
while(!(SPSR & (1<<SPIF)));

    }
}

After loading up the AVR (I can see the write process from my AVRISP mkII) nothing happens. I wanted it to infinitely loop so I could watch it with my scope/LA.

I'm sure it's something painfully obvious, and I've been Googling for hours but there's not much good info with using SPI on an AVR. Lots of theory but very little practical implementation of coding...
Title: Re: Need help with SPI on AVR
Post by: TerminalJack505 on September 03, 2013, 08:07:47 pm
Try replacing this line:

Code: [Select]
DDRB &= (~1<<6); // and setting MISO as an input

With this:

Code: [Select]
DDRB &= ~(1<<6); // and setting MISO as an input

Or, just comment-out the line.
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 03, 2013, 08:10:10 pm
TJ's got it. ~1<<6 is 11000000. By and'ing this with DDRB you're clearing the output bits you just set.

DDRB starts out as zero after reset, so you don't need to clear bits that aren't already set. (If it makes you feel safe, put a DDRB=0 before the assignments to make sure.)

Additionally:
You do not need SPIE unless you plan on using interrupts. With that flag set, if interrupts are turned on, the chip will generate an interrupt when a transfer completes (you can use this to buffer your data transfers to do a "background" transmission instead of having to busy-loop checking SPIF - save this for after you get basic SPI running). And keep in mind that you won't much like the results of having an interrupt fire for which no handler exists (the chip will reset).

Also, you need to manually toggle #SS - pull it low before you transmit and high after. Otherwise, the data will be transmitted, but the EEPROM will ignore it.
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 03, 2013, 08:14:13 pm
Okay, I fixed that line, but there's still no output after the chip is programmed. Is my while loop actually infinite?
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 03, 2013, 08:23:03 pm
Yes, it is.

Temporarily replace the SPI transmission with a pin toggle, and stick a scope on that pin. Make sure you haven't messed up the fuse settings and the clock is running.
Title: Re: Need help with SPI on AVR
Post by: TerminalJack505 on September 03, 2013, 08:25:17 pm
Make sure to get rid of this instruction:

Code: [Select]
SPCR |= (1<<SPIE);

Like c4757p says, it can cause your MCU to reset since you don't have an interrupt handler setup.
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 03, 2013, 08:27:32 pm
It's not the problem, though, unless he's hiding an sei()  from us; the chip boots with interrupts disabled.
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 03, 2013, 10:51:32 pm
Hmm I'll be back home in a bit. What I want to do to keep it simple and to learn is to write a number into the EEPROM and then read it back and display it with LEDs or something. Maybe assign a button to each LED so I can input the number.

Does anyone know of good online resources for programming ISP for AVRs? I can't find the right info. I'm trying to find a simple project like I mentioned to get the basics down.

Sent from my HTC Desire C using Tapatalk 4

Title: Re: Need help with SPI on AVR
Post by: Psi on September 03, 2013, 11:02:18 pm
- This line is wrong too
SPCR |= (0<<CPOL)|(0<<CPHA); // setting clock polarity and phase

(0<<X) will always produce zero
So you're going  SPCR = SPCR bitwise-or 0 bitwise-or 0  which will have no effect on SPCR.

This isn't your problem though because CPOL and CPHA are zero already. (they're initial state is zero)

- This line doesn't do what you intended
data = 00000110;

That will set the data variable to 110 in base 10.  You need to add 0b if you want to enter binary like that.

data = 0b00000110;

( For hex you can use 0x   etc..  data = 0x06  )


- I would move the SPI enable line until after you finish setting up the SPI registers. Sometimes things get lost if you try and configure hardware while its running.



Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 01:17:07 am
Looking better?

Code: [Select]
#include <avr/io.h>

int main(void)
{
int data;


DDRB |= (1<<4)|(1<<5)|(1<<7);
DDRB &= ~(1<<6);
SPCR |= (1<<MSTR);
SPCR |= (0<<CPOL)|(0<<CPHA);
SPCR |= (1<<SPR0)|(1<<SPR1);
SPCR |= (1<<SPE);

data = 0b00000110; // write enable on the 25AA640A??

    while(1)
    {
        SPDR = data;
while(!(SPSR & (1<<SPIF)));

    }
}

Or should I drop the SPCR |= (0<<CPOL)|(0<<CPHA); entirely?
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 01:19:02 am
Yup. Looks good to me :-+

Yes, I think you should drop that line, just because it looks kind of... well, stupid. ;) It doesn't do anything.

In fact, the whole thing could become:

Code: [Select]
#include <avr/io.h>

int main(void)
{
    DDRB = (1<<4) | (1<<5) | (1<<7);
    SPCR = (1 << MSTR) | (3 << SPR0) | (1 << SPE);

    while (1) {
        SPDR = 0b00000110;
        while (!(SPSR & (1 << SPIF)));
    }

    return 0;
}
Title: Re: Need help with SPI on AVR
Post by: Psi on September 04, 2013, 02:03:41 am
Just to make it easier to read, he could also replace
 DDRB = (1<<4) | (1<<5) | (1<<7);
with
 DDRB = (1<<PB4) | (1<<PB5) | (1<<PB7);

I prefer using =| rather than = when changing registers.
  Just because it's a good habit to get into to avoid overwriting bits. However for this code it doesn't matter and = ensures the other bits are zero
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 02:31:02 am
Hmmm...

I even ended up copying and pasting the concatenated version that c4757p posted, still no outputs. I have a probe on MOSI and MISO, and when I hit F5 in Atmel Studio, as I mentioned before, I can still see the AVRISP programming the device, but then after that everything just goes dead.

I've tested the chip with another program to make sure it's not the chip that's bad...

I feel like I'm missing something obvious. The fuses are programmed as follows:

ON:
SPIEN
EESAVE (doesn't really matter if it's on or off, correct?)
BOOTSZ = 2048W_3800
SUT_CKSEL = INTRCOSC_1MHZ_6CK_64MS_DEFAULT (although I've also tried it with a 20MHz crystal, a 14.7456MHz crystal, and a 6.0MHz ceramic resonator...)

Lock bits are off, JTAG disabled... it's programming the chip perfectly. Maybe I'll pop it out and try programming it with my TL866CS???
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 02:39:50 am
Just to make it easier to read, he could also replace
 DDRB = (1<<4) | (1<<5) | (1<<7);
with
 DDRB = (1<<PB4) | (1<<PB5) | (1<<PB7);

I prefer using =| rather than = when changing registers.
  Just because it's a good habit to get into to avoid overwriting bits. However for this code it doesn't matter and = ensures the other bits are zero

I prefer = in this case, because I'm setting the whole register. I'm configuring which ones are inputs and which are outputs - I want to know right then and there which one is which before I screw up and drive a voltage up some other chip's output. Unless you're bit-banging an open collector or bidirectional interface, you're unlikely to change the DDR registers once the chip is initialized.
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 02:41:12 am
Did you try changing your code from SPI to just flipping a bit? Don't put in a whole other program, you don't want to accidentally fix your problem when you do that - just comment out the SPDR and SPIF lines and put in a bit toggle.
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 02:42:33 am
@ c4757p I will try that right now and post back in a cpl mins. Also:

I don't know if it'll make a difference, but I've also got an ATmega644A, an ATmega324A, PIC18F4685, PIC18F4450... I could try any one of those.

EDIT: Here's what I changed it to... nothing on PB4!!

Code: [Select]
#define F_CPU 250000UL
#include <avr/io.h>
#include <util/delay.h>


int main(void)
{
DDRB |= (1<<PB4) | (1<<PB5) | (1<<PB7);
// SPCR = (1 << MSTR) | (3 << SPR0) | (1 << SPE);

while (1) {
// SPDR = 0b00000110;
// while (!(SPSR & (1 << SPIF)));
PORTB &= ~(1 << PB4); /* bit on */

_delay_ms(75);

PORTB |= (1 << PB4); /* bit off */

_delay_ms(40);
}

return 0;
}

I'm going to switch over to the 644A I think... unless I made a glaring error in the above code. Turning an LED on and off is a specialty, so I don't think I screwed that up  :-+
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 02:45:25 am
Don't give up and go to another chip. The 32A has perfectly good SPI facilities, it's good troubleshooting practice to get them running.
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 02:49:18 am
EDIT: Here's what I changed it to... nothing on PB4!!

Bingo. OK, what are your full fuse bits?


Also... your "bit on" and "bit off" comments are backwards. |= sets the bit, &= ~ clears it.
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 02:53:14 am
Full fuse bits are HIGH: 0xD1 LOW: 0xE1

By the way, thanks a million for taking the time to help me c4757p, I seriously appreciate it!

EDIT: Just changed HIGH to 0xD9, turning EESAVE off, no effect.
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 03:09:16 am
Low:
0xe1 = 11100001 = internal 1MHz oscillator, no BOD, SUT = 16 k ck/4.1ms

Try changing that to 16 kck/65ms (SUT = 11, low fuse = 0x11110001).

High:
0xd1 = 11010001 = SPI programming enabled, no bootloader

Other than the SUT change I suggested, everything looks good. (You'd be surprised how often that can be the cause. That switch matrix I just built with a mega168 needs to wait the full 65ms or else it malfunctions in bizarre ways.)
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 03:11:27 am
It already is at 6CK_64MS, that's what I'm getting for 0xE1 on the low fuse byte... strange.

EDIT: Did you accidentally put 0xD1 for both? That would give 6CK_4MS for the clock.
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 03:14:13 am
I must have mucked up the decoding. As long as you're setting them using some interface rather than manually plugging bits off the "Fuse Bits" table I'll assume you have them right, since you've already quoted to me what the settings are and they sounded good.

Hmm.... OK, basics. Are you 100% certain you're looking at the right pin, and your oscilloscope is set up to expect the right voltage and frequency? ???

Try it with a different pin on a different port, I guess there's always the chance that one's blown.

Set your probe to AC coupling, zoom in to the highest vertical sensitivity and a timebase near the chip's clock frequency, probe directly on a power or ground pin right at the chip package, and see if you pick up clock noise.

Also, do you know how to get the assembly language output from the compiler? (If you're using GCC, give the -S flag. If you're in AVR-Atmel-whateverthehelltheycallitnow-Studio, I can't help you there.) Post it.
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 03:16:53 am
There's a crap-ton of 1MHz clock noise near the ground pin. I'll try a different port and different pin, just see if I can get an LED blinking.

There's also about 40 or so mV of 60Hz mains noise... which seems higher than in my old place. Not sure why that is.

EDIT: OMG!!! I unplugged the AVRISP's entire plug from the breadboard, and voila! PB4 is switching just as programmed... that's bizarre. I've never had the programmer interfere that badly! The 60Hz noise almost disappeared afterward.
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 03:25:19 am
I've seen programmers hold the chip in reset, depending on the configuration - not sure about AVRISP. The mains noise is probably a completely unrelated coincidence caused by a ground loop involving the USB port and the oscilloscope. 40mV isn't too much.
Title: Re: Need help with SPI on AVR
Post by: Psi on September 04, 2013, 03:25:33 am
Be sure to double check your MCU has a good 5V power and ground connection.
It's really easy to assuming your MCU has power because you can reprogram it. However this is a bad assumption.
Often you can reprogram the chip with only the programmer connected because power will flow into the i/o lines and partly power up the mcu.

Edit: I see you got it working by unplugging the programmer. Yeah, as c4757p said. Reset is probable the issue. The programmer was probably holding it low.

Most programmers have an option for the RESET output.
This isn't applicable to you but when i program stuff with the printer port using avrdude i have to use "-E noreset" so the mcu is set to "run" state after the reprogram is complete.
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 03:28:06 am
The MCU definitely has power.

Just tried the original program, with the SPI byte, and it's working like a charm with the AVRISP unplugged.

About a month ago I accidentally put 120VAC into my breadboard, which had the AVRISP attached at the time. It seemed to be fine afterwards, but I've started to notice little quirks like this. I guess it's time to replace it... I also have a USBASP but I'm not a huge fan of it. I'd rather get another AVRISP mkII, or even a step up, like the AVR Dragon I think it's called?
Title: Re: Need help with SPI on AVR
Post by: Psi on September 04, 2013, 03:33:57 am
About a month ago I accidentally put 120VAC into my breadboard, which had the AVRISP attached at the time. It seemed to be fine afterwards, but I've started to notice little quirks like this. I guess it's time to replace it... I also have a USBASP but I'm not a huge fan of it. I'd rather get another AVRISP mkII, or even a step up, like the AVR Dragon I think it's called?

It could also be the breadboard itself. Even a good breadboards can give connection problems.
Did the 120V short out ? it may have coated parts of some holes internally with carbon and be causing bad connections. Or the heat may have removed the "spring"ness of the metal inside the holes
Title: Re: Need help with SPI on AVR
Post by: c4757p on September 04, 2013, 03:36:49 am
Don't forget the very likely possibility that the breadboard has always been a giant turd, like mine...
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 03:52:59 am
It was a different breadboard that took the beating... and I'm using my smallest breadboard, but it's also the best quality one of the three I have. My huge one is the next best, so maybe I'll switch over to that, but it's covered in Z80 et alii...

By the way, here's a picture of my sweet, sweet, success!  :-/O

(http://i.imgur.com/nkfXdPX.jpg)

For some reason, the output of the slave is very weak. Here it appears as a really low duty cycle, but on the scope it looks... well.. a bit wonky. Very weak, all logic 1's, and they're at different levels, they look capacitatively loaded (is capacitatively a word?)

EDIT: Duh, it's ghosting the clock line.  :palm:
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 05:27:53 am
(http://i.imgur.com/YcCGJh5.jpg)

I DID IT!!

I successfully wrote to my EEPROM. I know this seems like a small thing but after all the hell I've gone through trying to get it working, this is like seeing the light! No arduino, no raspberry pi, just a breadboard, some wires, and a couple chips! Man I'm proud of myself.
Title: Re: Need help with SPI on AVR
Post by: Psi on September 04, 2013, 06:55:09 am
I DID IT!!

I successfully wrote to my EEPROM. I know this seems like a small thing but after all the hell I've gone through trying to get it working, this is like seeing the light! No arduino, no raspberry pi, just a breadboard, some wires, and a couple chips! Man I'm proud of myself.
Well done.  You're now an electronic engineering, please don't use your new powers for evil.   :-+


I see you have a 150ms delay in your write loop. Your eeprom thanks you for that decision.
Without that delay it would wear out the eeprom in no time at all.

Better not leave it running though, even 150ms is still 6.66 writes per second.   
  100,000 writes / 6.66 = 15151 seconds = 252 minutes = 4 hours until eeprom dead.
Title: Re: Need help with SPI on AVR
Post by: MrAureliusR on September 04, 2013, 07:13:58 am
I wouldn't say I'm an EE yet. Wait till I have my diploma in 2-3 yrs.

Yeah I kept that in mind when running the program. I ran power to the ATmega for a few seconds at a time.

Next step is to write only when a button is pressed. I really need to learn how to use 7-segment displays. I want to create a PDP like switching panel for entering data into the Z80/EEPROM/RAM...

Typed using Hacker's Keyboard for Android

Title: Re: Need help with SPI on AVR
Post by: mariush on September 04, 2013, 02:09:09 pm
Have a look at this page, scroll down and it explains led 7segment displays and other things :

http://www.mikroe.com/chapters/view/17/chapter-4-examples/ (http://www.mikroe.com/chapters/view/17/chapter-4-examples/)