The card information of the RFID RC522 module is transmitted to the BeagleBone board through SPI communication, and the corresponding information is transmitted to the PC through UART communication.
The code at the time was written like this: And as a preliminary operation, we created a device tree through SS, SCK, MISO, MOSI pins that can > export echo{GPIO pin number}, and the URL below.
#define SPI_DEVICE "/dev/spidev9.0" // SPI device path (X: bus number, Y: device number)
#define UART_DEVICE "/dev/ttyS0" // UART device path
#define SS_PIN 328 // SPI SS(Chip Select) GPIO pin number
#define MOSI_PIN 339
#define MISO_PIN 340
#define SCK_PIN 338
#define MFRC522_PICC_TYPE_MIFARE_MINI 0x09
#define MFRC522_PICC_TYPE_MIFARE_1K 0x04
#define MFRC522_PICC_TYPE_MIFARE_4K 0x02
int spi_fd;
int uart_fd; // add UART file descriptor
// initialize SPI communication
int SpiInit() {
spi_fd = open(SPI_DEVICE, O_RDWR);
if (spi_fd < 0) {
printf("Failed to open SPI device");
return -1;
}
// set SPI mode
uint8_t mode = SPI_MODE_0;
if (ioctl(spi_fd, SPI_IOC_WR_MODE, &mode) == -1) {
printf("Failed to set SPI mode");
return -1;
}
// set the maximum baud rate (1MHz)
uint32_t speed = 1000000;
if (ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
printf("Failed to set SPI speed");
return -1;
}
}
// send and receive SPI data
int SpiTransfer(uint8_t* tx_data, uint8_t* rx_data, int len) {
struct spi_ioc_transfer spi_transfer = {
.tx_buf = (unsigned long)tx_data, // Specifies the address of the buffer where the data to be sent is stored
.rx_buf = (unsigned long)rx_data, // Specify buffer address to store received data
.len = len, // Specify the length of data to send and receive
.delay_usecs = 0,
.speed_hz = 1000000,
.bits_per_word = 8,
};
if (ioctl(spi_fd, SPI_IOC_MESSAGE(1), &spi_transfer) < 0) {
printf("SPI transfer error\n");
return -1;
}
return 0;
}
// Initialize MFRC522
void MFRC522Init() {
uint8_t tx_data[] = {0x0F}; // Data value for sending softreset command to MFRC522
uint8_t rx_data[sizeof(tx_data)];
if (SpiTransfer(tx_data, rx_data, sizeof(tx_data)) < 0) {
printf("Failed to send SPI message\n");
return;
}
usleep(500000); // wait a while
}
// Check if the card exists
int PiccIsNewCardPresent() {
uint8_t tx_data[] = {0x52}; // Data pattern value for transmitting the corresponding function to MFRC522, 0x52 : find all the cards antenna area
uint8_t rx_data[sizeof(tx_data)];
memset(rx_data, 0, sizeof(rx_data));
if (SpiTransfer(tx_data, rx_data, sizeof(tx_data)) < 0) { // To determine whether or not the card exists when SPI communication fails.
printf("Failed to transfer data\n");
return -1;
}
return rx_data[1];
}
// read card UID information
int PiccReadCardSerial(uint8_t* uid) {
uint8_t tx_data[] = {0x93}; // Data pattern value to transmit the corresponding function to MFRC522, 0x93 : election card
uint8_t rx_data[sizeof(tx_data)];
memset(rx_data, 0, sizeof(rx_data));
if (SpiTransfer(tx_data, rx_data, sizeof(tx_data)) < 0) {
printf("Failed to transfer data\n");
return -1;
}
memcpy(uid, &rx_data[1], 4);
return 0;
}
// get card type
uint8_t PiccGetType(uint8_t sak) { // select Acknowledge, returns a 7-bit value representing card type information
return sak & 0x7F;
}
// get card type name
const char* PiccGetTypeName(uint8_t piccType) {
switch (piccType) {
case MFRC522_PICC_TYPE_MIFARE_MINI:
return "MIFARE Mini";
case MFRC522_PICC_TYPE_MIFARE_1K:
return "MIFARE 1K";
case MFRC522_PICC_TYPE_MIFARE_4K:
return "MIFARE 4K";
default:
return "Unknown";
}
}
// Convert to hexadecimal and output
void printHex(uint8_t* data, uint8_t length) {
for (uint8_t i = 0; i < length; i++) {
printf("%02X", data[i]);
}
}
// Initialize UART
int UartInit() {
uart_fd = open(UART_DEVICE, O_RDWR | O_NOCTTY);
if (uart_fd < 0) {
printf("Failed to open UART\n");
return -1;
}
struct termios options;
tcgetattr(uart_fd, &options); // import current setting
// set baud rate (9600 bps)
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
// set data bit, parity bit, stop bit
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// set control options
// options.c_cflag &= ~CRTSCTS;
options.c_cflag |= CREAD | CLOCAL;
options.c_iflag &= ~(IXON | IXOFF | IXANY);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
tcsetattr(uart_fd, TCSANOW, &options); // apply new settings to uart_fd
return 0;
}
// send data to UART
void WriteUidUart(const char* data) {
write(uart_fd, data, strlen(data));
}
void delay(int seconds) {
struct timespec req, rem;
req.tv_sec = seconds;
req.tv_nsec = 0;
while (nanosleep(&req, &rem) == -1) {
req = rem;
}
}
int main() {
// initialize SPI communication
if (SpiInit() != 0) {
return -1;
}
// set SS pin
int ss_gpio_fd; // fd: A file descriptor, an abstract value used to access a specific file
char ss_gpio_path[64];
// set SS direction
snprintf(ss_gpio_path, sizeof(ss_gpio_path), "/sys/class/gpio/gpio%d/direction", SS_PIN);
ss_gpio_fd = open(ss_gpio_path, O_WRONLY); // O_WRONLY : Open file write-only flag
if (ss_gpio_fd < 0) {
printf("Failed to open SS direction file\n");
return -1;
}
// set SS pin as output
write(ss_gpio_fd, "out", 3); // or "in"
// To write a string called out to the file descriptor, write the data length of 3 to the file.
// MOSI pin settings
int mosi_gpio_fd;
char mosi_gpio_path[64];
// set MOSI direction
snprintf(mosi_gpio_path, sizeof(mosi_gpio_path), "/sys/class/gpio/gpio%d/direction", MOSI_PIN);
mosi_gpio_fd = open(mosi_gpio_path, O_WRONLY);
if (mosi_gpio_fd < 0) {
printf("Failed to open MOSI direction file\n");
return -1;
}
// set the MOSI pin as an output
write(mosi_gpio_fd, "out", 3);
// write value to MOSI pin
snprintf(mosi_gpio_path, sizeof(mosi_gpio_path), "/sys/class/gpio/gpio%d/value", MOSI_PIN);
mosi_gpio_fd = open(mosi_gpio_path, O_WRONLY);
if (mosi_gpio_fd < 0) {
printf("Failed to open MOSI value file\n");
return -1;
}
write(mosi_gpio_fd, "1", 1);
// close MOSI pin
close(mosi_gpio_fd);
// set MISO pin
int miso_gpio_fd;
char miso_gpio_path[64];
// set MISO direction
snprintf(miso_gpio_path, sizeof(miso_gpio_path), "/sys/class/gpio/gpio%d/direction", MISO_PIN);
miso_gpio_fd = open(miso_gpio_path, O_WRONLY);
if (miso_gpio_fd < 0) {
printf("Failed to open SCK direction file\n");
return -1;
}
// set MISO pin as input
write(miso_gpio_fd, "in", 2);
// write value to MISO pin
snprintf(miso_gpio_path, sizeof(miso_gpio_path), "/sys/class/gpio/gpio%d/value", MISO_PIN);
miso_gpio_fd = open(miso_gpio_path, O_WRONLY);
if (miso_gpio_fd < 0) {
printf("Failed to open MISO value file\n");
return -1;
}
write(miso_gpio_fd, "1", 1);
// close MISO pin
close(miso_gpio_fd);
// set SCK pin
int sck_gpio_fd;
char sck_gpio_path[64];
// set SCK direction
snprintf(sck_gpio_path, sizeof(sck_gpio_path), "/sys/class/gpio/gpio%d/direction", SCK_PIN);
sck_gpio_fd = open(sck_gpio_path, O_WRONLY);
if (sck_gpio_fd < 0) {
printf("Failed to open SCK direction file\n");
return -1;
}
// set SCK pin as output
write(sck_gpio_fd, "out", 3);
// write value to SCK pin
snprintf(sck_gpio_path, sizeof(sck_gpio_path), "/sys/class/gpio/gpio%d/value", SCK_PIN);
sck_gpio_fd = open(sck_gpio_path, O_WRONLY);
if (sck_gpio_fd < 0) {
printf("Failed to open SCK value file\n");
return -1;
}
write(sck_gpio_fd, "1", 1);
// close SCK pin
close(sck_gpio_fd);
// Initialize MFRC522
MFRC522Init();
// Initialize UART communication
if (UartInit() != 0) {
return -1;
}
uint8_t nuidPICC[4] = {0}; // Save the previous card UID
while (1) {
// If the card is recognized, move on to the next step, otherwise do not run any further
if (!PiccIsNewCardPresent())
continue;
// If the ID has been read, move on to the next one, otherwise don't run any more
if (!PiccReadCardSerial(nuidPICC))
continue;
// write value to SS pin
snprintf(ss_gpio_path, sizeof(ss_gpio_path), "/sys/class/gpio/gpio%d/value", SS_PIN);
ss_gpio_fd = open(ss_gpio_path, O_WRONLY);
if (ss_gpio_fd < 0) {
printf("Failed to open SS value file\n");
return -1;
}
write(ss_gpio_fd, "1", 1); // high
printf("PICC type: ");
// read the card type
uint8_t piccType = PiccGetType(nuidPICC[0]);
// output to monitor
printf("%s\n", PiccGetTypeName(piccType));
// check if it is a MIFARE method and return otherwise
if (piccType != MFRC522_PICC_TYPE_MIFARE_MINI &&
piccType != MFRC522_PICC_TYPE_MIFARE_1K &&
piccType != MFRC522_PICC_TYPE_MIFARE_4K) {
printf("Your tag is not of type MIFARE Classic.\n");
continue;
}
// If it is different from the RF card recognized just before. That is, to prevent duplicate card detection.
if (nuidPICC[0] != nuidPICC[0] ||
nuidPICC[1] != nuidPICC[1] ||
nuidPICC[2] != nuidPICC[2] ||
nuidPICC[3] != nuidPICC[3]) {
printf("A new card has been detected.\n");
// I saved the ID
memcpy(nuidPICC, nuidPICC, sizeof(nuidPICC));
// monitor output
printf("The NUID tag is:\n");
printf("In hex: ");
// Convert to hexadecimal and output
printHex(nuidPICC, sizeof(nuidPICC));
printf("\n");
// Send card information to PC via UART
char uartData[9];
snprintf(uartData, sizeof(uartData), "%02X%02X%02X%02X\n", nuidPICC[0], nuidPICC[1], nuidPICC[2], nuidPICC[3]);
WriteUidUart(uartData);
}
// Write value to SS pin (set to 0)
write(ss_gpio_fd, "0", 1); // low
// exit PICC
// usleep(3000000);
delay(1);
// if (piccType > 0) {
// break;
// }
}
close(spi_fd);
close(uart_fd);
// close SS pin
close(ss_gpio_fd);
return 0;
}