I am using the i2c adapters (in master mode) for doing asynchronous writes or reads that waits FOREVER for an OS_EVENT to be signalled from the callback.
However instead of waiting FOREVER I want to be able to set a timeout value so that it doesn't get stuck if say there's no device on the bus.
But then after a timeout If I try to initiated another async read or write the adapter hangs because there's (for e.g. 2) pending transactions that are unfinished. How can I cancel these pending transactions or better yet, what's the proper way so that I can use timeouts with ad_i2c_async_read or ad_i2c_async_write.
Device:
Hi rajames,
If you start an asynchronous transaction using the asynch functions of the SDK, the API provides you with a callback parameter, this callback should be executes upon completing the transaction. If for any reason the the device gets a NACK when trying to access an I2C device then the interaction will terminate with the appropriate error, in the case of NACK from the device's side HW_I2C_ABORT_7B_ADDR_NO_ACK, and you will able to know that when the callback occurs. Instead of having the wait_for_event(event) (i suppose that this is what you mean) you can ommit that in order not to block the task but you cannot cancel the transaction that has allready began, and also you cannot use a second asynch transaction before the previous one returns, this clearly stated in the doxygen in the description of the ad_i2c_asynch_read and write functions.
Thanks MT_dialog
Hi Dalog,
Thanks for your response.
如果我你nderstand correctly that callback should ALWAYS execute even if an error occurs.
I am using the callback to signal the task , see below for pseudo code:
callback(params) {
// handle params
OS_SIGNAL(event)
}
task() {
async_write(data, callback)
OS_EVENT_WAIT(event, TIMEOUT)
// more asynchronous writes or reads in the same fashion
}
The problem I am facing is that if the callback is not executed before TIMEOUT expires then I cannot cancel any pending transactions. This is why use OS_EVENT_FOREVER.
But the callback is NOT ALWAYS executed. Will the callback execute during the following error? Say that the SCLK line is held low by the slave device BEFORE the asynchronous write or read started . Will the callback still be executed with an HW_I2C_ABORT_* ? And are there any other situations when the callback is not fired?
How do I prevent a blockage in the following sequence
master: ad_i2c_async_read
主:启动读请求
slave: ACKnowledges and holds SCLK line low
slave: never sends response
master: OS_EVENT_WAIT timeout expires
master: initiates another ad_i2c_async_read request
master: blocks because there's pending transactions.
Thanks for the help
Hi rajames,
So, you are saying that sometimes the operation never completes so the device stalls and waits ? What you mention is possible since if the I2C hw see's that the clock line low it wont transmit any data, and it wont return an error (since there is no error) it will just wait until the clock line gets free and transmits the data out of the buffer. So yes in that case there shouldn't be any completion of the transaction. But you can't have a slave that will hold the CLK line low all the time. If that occurs and the line is kept low it should be better handled by the slave device and not from the master, since holding the clock line low would block the communication for all the devices that are attached on that bus, and even if there is a cancel procedure in order to stop the async transaction, if the slave continues to hold the line low, all subsequent transaction will have to be aborded as well. In any case what you could try is to have something like the following snippet in order to cancel the procedure (please be aware that this is not tested and not official SDK code and i am not able to predict any side-effects that this might have to the behaviour of the I2C transactions):
static void i2c_release_uncomp_transact(i2c_device dev)
{
i2c_device_config *device = (i2c_device_config *) dev;
i2c_bus_dynamic_data *data = device->bus_data;
if (data->transaction_ix != 0)
{
data->transaction_ix = 0;
/* Just release bus and device */
ad_i2c_bus_release(dev);
ad_i2c_device_release(dev);
}
}
So, using the above you can have a timeout instead of using the OS_EVENT_FOREVER in your wait_for_event() function and as soon as the timeout ends you can invoke the above function in order to cancel the previous transaction and continue with another one.
Thanks MT_dialog