Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Wire library support for TWI General Call #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions libraries/SoftwareSerial/SoftwareSerial.cpp
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,12 @@ SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inv
_buffer_overflow(false),
_inverse_logic(inverse_logic)
{
//set flag if rx and tx shares pin
if (transmitPin == receivePin)
_sharedRxTx = 1;
else
_sharedRxTx = 0;

setTX(transmitPin);
setRX(receivePin);
}
Expand All @@ -351,8 +357,14 @@ SoftwareSerial::~SoftwareSerial()

void SoftwareSerial::setTX(uint8_t tx)
{
pinMode(tx, OUTPUT);
digitalWrite(tx, HIGH);
//if rx and tx shares a pin, only set pin to output when writing
if(!_sharedRxTx){
pinMode(tx, OUTPUT);

//@edbaafi - if inverse logic is allowed, why would line rest high
//regardless if _invers_logic is set? Was inverse logic added for rx-only?
digitalWrite(tx, HIGH);
}
_transmitBitMask = digitalPinToBitMask(tx);
uint8_t port = digitalPinToPort(tx);
_transmitPortRegister = portOutputRegister(port);
Expand Down Expand Up @@ -450,6 +462,12 @@ size_t SoftwareSerial::write(uint8_t b)
uint8_t oldSREG = SREG;
cli(); // turn off interrupts for a clean txmit

//if rx and tx shares a pin, set pin to output when writing
if(_sharedRxTx){
//_receivePin same as transmit pin
pinMode(_receivePin, OUTPUT);
digitalWrite(_receivePin, HIGH);
}
// Write the start bit
tx_pin_write(_inverse_logic ? HIGH : LOW);
tunedDelay(_tx_delay + XMIT_START_ADJUSTMENT);
Expand Down Expand Up @@ -484,6 +502,26 @@ size_t SoftwareSerial::write(uint8_t b)
tx_pin_write(HIGH); // restore pin to natural state
}

//if rx and tx shares a pin, set back to input when done writing
if(_sharedRxTx){

pinMode(_receivePin, INPUT);
if (!_inverse_logic){
//@edbaafi - PORTx is already set to high for this pin
////but given questions about rest states when inverse logic, I'll leave this for clarity
digitalWrite(_receivePin, HIGH); // pullup for normal logic!
}
else{
//disable pullup

//@edbaafi - don't think this is happening by default by setting pinMode alone
////Haven't followed pinMode->portModeRegister->even_more_indirection but it appears to
////simply set DDRB without initializing PORTx and previous (rest) state is HIGH
////(even when inverse logic - see questions above)
digitalWrite(_receivePin,LOW);
}
}

SREG = oldSREG; // turn interrupts back on
tunedDelay(_tx_delay);

Expand Down
3 changes: 2 additions & 1 deletion libraries/SoftwareSerial/SoftwareSerial.h
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ The latest version of this library can always be found at
class SoftwareSerial : public Stream
{
private:
// per object data
// per object data
uint8_t _sharedRxTx;
uint8_t _receivePin;
uint8_t _receiveBitMask;
volatile uint8_t *_receivePortRegister;
Expand Down
58 changes: 45 additions & 13 deletions libraries/Wire/Wire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ uint8_t TwoWire::txBufferLength = 0;
uint8_t TwoWire::transmitting = 0;
void (*TwoWire::user_onRequest)(void);
void (*TwoWire::user_onReceive)(int);
void (*TwoWire::user_onGcallReceive)(int);

// Constructors ////////////////////////////////////////////////////////////////

Expand Down Expand Up @@ -208,12 +209,22 @@ void TwoWire::flush(void)
}

// behind the scenes function that is called when data is received
void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes, uint8_t isGeneralCall)
{
// don't bother if user hasn't registered a callback
if(!user_onReceive){
return;
}
//check if general call or normal receive
if(isGeneralCall){
// don't bother if user hasn't registered a general call callback
if(!user_onGcallReceive){
return;
}
}
else{
// don't bother if user hasn't registered a callback
if(!user_onReceive){
return;
}
}

// don't bother if rx buffer is in use by a master requestFrom() op
// i know this drops data, but it allows for slight stupidity
// meaning, they may not have read all the master requestFrom() data yet
Expand All @@ -228,8 +239,18 @@ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
// set rx iterator vars
rxBufferIndex = 0;
rxBufferLength = numBytes;
// alert user program
user_onReceive(numBytes);

if(isGeneralCall){
// alert user's general call receive callback
user_onGcallReceive(numBytes);
}
else{
// alert user's receive callback
user_onReceive(numBytes);
}



}

// behind the scenes function that is called when data is requested
Expand All @@ -247,16 +268,27 @@ void TwoWire::onRequestService(void)
user_onRequest();
}

// sets function called on slave write
void TwoWire::onReceive( void (*function)(int) )
// sets function called when slave receives data from master at slave's address
void TwoWire::onReceive( void (*recFunction)(int) )
{
user_onReceive = recFunction;
}

// sets function called when slave receives data from master at slaves address
// and another function called when slave receives data from a general call
void TwoWire::onReceive( void (*recFunction)(int), void (*gcallRecFunction)(int) )
{
user_onReceive = function;
user_onReceive = recFunction;
user_onGcallReceive = gcallRecFunction;

//enable general call addressing
twi_enableGenCall();
}

// sets function called on slave read
void TwoWire::onRequest( void (*function)(void) )
// sets function called when master requests data from slave
void TwoWire::onRequest( void (*reqFunction)(void) )
{
user_onRequest = function;
user_onRequest = reqFunction;
}

// Preinstantiate Objects //////////////////////////////////////////////////////
Expand Down
4 changes: 3 additions & 1 deletion libraries/Wire/Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ class TwoWire : public Stream
static uint8_t transmitting;
static void (*user_onRequest)(void);
static void (*user_onReceive)(int);
static void (*user_onGcallReceive)(int);
static void onRequestService(void);
static void onReceiveService(uint8_t*, int);
static void onReceiveService(uint8_t*, int,uint8_t);
public:
TwoWire();
void begin();
Expand All @@ -59,6 +60,7 @@ class TwoWire : public Stream
virtual int peek(void);
virtual void flush(void);
void onReceive( void (*)(int) );
void onReceive( void (*)(int), void (*)(int) );
void onRequest( void (*)(void) );

using Print::write;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Author: Ed Baafi
* Date: 11/11/11
*
* This example demonstrates the TWI (I2C) "General Call" capabilities.
*
* General call is like a broadcast that can be received by many listeners at the same same. This
* is useful when you don't know the address of the device you want to talk to or it can be used as
* a sort of interrupt over the TWI (I2C). For more info on General Call, please see the I2C specs.
*
* The Wire library now supports General Call by adding a second receive callback to Wire.onReceive()
* This second callback will be called whenever a message is received over the general call address.
*
* This code is for the master device. Instructions are in comments for the slave device code.
*
*/

#include <Wire.h>

//button to send a general call message (connect button between pin10 and ground)
#define GENERAL_CALL_ADDR_BUTTON 10
//button to send a normal i2c message (connect button between pin 9 and ground)
#define SLAVE_ADDR_BUTTON 9

#define SLAVE_ADDRESS 0x9
#define GENERAL_CALL_ADDR 0x0

//store state of slave message button
boolean slave_btn_state = HIGH;
//store state of general call message button
boolean general_call_btn_state = HIGH;

void setup() {
Serial.begin(9600);

//setup general call button as input with internal pullup
pinMode(GENERAL_CALL_ADDR_BUTTON, INPUT);
digitalWrite(GENERAL_CALL_ADDR_BUTTON, HIGH);

//setup normal i2c send button as input with internal pullup
pinMode(SLAVE_ADDR_BUTTON, INPUT);
digitalWrite(SLAVE_ADDR_BUTTON, HIGH);

//setup TWI as master
Wire.begin();

}

void loop() {
//if general call button state changes, send new state over message to general call address
if (digitalRead(GENERAL_CALL_ADDR_BUTTON) != general_call_btn_state){
general_call_btn_state = !general_call_btn_state;
Wire.beginTransmission(GENERAL_CALL_ADDR);
Wire.write(general_call_btn_state);
Wire.endTransmission();
delay(100);
}

//if slave address send button changes state, send new state over message to slave address
if (digitalRead(SLAVE_ADDR_BUTTON) != slave_btn_state){
slave_btn_state = !slave_btn_state;
Wire.beginTransmission(SLAVE_ADDRESS);
Wire.write(slave_btn_state);
Wire.endTransmission();
//we need a small delay or we'll crash the Wire library - TODO - fix it
delay(100);
}

}
84 changes: 84 additions & 0 deletions libraries/Wire/examples/general_call_slave/general_call_slave.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Author: Ed Baafi
* Date: 11/11/11
*
* This example demonstrates the TWI (I2C) "General Call" capabilities.
*
* General call is like a broadcast that can be received by many listeners at the same same. This
* is useful when you don't know the address of the device you want to talk to or it can be used as
* a sort of interrupt over the TWI (I2C). For more info on General Call, please see the I2C specs.
*
* The Wire library now supports General Call by adding a second receive callback to Wire.onReceive()
* This second callback will be called whenever a message is received over the general call address.
*
* 1) This code is for the slave device. Connect the slave device (through usb) to your PC and open
* up the serial monitor (set it to 9600 bps). You can optionally connect two LEDs to pins 12 and 11
*
* 2) On the master device, connect a button between pin10 and ground and another between pin9
* and ground. The pin10 button will send its state to the general call address (can be picked up by
* any attached slave device) and the pin9 button will sent through to a specific slave address.
*
* 3) Connect the SCL and SDA lines from the slave to the master. For UNO boards SDA is on analog pin
* 4 and SCL is on analog pin 5.
*
* 4) Pressing one button will send a message to general call and the other will send a message through
* the slave's address. Want to go further, add a second slave device and/or use the LEDs to see which
* address is being sent to.
*/

#include <Wire.h>

//led to tie to the master's general call i2c button
#define GENERAL_CALL_RECV_LED 12
//led to tie to the master's normal i2c button
#define RECV_LED 11

#define MY_ADDRESS 0x9

void setup() {
Serial.begin(9600);

//set general call led pin as output and set low (turn off)
pinMode(GENERAL_CALL_RECV_LED, OUTPUT);
digitalWrite(GENERAL_CALL_RECV_LED, LOW);

//set slave receive led pin as output and set low (turn off)
pinMode(RECV_LED, OUTPUT);
digitalWrite(RECV_LED, LOW);

//setup TWI as slave and set address
Wire.begin(MY_ADDRESS);

//setup first callback to fire when data is received on MY_ADDRESS
//and the second when a data is received on the general call address (0x0)
//if you omit the second callback, general call wil not be enabled in the Wire library
Wire.onReceive(receiveCallback,generalCallreceiveCallback);

}

void loop() {
//do nothing - wait for callbacks to fire
}

void receiveCallback(int howMany){
//print data sent to MY_ADDRESS to the serial monitor
Serial.print("\nRECIEIVED BYTE FROM SLAVE ADDRESS: ");
while (Wire.available() > 0 && howMany > 0){
boolean b = Wire.read();
Serial.print(b, DEC);
digitalWrite(RECV_LED, !b);
howMany--;
}
}

void generalCallreceiveCallback(int howMany){
//print data sent to the general call address to the serial monitor
Serial.print("\nRECEIVED BYTE FROM GENERAL CALL ADDRESS: ");
while (Wire.available() > 0 && howMany > 0){
boolean b = Wire.read();
Serial.print(b, DEC);
digitalWrite(GENERAL_CALL_RECV_LED, !b);
howMany--;
}
}

Loading