PXA270 Tips


I'm writing this document in the hopes that it will help those who are struggling to sift through the gigantic 1270 page manual for the PXA270 microprocessor. While initially configuring mine, I spent a good deal of time figuring out why software and hardware interrupts were behaving strangely or not working at all, where the interrupt vectors lived at, and how I could get the Micrium OS-II operating system to work with this thing.

As a little bit of background, I am running the Intel XScale PXA270-10-520 processor with a Starter Development Kit (SDK) board from Zoom Logic. I am compiling my instructions with the IAR ARM compiler running on an old Dell laptop, and they're written partly in C and partly in assembly. The reason for the latter is that the Micrium OS-II requires you to write your own functions for placing the processor registers on the stack and taking them off again in case the OS needs to switch tasks (multi-thread) or gets interrupted by software or hardware. Later on I'll talk more about this and provide port files that should work if you're using the same architecture.

For a mapping of the register names to hexidecimal values, see the file bsp.h linked below.

Serial Port (FFUART)

OS Timers

It doesn't seem to be listed anywhere in the manual, and it's most likely a result of the firmware initally loaded by the Zoom development kit, but OS Timer 4 is initially enabled as a source of interrupts to the processor. This took me some time to figure out, and it took me even more time to figure out how to service the interrupt.

The second task that was somewhat confusing was getting the 1 ms and 1 s clock ticks working. It turns out that you have to enable the 32.768 kHz clock manually by setting OSCC[OON] and then waiting until OSCC[OOK] is set high. The exact steps are well described on p. 108 of the PXA270 Developers Manual, but it took me a while to find this exact section.

Port Files for MICRIUM OS-II on the PXA 270

While the Micrium site does offer some useful application notes (AN-1011 and AN-1018 are probably the most helpful) to help one in getting started with a port, it does not provide a full port for the PXA 270 processor. Furthermore, the application notes do not provide a complete prescription of how to produce a port for the PXA 270, and they disagree in some areas. For instance, one note tells you to push both CPSR and SPSR onto the stack during a context switch while the other tells you to only do so for CPSR. The textbook "MicroC/OS-II: The Real Time Kernel, Second Edition" by Jean J. Labrosse helps to make up for areas where these notes fall short. But it adds a touch of its own complication by using different file and function names than those used in the application notes.

Reading through all this material helped my understanding of what is going on inside the processor and OS quite a bit. However, I would have gladly taken a full port if someone had offered it to me. Here are the C and assembly files one needs to successfully port Micrium to the PXA 270. Note that while the files contain all the necessary instructions and registers to get you going, you will definitely have to tailor them to your application. Also, I've included the files as they were while I was debugging things, so there are a lot of unecessary print statements and LED flashing and whatnot.

Port Files for MICRIUM FileSystem Module and Compact Flash on the PXA 270

In my application, I'm using the Micrium Filesystem (FS) module to read and write files on a compact flash (CF) card. The Logic SDK kit contains an onboard compact flash drive and a specialized IO controller chip that handles most of the signals that are necessary to drive the controller on the card. So there's no need to break out the soldering iron or play with jumpers to get the thing working; only writing some software.

Now, if one has experience with memory mapped peripherals and IDE controllers and writing device drivers, reading and writing a file on the CF card might not be that challenging. But if that's not the case, this can be a difficult task. Part of the challenge is knowing where to look to get the information you want. The PXA 270 manual has a long, well written section about the CF interface, but unfortunately, most of it is useless if you're trying to get the drive on the SDK board working. That's because the IO controller does most of the work for you. And also, it doesn't provide any sort of description of what "Attribute Memory Space" or "Common Memory Space" actually is.

Instead of trying to explain these things myself and potentially doing a lousy job, I'll point out the references I found useful. This Circuit Cellar Article on Compact Flash cards is an excellent, concise start to Compact Flash. The CompactFlash Specification Manual will give you the finer details of how to write the configuration registers and interpret the Card Information Structure (CIS), which lies in Attribute Memory Space. And this XiLinx Application Note provides an excellent guide to the Attribute Memory, Common Memory, and I/O space.

For the case of the Logic SDK Kit, the address range 0x14000000-0x14FFFFFF has been mapped to the off-board CompactFlash Type 1 Memory Only Slot. The uP_MA[12] line is actually connected to the REG line on the controller, which means that when an address starts with 0x14000___, we are accessing configuration registers and the CIS, and when the address starts with 0x14001___, we are accessing common memory space. The latter is the space we want to write/read to get the data off the Compact Flash card. The former will tell us about the card itself (how big the sectors are, how many there are, etc.). It's a pretty informative exercise just to read all the values in the 0x14000___ to 0x14001___ range to see how this all works.

The process of actually reading and writing data from/to the card is a little tricky. And rather than try to explain where to wait for status bits to flip or how to write the ATA registers to set up a read/write, I'll just provide a Compact Flash driver I wrote for the Micrium FileSystem module. You'll need the registers defined in bsp.h. The files fs_dev_cf_card.c and fs_dev_cf_card.h show how to manipulate the Compact Flash card.

SD Card Interface in SPI Mode

Programming the SD Card controller to operate in SPI mode is a little bit of a challenge, mostly because the documentation in the PXA270 manual is very poorly organized (in my opinion, at least). I will try to sum up the most important things that I learned and correct the documentation where necessary.

1) For starters, the PXA manual says conflicting things about what software (i.e. you) have to do with the Chip Select (CS) signal. It implies that you have to manually turn the signal off in between commands. If you try this, you won't have success. It turns out that you needn't do anything with the CS signal once you've activated it in the MMC_SPI register. The controller will assert the signal as necessary when it issues a command.

Quick Capture Interface and DMA

There are several very tricky issues one must consider when trying to get the Quick Capture Interface (QCI) to write buffers using DMA. The biggest speedbumps I encountered were 1) configuring the DMA descriptors for the QCI properly, 2) writing the DMA registers in the proper order, and 3) getting the DMA to work consistently on a buffer in memory. The secret to the last one was something I probably wouldn't have figured out for weeks if a friend hadn't diagnosed it as a cache-related problem. As I now know, DMA and cache are always going to be problematic on your standard microprocessor because the CPU doesn't know that the values in physical memory have changed when DMA writes them.

The Exception Vector Table

The exception vector table is a set of 7 registers that determine how to handle things like interrupts and undefined instructions that may arise while the processor is running. It normally lives at 0x0000_0000. But in the ARM architecture, there is a bit in the C1 Control Register that can be used to move the table to 0xFFFF_0000. And if it's moved there, it can be re-mapped through the MMU to any address in RAM that you see fit.

So first off, here's what the exception vector table looks like:

A more detailed table can be found at this ARM Exception Website. For our purposes it will suffice to say that at each one of these memory addresses there should be an appropriate instruction to handle its exception. For instance, in the bsp.c file above, you'll see that the instruction is to jump by 0x18 memory addresses to the memory cell that contains the address for the software interrupt handler. So whenever there is an interrupt from the serial port or QCI or whatever else, the software interrupt handler will be called.

You'll see many references that simply neglect to list the BASE address in the above table, leading you to believe that the vectors live at 0x0000_0000-0x0000_0020. But as mentioned above, they can be relocated to 0xFFFF_0000 by changing bit [13] of the C1 control register. To get this register, you'd execute the assembly instructions

                    MRC    P15, 0, R0, C1, C0, 0
   ORRS R0, R0, #0x00002000
   MCR P15, 0, R0, C1, C0, 0

I did not realize that my exception vector table had already been relocated to 0xFFFF_0000 for quite some time. It turns out that the Logic Loader program that runs on the Logic SDK system I have does this at startup.

When I was first getting my code up and running, before I had realized any of this, I had read somewhere that the exception vector table might live at the start of RAM (0xA000_0000). So I took a shot at writing the code for the exception vectors at 0xA000_0000-0xA000_0020, and sure enough, things worked as expected. And all the while, I was unaware that the address space 0xA000_0000-0xA000_1000 is actually mapped to 0xFFFF_0000-0xFFFF_FFFF.

The key to understanding this is to look at the last address in the MMU Table from the previous section. That is, at the virtual address of 0xFFF0_0000, we see the value 0xA004C011. Since bits[1:0]=1, this tells us it is a coarse page table base address and the coarse table lives at 0xA004_C000 (it must start on a 1kB boundary, i.e 0x000, 0x400, 0x800, or 0xC00). If we look at the memory from 0xA004_C000-0xA004_C3FF, we can see all the entries in this coarse table and how the re-mapping takes place.

All the address in the table are 0's except for one at 0xA004_C3C0:

   [0xA004_C3C0] = 0xA000_0002 

Since each entry in the coarse table is 4 kB, it takes an entire 256 entries to cover the whole table (note that this is a 1k virtual address range, with each entry separated by 4 bytes, so each entry maps to the one before+0x4000). And the table entry at 0xA004_C3C0 lines up with 0xFFFF_0000. Thus,

writing [0xA000_0000] = writing [0xFFFF_0000]

and this is why the exception vector table appears to live at 0xA000_0000 for the Logic Loader (LOLO) system. Moving it simply requires updating the final entry in the MMU Section Table with a coarse table address of your own. You'd want to use a 1kB coarse table entry, otherwise you'd be wasting a full 1MB of RAM.

JTAG Programming

The JTAG interface on the PXA270 consists of essentially 5 pins: TDI, TDO, TMS, TCLK, and NTRST. Here is a brief description of each pin.

There are many better and more in-depth explanations of these signals out there on the internet. However, each source seems to have its own advice about what pull-up resistors to use for each of these pins, especially for the nTRST pin. And this can cause a good deal of headache.

The PXA 27x Design Guide states that the for the nTRST pin, "an external source must drive nTRST before or at the same time as the hardware nRESET pin for correct TAP controller and device operation (pg 217)." In most cases, you will see people recommend using a 10 kOhm or 100 kOhm resistor to pull nTRST up. The problem is that if nRESET is also being pulled up by the same value, then there is no gaurantee that nTRST will be driven high before nRESET.

To get around this problem, I recommend using a lower resistance value for nTRST. While the exact values will depend on what sort of capacitance each pin is seeing, for the case of the Triton PXA270 daughter board, appropriate values are 100 kOhm for nRESET and 10 Ohm for nTRST.