This tutorial was extracted from Erich Styger blog http://mcuoneclipse.wordpress.com with his agreement.
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:
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 MMA8451QR1MMA8451QR1 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(),
orNeg()
for a LED:
- 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()
.
- Properties: these are static settings in the component. Things like an I2C address.
- 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:
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 MMA8451QR1MMA8451QR1 here, but this was not using a dedicated component for the accelerometer. Since then I have updated the project to use my GenericI2C component:
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 MMA8451QR1MMA8451QR1 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
/* MMA8451QR1MMA8451QR1 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:
In the wizard, I give a name for my 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:
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:
Component Details
The Component Details editor view shows (most of) the information we just have entered:
Component Details Editor View
That view can be re-opened any time with the Component Information context menu on the component itself:
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:
CTRL+S (for Save) will store the settings. A dialog will pop up:
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
Adding Properties
The MMA8451QR1MMA8451QR1 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:
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:
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:
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:
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:
- 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.
- 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’:
The term ‘Inherit to this Component’ can be very misleading (again): what it does here is defining an interface.
This triggers this 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:
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’:
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:
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:
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’:
I will notice that the interface has been added to my workspace as a folder:
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:
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.
Next, I’m verifying the settings and extend the description:
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 :
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 toInit()
.GetRaw8XYZ()
: returns the raw 8bit accelerometer values.
To add a new method, I use the context menu ‘Add Method’:
First, I configure the Init()
method:
Using the ‘Source code’ tab I switch to the implementation of this 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));
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 MMA8451QR1MMA8451QR1 register #defines.
For this I open the driver and search for BW_CUSTOM_VARIABLE_START:
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
/* MMA8451QR1MMA8451QR1 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:
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:
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:
Next to add the GetRaw8XYZ()
method:
This method requires a 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.
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):
Then I use the Open button:
Then browse to the location where the bitmap file is and then open that file:
Now I have a cool icon for my 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:
With this, my new component shows up:
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:
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:
In the component Inspector, I see now the default I2C slave address plus the I2C Bus interface selected:
For the Slave Address, I can select one of the enumeration values I have defined earlier:
With the new component added to the project, it shows up with the three methods as defined:
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:
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:
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 : MMA8451QR1MMA8451QR1
** 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
/* MMA8451QR1MMA8451QR1 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 MMA8451QR1MMA8451QR1)
**
** 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 MMA8451QR1MMA8451QR1)
**
** 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 MMA8451QR1MMA8451QR1)
**
** 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
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 MMA8451QR1MMA8451QR1 component is here. A ‘Getting Started’ on CDE can be found here. Additionally have a look at the Freescale CDE Home Page.