I'm currently working on a small project with a NXP PN532 NFC RFID Module V3 Kits Reader Writer.
My question is: What address and further function parameters do I need to set to read from BLE113-Port 15 (SDA) using the following method? By the way my NFC tag contains a UUID like this one:
dim nfcdatalen dim nfcUuid(37) dim nfcresult call hardware_i2c_read($38,0, 36)(nfcresult,nfcdatalen,nfcUuid(0))
I'm guessing my current method call is quite wrong, because I don't now the address value for Port 15 using a BLE113. SCL is running on Port 14.
Thanks in advance.
I will try to take a look at your code later today, but a new notes:
1) If you are debugging a problem with I2C, it would be better to remove everything else that is not absolutely needed from your code. This will help you make sure that some other piece of code is not causing trouble and it is also much easier for someone else who is going to work with your code.
2) Try to keep your comments and code consistent, even if it is an intermediate version of a hobby project:
#0x48 is default I2C slave address for NXP board -> so 0x48 << 1 would be 0x90 call hardware_i2c_read($24,1,37)(nfcresult,nfcdatalen,nfcUuid(0:nfcdatalen))
I have seen many times users not updating their comments when they edit the code. This makes it harder for anyone else to follow what the code is supposed to do. (In this case I know why the above line is changed as it is but this is just a general remark)
And number 3): if it is a longer piece of code than about 10 lines you are posting, it would be better to attach the source file as attachment and not copy the code (this is at least my personal preference)
Ok, I'll try to keep your tipps in mind.
I've separated my NFC configuration in a new, smaller, own project which you can find attached to this reply.
Thanks for looking into my code :-)
What are you actually trying to achieve with this I2C command? It is called repeatedly in your script:
call hardware_i2c_read($38,0, 36)(nfcresult,nfcdatalen,nfcUuid(0))
I browsed quickly trough the datasheet of the NFC reader and it seems to me that you have to write some commands to the reader to get data out of it. Now you are just trying to read something out from the device.
For example, see chapter 7.2.2 in the datasheet: "GetFirmwareVersion"
I understood this so that if you want to read the firmware version of the unit, you will first write "0xD4 0x02" to the reader. It will then respond with a 6-byte packet that includes firmware version.
To test this, I would write the code something like this: (NOTE this is not necessarily correct, just to give an idea how to interface with the reader)
dim i2cdata(16) dim i2clen # command D4 02 = GetFirmwareVersion i2cdata(0:1) = $d4 i2cdata(1:1) = $02 # send command to reader: call hardware_i2c_write($24, 1, 2, i2cdata(0:2)) # read response from reader: call hardware_i2c_read($24, 1, 6)(result, i2clen, i2cdata(0:i2clen))
I don't think the reader you are using will do anything useful if you just try to read data from it via I2C. You must probably configure the reader using I2C writes to work in the mode that is suitable for your needs.
Do you understand how the reader is supposed to work? It may be that the I2C interface itself is just fine but you are not sending the right commands to your NFC reader.
The datasheet looks quite long and complex, try looking for some online resources on how to use this reader. For example this link looks promising:
There seems to be some Python code that knows how to talk to the PN532. You can study that code and try to adapt it to BGScript.
Ok, I tried some configurations to achieve your suggested GetFirmwareVersion approach.
Unfortunately the reader does not respond the 6-byte package which includes the firmware version. It just responds nothing.
Here is what I'm doing at the moment:
i2cmode(0:1) = $d4 i2cmode(1:1) = $14 i2cmode(2:1) = $01 i2cdata(0:1) = $d4 i2cdata(1:1) = $02 call hardware_i2c_write($24, 1, 3, i2cmode(0:3))(i2cWritten) call hardware_i2c_write($24, 1, 2, i2cdata(0:2))(i2cWritten) call hardware_i2c_read($24, 1, 6)(i2cresult, i2clen, i2cdata(0:i2clen)) call attributes_write(testvalue,0,i2clen,i2cdata(0:i2clen))
As you can see I even tried to set the SAM-mode of the NFC reader which disables security authentication, so you won't need a handshake in the first place (note: it is set to "normal" mode as it's called by default, I just thought it would be a good idea to set it anyway).
Furthermore I tried to understand the command structure of the datasheets chapter 7:
00 00 FF LEN LCS D4 CC Optional Input Data DCS 00
Which parts are already covert by the read/write i2c methods of BGScript?
As far as I understand your example from your last post, I only need to send the CC part, which would be 0x02 in the "GetFirmwareVersion" case. By the way the written response object of the hardware_i2c_write method returns '0'.
I'm getting the impression, that I cannot reach the reader at all. Maybe I'd have to use a different address than 0x24?
I tried something in the meantime. I also have an Arduino Uno for testing my NFC-reader.
An guess what the PN532 library from this source (Arduino-PN532 example) works and I can read in my tag. The only problem is how to port this to BG-script.
When I look into the library itself it establishes a command process by constructing the previously mentioned command like:
i2cdata(0:1) = $00 # 00 -> 2-byte i2cdata(1:1) = $00 # 00 -> 2-byte i2cdata(2:1) = $ff # FF -> 2-byte i2cdata(3:1) = $05 # LEN -> 1-byte i2cdata(4:1) = $fc # LCS -> 1-byte checksum of 0x05 is (0xfb + 1) = 0xfc i2cdata(5:1) = $d4 # D4 -> 2-byte i2cdata(6:1) = $02 # CC -> 2-byte i2cdata(7:1) = $fc # DCS -> 1-byte i2cdata(8:1) = $00 # 00 -> 2-byte
The only part which I'm not quite sure of is the LCS part. The arduino example uses ~length+1 = LCS. Which would be 0xfc if I'm not mistaken, right?
I've also attached you the source of the cpp file managing the read/write commands with the reader.
I hope someone can help me with further ideas
Looks to me that you are moving to the right direction. The i2c write function in BLE113 does not handle any data bytes automatically, you have to construct the command frame byte by byte yourself and it seems that you are on the right track.
I guess the question is now more about understanding how the NXP reader works and not so much about BLE113 or our i2c routines. I doubt that you will get too much help in this forum on this.
I assume that the NXP reader can also be used trough UART interface? If I was debugging this myself I would try to hook up the reader to my PC and get it working with some simple C, Python or whatever program that can talk to the reader via UART. This is much easier to debug than debugging a BGScript application. If you can get the reader working this way then you will know exactly what commands are needed to do that and you can then try to convert the code to BGScript.
Good luck with your project! It may require lots of work but it will be rewarding when you get it working.
Thanks for the wishes but, here is the deal: I'm getting the impression, that there is a general problem with the reader communication using the bgscript stack. Because the method call:
returns a '0' which means no bytes were written to the reader. Instead the return value has to be 9, right?
I'm pretty sure I have the protocol right because the Arduino framework sends the exact message to the reader, when trying to read out the current firmeware version.
It would be great if you could have a second look into your bgscript stack and it's communication mechanism as I'm not quite sure whether the calculation of the address is handled correctly by your software stack.
Thanks in advance!
You are correct, there is something fundamentally wrong with the reader communication. It is not that the stack would calculate I2C address wrong, but we have not read the manual carefully enough...
I checked the API doc again and it clearly says how the I2C address is given for hardware_i2c_write:
"I2C's 8-bit slave address according to the note above. Keep read/write bit
(LSB) set to zero, as the firmware will set it automatically."
In your case, the slave address is 0x48 for write, 0x49 for read. According to the note above, you should set the first parameter of hardware_i2c_write as $48 (regardless if it is a read or write).
Sorry for the confusion, I gave some wrong advice above. Please try with this parameter and check if you can get some non-zero return value out of the hardware_i2c_write call.
Ok, but unfortunately the return value is still zero although I've set the parameter to $48 for writing.
Do I have to set the address to $49 for reading? Or does the stack handle that for me?
The documentation says explicitly that you should keep the R/W bit zero: "Keep read/write bit
(LSB) set to zero, as the firmware will set it automatically"
This means that you should use value $48 for both write and read operations.
If the I2C communication is still failing, then the next thing would be to hook up a logic analyzer to the I2C lines and see if there is any activity at all from the reader.
What do you mean by hooking up a logic analyzer to the lines of the reader?
Furthermore is the rest of my method call correct?
By googling "low cost logic analyzer" you can find logic analyzers that are attached to your PC via USB and they cost < $100. It may seem pricey if you are working on a hobby project but if you are working with anything serious then it can save you hours or days of debugging.
Sometimes when everything else fails, you simply need to hook up some measurement device to your wires and probe what is going on.
Your I2C function call seems correct to me.
To be honest with you, I'm already over my budget concerning this project as it's a larger project with additional hardware investments in the past.
Is there another way of making sure, that I'm not missing something? I did a bit of research and it turns out that sometimes the hardware needs to be told its address, but that might not be the case, right?
I just wanted to let you guys know, that I found a solution to the problem. First of all the main problem was, that I was confused about the BLE113 description in the BG-Script documentation. It says that the Pins for I2C communication were P14, respectively P15, but what I did was I connected them to P1_4, P1_5, which was wrong. Instead I had to use the dedicated ports for SDA and SCL. My mistake after all on this end of the problem, not a failure of the BLE113.
Furthermore I managed to communicate with my NXP-PN532 NFC reader. I had to read the datasheet in more detail to figure out the whole communication approach. So to read out the firmware of the NXP you have to use the following steps:
#receive firmware version of nxp pn532 call hardware_i2c_write($48, 1, 9,"\x00\x00\xFF\x02\xFE\xD4\x02\x2A\x00")(i2cWritten) # ask module for firmware version call hardware_i2c_read($48, 1, 7)(i2cresult, i2clen, ack(0:7)) # receive ack from nfc module call hardware_i2c_read($48, 1, 14)(i2cresult, i2clen, i2cfirmwareversion(0:14)) # receive data afterwards call hardware_i2c_write($48, 1, 6, "\x00\x00\xFF\x00\xFF\x00")(i2cWritten) # send ack as all data was successfully received call attributes_write(testvalue,0,5,i2cfirmwareversion(7:5)) # forward response to gatt
To communicate with the NXP you need to send your command first. After that you will receive a 7-byte ACK from the NXP, that the command was received without a problem (see 18.104.22.168 of NXP datasheet for data link level information and how to build a communication frame). Now you can read again from the module and receive the firmware as payload. The last step is to send an ACK from your site to the NXP and separate the rest of the protocol frame from the payload and send it to the GATT attribute.
Hope it helps someone with the same kind of problem using NXP modules and BG-Script powered modules.
Great to hear that you got it working! And thanks for sharing the detailed solution.