Merged with Wire implementation from stm32duino/Arduino_Core_STM32

This commit is contained in:
lacklustrlabs 2017-12-22 18:52:12 +01:00 committed by Lacklustrlabs
parent 78f8a90a2d
commit b46b7461f4
14 changed files with 885 additions and 456 deletions

View File

@ -15,7 +15,7 @@
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial communication at 9600bps
Serial.begin(115200); // start serial communication at 9600bps
}
int reading = 0;

View File

@ -8,7 +8,6 @@
*/
#include <Wire_slave.h>
#include <Arduino.h>
#include <libmaple/i2c.h>
#define USE_BUFFERED_EXAMPLE 1
@ -52,12 +51,8 @@ void functx(i2c_msg *msg){
#endif
// #define Serial Serial1
void setup() {
Serial.begin(115200);
while(!Serial)
;
Serial.println("I2C Slave example");
// attach the buffer

View File

@ -0,0 +1,78 @@
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire_slave.h>
//use IIC2
//TwoWire WIRE2 (2,I2C_FAST_MODE);
//#define Wire WIRE2
void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++) {
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
nDevices++;
}
else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found");
else
Serial.println("done");
delay(5000); // wait 5 seconds for next scan
}

View File

@ -15,12 +15,12 @@
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
Serial.begin(115200); // start serial for output
}
void loop()
{
Wire.requestFrom(2, 6); // request 6 bytes from slave device #2
Wire.requestFrom(8, 6); // request 6 bytes from slave device #8
while(Wire.available()) // slave may send less than requested
{

View File

@ -0,0 +1,68 @@
// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire_slave.h>
//#define Serial Serial1
#define MasterWire Wire
#define SlaveWire Wire1
#define ENABLE_SLAVE
#define ENABLE_MASTER
void receiveEvent(int howMany);
void setup(){
Serial.begin(115200); // start serial for output
#ifdef ENABLE_MASTER
MasterWire.begin(); // join i2c bus #1 as master
Serial.println("Done with MasterWire.begin ");
#endif
#ifdef ENABLE_SLAVE
SlaveWire.begin(4); // join i2c bus #2 as slave with address #4
Serial.println("Done with SlaveWire.begin ");
#endif
#ifdef ENABLE_SLAVE
SlaveWire.onReceive(receiveEvent); // register event
#endif
}
void loop(){
#ifdef ENABLE_MASTER
static byte x = 0;
Serial.print("Master writing ");
Serial.println(x);
MasterWire.beginTransmission(4); // transmit to device #4
MasterWire.write("x is "); // sends five bytes
MasterWire.write(x); // sends one byte
MasterWire.endTransmission(); // stop transmitting
x++;
#endif
delay(500);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
// Note that it is not advicable to call Serial.print() from within an ISR
void receiveEvent(int howMany){
//Serial.print("Slave receving ");
while(1 < SlaveWire.available()){ // loop through all but the last
char c = SlaveWire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = SlaveWire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}

View File

@ -0,0 +1,16 @@
// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
// The code is temporarily moved to the code.cpp.
// This makes it possible to set breakpoints in eclipse IDE.
// I'm sure that there is an Eclipse configuration that makes it
// possible for it to detect .ino files as .cpp, but I'm lazy

View File

@ -0,0 +1,37 @@
// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire_slave.h>
#define Serial Serial1
void setup(){
Serial.begin(115200); // start serial for output
Wire.begin(4); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
}
void loop(){
delay(100);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
// Note that it is not advicable to call Serial.print() from within an ISR
void receiveEvent(int howMany){
while(1 < Wire.available()){ // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}

View File

@ -0,0 +1,32 @@
// Wire Slave Sender
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Sends data as an I2C/TWI slave device
// Refer to the "Wire Master Reader" example for use with this
// Created 29 March 2006
// This example code is in the public domain.
#include <Wire_slave.h>
void setup()
{
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
}
void loop()
{
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
Wire.write("hello "); // respond with message of 6 bytes
// as expected by master
}

View File

@ -1,106 +1,523 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file TwoWire.cpp
* @author Trystan Jones <crenn6977@gmail.com>
* @brief Wire library, uses the hardware I2C available in the Maple to
* interact with I2C slave devices.
*/
/*
* Library created by crenn to use the new WireBase system and allow Arduino
* users easy interaction with the I2C Hardware in a familiar method.
TwoWire.cpp - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
*/
extern "C" {
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
}
#include "Wire_slave.h"
#include "wirish.h"
#include <libmaple/i2c_slave.h>
uint8 TwoWire::process(uint8 stop) {
int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0);
if (res == I2C_ERROR_PROTOCOL) {
if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */
res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR :
ENACKTRNS);
} else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */
res = EDATA;
} else { /* Bus or Arbitration error */
res = EOTHER;
}
i2c_disable(sel_hard);
i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags));
}
return res;
#define BUFFER_LENGTH 32
#define MASTER_ADDRESS 0x33
// Constructors ////////////////////////////////////////////////////////////////
TwoWire::TwoWire(i2c_dev* i2cDevice) :
sel_hard(i2cDevice),
rxBuffer(nullptr),
rxBufferAllocated(0),
rxBufferIndex(0),
rxBufferLength(0),
txBuffer(nullptr),
txBufferAllocated(0),
txBufferIndex(0),
txBufferLength(0),
transmitting(false),
master(true),
dev_flags(0),
itc_msg(),
itc_slave_msg(),
user_onRequest(nullptr),
user_onReceive(nullptr) {
}
uint8 TwoWire::process(){
return process(true);
// Public Methods //////////////////////////////////////////////////////////////
void TwoWire::begin(void) {
begin(MASTER_ADDRESS);
}
// TODO: Add in Error Handling if devsel is out of range for other Maples
TwoWire::TwoWire(uint8 dev_sel, uint8 flags) {
if (dev_sel == 1) {
sel_hard = I2C1;
} else if (dev_sel == 2) {
sel_hard = I2C2;
} else {
ASSERT(1);
}
dev_flags = flags;
}
void TwoWire::begin(uint8_t address){
TwoWire::~TwoWire() {
i2c_disable(sel_hard);
sel_hard = 0;
}
rxBufferIndex = 0;
rxBufferLength = 0;
allocateRxBuffer(BUFFER_LENGTH);
void TwoWire::begin(uint8 self_addr) {
txBufferIndex = 0;
txBufferLength = 0;
allocateTxBuffer(BUFFER_LENGTH);
transmitting = 0;
master = (address == MASTER_ADDRESS);
// Set default speed to 100KHz
if (master) {
dev_flags = 0;
i2c_master_enable(sel_hard, dev_flags);
} else {
// TODO: I2C_SLAVE_DUAL_ADDRESS ?
dev_flags = I2C_SLAVE_GENERAL_CALL | I2C_SLAVE_USE_RX_BUFFER |
I2C_SLAVE_USE_TX_BUFFER;
itc_slave_msg.addr = address;
itc_slave_msg.flags = 0;
itc_slave_msg.data = rxBuffer;
itc_slave_msg.length = 0;
itc_slave_msg.flags = 0;
// TODO why does enable only work before setting IRS and address?
i2c_slave_enable(sel_hard, dev_flags);
if (sel_hard==I2C1){
// attach receive handler
i2c_slave_attach_recv_handler(sel_hard, &itc_slave_msg, onReceiveService1);
// attach transmit handler
i2c_slave_attach_transmit_handler(sel_hard, &itc_slave_msg, onRequestService1);
}
#if WIRE_INTERFACES_COUNT > 1
else if (sel_hard==I2C2){
// attach receive handler
i2c_slave_attach_recv_handler(sel_hard, &itc_slave_msg, onReceiveService2);
// attach transmit handler
i2c_slave_attach_transmit_handler(sel_hard, &itc_slave_msg, onRequestService2);
}
#endif
i2c_slave_set_own_address(sel_hard, address);
}
}
void TwoWire::end() {
void TwoWire::begin(int address) {
begin((uint8_t) address);
}
void TwoWire::end(void) {
free(txBuffer);
txBuffer = nullptr;
txBufferAllocated = 0;
free(rxBuffer);
rxBuffer = nullptr;
rxBufferAllocated = 0;
i2c_peripheral_disable(sel_hard);
i2c_master_release_bus(sel_hard); // TODO is this required?
}
void TwoWire::setClock(uint32_t frequencyHz) {
switch (frequencyHz) {
case 400000:
dev_flags |= I2C_FAST_MODE; // set FAST_MODE bit
break;
case 100000:
default:
dev_flags &= ~I2C_FAST_MODE; // clear FAST_MODE bit
break;
}
if (sel_hard->regs->CR1 & I2C_CR1_PE){
i2c_disable(sel_hard);
sel_hard = 0;
i2c_master_enable(sel_hard, dev_flags);
}
}
void TwoWire::setClock(uint32_t frequencyHz)
{
switch(frequencyHz)
{
case 400000:
dev_flags |= I2C_FAST_MODE;// set FAST_MODE bit
break;
case 100000:
default:
dev_flags &= ~I2C_FAST_MODE;// clear FAST_MODE bit
break;
}
if (sel_hard->regs->CR1 & I2C_CR1_PE){
i2c_disable(sel_hard);
i2c_master_enable(sel_hard, dev_flags);
}
uint8 TwoWire::process(bool stop) {
int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0);
if (res == I2C_ERROR_PROTOCOL) {
if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */
res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR : ENACKTRNS);
} else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */
res = EDATA;
} else { /* Bus or Arbitration error */
res = EOTHER;
}
i2c_disable(sel_hard);
i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags));
}
return res;
}
TwoWire Wire(1);
//TODO: Add the ability to queue messages (adding a boolean to end of function
// call, allows for the Arduino style to stay while also giving the flexibility
// to bulk send
uint8 TwoWire::requestFrom(uint8_t address, uint8_t num_bytes,
uint32_t iaddress, uint8_t isize, uint8_t sendStop) {
ASSERT(master);
allocateRxBuffer(num_bytes);
// error if no memory block available to allocate the buffer
if (rxBuffer == nullptr) {
return EDATA;
}
// reset tx buffer iterator vars
rxBufferIndex = 0;
rxBufferLength = 0;
if (num_bytes > BUFFER_LENGTH) {
num_bytes = BUFFER_LENGTH;
}
itc_msg.addr = address;
itc_msg.flags = I2C_MSG_READ;
itc_msg.length = num_bytes;
itc_msg.data = &rxBuffer[rxBufferIndex];
process(sendStop); // TODO deal with to the return value
// TODO handle iaddress & isize
rxBufferLength += itc_msg.xferred;
itc_msg.flags = 0;
return rxBufferLength;
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity,
uint8_t sendStop) {
// TODO shouldn't this set flag |= I2C_MSG_10BIT_ADDR ???
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0,
(uint8_t) 0, sendStop);
}
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) {
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0,
(uint8_t) 0, (uint8_t) true);
}
uint8_t TwoWire::requestFrom(int address, int quantity) {
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0,
(uint8_t) 0, (uint8_t) true);
}
uint8_t TwoWire::requestFrom(int address, int quantity,
int sendStop) {
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0,
(uint8_t) 0, (bool) sendStop);
}
void TwoWire::beginTransmission(uint8_t address) {
// indicate that we are transmitting
transmitting = 1;
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
itc_msg.addr = address;
itc_msg.data = &txBuffer[txBufferIndex];
itc_msg.length = 0;
itc_msg.flags = 0;
}
void TwoWire::beginTransmission(int address) {
beginTransmission((uint8_t) address);
}
//
// Originally, 'endTransmission' was an f(void) function.
// It has been modified to take one parameter indicating
// whether or not a STOP should be performed on the bus.
// Calling endTransmission(false) allows a sketch to
// perform a repeated start.
//
// WARNING: Nothing in the library keeps track of whether
// the bus tenure has been properly ended with a STOP. It
// is very possible to leave the bus in a hung state if
// no call to endTransmission(true) is made. Some I2C
// devices will behave oddly if they do not see a STOP.
//
uint8_t TwoWire::endTransmission(uint8_t sendStop) {
//UNUSED(sendStop);
int8_t ret = 4;
if (master == true) {
itc_msg.data = txBuffer;
itc_msg.length = txBufferLength;
itc_msg.flags = 0;
ret = process(sendStop); // Changed so that the return value from process is returned by this function see also the return line below
txBufferIndex = 0;
// reset Tx buffer
resetTxBuffer(); // TODO why? isn't this just unesssesary?
// reset tx buffer iterator vars
txBufferIndex = 0;
txBufferLength = 0;
// indicate that we are done transmitting
transmitting = 0;
}
return ret;
}
// This provides backwards compatibility with the original
// definition, and expected behaviour, of endTransmission
//
uint8_t TwoWire::endTransmission(void) {
return endTransmission(true);
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
size_t TwoWire::write(uint8_t data) {
if (!transmitting && master) {
return 0;
} else {
// in master transmitter mode or slave tx event callback
allocateTxBuffer(txBufferLength + 1);
// error if no memory block available to allocate the buffer
if (txBuffer == nullptr) {
setWriteError();
return 0;
}
// put byte in tx buffer
txBuffer[txBufferIndex] = data;
++txBufferIndex;
// update amount in buffer
txBufferLength = txBufferIndex;
}
return 1;
}
/**
* @brief This function must be called in slave Tx event callback or after
* beginTransmission() and before endTransmission().
* @param pdata: pointer to the buffer data
* @param quantity: number of bytes to write
* @retval number of bytes ready to write.
*/
size_t TwoWire::write(const uint8_t *data, size_t quantity) {
if (!transmitting && master) {
return 0;
} else {
// in master transmitter mode or slave Tx event callback
allocateTxBuffer(txBufferLength + quantity);
// error if no memory block available to allocate the buffer
if (txBuffer == nullptr) {
setWriteError();
return 0;
}
// put bytes in tx buffer
memcpy(&(txBuffer[txBufferIndex]), data, quantity);
txBufferIndex = txBufferIndex + quantity;
// update amount in buffer
txBufferLength = txBufferIndex;
return quantity;
}
return 0;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::available(void) {
return rxBufferLength - rxBufferIndex;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::read(void) {
int value = -1;
// get each successive byte on each call
if (rxBufferIndex < rxBufferLength) {
value = rxBuffer[rxBufferIndex];
++rxBufferIndex;
/* Commented as not I think it is not useful
* but kept to show that it is possible to
* reset rx buffer when no more data available */
/*if(rxBufferIndex == rxBufferLength) {
resetRxBuffer();
}*/
}
return value;
}
// must be called in:
// slave rx event callback
// or after requestFrom(address, numBytes)
int TwoWire::peek(void) {
int value = -1;
if (rxBufferIndex < rxBufferLength) {
value = rxBuffer[rxBufferIndex];
}
return value;
}
void TwoWire::flush(void) {
rxBufferIndex = 0;
rxBufferLength = 0;
resetRxBuffer();
txBufferIndex = 0;
txBufferLength = 0;
resetTxBuffer();
}
// behind the scenes function that is called when data is received
void __attribute__((always_inline)) TwoWire::onReceiveService(i2c_msg* msg) {
// 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
if (rxBufferIndex < rxBufferLength) {
return;
}
// copy twi rx buffer into local read buffer
// this enables new reads to happen in parallel
//
// TODO: Something is strange here, isn't msg->data==rxBuffer? nope, itsnot
//
memcpy(rxBuffer, msg->data, msg->length);
// set rx iterator vars
rxBufferIndex = 0;
rxBufferLength = msg->length;
// alert user program
user_onReceive(msg->length);
}
// behind the scenes function that is called when data is requested
void __attribute__((always_inline)) TwoWire::onRequestService(i2c_msg* msg) {
// don't bother if user hasn't registered a callback
if (!user_onRequest) {
return;
}
// reset tx buffer iterator vars
// !!! this will kill any pending pre-master sendTo() activity
txBufferIndex = 0;
txBufferLength = 0;
// alert user program
user_onRequest();
// update i2c_msg
msg->data = txBuffer;
msg->length = txBufferLength;
msg->xferred = 0;
}
// sets function called on slave write
void TwoWire::onReceive(void (*function)(int)) {
user_onReceive = function;
}
// sets function called on slave read
void TwoWire::onRequest(void (*function)(void)) {
user_onRequest = function;
}
/**
* @brief Allocate the Rx/Tx buffer to the requested length if needed
* @note Minimum allocated size is BUFFER_LENGTH)
* @param length: number of bytes to allocate
*/
inline void TwoWire::allocateRxBuffer(size_t length) {
// By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
if (length < BUFFER_LENGTH) {
length = BUFFER_LENGTH;
}
if (rxBufferAllocated < length) {
rxBuffer = (uint8_t *) realloc(rxBuffer, length * sizeof(uint8_t));
rxBufferAllocated = (rxBuffer != nullptr) ? length : 0;
}
}
inline void TwoWire::allocateTxBuffer(size_t length) {
// By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
if (length < BUFFER_LENGTH) {
length = BUFFER_LENGTH;
}
if (txBufferAllocated < length) {
txBuffer = (uint8_t *) realloc(txBuffer, length * sizeof(uint8_t));
txBufferAllocated = (txBuffer != nullptr) ? length : 0;
}
}
/**
* @brief Reset Rx/Tx buffer content to 0
*/
inline void TwoWire::resetRxBuffer(void) {
if (rxBuffer != nullptr)
memset(rxBuffer, 0, rxBufferAllocated);
}
inline void TwoWire::resetTxBuffer(void) {
if (txBuffer != nullptr)
memset(txBuffer, 0, txBufferAllocated);
}
// Preinstantiate Objects //////////////////////////////////////////////////////
TwoWire& Wire = TwoWire::getInstance(); //SCL:D14 SDA:D15
#if WIRE_INTERFACES_COUNT > 1
TwoWire& Wire1 = TwoWire::getInstance1(); //SCL: D1 SDA: D0
#endif
// Static methods //////////////////////////////////////////////////////////////
TwoWire& TwoWire::getInstance(){
static TwoWire instance(I2C1);
return instance;
}
#if WIRE_INTERFACES_COUNT > 1
TwoWire& TwoWire::getInstance1(){
static TwoWire instance(I2C2);
return instance;
}
#endif
// onRequestServiceX and onReceiveServiceX can't be inline since they
// are exclusively called via a function pointer
void TwoWire::onRequestService1(i2c_msg* msg) {
Wire.onRequestService(msg);
}
void TwoWire::onReceiveService1(i2c_msg* msg) {
Wire.onReceiveService(msg);
}
#if WIRE_INTERFACES_COUNT > 1
void TwoWire::onRequestService2(i2c_msg* msg) {
Wire1.onRequestService(msg);
}
void TwoWire::onReceiveService2(i2c_msg* msg) {
Wire1.onReceiveService(msg);
}
#endif

View File

@ -1,78 +1,149 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file Wire.h
* @author Trystan Jones <crenn6977@gmail.com>
* @brief Wire library, uses the hardware I2C available in the Maple to
* interact with I2C slave devices.
*/
/*
* Library created by crenn to use the new WireBase system and allow Arduino
* users easy interaction with the I2C Hardware in a familiar method.
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
*/
#ifndef _TWOWIRE_H_
#define _TWOWIRE_H_
#ifndef TwoWire_h
#define TwoWire_h
#include "utility/WireBase_slave.h"
#include "wirish.h"
#include <inttypes.h>
#include "Stream.h"
#include "Arduino.h"
#include <libmaple/i2c_slave.h>
class TwoWire : public WireBase {
// WIRE_HAS_END means Wire has end()
#ifndef WIRE_HAS_END
#define WIRE_HAS_END 1
#endif
#ifndef WIRE_INTERFACES_COUNT
#define WIRE_INTERFACES_COUNT 2
#endif
/* return codes from endTransmission() */
typedef enum EndTranmissionCodes {
SUCCESS = 0, /* transmission was successful */
EDATA = 1, /* too much data */
ENACKADDR = 2, /* received nack on transmit of address */
ENACKTRNS = 3, /* received nack on transmit of data */
EOTHER = 4, /* other error */
} EndTranmissionCodes;
class TwoWire: public Stream {
private:
i2c_dev* sel_hard;
uint8 dev_flags;
protected:
/*
* Processes the incoming I2C message defined by WireBase to the
* hardware. If an error occured, restart the I2C device.
*/
uint8 process(uint8);
uint8 process();
i2c_dev* sel_hard;
uint8_t *rxBuffer; // lazy allocation
uint8_t rxBufferAllocated;
uint8_t rxBufferIndex;
uint8_t rxBufferLength;
uint8_t *txBuffer; // lazy allocation
uint8_t txBufferAllocated;
uint8_t txBufferIndex;
uint8_t txBufferLength;
uint8_t transmitting;
bool master;
uint8 dev_flags;
i2c_msg itc_msg;
i2c_msg itc_slave_msg;
void (*user_onRequest)(void);
void (*user_onReceive)(int);
void allocateRxBuffer(size_t length);
void allocateTxBuffer(size_t length);
void resetRxBuffer(void);
void resetTxBuffer(void);
uint8 process(bool stop = true); // wrapper for i2c_master_xfer
inline void __attribute__((always_inline)) onReceiveService(i2c_msg* msg);
inline void __attribute__((always_inline)) onRequestService(i2c_msg* msg);
static void onRequestService1(i2c_msg*);
static void onReceiveService1(i2c_msg*);
#if WIRE_INTERFACES_COUNT > 1
static void onRequestService2(i2c_msg*);
static void onReceiveService2(i2c_msg*);
#endif
TwoWire(i2c_dev* i2cDevice);
TwoWire() = delete;
TwoWire(const TwoWire&) = delete;
TwoWire& operator=(const TwoWire&) = delete;
TwoWire(TwoWire&&) = delete;
TwoWire& operator=(TwoWire&&) = delete;
public:
/*
* Check if devsel is within range and enable selected I2C interface with
* passed flags
*/
TwoWire(uint8, uint8 = 0);
static TwoWire& getInstance();
#if WIRE_INTERFACES_COUNT > 1
static TwoWire& getInstance1();
#endif
/*
* Shuts down (disables) the hardware I2C
*/
void end();
void begin();
void begin(uint8_t);
void begin(int);
void end();
void setClock(uint32_t);
void beginTransmission(uint8_t);
void beginTransmission(int);
uint8_t endTransmission(void);
uint8_t endTransmission(uint8_t);
void setClock(uint32_t frequencyHz);
/*
* Disables the I2C device and remove the device address.
*/
~TwoWire();
uint8_t requestFrom(uint8_t, uint8_t);
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t);
uint8_t requestFrom(int, int);
uint8_t requestFrom(int, int, int);
void begin(uint8 = 0x00);
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *, size_t);
virtual int available(void);
virtual int read(void);
virtual int peek(void);
virtual void flush(void);
void onReceive(void (*)(int));
void onRequest(void (*)(void));
inline size_t write(unsigned long n) {
return write((uint8_t) n);
}
inline size_t write(long n) {
return write((uint8_t) n);
}
inline size_t write(unsigned int n) {
return write((uint8_t) n);
}
inline size_t write(int n) {
return write((uint8_t) n);
}
using Print::write;
};
extern TwoWire Wire;
#endif // _TWOWIRE_H_
extern TwoWire& Wire;
#if WIRE_INTERFACES_COUNT > 1
extern TwoWire& Wire1;
#endif
#endif // TwoWire_h

Binary file not shown.

View File

@ -158,6 +158,7 @@ void i2c_bus_reset(const i2c_dev *dev) {
* @param dev Device to initialize.
*/
void i2c_init(i2c_dev *dev) {
rcc_reset_dev(dev->clk_id);
rcc_clk_enable(dev->clk_id);
_i2c_irq_priority_fixup(dev);
@ -197,8 +198,10 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) {
i2c_init(dev);
i2c_config_gpios(dev);
/* Configure clock and rise time */
set_ccr_trise(dev, flags);
/* Configure clock and rise time, but only if in master mode */
if (!(flags & (I2C_SLAVE_DUAL_ADDRESS|I2C_SLAVE_GENERAL_CALL))) {
set_ccr_trise(dev, flags);
}
/* Enable event and buffer interrupts */
nvic_irq_enable(dev->ev_nvic_line);
@ -245,8 +248,9 @@ void i2c_master_enable(i2c_dev *dev, uint32 flags) {
* Callback will be called before tx
*/
void i2c_slave_enable(i2c_dev *dev, uint32 flags) {
// TODO: Figure out why i2c_disable(I2C2) causes a crash when I2C1 is enabled
i2c_disable(dev);
i2c_master_enable(dev, dev->config_flags | flags);
i2c_master_enable(dev, flags);
}
/**
@ -329,7 +333,8 @@ static inline int32 wait_for_state_change(i2c_dev *dev,
*/
/*
* IRQ handler for I2C master. Handles transmission/reception.
* IRQ handler for I2C master and slave.
* Handles transmission/reception.
*/
void _i2c_irq_handler(i2c_dev *dev) {
/* WTFs:
@ -676,7 +681,7 @@ void _i2c_irq_error_handler(i2c_dev *dev) {
I2C_SR1_OVR);
/* Are we in slave mode? */
if ((dev->regs->SR2 & I2C_SR2_MSL) != I2C_SR2_MSL) {
if (dev->config_flags & (I2C_SLAVE_DUAL_ADDRESS|I2C_SLAVE_GENERAL_CALL)) {
/* Check to see if the master device did a NAK on the last bit
* This is perfectly valid for a master to do this on the bus.
* We ignore this. Any further error processing takes us into dead

View File

@ -1,145 +0,0 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file WireBase.cpp
* @author Trystan Jones <crenn6977@gmail.com>
* @brief Wire library, following the majority of the interface from Arduino.
* Provides a 'standard' interface to I2C (two-wire) communication for
* derived classes.
*/
/*
* Library created by crenn to allow a system which would provide users the
* 'standardised' Arduino method for interfacing with I2C devices regardless of
* whether it is I2C hardware or emulating software.
*/
#include "WireBase_slave.h"
#include "wirish.h"
void WireBase::begin(uint8 self_addr) {
tx_buf_idx = 0;
tx_buf_overflow = false;
rx_buf_idx = 0;
rx_buf_len = 0;
}
void WireBase::beginTransmission(uint8 slave_address) {
itc_msg.addr = slave_address;
itc_msg.data = &tx_buf[tx_buf_idx];
itc_msg.length = 0;
itc_msg.flags = 0;
}
void WireBase::beginTransmission(int slave_address) {
beginTransmission((uint8)slave_address);
}
uint8 WireBase::endTransmission(bool stop) {
uint8 retVal;
if (tx_buf_overflow) {
return EDATA;
}
retVal = process(stop);// Changed so that the return value from process is returned by this function see also the return line below
tx_buf_idx = 0;
tx_buf_overflow = false;
return retVal;//SUCCESS;
}
uint8 WireBase::endTransmission(){
endTransmission(true);
}
//TODO: Add the ability to queue messages (adding a boolean to end of function
// call, allows for the Arduino style to stay while also giving the flexibility
// to bulk send
uint8 WireBase::requestFrom(uint8 address, int num_bytes) {
if (num_bytes > BUFFER_LENGTH) {
num_bytes = BUFFER_LENGTH;
}
itc_msg.addr = address;
itc_msg.flags = I2C_MSG_READ;
itc_msg.length = num_bytes;
itc_msg.data = &rx_buf[rx_buf_idx];
process();
rx_buf_len += itc_msg.xferred;
itc_msg.flags = 0;
return rx_buf_len;
}
uint8 WireBase::requestFrom(int address, int numBytes) {
return WireBase::requestFrom((uint8)address, numBytes);
}
void WireBase::write(uint8 value) {
if (tx_buf_idx == BUFFER_LENGTH) {
tx_buf_overflow = true;
return;
}
tx_buf[tx_buf_idx++] = value;
itc_msg.length++;
}
void WireBase::write(uint8* buf, int len) {
for (uint8 i = 0; i < len; i++) {
write(buf[i]);
}
}
void WireBase::write(int value) {
write((uint8)value);
}
void WireBase::write(int* buf, int len) {
write((uint8*)buf, (uint8)len);
}
void WireBase::write(char* buf) {
uint8 *ptr = (uint8*)buf;
while (*ptr) {
write(*ptr);
ptr++;
}
}
uint8 WireBase::available() {
return rx_buf_len - rx_buf_idx;
}
uint8 WireBase::read() {
if (rx_buf_idx == rx_buf_len) {
rx_buf_idx = 0;
rx_buf_len = 0;
return 0;
} else if (rx_buf_idx == (rx_buf_len-1)) {
uint8 temp = rx_buf[rx_buf_idx];
rx_buf_idx = 0;
rx_buf_len = 0;
return temp;
}
return rx_buf[rx_buf_idx++];
}

View File

@ -1,145 +0,0 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file WireBase.h
* @author Trystan Jones <crenn6977@gmail.com>
* @brief Wire library, following the majority of the interface from Arduino.
* Provides a 'standard' interface to I2C (two-wire) communication for
* derived classes.
*/
/*
* Library created by crenn to allow a system which would provide users the
* 'standardised' Arduino method for interfacing with I2C devices regardless of
* whether it is I2C hardware or emulating software.
*/
#ifndef _WIREBASE_H_
#define _WIREBASE_H_
#include "wirish.h"
#include <libmaple/i2c_slave.h>
#define BUFFER_LENGTH 32
/* return codes from endTransmission() */
#define SUCCESS 0 /* transmission was successful */
#define EDATA 1 /* too much data */
#define ENACKADDR 2 /* received nack on transmit of address */
#define ENACKTRNS 3 /* received nack on transmit of data */
#define EOTHER 4 /* other error */
class WireBase { // Abstraction is awesome!
protected:
i2c_msg itc_msg;
uint8 rx_buf[BUFFER_LENGTH]; /* receive buffer */
uint8 rx_buf_idx; /* first unread idx in rx_buf */
uint8 rx_buf_len; /* number of bytes read */
uint8 tx_buf[BUFFER_LENGTH]; /* transmit buffer */
uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow
boolean tx_buf_overflow;
// Force derived classes to define process function
virtual uint8 process(uint8) = 0;
virtual uint8 process() = 0;
public:
WireBase() {}
~WireBase() {}
/*
* Initialises the class interface
*/
// Allow derived classes to overwrite begin function
virtual void begin(uint8 = 0x00);
/*
* Sets up the transmission message to be processed
*/
void beginTransmission(uint8);
/*
* Allow only 8 bit addresses to be used
*/
void beginTransmission(int);
/*
* Call the process function to process the message if the TX
* buffer has not overflowed.
*/
uint8 endTransmission(bool);
uint8 endTransmission(void);
/*
* Request bytes from a slave device and process the request,
* storing into the receiving buffer.
*/
uint8 requestFrom(uint8, int);
/*
* Allow only 8 bit addresses to be used when requesting bytes
*/
uint8 requestFrom(int, int);
/*
* Stack up bytes to be sent when transmitting
*/
void write(uint8);
/*
* Stack up bytes from the array to be sent when transmitting
*/
void write(uint8*, int);
/*
* Ensure that a sending data will only be 8-bit bytes
*/
void write(int);
/*
* Ensure that an array sending data will only be 8-bit bytes
*/
void write(int*, int);
/*
* Stack up bytes from a string to be sent when transmitting
*/
void write(char*);
/*
* Return the amount of bytes that is currently in the receiving buffer
*/
uint8 available();
/*
* Return the value of byte in the receiving buffer that is currently being
* pointed to
*/
uint8 read();
};
#endif // _WIREBASE_H_