Raspberry Pi Bare-metal Programming – SPI Interface

Bare-metal programming is a low-level method of programming that is specific to the hardware hence there is a need to understand how a hardware architecture works and what happens in the lowest levels of an operating system. Bare-metal programs run without OS beneath(e.g Linux Kernel) and  are OSes themselves for  you are forced to work directly with memory, pointers, and the underlying arrangement of the bits and bytes. Assembly language  and C language are preferred in bare-metal programming for they are closer to the machine code. A good write up with great tutorials for writing bare programs in Assembly is available online from the University of Cambridge. Another great source that I heavily borrowed my OS template is from David Welch git-hub resource and both implementations are discussed in the bare-metal section of Rpi forums. where you can seek clarification in case you are stuck.

I have written a simple program for  SPI driver which uses the polled method and the source is available  here at bit-bucket. The steps of achieving this operation as described in page 158 of BCM2835 ARM Peripheral Datasheet are:

1 Set CS, CPOL, CPHA as required and set TA = 1
2 Poll TXD writing bytes to SPI_FIFO, RXD reading bytes from SPI_FIFO until all data written.
3 Poll DONE until it goes to 1
4 Set TA = 0.

The DONE bit of Control Register in step 3 did not change to 1 after writing to the FIFO transmit register and the program got stuck at this loop. I was forced to substitute it with a small delay as a temporary measure as I check into this issue.

To compile the program I used  Codesourcery  free version of the gcc tool-chain for ARM cores. Make sure that the  path to the toolchain binaries is added to the PATH environment variable otherwise the make will not find the toolchains to compile the files.  I have included a sample program test.c (video of the sample below) which send a byte of data to the spi port that is connected to 74HCT595 (shift register). 8 LEDs are connected to output of the shift register to generate a binary equivalent of the sent data byte looping through 1 to 255 decimal.  Once the program has successfully compiled , copy the generated kernel.img (from the output directory) to the first FAT partition of the SD card  replacing the existing kernel.img. The start.elf , boot-code.bin and loader.bin must be present(firmwares required by video core processor ,read here for rpi boot process) in the same partition for the system to successful boot. If you don’t have these files you can obtain them from raspberry pi firmware directory.



One comment

  1. I think step 3 should be:

    while (!(var & (1 << SPI_C_DONE)))
    var = *SPI0_CONTROL;

    Also, I think there is no need to wait for TXD.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: