This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

New RFID Reader Firmware Example

Other Parts Discussed in Thread: MSP430G2553, TRF7970A, MSP-EXP430G2, DLP-7970ABP, TRF7960A, MSP430F2370

Hello E2E Community,

We have just released a new example firmware base for a simple and low resource RFID reader example.

The firmware uses our TRF7970A NFC Transceiver and is run on an MSP430G2553 MCU.

This example supports reading ISO14443A, ISO14443B, ISO15693, and FeliCa compliant RFID tags.

You can find the new firmware at the following link:

To evaluate it, you only need an MSP-EXP430G2 LaunchPad and the DLP-7970ABP BoosterPack. You can purchase these items as a bundle on our TI eStore:

Firmware Details

This example firmware is designed to allow for quick and easy evaluation of the TRF79xx series of devices for RFID reader designs. The firmware can be loaded and modified with Code Composer Studio. After programming the MSP-EXP430G2 LaunchPad with the firmware, remove the jumper on P1.6 to enable SPI communication. This is important as the TRF7970A will not receive any commands until the jumper is removed.

If the UART is enabled and the LaunchPad is configured correctly then a UART terminal (such as DockLight, PuTTY, or Termite) can be used to receive data from the tags. Information will include the tag UID, relevant tag settings, and the tag data itself. Please see the picture at the very end of this post which illustrates how to configure the G2 LaunchPad for UART communication.

Please note that this firmware only handles very basic NDEF processing for Type 4A and Type 4B tags, and it is limited to small messages due to resource limitations of the device. If you are looking for a robust and fully featured NDEF NFC Reader/Writer solution, please check out our NFC Reader/Writer App Note and Reference Design

Additionally, this RFID Reader example will not handle reading tags with special or proprietary protocols such as MIFARE Classic.

The firmware has been designed in a way that makes it easily configurable, so you can turn off the polling for specific technologies by going to the nfc.h file and commenting out the #define for unwanted technologies.

If UART communication is not desired, it can also be disabled by going to uart.h and commenting out the #define ENABLE_HOST line there. This would also speed up the rate at which tags are read as the UART communication currently takes up a bit of time to output data.

MSP-EXP430G2 Hardware Configuration

As mentioned above, to enable SPI Communication for the TRF7970A, the Jumper on P1.6 must be removed as seen on the yellow box in the below picture. No tags can be read until this jumper is removed!

To use UART on the MSP-EXP430G2 LaunchPad, the TXD and RXD jumpers have to be switched to a horizontal position on the G2 LaunchPad board as seen in the light blue box on the below picture. This will allow for terminal programs such as DockLight, PuTTY, and Termite to be used in order to receive the outputted UART data.

UPDATE 3/27/2017

This firmware base has received another update which provides support for the TRF7960A as well.

Other updates included in this release are:

  • Reworked TX and RX timeout handling
  • Adjustments to startup sequence and error recovery sequences to ensure correct flow of commands are being sent
  • Increased delay for ISO15693 Write Blocks when using Option flag to match datasheet specifications for TI Tag-It HF-I transponders
  • Removed heartbeat LED which was disrupting debug capabilities (as reported below)
  • Streamlined certain TRF79xx driver API's and removed unnecessary API's
  • Added VLO Calibration to handle VLO drift over time which could disrupt NFC timing over long enough periods
  • Added recursion counter for ISO15693 Anticollision to prevent stack overflow issues

TRF7960A Support

This functionality is now available as all TRF7960A projects are over 5+ years in age. Internal usage and testing with the TRF7960A has been handled using a modified version of this code base. Therefore it made sense to provide all users of the TRF7960A the option to move towards this latest firmware.

However, from a hardware standpoint, there is no purchasable tool which will allow for a very quick out-of-box experience. There are ways to modify either hardware or software to leverage this with TI EVM's which will be discussed below.

This release is primarily about offering an updated firmware base that will work for the TRF7960A that will serve as a superior starting point for any project development compared to what currently exists on the web.

In order to switch the firmware over to support the TRF7960A, the #define for the TRF79xxA_VERSION needs to be changed from "70" to "60". This change can be made within the trf79xxa.h file on line 66.

Changing the #define will automatically handle the following:

  • Changing FIFO size to reflect the TRF7960A FIFO size
  • Handling of all SPI related requirements (dummy clocks, polarity change etc) for the TRF7960A
  • Configuring the correct registers with proper initial values and removing reads/writes to registers which only exist for the TRF7970A
  • Handling for reception of data and timeouts based on testing with both 60A and 70A devices

In order to evaluate a TRF7960A device on TI EVM hardware with this example firmware, the following options are possible at this time:

  1. Chip swap the TRF7960A onto a TRF7970A BoosterPack (Requires soldering station with a heat gun due to ground pad and QFN package)
    1. Get the TRF7970A BoosterPack (discussed above)
    2. Get a TRF7960A sample from TI eStore
    3. Remove the tin cover for DLP Design to access the TRF7970A IC. The cover is soldered on the top left and bottom right corners. It is possible to lift one corner at a time to remove the cover.
    4. Remove the TRF7970A using a heat gun to evenly heat up the solder for the ground pad of the QFN package.
    5. Solder the TRF7960A chip to the LaunchPad in the correct orientation. Guides for how to solder QFN packages can be found online if required.

  2. Purchase the TRF7960AEVM and port the Reader software example to the MSP430F2370. Considerations to keep in mind when porting are:
    1. Change the MCU file functions to configure the F2370 Clock, Timers, and ISR's
    2. Change the SPI and UART files to use the F2370's peripheral modules
    3. Change the device pinout to match the TRF7960AEVM pinout
    4. Add in firmware to enable pull down resistors for MOD, ASK/OOK, and EN2 
  • Ralph,

    Thanks for sharing this!  It is a great example for a small MCU and basic RFID functions.

  • That is amazing, thanks for sharing! :)
  • Ralph thank you for the release. Have noticed that with the McuHeartBeat() enabled, long running interactions between the Launchpad/Boosterpack and an NXP NTAG I2C Plus will eventually hang.

    It's a power harvesting setup running a continual two way communication between the RF430G2 and an LPC11U24 via the TRF7970A and NXP NT3H2211.

    Unfortunately, so long as the heartbeat is enabled, the only debugging information available is:


    ;-- default ISR handler if user does not supply
    ;-- simply puts device into lpm0

    .sect ".text:_isr:__TI_ISR_TRAP"
    .align 2
    .global __TI_ISR_TRAP
    BIS.W #(0x0010),SR

    Is the heart beat interfering with the interrupt processing for regular communications?

    The behavior I see right now would almost imply that the last packet was sent to the NTH2211 but the request to read the next packet to be received from the NTH2211 'froze' up. The heartbeat light also ceases to flash prior to pausing the debugger and either stays fully illuminated or goes out.

    The timing before the freeze is not consistent, which implies a race condition. Without the heartbeat, the issue does not manifest.

  • Hi Karl,

    The heartbeat should not affect regular communications at all, and I haven't observed issues with having the heartbeat on across long term communications (I've left my setup running overnight at times and had no issues).

    However, it definitely does have a tendency to get in the way of debugging in CCS as you have seen. I disable it when I do any debugging with the firmware as any time after a breakpoints hit and the code is paused, when the resumption occurs the trap ISR will fire so a soft reset of the firmware is needed each time a breakpoint is used or the code is paused. Also makes sequential breakpoints not possible.

    Perhaps I should include a comment above the heartbeat line in main.c to mention this - I will see about doing so when making any updates.
  • Thanks. Is there actually a way to find where the things may be held up via CCS while the heartbeat is enabled? I have the non-heartbeat version of this running now for about 6 hours without issue.

    If it helps add any context, this interaction between the two devices is constantly transmitting and receiving 64 bytes of data in a single command (FAST_READ/FAST_WRITE) to/from the NXP tag. 


  • Hi karl,

    Honestly I haven't tried to figure that out. One thing to maybe check is to see if you can change the priority of the interrupt when it fires and have the heartbeat lower than the IRQ interrupt? As I mentioned, I never observed any issues, so I didn't do anything about looking into the priorities yet.
  • Thanks. Taking a few minutes just now to look at it, the trap is due to no handler for TIMER1_A1_VECTOR. The code I'm using doesn't make any additional use of timers beyond what is already in the sample. 


  • All,

    Firmware update has been released. The changes and new features are highlighted in the original E2E post under Update 3/27/2017.
  • Hi all,

    I am using the TRF7960AEVM evaluation board. My aim is to run the evaluation software on the same processor MSP430, but on my own PCB.

    What I noticed on the frame communication between the PC and this board is that it is in ASCII format (for example a 0x10 takes two characters instead of one '1' and '0') and there is no CRC included to assure the communication is correct.

    Does the software that you describe above have the same limitations, or is there a version including a CRC and supporting a binary frame?

    Thanks and regards,

  • Hello John,

    This example doesn't have a communication process setup for controlling it on the PC side. It just has a UART terminal connection which dumps data. There is no CRC check on that and there is no way to send commands back over UART with the implementation. In that regard, it is even more limited actually.
  • Hi,
    the line that splits the length of the message to the two bytes seems strange.
    The max size you can have on the length is 12 bit and the lower 0-3 bits should go to one byte and the upper bits 4-11 should go to the other length byte.
    Shouldn't the first 16 bit be shifted right by 4 instead of 8?
    g_pui8TrfBuffer[ui8Offset++] = (uint8_t) (ui16TransmitByteLength >> 4); // Upper and middle nibbles of transmit byte length
    g_pui8TrfBuffer[ui8Offset++] = (uint8_t) (ui16TransmitByteLength << 4); // Lower and broken nibbles of transmit byte length

    Original code below:
    // Format Anti-collision command packet
    g_pui8TrfBuffer[ui8Offset++] = 0x8F; // Reset FIFO
    g_pui8TrfBuffer[ui8Offset++] = 0x91; // Send with CRC
    g_pui8TrfBuffer[ui8Offset++] = 0x3D; // Write Continuous
    g_pui8TrfBuffer[ui8Offset++] = (uint8_t) (ui16TransmitByteLength >> 8); // Upper and middle nibbles of transmit byte length
    g_pui8TrfBuffer[ui8Offset++] = (uint8_t) (ui16TransmitByteLength << 4); // Lower and broken nibbles of transmit byte length
    g_pui8TrfBuffer[ui8Offset++] = ui8ReqFlags; // ISO15693 Request Flags
    g_pui8TrfBuffer[ui8Offset++] = 0x01; // Inventory Request Command Code
    calculates the length of

  • Hello Hakan,

    Thanks for the inquiry, I reviewed the segment and you are entirely right. Actually we can take this to another step and get rid of the uint16_t and instead use a uint8_t to save a byte of space, because the anticollision command wouldn't exceed 20 bytes being sent, meaning we won't exceed hex 0x100 and thus do not need a uint16_t to store it.

    Thanks for point this out, I will include this update on the next release. The reason the firmware passed my tests without the issue arising is there hasn't been a case where the collision goes beyond 11 bytes deep into the 16 byte UID based on the tags I have available to test.

  • helo ,

    I am not able to access the link: . Can you please release this link as soon as possible.
  • Hello Anil,

    I tried the link just now and it worked fine. Please try again.

  • Helo ralph,

    thanks for this code.
    I need the code is for writing into the MIFARE/RFID card. Can you please share the code.

    Anil D.
  • Hello Anil,

    Mifare Ultralight? Mifare DESFire? Mifare Classic? What you need will depend on the specific tags.
  • Hello Ralph,

    MIFARE Classic EV1 1K / MIFARE Classic EV1 4K this is my mifare card. so please tell me about this. But i dont know the card is 1K or 4K. so i am searching for this one also.

    Anil D.

  • Hello Anil,

    The firmware in this post does not support MIFARE Classic.

    You need to use the hardware/firmware described here:

  • Dear Ralph,

    The function 'ISO14443A_sendRATS(void)' in the iso14443a.c file returns STATUS_FAIL after calling it from the detection procedure in nfc_app.c. 

    I think there is an error in this code snippet from the function. The response from the TRF7970A is stored in the buffer starting at index 0. But when getting the supported bit rate, 'ui8Offset++' is used as index. As far as I can see the index should be 2, but this way the index is 7.

    	// If data received
    	if(g_sTrfStatus == RX_COMPLETE)
    		ui8RxLength = TRF79xxA_getRxBytesReceived();
    		if (g_pui8TrfBuffer[0] == ui8RxLength)
    			ui8Status = STATUS_SUCCESS;
    			if ((ui8RxLength > 1) && (g_pui8TrfBuffer[1] & 0x10))
    				g_ui8AtsSupportedBitrates = g_pui8TrfBuffer[ui8Offset++];
    			ui8Status = STATUS_FAIL;

    Could you please let me know what the correct use of this function is?

    Thanks in advance.

    Kind regards,


  • Hello Koos,

    This is a good catch. Originally the code reset the ui8Offset position and then incremented it for each check which was a bit foolish, but it looks like I was also foolish in not catching the ui8Offset used to store into g_ui8AtsSupportedBitrates. The correct line is:

    g_ui8AtsSupportedBitrates = g_pui8TrfBuffer[2];

    I will document this change for future releases.

    Now - all that said... that doesn't explain the STATUS_FAIL issue. The STATUS_FAIL should only occur if you don't receive the ATS correctly.

    Are you using an NFC Type 4A Tag or an NFC Type 2 tag? What's the SAK response for the tag?

    Also by using breakpoints can you tell me how many bytes are received and what the g_pui8TrfBuffer contents are corresponding to that number of bytes received?

  • Dear Ralph, 

    I expected that it got mixed up that way. Thanks for confirming!

    Sorry, I meant to say that the 'ISO14443A_sendPPS(void)' returns an error, but that it was caused by that snippet from the RATS command.

    The code didn't return on this snippet before:

    	// Check if PPS is supported based on last received ATS reply
    	if ((g_ui8AtsSupportedBitrates == 0x00) || (g_ui8AtsSupportedBitrates == 0x80))
    		return ui8Status = STATUS_SUCCESS;

    So it started sending the PPS command. That causes a timeout and returns NO_RESPONSE_RECEIVED. That's why the PPS function returned STATUS_FAIL.

    I guess that makes sense, since it should have returned from the function at the very start.

    Thanks again!

    Kind regard,