summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2016-09-19 11:36:13 +0200
committerNicolas Schodet2019-10-09 23:05:51 +0200
commiteda5cf5e3ba38eb8eb7c0c3f0110db886bae93b4 (patch)
tree2d7db1bc4da801b9be7405b54bf5a5e0103d61a1
parent01585a368762caa2e5acb077f48f477339f7ed67 (diff)
ucoo/{intf, hal/i2c}: add send/recv with restart
-rw-r--r--ucoo/hal/i2c/i2c.host.cc16
-rw-r--r--ucoo/hal/i2c/i2c.host.hh3
-rw-r--r--ucoo/hal/i2c/i2c_hard.stm32.cc8
-rw-r--r--ucoo/hal/i2c/i2c_hard.stm32.hh3
-rw-r--r--ucoo/hal/i2c/i2c_soft.cc50
-rw-r--r--ucoo/hal/i2c/i2c_soft.hh5
-rw-r--r--ucoo/intf/i2c.hh6
7 files changed, 91 insertions, 0 deletions
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 ()
{
@@ -130,6 +169,17 @@ I2cSoft::send_start ()
}
void
+I2cSoft::send_restart ()
+{
+ sda_.input ();
+ delay ();
+ scl_.input ();
+ wait_scl ();
+ delay ();
+ send_start ();
+}
+
+void
I2cSoft::send_stop ()
{
sda_.output ();
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.