# RTL8720DN as I2C slave

**URL:** <https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407>\
**Category:** Peripherals\
**Tags:** evb-bw16, rtl872xd\
**Created:** [March 30, 2021, 8:00am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407 "2021-03-30T08:00:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [March 30, 2021, 8:00am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/1 "2021-03-30T08:00:04Z")

</div>

Hi,

I’m currently trying to use the RTL8720dn chip as I2C Slave. I’ve tried using some functions and implementations of the sdk (i2c\_api), but facing some weird issues where the polling mode doesn’t seem to work. Because of this, I’m curious if the Arduino package contains the full implementation. What’s the best practise in this occasion?

Currently I’m programming the chip with a library (self made) on top of the i2c\_api.h header which in included in the arduino package (AmebaD/3.0.7/system/libameba/sdk/component/common/mbed/hal/i2c\_api.h). But I just had a look into the SDK and faces the rtl8721d\_i2c.h header and source ([https://github.com/ambiot/ambd\_sdk/blob/master/component/soc/realtek/amebad/fwlib/ram\_common/rtl8721d\_i2c.c](https://github.com/ambiot/ambd_sdk/blob/master/component/soc/realtek/amebad/fwlib/ram_common/rtl8721d_i2c.c)). Does any of you have experience with this case, and what’s best practise?  
Use the i2c\_api in the arduino package, or take a look into the official sdk. As told it’s required to use the 8720dn in polling mode (waiting for the master to send a request to respond on).

Thanks guys!

Kind regards,  
Tim

---

<div class="post-metadata">

**Author:** ![xidameng](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xidameng/32/18_2.png) [@xidameng](https://forum.amebaiot.com/u/xidameng)\
**Post date:** [March 30, 2021, 8:20am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/2 "2021-03-30T08:20:05Z")

</div>

hi Tim,

afaik, arduino also only uses i2c in master mode

> [@TBeeren](#):
>
> but facing some weird issues where the polling mode doesn’t seem to work

do you mind elaborate?

---

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [March 30, 2021, 8:53am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/3 "2021-03-30T08:53:52Z")

</div>

Hi Simon,

That’s what I was a bit afraid of hahah! I tried editing the header a bit by changing the way it uses the slave. I did this by changing the TwoWireStatus and calling the functions, which are provided by the package a bit different. For writing, it seems to work. But it’s more of a brute force where the slaves tries to finish the transaction, which needs to be on the specific time when the master reads. Ofcourse, this isn’t the desired behaviour, but this was just me trying to find a workaround for the lack on slave-mode. Happy to hear that you think to know that the arduino package only provides master usage.

Have you used the rtl8721d\_i2c header and source of the sdk? Just checked the code and header and this seems to have a chance of working. Only not sure if it provides a polling mode for the slave. In an ideal scenario, the slave keeps listening, and will be triggered (by callback) when he get’s polled by the master.  
 ![afbeelding](https://us1.discourse-cdn.com/flex016/uploads/ameba/original/1X/b8290889c96cdad481583f8b15714b7fd5fb976a.png)

To elaborate on the polling issues:  
The slave tries reading from the bus, but this doesn’t sees anything. However, i’ve checked the signal with a logic analyser, which is all fine (address and payload). I think, as you told, the arduino package spares some support for the slave side.

---

<div class="post-metadata">

**Author:** ![xidameng](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xidameng/32/18_2.png) [@xidameng](https://forum.amebaiot.com/u/xidameng)\
**Post date:** [March 30, 2021, 10:22am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/4 "2021-03-30T10:22:09Z")

</div>

> [@TBeeren](#):
>
> Have you used the rtl8721d\_i2c header and source of the sdk?

Hi Tim, you probably should look into this file instead, as this is the api primarily used for I2C operation

> <https://github.com/ambiot/ambd_sdk/blob/master/component/common/mbed/hal/i2c_api.h>

---

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [March 30, 2021, 10:30am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/5 "2021-03-30T10:30:35Z")

</div>

Hi Simon,

I could be wrong, but that’s the same as in the arduino package (AmebaD/3.0.7/system/libameba/sdk/component/common/mbed/hal/i2c\_api.h), in which the slave mode seem to has lacks (as you told).

> [@xidameng](#):
>
> afaik, arduino also inly uses i2c in master mode

I can have a look in the source, but on the bus (using this api, as provided above) I’m not seeing a read signal when the slave is in polling mode.

---

<div class="post-metadata">

**Author:** ![xidameng](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xidameng/32/18_2.png) [@xidameng](https://forum.amebaiot.com/u/xidameng)\
**Post date:** [March 30, 2021, 10:36am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/6 "2021-03-30T10:36:07Z")

</div>

check this line out, is this the one you need?

> <https://github.com/ambiot/ambd_sdk/blob/a98cf3fa2ef4141f8c17238143ddef4121c01857/component/common/mbed/hal/i2c_api.h#L111>

also this line for polling mode

> <https://github.com/ambiot/ambd_sdk/blob/a98cf3fa2ef4141f8c17238143ddef4121c01857/component/common/mbed/hal/i2c_api.h#L163>

---

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [April 30, 2021, 7:10am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/7 "2021-04-30T07:10:16Z")

</div>

Hi everyone,

I’ve finally been able to get the slave in polling mode with the Master. However I’m stil facing a couple smaller issues.

The image below shows a simple I2C transmission where the master (raspberry pi 4, SMBUS protocol) sends a message (0). Then the interrupt of the slave is triggered which then returns WriteAddressed (i2c\_slave\_receive), with in this case the register (0x10 = 16 dec) and the payload (0). This is read correctly by the Slave, which then sends a response back (1) to the Master using i2c\_slave\_write. This flow is valid. Also on the logic analyzer (image below) you can see that the transaction is then completed, and the SDA line is pulled up by the Master.

![Example](https://us1.discourse-cdn.com/flex016/uploads/ameba/original/1X/58b2ce9c1e7c94be092323d8b695c505ae17ead1.png)

However, the i2c\_slave\_receive function remains constantly ‘ReadAddressed’ returned in an infinite loop. Is this because of the NACK to the (1) response message? Which on the one hand would be strange since the SDA line is pulled up, and the ‘1’ is actually read on the Master side. Does anyone have experience with this? And how do I fix this to repeat the previous transaction again without letting the WriteAddressed pass through because the slave thinks it is constantly being asked to read (which is not the case on the line).

The slave does not send the response until it receives a “ReadAddressed” for the first time. This also makes it strange that he keeps asking again while the master side (SMBUS) only asks for 1 byte.

Thanks guys.

---

<div class="post-metadata">

**Author:** ![xsutter](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xsutter/32/565_2.png) [@xsutter](https://forum.amebaiot.com/u/xsutter)\
**Post date:** [October 18, 2021, 9:17pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/8 "2021-10-18T21:17:52Z")

</div>

Hi,

I am resurrecting this thread because I am attempting to use the RTL8720DN as an I2C Slave, using the Wire library included in the Arduino SDK (AmebaD/3.0.8/libraries/Wire).

The problem I am facing is that the `Wire.onReceive` and `Wire.onRequest` callbacks never get called.  
The receiver is not completely dead however, because it correctly ACKs the received bytes – until it has accumulated 16 bytes, after which it stretches the SCL clock forever (which should never happen in a Slave Receiver Transfer operation). This of course stalls the bus. Here are the last two bytes received before the receiver hangs:

 ![I2S_slave_recv](https://us1.discourse-cdn.com/flex016/uploads/ameba/original/1X/a283e9969a4aeb1bde570f7a8f34a06feae9eb4d.png)

Here is the test code I am using:

> ```
> #include <string.h>
> #include "Wire.h"
> 
> #define BLUE_LED PA_11 // also known as PA13 in BW16 module (see variant.h)
> #define I2C_ADDRESS 0x3a // device address on the I2C bus
> 
> uint8_t I2C_SendBuf [] = { 41, 52, 63, 74 };
> volatile uint8_t I2C_RecvBuf[32];
> volatile bool I2C_newData;
> volatile int I2C_bytes_rcvd;
> 
> void setup() {
> pinMode(BLUE_LED, OUTPUT);
> digitalWrite(BLUE_LED, 0);
>   
> Serial1.begin(115200);
> while (!Serial1) ;
>     
> Wire.begin(I2C_ADDRESS); // declare the device as I2C slave
> Wire.onReceive(I2C_receiveEvent);
> Wire.onRequest(I2C_requestEvent);
> I2C_newData = false;
> I2C_bytes_rcvd = 0;
> 
> digitalWrite(BLUE_LED, 1);
> delay(1000);
> digitalWrite(BLUE_LED, 0);
> printf("\nInit OK\n");
> }
> 
> void loop() {
> if (I2C_newData) {
> printf("Received %d bytes, first = %02x\n", I2C_bytes_rcvd, I2C_RecvBuf[0]);
> I2C_newData = false;
> }
> delay(1);
> }
> 
> static void I2C_receiveEvent(int howMany) {
> I2C_newData = true;
> 
> digitalWrite(BLUE_LED, 1);
> for (int i = 0; i < howMany; i++) {
> I2C_RecvBuf[i] = Wire.read();
> }
> I2C_bytes_rcvd = howMany;
> }
> 
> static void I2C_requestEvent() {
> 
> digitalWrite(BLUE_LED, 1);
> Wire.write(I2C_SendBuf, sizeof(I2C_SendBuf)); // send response
> }
> 
> ```

Hence my simple question: am I missing something here, or is the Ameba Arduino SDK’s Wire library simply not able to perform as an I2C slave?

Thanks for help !

---

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [October 18, 2021, 9:52pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/9 "2021-10-18T21:52:12Z")

</div>

Hi xsutter,

Cool to see you’re also trying to use the 8720DN as i2c slave! I’ve to remember what I did to get it working, but the spoiler I can already give is that it does work as slave!

There were a couple thing I noticed during working with the chipset. I also never got it working with the Wire arduino library. It could be that they’re currently  
supporting the correct pins, however at the time  
i worked on it there were some issues there. My workaround have been creating a i2c-library yourself. This sounds like a lot of work, however you can look into the sdk code ameba provides on their ‘normal’ sdk. That code could almost identical be used and linked upon your arduino project. Just add the C or C++ (what you prefer) to your arduino files. Then you’re able to talk directly to the low-level i2c drivers from ameba, without the Wire lib in the middle. This will provide a lot of possibilities and insights in your I2C connection.

Next to that, if you’ll see clock stretching happening, you could conclude one of the next two things: your master pulls the clock down since It’s waiting for a transaction - which could be solved by implementing a timeout. Or there goes something wrong on slave side which affects the entire bus. Sadly, when you miss a single byte of I2C, you’re able to hang the entire bus. To fix all of this, you should implement a way in which a protocol (like go-back-n of retries) will save the day - without hanging the connection.

Sadly I’m not able and allowed to share my code, but I do hope this info will help you a bit.

---

<div class="post-metadata">

**Author:** ![xsutter](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xsutter/32/565_2.png) [@xsutter](https://forum.amebaiot.com/u/xsutter)\
**Post date:** [October 18, 2021, 10:36pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/10 "2021-10-18T22:36:24Z")

</div>

Hi Tim,

Thanks for your suggestion ! Unless someone at Ameba gives us a fresh status of the current capabilities of the Wire library, I am afraid I will have to forget about it and dive deep into the Mbed API like you did.

As for clock stretching: this can never be an operation performed by the I2C master, only the slave can do this. Therefore the problem is with the Realtek as a slave – I hope the cause is just within the Wire library, and not something deeper.

Xavier

---

<div class="post-metadata">

**Author:** ![xsutter](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xsutter/32/565_2.png) [@xsutter](https://forum.amebaiot.com/u/xsutter)\
**Post date:** [October 19, 2021, 9:54am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/11 "2021-10-19T09:54:51Z")

</div>

Hi Tim,  
I am now switching to the Mbed i2c API. I would like to use interrupts as much as possible, however `i2c_api` appears to lack extensive IRQ management like we can find in `spi_api` or `i2s_api`, for example. I would like to avoid writing an i2c interrupt manager. Are you aware of someone, somewhere, who did the job already and that I could use as a starting point?

Thanks !

---

<div class="post-metadata">

**Author:** ![xsutter](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xsutter/32/565_2.png) [@xsutter](https://forum.amebaiot.com/u/xsutter)\
**Post date:** [October 28, 2021, 6:06pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/12 "2021-10-28T18:06:30Z")

</div>

Hi everyone,  
Hi Tim,

Having switched to the Mbed API, I am now in the situation you described, where upon a Read Request the RTL8720 slave is stuck in “ReadAddressed” mode. Recognizing the final NACK is normally the role of the `RX_DONE` interrupt flag. _UM0400 - Ameba-D User Manual_ states that

> “When the I2C is acting as a slave-transmitter, this bit is set to 1 if the master does not acknowledge a transmitted byte. This occurs on the last byte of the transmission, indicating that the transmission is done.”

My understanding is that the RTL8720 driver fails to correctly handle the `RX_DONE` interrupt flag. The only way I found to escape the “ReadAddressed” and get back to “NoData” is to disable and re-enable I2C using `I2C_Cmd()`. However this does not solve everything, because now the Tx FIFO is empty (which the RTL8720 does not like), and a subsequent Read Request stalls the I2C bus forever. Did you find a way to get out of this situation?

I also tried to have the I2C Master read one byte less than what I wrote in the Tx FIFO. _UM0400_ states that

> “If the remote master is to receive n bytes from the I2C but the programmer wrote a number of bytes larger than n to the Tx FIFO, then when the slave finishes sending the requested n bytes, it clears the Tx FIFO and ignores any excess bytes.”

This is not the behaviour I have observed doing this. What I can see is that upon the final NACK, the `i2c_slave_write()` function never returns because the underlying `I2C_SlaveWrite()` waits forever for the Tx FIFO to be empty (the `BIT_IC_STATUS_TFE` flag). The reason of this clearly appears in the `I2C_SlaveWrite()` source code (have a look at the last `while`):

```auto
void I2C_SlaveWrite(I2C_TypeDef *I2Cx, u8* pBuf, u8 len)
{
	u8 cnt = 0;
	
	/* Check the parameters */
	assert_param(IS_I2C_ALL_PERIPH(I2Cx));

	for(cnt = 0; cnt < len; cnt++) {
		/* Check I2C RD Request flag */
		while((I2Cx->IC_RAW_INTR_STAT & BIT_IC_RAW_INTR_STAT_RD_REQ) == 0);

		if (I2C_SLAVEWRITE_PATCH) {
			I2Cx->IC_CLR_RD_REQ;
		}
		/* Check I2C TX FIFO status */
		while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFNF)) == 0);
		
		I2Cx->IC_DATA_CMD = (*pBuf++);
	}
	while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFE)) == 0);
}

```

This function never checks `BIT_IC_RAW_INTR_STAT_RX_DONE`, which is THE information it needs to return as soon as the Master terminates the transaction.

Does someone at Realtek have an opinion about all this? Don’t you think that `RX_DONE` management in this driver deserves a firmware update? If not, do you have a suggestion to help work around it and avoid freezing the I2C bus upon successive Read Requests?

Thanks for help!

---

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [October 28, 2021, 6:25pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/13 "2021-10-28T18:25:01Z")

</div>

Hi xsutter,

Happy to hear you’ve made progress! This part of the RTL8720DN chip also took me a lot of time to figure out. Everything you’ve mentioned is right. I sadly can’t look into my code again due to NDA’s and secrets within the project. However I can remember that I cleared the Interrupt myself. It was a really ugly workaround since it should be handled on their own (build within the sdk), however as you mentioned, the slave will stay in that while loop.

Again, don’t pin me on this answer since I’m trying to remember everything from months ago haha.

There should be a clear\_interrupt or i2c\_clear function (something like that) which could clear the flag which is currently blocking your slave to read / write more. Whenever you’re in this blocking state, you should adapt a condition in which you can clear this interrupt which is stated in the SDK.

@xidameng maybe also knows some info on this point since I think we discussed this a while ago.

Hope something will help you!

Kind regards,  
Tim

---

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [October 28, 2021, 6:27pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/14 "2021-10-28T18:27:57Z")

</div>

Just found my notes from a while ago. Let me check if I can share anything.

---

<div class="post-metadata">

**Author:** ![TBeeren](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/tbeeren/32/272_2.png) [@TBeeren](https://forum.amebaiot.com/u/TBeeren)\
**Post date:** [October 28, 2021, 6:37pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/15 "2021-10-28T18:37:49Z")

</div>

For example, this is the way I created the ‘workaround’ for the slave getting stuck on the interrupt. I won’t win any contest with this code, since it’s not nice designed. However I couldn’t find a solution within the SDK which solved my problem.

```auto
void I2C_Client::handlePollingFromMaster()
{
    switch (slave_receive(((i2c_t *)m_pI2C)))
    {
    case ReadAddressed:
    {
        if (m_readTimeout > MAX_READ_TIMEOUT)
        {
            if (I2C_GetRawINT(((i2c_t *)m_pI2C)->I2Cx) & BIT_IC_RAW_INTR_STAT_RD_REQ)
            {
                I2C_ClearAllINT(((i2c_t *)m_pI2C)->I2Cx);
            }
        }
        m_readTimeout++;
        break;
    }
    case WriteAddressed:
    {
        char buff[1];
        if (i2c_slave_read(((i2c_t *)m_pI2C), buff, 1) > 0)
        {
            // Do your operation based on the Byte which is sent by the Master.
        }
        break;
    }
    case WriteGeneral:
    {
        break;
    }
    default:
    {
        break;
    }
    }

```

---

<div class="post-metadata">

**Author:** ![xsutter](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xsutter/32/565_2.png) [@xsutter](https://forum.amebaiot.com/u/xsutter)\
**Post date:** [October 31, 2021, 9:00pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/16 "2021-10-31T21:00:52Z")

</div>

Hi everyone,  
Hi Tim,

Thanks for your example. Your idea of including a timeout helped me sort out the whole thing, and I think I have now a clear idea of what is happening and how to proceed. There are 3 things to take care about:

1- The main culprit is, as I suspected in my previous post, [Ameba Low Level API’s `I2C_SlaveWrite()`](https://github.com/ambiot/ambd_sdk/blob/6f784f436860a4f79f3f96092997073f16561a00/component/soc/realtek/amebad/fwlib/ram_common/rtl8721d_i2c.c) function. This function fails to test the `RX_DONE` flag, hence cannot return upon the closing NACK.

I reimplemented the function and now use my own version. I just had to change the final

```auto
    while((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFE)) == 0);

```

for

```auto
    while(((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFE)) == 0) &&
          ((I2Cx->IC_RAW_INTR_STAT & BIT_IC_RAW_INTR_STAT_RX_DONE) == 0));

```

Now `i2c_slave_write()` does not block forever any more and returns correctly – even if the I2C master reads fewer bytes than what I sent to the Tx FIFO.

This is also the place where I included the timeout as per your idea, although I have to say that once I did things cleverly, it never triggered once. I just keep it as a precaution. Here is the version of the lines above including the timeout:

```auto
    int count = 0;
    while(((I2C_CheckFlagState(I2Cx, BIT_IC_STATUS_TFE)) == 0) &&
          ((I2Cx->IC_RAW_INTR_STAT & BIT_IC_RAW_INTR_STAT_RX_DONE) == 0) &&
	      (count++ < MAXCOUNT));

```

You have to use a logic analyzer to check the speed of this loop and determine a proper value for MAXCOUNT. On my setup every loop accounted for about 2µs (including the fact that I actually had to toggle a GPIO line inside the loop to give a signal to my analyzer), but your mileage may vary.

2- Once `i2c_slave_write()` returns, typically the slave software is still in a `ReadAddressed` switch case. Before breaking, you **absolutely** want to cleanup the status of the I2C device in order to allow the software to switch to the `NoData` case the next time. I tested two methods to do this:

```auto
    I2C_Cmd(I2Cx, DISABLE);
    I2C_Cmd(I2Cx, ENABLE);

```

which clears the Tx and Rx FIFOs, but leaves the interrupt flags untouched;  
and

```auto
    I2C_ClearAllINT(I2Cx);

```

which just clears all interrupts.  
Both methods give equally satisfactory results, although not performing the same operation. I don’t know why. Failing to use either of them keeps the system in the `ReadAddressed` state forever (which you described earlier in this thread). Should the master attempt to perform subsequent Write transactions, the slave would not be able to switch to `WriteAddressed` to read the received data. Eventually, once the 16-byte Rx FIFO is full, the I2C bus may hang.

3- You want to make sure that

```auto
    switch (slave_receive((i2c_t *)device))

```

is called often enough. Here the key parameter is the I2C master’s I2C timeout. Let `T` be the period at which you call `slave_receive()`. Upon a Read Request by the master, the RTL8720 performs an I2C clock stretch which lasts until the slave software actually sends bytes to the Tx FIFO. This clock stretch may last as long as `T`. Should the master’s I2C timeout elapse before T, what happens is that the master merely relinquishes the bus and abandons the transaction. Then, when the RTL8720 eventually has something to transmit, there is no clock any more on the bus to empty the Tx FIFO and complete the transaction.  
Hence `T` should always be made shorter than the master’s I2C timeout by a good margin.

Now my system runs as smoothly as can be. Too bad the Ameba documentation is so sparse about how to use the I2C slave API successfully in the first place.  
Hope that helps !

Xavier

---

<div class="post-metadata">

**Author:** ![xidameng](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xidameng/32/18_2.png) [@xidameng](https://forum.amebaiot.com/u/xidameng)\
**Post date:** [November 1, 2021, 2:05am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/17 "2021-11-01T02:05:24Z")

</div>

Thanks @xsutter for sharing the info 👍

---

<div class="post-metadata">

**Author:** ![xsutter](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xsutter/32/565_2.png) [@xsutter](https://forum.amebaiot.com/u/xsutter)\
**Post date:** [November 1, 2021, 1:34pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/18 "2021-11-01T13:34:32Z")

</div>

Hi Simon,  
You’re welcome. To further refine my point, I think that the device cleanup I described in my 2- above should actually be performed **inside** the `I2C_SlaveWrite()` function right at the end, because anyway this action must be performed every time `I2C_SlaveWrite()` returns.

However I am not sure which is the appropriate cleanup action to perform. Is it a device `DISABLE` + `ENABLE` ? Is it an `I2C_ClearAllINT()`? Is it just an `I2C_ClearINT(RD_REQ)`? Probably only Realtek people aware of the detailed underlying mechanism could make a wise decision.

Anyway I think the `I2C_SlaveWrite()` function deserves an update in the next Ameba SDK release. This would make the life of I2C slave software developers considerably easier. Do you know what is the best way to request such an update?

Xavier

---

<div class="post-metadata">

**Author:** ![xidameng](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xidameng/32/18_2.png) [@xidameng](https://forum.amebaiot.com/u/xidameng)\
**Post date:** [May 17, 2022, 7:39am UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/19 "2022-05-17T07:39:02Z")

</div>

> [@xsutter](#):
>
> the detailed underlying mechanism

Dear @xsutter

This part is handled by other developing team thus it will be updated only if they deem necessary.

Thanks for your feedback though, we will feedback to them once we have the chance

---

<div class="post-metadata">

**Author:** ![xsutter](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.amebaiot.com/xsutter/32/565_2.png) [@xsutter](https://forum.amebaiot.com/u/xsutter)\
**Post date:** [May 17, 2022, 1:44pm UTC](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407/20 "2022-05-17T13:44:14Z")

</div>

Hi @xidameng ,

This question appears to have been settled some time ago already: see  
[I2C Slave API fails to recognize the master’s final NACK in slave-to-master transmissions](https://github.com/ambiot/ambd_sdk/issues/8).

Unfortunately the correction to the AmebaD SDK was not propagated to the Arduino SDK, which appears to still contain [the buggy `I2C_SlaveWrite()`](https://github.com/ambiot/ambd_arduino/blob/4823c9d7aa80c4bcc755857e1984a50c11ddfc3a/Arduino_package/hardware/system/component/soc/realtek/amebad/fwlib/ram_common/rtl8721d_i2c.c#L719). I will have to file an issue for this as well.

Cheers,  
Xavier

[Next page](https://forum.amebaiot.com/t/rtl8720dn-as-i2c-slave/407.md?page=2)
