shiftIn to go with shiftOut

Hi:

Can I ask why there is no shiftIn to go with shiftOut? shiftOut is working really well for me in talking to a DS1306 and a Max7219. My problem is that I need to read from the DS1306.

I have done a number of searches and ended up looking at a lot of code using SPI_Tranfer. I have not been able to get that code to work properly.

Is there a simple process to read a byte from a digital in?

Can I build a shiftIn command?

I'd appreciate some guidance or direction

Thanks,

TimV

Hi

http://www.arduino.cc/en/Tutorial/ShiftIn

I think had to modify it slightly to get it to work with a differnt chip.

Lee

Thanks Lee:

I have tried to lift the shiftIn function to put it into my code. It will not compile so something is seriously wrong. I should not have to use the latch chip they are interfacing to in order to use this function, or do I?

I have put my code in to hopefully make it clear what I am doing and how I am trying to use this function.

I switched my driving pins between the DS1306 and the MAX7219 so that the DS1306 is now connected to the supported SPI pins on the Arduino Diecimila that I am using. I guess I could try the code from the SPI examples now that I am using the supported pins. I guess I don’t understand how to read a digital input to capture a byte.

I have done this before on a PICAXE and on a Microchip but that was in basic and assembler. I am trying to learn “C”.

Any help troubleshooting this or posting an alternate strategy to read the response after sending the address would be appreciated. Here is the code.

oops, code got trimmed by character limit so here is the function where I am calling the shiftIn function

void read_DS1306(byte address, byte cldata)              //Function to write to DS1306
{
// Chip Select is active high
digitalWrite(CLOCK1306, HIGH);                           //Specified in Data Sheet
digitalWrite(CHIPSL1306, HIGH);                          //Select DS1306
shiftOut(OUT1306, CLOCK1306, MSBFIRST, claddress);       //send the register address we want to write to
shiftIn(int IN1306, int CLOCK1306);                      //read the clock register
digitalWrite(CHIPSL1306, LOW);                           //Deselect DS1306
//Send Values to Message Window
Serial.print(" Read Clock Address ");                    //Displays value of Register Address
Serial.println(address, HEX);                            //
Serial.print(" Read Data ");                             //Displays value written to "Data"
Serial.println(cldata, HEX);
delay(50);
}

This is the error message I get

error: expected ',' or '...' before numeric constant In function 'void read_DS1306(byte, byte)':
 At global scope:
 In function 'byte shiftIn(int)':

This is the shiftIn function changed to my DS1306 pin labels

byte shiftIn(int IN1306, int CLOCK1306) 
{ 
  int i;
  int temp2 = 0;
  int pinState;
  byte cldata = 0;
  for (i=7; i>=0; i--)
  {
  digitalWrite(CLOCK1306, 1);
  delayMicroseconds(2);
  cldata = digitalRead(IN1306);
    if (cldata) 
    {
    pinState = 1;
    //set the bit to 0 no matter what
    cldata = cldata | (1 << i);
    }
      else 
    {
    pinState = 0;
    }
    digitalWrite(CLOCK1306, 0);
  Serial.println(cldata, BIN);
  return cldata;
  }

These are the pin definitions

#define OUT1306      11       //Master Out Slave In DS1306
#define IN1306       12       //Master In Slave Out DS1306
#define CLOCK1306    13       //Serial Clock DS1306
#define CHIPSL1306   10       //Chip Select DS1306

Hey, Tim–

Remove the "int"s from the line

shiftIn(int IN1306, int CLOCK1306); //read the clock register

To the compiler that looks like a function declaration rather than a function call, which is what I think you intend.

Mikal

Thanks Mikal:

Done.

My error message has changed to the one below. Since shiftIn is using Integer values, should I change my byte declarations in my read function?

Actually I just tried it and the error message is the same except that it says int instead of byte

Thanks

TimV

error: expected ',' or '...' before numeric constant In function 'void read_DS1306(byte, byte)':
 At global scope:
 In function 'byte shiftIn(int)':

Ok

I dropped the designation in the Read 1306 function - I will post the code in a sec. My main Read 1306 function was also being declared as a type VOID which I obviously can’t do if I expect to return the data that I am reading.

byte read_DS1306(claddress, cldata)              //Function to write to DS1306
{
// Chip Select is active high
digitalWrite(CLOCK1306, HIGH);                           //Specified in Data Sheet
digitalWrite(CHIPSL1306, HIGH);                          //Select DS1306
shiftOut(OUT1306, CLOCK1306, MSBFIRST, claddress);       //send the register address we want to write to
shiftIn(IN1306, CLOCK1306);                              //read the clock register
digitalWrite(CHIPSL1306, LOW);                           //Deselect DS1306
//Send Values to Message Window
Serial.print(" Read Clock Address ");                    //Displays value of Register Address
Serial.println(address, HEX);                            //
Serial.print(" Read Data ");                             //Displays value written to "Data"
Serial.println(cldata, HEX);
delay(50);
}

Now the error message I get is

error: 'address' was not declared in this scope In function 'byte shiftIn(int)':

I did not change the shiftIn function which is :

//*****************************************************************************************************  
// Function to Read data from the DS1306 (Shiftin Function)
//*****************************************************************************************************
byte shiftIn(int IN1306, int CLOCK1306) 
{ 
  int i;
  int temp2 = 0;
  int pinState;
  byte cldata = 0;
  for (i=7; i>=0; i--)
  {
  digitalWrite(CLOCK1306, 1);
  delayMicroseconds(2);
  cldata = digitalRead(IN1306);
    if (cldata) 
    {
    pinState = 1;
    //set the bit to 0 no matter what
    cldata = cldata | (1 << i);
    }
      else 
    {
    pinState = 0;
    }
    digitalWrite(CLOCK1306, 0);
  Serial.println(cldata, BIN);
  return cldata;
  }

Tim,

I’m afraid we’re back-pedaling here. Here’s what I recommend:

  1. Put ShiftIn back exactly the way it was when you copied it from the tutorial page. It’s not a good idea to modify it to insert hard-coded values:
byte shiftIn(int myDataPin, int myClockPin) { 
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);

//we will be holding the clock pin high 8 times (0,..,7) at the
//end of each time through the for loop

//at the begining of each loop when we set the clock low, it will
//be doing the necessary low to high drop to cause the shift
//register's DataPin to change state based on the value
//of the next bit in its serial information flow.
//The register transmits the information about the pins from pin 7 to pin 0
//so that is why our function counts down
  for (i=7; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    delayMicroseconds(2);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      //set the bit to 0 no matter what
      myDataIn = myDataIn | (1 << i);
    }
    else {
      //turn it off -- only necessary for debuging
     //print statement since myDataIn starts as 0
      pinState = 0;
    }

    //Debuging print statements
    //Serial.print(pinState);
    //Serial.print("     ");
    //Serial.println (dataIn, BIN);

    digitalWrite(myClockPin, 1);

  }
  //debuging print statements whitespace
  //Serial.println();
  //Serial.println(myDataIn, BIN);
  return myDataIn;
}

The following is SHEER SPECULATION on how to fix the read_DS1306 function. You should read a little more about C to understand how to pass parameters to functions and become better equipped to validate code like this:

// Speculative fix by MH
byte read_DS1306(byte address)              //Function to read DS1306
{
  byte cldata;

  // Chip Select is active high
  digitalWrite(CLOCK1306, HIGH);                           //Specified in Data Sheet
  digitalWrite(CHIPSL1306, HIGH);                          //Select DS1306
  shiftOut(OUT1306, CLOCK1306, MSBFIRST, address);         //send the register address we want to write to
  cldata = shiftIn(IN1306, CLOCK1306);                     //read the clock register
  digitalWrite(CHIPSL1306, LOW);                           //Deselect DS1306
  //Send Values to Message Window
  Serial.print(" Read Clock Address ");                    //Displays value of Register Address
  Serial.println(address, HEX);                            
  Serial.print(" Read Data ");                             //Displays value written to "Data"
  Serial.println(cldata, HEX);
  delay(50);
  return cldata;
}

Mikal

Okay

Thanks. I will do that. I can change my defines to match the pin names in the routine. As you can see, my label is CLOCK1306 for the digital 13 from the SPI setup. My data input pin is labelled IN1306 which is digital 12 on the arduino.

The shiftIn routine is refering to these pins as myClockPin and myDataPin respectively. I would think they have to match, no?

The clocking is also opposite, but the DS1306 is supposed to sense the clock direction automatically, so maybe it will be fine.

I will see if it eliminate the error messages at any rate and then if something else needs to be fixed it can be done later.

Thanks

TimV

The shiftIn routine is refering to these pins as myClockPin and myDataPin respectively. I would think they have to match, no?

No! They already "match" implicitly because when you call

cldata = shiftIn(IN1306, CLOCK1306);                     //read the clock register

you are passing "IN1306" and "CLOCK1306" in as parameters to the shiftIn function where they BECOME "myClockPin" and "myDataPin".

I will see if it eliminate the error messages at any rate and then if something else needs to be fixed it can be done later.

These compiled fine in my Arduino IDE.

Good luck!

Mikal

Mikal:
You are a genius.

I had to modify my main loop because I was calling the function as

claddress=MinuteR; // Pass Read Minute register value of 0x01
read_DS1306(claddress,clbyte);

With clbyte removed from the function, I had to remove it from the main loop as well.

The sketch now compiles without any errors.

my main loop is

void loop()
{
  cldata=0;                          // make sure no data stuck in Clock Data byte
  Serial.println("Loop");            // send status to serial display - loop entered
  mask = B00001111;                  // mask off lower nibble for BCD conversion
                                     // read the minute register
  claddress=MinuteR;                 // Pass Read Minute register value of 0x01
  read_DS1306(claddress);     // Call the Read chip function
  delay(50);                         // give it a pause
  temp=(cldata & mask);              // AND value read with bit mask
  Min_Unit=temp;                     // assign this value to the Units of Minutes
  address=Digit3;                    // Pass to right most of 4 digits value 
  regdata=Min_Unit;                  // Put the value of the minutes unit to MAX7219 data byte
  write_MAX7219(address,regdata);    // Call the Write display funtion to send to MAX7219
  temp1=cldata / 16;                 // Calculate the tens digit value from Minute data
  Min_Tens=temp1;                    // assign this value to the Tens of Minutes
  address=Digit2;                    // Pass to 2nd digit from right
  regdata=Min_Tens;                  // Put the value of the minutes tens to MAX7219 data byte
  write_MAX7219(address,regdata);    // Call the Write display function to send to MAX7219
  //
  claddress=HourR;                   // Same as what is written for Minutes above
  read_DS1306(claddress);
  delay(50);
  temp=(cldata & mask);
  Hor_Unit=temp;
  address=Digit1;
  regdata=Hor_Unit;
  write_MAX7219(address,regdata);
  temp1=cldata / 16;
  Hor_Tens=temp1;
  address=Digit0;
  regdata=Hor_Tens;
  write_MAX7219(address,regdata);
  delay(500); 
}

I think that from here, I should change my pin names in my defines for the ds1306 to match the names in the function as they exist

Timv

Tim, I think you're on your way. I don't know exactly how your code is supposed to work, but I do know that you probably have to change your lines

read_DS1306(claddress);

to

cldata = read_DS1306(claddress);

because my revision of that function now returns the read value.

M

ok.

I posted while you were posting so I did not read your note before I wrote mine.

I don't get how the pin names are automatically changing. I will read through the code and try to follow it.

From what you have indicated, I would expect that if I don't have to change the names, I should be getting a result on the display which I am not. Perhaps something else in my main loop needs to be changed.

ok. I understand how the names are changing since you actually did explain it quite well.

In writing to the clock, my shiftOut is sending the address of the register that I wish to read the data from.

I have to get out of this modify to read your last post

Thanks for your patience

Tim

Hi Mikal:

When you say to change to cldata=read_DS1306(claddress);

do you mean in my main loop?

You note that your revision of the function now returns the read value.

The only place I see read_DS1306(claddress); is in the function name and the main loop.

I'm getting nothing back.

There's a fair chance I've destroyed the chip in my trials. I did verify that it's wired properly. I'm not getting a heartbeat from the 1hz line so either writing 0x04 to the control register is the wrong value or the chip is dead. I will have a detailed look tomorrow after a decent night's sleep.

Thank you very much for your help. I really do appreciate it..

Tim

Hey, Tim,

When you say to change to cldata=read_DS1306(claddress); do you mean in my main loop?

Yup. Or wherever you call the function.

You might try using Serial.print to debug:

cldata = read_DS1306(claddress);
Serial.print("cldata is ");
Serial.println(cldata);

Thank you very much for your help. I really do appreciate it..

Pas du tout!

Mikal

Ok, I feeling pretty dumb now.

I have spent the day troubleshooting this setup and I am still coming up empty. I have determined (by default logic) that I am not reading anything because there is nothing written on the DS1306 to read.

The data sheet says “The address byte is always the first byte entered after CE (chip select) is driven high” .

Fair enough. Figure 6 on page 12 is a timing diagram that shows CE going high, followed by Clock going from low to high.

I have checked my physical wiring several times now and it seems fine.

I have verified the Digital Pin assignments by printing in my code from within when it is running.

I have a 3V battery on pin 2 of the DS1306 and have measured that there is voltage.

I have an led on Pin 7 of the DS1306 waiting patiently for a heartbeat from the chip.

The chip is getting power and ground - on the correct pins.

I have set

  SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPHA);
  clr=SPSR;
  clr=SPDR;

after reading about a trailing edge issue in a tutorial.

I have a MAX7219 in the same setup on 4 other pins and it is working perfectly. (Verified by writing values to the digits, not just firing up self test)

My setup code for the DS1306 is:

//***************************************************************************************************** 
  // DS1306 Pin Settings 
  //***************************************************************************************************** 
  pinMode(DS_OUT,      OUTPUT);           // Set data out to output
  pinMode(DS_IN,       INPUT);            // Set data in to input (not using)
  pinMode(DS_CLOCK,    OUTPUT);           // Set clock pin to output
  pinMode(DS_CHIP_SEL, OUTPUT);           // Set chip selection pin to output
  //
  digitalWrite(DS_CHIP_SEL,LOW);          // release device
  delay(10);

My Write Function is :

//*****************************************************************************************************  
// Function to WRITE data to the DS1306
//*****************************************************************************************************
void write_DS1306(byte DS_address, byte DS_data)        //Function to write to DS1306
{
// Chip Select is active high
digitalWrite(DS_CHIP_SEL, HIGH);                        //Select DS1306
digitalWrite(DS_CLOCK,LOW);
digitalWrite(DS_CLOCK,HIGH);                            //Specified in Data Sheet
shiftOut(DS_OUT, DS_CLOCK, MSBFIRST, DS_address);       //send the register address we want to write to
shiftOut(DS_OUT, DS_CLOCK, MSBFIRST, DS_data);          //send the data we're writing
digitalWrite(DS_CHIP_SEL, LOW);                         //Deselect DS1306
//Send Values to Message Window
Serial.print(" Write Clock Address ");                  //Displays value of Register Address
Serial.println(DS_address, HEX);                        //
Serial.print(" Write  Data ");                          //Displays value written to "Data"
Serial.println(DS_data, HEX);
delay(50);
}

Here is my comparison write function for the MAX7219 which is working:

//*****************************************************************************************************  
// Function to send data to the Max7219
//*****************************************************************************************************
void write_MAX7219(byte MAX_address, byte MAX_data)      //Function to write to MAX7219
{                                     
// Chip Select is active low
digitalWrite(MAX_CLOCK, HIGH);                           //Specified in Data Sheet
digitalWrite(MAX_CHIP_SEL, LOW);                         //Select MAX7219
shiftOut(MAX_OUT, MAX_CLOCK, MSBFIRST, MAX_address);     //send the register address we want to write to
shiftOut(MAX_OUT, MAX_CLOCK, MSBFIRST, MAX_data);        //send the data we're writing
digitalWrite(MAX_CHIP_SEL, HIGH);                        //Deselect MAX7219
//Send Values to Message Window
Serial.print("Display Address ");                        //Displays value of Register Address
Serial.println(MAX_address, HEX);                        //
Serial.print(" Data ");                                  //Displays value written to "Data"
Serial.println(MAX_data, HEX);                           //
delay(50);
}

Mikal was extremely helpful in sorting out the read function which he confirmed is working on his end. I hope I didn’t screw it up today cleaning up variable names to make things more clear.

//*****************************************************************************************************  
// Function to Read data from the DS1306
//*****************************************************************************************************
// Speculative fix by MH
byte read_DS1306(byte DS_address)                      //Function to read DS1306
{
  // Chip Select is active high
  digitalWrite(DS_CHIP_SEL, HIGH);                     //Select DS1306
  digitalWrite(DS_CLOCK, HIGH);
  digitalWrite(DS_CLOCK, LOW);                         //Specified in Data Sheet
  //
  shiftOut(DS_OUT, DS_CLOCK, MSBFIRST, DS_address);    //send the register address we want to write to
  DS_read_data = shiftIn(DS_IN, DS_CLOCK);             //read the clock register
  digitalWrite(DS_CHIP_SEL, LOW);                      //Deselect DS1306
  //Send Values to Message Window
  Serial.print(" Read Clock Address ");                //Displays value of Register Address
  Serial.println(DS_address, HEX);                            
  //Serial.print(" Read Data ");                       //Displays value written to "Data"
  //Serial.println(DS_read_data, HEX);
  delay(50);
  return DS_read_data;
} 
//*****************************************************************************************************  
// Function to Read data from the DS1306 (Shiftin Function)
//*****************************************************************************************************
byte shiftIn(int myDataPin, int myClockPin) {
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin,  INPUT);
//we will be holding the clock pin high 8 times (0,..,7) at the
//end of each time through the for loop
//at the begining of each loop when we set the clock low, it will
//be doing the necessary low to high drop to cause the shift
//register's DataPin to change state based on the value
//of the next bit in its serial information flow.
//The register transmits the information about the pins from pin 7 to pin 0
//so that is why our function counts down
  for (i=7; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    delayMicroseconds(2);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      //set the bit to 0 no matter what
      myDataIn = myDataIn | (1 << i);
    }
    else {
      //turn it off -- only necessary for debuging
      //print statement since myDataIn starts as 0
      pinState = 0;
    }
    //Debuging print statements
    Serial.print(pinState);
    Serial.print("     ");
    Serial.println (myDataIn, BIN);
    digitalWrite(myClockPin, 1);
  }
  //debuging print statements whitespace
  Serial.println();
  Serial.println(myDataIn, BIN);
  return myDataIn;
}

A sample of the code in Setup() to put some values in the chip is:

DS_address=DS_SecondW;                          // Pass Write Seconds register value of 0x80
  DS_data=0x05;                                   // Arbitrary value of 5 for Seconds
  write_DS1306(DS_address,DS_data);               // Call Write to chip function
  delay(50);

A companion working MAX7219 example from Setup() is:

MAX_address=MAX_Intens;                 // Supplies value 0x0A from Defines
  MAX_data=0x0F;                          // Set to 0F for Full Brightness
  write_MAX7219(MAX_address,MAX_data);    // Send two bytes to write_MAX7219() function

and I don’t know what else I can supply that would help.

Oh, I also replaced the chip that I wasn’t sure was working last night. I have no reason to suspect this chip, but it might not be brand new.

All of this was working just fine on a DS1307 using I2C, but I really wanted to use only one com protocol and selected SPI because I couldn’t find an I2C display driver chip that I could put in a through hole socket.

I would really appreciate the time and effort it would take for someone to look at this and tell me what I am missing.

Thanks

TimV

Mikal was extremely helpful in sorting out the read function which he confirmed is working on his end.

Thanks, Tim, but No, no! I only claimed that it compiles correctly here. That read code was marked SPECULATIVE, in all caps, because not only do I not have a DS1306 or a datasheet, I don't really even know what one does! I posted that code as a framework because you were have troubles with the C syntax. I'm afraid you (or someone else) will have to validate and tweak the algorithm.

The "cleanup" you refer to seems fine, although I don't see where DS_read_data is defined. (Previously cldata was a local byte variable in the read function.)

Sorry, I wish I had some experience with this chip.

Mikal

Hi Mikal:

Sorry to have misrepresented you in my credit of your effort. I took your comment as meaning yours was working

because my revision of that function now returns the read value.

I guess you meant that it had the process in it to capture the read value. I am sorry.

DS_read_data is defined as a global variable in my list of defines that sets all the other variables up.

I suspect something simple but I think I have looked at it for so long now that I wouldn't catch something that's off.

Thanks for your help

TimV

Hi Tim,

Sorry to have misled you :-[ I'll bet if you sprinkle some Serial.print()s throughout your code, and keep reading that data sheet, you get a "Eureka!" moment. :)

Mikal

Hi Mikal:

You did not mislead me. English as a language is not very precise so it's easy to read a different meaning to the same words ;)

I swapped out the DS1306 for a DS1307. I have ordered a few DS1306's for later. I hae used the same function structures as have posted here and modified them to I2C. In less than an hour I had a running clock that is updating on it's own and my reads and writes are working perfectly.

I still don't get why the SPI code was working perfectly for the MAX7219 but not for the DS1306. I suspect the chips may have been damaged or I may have damaged them a year ago when I was playing around with the PIC.

I do appreciate the time you spent and the explanations you provided. I learned a great deal about C programming and about writing functions. I also learned a lot about passing variables through routines. That is a huge help for me as I head down the road.

I will be adding an MCP23S08 to handle a keypad interface. I have an SPI version of that chip so I will try out the software on it and see if it will work like the MAX7219 or not work like the DS1306. I can get an I2C version of the chip so I can stick to one bus for the clock and keypad.

Thanks again

Tim