circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

December 2006, Issue 197

ARM Scope
Build an Analog Oscilloscope Companion


by Greg Cloutier


Start Hardware Overview Embedded Code User Interface Functional Code System Development Sources and PDF

EMBEDDED CODE

Along with the MCB2130 evaluation board, the kit included Keil’s DK-ARM software package. The software package included Keil’s µVISION 3 IDE and Keil’s ARM compiler. The IDE handles everything including project management, code editing, calling up the flash memory programming application, simulation, and handling the compiler. If I had a JTAG debugger, it would handle that as well. 

You have a choice of using Keil’s ARM compiler or the included GNU compiler. The Keil compiler is limited to producing 16 KB or less of code (as is the simulator/debugger), while the GNU compiler can produce code of any size (although the simulator/debugger is still limited). I knew my code would fit under the 16 KB limit, so I used the Keil compiler. I assumed that it was fully integrated into the IDE and that it would get me up and running quickly. The user-friendly environment worked without fail. It is also nice to know that it can be set up to not only develop code for the LPC213x series, but also for nearly every brand and model of ARM processor in production today.

I knew that communicating with my PC would be essential, so I immediately began studying the examples included with the evaluation kit. Samples of UART functionality were found in two of the three examples. Along with the datasheet and NXP’s “UART/SPI/I2C Code Examples,” I was able to create my routines to communicate with the PC.

The straightforward output routine typically just sends the ADC data to the PC via the UART as the data is acquired within the Timer0 interrupt. The printf() command sends the data. I send the 8-bit piece of data and a \n character. The application on the PC adds each piece of data it receives to the display. The data sent from the PC and received by the ARM processor is handled in a slightly different way. A typical transfer in this direction usually includes a command and some data or parameters. This was implemented in such a way that the processor doesn’t stop while waiting for data to come in.

The main loop is set up to poll the UART for data in a continuous manner. Not much goes on in the main loop, and there is a 16-byte buffer, so it’s unlikely that any data will be missed. An alternative would be to set up a UART receive interrupt. Within the polling routine, the received data is transferred into a receive buffer array. This is done because it is not necessary to act on a command until all the data or parameters are received as well. It is determined that the reception is complete when a \r character is received. Once the reception is complete, a function is called to process the command. This function determines which command has been sent and then acts accordingly on the data or parameters.

I left the command structure fairly simple because there were not too many commands to implement. Commands must be agreed upon between the processor code and the application running on the PC. In this case, there are eight command represented by the uppercase letters A through H.

Command A sets the PWM period. The output duty cycles are calculated and updated based on this value as well. Command B stops the PWM output. Command C updates the Timer0 counter match limit, which updates the rate at which the ADC data is read in and the DAC data is output. Command D sets a flag that enables the ADC operation within the Timer0 interrupt. Command E clears a flag that disables the ADC operation within the Timer0 interrupt.

Command F fills the analog output data buffer with 500 values. These values are sent as ASCII text representation that gets converted into 10-bit binary representation for storage in the data array. Command G sets a flag that enables the DAC operation within the Timer0 interrupt. 

Command H clears a flag that disables the DAC operation within the Timer0 interrupt. The LED indicators on the evaluation board are also set and cleared to provide operational status. More commands could easily be appended to the list as needed. A sample of the command handler is shown in Listing 1.

The main() function starts by calling all set-up and initialization functions. These include the UART, PWM, DAC, ADC, and Timer0. It also lights an LED that let’s me know when the processor has initialized and is ready for operation. Following this, the main loop does nothing but poll for data arriving via the UART and calls the command processing function if the command is ready to be processed.

A nice thing about the Keil µVISION 3 IDE is the start-up configuration utility. Rather than sort through the datasheet and set up multiple registers, the configuration utility enables you just check or uncheck boxes and type in values as needed. I used this utility to set up the PLL to provide the 60-MHz clock rate.

Most of the work is done within the Timer0 interrupt. Some designers would argue that the interrupt routine should just set a flag and get back to the main routine as quickly as possible. There is not much going on in the main loop, so I felt that running the code in the interrupt would be fine. Maybe next time I’ll do it the other way just for the sake of functional upgrades over time. The ADC operation comes first. If the flag that allows this operation is set, the voltage on the pin is read and then sent to the PC via the UART. The data is appended with a \n termination character so that the receiving application knows that the data has been sent.

The DAC operation comes next. If the flag that allows this operation is set, the analog data array index is incremented to the next piece of data, which is sent through the DAC and then out the pin as a voltage. Listing 2 shows what the interrupt routine looks like.