Strange problem - sketch works on Uno but not Mega2560

Hi all,

I was trying to adapt the "Arduino as ISP" sketch to use software (bit-bang) SPI rather than hardware SPI so that I could use either an Uno or Mega 2560 board to burn bootloaders and other code.

I wrote a very simple SPI driver and it works just fine on the Uno:

spi.cpp

#include "spi.h"

void spi::init(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t mode)
{
        _sck_pin = sck;
        _miso_pin = miso;
        _mosi_pin = mosi;
        _spi_mode = mode;

        digitalWrite(_sck_pin, (_spi_mode % 2) ? HIGH : LOW);

        pinMode(_sck_pin, OUTPUT);
        pinMode(_miso_pin, INPUT);
        pinMode(_mosi_pin, OUTPUT);
}

uint8_t spi::transfer(uint8_t data)
{
        uint8_t n = 0x80;
        do {
                digitalWrite(_mosi_pin, data & n);
                digitalWrite(_sck_pin, (_spi_mode % 2) ? LOW : HIGH);

                if (digitalRead(_miso_pin)) {
                        data |= n;

                } else {
                        data &= ~n;
                }
                digitalWrite(_sck_pin, (_spi_mode % 2) ? HIGH : LOW);

        } while (n /= 2);
        return data;
}

spi.h

#ifndef _SOFTWARE_SPI
#define _SOFTWARE_SPI

#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class spi {
public:
        void init(uint8_t, uint8_t, uint8_t, uint8_t);
        uint8_t transfer(uint8_t);
private:
        uint8_t _sck_pin;
        uint8_t _miso_pin;
        uint8_t _mosi_pin;
        uint8_t _spi_mode;
};

#endif

To use it, all you do it create an spi object, then init() the code, then use the spi object:

#define sck  13
#define miso 12
#define mosi 11
#define ss   10
#define mode 0

static spi spi; // spi object

    pinMode(ss, OUTPUT);

    spi.init(sck, miso, mosi, mode);
    digitalWrite(ss, HIGH);
    returncode = spi.transfer(0x??); // write
    digitalWrite(ss, LOW);

As simple as can be. Works great on the Uno R3 board.

But if I try to use the same code on a Mega 2560 R3 board, it doesn't work!

Now I know that the 2560 HARDWARE SPI pins are different numbers, but I am not using that. I am using plain old "digitalRead" and "digitalWrite".

If I write to, say, pin 10, it shouldn't matter which board I'm using. 10 is 10. Right?

Anyone have an idea what the problem could be?

Thanks.

-- Roger

No clue what the problem is, but I don't like this:

static spi spi; // spi object

Having a class instance with the same name as the class just looks dumb.

Krupski:
Anyone have an idea what the problem could be?

No, but if it's any consolation I'm doing pretty much the same thing trying to combine software SPI with RF24 and that isn't working properly either. I've looked and looked for logic faults and I'm beginning to wonder whether it might be a timing issue. In my case I've made the SoftwareSPI a subclass of the Hardware SPIClass, although that did need some minor tweaks due to the weird way the class was implemented.

What's the objection to using the SPI pins (conveniently located on the ICSP header) on the Mega? Then all you need is a wire to Pin 50 (? the SS pin)

CrossRoads:
What's the objection to using the SPI pins (conveniently located on the ICSP header) on the Mega? Then all you need is a wire to Pin 50 (? the SS pin)

If I use an ISP shield (home made or from Sparkfun) it is setup to use pins 13, 12, 11 and 10 (the standard UNO SPI pins). The Mega2560 of course has a different pinout (WHY, I have no idea).

Anyway, if I use a software (bit bang) driver, then the ISP shield should work on any board.

What I am trying to do is build a stand alone bootloader programmer. What it will do is attach to another Arduino board via a 6 pin ICSP connector or else plug a bare chip into the ZIF socket. The programmer will then read the ID bytes of the chip and burn the appropriate bootloader from PROGMEM in the programmer -> to the new chip or board.

It's very similar to the code that Nick Gammon wrote, except that instead of storing hex numbers in PROGMEM and decoding them, the bootloaders will be stored as raw binary.

The whole point is that this is is going to be used in a teaching lab where the students use their own Arduino MEGA 2560 boards. The lab hardware is going to consist of a baseplate with all kinds of goodies attached (the MEGA 2560 board, a graphic 128 x 64 VFD display, a 4 digit seven segment display, a piezo beeper, a little DC motor with a wheel on it (with optical encoder), two 10K linear taper potentiometers, a 4 x 4 hex keypad, 8 general purpose LED's and a breadboard area).

Kinda like a super duper version of an Esplora board. :slight_smile:

Their first task is going to be to burn the bootloader into the MEGA board, because when they first get the hardware, it's going to have an erased 2560 on it.

My basic question is, why would "digitalWrite(13, HIGH or LOW)" be different on a MEGA versus an UNO?

I checked it on an oscilloscope and there's no difference. A sketch to pulse those pins compiled on each board (MEGA and UNO) results in exactly the same signals.

I even thought maybe I had a bad or blown 2560 board, so I tried another one... same difference.

I'm not willing to just say "heck with it" and use hardware SPI or an UNO board. This SHOULD work and I want to find out why it doesn't.

It will bug me forever unless I figure it out!

PaulS:

static spi spi; // spi object

Having a class instance with the same name as the class just looks dumb.

And this helps me how?