Tutorial: ADC with the Freedom Board

Unlike other boards from Freescale, the FRDM-KL25Z has no potentiometer or analog components on it. But in many applications an ADC conversion is needed, so here we go with a tutorial reading in an external potentiometer with Eclipse, CodeWarrior and Processor Expert. For this tutorial I have a 10k Ohm linear potentiometer connected to the Freedom board:

Linear potentiometer with the FRDM-KL25Z

Linear potentiometer with the FRDM-KL25Z

💡 While this tutorial is for the Freedom KL25Z project, things are generic for any microcontroller supported by Processor Expert. Only the port/pins might be different.

The black (GND) and red (3.3V) wires are connected to the ‘full range’ connectors for the potentiometer, while the white wire is connected to the current position pin. The white wire is connected to the ‘Arduino’ A0 pin of the Freedom board:

Schematic with 10k Ohm Potentiometer

Schematic with 10k Ohm Potentiometer

Creating the Project

With CodeWarrior for MCU10.3, I create a project with the ‘New Project Wizard’ (menu File > New > Bareboard Project). I give a project name, select my microcontroller (KL25Z), connection (OpenSDA), Toolchain (gcc) and Rapid Application Development (Processor Expert).

Adding ADC Component

From the Components Library I add the ADC component to the project:

Adding ADC Component

Adding ADC Component

💡 If the Component Library view is not open, use the menu Processor Expert > Show Views.

Configuring ADC Component

With the component added, it shows with an error marker as I need to configure it first:

Added ADC Component

Added ADC Component

First, to configure the pin to be used. According to the schematics, the A0 pin is connected to ADC0_SE8/PTB0:

Selecting ADC Pin

Selecting ADC Pin

Next to configure the conversion time. For this I click the ‘…’ button:

❗ I need to click *into* the field to show the ‘…’ button.

Conversion Time Setup

Conversion Time Setup

This opens a dialog where I can specify the conversion time. I select one of the available values from the right side (e.g. double clicking on it):

Conversion Time Selection

Conversion Time Selection

💡 The Conversion Time specifies how fast the AD conversion shall be performed. This has of course an impact on the timing and quality of the conversion. For this tutorial, we simply select a timing.

Generating Code

With everything configured, I use the ‘Generate Code’ button:

Code Generation

Code Generation

The generated code ends up in the Generated_Code folder of the project:

Generated Code Folder

Generated Code Folder

In the next step, I’m going to use it in the main() inside the file ProcessorExpert.c.

Doing the Conversion

Instead of typing the code, I can drag&drop the method names to my source:

Drag and Drop of Method

Drag and Drop of Method

The method Measure() needs an extra boolean argument if it shall wait for the finish of the conversion (yes, I want to wait). And I’m not interested in the error return code, so I cast it to void:

  /* Write your code here */
(void)AD1_Measure(TRUE);
/* For example: for(;;) { } */

To get the conversion value, the method GetValue16() is used which returns the 16bit result. For the result I define a 16bit global variable:

static uint16_t value;

And do the AD conversion in an endless loop:

for(;;) {
  (void)AD1_Measure(TRUE); /* do conversion and wait for the result */
  (void)AD1_GetValue16(&value); /* get the result into value variable */
}

With this, it could look like this:

ProcessorExpert.c

ProcessorExpert.c

Build and Debug

With the menu Project > Build Project I compile my project. I press the ‘Debug’ button I download the program to the board and let it run.

💡 To watch the variable changing in the debugger while it is running, see Live View for Variables and Memory.

In the Variables View, I can see how the value changes:

Value in Variables View

Value in Variables View

Using Interrupts

So far I was waiting for the conversion to be finished with the TRUE parameter to the Measure() method. By default, the ADC component already has interrupts enabled:

Interrupts Enabled

Interrupts Enabled

If I use interrupts and do not wait for the conversion to be finished, I get notified by the OnEnd() event:

OnEnd Event

OnEnd Event

Double-Clicking on the OnEnd() method gets me to the Events.c file, where I can fill in the code:

AD1_OnEnd Hook

AD1_OnEnd Hook

To keep things simple, I set a boolean flag:

void AD1_OnEnd(void)
{
  extern volatile bool AD_finished;
  AD_finished = TRUE;
}

💡 I have marked this variable with volatile as the variable is changed in an interrupt service routine, and used the same time from the main program.  The volatile prevents the compiler to keep that variable in a register.

I add this boolean variable to my global variables in Processor Expert.c:

static uint16_t value;
volatile bool AD_finished;

💡 Once things are working, consider to put that AD_finished variable declaration into a header file.

Then I change my loop to start the conversion without waiting, so I can do something else while the conversion is going on:

for(;;) {
  AD_finished = FALSE; /* reset flag */
(void)AD1_Measure(FALSE); /* AD_finished will be set to TRUE once */
while(!AD_finished) {
/* do something else here... */
}
/* AD_finished set to TRUE by the interrupt to indicate the result is ready */
(void)AD1_GetValue16(&value); /* get the result into value variable */
}

Multiple Channels

So far I was using a single AD value. But the component (and hardware) can be configured to convert multiple channels. To read in as well the A1 pin which is mapped to PTB1 I use the ‘+’ icon to add another channel:

💡 I need to click into the field to have the ‘+’ and ‘-‘ icons.

Added another channel

Added another channel

I can use the same methods as above (Measure() and GetValue16(), but as GetValue16() is using a pointer to an array of values, I need to make sure I pass the right number of items to it:

byte AD1_GetValue16(word *Values)

The component has created a #define for the number of channels for me (CHANNEL_COUNT) which I can use for my value variable:

static uint16_t value[AD1_CHANNEL_COUNT];
volatile bool AD_finished;

To the GetValue16() method, I pass the address of the first item:

(void)AD1_GetValue16(&value[0]);

With this, my code works with multiple channels.

Summary

With Processor Expert, it is not very difficult to use ADC conversion. Once familiar with the concept, it is easy to add multiple channels and to use interrupt synchronization. I do not cover here advanced features like using DMA (as not supported out oft the box with Processor Expert yet), or using different conversion modes. I think this is enough for now to get you started :razz:.

Happy ADCing 🙂

Advertisements

156 thoughts on “Tutorial: ADC with the Freedom Board

  1. Good day erich, I have a problem. I declare my variables as well
    Static uint16_t potnivel [ADC_CHANNEL_COUNT]

    Static uint16_t sensorlm35 [ADC_CHANNEL_COUNT];
    And I use them like that
    ADC_Measure (TRUE);
    ADC_GetValue16 (& potential [0]);
    Level = ((90/65535) * pot level [0]) + 10;

    This does not send me error but it does not work, what am I doing wrong? 😦

    Like

    • Hi Juan,
      I don’t see anything wrong with your code. You say it does not send you any error, but I don’t see any error handling in your code (you are not checking the return error codes?).
      But what means ‘does not work’? Your are always getting zero back from GetValue16()? And if you measure the voltage with a multimeter, what do you get?
      The other thing is: 90/65535 will be zero, dos that does not make any sense?
      I hope this helps,
      Erich

      Like

What do you think?

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 )

Google+ photo

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

Connecting to %s