7-segment 4 digit display (COM-09765) and the SPI library

Hi.

Yesterday I got a 7-segment 4 digit display (this one: COM-09765, http://www.sparkfun.com/datasheets/Components/LED/7-Segment/SFE-0012-DS-7segmentSerial-v41.pdf), and I've been trying to make it work with the Arduino.

Implementing the serial protocol was really simple, and an implementation of the SPI protocol was no too difficult either thanks to several examples (without microprocessor SPI registers like SPCR, etc... because I didn't really dig into the documentation and I don't think speed is a requirement right now for me).
The issue I found is that, when using the default SPI library (Arduino Alpha 0022), the display suddenly enters into command mode, stars displaying "A"s, "5"s, "2"s,... in pairs, enables the dots,... Could it be that SPI.transfer doesn't do what spi_transfer does? I'm struggling to understand the issue here.

Thanks in advance.

This are the pins I'm using:

const int SS   = 10;
const int MOSI = 11;
const int MISO = 12;
const int SCK  = 13;

And this is the code (you can see the spi_transfer function I was using on my explicit implementation of SPI, commented out).

#include <SPI.h>

const int aa   = 10;

void setup() {
  pinMode (aa, OUTPUT);

  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);
  
  digitalWrite(aa,HIGH); //disable device
  delay(2000);
  spi_out_command(0x76, 'x');
  // brightness setup (will wear out the flash or eeprom with every write).
  //spi_out_command(0x7A, 0x00);
  
  spi_out_display('h','o','l','a');
  delay(2000);
  
  // TTL Serial interface
  //Serial.begin(9600);
  //Serial.print("v");
}

/*
void spi_transfer(byte command) {
  for(int i = 1; i <= 8; i++) { // setup a loop of 8 iterations, one for each bit

    if (command > 127) { // test the most significant bit
      digitalWrite (MOSI,HIGH); // if it is a 1 (ie. B1XXXXXXX), set the master out pin high
    } else {
      digitalWrite (MOSI, LOW); // if it is not 1 (ie. B0XXXXXXX), set the master out pin low
    }

    digitalWrite (SCK,HIGH); // set clock high, device will read
    command = command << 1;
    digitalWrite(SCK,LOW); // set clock low, device will stop reading
    //delay(10);
  }
}

*/
void spi_out_command(byte command, byte data) {
  digitalWrite(aa, LOW); // enable device
  delay(30);
   SPI.transfer(command);    // command
   if ( command != 0x76 ) {
     SPI.transfer(data);    // data
   }
  digitalWrite(aa, HIGH); // disable device
}

void spi_out_display(byte digit1, byte digit2, byte digit3, byte digit4) {
  digitalWrite(aa, LOW); // enable device
    delay(30);
   SPI.transfer(digit1);    // Thousands Digit
   SPI.transfer(digit2);    // Hundreds Digit
   SPI.transfer(digit3);    // Tens Digit
   SPI.transfer(digit4);    // Ones Digit
  digitalWrite(aa, HIGH); // disable device
}

void spi_out_number(unsigned short num, unsigned short base) {
  unsigned short digit[4] = { 0, ' ', ' ', ' ' };
  if ( (base<2) || (base>16) || (num>(base*base*base*base-1)) ) {
    spi_out_display('x', 'x', 'n', 'o');  // indicate overflow
  } else {
    unsigned short place = 0;
    while ( num && place < 4 ) {
      if ( num > 0 ) digit[place++] = num%base;
      num /= base;
   }

    spi_out_display(digit[3], digit[2], digit[1], digit[0]);
  }
}


void loop() {
 for (int i = 0; i < 9999; i++) {
    spi_out_number(i, 103);
   // this is to always trigger the same error message "  no"
    
    // TTL Serial interface
    //Serial.print(i);
    delay(1000);
 }
}

These displays work fine for me with SPI. You may be trying to run the SPI bus too fast. From my code:

    //The SparkFun display doc says max SPI clock freq is 250kHz.
    //Arduino Uno has a 16MHz clock, so we cannot use a clock divider less than 64.
    //250kHz is right at the max spec, so if the display behaves funny,
    //back down to 125kHz.
    SPI.setClockDivider(SPI_CLOCK_DIV128);     //Sets clock freq to 125kHz
    //SPI.setClockDivider(SPI_CLOCK_DIV64);    //Sets clock freq to 250kHz

As jack says, TOO FAST!

The manual says that the max clock rate of the SPI interface is 250 KHz. The default setting is SPI_CLOCK_DIV4 (4 MHz!).

Thanks a lot, friends.

It works like a charm now with the SPI library as well.

I looked at the code of the SPI library and it's using the SPI registers, which is probably the reason why it's so fast by default as compared to the digitalWrite I was using on my manual implementation. And I saw the inclusion of pins_arduino.h.

I skimmed through the ATMega328 specs and if I understood it correctly the SPI registers are tied to PORTB and specific pins, but would it be possible somehow using a different set of pins with the same approach? I guess the closest would be using code like:

PORTB |= _BV(PB5);
PORTB &= ~_BV(PB5)

, to right directly to the pins I wish instead of using digitalWrite and bit-banging. Am I right?

Thanks again.

I skimmed through the ATMega328 specs and if I understood it correctly the SPI registers are tied to PORTB and specific pins, but would it be possible somehow using a different set of pins with the same approach? I guess the closest would be using code like:

PORTB |= _BV(PB5);

PORTB &= ~_BV(PB5)




, to right directly to the pins I wish instead of using digitalWrite and bit-banging. Am I right?

Yes, that will be much faster than digitalWrite.

And yes the hardware SPI is tied to the SCLK/MISO/MOSI pins (13/12/11) in master mode (and also tied to SS pin (10) in slave mode). (BTW the Arduino Mega has different pin assignments)

FYI,
there's a thread on the old forum (under "Arduino Forum › Hardware › Interfacing › 7 Segment Display using SPI") that addresses similar issues.

There's also an interesting read about the reason the SPI does not work at fast speeds at http://bleaklow.com/2010/08/28/sparkfun_are_less_than_electrifying.html