From 2cda37290deeed9ace58dc59ea1f169643f6cbd0 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Fri, 30 Oct 2015 13:45:40 +0100 Subject: ucoo/hal/i2c: add software implementation --- ucoo/hal/i2c/i2c_soft.cc | 195 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 ucoo/hal/i2c/i2c_soft.cc (limited to 'ucoo/hal/i2c/i2c_soft.cc') diff --git a/ucoo/hal/i2c/i2c_soft.cc b/ucoo/hal/i2c/i2c_soft.cc new file mode 100644 index 0000000..130d425 --- /dev/null +++ b/ucoo/hal/i2c/i2c_soft.cc @@ -0,0 +1,195 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2015 Nicolas Schodet +// +// 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. +// +// }}} +#include "ucoo/hal/i2c/i2c_soft.hh" +#include "ucoo/utils/delay.hh" + +namespace ucoo { + +I2cSoft::I2cSoft (Io &scl, Io &sda) + : scl_ (scl), sda_ (sda), half_period_ns_ (0), + current_status_ (STATUS_ERROR) +{ +} + +I2cSoft::~I2cSoft () +{ + disable (); +} + +void +I2cSoft::enable (int speed) +{ + half_period_ns_ = 1000000000 / speed; + sda_.reset (); + scl_.reset (); +} + +void +I2cSoft::disable () +{ + half_period_ns_ = 0; +} + +void +I2cSoft::send (uint8_t addr, const char *buf, int count) +{ + bool nack; + int sent = 0; + // Start. + send_start (); + // Send SLA+W. + nack = send_byte (addr); + // Send data. + for (; !nack && sent < count; sent++) + nack = send_byte (buf[sent]); + // Stop. + send_stop (); + // Update status, there is no background task. + current_status_ = sent; + if (finished_handler_) + finished_handler_->finished (sent); +} + +void +I2cSoft::recv (uint8_t addr, char *buf, int count) +{ + bool nack; + int recv = 0; + // Start. + send_start (); + // Send SLA+R. + nack = send_byte (addr | 1); + if (!nack) + { + // Receive data, send nack in last byte. + for (; recv < count; recv++) + buf[recv] = recv_byte (recv == count - 1 ? true : false); + } + // Stop. + send_stop (); + // Update status, there is no background task. + current_status_ = recv; + if (finished_handler_) + finished_handler_->finished (recv); +} + +int +I2cSoft::status () +{ + return current_status_; +} + +int +I2cSoft::wait () +{ + // No background task, nothing to wait. + return current_status_; +} + +void +I2cSoft::delay () +{ + delay_ns (half_period_ns_); +} + +void +I2cSoft::wait_scl () +{ + while (!scl_.get ()) + ; +} + +void +I2cSoft::send_start () +{ + sda_.output (); + delay (); + scl_.output (); + delay (); +} + +void +I2cSoft::send_stop () +{ + sda_.output (); + delay (); + scl_.input (); + wait_scl (); + delay (); + sda_.input (); + delay (); +} + +void +I2cSoft::send_bit (bool bit) +{ + if (bit) + sda_.input (); + else + sda_.output (); + delay (); + scl_.input (); + wait_scl (); + delay (); + scl_.output (); +} + +bool +I2cSoft::recv_bit () +{ + sda_.input (); + delay (); + scl_.input (); + wait_scl (); + bool bit = sda_.get (); + delay (); + scl_.output (); + return bit; +} + +bool +I2cSoft::send_byte (char b) +{ + for (int i = 8; i; i--) + { + send_bit (b & 0x80); + b <<= 1; + } + return recv_bit (); +} + +char +I2cSoft::recv_byte (bool nack) +{ + char b = 0; + for (int i = 8; i; i--) + { + b <<= 1; + b |= recv_bit () ? 1 : 0; + } + send_bit (nack); + return b; +} + +} // namespace ucoo -- cgit v1.2.3