PCF8574 as a I2C to SPI Bridge

Hi. :slight_smile:

I have several of these cheap PCF8574 modules and I was curious as to it being able to act as a I2C to SPI bridge like the SC18IS602 I2C to SPI Bridge Module for Arduino with Arduino Library.

Since the PCF8574 is being advertised as a IIC/I2C/TWI/SPI Serial interface Board Module, I thought why bother buying the more expensive one if I can get away with doing the same thing for cheaper?

I have an SPI based sensor that I want to directly interface to a I2C DAC. The data rate is I'm working with is not that fast and I only want to work with 12 bits every 250 milliseconds anyhow.

My sensor is a temperature sensor that goes from 0 - 1024 C and the voltage range of the DAC is 0 - Vcc.

Buffering the array and addressing the interface is where I got a bit lost.

Is there any advice on how a PCF8574 module (normally used for LCDs) can be used to function as I tried to describe above?

I found some excellent code from: Simple 3-Wire MAX6675 Thermocouple ADC Arduino Interface

/* 3-wire connection between the MAX6675 Cold-Junction-Compensated K-Thermocouple- to-Digital Converter and Arduino.
 
 This is a read only device with a 12-bit output (16 total bits) with bit 15 (MSB) output first.

15 is a dummy sign bit and is discarded. Bits 14-3 are the actual temperature reading,

bit 2 is normally 0 but if the sensor is not attached is a 1. Useful for detecting if sensor is attached.

Bits 0 and 1 are discarded.

There are several "libraries" on the web for Arduino to read the MAX6675 but to me are a mess - I wrote my own more

portable code anyone can use.

The code works as follows in subroutine spiRead():

We declare variable "value" as an integer and set to zero. An integer variable in Arduino is 16-bits.

CS is taken LOW for 2 mSec. then HIGH to start the conversion process. We delay 200 mSec. for the process to complete.

The CS is taken LOW again to read the data. One CLK cycle from LOW to HIGH to LOW discards bit 15.

Next we use a "for" loop to retrieve the next 15 bits (14-0) that are stored in variable "value".

Next we test bit 2 to see if the sensor is connected. A 1 means no sensor and a value of -1 is returned to the main program.

If bit 2 is 0 everything is OK, "value" is shifted right three places and the Centigrade integer value is returned to the main program.

Back in "loop" if a -1 is returned to variable v a message "No sensor" is generated. Otherwise v is multiplied by 0.25 to get the

temperature in Celsius which is converted to Fahrenheit then displayed on the serial monitor or on a LCD display.

*/

#define Gnd 22
#define Vcc 24

#define CLK 26
#define CS 28
#define DBIT 30 // so


//#include <SoftwareSerial.h> ?

int v = 0;
float Ctemp, Ftemp;

void setup()   {
  Serial.begin(9600);
  pinMode(CLK, OUTPUT);
  pinMode(DBIT, INPUT);
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);
  digitalWrite(CLK, LOW);

  pinMode(Gnd, OUTPUT);
  pinMode(Vcc, OUTPUT);
  digitalWrite(Gnd, LOW);
  digitalWrite(Vcc, HIGH);
  
}

void loop()   {
  v = spiRead();
  if (v == -1)   {
    Serial.print("No sensor \n");
  }
  else   {
    Ctemp =  v * 0.25;
    Ftemp = (Ctemp * 9 / 5) + 32;
    Serial.println(Ftemp);
   // Serial.print("\n");
  }
  delay(100);
}

int spiRead()   {
  int value = 0; //We declare variable "value" as an integer and set to zero
  digitalWrite(CS,LOW); //CS is taken LOW for 2 mSec. then HIGH to start the conversion process.
  delay(2);
  digitalWrite(CS,HIGH);
  delay(220);

  /* Read the chip and return the raw temperature value */
  /* Bring CS pin low to allow us to read the data from
   the conversion process */

  digitalWrite(CS,LOW); //The CS is taken LOW again to read the data. One CLK cycle from LOW to HIGH to LOW discards bit 15.
  /* Cycle the clock for dummy bit 15 */
  digitalWrite(CLK,HIGH); 
  delay(1);
  digitalWrite(CLK,LOW);

  /*
   Read bits 14-3 from MAX6675 for the Temp. Loop for each bit reading
   the value and storing the final value in 'temp'
   */

  for (int i=14; i>=0; i--) { //Next we use a "for" loop to retrieve the next 15 bits (14-0) that are stored in variable "value".
    digitalWrite(CLK,HIGH);
    value += digitalRead(DBIT) << i;
    digitalWrite(CLK,LOW);
  }
  // check bit D2 if HIGH no sensor
  if ((value & 0x04) == 0x04) return -1;

  // shift right three places
  return value >> 3;
}

I wish more open-source coders could lay it out line-by-line like this in order to describe the whats/whens/wheres/whys/hows as comprehensively as this one seems to.
(It would make many lives easier.) :stuck_out_tongue:

Anyhow, I now must figure out how to send the bits from this code into an I2C device and have the I2C device reflect what the SPI device is doing.

Wish me luck.
:art:

You can do it but with a lot of software overhead, is it worth it when the arduino already has SPI and the necessary libraries? This response is to help you get started in solving your problem, not solve it for you.
Good Luck & Have Fun!
Gil

Thank you for overstating the obvious.

I'm not asking for anyone to solve my problem.
I'm asking for some friendly guidance.

And I do feel lucky.

"This response is to help you get started in solving your problem, not solve it for you."
Responses like that kinda defeats the purpose of any educational forum.(IMHO)

I know about the SPI library and the two-wire library...

My issues are the coding in such a way as I previously described.
(Since my understanding is fairly limited and I don't have a millennium to decipher every *.h and *cpp file in every example folder just to find out that certain functions are not even readily supported. e.g. ONLY Pin 11 for an input and not being able to change that without massively altering the library.)

I know there is a way to even code without using any libraries whatsoever!
(If I were that good, I probably wouldn't even be here.)

Step-by-step instructions on how to get from A to B and then to C seems to be a bit scarce.

Although it would be very nice to see how using lots of software overhead can take the place of having to even use a piece of additional hardware. :slight_smile:

Arduino_n00b:
I have an SPI based sensor that I want to directly interface to a I2C DAC.

Please, provide links to your SPI sensor and the I2C DAC.

Arduino_n00b:
Hi. :slight_smile:

I have several of these cheap PCF8574 modules and I was curious as to it being able to act as a I2C to SPI bridge like the SC18IS602 I2C to SPI Bridge Module for Arduino with Arduino Library.

Since the PCF8574 is being advertised as a IIC/I2C/TWI/SPI Serial interface Board Module, I thought why bother buying the more expensive one if I can get away with doing the same thing for cheaper?

I have an SPI based sensor that I want to directly interface to a I2C DAC. The data rate is I'm working with is not that fast and I only want to work with 12 bits every 250 milliseconds anyhow.

My sensor is a temperature sensor that goes from 0 - 1024 C and the voltage range of the DAC is 0 - Vcc.

Anyhow, I now must figure out how to send the bits from this code into an I2C device and have the I2C device reflect what the SPI device is doing.

Wish me luck.
:art:

Is something like this what you are trying to achive? (Compiles NOT tested)

/** MAX6675 Thermocouple Reader / MCP4725 DAC output Example Code

  MAX6675 Module   ==>   Arduino UNO
     CS            ==>     D10
     SO            ==>     D12
     SCK           ==>     D13
     Vcc           ==>     Vcc (5v OK)
     Gnd           ==>     Gnd

  MCP4725 Module   ==>   Arduino UNO
     SCL           ==>     SCL
     SCA           ==>     SCA
     Vcc           ==>     Vcc (5v OK)
     Gnd           ==>     Gnd
**/

#include <Wire.h>
#include <SPI.h>

//This is the I2C Address of the MCP4725, by default (A0 pulled to GND). For devices with A0 pulled HIGH, use 0x61
#define MCP4725_ADDR 0x60

//Chip selecte pin defined for MAX6675
#define MAX6675_CS   10

uint16_t readThermocouple() {

  uint16_t v;

  digitalWrite(MAX6675_CS, LOW);
  delay(1);

  // Read in 16 bits,
  //  15    = 0 always
  //  14..2 = 0.25 degree counts MSB First
  //  2     = 1 if thermocouple is open circuit
  //  1..0  = uninteresting status

  v = SPI.transfer(0x00);
  v <<= 8;
  v |= SPI.transfer(0x00);

  digitalWrite(MAX6675_CS, HIGH);

  return v;
}

void setup()
{
  Wire.begin();
  SPI.begin();
  Serial.begin(115200);

  pinMode(MAX6675_CS, OUTPUT);
  digitalWrite(MAX6675_CS, HIGH);
}
//---------------------------------------------------
void loop()
{
  uint16_t temp_raw = readThermocouple();

  if (temp_raw & 0x04 == 0x00) { // Bit 2 indicates if the thermocouple.1: Disconnected, 0: Connected 
    // The lower three bits (0,1,2) are discarded status bits
    temp_raw >>= 3;

    Serial.print("Temp read(degC): ");
    Serial.println(temp_raw * 0.25, 2); //0.25 degC per bit

    //output thermocouple read to MCP4725
    Wire.beginTransmission(MCP4725_ADDR);
    Wire.write(64);                     // cmd to update the DAC
    Wire.write(temp_raw >> 4);        // the 8 most significant bits...
    Wire.write((temp_raw & 15) << 4); // the 4 least significant bits...
    Wire.endTransmission();
  }
}

Original codes taken form the link below
https://learn.sparkfun.com/tutorials/mcp4725-digital-to-analog-converter-hookup-guide

On a side note, from some threads I have seen from you, you seem to rush into things without thinking whether it is the right direction or not.

My advice to you would be to take a step back when you face a problem and have a good think about it before you get move further. It would save you a lot of pain and headaches especially when you would need trouble shooting... but that's just my opinion! :slight_smile:

Good Luck