【Jihai APM32F407 Tiny Board】RFID reader and writer IC card (RC522)
[Copy link]
I am studying IC card operation recently, and I just use APM32 development board to do a complete read and write verification.
I just started to contact related products, mainly studying M1 IC cards. This test is based on RC522 for learning test, and the card in hand is NXP S50 card.
The RC522 chip supports three types of communications: UART, IIC, and SPI. The module in hand is an SPI interface. Compared with IIC and UART, the SPI operation speed should be the fastest.
The board connection is shown in the figure below:
The RC522 module is connected to SPI1, and the pin configuration is as follows:
// SPI1-PB3:SCK-PB4:MISO-PB5:MOSI
{GPIOB, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_PUPD_NOPULL, GPIO_AF_SPI1, GPIO_SPEED_50MHz, 1, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5},
// SPI1 AUX
{GPIOB, GPIO_MODE_OUT, GPIO_OTYPE_PP, GPIO_PUPD_NOPULL, 0, GPIO_SPEED_25MHz, 1, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 },
port_io_pin_make(rfid_cs, PB, 6);
port_io_pin_make(rfid_rst, PB, 7);
In addition to the SPI interface, a RST pin is also required to control the reset of RC522 communication.
The structure of the M1 card is not described here. It can be regarded as an EEPROM with wireless communication and key protection.
The operations of the M1 card mainly include: card selection, key verification, card reading, and card writing.
The card reading and writing is based on blocks, each block is 16B. Each sector has 4 blocks, and the last block of the 4 blocks is the key and protection information.
There is an operation code based on LPC4xxx on GITHUB, but it embeds the fls driver library, so the underlying operations need to be replaced.
To facilitate porting, this test uses function pointers to implement all underlying operations. The underlying operations mainly include the following:
void MFRC522_SS_enable(void)
{
rfid_cs.dis();
}
void MFRC522_SS_disable(void)
{
rfid_cs.en();
}
void MFRC522_RST_enable(void)
{
rfid_rst.dis();
}
void MFRC522_RST_disable(void)
{
rfid_rst.en();
}
const struct MFRC522_HAL_T rc522_hal = {
MFRC522_SS_enable, // 片选生效
MFRC522_SS_disable, // 片选取消
MFRC522_RST_enable, // 复位生效
MFRC522_RST_disable, // 复位取消
ext_spi_rw}; // SPI读写
The application code is as follows, a serial port command input processing function and an IC scanning program:
/*******************************************************************************
* @brief: rc522 lib app
******************************************************************************/
struct MFRC522_T rfid_obj;
int last_balance = 0;
unsigned int last_user_ID;
uu08 rc522_scan_en = 0;
uu08 rc522_scan_mode = 0;
#define MIN_BALANCE 300
/*******************************************************************************
* @brief: rc522 lib start
* @param argc 参数数量
* @param argv 参数指针
* [url=home.php?mod=space&uid=784970]@return[/url] 错误代码
******************************************************************************/
int rc522_lib_init(int argc, char *argv[])
{
uu08 buff[80];
rfid_cs.dir_out_pp();
rfid_rst.dir_out_pp();
rc522_scan_mode = 0;
if(argc > 1)
{
if(argv[1][0] == 'w')
rc522_scan_mode = 1;
}
rfid_obj.hal = &rc522_hal;
setupRFID(&rfid_obj);
rc522_scan_en = 1;
dbg_puts(SYMBOL_LINE_DOT PTCR);
return 0;
}
DBG_FUNX_EXPORT(rc522_lib_init, "[r/w]");
/*******************************************************************************
* @brief: rc522 scan
* @param none
* @return none
******************************************************************************/
void MFRC522_scan(void)
{
if (rc522_scan_en)
{
// Look for new cards in RFID2
if (PICC_IsNewCardPresent(&rfid_obj))
{
// Select one of the cards
if (PICC_ReadCardSerial(&rfid_obj))
{
// int status = writeCardBalance(rfid_obj, 100000); // used to recharge the card
ic_card_opt();
}
}
}
}
obj_app_order(MFRC522_scan);
/*******************************************************************************
* @brief: rc522 opt
* @param none
* @return none
******************************************************************************/
void ic_card_opt(void)
{
// show card UID
dbg_print("\nCard uid bytes: ");
for (uint8_t i = 0; i < rfid_obj.uid.size; i++)
{
dbg_print(" %X", rfid_obj.uid.uidByte[i]);
}
dbg_print("\n\r");
// Convert the uid bytes to an integer, byte[0] is the MSB
last_user_ID =
(int)rfid_obj.uid.uidByte[3] |
(int)rfid_obj.uid.uidByte[2] << 8 |
(int)rfid_obj.uid.uidByte[1] << 16 |
(int)rfid_obj.uid.uidByte[0] << 24;
dbg_print("\nCard Read user ID: %X ", last_user_ID);
if(0 == rc522_scan_mode)
{
// Read the user balance
last_balance = readCardBalance(&rfid_obj);
if (last_balance == (-999))
{
// Error handling, the card does not have proper balance data inside
}
else
{
// Check for minimum balance
if (last_balance < MIN_BALANCE)
{
dbg_print("%08X, Insufficient balance\n", last_balance);
}
else
{
dbg_print("%08X, Balance OK\n", last_balance);
}
}
}
else
{
writeCardBalance(&rfid_obj, 0);
}
dbg_puts(SYMBOL_LINE_ADD PTCR);
}
Demonstration video:
Debug serial port starts IC card scanning program.
The rc522_lib_init w command indicates to perform a write operation after scanning the IC card, specifically to read out block 0 of the IC and write the read data into block 4.
The rc522_lib_init r command indicates to perform a read operation after scanning the IC card, specifically to read blocks 0 and 4 of the IC card respectively.
After sending rc522_lib_init w, turn on the card driver board, and take away the IC card after the write operation is prompted. Then send rc522_lib_init r command and bring the card close to the driver board again to complete the card reading operation.
rfid
The test code is hosted on the gitee platform:
|