Show Posts
Pages: [1]
1  Forum 2005-2010 (read only) / Bugs & Suggestions / Re: Wire Library, Wire.begin ┬áDocumentation on: July 18, 2010, 07:23:18 pm
The Wire.begin() should only be called once - it initializes the wire library.

You will need to address each of your slave devices just before you talk to it using wire.beginTransmission(Address). Then you use wire.send() to queue up the message data and wire.endTransmission to initiate the sending.
2  Forum 2005-2010 (read only) / Bugs & Suggestions / Wire Library, Wire.begin  Documentation on: July 08, 2010, 01:21:14 pm
It seems the Wire.begin() procedure is intended to be called only once, usually in setup(). I found out the hard way it bombs if you keep calling it, though it does not complain.

Could we update the documentation to:

Description: Initiate the Wire library and join the I2C  bus as a master or slave. This should normally be called only once.
3  Forum 2005-2010 (read only) / Bugs & Suggestions / Wire Library, Wire.endTransmission documentation on: July 08, 2010, 01:22:29 pm
It seems that the wire library was enhanced to allow error codes to be reported from a Wire.endTransmission()
(see http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1206621511/4 )

From what I can see this has been implemented in the wire library but the documentation has not been updated to describe the return codes.

This is really useful functionality - how can we update the docs? It seems other changes (also described in the thread referenced above) were made and are not documented.
4  Forum 2005-2010 (read only) / Development / Re: Print hex with leading zeroes on: July 18, 2010, 08:53:29 pm
New code based on sprintf as suggested (but without any bounds checking smiley-sad)...

Code:
/*
  PrintHex routines for Arduino: to print byte or word data in hex with
  leading zeroes.
  Copyright (C) 2010 Kairama Inc

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
void PrintHex8(uint8_t *data, uint8_t length) // prints 8-bit data in hex with leading zeroes
{
      char tmp[16];
        for (int i=0; i<length; i++) {
          sprintf(tmp, "0x%.2X",data[i]);
          Serial.print(tmp); Serial.print(" ");
        }
}

void PrintHex16(uint16_t *data, uint8_t length) // prints 16-bit data in hex with leading zeroes
{
        char tmp[16];
        for (int i=0; i<length; i++)
        {
          sprintf(tmp, "0x%.4X",data[i]);
          Serial.print(tmp); Serial.print(" ");
        }
}

Use it the same way...
Code:
void setup()
{
        Serial.begin(9600);
        Serial.print("Examples of PrintHex usage\n\n");
}

void loop()
{
        uint8_t ByteData[5]={0x01, 0x0F, 0x10, 0x11, 0xFF};
        Serial.print("With uint8_t array:  "); PrintHex8(ByteData,5); Serial.print("\n");

        uint8_t ByteDatum=0x01;
        Serial.print("With uint8_t scalar: "); PrintHex8(&ByteDatum,1); Serial.print("\n");
 
        uint16_t Shorts[5]={0x0001, 0x00FF, 0x0100, 0xAAAA, 0xFFFF};
        Serial.print("With uint16_t array: "); PrintHex16(Shorts,5); Serial.print("\n");

        Serial.print("==========================================\n");
        delay(10000);
}

and get these results:
Code:
Examples of PrintHex usage

With uint8_t array:  0x01 0x0F 0x10 0x11 0xFF
With uint8_t scalar: 0x01
With uint16_t array: 0x0001 0x00FF 0x0100 0xAAAA 0xFFFF
5  Forum 2005-2010 (read only) / Development / Re: Print hex with leading zeroes on: July 18, 2010, 08:27:02 pm
sprintf is so much cleaner - I didn't know it was available! Thx a lot.
6  Forum 2005-2010 (read only) / Development / Print hex with leading zeroes on: July 18, 2010, 07:40:31 pm
You can print hex using the serial library with Serial.print(data,HEX), but it does not include leading zeroes, so 0x01 will come out as 1, etc. This can get confusing if you print an array, so I put together some simple functions to include leading zeroes. In case they are useful to others, here they are:

Code:
/*
  PrintHex routines for Arduino: to print byte or word data in hex with
  leading zeroes.
  Copyright (C) 2010 Kairama Inc

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
void PrintHex8(uint8_t *data, uint8_t length) // prints 8-bit data in hex with leading zeroes
{
        Serial.print("0x");
        for (int i=0; i<length; i++) {
          if (data[i]<0x10) {Serial.print("0");}
          Serial.print(data[i],HEX);
          Serial.print(" ");
        }
}

void PrintHex16(uint16_t *data, uint8_t length) // prints 16-bit data in hex with leading zeroes
{
        Serial.print("0x");
        for (int i=0; i<length; i++)
        {
          uint8_t MSB=byte(data[i]>>8);
          uint8_t LSB=byte(data[i]);
          
          if (MSB<0x10) {Serial.print("0");} Serial.print(MSB,HEX); Serial.print(" ");
          if (LSB<0x10) {Serial.print("0");} Serial.print(LSB,HEX); Serial.print(" ");
        }
}

Example of how to use them:

Code:
void setup()
{
        Serial.begin(9600);
        Serial.print("Setup: Examples of PrintHex usage\n\n");
}

void loop()
{
        uint8_t ByteData[5]={0x01, 0x0F, 0x10, 0x11, 0xFF};
        Serial.print("With uint8_t array:  "); PrintHex8(ByteData,5); Serial.print("\n");

        uint8_t ByteDatum=0x01;
        Serial.print("With uint8_t scalar: "); PrintHex8(&ByteDatum,1); Serial.print("\n");
 
        uint16_t Shorts[5]={0x0001, 0x00FF, 0x0100, 0xAAAA, 0xFFFF};
        Serial.print("With uint16_t array: "); PrintHex16(Shorts,5); Serial.print("\n");

        Serial.print("==========================================\n");
        delay(10000);
}

The output of which is:
Code:
Setup: Examples of PrintHex usage

With uint8_t array:  0x01 0F 10 11 FF
With uint8_t scalar: 0x01
With uint16_t array: 0x00 01 00 FF 01 00 AA AA FF FF
==========================================
7  Forum 2005-2010 (read only) / Development / CRC for Dallas 1-Wire on: July 18, 2010, 09:13:46 pm
It can be tricky to interpret Dallas 1-Wire CRCs. The following shows how to do the 16-bit CRC for data, and also includes usage of the 8-bit CRC. The main things I learned are
  • the Dallas chips (at least the DS2450 I'm using) inverts the 16-bit CRC data before transmitting it, and puts the bytes in opposite order to what I expected. The bit-inversion and why it's a good idea are mentioned in the Maxim application note (http://www.maxim-ic.com/app-notes/index.mvp/id/27) but not in the chip documentation.
  • There's a neat trick where you compute the CRC on the transmitted message and transmitted CRC and you should always get the same result if there's no transmission error.
Hopefully this will save some headaches :-).

The new 16-bit CRC routine is:
Code:
/*
  Dallas 1-wire CRC routines for Arduino with examples of usage.
  The 16-bit routine is new.
  The 8-bit routine is from http://github.com/paeaetech/paeae/tree/master/Libraries/ds2482/
  
  Copyright (C) 2010 Kairama Inc

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
// Dallas 1-wire 16-bit CRC calculation. Developed from Maxim Application Note 27.
uint16_t crc16( uint8_t *data, uint8_t len)
{
      uint16_t crc=0;
      
      for (uint8_t i=0; i<len;i++)
      {
            uint8_t inbyte = data[i];
            for (uint8_t j=0;j<8;j++)
            {
                  uint8_t mix = (byte(crc)^ inbyte) & 0x01;
                  crc = crc >> 1;
                  if (mix)
                        crc = crc ^ 0xA001;
                  
                  inbyte = inbyte >> 1;
            }
      }
      return crc;
}

and the 8-bit version from http://github.com/paeaetech/paeae/tree/master/Libraries/ds2482/ is:
Code:
// The 1-Wire CRC scheme is described in Maxim Application Note 27:
// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"

uint8_t crc8( uint8_t *addr, uint8_t len)
{
      uint8_t crc=0;
      
      for (uint8_t i=0; i<len;i++)
      {
            uint8_t inbyte = addr[i];
            for (uint8_t j=0;j<8;j++)
            {
                  uint8_t mix = (crc ^ inbyte) & 0x01;
                  crc >>= 1;
                  if (mix)
                        crc ^= 0x8C;
                  
                  inbyte >>= 1;
            }
      }
      return crc;
}

The output from a talkative test routine is:
Code:
Setup: Maxim 1-wire CRC Examples...

First, 8-bit CRC. We use a valid 64-bit ROM+CRC address
ROM code with CRC 0xFF 0x00 0x07 0x5F 0x07 0xB7 0x00 0x68
For the 7-byte ROM code alone, computed 8-bit CRC is 0x37
This should equal the correct value of 0x37

Another approach is to compute the CRC of the message&transmitted CRC.
The resulting 8-bit CRC is 0x00
This should always be 0 if there was no error in transmission.
----------
Now the 16-bit CRC, using a valid 7-byte sequence where the CRC is known
Data=0xAA 0x06 0x00 0x00 0x00
The CRC as transmitted by a DS2450 is 0xE7 0x6F

For message alone, computed CRC is 0x9018
The two are not equal because the DS2450 transmits the complement of the CRC!
Inverting what the DS2450 sends results in: 0x18 0x90
Which is almost correct, but the bytes are reversed
Inverting what the DS2450 sends and swapping byte order results in: 0x90 0x18
Which finally agrees with the computed CRC.

Another approach is to compute the CRC of the message&transmitted CRC
For message plus CRC, result is =0xB001
This should always equal 0xB001 if there was no error in transmission
==========================================

The code to generate this is:
Code:
uint8_t TempSensA[8] = {0x10,0x50,0xA9,0x0A,0x02,0x08,0x00,0x37}; // DS18S20

void setup()
{
        Serial.begin(9600);        // set up Serial library at 9600 bps
        Serial.print("Setup: Maxim 1-wire CRC Examples...\n\n");
}

void loop()
{
      uint8_t Data[10], length, CRCByte, i, CRCCorrect[2], CRCDS2450[2];
        uint16_t CRCWord;

        Serial.print("First, 8-bit CRC. We use a valid 64-bit ROM+CRC address\n");

        length=8;
        Serial.print("ROM code with CRC "); PrintHex8(Data,length); Serial.print("\n");

        length=7; // this time just the data bits
        CRCByte=crc8(TempSensA,length);
        Serial.print("For the 7-byte ROM code alone, computed 8-bit CRC is ");
        PrintHex8(&CRCByte,1); Serial.print("\n");
        Serial.print("This should equal the correct value of ");
        PrintHex8(&TempSensA[7],1); Serial.print("\n\n");

        length=8;
        CRCByte=crc8(TempSensA,length); // this time include the CRC
        Serial.print("Another approach is to compute the CRC of the message&transmitted CRC.\n");
        Serial.print("The resulting 8-bit CRC is "); PrintHex8(&CRCByte,1); Serial.print("\n");
        Serial.print("This should always be 0 if there was no error in transmission.\n");
        Serial.print("----------\n");

        Serial.print("Now the 16-bit CRC, using a valid 7-byte sequence where the CRC is known\n");
        Data[0]=0xAA; Data[1]=0x06; Data[2]=0x00; Data[3]=0x00; Data[4]=0x00; Data[5]=0xE7; Data[6]=0x6F;
        CRCDS2450[0]=Data[5]; CRCDS2450[1]=Data[6];

        length=5;
        Serial.print("Data="); PrintHex8(Data,length); Serial.print("\n");
        Serial.print("The CRC as transmitted by a DS2450 is "); PrintHex8(CRCDS2450,2); Serial.print("\n\n");
        
        CRCWord=crc16(Data,length);
        Serial.print("For message alone, computed CRC is "); PrintHex16(&CRCWord, 1); Serial.print("\n");
        Serial.print("The two are not equal because the DS2450 transmits the complement of the CRC!\n");
        
        CRCCorrect[0]=~CRCDS2450[0];
        CRCCorrect[1]=~CRCDS2450[1];
        Serial.print("Inverting what the DS2450 sends results in: "); PrintHex8(CRCCorrect,2); Serial.print("\n");
        Serial.print("Which is almost correct, but the bytes are reversed\n");
 
        CRCCorrect[0]=~CRCDS2450[1];
        CRCCorrect[1]=~CRCDS2450[0];      
        Serial.print("Inverting what the DS2450 sends and swapping byte order results in: ");
        PrintHex8(CRCCorrect,2); Serial.print("\n");
        Serial.print("Which finally agrees with the computed CRC.\n\n");
        
        length=7;
        CRCWord=crc16(Data,length);

        Serial.print("Another approach is to compute the CRC of the message&transmitted CRC\n");
        Serial.print("For message plus CRC, result is ="); PrintHex16(&CRCWord, 1); Serial.print("\n");
        Serial.print("This should always equal 0xB001 if there was no error in transmission\n");
      
        Serial.print("==========================================\n");    
        delay(10000);
}
8  Forum 2005-2010 (read only) / Development / Maxim DS2482 1-wire master library, slow read on: July 13, 2010, 05:24:35 pm
I have found the DS2482 library posted by sivu (see http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1242137666/4)  extremely useful to get going quickly.

Unfortunately I ran across a bug in wireReadByte. The existing code is:

Code:
uint8_t DS2482::wireReadByte()
{
busyWait(true);
begin();
Wire.send(0x96);
end();
busyWait();
setReadPtr(PTR_READ);
busyWait();
return readByte();
}

The problem occurs with the last 3 lines above: after setting the read pointer to the Read Data Register, busyWait starts to poll and wait until the device is not busy. busyWait is expecting to read the status register but it gets the data register instead. If the LSB of the data is 1 it concludes the device is busy and times out waiting. After timeout the last line correctly reads the data.

The impact is silent because the timeout is not reported, but it takes time (about 250ms with default settings on my Duemilanove). This occurs roughly half the time if your data is random. Reading 9 bytes from my DS18S20 temperature sensor this translates into about 1s just to read the data, which is very slow.

As far as I can see from reading the DS2482 data sheet there is no need to wait for the device to be ready at this point, so the extra busyWait can be eliminated in this corrected code:

Code:
uint8_t DS2482::wireReadByte()
{
busyWait(true);
begin();
Wire.send(0x96);
end();
busyWait();
setReadPtr(PTR_READ);
return readByte();
}

In this case it only takes 19ms to read the 9 bytes from my temperature sensor  smiley.
Pages: [1]