Hardware Platform:
1 master: SMDK Exynos4412 POP S5M8767A
2 RFID module: RC522 module provided by jundun Group
3. Communication Interface: SPI
Software Platform: Android ICS & kernel version 3.0.15
1. enable the master SPI
1 hardware enabling:
From the SMDK schematic, we can see that SPI0 is shared with I2C. SPI1 has been connected to other devices, and SPI2 is not used. Therefore, SPI2 is used here.
2 software enabling:
The SPI interface has been configured on the SMDK Exynos4412 master. You only need to enable macro config_jx64xx_dev_spi for use.
Open Method: make menuconfig à Device Drivers à SPI support à Samsung s364xx series type SPI.
After compilation, zImage is generated and burned into the Development Board.
Ii. Test the SPI on the master side
The master SPI has been enabled. Next, you can use a general SPI driver to test whether the master SPI hardware works properly.
Compile the program as a module: drivers/spi/spidev. c to generate spidev. ko, which is a common device-side SPI driver.
Compile the test program: Documentation/spi/spidev_test.c. First, modify the device "/dev/spidev2.0" for line 1: static const char * device = "/dev/spidev1.1 ", then compile the program as an application to generate the spidev_test, which is the test program corresponding to the SPI.
Grant root and system read/write permissions through the serial port:
Shell @ android:/$ su root
Shell @ android: // # mount-o remount-rw/system
[391.423930] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)
Shell @ android :/#
Push spidev. ko and spidev_test to the Development Board through adb:
Load DRIVER:
Shell @ android:/system # insmod spidev. ko
Short-circuited MISO and MOSI, that is, self-collect, and then run the test program:
As shown in, it indicates that data can be sent and received through SPI. If all data is displayed as 0, it means that SPI is not working properly. Next we can debug our RC522 module with confidence.
3. RC522 Device Driver debugging
The above experiment has proved that the SPI of the master can work normally, and then you can debug RC522. -Assume that your rfid_rc522 driver has been written, and now you only need to debug it-if the driver is not written, read another Blog.
1 open the Development Board related files: arch/arm/mach-exynos/mach-smdk4x12.c
Because spi2 is used, modify modalias = "rfid_rc522" in board_info to match spi_drviver.name in the driver. Otherwise, the probe function fails.
- 988 static struct spi_board_info spi2_board_info [] _ initdata = {
- 989 {
- 990. modalias = "rfid_rc522 ",
- 991. platform_data = NULL,
- 992. max_speed_hz = 10*1000*1000,
- 993. bus_num = 2,
- 994. chip_select = 0,
- 995. mode = SPI_MODE_0,
- 996. controller_data = & spi2_csi [0],
- 997}
- 998 };
2. recompile the kernel and install it on the Development Board.
3. Compile the rc522 driver and copy the generated rfid_rc522.ko to the/system directory of the Development Board system through adb usb. Then, insmod rfid_rc522.ko, in this way, the driver is loaded into the kernel system in the form of modules. After the file is loaded successfully, the directory rfid_rc522_dev is displayed in the/dev directory.
4. Applications
The write function in the driver is:
Rc522_write (struct file * filp, const char * buf, size_t count, loff_t * f_pos );
The user space application write function is:
Write (rc522_fd, bufpw1, sizeof (bufpw1 ));
How do they connect?
In fact, the write function in the application is implemented by calling the core function sys_write (unsigned int fd, const char * buf, size_t count) in the operating system, while sys_write () the function encapsulates rc522_write () in the driver.
// Start from Forum
The driver of the character device is described as follows:
1. insmod driver. The device name and master device number applied by the driver can be obtained in/proc/devieces.
2. Obtain the master device number from/proc/devices and run the mknod command to create a device node file. This is to associate the device node file with the device driver by the master device number. The file attribute in the device node file specifies the function pointer implemented by the fops method in the driver.
3. the user program uses open to open the device node file. When the operating system kernel knows that the driver is working, it calls the open function in the fops Method for relevant work. The open method generally returns a File Identifier. In fact, it does not directly operate on it, but the system calls of the operating system work behind the scenes.
4. When you use the write function to operate the device file, the operating system calls the sys_write function. This function first obtains the inode pointer and flip pointer corresponding to the device node file through the file identifier. The inode pointer contains the device number, which tells the operating system which device driver should be used, the flip pointer contains the fops information, and the corresponding fops method function of the operating system can be found there.
5. Then, sys_write will call the write method in the driver to write the device.
Among them, 1-3 is performed in the user space, and 4-5 is performed in the kernel space. The user's write function is associated with the OS's write function by calling sys_write.
Note:
For Block devices, the writing mode still exists. This should be solved by the gnu c library. I will not discuss it here because I have not read the source code of the GNU C library.
// End of the Forum
The application source code is as follows:
- # Include <stdio. h>
- # Include <string. h>
- # Include <stdlib. h>
- # Include <sys/types. h>
- # Include <unistd. h>
- # Include <errno. h>
- # Include <arpa/inet. h>
- # Include <sys/time. h>
- # Include <sys/types. h>
- # Include <sys/stat. h>
- # Include <fcntl. h>
- # Include <sys/ioctl. h>
- # Include <math. h>
- Static enum IO_CMD {
- READ_CARD = 0,
- CHANGE_PASSWD = 1,
- CHANGE_BLOCK = 3,
- SET_RW_TIME = 4,
- WRITE_CARD = 5,
- };
- Int main (int argc, char ** argv)
- {
- Int rc522_fd;
- Int I, read_num;
- Char r [256];
- Printf ("test: rc522 % s \ n", _ DATE __, _ TIME __);
- Printf ("test: before open rc522_fd \ n ");
- Rc522_fd = open ("/dev/rfid_rc522_dev", O_RDWR );
- Printf ("test: rc522_fd = % d \ n", rc522_fd );
- If (rc522_fd =-1)
- {
- Printf ("test: Error Opening rc522 \ n ");
- Return (-1 );
- }
- Printf ("test: wait 01 \ n ");
- Sleep (1); // wait
- Printf ("test: wait 02 \ n ");
- /******* Never to open ********/
- # If 0
- // Change password as: 020202020202
- Ioctl (rc522_fd, CHANGE_BLOCK, 0); // parameter 3: Select 0th
- Ioctl (rc522_fd, CHANGE_PASSWD, 0 );
- Char bufpw1 [6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- Write (rc522_fd, bufpw1, sizeof (bufpw1 ));
- # Endif
- Ioctl (rc522_fd, CHANGE_BLOCK, 0); // parameter 3: Select 0th
- Ioctl (rc522_fd, READ_CARD, 0); // parameter 3 is useless
- For (I = 0; I <3; I ++) // read the Three Card Numbers
- {
- Read_num = read (rc522_fd, r, 0 );
- Printf ("test: I = % d read_num = % d", I, read_num );
- If (read_num> 0 ){
- Printf ("r = [0x %. 2X]", r [0]);
- }
- Printf ("\ n ");
- Sleep (1 );
- }
- // Write something to the card
- Ioctl (rc522_fd, CHANGE_BLOCK, 1); // parameter 3: select 2nd
- Ioctl (rc522_fd, WRITE_CARD, 1 );
- Printf ("before write card! \ N ");
- Char buf [11] = "186652133xx ";
- If (write (rc522_fd, buf, sizeof (buf )))
- {
- Printf ("write error \ n ");
- }
- // Read block [1], just writed
- Ioctl (rc522_fd, CHANGE_BLOCK, 1); // parameter 3: Select 1st
- Ioctl (rc522_fd, READ_CARD, 0); // parameter 3 is useless
- Read_num = read (rc522_fd, r, 0 );
- Printf ("read block [1] \ n The number you just writed is: % s \ n", r );
- Printf ("test: close rc522_fd \ n ");
- Close (rc522_fd );
- Printf ("test: exit rc522_fd \ n ");
- Return 0;
- }
The Makefile compiled by the application is as follows:
- # Comment/uncomment the following line to disable/enable debugging
- # DEBUG = y
- DEST_BIN_DIR = drivers/
- EXTRA_CFLAGS + =-D_V3
- # TESTFLAGS =-D_V3
- # Add your debugging flag (or not) to CFLAGS
- Ifeq ($ (DEBUG), y)
- DEBFLAGS =-O-g-DSCULL_DEBUG # "-O" is needed to expand inlines
- Else
- DEBFLAGS =-O2
- Endif
- EXTRA_CFLAGS + = $ (DEBFLAGS)
- EXTRA_CFLAGS + =-I $ (LDDINC)
- EXTRA_CFLAGS + =-DREV_VERSION = $ (REV_VERSION)
- LDFLAGS + = -- static
- All: test
- Clean:
- Rm-rf test_rc522
- Cp:
- Cp-f test_rc522 $ (DEST_BIN_DIR)
- Mv:
- Mv-f test_rc522 $ (DEST_BIN_DIR)
- Test:
- Arm-linux-gcc $ (CFLAGS) $(LDFLAGS)-O2 test_rc522.c-o test_rc522
- Depend. depend dep:
- $ (CC) $ (CFLAGS)-M *. c>. depend
- Ifeq (. depend, $ (wildcard. depend ))
- Include. depend
- Endif
During the test, close the card to the antenna area of RC522 to read the card ID normally.
V. Summary
This debugging was successful and encountered several major problems as follows:
1 SMDK Development Board SPI0 communication problems, started to think that driver problems, do not know how to test the Development Board SPI interface OK, after finding some information on the Internet, I found that the SPI driver can be tested by the driver modules and applications that come with the kernel.
2. Applications (test programs) cannot run on the development board system because the Linked Library is not set to static.
3 The VCC in RC522 needs 3.3 V, MOSI, CLK, and other TTL high levels, which are also 3.3 V. However, the high levels of GPIO output by the 4412 controller are all 1.8 V, so the module cannot work normally. Due to debugging, it is impossible to add an IC for TTL level conversion. Later, I tried to lower the VCC to 2.6 V, and the result module was working properly.