Skip to content

Commit

Permalink
V1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
felias-fogg committed Dec 14, 2023
1 parent 08cf33d commit db4255b
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 75 deletions.
59 changes: 59 additions & 0 deletions .github/workflows/LibraryBuild.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# LibraryBuild.yml
# Github workflow script to test compile all examples of an Arduino library repository.
#
# Copyright (C) 2021 Armin Joachimsmeyer
# https://github.com/ArminJo/Github-Actions

# This is the name of the workflow, visible on GitHub UI.
name: LibraryBuild

on:
workflow_dispatch: # To run it manually
push: # see: https://help.github.com/en/actions/reference/events-that-trigger-workflows#pull-request-event-pull_request
paths:
- '**.ino'
- '**.cpp'
- '**.h'
- '**LibraryBuild.yml'
pull_request:

jobs:
build:
name: ${{ matrix.arduino-boards-fqbn }} - test compiling examples

runs-on: ubuntu-latest # I picked Ubuntu to use shell scripts.

strategy:
matrix:
# The matrix will produce one job for each configuration parameter of type `arduino-boards-fqbn`
# In the Arduino IDE, the fqbn is printed in the first line of the verbose output for compilation as parameter -fqbn=... for the "arduino-builder -dump-prefs" command
#
# Examples: arduino:avr:uno, arduino:avr:leonardo, arduino:avr:nano, arduino:avr:mega
# arduino:sam:arduino_due_x, arduino:samd:arduino_zero_native"
# ATTinyCore:avr:attinyx5:chip=85,clock=1internal, digistump:avr:digispark-tiny, digistump:avr:digispark-pro
# STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8
# esp8266:esp8266:huzzah:eesz=4M3M,xtal=80, esp32:esp32:featheresp32:FlashFreq=80
# You may add a suffix behind the fqbn with "|" to specify one board for e.g. different compile options like arduino:avr:uno|trace
#############################################################################################################
arduino-boards-fqbn:
- arduino:avr:uno
- arduino:avr:leonardo

# Choose the right platform for the boards we want to test. (maybe in the future Arduino will automatically do this for you)
# With sketches-exclude you may exclude specific examples for a board. Use a comma separated list.
#############################################################################################################
# Do not cancel all jobs / architectures if one job fails
fail-fast: false

steps:
- name: Checkout
uses: actions/checkout@master

- name: Compile all examples
uses: ArminJo/arduino-test-compile@master
with:
arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }}
platform-url: ${{ matrix.platform-url }}
build-properties: ${{ toJson(matrix.build-properties) }}
cli-version: 0.33.0 # in order to avoid errors for ATTinyCore

19 changes: 17 additions & 2 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
CHANGELOG for FlexWire

V0.0.1 (30.1.2023)
V1.0.0 (14.12.2023)
- Fix: Set received bytes to zero in call to requestFrom when I2C
device NAKs on the device address
- Changed DELAY to I2C_DELAY
- Added Atomic Blocks for level changes, provided the AVR
architecture is used
- Added new example: multi_i2c
- Added new method: setPins
- removed the requestFrom call with internal registers (not
documented, but present in the Wire lib)
- Added the possibility to instantiate class without pin arguments;
these have to be set later using setPins
- removed i2c_start_wait

V0.0.1 (30.11.2023)
- initial commit, merging SlowSoftI2CMaster and SlowSoftMaster
- contains already Wire.h in the library folder
- contains already Wire.h in the library folder

2 changes: 1 addition & 1 deletion examples/i2cscanFlexWire/i2cscanFlexWire.ino
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

#include <FlexWire.h>

FlexWire Wire = FlexWire(A4, A5, true);
FlexWire Wire = FlexWire(A4, A5, false);

void setup()
{
Expand Down
66 changes: 66 additions & 0 deletions examples/multi_i2c/multi_i2c.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Demonstrate that we can replace Wire and use multiple instances to implement multiple I2C buses.
* We use the Sparkfun library for the HTU21D temp/humidity sensor to demonstrate that
*/

#define SHARESCL 0
#define SWITCHPINS 0

#include <FlexWire.h>
#include <SparkFunHTU21D.h>

#define MAXSENSOR 2

// The pins are we are going to use for the I2C buses
uint8_t sdapin[MAXSENSOR] = { 2, 4 };
#if SHARESCL
const uint8_t sclpin = 3;
#else
uint8_t sclpin[MAXSENSOR] = { 3, 5 };
#endif

#if SWITCHPINS
FlexWire Wire;
HTU21D htu;
#else
// Array of Flexwire instances
#if SHARESCL
FlexWire wire[MAXSENSOR] = { {sdapin[0], sclpin}, {sdapin[1], sclpin} };
#else
FlexWire wire[MAXSENSOR] = { {sdapin[0], sclpin[0]}, {sdapin[1], sclpin[1]} };
#endif
// Create array of instances of the HTU21D class
HTU21D htu[MAXSENSOR];
#endif

void setup()
{
Serial.begin(9600);
Serial.println(F("Multi-I2C example with HTU21D"));
#if SWITCHPINS
for (uint8_t i=0; i < MAXSENSOR; i++) {
Wire.setPins(sdapin[i], sclpin);
htu.begin();
}
#else
for (uint8_t i=0; i < MAXSENSOR; i++) htu[i].begin(wire[i]);
#endif
}

void loop()
{
for (uint8_t i=0; i < MAXSENSOR; i++) {
Serial.print(F("Sensor "));
Serial.print(i+1);
Serial.print(F(": "));
#if SWITCHPINS
Wire.setPins(sdapin[i], sclpin);
Serial.print(htu.readTemperature(), 1);
#else
Serial.print(htu[i].readTemperature(), 1);
#endif
Serial.println("C");
}
Serial.println();
delay(1000);
}
6 changes: 3 additions & 3 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name=FlexWire
version=0.0.1
version=1.0.0
author=Bernhard Nebel
maintainer=Bernhard Nebel <nebel@hinterm-ziel.de>
sentence=This library implements the master side of the I2C protocol.
paragraph=It can be used a drop-in replacement for the Wire library without even touching the sensor/actuator library, which uses Wire
sentence=This library implements the master side of the I2C protocol in a platform independent way.
paragraph=It can be used a drop-in replacement for the Wire library without even touching the sensor/actuator library, which uses the Wire library. The reason is that the library folder contains the header file Wire.h, which satisfies the dependency for the Wire library. In addition, it supports dynamic changes of the I2C pins.
category=Communication
url=https://github.com/felias-fogg/FlexWire
architectures=*
Expand Down
103 changes: 46 additions & 57 deletions src/FlexWire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
#include <FlexWire.h>

FlexWire::FlexWire(uint8_t sda, uint8_t scl, bool internal_pullup):
_sda(sda),
_scl(scl),
_pullup(internal_pullup) { }
_pullup(internal_pullup) {
setPins(sda, scl);
}

void FlexWire::begin(void) {
_rxBufferIndex = 0;
Expand All @@ -29,6 +29,12 @@ void FlexWire::begin(void) {
void FlexWire::setClock(uint32_t _) {
}

void FlexWire::setPins(uint8_t sda, uint8_t scl)
{
_sda = sda;
_scl = scl;
}

void FlexWire::beginTransmission(uint8_t address) {
if (_transmitting) {
_error = (i2c_rep_start((address<<1)|I2C_WRITE) ? 0 : 2);
Expand Down Expand Up @@ -79,59 +85,35 @@ size_t FlexWire::write(const uint8_t *data, size_t quantity) {
return trans;
}

uint8_t FlexWire::requestFrom(uint8_t address, uint8_t quantity,
uint32_t iaddress, uint8_t isize, uint8_t sendStop) {
uint8_t FlexWire::requestFrom(uint8_t address, uint8_t quantity, bool sendStop) {
uint8_t localerror = 0;
if (isize > 0) {
// send internal address; this mode allows sending a repeated start to access
// some devices' internal registers. This function is executed by the hardware
// TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers)
beginTransmission(address);
// the maximum size of internal address is 3 bytes
if (isize > 3){
isize = 3;
}
// write internal register address - most significant byte first
while (isize-- > 0)
write((uint8_t)(iaddress >> (isize*8)));
endTransmission(false);
}
// clamp to buffer length
if(quantity > BUFFER_LENGTH){
quantity = BUFFER_LENGTH;
}
localerror = !i2c_rep_start((address<<1) | I2C_READ);
if (_error == 0 && localerror) _error = 2;
// perform blocking read into buffer
for (uint8_t cnt=0; cnt < quantity; cnt++)
_rxBuffer[cnt] = i2c_read(cnt == quantity-1);
if (!localerror) {
for (uint8_t cnt=0; cnt < quantity; cnt++)
_rxBuffer[cnt] = i2c_read(cnt == quantity-1);
} else {
quantity = 0;
}
// set rx buffer iterator vars
_rxBufferIndex = 0;
_rxBufferLength = quantity;
if (sendStop) {
if (sendStop || _error != 0) {
_transmitting = 0;
i2c_stop();
}
return quantity;
}

uint8_t FlexWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) {
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint32_t)0, (uint8_t)0, (uint8_t)sendStop);
uint8_t FlexWire::requestFrom(int address, int quantity, bool sendStop) {
return requestFrom((uint8_t)address, (uint8_t)quantity, sendStop);
}

uint8_t FlexWire::requestFrom(int address, int quantity, int sendStop) {
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop);
}


uint8_t FlexWire::requestFrom(uint8_t address, uint8_t quantity) {
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}

uint8_t FlexWire::requestFrom(int address, int quantity) {
return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true);
}


int FlexWire::available(void) {
return _rxBufferLength - _rxBufferIndex;
}
Expand Down Expand Up @@ -159,23 +141,29 @@ void FlexWire::flush(void) {

// Init function. Needs to be called once in the beginning.
// Returns false if SDA or SCL are low, which probably means
// a I2C bus lockup or that the lines are not pulled up.
// an I2C bus lockup or that the lines are not pulled up.
bool FlexWire::i2c_init(void) {
digitalWrite(_sda, LOW);
digitalWrite(_scl, LOW);
setHigh(_sda);
delayMicroseconds(I2C_DELAY/2);
setHigh(_scl);
delayMicroseconds(I2C_DELAY/2);
setHigh(_sda);
delayMicroseconds(I2C_DELAY/2);
if (digitalRead(_sda) == LOW || digitalRead(_scl) == LOW) return false;
return true;
}

// Start transfer function: <addr> is the 8-bit I2C address (including the R/W
// bit).
// Return: true if the slave replies with an "acknowledge", false otherwise
// return also false when one of the lines is initially low (which might be a shortcut)
bool FlexWire::i2c_start(uint8_t addr) {
if (digitalRead(_sda) == 0 || digitalRead(_scl) == 0) return false;
setLow(_sda);
delayMicroseconds(DELAY);
delayMicroseconds(I2C_DELAY);
setLow(_scl);
delayMicroseconds(I2C_DELAY/2);
return i2c_write(addr);
}

Expand All @@ -185,38 +173,39 @@ bool FlexWire::i2c_start(uint8_t addr) {
// Return: true if the slave replies with an "acknowledge", false otherwise
bool FlexWire::i2c_rep_start(uint8_t addr) {
setHigh(_sda);
delayMicroseconds(I2C_DELAY/2);
setHigh(_scl);
delayMicroseconds(DELAY);
delayMicroseconds(I2C_DELAY);
return i2c_start(addr);
}

// Issue a stop condition, freeing the bus.
void FlexWire::i2c_stop(void) {
setLow(_sda);
delayMicroseconds(DELAY);
delayMicroseconds(I2C_DELAY);
setHigh(_scl);
delayMicroseconds(DELAY);
delayMicroseconds(I2C_DELAY);
setHigh(_sda);
delayMicroseconds(DELAY);
delayMicroseconds(I2C_DELAY);
}

// Write one byte to the slave chip that had been addressed
// by the previous start call. <value> is the byte to be sent.
// Return: true if the slave replies with an "acknowledge", false otherwise
bool FlexWire::i2c_write(uint8_t value) {
for (uint8_t curr = 0X80; curr != 0; curr >>= 1) {
for (uint8_t curr = 0x80; curr != 0; curr >>= 1) {
if (curr & value) setHigh(_sda); else setLow(_sda);
setHigh(_scl);
delayMicroseconds(DELAY);
delayMicroseconds(I2C_DELAY);
setLow(_scl);
}
// get Ack or Nak
setHigh(_sda);
setHigh(_scl);
delayMicroseconds(DELAY/2);
delayMicroseconds(I2C_DELAY/2);
uint8_t ack = digitalRead(_sda);
setLow(_scl);
delayMicroseconds(DELAY/2);
delayMicroseconds(I2C_DELAY/2);
setLow(_sda);
return ack == 0;
}
Expand All @@ -228,35 +217,35 @@ uint8_t FlexWire::i2c_read(bool last) {
setHigh(_sda);
for (uint8_t i = 0; i < 8; i++) {
b <<= 1;
delayMicroseconds(DELAY);
delayMicroseconds(I2C_DELAY);
setHigh(_scl);
if (digitalRead(_sda)) b |= 1;
setLow(_scl);
}
if (last) setHigh(_sda); else setLow(_sda);
setHigh(_scl);
delayMicroseconds(DELAY/2);
delayMicroseconds(I2C_DELAY/2);
setLow(_scl);
delayMicroseconds(DELAY/2);
delayMicroseconds(I2C_DELAY/2);
setLow(_sda);
return b;
}

void FlexWire::setLow(uint8_t pin) {
noInterrupts();
#ifdef ATOMIC_BLOCK
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#endif
{
if (_pullup)
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
interrupts();
}
}


void FlexWire::setHigh(uint8_t pin) {
noInterrupts();
if (_pullup)
pinMode(pin, INPUT_PULLUP);
else
pinMode(pin, INPUT);
interrupts();
}

Loading

0 comments on commit db4255b

Please sign in to comment.