The objective of my project is to communicate to my Raspberry PI through I2C when I make use of a CoAP petition from the user. I used "frdmkw41z_wireless_examples_thread_router_eligible_device_freertos" as project base and I configured the KW41Z as I2C slave (from the driver_examples_i2c_polling_transfer) because RP is my I2C master:
When there is an I2C transfer the next callback is called (a 32 byte buffer to transfer and a 1 byte variable to receive):
To perform an I2C communication between the CoAP user KW41Z and the Raspberry-Pi I perform the next rule:
The graphic flow it should show is:
But in my case, when the user receives the ACK + DATA that works OK, the Thread program enters to the CoAP callback another time. So the RP receives another PIN interrupt and perform the same operation as before, the real graphic flow is the following in my case:
What could be the problem? It is related to the I2C interrupt callback? What is the best way to perform an I2C operation during a CoAP callback in the router_eligible_device_freertos?
I perform the I2C operation in the RP though the SMBus library.
It is a really important issue we need to fix in our company in order to solve our IoT project.
I really apreciate some help,
I am sorry to come another time to this I2C issue. In this time, we would like to receive an int data to my KW41Z from my RP instead of a byte like I posted before. I attach the code of the KW41Z slave callback where the read buffer is g_slave_buff_int and the length is I2C_DATA_LENGTH_INT:
#define I2C_DATA_LENGTH_INT 2U
The CoAP callback used is similar to that I posted here, but instead of waiting just 1 g_SlaveCompletionFlag I wait 2 because I send 2 bytes (1 int) from my RP:
I used the Timer that Alexandru posted in order to avoid the KW41Z to get stuck, but I do not understand why, in some cases I receive 2 flags and I receive the int correctly and in other cases I only receive 1 flag and the Timer takes place. In my RP I send one byte I wait 0.1 secs and I send other byte (with SMBus python library).
The I2C communication fail issue is due to my RP? Or the Slave Operation in interrupt transactional method for the KW41Z is not suggested to be used with the wireless_examples_thread_router_eligible_device_freertos?? I should use I2C Slave FreeTOS Driver instead to avoid this bad behaviour?
I have been working with this error for many months and I am still stucked....
In the red highlighted snipet of code, why do you wait for completion for the number of bytes you should receive? I see in I2C examples from the SDK that the while block where you check the completion flag is used for a complete transmission, not for every byte.
From the raspi, can you send the 2 bytes into a single transfer? Otherwise I think you will overwrite the old data (unless reinitialized). E.g. if you have slave_buff of size 2, then if you save the separately the bytes, they both will replace slave_buff.
So remove the for block in which you iterate over the size of the buffer and from raspi send the 2 bytes at the same time.
Tell me if it worked.
I followed your advices, I removed the for block and I send from raspi the 2 bytes at the same time with the function write_i2c_block_data(int addr,char cmd,long vals) of the smbus python library of the RP. I obtain the following data:
1) Is the error that reports me the Timer took place (so even if I put only a flag the coap callback gets stucked)
2) Is an incorrect value that I do not understand why I receive this
3) Is the correct value of the data I want to know
These values are almost periodically sent as I can see. Also I realized that when I periodically send Coap request to get the data the KW41Z resets after some minutes of working (I think it is due to the several interrupts performed in the I2C callback) but continues to perform the requests.
Maybe the method used here (Slave Operation in interrupt transactional method) to program an I2C slave communication do not work in FreeRTOS (wireless_examples_thread_router_eligible_device_freertos )?
I saw from Kinetis Thread Stack Application Developers's Guide.pdf a serial manager that may help to handle I2C communication in wireless_examples_thread_router_eligible_device_freertos base program, but I do not know how to use it:
I programed KW41Z to be a master I2C device to read a sensor and with Master Operation in interrupt transactional method works perfectly, the problem seems to be related to the slave operation.
Any advice to solve my setup?
I appreciate so much your help...
I think that would be better if you break the problem in smaller problems.
Take it incrementally, firstly try to see if you manage to correctly transfer data via I2C. If this works fine, then integrate it into CoAP messaging and see if it works as desired.
Even if you feel like it's a waste of time, at least you get a better understanding where the problem is.
Hello Alexandru, JC,
With the addition of if((gCoapGET_c == pSession->code) && (sessionStatus == gCoapSuccess_c) && (sessionStatus != gCoapDuplicate_c)) seems to work perfectly! Thanks!
In my CoAP callback there are cases where the Raspi do not send or receive I2C data when it is requested by the KW41Z with the interrupt pin (This is due to a bad programming in the RP program, my bad) , so the program get stucked at the while (!g_SlaveCompletionFlag) condition, then the KW41Z dont send ACK and I get the message "No response received!". From this moment I am not able to send more CoAP requests because the KW41Z seems to get stopped at the while condicion. Is there a way to exit or kill the CoAP callback when I reach the timout and I get the "No response received!" in order not to block the KW41Z for further operations? Or I need mandatory to turn down and turn on the module to make it operate again?
PD: When I turn down and turn on the module to make it operate again, at the moment to send I2C commands to the RP, the buffer seems to be moved and I do not send the right command. E.g: If the command is this "-0-0-RQST_STATUS-0-0-" the I2C command received from the RP is "TATUS-0-0--0-0-RQST_S". Any suggestions?
I really apreciate your help.
You could start a timer for a defined period of time, an estimation of what those 4 retries would take (I think 10 seconds are enough), and in the callback of that timer you could create a function that takes care of what needs to be done (probably re-transmission of pin interrupt signal).
You can look up TMR_StartTimer, you will see plenty of examples how it is being used and how it works. Do not forget to allocate it with TMR_AllocateTimer.
Please let me know if you managed to solve the problem.
Thanks for your quickle answer Alexandru,
It is not possible in the callback of the timer to call a function that kills the current CoAP callback? There is not any function that ends a CoAP session or kill the CoAP callback in order to avoid getting stucked in this CoAP callback?
I don't think it exists such a function. It isn't a clean solution, it's the fastest solution it came into my head, but you could set another flag made by you that indicates that the the I2C transfer wasn't successful, and to set that global flag you are verifying on true so that it will unblock from that while condition, and look at the other flag to know if the transfer was truly successful.
In the CoAP callback function you are using, is it possible that you missed out the case in which a duplicate message is sent. Take a look at the enum coapSessionStatus_t, you have the option gCoapDuplicate_c, which helps you dealing with such situations. By default, in the CoAP callback from SDK, duplicate and success statuses are treated the same, maybe you did the same in your function.
Let me know if this was the problem.
With the option gCoapDuplicate_c added my code appears like that:
Thanks a lot Alexandru! The result has improved notably and in the most of the cases when I request a CoAP GET the CoAP callback is only called one time and I receive the response from the RaspberryPi. However in some few cases the CoAP callback is called twice as before and in other cases the CoAP is called once but I do not receive thorugh the CoAP the data requested to theRP (and the RP is not the problem because I see it has sent the right data to KW41Z via I2C).
It is possible to solve it perfectly? Some other manner to perform it?
I'm happy to see that you are progressing with the project!
A couple of questions I have in order to clarify some things:
Also, can you add also to the condition in which you verify if sessionStatus is not duplicate, if it is not failure (gCoapFailure_c)?