Added Wire_slave.h (no actual i2c slave implementation yet)

This commit is contained in:
lacklustrlabs 2017-12-14 16:32:59 +01:00 committed by Lacklustrlabs
parent 9cd2f3a743
commit 0f78c266ed
23 changed files with 2251 additions and 0 deletions

View File

@ -0,0 +1 @@
#error "Something is trying to include Wire.h when Wire_Slave.h is already included, they are mutually exclusive"

View File

@ -0,0 +1,10 @@
name=Wire
version=1.0
author=Arduino
maintainer=Arduino <info@arduino.cc>
sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus.
paragraph=
category=Communication
url=http://www.arduino.cc/en/Reference/Wire
architectures=STM32F1
include=Wire.h

View File

@ -0,0 +1,87 @@
// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder
// by Nicholas Zambetti <http://www.zambetti.com>
// and James Tichenor <http://www.jamestichenor.net>
// Demonstrates use of the Wire library reading data from the
// Devantech Utrasonic Rangers SFR08 and SFR10
// Created 29 April 2006
// This example code is in the public domain.
#include <Wire_slave.h>
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial communication at 9600bps
}
int reading = 0;
void loop()
{
// step 1: instruct sensor to read echoes
Wire.beginTransmission(112); // transmit to device #112 (0x70)
// the address specified in the datasheet is 224 (0xE0)
// but i2c adressing uses the high 7 bits so it's 112
Wire.write(byte(0x00)); // sets register pointer to the command register (0x00)
Wire.write(byte(0x50)); // command sensor to measure in "inches" (0x50)
// use 0x51 for centimeters
// use 0x52 for ping microseconds
Wire.endTransmission(); // stop transmitting
// step 2: wait for readings to happen
delay(70); // datasheet suggests at least 65 milliseconds
// step 3: instruct sensor to return a particular echo reading
Wire.beginTransmission(112); // transmit to device #112
Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02)
Wire.endTransmission(); // stop transmitting
// step 4: request reading from sensor
Wire.requestFrom(112, 2); // request 2 bytes from slave device #112
// step 5: receive reading from sensor
if(2 <= Wire.available()) // if two bytes were received
{
reading = Wire.read(); // receive high byte (overwrites previous reading)
reading = reading << 8; // shift high byte to be high 8 bits
reading |= Wire.read(); // receive low byte as lower 8 bits
Serial.println(reading); // print the reading
}
delay(250); // wait a bit since people have to read the output :)
}
/*
// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08)
// usage: changeAddress(0x70, 0xE6);
void changeAddress(byte oldAddress, byte newAddress)
{
Wire.beginTransmission(oldAddress);
Wire.write(byte(0x00));
Wire.write(byte(0xA0));
Wire.endTransmission();
Wire.beginTransmission(oldAddress);
Wire.write(byte(0x00));
Wire.write(byte(0xAA));
Wire.endTransmission();
Wire.beginTransmission(oldAddress);
Wire.write(byte(0x00));
Wire.write(byte(0xA5));
Wire.endTransmission();
Wire.beginTransmission(oldAddress);
Wire.write(byte(0x00));
Wire.write(newAddress);
Wire.endTransmission();
}
*/

View File

@ -0,0 +1,38 @@
// I2C Digital Potentiometer
// by Nicholas Zambetti <http://www.zambetti.com>
// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.bonkowski/>
// Demonstrates use of the Wire library
// Controls AD5171 digital potentiometer via I2C/TWI
// Created 31 March 2006
// This example code is in the public domain.
// This example code is in the public domain.
#include <Wire_slave.h>
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
}
byte val = 0;
void loop()
{
Wire.beginTransmission(44); // transmit to device #44 (0x2c)
// device address is specified in datasheet
Wire.write(byte(0x00)); // sends instruction byte
Wire.write(val); // sends potentiometer value byte
Wire.endTransmission(); // stop transmitting
val++; // increment value
if(val == 64) // if reached 64th position (max)
{
val = 0; // start over from lowest value
}
delay(500);
}

View File

@ -0,0 +1,122 @@
/*
* i2c_slave example.cpp
*
* You can use this sketch in combination with master_writer.pde
*
* Created on: 4 Sep 2012
* Author: Barry Carter <barry.carter@gmail.com>
*/
#include <Arduino.h>
#include <libmaple/i2c.h>
#define USE_BUFFERED_EXAMPLE 1
i2c_msg msg;
uint8 buffer[255];
char* const bufferAsChar = (char*)buffer; // ready type casted alias
volatile bool newMessage = false;
void funcrx(i2c_msg *msg __attribute__((unused))){
// Received length will be in msg->length
newMessage = true;
}
#if USE_BUFFERED_EXAMPLE == 1
/* We ARE using a buffer to transmit the data out.
* Make sure you fill the buffer with the data AND you set the length correctly
*/
void functx(i2c_msg *msg){
// Cheeky. We are using the received byte of the data which is currently in
// byte 0 to echo it back to the master device
//msg->data[0] = 0x01; // We are re-using the rx buffer here to echo the request back
msg->data[1] = 0x02;
msg->data[2] = 0x03;
msg->data[3] = 0x04;
msg->data[4] = 0x05;
msg->length = 5;
}
#else
/* We are NOT using the buffered data transmission
* We will get this callback for each outgoing packet. Make sure to call i2c_write
* Strickly speaking, we should be sending a NACk on the last byte we want to send
* but for this test example I am going to assume the master will NACK it when it
* wants to stop.
*/
void functx(i2c_msg *msg){
i2c_write(I2C1, msg->data[0]);
}
#endif
// #define Serial Serial1
void setup() {
Serial.begin(115200);
while(!Serial)
;
Serial.println("I2C Slave example");
// attach the buffer
msg.data = buffer;
/* Init slave mode. Enables master too
* We are going to configure the slave device to
* - enable fast I2C (400khz)
* - dual addresses (can have 2 addresses per module)
* general call (accepts data writes to 0x00 on a broadcast basis)
*
* If the buffered example is enabled, then we also enable the
* buffer for rx and tx.
* Note you can independently enable/disable RX and TX buffers to
* allow a buffered read and direct writes. Useful if you don't know how
* much the master will read.
*/
#if USE_BUFFERED_EXAMPLE == 1
i2c_slave_enable(I2C1, I2C_FAST_MODE | I2C_SLAVE_DUAL_ADDRESS | I2C_SLAVE_GENERAL_CALL | I2C_SLAVE_USE_RX_BUFFER | I2C_SLAVE_USE_TX_BUFFER);
#else
i2c_slave_enable(I2C1, I2C_FAST_MODE | I2C_SLAVE_DUAL_ADDRESS | I2C_SLAVE_GENERAL_CALL);
#endif
// attach receive handler
i2c_slave_attach_recv_handler(I2C1, &msg, funcrx);
// attach transmit handler
i2c_slave_attach_transmit_handler(I2C1, &msg, functx);
// set addresss to 4
i2c_slave_set_own_address(I2C1, 4);
}
void loop() {
static uint32_t lastMessage = millis();
// This is potentially dangerous.
// We're reading from the live buffer, the content can change
// in the middle of Serial.println
if (newMessage && strlen(bufferAsChar)==6) {
for (int i=0; i<5; i++) {
// Print as char
Serial.print(bufferAsChar[i]);
}
// Print as byte
Serial.println(buffer[5]);
lastMessage = millis();
newMessage = false;
} else {
if(newMessage && strlen(bufferAsChar)!=6) {
// this also happends on the line "x is 0"
Serial.print("Bad data received:");
Serial.println(bufferAsChar);
Serial.print("strlen:");
Serial.println(strlen(bufferAsChar));
newMessage = false;
} else
if(millis() - lastMessage > 3000){
Serial.println("Nothing received in 3 seconds.");
lastMessage = millis();
}
}
}

View File

@ -0,0 +1,32 @@
// Wire Master Reader
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Reads data from an I2C/TWI slave device
// Refer to the "Wire Slave Sender" 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(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop()
{
Wire.requestFrom(2, 6); // request 6 bytes from slave device #2
while(Wire.available()) // slave may send less than requested
{
char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
}
delay(500);
}

View File

@ -0,0 +1,31 @@
// Wire Master Writer
// by Nicholas Zambetti <http://www.zambetti.com>
// Demonstrates use of the Wire library
// Writes data to an I2C/TWI slave device
// Refer to the "Wire Slave Receiver" 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(); // join i2c bus (address optional for master)
}
byte x = 0;
void loop()
{
Wire.beginTransmission(4); // transmit to device #4
Wire.write("x is "); // sends five bytes
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting
x++;
delay(500);
}

View File

@ -0,0 +1,38 @@
// 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>
void setup()
{
Wire.begin(4); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}
void loop()
{
delay(100);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
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(2); // join i2c bus with address #2
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

@ -0,0 +1,11 @@
name=Wire_Slave
version=1.0
author=
email=
sentence=Wire with slave support
paragraph=Experimental Wire with slave support
url=
architectures=STM32F1
maintainer=
category=Communication
include=src/Wire_Slave.h

View File

@ -0,0 +1 @@
#error "Something is trying to include Wire_slave.h when Wire.h is already included, they are mutually exclusive"

Binary file not shown.

View File

@ -0,0 +1,106 @@
/******************************************************************************
* 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.
*/
#include "Wire_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;
}
uint8 TwoWire::process(){
return process(true);
}
// 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;
}
TwoWire::~TwoWire() {
i2c_disable(sel_hard);
sel_hard = 0;
}
void TwoWire::begin(uint8 self_addr) {
i2c_master_enable(sel_hard, dev_flags);
}
void TwoWire::end() {
i2c_disable(sel_hard);
sel_hard = 0;
}
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);
}
}
TwoWire Wire(1);

View File

@ -0,0 +1,78 @@
/******************************************************************************
* 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.
*/
#ifndef _TWOWIRE_H_
#define _TWOWIRE_H_
#include "utility/WireBase_slave.h"
#include "wirish.h"
#include <libmaple/i2c_slave.h>
class TwoWire : public WireBase {
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();
public:
/*
* Check if devsel is within range and enable selected I2C interface with
* passed flags
*/
TwoWire(uint8, uint8 = 0);
/*
* Shuts down (disables) the hardware I2C
*/
void end();
void setClock(uint32_t frequencyHz);
/*
* Disables the I2C device and remove the device address.
*/
~TwoWire();
void begin(uint8 = 0x00);
};
extern TwoWire Wire;
#endif // _TWOWIRE_H_

Binary file not shown.

View File

@ -0,0 +1,789 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2012 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 libmaple/i2c.c
* @author Perry Hung <perry@leaflabs.com>
* @author Barry Carter <barry.carter@gmail.com>
* @brief Inter-Integrated Circuit (I2C) support.
*
* Master and Slave supported
* I2C slave support added 2012 by Barry Carter. barry.carter@gmail.com, headfuzz.co.uk
*/
#include "libmaple/i2c_common_slave.h"
#include "i2c_private.h"
#include "libmaple/i2c_slave.h"
#include <libmaple/libmaple.h>
#include <libmaple/rcc.h>
#include <libmaple/gpio.h>
#include <libmaple/nvic.h>
#include <libmaple/systick.h>
#include <string.h>
static inline int32 wait_for_state_change(i2c_dev *dev,
i2c_state state,
uint32 timeout);
static void set_ccr_trise(i2c_dev *dev, uint32 flags);
/**
* @brief Fill data register with slave address
* @param dev I2C device
* @param addr Slave address
* @param rw Read/write bit
*/
static inline void i2c_send_slave_addr(i2c_dev *dev, uint32 addr, uint32 rw) {
dev->regs->DR = (addr << 1) | rw;
}
/*
* Simple debugging trail. Define I2C_DEBUG to turn on.
*/
#ifdef I2C_DEBUG
#define NR_CRUMBS 128
static struct crumb crumbs[NR_CRUMBS];
static uint32 cur_crumb = 0;
static inline void i2c_drop_crumb(uint32 event, uint32 arg0, uint32 arg1) {
if (cur_crumb < NR_CRUMBS) {
struct crumb *crumb = &crumbs[cur_crumb++];
crumb->event = event;
crumb->arg0 = arg0;
crumb->arg1 = arg1;
}
}
#define I2C_CRUMB(event, arg0, arg1) i2c_drop_crumb(event, arg0, arg1)
#else
#define I2C_CRUMB(event, arg0, arg1)
#endif
struct crumb {
uint32 event;
uint32 arg0;
uint32 arg1;
};
enum {
IRQ_ENTRY = 1,
TXE_ONLY = 2,
TXE_BTF = 3,
STOP_SENT = 4,
TEST = 5,
RX_ADDR_START = 6,
RX_ADDR_STOP = 7,
RXNE_ONLY = 8,
RXNE_SENDING = 9,
RXNE_START_SENT = 10,
RXNE_STOP_SENT = 11,
RXNE_DONE = 12,
ERROR_ENTRY = 13,
};
/**
* @brief Reset an I2C bus.
*
* Reset is accomplished by clocking out pulses until any hung slaves
* release SDA and SCL, then generating a START condition, then a STOP
* condition.
*
* @param dev I2C device
*/
void i2c_bus_reset(const i2c_dev *dev) {
/* Release both lines */
i2c_master_release_bus(dev);
/*
* Make sure the bus is free by clocking it until any slaves release the
* bus.
*/
while (!gpio_read_bit(sda_port(dev), dev->sda_pin)) {
/* Wait for any clock stretching to finish */
while (!gpio_read_bit(scl_port(dev), dev->scl_pin))
;
delay_us(10);
/* Pull low */
gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
delay_us(10);
/* Release high again */
gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
delay_us(10);
}
/* Generate start then stop condition */
gpio_write_bit(sda_port(dev), dev->sda_pin, 0);
delay_us(10);
gpio_write_bit(scl_port(dev), dev->scl_pin, 0);
delay_us(10);
gpio_write_bit(scl_port(dev), dev->scl_pin, 1);
delay_us(10);
gpio_write_bit(sda_port(dev), dev->sda_pin, 1);
}
/**
* @brief Initialize an I2C device and reset its registers to their
* default values.
* @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);
}
/* Hack for deprecated bit of STM32F1 functionality */
#ifndef _I2C_HAVE_DEPRECATED_I2C_REMAP
#define _i2c_handle_remap(dev, flags) ((void)0)
#endif
/**
* @brief Initialize an I2C device as bus master
* @param dev Device to enable
* @param flags Bitwise or of the following I2C options:
* I2C_FAST_MODE: 400 khz operation,
* I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for
* fast mode),
* I2C_BUS_RESET: Reset the bus and clock out any hung slaves on
* initialization,
* I2C_10BIT_ADDRESSING: Enable 10-bit addressing,
* I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8
* SDA/PB9.
*/
void i2c_master_enable(i2c_dev *dev, uint32 flags) {
/* PE must be disabled to configure the device */
ASSERT(!(dev->regs->CR1 & I2C_CR1_PE));
/* Ugh */
_i2c_handle_remap(dev, flags);
/* Reset the bus. Clock out any hung slaves. */
if (flags & I2C_BUS_RESET) {
i2c_bus_reset(dev);
}
/* Turn on clock and set GPIO modes */
i2c_init(dev);
i2c_config_gpios(dev);
/* Configure clock and rise time */
set_ccr_trise(dev, flags);
/* Enable event and buffer interrupts */
nvic_irq_enable(dev->ev_nvic_line);
nvic_irq_enable(dev->er_nvic_line);
i2c_enable_irq(dev, I2C_IRQ_EVENT | I2C_IRQ_BUFFER | I2C_IRQ_ERROR);
/* Configure the slave unit */
if (flags & I2C_SLAVE_DUAL_ADDRESS) {
i2c_slave_dual_address_enable(dev);
}
if (flags & I2C_SLAVE_GENERAL_CALL) {
i2c_slave_general_call_enable(dev);
}
/* store all of the flags */
dev->config_flags = flags;
/* Make it go! */
i2c_peripheral_enable(dev);
i2c_enable_ack(dev);
dev->state = I2C_STATE_IDLE;
}
/**
* @brief Initialize an I2C device as slave (and master)
* @param dev Device to enable
* @param flags Bitwise or of the following I2C options:
* I2C_FAST_MODE: 400 khz operation,
* I2C_DUTY_16_9: 16/9 Tlow/Thigh duty cycle (only applicable for
* fast mode),
* I2C_BUS_RESET: Reset the bus and clock out any hung slaves on
* initialization,
* I2C_10BIT_ADDRESSING: Enable 10-bit addressing,
* I2C_REMAP: (deprecated, STM32F1 only) Remap I2C1 to SCL/PB8
* SDA/PB9.
* I2C_SLAVE_DUAL_ADDRESS: Slave can respond on 2 i2C addresses
* I2C_SLAVE_GENERAL_CALL: SLA+W broadcast to all general call
* listeners on bus. Addr 0x00
* I2C_SLAVE_USE_RX_BUFFER: Use a buffer to receive the incoming
* data. Callback at end of recv
* I2C_SLAVE_USE_TX_BUFFER: Use a buffer to transmit data.
* Callback will be called before tx
*/
void i2c_slave_enable(i2c_dev *dev, uint32 flags) {
i2c_disable(dev);
i2c_master_enable(dev, dev->config_flags | flags);
}
/**
* @brief Process an i2c transaction.
*
* Transactions are composed of one or more i2c_msg's, and may be read
* or write tranfers. Multiple i2c_msg's will generate a repeated
* start in between messages.
*
* @param dev I2C device
* @param msgs Messages to send/receive
* @param num Number of messages to send/receive
* @param timeout Bus idle timeout in milliseconds before aborting the
* transfer. 0 denotes no timeout.
* @return 0 on success,
* I2C_ERROR_PROTOCOL if there was a protocol error,
* I2C_ERROR_TIMEOUT if the transfer timed out.
*/
int32 i2c_master_xfer(i2c_dev *dev,
i2c_msg *msgs,
uint16 num,
uint32 timeout) {
int32 rc;
ASSERT(dev->state == I2C_STATE_IDLE);
dev->msg = msgs;
dev->msgs_left = num;
dev->timestamp = systick_uptime();
dev->state = I2C_STATE_BUSY;
i2c_enable_irq(dev, I2C_IRQ_EVENT);
i2c_start_condition(dev);
rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout);
if (rc < 0) {
goto out;
}
dev->state = I2C_STATE_IDLE;
out:
return rc;
}
/**
* @brief Wait for an I2C event, or time out in case of error.
* @param dev I2C device
* @param state I2C_state state to wait for
* @param timeout Timeout, in milliseconds
* @return 0 if target state is reached, a negative value on error.
*/
static inline int32 wait_for_state_change(i2c_dev *dev,
i2c_state state,
uint32 timeout) {
i2c_state tmp;
while (1) {
tmp = dev->state;
if (tmp == I2C_STATE_ERROR) {
return I2C_STATE_ERROR;
}
if (tmp == state) {
return 0;
}
if (timeout) {
if (systick_uptime() > (dev->timestamp + timeout)) {
/* TODO: overflow? */
/* TODO: racy? */
return I2C_ERROR_TIMEOUT;
}
}
}
}
/*
* Private API
*/
/*
* IRQ handler for I2C master. Handles transmission/reception.
*/
void _i2c_irq_handler(i2c_dev *dev) {
/* WTFs:
* - Where is I2C_MSG_10BIT_ADDR handled?
*/
i2c_msg *msg = dev->msg;
uint8 read = msg->flags & I2C_MSG_READ;
uint32 sr1 = dev->regs->SR1;
uint32 sr2 = dev->regs->SR2;
I2C_CRUMB(IRQ_ENTRY, sr1, sr2);
/*
* Reset timeout counter
*/
dev->timestamp = systick_uptime();
/*
* Add Slave support
*/
/* Check to see if MSL master slave bit is set */
if ((sr2 & I2C_SR2_MSL) != I2C_SR2_MSL) { /* 0 = slave mode 1 = master */
/* Check for address match */
if (sr1 & I2C_SR1_ADDR) {
/* Find out which address was matched */
/* Check the general call address first */
if (sr2 & I2C_SR2_GENCALL) {
dev->i2c_slave_msg->addr = 0;
}
/* We matched the secondary address */
else if (sr2 & I2C_SR2_DUALF) {
dev->i2c_slave_msg->addr = dev->regs->OAR2 & 0xFE;
}
/* We matched the primary address */
else if ((sr2 & I2C_SR2_DUALF) != I2C_SR2_DUALF) {
dev->i2c_slave_msg->addr = dev->regs->OAR1 & 0xFE;
}
/* Shouldn't get here */
else {
dev->i2c_slave_msg->addr = -1; /* uh oh */
}
/* if we have buffered io */
if ((dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) ||
(dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) {
/* if receiving then this would be a repeated start
*
*if we have some bytes already
*/
if ((dev->state == I2C_STATE_SL_RX) &&
(dev->i2c_slave_msg->xferred > 0) &&
(dev->config_flags & I2C_SLAVE_USE_RX_BUFFER)) {
/* Call the callback with the contents of the data */
if (dev->i2c_slave_recv_callback != NULL) {
(*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg);
}
}
/* Reset the message back to defaults.
* We are starting a new message
*/
dev->i2c_slave_msg->flags = 0;
dev->i2c_slave_msg->length = 0;
dev->i2c_slave_msg->xferred = 0;
dev->msgs_left = 0;
dev->timestamp = systick_uptime();
/* We have been addressed with SLA+R so
* the master wants us to transmit
*/
if ((sr1 & I2C_SR1_TXE) &&
(dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) {
/* Call the transmit callback so it can populate the msg
* data with the bytes to go
*/
if (dev->i2c_slave_transmit_callback != NULL) {
(*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg);
}
}
dev->state = I2C_STATE_BUSY;
}
sr1 = sr2 = 0;
}
/* EV3: Master requesting data from slave. Transmit a byte*/
if (sr1 & I2C_SR1_TXE) {
if (dev->config_flags & I2C_SLAVE_USE_TX_BUFFER) {
if (dev->i2c_slave_msg->xferred >= dev->i2c_slave_msg->length) {
/* End of the transmit buffer? If so we NACK */
i2c_disable_ack(dev);
/* We have to either issue a STOP or write something here.
* STOP here seems to screw up some masters,
* For now padding with 0
*/
i2c_write(dev, 0);
/*i2c_stop_condition(dev); // This is causing bus lockups way more than it should !? Seems some I2C master devices freak out here*/
}
else
{
/* NACk the last byte */
if (dev->i2c_slave_msg->xferred == dev->i2c_slave_msg->length-1) {
i2c_disable_ack(dev);
}
else {
i2c_enable_ack(dev);
}
i2c_write(dev, dev->i2c_slave_msg->data[dev->i2c_slave_msg->xferred++]);
}
}
else
{
/* Call the callback to get the data we need.
* The callback is expected to write using i2c_write(...)
* If the slave is going to terminate the transfer, this function should
* also do a NACK on the last byte!
*/
if (dev->i2c_slave_transmit_callback != NULL) (*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg);
}
dev->state = I2C_STATE_BUSY;
sr1 = sr2 = 0;
}
/* EV2: Slave received data from a master. Get from DR */
if (sr1 & I2C_SR1_RXNE) {
if (dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) {
/* Fill the buffer with the contents of the data register */
/* These is potential for buffer overflow here, so we should
* really store the size of the array. This is expensive in
* the ISR so left out for now. We must trust the implementor!
*/
dev->i2c_slave_msg->data[dev->i2c_slave_msg->xferred++] = dev->regs->DR;
dev->i2c_slave_msg->length++;
}
else {
/* Call the callback with the contents of the data */
dev->i2c_slave_msg->data[0] = dev->regs->DR;
if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg);
}
dev->state = I2C_STATE_SL_RX;
sr1 = sr2 = 0;
}
/* EV4: Slave has detected a STOP condition on the bus */
if (sr1 & I2C_SR1_STOPF) {
dev->regs->CR1 |= I2C_CR1_PE;
if ((dev->config_flags & I2C_SLAVE_USE_RX_BUFFER) ||
(dev->config_flags & I2C_SLAVE_USE_TX_BUFFER)) {
/* The callback with the data will happen on a NACK of the last data byte.
* This is handled in the error IRQ (AF bit)
*/
/* Handle the case where the master misbehaves by sending no NACK */
if (dev->state != I2C_STATE_IDLE) {
if (dev->state == I2C_STATE_SL_RX) {
if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg);
}
else {
if (dev->i2c_slave_transmit_callback != NULL) (*(dev->i2c_slave_transmit_callback))(dev->i2c_slave_msg);
}
}
}
sr1 = sr2 = 0;
dev->state = I2C_STATE_IDLE;
}
return;
}
/*
* EV5: Start condition sent
*/
if (sr1 & I2C_SR1_SB) {
msg->xferred = 0;
i2c_enable_irq(dev, I2C_IRQ_BUFFER);
/*
* Master receiver
*/
if (read) {
i2c_enable_ack(dev);
}
i2c_send_slave_addr(dev, msg->addr, read);
sr1 = sr2 = 0;
}
/*
* EV6: Slave address sent
*/
if (sr1 & I2C_SR1_ADDR) {
/*
* Special case event EV6_1 for master receiver.
* Generate NACK and restart/stop condition after ADDR
* is cleared.
*/
if (read) {
if (msg->length == 1) {
i2c_disable_ack(dev);
if (dev->msgs_left > 1) {
i2c_start_condition(dev);
I2C_CRUMB(RX_ADDR_START, 0, 0);
} else {
i2c_stop_condition(dev);
I2C_CRUMB(RX_ADDR_STOP, 0, 0);
}
}
} else {
/*
* Master transmitter: write first byte to fill shift
* register. We should get another TXE interrupt
* immediately to fill DR again.
*/
if (msg->length > 1) {
i2c_write(dev, msg->data[msg->xferred++]);
} else if (msg->length == 0) { /* We're just sending an address */
i2c_stop_condition(dev);
/*
* Turn off event interrupts to keep BTF from firing until
* the end of the stop condition. Why on earth they didn't
* have a start/stop condition request clear BTF is beyond
* me.
*/
i2c_disable_irq(dev, I2C_IRQ_EVENT);
I2C_CRUMB(STOP_SENT, 0, 0);
dev->state = I2C_STATE_XFER_DONE;
} /* else we're just sending one byte */
}
sr1 = sr2 = 0;
}
/*
* EV8: Master transmitter
* Transmit buffer empty, but we haven't finished transmitting the last
* byte written.
*/
if ((sr1 & I2C_SR1_TXE) && !(sr1 & I2C_SR1_BTF)) {
I2C_CRUMB(TXE_ONLY, 0, 0);
if (dev->msgs_left) {
i2c_write(dev, msg->data[msg->xferred++]);
if (msg->xferred == msg->length) {
/*
* End of this message. Turn off TXE/RXNE and wait for
* BTF to send repeated start or stop condition.
*/
i2c_disable_irq(dev, I2C_IRQ_BUFFER);
dev->msgs_left--;
}
} else {
/*
* This should be impossible...
*/
ASSERT(0);
}
sr1 = sr2 = 0;
}
/*
* EV8_2: Master transmitter
* Last byte sent, program repeated start/stop
*/
if ((sr1 & I2C_SR1_TXE) && (sr1 & I2C_SR1_BTF)) {
I2C_CRUMB(TXE_BTF, 0, 0);
if (dev->msgs_left) {
I2C_CRUMB(TEST, 0, 0);
/*
* Repeated start insanity: We can't disable ITEVTEN or else SB
* won't interrupt, but if we don't disable ITEVTEN, BTF will
* continually interrupt us. What the fuck ST?
*/
i2c_start_condition(dev);
while (!(dev->regs->SR1 & I2C_SR1_SB))
;
dev->msg++;
} else {
i2c_stop_condition(dev);
/*
* Turn off event interrupts to keep BTF from firing until
* the end of the stop condition. Why on earth they didn't
* have a start/stop condition request clear BTF is beyond
* me.
*/
i2c_disable_irq(dev, I2C_IRQ_EVENT);
I2C_CRUMB(STOP_SENT, 0, 0);
dev->state = I2C_STATE_XFER_DONE;
}
sr1 = sr2 = 0;
}
/*
* EV7: Master Receiver
*/
if (sr1 & I2C_SR1_RXNE) {
I2C_CRUMB(RXNE_ONLY, 0, 0);
msg->data[msg->xferred++] = dev->regs->DR;
/*
* EV7_1: Second to last byte in the reception? Set NACK and generate
* stop/restart condition in time for the last byte. We'll get one more
* RXNE interrupt before shutting things down.
*/
if (msg->xferred == (msg->length - 1)) {
i2c_disable_ack(dev);
if (dev->msgs_left > 2) {
i2c_start_condition(dev);
I2C_CRUMB(RXNE_START_SENT, 0, 0);
} else {
i2c_stop_condition(dev);
I2C_CRUMB(RXNE_STOP_SENT, 0, 0);
}
} else if (msg->xferred == msg->length) {
dev->msgs_left--;
if (dev->msgs_left == 0) {
/*
* We're done.
*/
I2C_CRUMB(RXNE_DONE, 0, 0);
dev->state = I2C_STATE_XFER_DONE;
} else {
dev->msg++;
}
}
}
}
/*
* Interrupt handler for I2C error conditions. Aborts any pending I2C
* transactions.
*/
void _i2c_irq_error_handler(i2c_dev *dev) {
I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2);
dev->error_flags = dev->regs->SR1 & (I2C_SR1_BERR |
I2C_SR1_ARLO |
I2C_SR1_AF |
I2C_SR1_OVR);
/* Are we in slave mode? */
if ((dev->regs->SR2 & I2C_SR2_MSL) != I2C_SR2_MSL) {
/* 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
* loop waiting for the stop condition that will never arrive
*/
if (dev->regs->SR1 & I2C_SR1_AF) {
/* Clear flags */
dev->regs->SR1 = 0;
dev->regs->SR2 = 0;
/* We need to write something to CR1 to clear the flag.
* This isn't really mentioned but seems important */
i2c_enable_ack(dev);
if (dev->state == I2C_STATE_SL_RX &&
dev->config_flags & I2C_SLAVE_USE_RX_BUFFER &&
dev->i2c_slave_msg->xferred > 0) {
/* Call the callback with the contents of the data */
if (dev->i2c_slave_recv_callback != NULL) (*(dev->i2c_slave_recv_callback))(dev->i2c_slave_msg);
}
dev->state = I2C_STATE_IDLE;
return;
}
/* Catch any other strange errors while in slave mode.
* I have seen BERR caused by an over fast master device
* as well as several overflows and arbitration failures.
* We are going to reset SR flags and carry on at this point which
* is not the best thing to do, but stops the bus locking up completely
* If we carry on below and send the stop bit, the code spins forever */
/* Clear flags */
dev->regs->SR1 = 0;
dev->regs->SR2 = 0;
dev->state = I2C_STATE_IDLE;
return;
}
/* Clear flags */
dev->regs->SR1 = 0;
dev->regs->SR2 = 0;
i2c_stop_condition(dev);
i2c_disable_irq(dev, I2C_IRQ_BUFFER | I2C_IRQ_EVENT | I2C_IRQ_ERROR);
dev->state = I2C_STATE_ERROR;
}
/*
* CCR/TRISE configuration helper
*/
static void set_ccr_trise(i2c_dev *dev, uint32 flags) {
uint32 ccr = 0;
uint32 trise = 0;
uint32 clk_mhz = _i2c_bus_clk(dev);
uint32 clk_hz = clk_mhz * (1000 * 1000);
i2c_set_input_clk(dev, clk_mhz);
if (flags & I2C_FAST_MODE) {
ccr |= I2C_CCR_FS;
if (flags & I2C_DUTY_16_9) {
/* Tlow/Thigh = 16/9 */
ccr |= I2C_CCR_DUTY_16_9;
ccr |= clk_hz / (400000 * 25);
} else {
/* Tlow/Thigh = 2 */
ccr |= clk_hz / (400000 * 3);
}
trise = (300 * clk_mhz / 1000) + 1;
} else {
/* Tlow/Thigh = 1 */
ccr = clk_hz / (100000 * 2);
trise = clk_mhz + 1;
}
/* Set minimum required value if CCR < 1*/
if ((ccr & I2C_CCR_CCR) == 0) {
ccr |= 0x1;
}
i2c_set_clk_control(dev, ccr);
i2c_set_trise(dev, trise);
}
/**
* @brief callback for when the device acts as a slave. If using an rx buffer, this is triggered
* after the last byte, otherwise it is called for every incoming packet.
* @param dev I2C device
* @param msg The dev_msg to pass to the slave init code
* @param func The function pointer to call
*/
void i2c_slave_attach_recv_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_recv_callback_func func) {
dev->i2c_slave_recv_callback = func;
dev->i2c_slave_msg = msg;
msg->xferred = 0;
}
/**
* @brief callback for when the device acts as a slave. If using a tx buffer, this is triggered
* after the device is successsfully addressed with SLA+R.
* @param dev I2C device
* @param msg The dev_msg to pass to the slave init code
* @param func The function pointer to call
*/
void i2c_slave_attach_transmit_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_transmit_callback_func func) {
dev->i2c_slave_transmit_callback = func;
dev->i2c_slave_msg = msg;
msg->xferred = 0;
}

Binary file not shown.

View File

@ -0,0 +1,110 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung (from <libmaple/i2c.h>).
* Copyright (c) 2012 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 libmaple/include/libmaple/i2c_common.h
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief This file is an implementation detail
*
* CONTENTS UNSTABLE. The existence of this file is an implementation
* detail. Never include it directly. If you need something from
* here, include <libmaple/i2c.h> instead.
*
* I2C slave support added 2012 by Barry Carter. barry.carter@gmail.com, headfuzz.co.uk
*
*/
#ifndef _LIBMAPLE_I2C_COMMON_H_
#define _LIBMAPLE_I2C_COMMON_H_
#include <libmaple/libmaple_types.h>
#include <libmaple/nvic.h>
#include <libmaple/rcc.h>
struct gpio_dev;
struct i2c_reg_map;
struct i2c_msg;
/** I2C device states */
typedef enum i2c_state {
I2C_STATE_DISABLED = 0, /**< Disabled */
I2C_STATE_IDLE = 1, /**< Idle */
I2C_STATE_XFER_DONE = 2, /**< Done with transfer */
I2C_STATE_BUSY = 3, /**< Busy */
I2C_STATE_SL_RX = 4, /**< Slave receiving */
I2C_STATE_ERROR = -1 /**< Error occurred */
} i2c_state;
typedef void (*i2c_slave_recv_callback_func)(struct i2c_msg *);
typedef void (*i2c_slave_transmit_callback_func)(struct i2c_msg *);
/**
* @brief I2C device type.
*/
typedef struct i2c_dev {
struct i2c_reg_map *regs; /**< Register map */
struct i2c_msg *msg; /**< Messages */
uint32 error_flags; /**< Error flags, set on I2C error condition */
volatile uint32 timestamp; /**< For internal use */
/**
* @brief Deprecated. Use .scl_port or .sda_port instead.
* If non-null, this will be used as SDA, SCL pins' GPIO port. If
* null, then .sda_port will be used for SDA, and .sda_port for
* SDA. */
struct gpio_dev *gpio_port;
/**
* @brief SDA GPIO device (but see .gpio_port).
*/
struct gpio_dev *sda_port;
/**
* @brief SCL GPIO device (but see .gpio_port).
*/
struct gpio_dev *scl_port;
uint16 msgs_left; /**< Messages left */
uint8 sda_pin; /**< SDA bit on gpio_port */
uint8 scl_pin; /**< SCL bit on gpio_port */
rcc_clk_id clk_id; /**< RCC clock information */
nvic_irq_num ev_nvic_line; /**< Event IRQ number */
nvic_irq_num er_nvic_line; /**< Error IRQ number */
volatile i2c_state state; /**< Device state */
uint32 config_flags; /**< Configuration flags */
/*
* Slave implementation. Callback functions in this struct allow
* for a separate callback function for each I2C unit available onboard
*/
i2c_slave_transmit_callback_func i2c_slave_transmit_callback;
i2c_slave_recv_callback_func i2c_slave_recv_callback;
struct i2c_msg *i2c_slave_msg; /* the message that the i2c slave will use */
} i2c_dev;
#endif

View File

@ -0,0 +1,475 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 Perry Hung.
* Copyright (c) 2012 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 libmaple/include/libmaple/i2c.h
* @brief Inter-Integrated Circuit (I2C) peripheral support
*
* Supports Master and Slave.
* Master Usage notes:
*
* - Enable an I2C device with i2c_master_enable().
* - Initialize an array of struct i2c_msg to suit the bus
* transactions (reads/writes) you wish to perform.
* - Call i2c_master_xfer() to do the work.
*
* Slave Usage notes:
* - Enable I2C slave by calling i2c_slave_enable().
* Check flags for usage. Enabling master also enabled slave.
* - initialise the i2c_msg struct and the data buffer
* - initialise the callback functions
*
* I2C slave support added 2012 by Barry Carter. barry.carter@gmail.com, headfuzz.co.uk
*/
#ifndef _LIBMAPLE_I2C_H_
#define _LIBMAPLE_I2C_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Series header must provide:
*
* - uint32 _i2c_bus_clk(i2c_dev*): Clock frequency of dev's bus, in
* MHz. (This is for internal use only).
*
* - (optional) _I2C_HAVE_IRQ_FIXUP: Leave undefined, or define to 1.
* This is for internal use only. It's a hack to work around a
* silicon bug related to I2C IRQ pre-emption on some targets. If 1,
* the series header must also declare and implement a routine with
* this signature (it may also be provided as a macro):
*
* void _i2c_irq_priority_fixup(i2c_dev*)
*
* This will be called by i2c_enable_irq() before actually enabling
* I2C interrupts.
*
* - Reg. map base pointers, device pointer declarations.
*/
/* Roger clark. Replaced with line below #include <series/i2c.h>*/
#include "libmaple/i2c_common_slave.h"
#include "stm32f1/include/series/i2c.h"
#include <libmaple/libmaple_types.h>
#include <libmaple/rcc.h>
#include <libmaple/nvic.h>
#include <libmaple/gpio.h>
/** I2C register map type */
typedef struct i2c_reg_map {
__io uint32 CR1; /**< Control register 1 */
__io uint32 CR2; /**< Control register 2 */
__io uint32 OAR1; /**< Own address register 1 */
__io uint32 OAR2; /**< Own address register 2 */
__io uint32 DR; /**< Data register */
__io uint32 SR1; /**< Status register 1 */
__io uint32 SR2; /**< Status register 2 */
__io uint32 CCR; /**< Clock control register */
__io uint32 TRISE; /**< TRISE (rise time) register */
} i2c_reg_map;
/**
* @brief I2C message type
*/
typedef struct i2c_msg {
uint16 addr; /**< Address */
#define I2C_MSG_READ 0x1
#define I2C_MSG_10BIT_ADDR 0x2
/**
* Bitwise OR of:
* - I2C_MSG_READ (write is default)
* - I2C_MSG_10BIT_ADDR (7-bit is default) */
uint16 flags;
uint16 length; /**< Message length */
uint16 xferred; /**< Messages transferred */
uint8 *data; /**< Data */
} i2c_msg;
/*
* Register bit definitions
*/
/* Control register 1 */
#define I2C_CR1_SWRST (1U << 15) // Software reset
#define I2C_CR1_ALERT (1U << 13) // SMBus alert
#define I2C_CR1_PEC (1U << 12) // Packet error checking
#define I2C_CR1_POS (1U << 11) // Acknowledge/PEC position
#define I2C_CR1_ACK (1U << 10) // Acknowledge enable
#define I2C_CR1_STOP (1U << 9) // Stop generation
#define I2C_CR1_START (1U << 8) // Start generation
#define I2C_CR1_NOSTRETCH (1U << 7) // Clock stretching disable
#define I2C_CR1_ENGC (1U << 6) // General call enable
#define I2C_CR1_ENPEC (1U << 5) // PEC enable
#define I2C_CR1_ENARP (1U << 4) // ARP enable
#define I2C_CR1_SMBTYPE (1U << 3) // SMBus type
#define I2C_CR1_SMBTYPE_DEVICE (0U << 3) // SMBus type: device
#define I2C_CR1_SMBTYPE_HOST (1U << 3) // SMBus type: host
#define I2C_CR1_SMBUS (1U << 1) // SMBus mode
#define I2C_CR1_SMBUS_I2C (0U << 1) // SMBus mode: I2C
#define I2C_CR1_SMBUS_SMBUS (1U << 1) // SMBus mode: SMBus
#define I2C_CR1_PE (1U << 0) // Peripheral Enable
/* Control register 2 */
#define I2C_CR2_LAST (1U << 12) // DMA last transfer
#define I2C_CR2_DMAEN (1U << 11) // DMA requests enable
#define I2C_CR2_ITBUFEN (1U << 10) // Buffer interrupt enable
#define I2C_CR2_ITEVTEN (1U << 9) // Event interupt enable
#define I2C_CR2_ITERREN (1U << 8) // Error interupt enable
#define I2C_CR2_FREQ 0x3F // Peripheral input frequency
/* Own address register 1 */
#define I2C_OAR1_ADDMODE (1U << 15) // Addressing mode
#define I2C_OAR1_ADDMODE_7_BIT (0U << 15) // Addressing mode: 7-bit
#define I2C_OAR1_ADDMODE_10_BIT (1U << 15) // Addressing mode: 10-bit
#define I2C_OAR1_ADD 0x3FF // Interface address
/* Own address register 2 */
#define I2C_OAR2_ADD2 0xFE // Interface address
#define I2C_OAR2_ENDUAL 1U // Dual addressing mode enable
/* Status register 1 */
#define I2C_SR1_SMBALERT (1U << 15) // SMBus alert
#define I2C_SR1_TIMEOUT (1U << 14) // Timeout or Tlow error
#define I2C_SR1_PECERR (1U << 12) // PEC Error in reception
#define I2C_SR1_OVR (1U << 11) // Overrun/underrun
#define I2C_SR1_AF (1U << 10) // Acknowledge failure
#define I2C_SR1_ARLO (1U << 9) // Arbitration lost
#define I2C_SR1_BERR (1U << 8) // Bus error
#define I2C_SR1_TXE (1U << 7) // Data register empty
#define I2C_SR1_RXNE (1U << 6) // Data register not empty
#define I2C_SR1_STOPF (1U << 4) // Stop detection
#define I2C_SR1_ADD10 (1U << 3) // 10-bit header sent
#define I2C_SR1_BTF (1U << 2) // Byte transfer finished
#define I2C_SR1_ADDR (1U << 1) // Address sent/matched
#define I2C_SR1_SB (1U << 0) // Start bit
/* Status register 2 */
#define I2C_SR2_PEC 0xFF00 // Packet error checking register
#define I2C_SR2_DUALF (1U << 7) // Dual flag
#define I2C_SR2_SMBHOST (1U << 6) // SMBus host header
#define I2C_SR2_SMBDEFAULT (1U << 5) // SMBus device default address
#define I2C_SR2_GENCALL (1U << 4) // General call address
#define I2C_SR2_TRA (1U << 2) // Transmitter/receiver
#define I2C_SR2_BUSY (1U << 1) // Bus busy
#define I2C_SR2_MSL (1U << 0) // Master/slave
/* Clock control register */
#define I2C_CCR_FS (1U << 15) // Fast mode selection
#define I2C_CCR_DUTY (1U << 14) // Fast mode duty cycle
#define I2C_CCR_DUTY_2_1 (0U << 14) // Fast mode duty: 2/1
#define I2C_CCR_DUTY_16_9 (1U << 14) // Fast mode duty: 16/9
#define I2C_CCR_CCR 0xFFF // Clock control bits
/*
* Convenience routines
*/
/* Main I2C API */
/* I2C enable options */
#define I2C_FAST_MODE 0x1 // 400 khz
#define I2C_DUTY_16_9 0x2 // 16/9 duty ratio
/* Flag 0x4 is reserved; DO NOT USE. */
#define I2C_BUS_RESET 0x8 // Perform a bus reset
#define I2C_SLAVE_USE_RX_BUFFER 0x10 // Use a buffered message when doing a slave recv
#define I2C_SLAVE_USE_TX_BUFFER 0x20 // Use a buffered message when doing a slave transmit
#define I2C_SLAVE_DUAL_ADDRESS 0x40 // Enable the dual slave address scheme
#define I2C_SLAVE_GENERAL_CALL 0x80 // Enable the general call on address 0x00
void i2c_master_enable(i2c_dev *dev, uint32 flags);
void i2c_slave_enable(i2c_dev *dev, uint32 flags);
#define I2C_ERROR_PROTOCOL (-1)
#define I2C_ERROR_TIMEOUT (-2)
int32 i2c_master_xfer(i2c_dev *dev, i2c_msg *msgs, uint16 num, uint32 timeout);
void i2c_bus_reset(const i2c_dev *dev);
/**
* @brief Disable an I2C device
*
* This function disables the corresponding peripheral and marks dev's
* state as I2C_STATE_DISABLED.
*
* @param dev Device to disable.
*/
static inline void i2c_disable(i2c_dev *dev) {
dev->regs->CR1 &= ~I2C_CR1_PE;
dev->state = I2C_STATE_DISABLED;
}
/* Start/stop conditions */
/**
* @brief Generate a start condition on the bus.
* @param dev I2C device
*/
static inline void i2c_start_condition(i2c_dev *dev) {
uint32 cr1;
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
I2C_CR1_STOP |
I2C_CR1_PEC)) {
;
}
dev->regs->CR1 |= I2C_CR1_START;
}
/**
* @brief Generate a stop condition on the bus
* @param dev I2C device
*/
static inline void i2c_stop_condition(i2c_dev *dev) {
uint32 cr1;
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
I2C_CR1_STOP |
I2C_CR1_PEC)) {
;
}
dev->regs->CR1 |= I2C_CR1_STOP;
while ((cr1 = dev->regs->CR1) & (I2C_CR1_START |
I2C_CR1_STOP |
I2C_CR1_PEC)) {
;
}
}
/* IRQ enable/disable */
#ifndef _I2C_HAVE_IRQ_FIXUP
/* The series header provides this if _I2C_HAVE_IRQ_FIXUP is defined,
* but we need it either way. */
#define _i2c_irq_priority_fixup(dev) ((void)0)
#endif
#define I2C_IRQ_ERROR I2C_CR2_ITERREN
#define I2C_IRQ_EVENT I2C_CR2_ITEVTEN
#define I2C_IRQ_BUFFER I2C_CR2_ITBUFEN
/**
* @brief Enable one or more I2C interrupts
* @param dev I2C device
* @param irqs Bitwise or of:
* I2C_IRQ_ERROR (error interrupt),
* I2C_IRQ_EVENT (event interrupt), and
* I2C_IRQ_BUFFER (buffer interrupt).
*/
static inline void i2c_enable_irq(i2c_dev *dev, uint32 irqs) {
_i2c_irq_priority_fixup(dev);
dev->regs->CR2 |= irqs;
}
/**
* @brief Disable one or more I2C interrupts
* @param dev I2C device
* @param irqs Bitwise or of:
* I2C_IRQ_ERROR (error interrupt),
* I2C_IRQ_EVENT (event interrupt), and
* I2C_IRQ_BUFFER (buffer interrupt).
*/
static inline void i2c_disable_irq(i2c_dev *dev, uint32 irqs) {
dev->regs->CR2 &= ~irqs;
}
/* ACK/NACK */
/**
* @brief Enable I2C acknowledgment
* @param dev I2C device
*/
static inline void i2c_enable_ack(i2c_dev *dev) {
dev->regs->CR1 |= I2C_CR1_ACK;
}
/**
* @brief Disable I2C acknowledgment
* @param dev I2C device
*/
static inline void i2c_disable_ack(i2c_dev *dev) {
dev->regs->CR1 &= ~I2C_CR1_ACK;
}
/* GPIO control */
/**
* @brief Configure device GPIOs.
*
* Configure GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
* dev->gpio_port for use with I2C device dev.
*
* @param dev I2C Device
* @see i2c_release_gpios()
*/
extern void i2c_config_gpios(const i2c_dev *dev);
/**
* @brief Release GPIOs controlling an I2C bus
*
* Releases the I2C bus controlled by dev as master, and disconnects
* GPIO bits dev->sda_pin and dev->scl_pin on GPIO device
* dev->gpio_port from I2C device dev.
*
* @param dev I2C device
* @see i2c_config_gpios()
*/
extern void i2c_master_release_bus(const i2c_dev *dev);
/* Miscellaneous low-level routines */
void i2c_init(i2c_dev *dev);
/**
* @brief Turn on an I2C peripheral
* @param dev Device to enable
*/
static inline void i2c_peripheral_enable(i2c_dev *dev) {
dev->regs->CR1 |= I2C_CR1_PE;
}
/**
* @brief Turn off an I2C peripheral
* @param dev Device to turn off
*/
static inline void i2c_peripheral_disable(i2c_dev *dev) {
dev->regs->CR1 &= ~I2C_CR1_PE;
}
/**
* @brief Fill transmit register
* @param dev I2C device
* @param byte Byte to write
*/
static inline void i2c_write(i2c_dev *dev, uint8 byte) {
dev->regs->DR = byte;
}
/**
* @brief Set input clock frequency, in MHz
* @param dev I2C device
* @param freq Frequency, in MHz. This must be at least 2, and at most
* the APB frequency of dev's bus. (For example, if
* rcc_dev_clk(dev) == RCC_APB1, freq must be at most
* PCLK1, in MHz). There is an additional limit of 46 MHz.
*/
static inline void i2c_set_input_clk(i2c_dev *dev, uint32 freq) {
#define I2C_MAX_FREQ_MHZ 46
ASSERT(2 <= freq && freq <= _i2c_bus_clk(dev) && freq <= I2C_MAX_FREQ_MHZ);
uint32 cr2 = dev->regs->CR2;
cr2 &= ~I2C_CR2_FREQ;
cr2 |= freq;
dev->regs->CR2 = freq;
#undef I2C_MAX_FREQ_MHZ
}
/**
* @brief Set I2C clock control register.
*
* See the chip reference manual for the details.
*
* @param dev I2C device
* @param val Value to use for clock control register (in
* Fast/Standard mode)
*/
static inline void i2c_set_clk_control(i2c_dev *dev, uint32 val) {
uint32 ccr = dev->regs->CCR;
ccr &= ~I2C_CCR_CCR;
ccr |= val;
dev->regs->CCR = ccr;
}
/**
* @brief Set SCL rise time
* @param dev I2C device
* @param trise Maximum rise time in fast/standard mode (see chip
* reference manual for the relevant formulas).
*/
static inline void i2c_set_trise(i2c_dev *dev, uint32 trise) {
dev->regs->TRISE = trise;
}
/*
* Slave support
*/
/**
* @brief Enable Dual addressing mode to allow peripheral to have 2 addresses
* @param dev I2C device
*/
static inline void i2c_slave_dual_address_enable(i2c_dev *dev) {
dev->regs->OAR2 |= I2C_OAR2_ENDUAL;
}
/**
* @brief Enable General Call to allow the unit to respond on addr 0x00
* @param dev I2C device
*/
static inline void i2c_slave_general_call_enable(i2c_dev *dev) {
dev->regs->CR1 |= I2C_CR1_ENGC;
}
/* callback functions */
/* Callback handler for data received over the bus */
void i2c_slave_attach_recv_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_recv_callback_func func);
/* Callback handler for data being requested over the bus
* The callback function must call i2c_write to get the data over the bus
*/
void i2c_slave_attach_transmit_handler(i2c_dev *dev, i2c_msg *msg, i2c_slave_transmit_callback_func func);
/**
* @brief Set the primary I2c slave address
* @param dev I2C device
* @param address the 8 or 10 bit i2c address
*/
static inline void i2c_slave_set_own_address(i2c_dev *dev, uint16 address) {
dev->regs->OAR1 = address <<1;
}
/**
* @brief Set the secondary I2c slave address
* @param dev I2C device
* @param address the 8 or 10 bit i2c address
*/
static inline void i2c_slave_set_own_address2(i2c_dev *dev, uint16 address) {
dev->regs->OAR2 = (address <<1 ) | I2C_OAR2_ENDUAL;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,145 @@
/******************************************************************************
* 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

@ -0,0 +1,145 @@
/******************************************************************************
* 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_