Computing stuff tied to the physical world

More LPC824 peripherals

As mentioned, there is quite a bit of functionality in the LPC824. One way to get to grips with it, is to compare some of its features with what’s available on an ATmega328.

A/D converter

The ATmega could be called a one-shot ADC: once set up, it measures the voltage on a specified pin, saves the result, and it optionally continues with the next measurement. Interrupts can be enabled to let us know when each measurement is ready.

The LPC824’s ADC works differently. First of all it’s 12-bit, 4 times the resolution, i.e. steps of less than 1 mV. But it also has more autonomy: you can set it up to scan a number of channels and take measurements on each one. All results end up in their own registers.

Moreover, DMA can be enabled to perform these scans based on various triggers (such as a periodic timer), and save a whole range of measurements in memory as arrays – all without requiring any processor attention. This not only reduces the load on the CPU, it also allows much faster acquisition rates. With DMA, brief, but fast 1 Ms/s acquisitions are possible.

Another interesting feature, is the ability to set thresholds: whenever an ADC measurement exceeds a limit, or crosses a level in a specified direction (low-to-high or high-to-low), an interrupt can be generated. This could be used for keeping track of a critical voltage level.

SPI and I2C

Neither of these are spectacularly different from what’s on an ATmega, apart from DMA support for performing data transfers without CPU overhead.

The I2C devices can passively listen and react to a specific set of addresses when used as a slave. The number of I2C interfaces in an LPC824 is bordering on the ridiculous: one with fixed pins supporting I2C up to 1 MHz, and three up to 400 KHz through the switch matrix. One scenario where this could be of use is when attaching several I2C devices which all happen to have the same bus address – then separate I2C buses will be a great help.

SPI has support for multiple devices on each bus. This means that you can define up to four I/O pins to act as slave selects, and then very simply re-use the same SPI bus connections for any one of them (not at the same time, obviously). Furthermore, it’s easy to activate a slave select pin on send and deactivate automatically once the last data has been sent out. Slight timing delays can be automatically inserted if a slave device has speed limitations.

Timers

This is where things become interesting. The “State Configurable Timer” (SCT) in the LPC8xx series is a fairly complex device which can be tricked into performing all sorts of tasks, including generating PWM signals and even performing delta-sigma ADC conversion using the analog comparator and one GPIO pin. The SCT timer can be used as two counters of 16 bits or a single “unified” one with 32-bit resolution.

In addition, there are also four independent “Multi Rate Timers” (MRT), but these can’t be connected to I/O pins, they merely generate periodic software interrupts. Each of these timers is 32-bit, unlike the ATmega’s three timers with (2x) 8- and (1x) 16-bit resolution.

Then there is a “Windowed Watchdog Timer” (WWDT). As the name says, this is intended for watchdog use, i.e. making sure the processor is still running code in the way things were intended. In this context, “windowed” means you can set it up so this timer always has to be triggered within a certain time range. Failure to do so generates a reset.

Lastly, there is a special “Self Wake-up Timer” (WKT). This timer consumes extremely low power and can be kept running even when everything else has been powered down. It’s a 32-bit down-counter which can be clocked at up to 10 KHz. This makes it possible to wake up at any time in the future in steps of roughly 100 µs (compared to 16 ms minimum on an ATmega). There is one caveat: the accuracy of the WKT is pretty low, it can be ±40% off.

Pin interrupts

There can be up to 8 pin interrupts, each one defined to trigger on the rising or falling edge (or both) or when the pin is a high or low level. Unlike the ATmega, these interrupts can be set up and used independently of each other (on the ATmega, any 8-bit port access will clear all pin interrupts on that port).

There is also a “pattern match” mode for pin interrupts, where only specific combinations of pin states and state changes generate an interrupt. But you can’t have both: you have to choose between either 8x independent pin interrupts, or the pattern matcher.

GPIO

This is probably a good place to point out that plain pin-wise digital input and output is also considerably more sophisticated on the LPC8xx than on an ATmega: pins can have pull-ups or pull-downs, or be used in open-collector mode.

For each pin, you can define a level of hysteresis, i.e. a slight reluctance to change when the input level crosses the 0/1 voltage threshold. This allows the use of analog-type input levels as 0/1 digital signals. Also very particular for the LPC series, is (fairly basic) support for hardware-based glitch/debounce filtering.

But the most interesting part of GPIO pins is perhaps one shared by all ARM chips in some way or other: the ability to precisely set, clear, or toggle any number of bits on a GPIO port. An LPC824 has a single GPIO port, but larger chips can have several. The ability to set a specific group of bits in a GPIO port solves a major issue when multiple pins all need to be changed at exactly the same time.

There are simple ways of setting, clearing, and toggling pins, plus reading out all the pins at once or reading each one individually. The reason this is so much easier on ARM chips, is the 32-bit addressing architecture: a large virtual address space is reserved for numerous access modes in the GPIO subsystem.

DMA

The Direct Memory Access (DMA) interface is like a very special-purpose processor. In a way, its main role is to take some tasks off the CPU, related to transferring sets of bytes, half-words, or words between memory and/or peripherals. DMA can also copy memory.

In the LPC824, it’s a fairly advanced design, in that it also supports scatter/gather style transfers, i.e. transfers which take place across multiple disjoint areas of memory. It would for example be possible to save the first N incoming bytes in one buffer and the remainder in another buffer, all without any CPU intervention.

The performance benefits of DMA can be dramatic: for each interrupt-based data transfer through the CPU, an interrupt must be triggered and handled, state must be saved on the stack, the transfer done, and then the state popped and prior activity resumed. All that possibly once for every byte in the transfer. With DMA, you just set it up, and the DMA hardware will “steal” one bus cycle whenever it needs to access a peripheral or memory.

Closing note

Most of the features described above are optional. It’s quite easy to ignore most of this and simply write code which polls a serial USART for incoming data, and then extract that data. GPIO accesses can be kept simple. DMA is not strictly necessary in many cases.

But it’s also good to know that a variety of high-performance features are available in the LPC824 for when you do need them. That’s the whole point of being “general purpose” …