Sunday, September 7, 2014

Minima Controller Shield programming

UPDATED:

As was intended, programming of the controller shield is trivial.  A single additional class was required and no changes to other code or libraries was necessary.  With the Si570 devices behind a multiplexer, the only change necessary to the main Minima sketch is to select the multiplexer channel containing the Si570 you wish to talk to.  For a controller with a single Si570, selecting that channel needs only happen at startup and existing code continues to work unchanged.

I created a driver class for the PCA9546 as follows:

File: PCA9546.h

#ifndef PCA9546_H
#define PCA9546_h

#ifndef P
#define PBUFSIZE (66)
extern char buf[PBUFSIZE];

#define  P(x) strcpy_P(buf, PSTR(x))
#endif

typedef enum 
{
  PCA9546_ERROR = 0,
  PCA9546_SUCCESS
} PCA9546_Status;

#define PCA9546_CHANNEL_1 (1) // Bit 1
#define PCA9546_CHANNEL_2 (2) // Bit 2
#define PCA9546_CHANNEL_3 (4) // Bit 3
#define PCA9546_CHANNEL_4 (8) // Bit 4

class PCA9546
{
public:
  PCA9546(uint8_t i2c_address, uint8_t channel);

  PCA9546_Status status;
  uint8_t channel;

private:
  uint8_t i2c_address;
  bool selectChannel(uint8_t channel);
  uint8_t i2c_read();
  void i2c_write(uint8_t data);
};

#endif

File: PCA9546.cpp

/*
 * PCA9546 Library for Arduino
 *
 * MIT License
 *
 * Copyright Jeff Whitlatch - ko7m - 2014
 */

#include <Arduino.h>
#include <Wire.h>
#include "PCA9546.h"
#include "debug.h"


#define DEBUG(x ...)  // Default to NO debug    
//#define DEBUG(x ...) debugUnique(x)    // UnComment for Debug

// Initialize the PCA9546 and enable the channel(s) indicated
PCA9546::PCA9546(uint8_t PCA9546_address, uint8_t channel)

  i2c_address = PCA9546_address;

  Wire.begin();
  selectChannel(channel);
}

// Send a channel selection word to the PCA9546
bool PCA9546::selectChannel(uint8_t channel)
{
  // Sanity check value passed.  Only least significant 4 bits valid
  if (channel <= 0xf)
  {
    i2c_write(channel);
    debug(P("Successfully selected PCA9546 channel"));
    status = PCA9546_SUCCESS;
  }
  else
  {
    debug(P("PCA9546 channel selection failed"));
    status = PCA9546_ERROR;
  }
  return (PCA9546_SUCCESS == status);
}

// Write a byte to I2C device.  There is only a single register.  If multiple bytes written, last one wins.
void PCA9546::i2c_write(uint8_t data)
{
  Wire.beginTransmission(i2c_address);
  Wire.write(data);
  Wire.endTransmission();
}

// Read the one byte register from the I2C device
uint8_t PCA9546::i2c_read()
{
  uint8_t rdata = 0xFF;
  Wire.beginTransmission(i2c_address);
  Wire.requestFrom(i2c_address, (uint8_t)1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

So, this new class has been added to the Minima source files.  In the Minima main sketch, I add the following code right before including "Si570.h":

#include "PCA9546.h"

I then add the definition of the PCA9546 I2C address right before the one for the Si570:

#define PCA9546_I2C_ADDRESS 0x70

I then create a global variable to hold the PCA9546 object right before the one defined to hold the Si570 object:

PCA9546 *mux;

Ok, so the only thing required now is to initialize the multiplexer and select channel 1.  The rest of the Minima sketch can run without change.  I put the following code right before the initialization of the Si570:

  // Initialize the PCA9546 multiplexer and select channel 1
  mux = new PCA9546(PCA9546_I2C_ADDRESS, PCA9546_CHANNEL_1);
  if (mux->status == PCA9546_ERROR)
  {
    printLine2CEL(P("PCA9546 init error"));
    delay(3000);

  }

I have posted the PCA9546 driver source and integration with Eldon Brown's (WA0UWH) latest Minima sketch on my public branch of my Minima repository on Github.  Please check it out at https://github.com/ko7m/radiono_ko7m.

If integration of the files above provides any grief for anyone cloning my shield, please contact me for assistance and I will be happy to help.  Direct email is ko7m at arrl.net.

No comments:

Post a Comment