Replacing SPI with shiftOut?

Hi there.

So I am trying to interface with the MAX7219. I can get it working fine using SPI, however I don't want to be limited to the hardware SPI pins so I am trying to use the shiftOut function instead of the SPI but I cannot get it to work.

This code works - however I am limited to using the hardware SPI pins.

  byte modeReg = 0x0f;
  byte testModeOn = 1;  
//Turn on test mode
  digitalWrite(csPin, LOW);
  SPI.transfer(modeReg);
  SPI.transfer(testModeOn );
  digitalWrite(csPin, HIGH);

I don't want to be limited to the pins I use so I unsuccessfully tried to do:

  byte modeReg = 0x0f;
  byte testModeOn = 1;

  digitalWrite(csPin, LOW);
    shiftOut(dinPin, clkPin, MSBFIRST, modeReg); 
    shiftOut(dinPin, clkPin, MSBFIRST, testModeOn); 
  digitalWrite(csPin, HIGH);

Any ideas how to get it working?

Thanks!

If you're trying to use shiftOut to talk to the SPI slave on the MAX, that won't work. Read up on how SPI works - there's a lot more to it than simply shifting out 8 data bits. It is entirely possible to make (low-speed) SPI work using almost any I/O pins, but you MUST implement the SPI protocol, which is non-trivial.

Regards,
Ray L.

digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, registerAddress); // address 0x01 to 0x0F, 0x0D not used
shiftOut(dataPin, clockPin, MSBFIRST, relevantData); // as needed
digitalWrite(latchPin, HIGH);

Why does that take so much discussion?

Can use any pins as long as you define them first - I usually make them global - so define before setup() :

byte latchpin = 2;
byte dataPin = 3;
byte clockPin = 4;

in setup():
pinMode (latchPin, OUTPUT);
pinMode (dataPin, OUTPUT);
pinMode (clockPin, OUTPUT);

Delta_G:
What is the aversion to using the SPI pins? What do you need on those pins that you can't do with other pins?

I just wanted the flexibility of being able to add a display (the MAX7219) to an existing setup and not have to worry about modifying the SPI bus or anything else that was already on the SPI pins.

CrossRoads:
Can use any pins as long as you define them first - I usually make them global - so define before setup() :

byte latchpin = 2;
byte dataPin = 3;
byte clockPin = 4;

in setup():
pinMode (latchPin, OUTPUT);
pinMode (dataPin, OUTPUT);
pinMode (clockPin, OUTPUT);

It happened again! A simple mistake caused me hours of headaches. I FORGOT the PINOUTS. Thanks again CrossRoads.

It is working perfectly now.

All AVR serial ports are capable of full speed master mode SPI.
The Mega2560 has 4 hardware serial ports and a Bobuino has 2.
If you don't use the USB link, the 1 serial port of small Arduinos will do too.
Perfect for hanging dedicated devices you don't want to open/close/open/close on.
If you want to copy files between 2 SD cards, 2 SPI buses can speed that up incredibly.

Many ways to do SPI including Arduino as slave and serial port SPI.

Delta_G:
The MAX7219 uses SPI, so it wouldn't matter if you had something else on the SPI bus. You can have several things sharing the SPI bus at the same time. They only need separate CS pins. That's the point of having the dedicated bus, so many things can share the same pins. If you try to create a "software SPI" for one of them then you are needlessly giving up 3 pins on your Arduino that could be doing something else.

that's true but if I have an SD card on that bus and wanted to shovel SD data through the MAX7219, the very act of switching the SD off to switch the MAX on means the SD has to reinitialize, open the file and set the seek whereas if they are on different SPI buses there is no need to do that every time the buffer gets full.

Do you remember copying files between floppy disks with only one FD, no HD, and 64K or less RAM?
Compare to the same operation with 2 FD's. That's why more than one SPI bus can make a big difference.

Delta_G:
So an SD card closes the file if I pull the SS pin to HIGH? I figured it would just sit until I pulled SS low and started talking to it again.

My understanding from the docs is that the card turns off when it's deselected.
I would not count on the card closing the file for me. My code should do that before deselect if I've been writing to file to ensure that the FAT is updated.
Perhaps a test is in order but I'm past bedtime already.

No. Have a look at the code for any of the small TFT screens that come with an SD card on the shield. They all have an example sketch which loads a BMP image from the SD card onto the screen. There isn't enough memory on an Arduino to hold the whole image, so it has to work in small chunks. Raising the CS for the SD card doesn't break the file that's currently open.

Bit-banged SPI on this page: Gammon Forum : Electronics : Microprocessors : SPI - Serial Peripheral Interface - for Arduino

MorganS:
No. Have a look at the code for any of the small TFT screens that come with an SD card on the shield. They all have an example sketch which loads a BMP image from the SD card onto the screen. There isn't enough memory on an Arduino to hold the whole image, so it has to work in small chunks. Raising the CS for the SD card doesn't break the file that's currently open.

Are you saying that because the buffer is smaller than the image that therefore the SD card stays on point?

I need to see code, not assumptions. I spent too many years learning that lesson.

So I modified a modified SD example to deselect and select with a delay between and I found out that yes, the SD card does "hold position" which is great news to me!

I must have been really tired last night. I was thinking I'd have to do a bunch of cut and splice to hang two devices on the bus (got the SD module on jumpers) to test and then this morning I see there's no need for that.

// Testing SD Module connected to Arduino UNO
// This UNO is running IDE version 1.61

// Arduino SPI library and SD library are imported using the
// Sketch->Import Library pop-down menu. Both are standard.
// SD Lib reference: http://arduino.cc/en/Reference/SD

// This sketch demonstrates writing a struct to file as a block and
// reading it back to a struct.

// Connections:
// SD Module pin --- UNO pin
// GND --- GND
// 3.3V --- 3.3V
// 5V --- 5V
// CS --- 10
// MOSI --- 11
// SCK --- 13
// MISO --- 12
// GND --- GND

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <SPI.h>
#include <SD.h>

#define CARD_CS 10

struct myVars
{
  byte  b0;
  byte  b1;
  int   i2;
  int   i3;
  char  s4[ 20 ];
};

char addedText[] = "\n Here is some text appended to the data.";

const byte testSelectOffOn = 1;


// ====================================================================

void setup(void)
{
  pinMode( CARD_CS, OUTPUT );
  digitalWrite( CARD_CS, LOW );

  Serial.begin( 115200 );

  byte  count;

  struct  myVars  example; // creates space for struct example in SRAM
  struct  myVars  copyto; // creates space for struct example in SRAM
  byte    *buff = (byte *) &example; // to access example as bytes

  example.b0 = 1;           // fill example with test data, copyto stays empty
  example.b1 = 20;
  example.i2 = 3000;
  example.i3 = 4000;
  strcpy( example.s4, "file is test.txt" );

  File  sdfile;      // File object
  char  fname[ 14 ]; // even # of bytes big enough to hold 8.3 filename and terminator
  strcpy( fname, "test.txt" );


  // ========== SD begin ====================================

  byte flag = SD.begin( ); // test if card is recognized

  Serial.print( F("SD card status " ));
  Serial.print( flag, DEC ); // show success as 1, fail as 0
  if ( !flag )
  {
    Serial.println( F( " Failed to recognize SD card. Goodbye." ));
    while ( 1 );   // if fail then sketch ends
  }
  else
  {
    Serial.println( F( " is good to go." ));
  }

  // ========== SD open/create file to write ============================

  strcpy( fname, "test.txt" );
  sdfile = SD.open( fname, FILE_WRITE );
  if ( !sdfile )
  {
    Serial.print( F( "Unable to open for write: " ));
    Serial.println( fname );
    while ( 1 ); // sketch stops if reach here
  }

  // ========== SD write struct to file =================================
  // this file will only contain 1 struct although it could hold many
  // since opening a file that already exists for write will start at the end
  // we will set the read/write pointer at the start so as not to grow the file

  if ( !sdfile.seek( 0 ))
  {
    Serial.print( F( "Unable to set seek: " ));
    Serial.println( fname );
    while ( 1 ); // sketch stops if reach here
  }

  count = sdfile.write( buff, sizeof( myVars ));
  if ( count != sizeof( myVars ))
  {
    Serial.print( F( "Unable to write the example block to " ));
    Serial.println( fname );
    Serial.print( count, DEC );
    Serial.println( F( " bytes written." ));
    while ( 1 ); // sketch stops if reach here
  }

  sdfile.println( addedText );

  // ========== SD close file ===========================================

  sdfile.close(); // I could error check this. If it fails the next open will too.

  // ========== SD open file to read ====================================

  sdfile = SD.open( fname, FILE_READ ); // try to open text.txt
  if ( !sdfile ) // if test.txt not found, notify and change state
  {
    Serial.print( F( "Unable to open for read: " ));
    Serial.println( fname );
    while ( 1 );
  }

  // ========== SD read file to struct ==================================

  buff = (byte *) &copyto; // to access copyto as bytes


  for ( count = 0; count < sizeof( myVars ); count++ )
  {

    if ( sdfile.available())
    {
      *( buff + count ) = sdfile.read();
    }
    else
    {
      Serial.print( F( "Unable to read the example block in " ));
      Serial.println( fname );
      Serial.print( count, DEC );
      Serial.println( F( " bytes read." ));
      while ( 1 ); // sketch stops if reach here
    }
  }

  if ( testSelectOffOn )
  {
    Serial.println( F( "\n\nSD Select Test\n" )); 
    digitalWrite( CARD_CS, HIGH );
    delay( 1000 );
    digitalWrite( CARD_CS, LOW );
  }

  char ch;
  do
  {
    ch = sdfile.read();
    if ( ch && ch != EOF )
    {
      Serial.write( ch );
    }
    else
    {
      ch = 0;
    }
  }
  while ( ch );

  // ========== SD close file ===========================================

  sdfile.close(); // I could error check this too.

  // ========== print retrieved data ====================================

  Serial.print( F( "\n Data in copyto block from " ));
  Serial.println( fname );
  Serial.print( F( "\ncopyto byte b0 " ));
  Serial.println( copyto.b0, DEC );
  Serial.print( F( "copyto byte b1 " ));
  Serial.println( copyto.b1, DEC );
  Serial.print( F( "copyto byte i2 " ));
  Serial.println( copyto.i2, DEC );
  Serial.print( F( "copyto byte i3 " ));
  Serial.println( copyto.i3, DEC );
  Serial.print( F( "copyto string s4 " ));
  Serial.println( copyto.s4 );

  // ========== finished ================================================

}

void loop(void)
{
}