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/Module | 3 +- ucoo/hal/i2c/i2c.hh | 3 +- ucoo/hal/i2c/i2c_soft.cc | 195 +++++++++++++++++++++++++++++++++++++++++++++++ ucoo/hal/i2c/i2c_soft.hh | 79 +++++++++++++++++++ 4 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 ucoo/hal/i2c/i2c_soft.cc create mode 100644 ucoo/hal/i2c/i2c_soft.hh (limited to 'ucoo/hal') diff --git a/ucoo/hal/i2c/Module b/ucoo/hal/i2c/Module index 872be6f..0d34c11 100644 --- a/ucoo/hal/i2c/Module +++ b/ucoo/hal/i2c/Module @@ -1 +1,2 @@ -ucoo_hal_i2c_SOURCES := i2c.host.cc i2c_slave_data_buffer.cc i2c_hard.stm32.cc +ucoo_hal_i2c_SOURCES := i2c.host.cc i2c_slave_data_buffer.cc \ + i2c_hard.stm32.cc i2c_soft.cc diff --git a/ucoo/hal/i2c/i2c.hh b/ucoo/hal/i2c/i2c.hh index 2c06085..e5d940e 100644 --- a/ucoo/hal/i2c/i2c.hh +++ b/ucoo/hal/i2c/i2c.hh @@ -28,9 +28,8 @@ # include "i2c.host.hh" #elif defined (TARGET_stm32) # include "i2c_hard.stm32.hh" -#else -# error "not implemented for this target" #endif +#include "i2c_soft.hh" #include "i2c_slave_data_buffer.hh" #endif // ucoo_hal_i2c_i2c_hh 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 diff --git a/ucoo/hal/i2c/i2c_soft.hh b/ucoo/hal/i2c/i2c_soft.hh new file mode 100644 index 0000000..83bc44c --- /dev/null +++ b/ucoo/hal/i2c/i2c_soft.hh @@ -0,0 +1,79 @@ +#ifndef ucoo_hal_i2c_i2c_soft_hh +#define ucoo_hal_i2c_i2c_soft_hh +// 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/intf/i2c.hh" +#include "ucoo/intf/io.hh" + +namespace ucoo { + +/// I2C interface, using IO. +class I2cSoft : public I2cMaster +{ + public: + /// Constructor. + I2cSoft (Io &scl, Io &sda); + /// Destructor. + ~I2cSoft (); + /// Enable and setup. + void enable (int speed = 100000); + /// Disable. + void disable (); + /// See I2cMaster::send. + void send (uint8_t addr, const char *buf, int count); + /// See I2cMaster::recv. + void recv (uint8_t addr, char *buf, int count); + /// See I2cMaster::status. + int status (); + /// See I2cMaster::wait. + int wait (); + private: + /// Wait half a bit period. + void delay (); + /// Wait until SCL goes high (clock stretching). + void wait_scl (); + /// Send start condition. + void send_start (); + /// Send stop condition. + void send_stop (); + /// Send one bit. + void send_bit (bool bit); + /// Receive one bit. + bool recv_bit (); + /// Send one byte, return nack bit. + bool send_byte (char b); + /// Receive one byte. + char recv_byte (bool nack); + private: + /// I2C signals. + Io &scl_, &sda_; + /// Half period. + int half_period_ns_; + /// Current status. + int current_status_; +}; + +} // namespace ucoo + +#endif // ucoo_hal_i2c_i2c_soft_hh -- cgit v1.2.3