Tutorial: Creating a Processor Expert Component for an Accelerometer

If you are a frequent reader of this blog, then you know: I’m a big fan of Processor Expert components. While there are many Processor Expert components delivered with CodeWarrior, it lacks many components and device drivers beside of the normal on-chip peripherals. But value gets added to an embedded project with all the external devices, sensors and actuators. That’s why I have created many more components which are available on my GitHub site. Readers of this blog have asked several times to create a tutorial on how to create a Processor Expert component. So why not working on that on a long Easter weekend full of cold rain and snow?

So here we go: a tutorial how to create a Processor Expert component for the MMA8451Q accelerometer found on the FRDM-KL25Z board:

MMA8451Q Accelerometer on the FRDM-KL25Z Board

MMA8451Q Accelerometer on the FRDM-KL25Z Board

Warning

This tutorial is hard-core, with tips and tricks to work around some issues you might meet. But once you through the traps and pitfalls, creating component can be very addictive. You have been warned :-). Developing Processor Expert component at least in the current stage of the Eclipse based CDE (Component Development Environment) is not the simplest thing in the world. But very rewarding once you master it.

💡 There exists the non-Eclipse ‘classic’ BeanWizard in CodeWarrior for MCU10.2. This BeanWizard is much easier to use in my view, but not available in MCU10.3 any more, and has been replaced by the Eclipse based one I’m showing here. The good thing with the Eclipse based one is that there is a free ‘Community Edition’ license (see below), while the BeanWizard requires a CodeWarrior Professional Edition License. It is possible to use the classic BeanWizard as well within MCU10.3. If there is interest about trying this out, post a comment and I consider writing a post about how to use the BeanWizard in MCU10.3. 🙂 On the other side: every new tool (and especially development method) requires a learning phase, and Freescale is constantly improving the CDE for Processor Expert.

Overview

In this tutorial I’m creating a simple driver for the Freescale MMA8451Q accelerometer. The MMA8451Q is a cool accelerometer with a lot of features, and connected with a I2C bus to the microcontroller. I need that driver for my lecture project, so this is a ‘real’ thing. As such, I’m documenting things as I go, and I plan to frequently update and extend that component. So I plan to post more tutorials.

Processor Expert Component Development Environment (CDE)

Processor Expert is using ‘components’ to generate software and drivers. While CodeWarrior comes with many components, it is possible to create your own components. The components are written in a ‘C-like’ scripting language.

I’m not explaining every concept behind components (see this link as a starting point for other documentation provided by Freescale), as this would be too much as a starter. So here just a few basic concepts and terms:

  • Methods: These are like normal C functions. An example would be something like ReadAccelerometerValue(), or Neg() for a LED:

    LED Methods

    LED Methods

  • Events: This are callback which can be called by the component in an asynchronous way. It is a way to notify the application. An example would be OnFreefallDetected() or OnError().

    GenericI2C Events

    GenericI2C Events

  • Properties: these are static settings in the component. Things like an I2C address.

    I2C_LDD Properties

    I2C_LDD Properties

  • Inheritance and Interface: It is possible to re-use another component, either ‘incorporating’ it or to interface with it. For example the LED component inherits from the BitIO component to do low-level bit I/O operations:

    Inherited Component

    Inherited Component

The create a component for Processor Expert component, I use the ‘CDE’ (Component Development Environment which is part of CodeWarrior for MCU and the Driver Suite (e.g with IAR). In the past an expensive (Professional) license was required to create Processor Expert components. Recently Freescale has made a ‘Community Edition’ license available which is free of charge for open source/non-commercial components. See this link for details. A time bombed license file is available here on this page.

💡 Future updates of CodeWarrior, Processor Expert and Driver Suite very likely have this community edition license already integrated.

Starting Point

I already wrote a tutorial how to use the MMA8451Q here, but this was not using a dedicated component for the accelerometer. Since then I have updated the project to use my GenericI2C component:

Project with GenericI2C

Project with GenericI2C

💡 The reason why I use the GenericI2C component is this: I want to have my software and components working both for devices having LDD (Logical Device Drivers, e.g. for Kinetis) and non-LDD devices (like S08 and ColdFire). The LDD concept in Processor Expert has been very disruptive, and only the recent CodeWarrior for MCU10.3 release has improved the software compatibility. Still, I need an extra software layer for I2C. Painful, but necessary for now. But the advantage is: I can use all my I2C based sensors immediately with my GenericI2C component, independent of the driver architecture Freescale offers me: the power of re-using software 🙂

Starting Point

It is a good idea to have something working as normal C files as starting point. This makes transformation of the driver into a component much easier. For this tutorial, I have the MMA8451Q working with this simple driver interface:

/*
 * MMA8451.h
 *
 *  Created on: Mar 30, 2013
 *      Author: Erich Styger
 */

#ifndef MMA8451_H_
#define MMA8451_H_

#include "PE_Types.h"

uint8_t MMA8451_GetRaw8XYZ(uint8_t xyz[3]);

uint8_t MMA8451_Deinit(void);

uint8_t MMA8451_Init(void);

#endif /* MMA8451_H_ */

The driver implementation looks like this:

/*
 * MMA8451.c
 *
 *  Created on: Mar 30, 2013
 *      Author: Erich Styger
 */
#include "MMA8451.h"
#include "GI2C1.h"

/* External 3-axis accelerometer control register addresses */
#define MMA8451_CTRL_REG_1 0x2A
/* MMA8451 3-axis accelerometer control register bit masks */
#define MMA8451_ACTIVE_BIT_MASK 0x01
#define MMA8451_F_READ_BIT_MASK 0x02

/* External 3-axis accelerometer data register addresses */
#define MMA8451_OUT_X_MSB 0x01
#define MMA8451_OUT_X_LSB 0x02
#define MMA8451_OUT_Y_MSB 0x03
#define MMA8451_OUT_Y_LSB 0x04
#define MMA8451_OUT_Z_MSB 0x05
#define MMA8451_OUT_Z_LSB 0x06

#define MMA8451_I2C_ADDR   (0x1D) /* SA0=1 */
//#define MMA8451_I2C_ADDR   (0x1C) /* SA0=0 */

uint8_t MMA8451_GetRaw8XYZ(uint8_t xyz[3]) {
  static const uint8_t addr = MMA8451_OUT_X_MSB;

  return GI2C1_ReadAddress(MMA8451_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &xyz[0], sizeof(xyz));
}

uint8_t MMA8451_Deinit(void) {
  return ERR_OK; /* nothing to do */
}

uint8_t MMA8451_Init(void) {
  static const uint8_t addr = MMA8451_CTRL_REG_1;
  static const uint8_t data = MMA8451_F_READ_BIT_MASK|MMA8451_ACTIVE_BIT_MASK;
  /* F_READ: Fast read mode, data format limited to single byte (auto increment counter will skip LSB)
   * ACTIVE: Full scale selection
   */
  return GI2C1_WriteAddress(MMA8451_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), (uint8_t*)&data, sizeof(data));
}

And I’m using it like this:

/*
 * Application.c
 *
 *  Created on: Mar 30, 2013
 *      Author: Erich Styger
 */

#include "Application.h"
#include "MMA8451.h"
#include "LED1.h"
#include "LED2.h"
#include "LED3.h"

void APP_Run(void) {
  uint8_t res=ERR_OK;
  uint8_t xyz[3];

  LED1_On();
  LED2_On();
  LED3_On();
  res = MMA8451_Init();
  while (res==ERR_OK) {
    res = MMA8451_GetRaw8XYZ(&xyz[0]);
    LED1_Put(xyz[0]>50);
    LED2_Put(xyz[1]>50);
    LED3_Put(xyz[2]>50);
  }
  LED1_Off();
  LED2_Off();
  LED3_Off();
}

I’m going now to create a Processor Expert driver for it.

Creating an Embedded Component Project

To create a new component, I select the menu File > New > Embedded Component Project:

New Embedded Component Project

New Embedded Component Project

In the wizard, I give a name for my component:

Name for New Component

Name for New Component

💡 Choosing a good name is important. It is a good idea not to select a name which is not already used, as Processor Expert cannot handle different components with same name. I have found this out the hard way when I created my LED component, not knowing that Freescale has a LED component for the DSC microcontroller family. Additionally, the component name will used as Eclipse project folder name in workspace. As it is not possible to have multiple projects with the same name in the workspace, better to select a component name not producing a conflict. Alternatively a dedicated Eclipse workspace for components can be used. And it will not be easy to change the name of the component afterwards.

Pressing next, and I can enter the information for my component:

New Component Information

New Component Information

I do not need to worry much about the entries, as I can change them later on.

💡 the ‘Shortcut’ will be used in my driver as prefix (plus a number) for the methods and events (e.g. MMA1_OnError()). With this in mind, it is a good idea to keep it to 3 to 4 characters only.

Pressing Finish will create the component project in my workspace:

MMA8451Q Component Created

MMA8451Q Component Created

Component Details

The Component Details editor view shows (most of) the information we just have entered:

Component Details Editor View

Component Details Editor View

That view can be re-opened any time with the Component Information context menu on the component itself:

Component Information Context Menu

Component Information Context Menu

💡 To edit an item in the Component, simply use either the context menu or double-click on it to open an editor view.

A ‘*’ mark in the view shows me that the settings have not been saved yet:

Dirty Editor Marker

Dirty Editor Marker

CTRL+S (for Save) will store the settings. A dialog will pop up:

Save Dialog

Save Dialog

💡 This dialog will be very annoying. Luckily it is possible to switch it off. For this I use the menu Window > Preferences > Processor Expert > Component Development and switch it off:

Disabled Save Dialog

Disabled Save Dialog

Adding Properties

The MMA8451Q can have two different I2C addresses: either 0x1D or 0x1C.

I want the user to select the address from a drop-down (enumeration list), so first I add a new Enumeration Property Type with the context menu:

Adding Enum Property Type

Adding Enum Property Type

Then I specify a name and add (‘Add Item’ button) two different enumeration values. The ‘Item Name’ is what the user will see in the drop-down list:

Defined Enumeration Property Enumeration

Defined Enumeration Property Enumeration

💡 I explicitly set the ‘Item Value’ to a value I can use later on. That Item Value is technically a string type, but I can use it ‘as is’. You will see later on how this works.

Save it with CTRL-S.

Next step is to add the property itself with the context menu:

Adding Property

Adding Property

For the property, I specify that this is an Enumeration, give it a name (this will be visible to the user). The Symbol name is what I will use in my code. As type I specify the enumeration type I just have defined with its initial Value:

Slave Address Property Settings

Slave Address Property Settings

Save the settings with CTRL-S.

Inherited Component (Interface)

For my accelerometer, I need to talk to it using the I2C protocol. So I need to interface (or inherit) to such an I2C component. In my case this is the GenericI2C component.

There are two ways how I can inherit or share a base component:

  1. Inherited component (interface): With this, the component I inherit from will be part of my component. A typical case is the LED example from above where the BitIO component is ‘inside’ the LED component, and every access to the BitIO component goes through the LED component.
  2. Link to component: here I have an interface to the component with a ‘link’. That inherited component is not ‘inside’ my component, but ‘outside’. This means that other components can inherit from it too.

❗ Dealing with interfaces is probably the most difficult part in CDE. Messing things up means you can really screw up your component. Better you explore things slowly, and do regular backups of your component.

I want to interface (or inherit from) the GenericI2C component. But as there might be other components which need to inherit from it, I use the ‘Link to component‘ way.

❗ The way how Processor Expert is using ‘inheritance’ and the terms around this topic are ‘non-standard’, and this can be very confusing, as the inheritance schemes and details are different from other object-oriented terminology.

In order to ‘inherit’ (well, ‘link to’), I need first to define the ‘interface‘. The interface is nothing more than basically defining the method and event interface to what I want to interface to. For this I select ‘Inherit to this Component’:

Inherit to this Component

Inherit to this Component

❗ The term ‘Inherit to this Component’ can be very misleading (again): what it does here is defining an interface.

This triggers this dialog:

Confirmation dialog

Confirmation dialog

❓ Not sure why this dialog even shows up if my component settings are all saved?

Then, in the following dialog I select the GenericI2C component:

Inheritance Wizard

Inheritance Wizard

❗ Note the warning in the dialog header. This is because I inherit from GenericI2C, but I use a different identifier (I2C) for my interface. The reason is that if I’m not doing this, CDE will create a global interface for me, which I definitely do not want and need. I need a local interface to a global component. This was supported out of the box in the old classic BeanWizard, but the Eclipse based only supports this with the changes I’m doing in this step and below. I want to have my interface named ‘I2C’ (to have it generic), and I want to have the GenericI2C assigned as template. More on this in the next steps.

Pressing Next will get me to a dialog where I can specify the type of inheritance. As I want to share the GenericI2C component, I select ‘shared usage’:

Shared usage

Shared usage

Next, I can specify which methods and events I want to use: I select ‘Inherit: Yes’ for ReadAddress() and WriteAddress(), as I want them to be used from my component:

Interface definition

Interface definition

💡 I don’t need to worry too much about the interface definition in this dialog. I can change things at a later stage. With this, I even can not inherit anything here, and change my mind later on.

Pressing next gets me to the next dialog:

Multiple Inheritance

Multiple Inheritance

This introduces another concept: multiple Inheritance. Similar to the concepts above, this is probably not the same what you would typically understand under ‘multiple inheritance’ in object-oriented languages. What it means here is that you can interface to different components. For simplicity, I keep the settings (as I can change things later) and press Next.

In the next dialog, I cannot change anything, so time now to press ‘Finish’:

Select programming language

Select programming language

I will notice that the interface has been added to my workspace as a folder:

Interface added to Workspace

Interface added to Workspace

❗ The fact that the interface has been added as a folder into my workspace has the consequence that I cannot have multiple interfaces with the same name inside my workspace, which is a problem, as I want to have interfaces like MMA8451Q\GenericI2C and e.g. RTC3232\GenericI2C. Because it would be the same interface name (even for different components), this is not supported with this CDE approach. As a workaround I use different workspaces.

Property for the Interface

I want to be able to select my newly created interface as a property in my component. For this, I could a new property if CDE has not already added one:

Adding new Property for Link to Component

Adding new Property for Link to Component

But CDE should already added the property if you followed the above steps. If not, use the ‘Add Property’ context menu as shown in the previous screenshot.

Added Property for Inherited Component

Added Property for Inherited Component

Next, I’m verifying the settings and extend the description:

Link to Component Setting

Link to Component Setting

The ‘Item Name’ is what will be shown in the user interface, while the ‘Symbol’ is what I will use in my code. As InterfaceName I select the just created interface which shows up under my Component name (MMA8451Q\I2C.int).

Assigning Template to Inherited Interface

Remember the above step where I decided to use ‘I2C’ instead of ‘GenericI2C’? This means, that I have an interface named ‘I2C’, and now need to assign a ‘Template’ to it so Processor Expert knows which components are ‘compatible’ with it.

💡 The fact that I need to register a template to an inherited interface is problematic. It means that without assigning a template of a ‘yet-to-built’ component, I can not interface with it. At least this is what happened to me: If I do not register a template, I cannot use it as interface. For example if I would implement another ‘GenericI2C_Other’ component, even if the interface matches, without having it assigned as template to the interface I cannot use it. And I need to be careful not to use a local template (within the component), because then I cannot select a global component for my interface. The best way is always to choose an interface name which is not likely to conflict with a component name.

So I’m going to register the GenericI2C component as template to the interface. For this I open the interface file (*.int) inside the component structure and search for :

Interface file open in text editor

Interface file open in text editor

Then replace the I2C template with the GenericI2C one:

  <Registration>
    <Template>GenericI2C</Template>
  </Registration>

Later, if you want to allow more components to interface with your component, simply add extra Template lines within the block.

💡 It is possible to register a template to an interface with the CDE GUI too: for this I would need to import the interface, and then register the template. But this will create an interface project folder in my workspace, and for whatever reason somehow my interfaces and templates got screwed up. So at least to me just using a text editor was faster and worked always :-).

Adding Methods

Now I’m going to the following methods to my driver:

  • Init(): Initialize the driver, allocates any needed memory data structure.
  • Deinit(): Counterpart to Init().
  • GetRaw8XYZ(): returns the raw 8bit accelerometer values.

To add a new method, I use the context menu ‘Add Method’:

Adding Method

Adding Method

First, I configure the Init() method:

Init Method

Init Method

Using the ‘Source code’ tab I switch to the implementation of this method:

Source Code of Init Method

Source Code of Init Method

Next, I copy my existing driver code into the block after %CODE_BEGIN:

static const uint8_t addr = MMA8451_CTRL_REG_1;
static const uint8_t data = MMA8451_F_READ_BIT_MASK|MMA8451_ACTIVE_BIT_MASK;
/* F_READ: Fast read mode, data format limited to single byte (auto increment counter will skip LSB)
* ACTIVE: Full scale selection
*/
return GI2C1_WriteAddress(MMA8451_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), (uint8_t*)&data, sizeof(data));
Copied Driver Init Code

Copied Driver Init Code

❗ Only make changes between %CODE_BEGIN and %CODE_END, unless you know exactly what you are doing!

Wait, something is not ok. I’m have spent so much time above for my I2C interface, so I better use it ;-). To use an inherited interface method, the following syntax is used:

%@InterfaceName@'ModuleName'%.MethodName

With this, I’m changing my return statement to

return %@I2C@'ModuleName'%.WriteAddress(MMA8451_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), (uint8_t*)&data, sizeof(data));

Next, I need to add the MMA8451Q register #defines.

For this I open the driver and search for BW_CUSTOM_VARIABLE_START:

Driver with custom variables start area

Driver with custom variables start area

That’s just the beginning of my driver module, so a good place for my defines I want to keep inside my implementation module:

/* External 3-axis accelerometer control register addresses */
#define MMA8451_CTRL_REG_1 0x2A
/* MMA8451 3-axis accelerometer control register bit masks */
#define MMA8451_ACTIVE_BIT_MASK 0x01
#define MMA8451_F_READ_BIT_MASK 0x02

/* External 3-axis accelerometer data register addresses */
#define MMA8451_OUT_X_MSB 0x01
#define MMA8451_OUT_X_LSB 0x02
#define MMA8451_OUT_Y_MSB 0x03
#define MMA8451_OUT_Y_LSB 0x04
#define MMA8451_OUT_Z_MSB 0x05
#define MMA8451_OUT_Z_LSB 0x06

#define MMA8451_I2C_ADDR   (0x1D) /* SA0=1 */
//#define MMA8451_I2C_ADDR   (0x1C) /* SA0=0 */

I’m adding my defines there:

defines added

defines added

But what about the I2C address defines? I have now a property in the component for this. So I can reference to the value of the property using

%SymbolName

I have used the symbol name ‘I2CSlaveAddress’, so I can change it to

#define MMA8451_I2C_ADDR   (%I2CSlaveAddress) /* I2C slave device address as set in the properties */

With this knowledge, it is easy to add the Deinit() method properties and code:

Deinit Method Properties

Deinit Method Properties

Deinit() driver source code

Deinit() driver source code

If you are a good C/C++ programmer, you probably have spotted a bug in CDE for the above driver code: there is no ‘void’ in the method parameter list :-(.

In C, the following

void foo();

is not the same as

void foo(void);

The first declaration does not declare any parameters (so it could be zero, or one parameter, or any number of parameter), while the second version with ‘void’ defines the interface that there are no parameter. While the ‘classic’ BeanWizard properly uses (void) for a method without parameters, this is wrong in CDE for MCU10.3. To fix this, I edit the .drv sources and add the void to it, both for the declaration and the implementation:

Fixed Driver Code Declaration

Fixed Driver Code Declaration

Fixed Driver Code Definition

Fixed Driver Code Definition

Next to add the GetRaw8XYZ() method:

GetRaw8XYZ Method Properties

GetRaw8XYZ Method Properties

This method requires a parameter:

Added Parameter

Added Parameter

❓ This translates into ‘uint8_t *xyz’ which is not exactly the same as ‘uint8_t xyz[3]’. The classic BeanWizard has the ability to specify parameters of any kind, while the Eclipse based CDE misses that capability. While it would be possible to define a custom type, I’m not going down that road here.

GetRaw8XYZ() Method Source Code

GetRaw8XYZ() Method Source Code

  static const uint8_t addr = MMA8451_OUT_X_MSB;

  return inherited.I2C.ReadAddress(MMA8451_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &xyz[0], 3);

Changing Icon

Our shiny component only will look professional, if it has a nice icon :-). It is possible to create a custom icon for it, as long it is a 16×16 pixel bitmap file.

❗ Note: the pixel at (0,0) defines the transparent background color. See this post.

I can create a new icon (16×16 pixels). The easiest way is to copy an existing one (e.g. from my GitHub repository) and modify it with Paint or any other Windows Bitmap program.

I recommend to place the component icon bitmap file into the Beans folder of the component, with the same name as the component (MMA8451Q.bmp):

MMA8451Q Component Icon

MMA8451Q Component Icon

Then I use the Open button:

Open for a new Icon

Open for a new Icon

Then browse to the location where the bitmap file is and then open that file:

❗ Note: select *.bmp as filter.

MMA8451Q Bitmap File

MMA8451Q Bitmap File

Now I have a cool icon for my component:

Updated Icon for Component

Updated Icon for Component

❗ There is bug in the current CDE (at least in CodeWarrior for MCU10.3): the user icon is not shown in the Components Library view. It still shows the default user one. The reason seems to be that the bitmap conversion/settings are not stored properly. I still have the ‘classic’ BeanWizard, and with this one I’m able to convert and set the bitmap correctly.

Trying it out

So far my Components Library view is not showing my new component: I need first to refresh the list:

Refresh Components

Refresh Components

With this, my new component shows up:

MMA8451Q in Component Library

MMA8451Q in Component Library

💡 In case the component shows up with the default/blue icon, then this is probably the Icon problem I have described above. Converting/setting the Icon with the classic BeanWizard works.

I double-click on the component to add it to my project:

Creating new Component

Creating new Component

Then it will ask me either to create a new shared component for I2C, or to use an existing one. As I already have a GenericI2C component in my project, I can select the existing one:

Selecting Shared Component

Selecting Shared Component

In the component Inspector, I see now the default I2C slave address plus the I2C Bus interface selected:

Component Inspector

Component Inspector

For the Slave Address, I can select one of the enumeration values I have defined earlier:

Drop Down with Predefined Enumeration Values

Drop Down with Predefined Enumeration Values

With the new component added to the project, it shows up with the three methods as defined:

New Component with Methods

New Component with Methods

There is one problem: sometimes the methods are marked with an ‘x’. This means they are disabled. I use the context menu to enable them:

Toggle to Enable the Method

Toggle to Enable the Method

❗ I believe this is a bug in CDE in MCU10.3, as I feel I have my settings correct, and it works as expected with the classic BeanWizard.

With this, all my methods are enabled:

All Methods enabled

All Methods enabled

Generated Code

Time to inspect the generated code:

/** ###################################################################
**     THIS COMPONENT MODULE IS GENERATED BY THE TOOL. DO NOT MODIFY IT.
**     Filename    : MMA1.c
**     CDE edition : Standard
**     Project     : ProcessorExpert
**     Processor   : MKL25Z128VLK4
**     Component   : MMA8451Q
**     Version     : Component 01.003, Driver 01.00, CPU db: 3.00.000
**     Compiler    : GNU C Compiler
**     Date/Time   : 2013-03-31, 20:24, # CodeGen: 18
**     Abstract    :
**
**     Settings    :
**     Contents    :
**         Init       -
**         Deinit     -
**         GetRaw8XYZ -
**
**     License : Open Source (LGPL)
**     Copyright : (c) Copyright Erich Styger, 2013, all rights reserved.
**     http://www.mcuoneclipse.com
**     This an open source software in the form of a Processor Expert Embedded Component.
**     This is a free software and is opened for education, research and commercial developments under license policy of following terms:
**     * This is a free software and there is NO WARRANTY.
**     * No restriction on use. You can use, modify and redistribute it for personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
**     * Redistributions of source code must retain the above copyright notice.
** ###################################################################*/

/* MODULE MMA1. */

#include "MMA1.h"

/* External 3-axis accelerometer control register addresses */
#define MMA8451_CTRL_REG_1 0x2A
/* MMA8451 3-axis accelerometer control register bit masks */
#define MMA8451_ACTIVE_BIT_MASK 0x01
#define MMA8451_F_READ_BIT_MASK 0x02

/* External 3-axis accelerometer data register addresses */
#define MMA8451_OUT_X_MSB 0x01
#define MMA8451_OUT_X_LSB 0x02
#define MMA8451_OUT_Y_MSB 0x03
#define MMA8451_OUT_Y_LSB 0x04
#define MMA8451_OUT_Z_MSB 0x05
#define MMA8451_OUT_Z_LSB 0x06

#define MMA8451_I2C_ADDR   (0x1D) /* I2C slave device address as set in the properties */
/*
** ===================================================================
**     Method      :  MMA1_GetRaw8XYZ (component MMA8451Q)
**
**     Description :
**         Returns in an array the x, y and z accelerometer as 8bit values.
**     Parameters  :
**         NAME            - DESCRIPTION
**         uint8_t xyz     - Pointer to an array of three unsigned 8bit
**                           values which are used to return the accelerometer
**                           values.
**     Returns     :
**         uint8_t         -
** ===================================================================
*/
uint8_t MMA1_GetRaw8XYZ(uint8_t *xyz)
{
  static const uint8_t addr = MMA8451_OUT_X_MSB;

  return GI2C1_ReadAddress(MMA8451_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &xyz[0], sizeof(xyz));
}

/*
** ===================================================================
**     Method      :  MMA1_Deinit (component MMA8451Q)
**
**     Description :
**         Counterpart to Init() method.
**     Parameters  :
**         NAME            - DESCRIPTION
**     Returns     :
**         uint8_t         -
** ===================================================================
*/
uint8_t MMA1_Deinit(void)
{
  return ERR_OK; /* nothing to do */
}

/*
** ===================================================================
**     Method      :  MMA1_Init (component MMA8451Q)
**
**     Description :
**         Initializes the device driver
**     Parameters  :
**         NAME            - DESCRIPTION
**     Returns     :
**         uint8_t         -
** ===================================================================
*/
uint8_t MMA1_Init(void)
{
  static const uint8_t addr = MMA8451_CTRL_REG_1;
  static const uint8_t data = MMA8451_F_READ_BIT_MASK|MMA8451_ACTIVE_BIT_MASK;
  /* F_READ: Fast read mode, data format limited to single byte (auto increment counter will skip LSB)
   * ACTIVE: Full scale selection
   */
  return GI2C1_WriteAddress(MMA8451_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), (uint8_t*)&data, sizeof(data));
}

/* END MMA1. */

/*
** ###################################################################
**
**     This file was created by Processor Expert 10.0 [05.03]
**     for the Freescale Kinetis series of microcontrollers.
**
** ###################################################################
*/

The code looks fine so far.

❓ You might notice that the return ‘hints’ have not been added to the comments. Not sure why CDE does not handle this properly, as I have specified the hints text in the method properties?

I can now change my Application.c to use my new driver generated by the component:

/*
 * Application.c
 *
 *  Created on: Mar 30, 2013
 *      Author: Erich Styger
 */

#include "Application.h"
#if 0
#include "MMA8451.h"
#else
#include "MMA1.h"
#endif
#include "LED1.h"
#include "LED2.h"
#include "LED3.h"

void APP_Run(void) {
  uint8_t res=ERR_OK;
  uint8_t xyz[3];

  LED1_On();
  LED2_On();
  LED3_On();
#if 0
  res = MMA8451_Init();
#else
  res = MMA1_Init();
#endif
  while (res==ERR_OK) {
#if 0
	res = MMA8451_GetRaw8XYZ(&xyz[0]);
#else
	res = MMA1_GetRaw8XYZ(&xyz[0]);
#endif
    LED1_Put(xyz[0]>50);
    LED2_Put(xyz[1]>50);
    LED3_Put(xyz[2]>50);
  }
  LED1_Off();
  LED2_Off();
  LED3_Off();
}

Build, download and run. And it works 🙂

Application running with new Component Code

Application running with new Component Code

Summary

If you are still reading this: Congratulations! You are a Component Warrior and you made it up to here :-). Seriously, things look very complicated at the beginning, and CDE development requires a learning curve, similar to learning a new language and tools. But as you maybe imagine with the components I have developed, it very well pays off. And with the outlook that things likely get easier and simpler in the future, the future is bright for Processor Expert Component development. 🙂

Sources and further reading

The CodeWarrior project used in this tutorial is available here, and the MMA8451Q component is here. A ‘Getting Started’ on CDE can be found here. Additionally have a look at the Freescale CDE Home Page.

Happy Componentizing 🙂

Advertisements

69 thoughts on “Tutorial: Creating a Processor Expert Component for an Accelerometer

  1. Hello Erich,

    When you create a new component, the wizard tool, in component type, shows an item named RTOS component, but it is always disabled. Do know about it?

    Like

    • Hi Juan,
      this option is to create an RTOS component, similar to what I did with FreeRTOS. The ability to create an RTOS component is not included in the free-of-charge community license for CDE.

      Like

  2. Hey Erich, nice article! Definitely ‘hard-core’ but very digestible nevertheless! I don’t know if you have any back-end web development experience, but a lot of this resonates with me in terms of how server side scripting / templating languages work – except in this case we’re generating C instead of HTML. Pretty neat, thanks.

    Like

  3. Hello Erich, I use the CodeWarrior 10.3 and there were a few recent updates. Things are a little different from this latest update.

    For example:
    When generating the interface is not named ‘I2C.int’ but ‘GenericI2C.int’ and I have to manually rename it so that everything works properly.

    About this latest update there appeared new macros in the Processor Expert View.

    Like

      • Sorry for the delay, I forgot to turn on notifications for this post. :s
        Here is a picture of what I mean:

        Like

        • Oh, now I see. The PDD’s have been added to Processor Expert with the latest update. To my understanding these are kind of low level macros in order to access low level functionality with Processor Expert. I have not found out how to make this work. It seems I need to include a header file or something. I see if I can find out.

          Like

  4. Hi, I still using the codewarrior version 6.3, and I will like to see how you create a component with this version, thanks

    Like

    • Hi braulio,
      do you have a Professional CodeWarrior license? If so, you can launch it with the menu Processor Expert > Component Wizard (or BeanWizard). The concepts are the same, only the UI is different.

      Like

  5. Erich,
    That was a great post. I attempted to create a component for the HC-SR04 (ultrasonic range finder), but had some issues when I got to the part where I was creating the events. I am not sure how to tie them back to the events from the timer unit. Could you please help me with this (or update this and or the HC-SR04 tutorial post)?

    Thanks

    Like

  6. Hello Erich, I have no experience with github but I want to to collaborate with the creation of components. I’ve created a component and I would like to know what is the procedure to upload it to the repository and the requirements it should have.

    Like

      • I created a PID that works with float variables and with which you can specify the type of output variable. I could not put the icon I did for it, by the reason you mentioned above. Give an email where I can send it to you, so you can check it and give me some suggestions.

        Like

  7. Pingback: Extended Driver for the MMA8451Q Accelerometer | MCU on Eclipse

  8. Pingback: How to use MCUonEclipse GitHub without Git | MCU on Eclipse

  9. Pingback: Using the FRDM-KL25Z as a USB Mouse Device | MCU on Eclipse

  10. Pingback: Processor Expert in Eclipse Generating code for L-series microcontrollers >> Karibe

  11. Hi Erich, could you share some bean project to understand how to create it? I can´t open any bean you that created I don´t know why. I tried to create one but return error when using it.

    Like

  12. Pingback: DIY: Changing Processor Expert Components | MCU on Eclipse

  13. Just an FYI, there is a link typo for your GitHub acct in the posting in the following section:

    …actuators. That’s why I have created many more components which are available on my GitHub site. Readers….

    Like

  14. Hi, I have this error:
    “Either LDD or nonLDD interface needs to be defined” GI2C1 Processor Expert Problem
    I can not fix it!
    do you know how can i fix it?

    thanks so much!!

    Like

    • In the GI2C1 component (use the component inspector), there you have to enable either ‘non-LDD I2C’ or ‘LDD I2C’ and configure it. If you are using Kinetis, then you probably want to use the ‘LDD I2C’ option.
      You can download one of my projects from GitHub to see how it is used?

      Like

  15. Hi Erich! thank you very much! how about a tutorial for an SPI accelerometer, isn’t easy as I2C, I already tried with your tutorial for the w5100 but it’s diferent… :/ what do you think?

    Like

    • Hi Diego,
      I do not have an SPI based accelerometer, so that does not make much sense for me. Just curious: why do you want (need) an SPI interface to it? I2C so much easier and flexible. SPI only would be better if you need to transmit a lot of data in a very small time, which typically is not the use case for an accelerometer.

      Like

  16. Hi Erich, thanks for yet another great blog / tutorial. Your blog has been critical to my ability to learn about these Freescale processors, which I am very new to. I made it through this awesome tutorial and I believe I was able to understand the concepts, but at the very end my new component wouldn’t generate code. This was due to a missing configuration in PE. In the GI2C1 component that gets referenced, I have to select non-LDD I2C or LDD I2C. If I pick non-LDD I2C, there are three options: 1) New component [GenericSWI2C], 2) New component [InternalI2C], and 3) New component [SW_I2C]. If I click LDD I2C (which I assume I need for Kinetis), then I only have one option, New component [I2C_LDD]. Can you provide insight into what those four options mean, and the differences between the non-LDD selections?

    Like

  17. Hello Erich,

    I would like to improve one of your components, and I understand on how creating new components work. My problem is probably something very silly and simple to solve, but I cannot find the right way to do it: I do not know how to import one of your components from GitHub to Codewarrior 10.6, so I can modify it and create a new version.

    I have downloaded the whole github PE repository in a zip file. Could you provide a step-by-step guide to import onw single component to CW in a way that I can modify it using the CDE?

    Thanks

    Antonio

    Like

    • Hi Antonio,
      many thanks for your offer. You can import a component using File > Import > Component Development Environment > Import Component/Interface. However, I have put a warning here: I’m currently *not* using the Eclispe based component development (CDE) environment: I still use the ‘classic’ BeanWizard which was part of CodeWarrior for MCU10.x/classic CodeWarrior. It is a standalone editor/environment, unfortunately not free (I have a professional Edition of CodeWarrior 10.2 which included the license for that BeanWizard). So you can edit/change the components with the new Eclispe based CDE, but the files will be very much different than the ones of the BeanWizard. I’m still using the old BeanWizard because this one is much, much easier and faster to use, and has less issues. So be free to use the Eclipse based CDE wizard, but if the changes are not easy to integrate, I might not be able to merge the change back to the files on SourceForge. 😦

      Like

  18. Pingback: Processor Expert Component Repositories | MCU on Eclipse

  19. Pingback: Overview: Processor Expert | MCU on Eclipse

  20. Hi Erich,

    if you have some time can you explain your code a little bit.
    I did not understand your entire Code.
    For example this one:

    >>
    >> /* External 3-axis accelerometer control register addresses */
    >> #define MMA8451_CTRL_REG_1 0x2A
    >> /* MMA8451 3-axis accelerometer control register bit masks */
    >> #define MMA8451_ACTIVE_BIT_MASK 0x01
    >> #define MMA8451_F_READ_BIT_MASK 0x02
    >>
    >> /* External 3-axis accelerometer data register addresses */
    >> #define MMA8451_OUT_X_MSB 0x01
    >> #define MMA8451_OUT_X_LSB 0x02
    >> #define MMA8451_OUT_Y_MSB 0x03
    >> #define MMA8451_OUT_Y_LSB 0x04
    >> #define MMA8451_OUT_Z_MSB 0x05
    >> #define MMA8451_OUT_Z_LSB 0x06
    >>

    What exact are you doing here?
    I am new at programming with CodeWarrior on MCU.
    But i want learn as much and fast i can.
    So maybe you can explain me your Code.

    Best Regards
    Armend

    Like

    • Hi Armend,
      these defines are for the individual bits and device addresses. You need to read the accelerometer device data sheet so you can understand what they mean and are doing.
      I hope this helps,
      Erich

      Like

  21. Hi bro!! Thank you very much for all information you’re posting. It has been useful for me. I want to ask you for a favor, I’m going to make a proyect about RFID technology with FRDM KL25Z so i wonder if you have a component (for CodeWarriror) for RFID. I bought a module RFID-RC522 for Arduino but I want to work it with KL25Z 😀

    This is my email: abraham9132@hotmail.com

    Thanks!!
    Greetings from Mexico!

    Like

  22. Hi Erich,
    Another great tutorial! Thanks. I am wondering if you’ve ever attempted to create a CPU component? If so, how much time did it take?

    Thanks again,
    -Mike

    Like

      • That’s what I was afraid of. My intention is to use a Kinetis MKS22 part, and am trying to determine if it is a worthwhile excersise (starting with an MK22) to create a PEx component for the new micro… I think I will not have the time. I was just wondering if perhaps you had done this type of work already.

        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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.