Saturday, July 6, 2024

Custom RDM6300 firmware RFID reader/writter for EM4100, T5577 ICs

So I bought an RDM6300 RFID card/tag reader and realized that it cannot write tags. Thus, I have decided to add writing capability and to include support for other RFID chips. Original firmware supports only chips that uses the EM4100 protocol but by replacing it with a custom firmware, new protocols can be added.

RDM6300 v2 uses the C8051F330 microcontroller from Silabs which is quite old and has only ~7.5kB of program memory that limits how much the functionality can be expanded. If there is interest, I might make a custom board with a more modern microcontroller and also include a PCB coil to reduce the cost of the RFID module.


RFID frequency: 125kHz
RFID mode: read/write
Supported ICs:
  • EM4100
  • T55xx (e.g. T5577, Blue Trinket tags)
Bit rates: RF/16, RF/32, RF/64
Supported encoding: Manchester
Supported Sequence Terminators (ST):
  • Default (ST bit=0)
  • ST bit=1 and X-Mode=0
  • ST bit=1 and X-Mode=1: not supported as it didn't provide reliable results
 Interface: UART, 115200, 8-bit

RDM6300 pinout and schematic 

This, I believe, is the version 2 of the RDM6300 module.

RDM6300 pinout
  • 5V and GND: DC power supply with at least 50mA current capability. The input is protected from reverse voltage by the diode D1. A 3V3 voltage regulator will use this supply to power the C8051F330 micro-controller which is a 3V3 type.
  • 3V3 and GND: the micro-controller can be powered directly using a 3.3V source but I think this is mostly for factory programming. Can be left unconnected.
  • C2CK and C2D: C2 interface used to program the micro-controller. C2CK is the clock pin and C2D is the data pin.
  • RX and TX: UART serial interface used to interact with the firmware. Commands can be sent to RX pin using a serial terminal or another micro-controller, and data is output to the TX pin.
  • Coil 1 and Coil 2: external coil. Polarity is not important.
  • LED: - blink a LED when a tag is detected. The pin will be pulled to ground to turn on the LED so the LED must have the other pin pulled to VCC through a resistor (~1k). At the moment this is not implemented in the custom firmware.
  • GND and Ush pin near the LED: not sure what these are for but you can see them in the schematic. Can be left unconnected.
RDM6300 v2 schematic
RDM6300 v2 schematic (click to enlarge)

Programming RDM6300 with a custom firmware

The firmware can be replaced using a commercial programmer from Silicon Labs or a custom made one. To make a custom C2 programmer you only need an AVR328PB with an USB to serial converter. I have made an in depth tutorial here:

The custom programming interface can also be used to interact with the RDM6300 and read data from it, by selecting the Serial mode. Works on Linux and Windows.

C2 programmer interface

Backing up the original firmware

If for some reason you want to use the module with the original firmware, you can do so by uploading the original firmware from the download section.

Flashing the micro-controller

To flash the micro-controller with the custom code use a programmer of your choice and the compiled hex file in the download section. In case you want to modify the code you will need the Simplicity Studio IDE. It's free. To compile the code you will need to sign up for a Keil license which is also free. If you don't know how to use Simplicity Studio, you can find some on this blog.

RDM-6300 API (Application Interface)

When a tag is successfully read, the module will automatically output the default frame.

Default frame format

Default frame consists of two field types, separated by ',' and terminated by a null character '\n'. The frame is repeated according to the corresponding setting (default 4).

Field type 1: integer representing the tag type

  • 1: EM4100
  • 2: T55xxCOMP - T55xx ICs that are set to be compatible with EM4100 readers
  • 3: T55xx

Field type 2: tag data that depends on the tag type

  • EM4100 and T55xxCOMP: 8-bit version/client ID, 32-bit tag number
  • T55xx: 32-bit block. The number of blocks depends on the tag configuration. Most often is 2.


03 - T55xx tag type, FFFB0000 - block 1, 00356244 - block 2 in hex format


01 - EM4100 tag type,  00 - client ID, 79178B56 - tag number in hex format


API data type


Output data

All numerical values are returned in HEX format. The reason for this is the space constraint. Since the UART is 8-bit, sending a larger value requires converting the integer to an ASCII string to represent the number and that function takes a lot more flash memory space than converting the integer to ASCII string but in hex format.

Input data

The API expects all input numbers to be an ASCII string since this is again a much more cost effective way regarding memory space.

Serial Commands

A command frame consists of a command number in an ASCII string format, followed by arguments. The command and arguments are separated by ':'. Arguments are separated by ','. End of frame is represented by the null character '\n'.

Command list

These should be copied from rdm.h to ensure they are up to date.

#define CMD_READ_TAG			"0"
#define CMD_READ_INFO			"1"
#define CMD_READ_PAGE			"2"
#define CMD_READ_BLOCK			"3"
#define CMD_READ_BLOCK_PWD		"4"
#define CMD_WRITE_BLOCK			"5"
#define CMD_WRITE_BLOCK_PWD		"6"
#define CMD_RESET			"7"
#define CMD_AOR				"8"
#define CMD_READ_CONF			"9"
#define CMD_READ_CONF_PWD		"10"
#define CMD_W_CONF_MASTER_KEY		"11"
#define CMD_W_CONF_BIT_RATE		"12"
#define CMD_W_CONF_XMODE		"13"
#define CMD_W_CONF_PSK			"15"
#define CMD_W_CONF_AOR			"16"
#define CMD_W_CONF_OTP			"17"
#define CMD_W_CONF_MAX_BLOCK		"18"
#define CMD_W_CONF_PWD			"19"
#define CMD_W_CONF_MARKER		"20"
#define CMD_W_CONF_FAST_WRITE		"21"
#define CMD_W_CONF_POR_DELAY		"23"


Read tag ID.


UART_sendInt(0); // send command 0


Read traceability data (CMD_READ_INFO)

The two 32-bit blocks are formatted and returned as follows:

  • ACL (8-bits)
  • MFC (8-bits)
  • ICR - IC revision (8-bits)
  • ICR - customer ID (8-bits) 
  • LotID (32-bits)
  • DPW - wafer number (8-bits)
  • DPW - die on wafer number (32-bits)

Example of returned data: E0,39,00,00,000D0D25,19,00005B03


UART_sendInt(1); // send command 1


Read page (CMD_READ_PAGE)


  1. page number


Returns block data within a page. Number of blocks are defined by the IC configuration register (default 2).


2:1 // send command 2 to read page 1



Direct reading a block within a page. If the password is active use the CMD_READ_BLOCK_PWD command.


  1. page number
  2. block number
  3. password (only when CMD_READ_BLOCK_PWD is used)


Returns data from the requested block.


3:0,2 // send command 3 to read block 2 from page 0 
4:0,2,1234 // send command 4 to read block 2 from page 0 using the secure password 1234


Write a block within a page. When the password is active, use the CMD_WRITE_BLOCK_PWD command.


  1. page number
  2. block number
  3. lock bit: 0 or 1. If 1, the block will be read-only.
  4. data (32-bit): what to write.
  5. lock bit again: same lock bit but sent twice to avoid user error that could lock the tag.
  6. password (only when CMD_WRITE_BLOCK_PWD is used)


5:0,1,0,5577,0 // send command 5 to write 5577 on block 1 from page 0 
6:0,1,0,5577,0,1234 // send command 5 to write 5577 on block 1 from page 0 using the most secure password 1234


Sends the reset command to the tag.


When AOR (Answer On Request) mode is active, use this command to activate the tag, by sending the given password.


  1. password


8:1234 // send command 8 and the 1234 password to activate the tag

Read configuration register (CMD_READ_CONF, CMD_READ_CONF_PWD)

Register data is formatted and returned in the following format. Each field is maximum 8 bits and separated by ','

  • Master key
  • Data bit rate
  • Extended bit
  • Modulation
  • PSK-CF
  • AOR
  • OTP
  • Max block
  • PWD
  • ST (Sequence Terminator)
  • Fast write bit
  • Inverse data bit
  • POR delay

Note: due to limited space, the function is commented out. A workaround is to read the block 0 directly then use the code inside the rdm_t55xx_parseConfig function to parse the 32-bit value configuration register.

Read tag description (CMD_READ_DESCRIPTION)

Returns more info about the tag. Might be expanded in the future.


Returns human readable info.

  • "RF/xx": Data bit rate, such as RF/16, RF/32, RF/64. This value is calculated based on the pulse duration an it can be off by 1 or 2. For example instead of 64 might be 65 or 63. This is useful when the configuration register cannot be read initially when the password is active, since the password in not known by the module.
  • "ST:n": ST (Sequence Terminator) bit where n can be 0 or 1.

Write configuration register

The configuration register can be written using the block write command, however, unless you have some pre-calculated values this method leaves room for user error. Using this function, each setting can be modified individually by first reading the register, modifying the desired field value and writing the modified register back to the tag.

Available commands:


There are no equivalent commands for when the password is active. If the password is active, set the password argument with a value other than 0.

Note that when setting the Bit Rate, the configuration data value argument must be according to the register shown in the datasheet and not the actual bit rate. For example, for RF/32 the value would be 2 and not 32, for RF/64 the value is 5 not 64, etc.


  1. lock bit
  2. configuration data: maximum 8 bits
  3. password: if the password is not active, set this argument to 0
  4. lock bit again


19:0,1,0,0 // send command 19 to set the PWD (password) bit to 1. Lock bit and password are 0.

12:0,2,0,0 // send command 12 to set the bit rate 32. Lock bit and password are 0.


Changelog and license can be found at the beginning of the header files

RDM6300 code Folder including:
- Original firmware (HEX)
- Custom compiled firmware (HEX)
- Source code
v1.0 06-07-2024:
- public release

No comments:

Post a Comment