First release of a Software I2C implementation, Tested and confirmed to work with the BMP085 Barometric Pressure Sensor
mbed Library to use a software master i2c interface on any GPIO pins
Copyright (c) 2012 Christopher Pepper
Released under the MIT License: http://mbed.org/license/mit
Revision 2:8670e78c4b63, committed 2012-04-01
- Comitter:
- p3p
- Date:
- Sun Apr 01 22:52:47 2012 +0000
- Parent:
- 1:6966eacc5914
- Commit message:
- Added the option to change the frequency (delay between GPIO toggles so blocking)
Changed in this revision
SoftwareI2C.cpp | Show annotated file Show diff for this revision Revisions of this file |
SoftwareI2C.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 6966eacc5914 -r 8670e78c4b63 SoftwareI2C.cpp --- a/SoftwareI2C.cpp Sun Apr 01 19:27:03 2012 +0000 +++ b/SoftwareI2C.cpp Sun Apr 01 22:52:47 2012 +0000 @@ -1,211 +1,212 @@ -/* - * mbed Library to use a software master i2c interface on any GPIO pins - * Copyright (c) 2012 Christopher Pepper - * Released under the MIT License: http://mbed.org/license/mit - */ - -#include "SoftwareI2C.h" - -/** - * @brief Initializes interface - * @param sda GPIO pin to use as I2C SDA - * @param scl GPIO pin to use as I2C SCL - */ - -SoftwareI2C::SoftwareI2C(PinName sda, PinName scl) : _sda(sda) , _scl(scl) { - _scl.output(); - _scl.mode(OpenDrain); - _sda.output(); - _sda.mode(OpenDrain); - - _device_address = 0; - - initialise(); -} - -SoftwareI2C::~SoftwareI2C() { - -} - -/** - * @brief Read 1 or more bytes from the I2C slave - * @param device_address The address of the device to read from - * @param data An allocated array to read the data into - * @param data_bytes Number of bytes to read (must be equal to or less then the allocated memory in data) - */ -void SoftwareI2C::read(uint8_t device_address, uint8_t* data, uint8_t data_bytes) { - if (data == 0 || data_bytes == 0) return; - - device_address = device_address | 0x01; - start(); - putByte(device_address); - getAck(); - for (int x = 0; x < data_bytes; ++x) { - data[x] = getByte(); - if ( x < (data_bytes -1)) { //ack all but the final byte - giveAck(); - } - } - stop(); -} - -/** - * @brief Write 1 or more bytes to the I2C slave - * @param device_address The address of the device to write to - * @param data An array to write the data from - * @param data_bytes Number of bytes to write from array - */ -void SoftwareI2C::write(uint8_t device_address, uint8_t* data, uint8_t data_bytes) { - if (data == 0 || data_bytes == 0) return; - - device_address = device_address & 0xFE; - start(); - putByte(device_address); - getAck(); - for ( int x = 0; x < data_bytes; ++x ) { - putByte(data[x]); - getAck(); - } - stop(); -} - -/** - * @brief Write 1 byte to the I2C slave - * @param device_address The address of the device to write to - * @param byte The data to write - */ -void SoftwareI2C::write(uint8_t device_address, uint8_t byte) { - device_address = device_address & 0xFE; - start(); - putByte(device_address); - getAck(); - putByte(byte); - getAck(); - stop(); -} - -/** - * @brief Read 1 or more bytes from the I2C slave at the specified memory address - * @param device_address The address of the device to read from - * @param start_address The memory address to read from - * @param data The allocated array to read into - * @param data_bytes The number of bytes to read - */ -void SoftwareI2C::randomRead(uint8_t device_address, uint8_t start_address, uint8_t* data, uint8_t data_bytes) { - if (data == 0 || data_bytes == 0) return; - - device_address = device_address & 0xFE; - start(); - putByte(device_address); - if (!getAck()) { - return; - } - putByte(start_address); - if (!getAck()) { - return; - } - - device_address=device_address | 0x01; - start(); - putByte(device_address); - if (!getAck()) { - return; - } - for ( int x = 0; x < data_bytes; ++x) { - data[x] = getByte(); - if (x != (data_bytes - 1)) giveAck(); - } - stop(); -} - -/** - * @brief Write 1 byte to the I2C slave at the specified memory address - * @param device_address The address of the device to write to - * @param start_address The memory address to write to - * @param byte The data to write - */ -void SoftwareI2C::randomWrite(uint8_t device_address, uint8_t start_address, uint8_t byte) { - device_address = device_address & 0xFE; - start(); - putByte(device_address); - getAck(); - putByte(start_address); - getAck(); - putByte(byte); - getAck(); - stop(); -} - -/** - * @brief Write 1 or more bytes to the I2C slave at the specified memory address - * @param device_address The address of the device to write to - * @param start_address The memory address to write to - * @param data The data to write - * @param data_bytes The number of bytes to write - */ -void SoftwareI2C::randomWrite(uint8_t device_address, uint8_t start_address, uint8_t* data, uint8_t data_bytes) { - if (data == 0 || data_bytes == 0) return; - - device_address = device_address & 0xFE; - start(); - putByte(device_address); - getAck(); - putByte(start_address); - getAck(); - for ( int x = 0; x <= data_bytes; ++x ) { - putByte(data[x]); - getAck(); - } - stop(); -} - -/** - * @brief Read 2 bytes from the I2C slave at the specified memory address and return them as an 16bit unsigned integer - * @param device_address The address of the device to read from - * @param start_address The memory address to read from - * @return MSB 16bit unsigned integer - */ -uint16_t SoftwareI2C::read16(uint8_t device_address, uint8_t start_address) { - uint8_t short_array[2] = {0, 0}; - randomRead(device_address, start_address, short_array, 2 ); - uint16_t value = 0; - value = short_array[0] << 8; - value |= short_array[1]; - - return value; -} - -/** - * @brief Read 3 bytes from the I2C slave at the specified memory address and return them as an 32bit unsigned integer - * @param device_address The address of the device to read from - * @param start_address The memory address to read from - * @return MSB 32bit unsigned integer - */ -uint32_t SoftwareI2C::read24(uint8_t device_address, uint8_t start_address) { - uint8_t value_array[4] = {0, 0, 0}; - randomRead(device_address, start_address, value_array, 3 ); - uint32_t value = 0; - value = value_array[0] << 16; - value |= value_array[1] << 8; - value |= value_array[2]; - - return value; -} - -/** - * @brief Read 4 bytes from the I2C slave at the specified memory address and return them as an 32bit unsigned integer - * @param device_address The address of the device to read from - * @param start_address The memory address to read from - * @return MSB 32bit unsigned integer - */ -uint32_t SoftwareI2C::read32(uint8_t device_address, uint8_t start_address) { - uint8_t value_array[4] = {0, 0, 0, 0}; - randomRead(device_address, start_address, value_array, 4 ); - uint32_t value = 0; - value = value_array[0] << 24; - value |= value_array[1] << 16; - value |= value_array[2] << 8; - value |= value_array[3]; - - return value; +/* + * mbed Library to use a software master i2c interface on any GPIO pins + * Copyright (c) 2012 Christopher Pepper + * Released under the MIT License: http://mbed.org/license/mit + */ + +#include "SoftwareI2C.h" + +/** + * @brief Initializes interface + * @param sda GPIO pin to use as I2C SDA + * @param scl GPIO pin to use as I2C SCL + */ + +SoftwareI2C::SoftwareI2C(PinName sda, PinName scl) : _sda(sda) , _scl(scl) { + _scl.output(); + _scl.mode(OpenDrain); + _sda.output(); + _sda.mode(OpenDrain); + + _device_address = 0; + _frequency_delay = 1; + + initialise(); +} + +SoftwareI2C::~SoftwareI2C() { + +} + +/** + * @brief Read 1 or more bytes from the I2C slave + * @param device_address The address of the device to read from + * @param data An allocated array to read the data into + * @param data_bytes Number of bytes to read (must be equal to or less then the allocated memory in data) + */ +void SoftwareI2C::read(uint8_t device_address, uint8_t* data, uint8_t data_bytes) { + if (data == 0 || data_bytes == 0) return; + + device_address = device_address | 0x01; + start(); + putByte(device_address); + getAck(); + for (int x = 0; x < data_bytes; ++x) { + data[x] = getByte(); + if ( x < (data_bytes -1)) { //ack all but the final byte + giveAck(); + } + } + stop(); +} + +/** + * @brief Write 1 or more bytes to the I2C slave + * @param device_address The address of the device to write to + * @param data An array to write the data from + * @param data_bytes Number of bytes to write from array + */ +void SoftwareI2C::write(uint8_t device_address, uint8_t* data, uint8_t data_bytes) { + if (data == 0 || data_bytes == 0) return; + + device_address = device_address & 0xFE; + start(); + putByte(device_address); + getAck(); + for ( int x = 0; x < data_bytes; ++x ) { + putByte(data[x]); + getAck(); + } + stop(); +} + +/** + * @brief Write 1 byte to the I2C slave + * @param device_address The address of the device to write to + * @param byte The data to write + */ +void SoftwareI2C::write(uint8_t device_address, uint8_t byte) { + device_address = device_address & 0xFE; + start(); + putByte(device_address); + getAck(); + putByte(byte); + getAck(); + stop(); +} + +/** + * @brief Read 1 or more bytes from the I2C slave at the specified memory address + * @param device_address The address of the device to read from + * @param start_address The memory address to read from + * @param data The allocated array to read into + * @param data_bytes The number of bytes to read + */ +void SoftwareI2C::randomRead(uint8_t device_address, uint8_t start_address, uint8_t* data, uint8_t data_bytes) { + if (data == 0 || data_bytes == 0) return; + + device_address = device_address & 0xFE; + start(); + putByte(device_address); + if (!getAck()) { + return; + } + putByte(start_address); + if (!getAck()) { + return; + } + + device_address=device_address | 0x01; + start(); + putByte(device_address); + if (!getAck()) { + return; + } + for ( int x = 0; x < data_bytes; ++x) { + data[x] = getByte(); + if (x != (data_bytes - 1)) giveAck(); + } + stop(); +} + +/** + * @brief Write 1 byte to the I2C slave at the specified memory address + * @param device_address The address of the device to write to + * @param start_address The memory address to write to + * @param byte The data to write + */ +void SoftwareI2C::randomWrite(uint8_t device_address, uint8_t start_address, uint8_t byte) { + device_address = device_address & 0xFE; + start(); + putByte(device_address); + getAck(); + putByte(start_address); + getAck(); + putByte(byte); + getAck(); + stop(); +} + +/** + * @brief Write 1 or more bytes to the I2C slave at the specified memory address + * @param device_address The address of the device to write to + * @param start_address The memory address to write to + * @param data The data to write + * @param data_bytes The number of bytes to write + */ +void SoftwareI2C::randomWrite(uint8_t device_address, uint8_t start_address, uint8_t* data, uint8_t data_bytes) { + if (data == 0 || data_bytes == 0) return; + + device_address = device_address & 0xFE; + start(); + putByte(device_address); + getAck(); + putByte(start_address); + getAck(); + for ( int x = 0; x <= data_bytes; ++x ) { + putByte(data[x]); + getAck(); + } + stop(); +} + +/** + * @brief Read 2 bytes from the I2C slave at the specified memory address and return them as an 16bit unsigned integer + * @param device_address The address of the device to read from + * @param start_address The memory address to read from + * @return MSB 16bit unsigned integer + */ +uint16_t SoftwareI2C::read16(uint8_t device_address, uint8_t start_address) { + uint8_t short_array[2] = {0, 0}; + randomRead(device_address, start_address, short_array, 2 ); + uint16_t value = 0; + value = short_array[0] << 8; + value |= short_array[1]; + + return value; +} + +/** + * @brief Read 3 bytes from the I2C slave at the specified memory address and return them as an 32bit unsigned integer + * @param device_address The address of the device to read from + * @param start_address The memory address to read from + * @return MSB 32bit unsigned integer + */ +uint32_t SoftwareI2C::read24(uint8_t device_address, uint8_t start_address) { + uint8_t value_array[4] = {0, 0, 0}; + randomRead(device_address, start_address, value_array, 3 ); + uint32_t value = 0; + value = value_array[0] << 16; + value |= value_array[1] << 8; + value |= value_array[2]; + + return value; +} + +/** + * @brief Read 4 bytes from the I2C slave at the specified memory address and return them as an 32bit unsigned integer + * @param device_address The address of the device to read from + * @param start_address The memory address to read from + * @return MSB 32bit unsigned integer + */ +uint32_t SoftwareI2C::read32(uint8_t device_address, uint8_t start_address) { + uint8_t value_array[4] = {0, 0, 0, 0}; + randomRead(device_address, start_address, value_array, 4 ); + uint32_t value = 0; + value = value_array[0] << 24; + value |= value_array[1] << 16; + value |= value_array[2] << 8; + value |= value_array[3]; + + return value; } \ No newline at end of file
diff -r 6966eacc5914 -r 8670e78c4b63 SoftwareI2C.h --- a/SoftwareI2C.h Sun Apr 01 19:27:03 2012 +0000 +++ b/SoftwareI2C.h Sun Apr 01 22:52:47 2012 +0000 @@ -33,6 +33,10 @@ void setDeviceAddress(uint8_t address){ _device_address = address; } + + void setFrequency(uint32_t frequency){ + _frequency_delay = 1000000 / frequency; + } inline void initialise() { _scl.output(); @@ -40,7 +44,7 @@ _sda = 1; _scl = 0; - wait_us(10); + wait_us(_frequency_delay); for ( int n = 0; n <= 3; ++n ) { stop(); @@ -50,33 +54,33 @@ private: inline void start() { _sda.output(); - wait_us(1); + wait_us(_frequency_delay); _scl = 1; _sda = 1; - wait_us(1); + wait_us(_frequency_delay); _sda = 0; - wait_us(1); + wait_us(_frequency_delay); _scl = 0; - wait_us(1); + wait_us(_frequency_delay); } inline void stop() { _sda.output(); - wait_us(1); + wait_us(_frequency_delay); _sda = 0; - wait_us(1); + wait_us(_frequency_delay); _scl = 1; - wait_us(1); + wait_us(_frequency_delay); _sda = 1; } inline void putByte(uint8_t byte) { _sda.output(); for ( int n = 8; n > 0; --n) { - wait_us(1); + wait_us(_frequency_delay); _sda = byte & (1 << (n-1)); _scl = 1; - wait_us(1); + wait_us(_frequency_delay); _scl = 0; } _sda = 1; @@ -88,15 +92,15 @@ _sda.input(); //release the data line _sda.mode(OpenDrain); - wait_us(1); + wait_us(_frequency_delay); for ( int n = 8; n > 0; --n ) { _scl=1; //set clock high - wait_us(1); + wait_us(_frequency_delay); byte |= _sda << (n-1); //read the bit - wait_us(1); + wait_us(_frequency_delay); _scl=0; //set clock low - wait_us(1); + wait_us(_frequency_delay); } _sda.output(); //take data line back @@ -106,10 +110,10 @@ inline void giveAck() { _sda.output(); - wait_us(1); + wait_us(_frequency_delay); _sda = 0; _scl = 1; - wait_us(1); + wait_us(_frequency_delay); _scl = 0; _sda = 1; @@ -121,12 +125,12 @@ _scl = 1; _sda.input(); _sda.mode(OpenDrain); - wait_us(1); + wait_us(_frequency_delay); _scl = 0; if(_sda != 0){return false;} - wait_us(1); + wait_us(_frequency_delay); return true; } @@ -134,6 +138,7 @@ DigitalInOut _scl; uint8_t _device_address; + uint32_t _frequency_delay; }; #endif \ No newline at end of file