From eda5cf5e3ba38eb8eb7c0c3f0110db886bae93b4 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Mon, 19 Sep 2016 11:36:13 +0200 Subject: ucoo/{intf, hal/i2c}: add send/recv with restart --- ucoo/hal/i2c/i2c.host.cc | 16 ++++++++++++++ ucoo/hal/i2c/i2c.host.hh | 3 +++ ucoo/hal/i2c/i2c_hard.stm32.cc | 8 +++++++ ucoo/hal/i2c/i2c_hard.stm32.hh | 3 +++ ucoo/hal/i2c/i2c_soft.cc | 50 ++++++++++++++++++++++++++++++++++++++++++ ucoo/hal/i2c/i2c_soft.hh | 5 +++++ ucoo/intf/i2c.hh | 6 +++++ 7 files changed, 91 insertions(+) (limited to 'ucoo') diff --git a/ucoo/hal/i2c/i2c.host.cc b/ucoo/hal/i2c/i2c.host.cc index 6b3181b..d471df1 100644 --- a/ucoo/hal/i2c/i2c.host.cc +++ b/ucoo/hal/i2c/i2c.host.cc @@ -190,6 +190,22 @@ I2cHost::recv (uint8_t addr, char *buf, int count) finished_handler_->finished (master_status_); } +void +I2cHost::send_recv (uint8_t addr, const char *send_buf, int send_count, + char *recv_buf, int recv_count) +{ + // No restart in host implementation, do regular send/recv. + int r = shared_->send (addr, send_buf, send_count); + if (r == send_count) + { + master_status_ = STATUS_ERROR; + if (finished_handler_) + finished_handler_->finished (master_status_); + } + else + recv (addr, recv_buf, recv_count); +} + int I2cHost::status () { diff --git a/ucoo/hal/i2c/i2c.host.hh b/ucoo/hal/i2c/i2c.host.hh index c0bb7f9..adc7e84 100644 --- a/ucoo/hal/i2c/i2c.host.hh +++ b/ucoo/hal/i2c/i2c.host.hh @@ -40,6 +40,9 @@ class I2cHost : public I2c void send (uint8_t addr, const char *buf, int count); /// See I2cMaster::recv. void recv (uint8_t addr, char *buf, int count); + /// See I2cMaster::send_recv + void send_recv (uint8_t addr, const char *send_buf, int send_count, + char *recv_buf, int recv_count); /// See I2cMaster::status. int status (); /// See I2cMaster::wait. diff --git a/ucoo/hal/i2c/i2c_hard.stm32.cc b/ucoo/hal/i2c/i2c_hard.stm32.cc index 5e767d6..22567c9 100644 --- a/ucoo/hal/i2c/i2c_hard.stm32.cc +++ b/ucoo/hal/i2c/i2c_hard.stm32.cc @@ -183,6 +183,14 @@ I2cHard::recv (uint8_t addr, char *buf, int count) transfer (addr | 1, buf, count); } +void +I2cHard::send_recv (uint8_t addr, const char *send_buf, int send_count, + char *recv_buf, int recv_count) +{ + // TODO: not implemented. + assert_unreachable (); +} + int I2cHard::status () { diff --git a/ucoo/hal/i2c/i2c_hard.stm32.hh b/ucoo/hal/i2c/i2c_hard.stm32.hh index 81c5deb..d2bb63a 100644 --- a/ucoo/hal/i2c/i2c_hard.stm32.hh +++ b/ucoo/hal/i2c/i2c_hard.stm32.hh @@ -57,6 +57,9 @@ class I2cHard : public I2c void send (uint8_t addr, const char *buf, int count); /// See I2cMaster::recv. void recv (uint8_t addr, char *buf, int count); + /// See I2cMaster::send_recv + void send_recv (uint8_t addr, const char *send_buf, int send_count, + char *recv_buf, int recv_count); /// See I2cMaster::status. int status (); /// See I2cMaster::wait. diff --git a/ucoo/hal/i2c/i2c_soft.cc b/ucoo/hal/i2c/i2c_soft.cc index 130d425..ac65dff 100644 --- a/ucoo/hal/i2c/i2c_soft.cc +++ b/ucoo/hal/i2c/i2c_soft.cc @@ -94,6 +94,45 @@ I2cSoft::recv (uint8_t addr, char *buf, int count) finished_handler_->finished (recv); } +void +I2cSoft::send_recv (uint8_t addr, const char *send_buf, int send_count, + char *recv_buf, int recv_count) +{ + bool nack; + int sent = 0, recv = 0; + // Start. + send_start (); + // Send SLA+W. + nack = send_byte (addr); + // Send data. + for (; !nack && sent < send_count; sent++) + nack = send_byte (send_buf[sent]); + // Update status, there is no background task. + if (sent != send_count) + { + current_status_ = STATUS_ERROR; + if (finished_handler_) + finished_handler_->finished (STATUS_ERROR); + return; + } + // Restart. + send_restart (); + // Send SLA+R. + nack = send_byte (addr | 1); + if (!nack) + { + // Receive data, send nack in last byte. + for (; recv < recv_count; recv++) + recv_buf[recv] = recv_byte (recv == 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 () { @@ -129,6 +168,17 @@ I2cSoft::send_start () delay (); } +void +I2cSoft::send_restart () +{ + sda_.input (); + delay (); + scl_.input (); + wait_scl (); + delay (); + send_start (); +} + void I2cSoft::send_stop () { diff --git a/ucoo/hal/i2c/i2c_soft.hh b/ucoo/hal/i2c/i2c_soft.hh index 83bc44c..dc66a97 100644 --- a/ucoo/hal/i2c/i2c_soft.hh +++ b/ucoo/hal/i2c/i2c_soft.hh @@ -44,6 +44,9 @@ class I2cSoft : public I2cMaster void send (uint8_t addr, const char *buf, int count); /// See I2cMaster::recv. void recv (uint8_t addr, char *buf, int count); + /// See I2cMaster::send_recv + void send_recv (uint8_t addr, const char *send_buf, int send_count, + char *recv_buf, int recv_count); /// See I2cMaster::status. int status (); /// See I2cMaster::wait. @@ -55,6 +58,8 @@ class I2cSoft : public I2cMaster void wait_scl (); /// Send start condition. void send_start (); + /// Send restart condition. + void send_restart (); /// Send stop condition. void send_stop (); /// Send one bit. diff --git a/ucoo/intf/i2c.hh b/ucoo/intf/i2c.hh index 7d3a624..6fa03e3 100644 --- a/ucoo/intf/i2c.hh +++ b/ucoo/intf/i2c.hh @@ -63,6 +63,12 @@ class I2cMaster /// /// If asynchronous transfer is not supported, this will block. virtual void recv (uint8_t addr, char *buf, int count) = 0; + /// Same as send followed by recv, but using a repeated start. If the + /// send phase is not completed fully, STATUS_ERROR is reported, else + /// reception phase status is reported. + virtual void send_recv (uint8_t addr, + const char *send_buf, int send_count, + char *recv_buf, int recv_count) = 0; /// Return last transfer status. virtual int status () = 0; /// Wait until transfer is finished and return status. -- cgit v1.2.3