Skip to content

Instantly share code, notes, and snippets.

@analog-io
Created April 10, 2015 15:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save analog-io/a95520fee652e7e6fb56 to your computer and use it in GitHub Desktop.
Save analog-io/a95520fee652e7e6fb56 to your computer and use it in GitHub Desktop.
SoftwareI2C for MSP430 Energia
//
// SoftwareWire.cpp
// Library C++ code
// ----------------------------------
// Developed with embedXcode
// http://embedXcode.weebly.com
//
// Project embed1
//
// Created by Rei VILO, mars 29, 2013 09:59
// http://embedXcode.weebly.com
//
//
// Copyright © Rei VILO, 2013-2014
// License CC = BY NC SA
//
// See I2C_SoftwareLibrary.h and ReadMe.txt for references
//
#include "I2C_SoftwareLibrary.h"
///
/// @brief Delay values for software I2C
///
const uint8_t DELAY_LONG = 32;
const uint8_t DELAY_FULL = 8;
const uint8_t DELAY_HALF = 4;
const uint8_t DELAY_PART = 2;
#define I2C_READ 1
#define I2C_WRITE 0
#define TICKS_PER_MS (F_CPU / 1000)
#define TICKS_PER_US (TICKS_PER_MS / 1000)
void delayI2Cms(uint16_t delay)
{
while (delay--) __delay_cycles(TICKS_PER_MS);
}
void delayI2Cus(uint16_t delay)
{
while (delay--) __delay_cycles(TICKS_PER_US);
}
uint8_t SoftwareWire::rxBuffer[BUFFER_LENGTH];
uint8_t SoftwareWire::rxBufferIndex = 0;
uint8_t SoftwareWire::rxBufferLength = 0;
uint8_t SoftwareWire::txAddress = 0;
uint8_t SoftwareWire::txBuffer[BUFFER_LENGTH];
uint8_t SoftwareWire::txBufferIndex = 0;
uint8_t SoftwareWire::txBufferLength = 0;
uint8_t SoftwareWire::transmitting = 0;
SoftwareWire::SoftwareWire(uint8_t pinSDA, uint8_t pinSCL) {
_pinSDA = pinSDA;
_pinSCL = pinSCL;
}
void SoftwareWire::begin() {
pinMode(_pinSDA, OUTPUT);
digitalWrite(_pinSDA, HIGH);
pinMode(_pinSCL, OUTPUT);
digitalWrite(_pinSCL, HIGH);
rxBufferIndex = 0;
rxBufferLength = 0;
txBufferIndex = 0;
txBufferLength = 0;
}
void SoftwareWire::beginTransmission(uint8_t address)
{
transmitting = 1;
txAddress = address;
txBufferIndex = 0;
txBufferLength = 0;
}
uint8_t SoftwareWire::endTransmission(uint8_t sendStop)
{
uint8_t result = 0;
startI2C(txAddress, I2C_WRITE);
result += writeI2C(txBuffer, txBufferLength);
if (sendStop) stopI2C();
else stallI2C();
txBufferIndex = 0;
txBufferLength = 0;
transmitting = 0;
return result;
}
uint8_t SoftwareWire::endTransmission(void)
{
return endTransmission(true);
}
uint8_t SoftwareWire::requestFrom(uint8_t address, uint8_t length)
{
bool first = true;
if (length > BUFFER_LENGTH) length = BUFFER_LENGTH;
startI2C(address, I2C_READ);
pinMode(_pinSCL, INPUT);
pinMode(_pinSDA, INPUT);
delayI2Cus(DELAY_FULL);
while (digitalRead(_pinSCL)==LOW);
if (length > 1) {
for (uint8_t i=0; i<length-1; i++) {
rxBuffer[i] = readI2C(false,first);
first = false;
}
}
rxBuffer[length-1] = readI2C(true,first);
stopI2C();
rxBufferIndex = 0;
rxBufferLength = length;
return length;
}
size_t SoftwareWire::write(uint8_t data)
{
if (transmitting){
if (txBufferLength >= BUFFER_LENGTH) {
return 0;
}
txBuffer[txBufferIndex] = data;
++txBufferIndex;
txBufferLength = txBufferIndex;
} else {
writeI2C(data);
}
return 1;
}
size_t SoftwareWire::write(const uint8_t *data, size_t length)
{
if (transmitting) {
for (size_t i = 0; i < length; ++i) write(data[i]);
} else {
for (size_t i = 0; i < length; ++i) writeI2C(data[i]);
}
return length;
}
int SoftwareWire::available(void)
{
return rxBufferLength - rxBufferIndex;
}
int SoftwareWire::read(void)
{
int value = -1;
if(rxBufferIndex < rxBufferLength){
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
}
return value;
}
int SoftwareWire::peek(void)
{
int value = -1;
if (rxBufferIndex < rxBufferLength) value = rxBuffer[rxBufferIndex];
return value;
}
void SoftwareWire::flush(void)
{
;
}
uint8_t SoftwareWire::readI2C(uint8_t last, bool first) {
uint8_t data = 0;
digitalWrite(_pinSDA, LOW);
if (!first)
{
delayI2Cus(DELAY_LONG);
pinMode(_pinSDA, INPUT);
delayI2Cus(DELAY_HALF);
}
for (uint8_t i = 0; i < 8; i++) {
if (first && i==0) {
data <<= 1;
if (digitalRead(_pinSDA)) data |= 1;
digitalWrite(_pinSCL, LOW);
pinMode(_pinSCL, OUTPUT);
delayI2Cus(DELAY_HALF);
}
else
{
data <<= 1;
digitalWrite(_pinSCL, HIGH);
delayI2Cus(DELAY_PART);
if (digitalRead(_pinSDA)) data |= 1;
delayI2Cus(DELAY_PART);
digitalWrite(_pinSCL, LOW);
delayI2Cus(DELAY_HALF);
}
}
pinMode(_pinSDA, OUTPUT);
digitalWrite(_pinSDA, last);
digitalWrite(_pinSCL, HIGH);
delayI2Cus(DELAY_HALF);
digitalWrite(_pinSCL, LOW);
digitalWrite(_pinSDA, LOW);
delayI2Cus(DELAY_LONG);
return data;
}
uint8_t SoftwareWire::readI2C(uint8_t* data, uint8_t length)
{
if (length > 1) {
while (--length) *data++= readI2C(false);
}
*data = readI2C(true);
}
bool SoftwareWire::restartI2C(uint8_t address, uint8_t RW) {
digitalWrite(_pinSDA, HIGH);
digitalWrite(_pinSCL, HIGH);
delayI2Cus(DELAY_FULL);
return startI2C(address, RW);
}
bool SoftwareWire::startI2C(uint8_t address, uint8_t RW) {
pinMode(_pinSDA, OUTPUT);
digitalWrite(_pinSDA, LOW);
digitalWrite(_pinSCL, LOW);
delayI2Cus(DELAY_FULL);
return writeI2C((address << 1) + RW);
}
void SoftwareWire::stopI2C(void) {
pinMode(_pinSDA, OUTPUT);
digitalWrite(_pinSDA, LOW);
delayI2Cus(DELAY_FULL);
digitalWrite(_pinSCL, HIGH);
delayI2Cus(DELAY_FULL);
digitalWrite(_pinSDA, HIGH);
delayI2Cus(DELAY_FULL);
}
void SoftwareWire::stallI2C(void) {
digitalWrite(_pinSDA, HIGH);
pinMode(_pinSDA, OUTPUT);
digitalWrite(_pinSCL, HIGH);
delayI2Cus(DELAY_FULL);
digitalWrite(_pinSDA, LOW);
delayI2Cus(DELAY_FULL);
}
bool SoftwareWire::writeI2C(uint8_t data) {
pinMode(_pinSDA, OUTPUT);
for (uint8_t i=0; i < 8; ++i ){
if (data & 0x80) digitalWrite(_pinSDA, HIGH);
else digitalWrite(_pinSDA, LOW);
digitalWrite(_pinSCL, HIGH);
data <<= 1;
delayI2Cus(DELAY_HALF);
digitalWrite(_pinSCL, LOW);
delayI2Cus(DELAY_HALF);
}
pinMode(_pinSDA, INPUT);
digitalWrite(_pinSCL, HIGH);
uint8_t result = !digitalRead(_pinSDA);
if (result) digitalWrite(_pinSDA, LOW);
delayI2Cus(DELAY_HALF);
digitalWrite(_pinSCL, LOW);
delayI2Cus(DELAY_FULL);
return result;
}
bool SoftwareWire::writeI2C(uint8_t* data, size_t length)
{
uint8_t result;
for (uint8_t i=0; i < length; i++) result = writeI2C(data[i]);
return result;
}
///
/// @mainpage I2C_Software
///
/// @details Software I2C for MSP430
/// @n
/// @n @b Contribute!
/// @n Help me for my developments: http://embeddedcomputing.weebly.com/contact
///
/// @n @a Developed with [embedXcode](http://embedXcode.weebly.com)
///
/// @author Rei VILO
/// @author http://embedXcode.weebly.com
/// @date Feb 10, 2014
/// @version 104
///
/// @copyright (c) Rei VILO, 2013-2014
/// @copyright CC = BY NC SA
///
/// @see
/// * ReadMe.txt for references
/// * TwoWire.h - TWI/I2C library for Arduino & Wiring
/// @n Copyright (c) 2006 Nicholas Zambetti. All right reserved.
/// * Arduino core files for MSP430
/// @n Copyright (c) 2012 Robert Wessels. All right reserved.
#ifndef I2C_MASTER_H
#define I2C_MASTER_H
#include "Energia.h"
#define BUFFER_LENGTH 16
class SoftwareWire {
public:
SoftwareWire(uint8_t pinSDA, uint8_t pinSCL);
void begin();
void beginTransmission(uint8_t address);
uint8_t endTransmission(void);
uint8_t endTransmission(uint8_t sendStop);
virtual size_t write(uint8_t data);
virtual size_t write(const uint8_t *data , size_t length);
uint8_t requestFrom(uint8_t address, uint8_t length);
virtual int available(void);
virtual int read(void);
virtual int peek(void);
virtual void flush(void);
private:
uint8_t readI2C(uint8_t last=false, bool first=false);
uint8_t readI2C(uint8_t* data, uint8_t length);
bool restartI2C(uint8_t address, uint8_t RW);
bool startI2C(uint8_t address, uint8_t RW);
void stopI2C();
void stallI2C();
bool writeI2C(uint8_t data);
bool writeI2C(uint8_t* data, size_t length);
uint8_t _pinSDA, _pinSCL;
static uint8_t txAddress;
static uint8_t rxBuffer[];
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;
static uint8_t txBuffer[];
static uint8_t txBufferIndex;
static uint8_t txBufferLength;
static uint8_t transmitting;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment