This is a work in progress. The last update was 16-Oct-2008.
The LPC2148 demo code demonstrates several software packages and the majority of the hardware features the LPC2148 is capable of. It is primarily targeted at the Olimex LPC-P2148 board, but is easily used on anything with an LPC2148 processor, or any compatible family member.
Can this use improvment? Please feel free to send suggestions to jcwren@jcwren.com.
The latest demo code version is 1.44, dated 12-Jan-2009

View the latest README file
Download the latest tar+gzip'ed version (Linux)
Download the latest zipped version (Windows)
Browse the directory for older versions
 

Was this useful?

 

ADC -- Analog to Digital Converter

The Olimex LPC-P2148 board has potentiometer AN_TR connected to ADC0.3. The sensors task (sensors/sensors.c) polls the ADC (adc/adc.c) every 100 milliseconds. If a change is detected in the value of the ADC, then a message is sent to the LED task (leds/leds.c) to change the duty cycle of the blinking of LED1. The range of the pot is divided into 4 quadrants. For quadrant 0, the on-time is 200 milliseconds, and the off-time is 800 milliseconds. Quadrant 1 is 400ms on/600ms off, quadrant 2 is 600ms on/400ms off, and quadrant 3 is 800ms on/200ms off.

CPU -- CPU configuration

The CPU initialization code (cpu/cpu.c) performs basic initialization of the CPU. All pins are reset to GPIO, fast GPIO is enabled, the PLL is enabled, the MAM is configured, the peripheral bus clock is configured, all peripheral modules are powered off, interrupts are disabled, the FIQ handler is copied to RAM, and finally the interrupt handlers are switched to be in RAM.
It is the responsibility of the various hardware initialization code to enable the module it is configuring, reassign I/O pins from GPIO to module specific functions (for instance, assigning pin P0.0 to TXD0 for UART0).

DAC -- Digital to Analog Converter

The LPC2148 has one 10-bit DAC channel, and this pin is not connected to anything on the Olimex LPC-P2148 board. As such, an oscilloscope or digital volt meter will be required to see the pin operating.
The sensors task (sensors/sensors.c) runs the 10-bit DAC from it's lower limit of 0 volts to its upper limit of 3.3 volts and then back down over a period of about 12.8 seconds. The DAC value starts at 0, and adds 16 to it every 100 milliseconds. Once the value reaches 1024, 16 is then subtracted every 100 milliseconds until it reaches 0, then the cycle repeats. The code to initialize and write the DAC value is in dac/dac.c.

FIQ -- Fast Interrupt reQuest

Interrupts can be placed in one of three categories: FIQ, vectored IRQ, and non-vectored IRQ. FIQs have the highest priority, and will preempt either type of IRQ. There is a caveat under FreeRTOS, however. Nested interrupts are not supported, and as such, if the normal IRQ is used for interrupt handling, the FIQ should never make use of FreeRTOS functions. Please see http://www.freertos.org/FAQISR.html#Nest for details.
To demonstrate the FIQ functionality without using FreeRTOS calls, Timer 1 is set up to generate an interrupt every 125 milliseconds. The FIQ handler increments a global counter, which can be displayed with the 'fiq count' command. Because 32 bit reads and writes are atomic in the LPC2148, no special protection is need to make sure the counter is read correctly if an interrupt occurs while the counter is being read.
While multiple interrupt sources can be assigned to the FIQ, it requires that the FIQ handler then evaluate the interrupt source prior to handling it. This largely defeats the purpose of the FIQ, and is typically considered to be a Really Bad Idea.

GPIO -- General Purpose Input/Output

Examples of using GPIO can be found in several modules, such as leds/leds.c, mmc/ssp.c, lcd/lcd_4bit.c and lcd/lcd_8bit.c.
GPIO is probably one of the easiest features of the processor to use. Other than the LED task (leds/leds.c), which toggles LED1 at a fixed rate with a variable duty cycle determined by ADC0.3, and pressing the B1 and B2 buttons to turn LED2 (eints/eint0ISR.c and eints/eint2ISR.c) on and off, there are no other examples where the effect of toggling a GPIO pin can be readily seen.
It should be noted the the LPC2148 has two GPIO modes; legacy mode and fast GPIO mode. Several of the earlier LPC21xx processors did not support the fast GPIO mode, which prevented toggling the GPIO pins at high rates. There is little valid reason to use legacy mode anymore, and as of version 1.30 of the LPC2148 demo code, the GPIO is now used in fast GPIO mode. It is possible to assign some GPIO pins to use fast GPIO mode and other to use legacy mode, but it's hard to imagine a practical use for this, and no example is provided.
Section 8.1 of the LPC214x Users Manual (UM10139) has a good description of the new functionality with the addition of the fast GPIO mode.

I2C -- Inter-Integrated Circuit

The LPC2148 has two I2C ports, however the Olimex LPC-P2148 board has no I2C peripherals present. To demonstrate I2C functionality, it is necessary to connect an LM75 and/or 24Cxxx EEPROM to I2C0. Any EEPROM between 512 and 64K bytes should work. The part must use a 16-bit address to address a location. The demo code was tested against an Atmel 24C1024.
There are three sets of commands in the CLI that pertain to I2C in general, and the EEPROM and LM75 specifically.
The 'i2c' set of commands allows raw reading and writing to an I2C address. An I2C device can be read, written or written then read. Data read from the device is placed in an internal 16 byte buffer that can be displayed. No interpolation of data is done with these commands, and they're likely of limited use when testing other I2C devices. Most devices need some supporting code to perform any useful function, other than testing that the device responds at the expected address.
See the EEPROM section for additional details regarding EEPROM commands.
See the LM75 section for additional details regarding LM75 commands.
Note that although the transfer of data to the EEPROM is handled with interrupt driven code, once the transfer completes, interrupts are disabled and a polling loop is used wait for the EEPROM to complete its operation. This is done at the tail end rather than at the start because it was easier. If an application needs faster through-put, this should be re-written to check the busy status prior to the read or write to the EEPROM.

IAP -- In-Application Programming

The IAP is program code internal to the LPC2148 that allows an application to erase and write blocks of internal flash memory (reading, of course, requires no special handling). The IAP exists because programming flash memory can be tricky. Keeping the programming voltage applied for too long will permanently damage the flash cells in that sector or block. It also helps provide protection against a change in the flash memory technology. Rather than an application having to "know" about the type of flash present, it uses the code present in the processor. The application only needs to know about the IAP API (Application Programming Interface), and can ignore the underlying flash programming algorithms and technology.
The IAP can be explored with the 'iap' commands. IAP deals with sectors of flash. Arbitrarily picking a sector to erase or re-write could result in wiping out programming code, so the CLI provides the 'fss' (Find Safe Sector) command. This will return a sector number that is not in used by the demo code, and permit erasing and filling with a value. The 'stoa' command converts a sector number to a 32-bit address, which the 'md' (memory dump) command requires to display memory.
Once a safe sector is located with the 'fss' command, that sector can be erased using 'erase', blank checked with 'blank', or filled with a value using 'fill'. In addition, the part ID (which indicates it's an LPC2148) can be read with 'id', and the bootloader version read with 'ver'. Lastly, the LPC2148 can be restarted into the bootloader with the 'isp' (In-System Programming) command.

IRQ -- Interrupt ReQuest

As mentioned in the FIQ section, interrupts can can be placed in one of three categories. All normal interrupt handling is done with vectored interrupts in the demo code (there are no examples of the non-vectored interrupt form). Devices that use interrupts are EINT0, EINT2, I2C, RTC, Timer 0, Timer 1, UART0, UART1 and USB. Optionally, EINT 3 is used if the ENC28J60 Ethernet controller is present.
EINT0 and EINT2 are connected to the B1 and B2 buttons, respectively. Pressing B1 turns LED2 on, while pressing B2 turns LED2 off (note that no switch debouncing is done, which is generally bad form. In this case since LED2 is already on when B1 is pressed a second time, there is no ill effect. In a more complex system, Very Bad Things could happen without appropriate debouncing).
If the ENC28J60 Ethernet controller is present and uIP is enabled in the top-level Makefile (which is the default), then EINT3 is connected to the interrupt output on the ENC28J60. Although EINT3 can be assigned to one of several GPIO pins, because of the design of the Olimex LPC-P2148 board, UART1 must be disabled and the RXD1 switched from the UART to EINT3. In addition, the RS1/UEXT jumper must be moved from the normal RS1 position to UEXT.
In the code build as provided in the demo code, UART1 is set to 4800 baud, and is expecting NMEA formatted GPS strings. GPS strings are parsed, and can be read with the 'gps' command. Additionally, the RTC can be set from the GPS time using the 'rtc gps' command. Once the uIP task is started with 'uip start', UART1 is disabled. The GPS task remains in the ready queue, but since no characters are arriving on UART1, the task is never woken. If the uIP task is stopped ('uip stop') and the RS1/UEXT jumper moved back to the RS1 position, then GPS parsing will resume.
EINT1 is not used by the Olimex LPC-P2148 board, however, code is provided in eints/eint1.c and eints/eint1ISR.c should EINT1 need to be used in a different application. Note that eint1.c will need to be edited to assign EINT1 to the desired pin.
VIC programming and GPIO assignment are handled in the code that makes use of the particular interrupt.

MAM -- Memory Accelerator Module

The MAM is best described by chapter 3 of the LPC214x Users Manual (UM10139). Note that depending on the step level of the LPC2148, there are one or more bugs that affect the MAM. Please see the LPC2148 errata sheet for details. Revision B LPC2148's are purportedly free of the MAM defects.
MAM problems are most evident when a seemingly innocuous change is made to the code, and it suddenly stops working (after, of course, eliminating programmer error). For an LPC2148 running at 48Mhz (the Olimex LPC-P2148 board has a 12Mhz crystal, and the 4x PLL is enabled), a MAMTIM of 0x03 is recommended. If MAM problems are encountered, it is suggested that the MAMCR be changed from FULL (0x02) to PARTIAL (0x01).
Currently the demo code is running with MAMCR set to FULL. At one point some problems were experienced, but subsequent changes (which caused the code to align differently) eliminated the problems.

PCB -- Pin Connect Block

The PCB determines what function a GPIO is assigned to. After the LPC2148 is reset, all pins are assigned to GPIO except for the P1.26 (assigned as /RTCK), and P1.25 through P1.16 (assigned to the ETM (Embedded Trace Macrocell)).
In the CPU initialization code (cpu/cpu.c), P1.26 and P1.25 through P1.16 are assigned to GPIO. For any pin that needs to be assigned to a peripheral function, that peripherals initialization code handles setting the PCB to assign the pin to the desired defice (for an example, see uart/uart0.c where P0.0 and P0.1 are assigned to UART0).
The PCB allows a great deal of flexibility in pin assignment. While certain perihperals, such as UART0, require that P0.0 be assigned to TXD0 and P0.1 to RXD0, other modules, such as the IRQs EINT3, can be assigned to P0.9, P0.20, or P0.30. Selection of a single function on a port pin completely excludes all other functions otherwise available on the same pin. However, it is unclear what happens if EINT3 is assigned to all three possible pins (likely another Very Bad Idea).

PWM -- Pulse Width Modulation

The LPC2148 has 6 PWM outputs, which can be configured as 6 single edge outputs, or 3 double edge outputs. 4 of the PWM outputs are of limited usefulness, as they share the same pins as UART0 and UART1 (PWM1, PWM3, PWM4, and PWM6).
On the Olimex LPC-P2148 board, PWM2 is shared with IRQ EINT2, which is connected to button B1. This leaves only PWM5 available for use. An oscilliscope or logic analyzer will be needed to be connected to P0.21 to see the output of PWM5.
PWM5 is initially configured to output a 20Khz frequency (50 microsecond period) at a 50% duty cycle. The 'pwm freq' command be used to set the frequency between 1Hz and 48Mhz. The 'pwm duty' command changes the duty cycle of the waveform from 0% to 100%.
The PWM5 channel was used in another project to drive a charge pump to negatively bias the contrast of a CrystalFontz CFA1602Z-YYH-ET LCD display. See the docs/biaspump.png file for a schematic of the charge pump. The pump is run at 20Khz, and the duty cycle varied to achieve the desired contrast.
Another interesting exercise is to interface to an R/C servo. Since the LPC2148 has a 3.3V output, it will be necessary to buffer the servo drive signal through a 2N7000 FET or NPN transistor. Set the frequency to 60Hz, and vary the duty cycle between 6% to position at one end, 12% to position at the opposite end, and 9% to position to center. This gives a very limited number of positions, but does demonstrate how PWM can be used to control a servo. This hasn't been tested, but the theory is good :)

RTC -- Real Time Clock

The RTC in the LPC2148 can keep time, generate an alarm at a programmed time, or generate a periodic interrupt. The Olimex LPC-P2148 board has no backup battery for the RTC, so the time and alarms will be lost whenever power is removed from the board (it will keep time and alarms across resets, as long as power is not removed).
The time may be set manually by using the 'rtc set' command, or if a GPS is attached to UART1, the time may be set from the GPS (note that the time will be UTC, and not local). The 'rtc get' command is used to display the time.
An alarm may be set to occur in the future with the 'rtc alarm' command. This is implemented by having the RTC interrupt service routine post a 0xff into the input buffer of the CLI, which will result in the command currently being typed (if any) to be aborted, and cause the string 'ALARM -- ' followed by the current time to be displayed on the console. Altough not implemented by the demo code, recurring alarms can be configured in the RTC. See section 4.7 of the LPC214x Users Manual (UM10139).
In addition to alarms, periodic interrupts can be defined. Although the RTC can be configured to generate an interrupt whenever the second, minute, hour, day of month, day of week, day of year, month or year increment, the demo code only implements the change of minute interrupt. Similiar to the alarm, the interrupt routine posts a 0xfe into the input buffer. This causes the string 'PERIODIC -- ' followed by the current time to be displayed. Like the alarm, any input in progress is discarded. The periodic interrupt is configure with 'rtc periodic on' and 'rtc periodic off'.

SPI -- Serial Peripheral Interface

The LPC2148 has two SPI ports, SPO0 and SPI1. SPI0 is a very simple SPI port, allowing 8 to 16-bit sized frames to be transferred, control of the clock phase and polarity, write collision detection, interrupts, and a few other basic amenities.
SPI1 is also called the SSP (Synchronous Serial Port), and is much more flexible, with such features as 4 to 16-bit frame lengths, 8 frame FIFO, and faster operation (PCLK/2, as opposed to the PCLK/8 of SPI0). See the SSP section for how the SSP is used. The SSP is used to interface to the SD/MMC card.
The Olimex LPC-P2148 board has no on-board SPI peripherials. If a Microchip ENC28J60 is available, it may be connected to the SPI0 port. See the docs/in28j60.png and docs/enc28j60.png files for how they should be connected.
Microcontroller Pros has a nice little module, the in28J60. These was selected only for the reason that it was $5 cheaper than the Olimex ENC28J60. Naturally, two days after I ordered the in28J60, the ENC28J60 dropped $6. Other than the price, and the fact the in28J60 has press-fit pins (not necessarily an advantage), there is no functional difference in the two modules (although the pin-outs may be different. This has not been verified).
Update: the in28J60 is a hateful little module, entirely because of the press-fit pins. They don't fit the prototype area holes of the Olimex LPC-P2148 board, and they're a great deal of trouble to remove (one of two modules was believed to be damaged by doing this). The Olimex ENC28J60 is now $1 cheaper, and has standard pins. While the two modules have the same pin functions, naturally they're arranged in a different order, and therefore not interchangable from a wiring standpoint.
Assuming that a in28J60 or ENC28J60 module is connected, the uIP-based HTTPD server may be started with the 'uip start' command, or stopped with the 'uip stop' command. Please see the note about the ENC28J60 in the IRQ section regarding interaction with UART1. Please see the HTTPD section for other uIP commands.

SSP -- Synchronous Serial Port

The SSP is connected to a single SD/MMC socket on the Olimex LPC-P2148 board. The SSP is used as the underlying transport layer to send commands and data to a MMC/SD card.
The FatFS package is used to provide access to FAT12/FAT16/FAT32 file systems on the SD/MMC card. The demo code provides commands for formatting, reading and writing cards. Directories and files may be created, deleted, and renamed. The 'thruput' command is provided to give a rough estimate of performance.
Note that LFN (Long File Name) support is NOT provided by the FatFS package, and cards with LFNs will display only the short 8.3 formatted name.
Special note: Depending on the capacity, SD/MMC cards may have sector sizes other than 512 bytes. The FatFS code cannot deal with sector sizes that are not 512 bytes. Some smaller cards have 256 byte sectors, while some larger cards have 1024 byte sectors. As a general rule, 1GB SD/MMC cards have 512 byte sectors. 512MB cards are hit or miss. 2GB cards appear to always have 1024 byte sectors.
The 'cpcon' command allows copying data from the console to a file on the SD/MMC card. Control-D is used to end entry of text and close the file. If using the terminal window of Flash Magic, please note that it does not pass control characters, and the only way to exit is to press reset (which will cause data loss). Consider using a proper terminal program such as ProComm. Also note that the Flash Magic terminal window has other problems; it's *very* slow. When using 'cp' to display the contents of a file (or 'md' to dump memory), once approximately 16K characters of backlog develops, FM loses it's mind and starts printing garbage.
In general, the FatFS code appears to be reliable. That being said, there's a few things that need improvement. It could have better error propogation (meaning that low level errors are translated into very generic upper level errors). Not all SD/MMC cards work, even those with 512 byte sectors. The card identification routines could use some refinement. The naming convention of routines is less than ideal. Too many global variable are used, and are exposed (not declared static). The low-level SSP code should be re-written to use interrupts.

SWI -- SoftWare Interrupt

The software interrupt (SWI) facility of the ARM7 core is not discussed in the LPC214x Users Manual (UM10139). It is not actually a peripheral of the LPC2148, but an integral part of the processor core. A good explanation of the SWI instruction is here.
At this point, it is assumed the reader understands what the SWI is useful for. FreeRTOS makes use of the SWI instruction in the portYIELD() macro. Unfortunately, it tends to assume that the entire SWI handler belongs to FreeRTOS. On the plus side, the SWI instruction with no parameters is the equivalent of "SWI 0", so the handler can special case that one, and pass it on to FreeRTOS.
The demo code shows handling various SWI's in both assembly (swi/swidispatch.s) and in C (swi/swi.c). SWI 1 through SWI 4 are handled in assembly. SWI 1 shows an example of passing a parameter; LED2 is disabled if the parameter is 0, or enabled if the parameter is non-zero. SWI 2 turns LED2 on, SWI 3 turns LED2 off, and SWI 4 toggles the LED2 state. SWI 5 and higher are passed off to the C code for processing.
SWI 5 through SWI 8 perform the same functions as SWI 1 through SWI 4, only they are performed in C code instead of assembly. SWI 9 and above generate an error message indicating it as an unhandled SWI.

Timers

There are 2 timers in the LPC2148, named (oddly enough) timer 0 and timer 1. Timer 0 is reserved by FreeRTOS to generate the system tick. The demo code sets the timer 0 tick to 10 milliseconds. In the various demos included in the FreeRTOS source tree, the timer is often run at 1 millisecond to show the performance of FreeRTOS. This is generally an unrealistic value, as much more CPU time is wasted in context switches. 10ms is adequate tick rate for most systems. Note that is no law that says the tick rate must be a an even multiple. If suitable, a 3.333 millisecond tick could be used. 1 or 10 milliseconds just happen to be easy numbers to work with.
Timer 1 is used for two purposes. When the FIQ example is being performed ('fiq on'), timer 1 is programmed to generate an interrupt every 125 milliseconds. When using the 'beep' commands, timer 1 is used set to twice the desired frequency for the tone.
Although no example of this is provided, if the PWM feature of the LPC2148 is not used, the PWM can be used as a third timer. See chapter 16 of the LPC214x Users Manual (UM10139).

UART -- Universal Asynchronous Receiver/Transmitter

There are 2 UARTS in the LPC2148, UART0 and UART1. Both UARTs conform nearly 100% with the industry standard 16550 UARTs. UART0 and UART1 are indentical, except that UART1 has a full set of modem control lines. Another very nice feature is the fractional baud rate generator (FBRG) and auto-baud capabilities. The FBRG allows selecting a desired baud rate within a fraction of a percent, regardless of the system clock speed.
UART0 is set to 115200 baud, 8 bits, no parity and 1 stop bit at reset. If the demo code has been recompiled with CFG_CONSOLE_UART0 in the top-level Makefile, the CLI will output a "Demo>" prompt at reset (remember that the terminal program used may require that hardware flow control be turned off. Otherwise, it will be waiting for CTS to be asserted, which is not present). In the default code build, UART0 is configured, but not used. [Authors note: I prefer serial ports, but the USB console is enabled in the default builds, due to the number of machines that no longer have real serial ports.]
The configuration of UART1 varies. If CFG_CONSOLE_UART1 is enabled in the top-level Makefile, then UART1 is configured for 115200/8/N/1, and the GPS task is not started. At reset, the "Demo>" prompt will be output (see note in UART0 about hardware flow control settings).
If CFG_CONSOLE_UART1 is NOT enabled, then UART1 is configured for 4800/8/N/1, and the GPS task is started. Please see the GPS section for more details about the task.
It should be noted that while UART1 does have the full complement of modem control lines (RTS, CTS, DSR, DTR, DTR, and RI), these pins are not available on the RS232_1 DB-9 connector of the Olimex LPC-P2148 board. There are two likely causes for this: Rarely are all the control lines needed, and the RS-232 driver chip would be more expensive. The board uses a MAX3232 chip, which has two drivers and two receivers, with UART0 using one set, and UART1 using the other. They would also require using 6 of the GPIO pins, which are already at a premium.

USB -- Universal Serial Bus

The LPC2148 has a USB 2.0 Full Speed (12 Mbits/s) compliant device controller. This port can allow the LPC2148 to act as a client (or peripheral), but not a host.
The USB port can be used in several configurations. The demo code, as shipped, uses the USB port for the CLI console. Plugged into a Windows box, the USB port should appear as a standard COM port. The COM number will vary, but can be displayed with Hardware Manager tool (a driver is provided in the Windows directory, usbser.inf and usbser.sys). Under Linux, the port should appear as /dev/ttyACM0 or something similiar (if you're using USB with Linux, you should already be familiar how to identify attached USB devices).
Using any decent Windows or Linux terminal program, set the baud rate for 115200 and 8/N/1, and connect. After pressing return, a "Demo>" prompt should appear. Do not press the RESET button on the Olimex LPC-P2148 board as this will cause the USB connection to be dropped. If RESET is pressed, it will likely be necessary to close and re-open the terminal program after the USB enumeration process has completed.
A USB connected mass storage device demo is also available. By editing the top-level Makefile and changing the console to the serial port (CFG_CONSOLE_UART0), adding CFG_USB_MSC, recompiling & re-flashing the code, a SD/MMC card, if present, it will appear as a removable drive under Windows or Linux. Please note that you should NOT use the 'file' commands from the CLI console while the SD/MMC is mounted as a mass storage device under Windows/Linux. Invariably, the SD/MMC card contents will get corrupted.
The USB hardware on the LPC2148 does have a DMA (Direct Memory Access) controller that allows moving end-point data between USB end-point memory and system memory. However, the code does not currently take advantage of this.

VIC -- Vectored Interrupt Controller

The VIC allows setting up to 16 levels of prioritized interrupts. FreeRTOS does not currently support nested interrupts, so the prioritization only affects two or more interrupts occuring at the same time. The interrupt priorities are configured as:
  1. Timer 0 (FreeRTOS tick)
  2. USB
  3. UART0
  4. UART1/EINT3
  5. EINT0
  6. EINT2
  7. RTC
  8. I2C
  9. EINT1
Priority 3 is handled somewhat differently. Because of the wiring on the Olimex LPC-P2148 board, UART1 and EINT3 cannot be active at the same time. UART1 is disabled when the ENC28J60 Ethernet controller is active because the RXD1 and EINT3 pin are shared. The ENC28J60 is enabled with the 'uip start' command, and disabled with 'uip stop'.
The VIC is priority levels are set by the code enabling a particular interrupt. See eints/eint0.c for an example.

WDT -- Watch Dog Timer

The watchdog is inactive by default. While a watchdog is very important in a finished product, they tend to be quite a nuisance during the development process. A good watch dog strategy is also a non-trivial exercise in a multi-tasking/multi-threaded system. There are a number of white pages available on the internet discussing correct, and more importantly, effective watchdog implementation.
The watchdog can be demonstrated with the 'wdt test' command. This sets the watchdog to a 10 second timeout. The watchdog is reset every time a new command is entered and <RETURN> is pressed. If no command is entered within 10 seconds, the system is reset. Once the watchdog is enabled, there is no way to disable it, short of a reset.
The 'wdt status' command can be used to display the current state of the watchdog, the timeout value, and also the RSIR register (which indicates the source of the last reset). 'wdt clear' will clear the RSIR.

CLI -- Command Line Interpreter

The CLI is a very simple command parser. It parses the typed command line into a argc/argv type structure, does some basic checks against the command table for command validity and the number of parameters, then calls the specified function. Adding command lists and command functions is quite trivial (see monitor/monitor.c).
The CLI supports two line editing control characters; backspacing (control-h), and line cancel (control-x). A line may be terminated with CR (control-m) or LF (control-j).
Internally, printf() statements always end with \n (LF). When the \n is written to stdout or stderr (handled in newlib/syscalls.c), it is converted to \r\n (CR/LF). Most terminal programs default to expecting CR/LF to move the cursor to the start of the next line, although this typically is configurable.
The 'help' command will display all the top level commands the CLI supports. Typing '<command> help' will display the sub-commands available under that commands. If the expected parameters to the sub-command is not display in the '<command> help' list, typing '<command> <sub-command> ?' will typically indicate what parameters are expected. If the parameters aren't clear, there's always the source code :) After all, that's what Open Source is all about, right?

GPS -- Global Positioning System

Included in the demo code is a task that will parse NMEA GGA and RMC strings and update a structure with the current position and date/time. The 'gps' command will display this information. The RTC may be set from the gps with the 'rtc set gps' command.
The GPS should be connected to UART1 and configured for 4800 baud, 8 data bits, no parity, and 1 stop bit, and to output NMEA strings (this is the default for all most all GPS units).
Note that if the CLI console is set to CFG_CONSOLE_UART1, the GPS task is not started. Obviously, it's not possible to run the two on the same port at the same time.

CPU Abort Handling

The ARM7TMDI core can determine when an undefined instruction is executed or a reserved or undefined address is accessed. When this occurs, an abort exception is generated. Aborts are caught by the abort handler code, and the address of the instruction causing the abort stored, along with all the registers. The block the abort information is stored in is marked as 'probable', and system reset.
Once the system has reset, the 'abort regs' command can be used to display the information in the block. The 'abort clear' command will write zeros to the abort storage block, while the 'abort dirty' command will clear the sigil that marks the block as probably value. When debugging a problem using the abort commands, it is recommended to use the 'abort dirty' or 'abort clear' to mark the abort data as invalid. Once the actual abort occurs, the block will be marked probable, and be more (but not 100%) assured that the abort data is valid after the abort.
All three types of aborts can be generated from the CLI with the 'abort undef' (undefined instruction), 'abort pabort' (pre-fetch abort, or attempting to execute an instruction from a reserved area), or 'abort dabort' (data abort, reading from a reserved area) commands.

EEPROM -- Electrically Eraseable Programmable Read Only Memory

To demonstrate I2C and the EEPROM, the CLI provides commands 'ee' set of commands. Up to 32 bytes may be written at one time to the EEPROM (a limitation of the argument processing in the CLI), but any number of bytes may be read and displayed.
There are two forms of the read and write commands. One set allows specifying an address to begin the operation at ('ra' and 'wa'), while the other set uses the next address after the last operation ('r' and 'w'). The 'a' command can be used to pre-set an address for 'r' and 'w' (although normally 'ra' and 'wa' would be used instead). There is also a fill command ('fa') to fill an address range with a value.
Note that writes should not span a page boundary, where the page size is defined by page sizeof the EEPROM. In most EEPROMs, the data will wrap back to the start of the page. This is to say that if the 'wa 0xfe 0 1 2 3' command is performed, locate 0xfe will have 0, 0xff will have 1, location 0x00 will have 2, and and location 0x01 will have 3. When the page size is known, it's quite trival to add code to check for this. When the page size can vary between family members, it's up to the user to prevent mistakes.
Please see the docs/24LCxxx.png file for how a 24LCxxx EEPROM should be connected. Atmel AT24LC1024 product page.

LM75 Digital Temperature IC

The LM75 is a temperature sensor, Delta-Sigma analog-to-digital converter, and digital over-temperature detector. The 'lm75' commands can read the current temperature and configuration register, and read or write the over-temperature and hysteresis values.
If the LM75 address pins are strapped for other than it's lowest address (A0, A1 and A2 grounded), the 'lm75 addr' command should be used to set the address of the device. The typical LM75 address is 0x90 (1001 | A2 | A1 | A0, shifted left once to allow space for the R/-W bit). If A2 was tied high, the command would be 'lm75 addr 0x98'.
Before the LM75 can be used, the 'lm75 init' command should be issued. The 'lm75 mode' command takes the argument 0 or 1, and selects comparator mode or interrupt mode, respectively (comparator mode is the default).
Once the optional address has been set and the part initialized, any of the four registers can be read. The temperature is read with the 'lm75 temp' command. The ID register of the LM75 is read with 'lm75 config'. The THYST register is read with 'lm75 thyst'. Lastly, the TOS register is read with 'lm75 tos'. Once a register has been read, it can be re-read with the 'lm75 reread' command.
Although the LM75 can generate an interrupt with the programmed temperature has been exceeded, the demo code has no support for this. If this is desired to be implemented, consider using EINT3, and examining the SPI ENC28J60 interrupt code as a basis.
Please see the docs/lm75.png file for how one or more LM75s should be connected. LM75 product page.

File management commands for FatFS + SD/MMC

(TODO)

LCD -- Liquid Crystal Display

(TODO)

Memory dump, mapping, and statistics

(TODO)

HTTPD -- Webserver

(TODO)