e42.uk Circle Device

 

Techie Stuff

Projects

Quick Reference

Will be moved to Quick Reference soon

Interface with I2C on Raspberry Pi

I2C with the Raspberry Pi

Note: Full source (still not finished) is available github.com/drcrane/raspberryrfid.

The Raspberry Pi has a few different interfaces available to it, one is I2C (a protocol created by Philips and used in many places, it is the basis of VESA DDC!). I had the opportunity recently to interface with an SL030 RFID Mifare reader, it is a nifty little thing that is quite cheap from SK Pang Electronics. The SL030 is based on an NXP 80C51 microcontroller (P89LPC922) and a specialised IC the MFRC522, also of NXP semiconductor origin.

This will be much clearer if you have a basic understanding of electronics and I2C, and if you have read the Broadcom datasheet page 34 (see References section below).

Hardware

This is pretty simple so I won't spend too long on it... I got to draw and take a picture ;-).

Diagram of 
Raspberry Pi I2C Ports

One thing to note (if you look in the source code for the driver) the GPIO ports are configured for you and by default (as with most microcontrollers) are inputs. These are pulled high already (as per the I2C specification) with 1K8 pullup resistors. All this means the only thing you need to do is connect up the SL030 by matching up the letters on the pins ;-).

Picture of the hardware

Kernel Compile and Install

As many people have a tutorial on this I will not bother to recreate it, I just wish to thank Chris Boot, selsinork and everybody who contributes to eLinux.

# Stuff here to help my poor struggling brain
crossdev -S -v -t armv6j-hardfloat-linux-gnueabi
git clone --depth 1 git://github.com/selsinork/linux.git
# from kernel directory
cp arch/arm/configs/bcmrpi_cutdown_defconfig .config
make ARCH=arm CROSS_COMPILE=armv6j-hardfloat-linux-gnueabi- oldconfig
make ARCH=arm modules_install INSTALL_MOD_PATH=/tmp/modules

Incase it was not obvious I used selsinork's kernel ;-)

Talking to SL030 via I2C

Once the Kernel was compiled I had my circuit all set up and wrote a nice bit of C and tried to get the firmware version number from the device. It should be:

0b f0 00 53 4c 30 33 30 2d 33 2e 32

According to the datasheet... what I got was not that, the first byte seemed to be fine but all subsequent bytes had the MSB set so I kept getting this:

0b f0 80 d3 cc b0 b3 b0 ad b3 ae b5

Too coincidental to be rubbish coming back from the device, the only thing I could think was that the Raspberry Pi clock was too fast... but then why are all the other bits of each byte correct? The Pi also says that it is running at 100KHz which is well within the tolerance of the SL030 which says 0-400KHz.

After trying to find the Broadcom datasheets and discovering that "Broadcom are not like STMicro or Philips" which meant no datasheet for me :-( anyway, without an Oscilloscope (which I am ashamed to say I do not own) and no idea of what registers to fiddle with I thought oh, this is going to be a long slog with the existing code. Fortunately for me Eben and co. managed to get Broadcom to release the details required and so I have been able to track down the problem to the DEL register... more specifically the REDL bits which determine how long the MCU should wait after SCL changes from LO to HI. DEL is not modified by the current I2C Bus implementation and so the Raspberry Pi is just using the reset value of 0x30. This is too quick for the IC on the SL030 to pull the SDA line LO so the first bit is sampled when it is HI.

My Change to the I2C Bus Driver

The datasheet says that by default the hardware will wait 0x30 core cycles, if the core frequency is nominally 150MHz that would be 320 nanoseconds. Our core is running faster than that and 0x30 evaluates to 192ns. I did try to change the REDL value to 0x50 which with a CDIV of 0x9c4 should have given 320ns, that did not work.

This is not quite how the I2C specification expects the bus to work however the specification says that SDA should be stable for the whole time SCL is high. Normal I2C implementations sample very close to the rising edge (as is the default configuration for the BCM2835) it is expected that the SDA line will be set correctly in the preceeding low half clock (grey on my diagram). For the SL030 the SDA line is not driven low until later so the first bit of each byte, after the first byte, are read as 1. So, the Ideal Sample Time here is only the ideal sample time for the SL030 but should work with other peripherals.

Please see my patch to selsinork's kernel.

References

Quick Links: Techie Stuff | General | Personal | Quick Reference