## MMA8451Q Accelerometer, calculating device orientation and G forces over the 3 axis

Nowadays any “mobile” device like tablet smartphone etc, has internal accelerometers that can provide information about the orientation of the device or the G force to which the device is subjected. From that capabilities derive functions as “pedometer”, commands activated with the “shake” movement, the screen orientation and so on.

But before you use it you need to understand exactly how it works. Imagine the device placed on a perfectly flat table. If the table is not moving and is perfectly flat, it is subject only to the force of gravity, that goes from the top down. This force is a constant acceleration, of 9,81m / s down, which is equivalent to 1G: the device will indicate +1G along the axis pointing toward the center of the Earth. If that indicates +1G on the Z axis, it means that it is laying on the table, while if it indicates + 1G on the X or Y axis, it means that it is placed on the table on one side or the other. Clearly are also computed intermediate points: for example placing it on a corner but perfectly vertical, this would indicate 0,70G on an axis and on the other 0,70G! (It will not be halved but calculated using the sine or cosine of the vector).

Leaving aside the inclination, moving the device quickly towards the floor, favoring the force of gravity, for a short period probably it will indicate 0G. The device no longer detects the gravity acceleration because you are pandering it, then it actually is in weightlessness status, a bit like the zero-gravity flights organized by NASA, where a plane is being flown in nosedive to get the same effect.

But, how can a small device detect accelerations on different axes? An excerpt from a technical paper can clarify some things:

Simply, the microchip inside has microscopic plates able to flex when the device is subjected to an acceleration, the same occurs with gravity: try imagine them “hanging down.” Moving, they move away or closer to their reference surface, thus varying the electric capacity between the two surfaces, exactly as it happens in a normal mechanical variable capacitor. Replicating the same mechanism for all 3 axes that describe three-dimensional space, we can get all the information we need to derive the direction and intensity of the vector of the force that is acting on the device.

Take for example this “breakout board” with very small SMD accelerometer mounted on board. The output pins, conveniently spaced with 2.54mm, are quite clear: GND, + 3.3V, SCL and SDA for I2C interface. After connecting the corresponding pins to your control board, and specifically setting up the I2C interface depending on your editor, you can begin to communicate with the device!

First of all, in my case using CodeWarrior and Processor Expert, I set the I2C communication:

Note that I set the SCL frequency below 100kHz, although it is possible to set up to 400kHz, just to avoid any problems.

Next, I created two simple functions to send and receive bytes with the device (the standard address is 0x77) using the I2C driver interrupt function, which resets a flag ended the respective process of sending or receiving data:

```// two interrupt used to know
// when is possible to close the comm.
{
}

void I2C2_OnTransmitData(void)
{
DataTransmittedFlg = TRUE; /* Set DataTransmittedFlg flag */
}

// read one or more regs from the device
char res;
word ret;

// set the pointer to a register

// wait till the end of the trasmission
while (!DataTransmittedFlg) {}
DataTransmittedFlg = FALSE;

// read the requested number of bytes
res = I2C2_RecvBlock(data, dataSize, &ret);

// wait till the end of the communication

// end the communication
I2C2_SendStop();
}

// write a byte to the register
void I2C_WriteReg(char regaddr, char val) {
char buf[2], res;
word ret;

buf[1] = val;     // value to put in the register
res = I2C2_SendBlock(&buf, 2U, &ret); // transmit the two bytes

// wait till the end of the communication
while (!DataTransmittedFlg) {}
DataTransmittedFlg = FALSE;

// end the communication
I2C2_SendStop();
}```

Now that we have simplified the whole thing by creating two functions to communicate with the device, we can bootstrap it and for that I have analyzed the datasheet obtaining the following table:

```// setting at 1 the reset bit
I2C_WriteReg(0x2B, 0x40);

// waiting till the end of the reset function
while (reg_data & 0x40)
{
}

// disabling fast-mode to obtain 14bit resolution
I2C_WriteReg(0x2A, 0x02);
// range to +-4g
I2C_WriteReg(0x0E, 0x02;
// high resolution
I2C_WriteReg(0x2B, 0x02);
// set accelerometer as active (yellow box in the table)
I2C_WriteReg(0x2A, 0x01);```

The device was initialized with the range + -4G, therefore checking the details on the datasheet, I have found that is needed to split the raw value by 2048:

```// defining some variables
#include "math.h" // necessary for the abs() function
float g_x, g_y, g_z, g_dir;

//reading 6 bytes related to the 3 axes

// joining the 8bit of the first byte
// with the 6bits of the second byte
g_x= (((xyz[0]<<8) | xyz[1])>>2)/2048;
g_y= (((xyz[2]<<8) | xyz[3])>>2)/2048;
g_z= (((xyz[4]<<8) | xyz[5])>>2)/2048;

// with the next series of conditions is
// possible to select four orientation settings
if ((abs(g_z) < 5) && (g_x > 5) && (abs(g_y) < 4)) { g_dir = 1; }
if ((abs(g_z) < 5) && (g_x < -5) && (abs(g_y) < 4)) { g_dir = 2; }
if ((abs(g_z) < 5) && (g_y > 5) && (abs(g_x) < 4)) { g_dir = 3; }
if ((abs(g_z) < 5) && (g_y < -5) && (abs(g_x) < 4)) { g_dir = 4; }```

At this point in g_x, g_y, g_z I find the numerical value of the acceleration per axis expressed in G, example “1.0”. While in g_dir I find the rotation of orientation recommended for a possible screen, whose four values correspond to 0, 90, 180, 270 degrees. I extracted this last set of conditions from a technical document.

## How to drive an LCD with KS0108 controller

I’m involved into developing a little instrument to display graphs and numerical values with characters of various sizes. I’m pretty expert with the classic controller standard “HD44780” for alphanumeric LCDs.  But this time I need something more flexible such as a graphic LCD, with the possibility of freely control every pixel of the screen. If you are interested in the topic I really recommend to thoroughly understand the operating logic, so you can freely create high-performance graphics to suit your needs… and also obviously having fun with tech stuff!

When you choose the correct device for you application, you must consider:

• connector type
• controller chip
• dimensions in pixels
• retroillumination color
• LCD contrast regulation voltage

To briefly summarize these parameters, I chose a product that have connector holes spaced with 2.54mm as standard connectors, so I can easily pay off the cables / connectors, and make everything as flexible as a first prototype needs.

I chose the KS0108 controller; because looking online I found a lot of documentation and datasheet about it, so, i guess also a lot of support if in need.

king about the pixel size, my choice fell on the 128×64, which is internally divided into two separate controllers but with the same connections: by sending the information to the first controller i will work on the 64×64 pixels box at the top, while the second controller works on the bottom 64x64px box. For example, if i had purchased a 192×64 pixels, i would find three separate controllers. In fact the management is easier than you think, you will see below.

I will not use the backlight because I have to keep the consumption very low, but if you need it, in the datasheet the white backlight consumes much less compared to other colors (however life in hours seems less!): To be considered.

As a final point, speaking about the contrast adjustment voltage, some LCDs require a negative voltage: this becomes a problem because it’s not so easy to get a negative voltage with a prototype board if you do not have the necessary components available, thus not seems appropriate to engage a bench supply just to obtain the negative voltage in question. The model I have chose, despite this characteristic, is equipped with an internal DC / DC converter to provide the negative voltage required, simply connecting it to a contrast trimmer and then to the contrast pin… and that’s it! … Anyhow I had some trouble with the contrast because I found out, after a tedious and meticulous research that the reset pin needs to be connected to VCC through a 10kohm pull-up resistor at least, to limit the current. Initially I was driving the LCD with RST pin directly connected to VCC and this was cause of an “unstable contrast” issue.

With the availability of different FRDM_KL25Z boards I used as a programmer for ARM micro, I decided to exploit one to drive the graphic display in question. As explained in this article KL25Z as an OpenSDA programmer I first of all prepared the board so that it can be easily programmed via USB (with the J6 jumper inserted to connect the SDA clock with the clock of the onboard micro!).

Before connecting the LCD to the board I checked into their details if they are all freely controllable with digital I/O:

• CS1, CS2: to enable controller 1 or controller 2, the two half of the screen;
• DB0-DB7: pins enabled to describe the 8 bits of a byte sent to the l’LCD;
• EN: enable pin, needs to be enabled to inform the controller to receive commands or data;
• RW/DI: to set the communication mode (reading, writing, command);
• RST: reset pin, needs to be high level (5v) to enable the LCD controllers;
• Vee: LCD contrast, need to be connected to Vo through a trimmer, see below;
• Vo: Voltage ouput from the internal DC/DC converter.

Then I have connected the LCD to the board checking the KL25z micro datasheet if some pins are open drain/collector (in that case to obtain a high logic level is necessary to add a pull-up resistor) or, as in the case of pin “PTD1” being in common with the RGB LED mounted on the board … I would avoid these mistakes if possible.

In this scheme you can see all the necessary connections, but keep in mind the pullup resistor on the RST pin. I recommend: first of all make sure that your Vcc voltage does not exceed the limits specified by the LCD datasheet, and then double check if you have properly connected all the pins, otherwise you risk to irreparably compromise the LCD! At this point I just have to write down some code! Without going into specific detail of CodeWarrior with ProcessorExpert and arm-gcc compiler, I will explain how to properly communicate with the KS0108 controller so you will be able to use it regardless of the language, compiler or mcu used.

First of all the controllers need to be initialized, and to do that we must send to each one some commands. Now we will see some code to communicate with the LCD.

In my case, using CodeWarrior, i’ve configured every pin in ProcessorExpert directing them as shown in the diagram above, and then writing two functions to set them as outputs and manage the logic levels of the single bits as needed.

```// this function sets every pin from D0 to D7 as outputs
void DATA_DIR_OUT() {
LCD_D0_SetOutput();
LCD_D1_SetOutput();
LCD_D2_SetOutput();
LCD_D3_SetOutput();
LCD_D4_SetOutput();
LCD_D5_SetOutput();
LCD_D6_SetOutput();
LCD_D7_SetOutput();
}

// this function sets every output data pin with
// the respective bit of the byte that we want to sent
void WR_DATA(char lcddata) {

LCD_D0_PutVal((lcddata) >> 1);
LCD_D1_PutVal((lcddata >> 1) & 1);
LCD_D2_PutVal((lcddata >> 2) & 1);
LCD_D3_PutVal((lcddata >> 3) & 1);
LCD_D4_PutVal((lcddata >> 4) & 1);
LCD_D5_PutVal((lcddata >> 5) & 1);
LCD_D6_PutVal((lcddata >> 6) & 1);
LCD_D7_PutVal((lcddata >> 7) & 1);
}

// send simply a little pulse through the EN pin
void send_enable() {
LCD_EN_SetVal();
Delay100us(1); // delay di 1 microsecondo
LCD_EN_ClrVal();
}

// controller selection (0-1)
//    0               1
// CS1 = 1         CS1 = 0
// CS2 = 0         CS2 = 0
void ChipSelect(bool chip)
{
if (chip == 0)
{
LCD_CS2_ClrVal();
LCD_CS1_SetVal();
}
if (chip == 1)
{
LCD_CS1_ClrVal();
LCD_CS2_SetVal();
}
}
```

The result is to transmit the byte bit by bit distributing it on pins DB0-DB7. This is called normally parallel transmission. In addition to transmitting the bits we need also to tell the controller what type of operation we are doing. Leafing through the datasheet of the LCD I found all the information needed to drive the controller.

I removed from this pattern all the other functions, to show only the interesting ones: “Display on/off” to initialize the LCD and “Write data” to send a byte. I have also divided the first row by the color of the data bits and the control bits, respecting the colors of the wiring diagram. The “EN” enable pin is missing, because the latter is very simple: first you prepare the check bits and the data bits, then a small pulse through the EN bit, to say to the LCD “ok I’m ready, listen to me”.

In summary, to activate the display must be set the RW pin to 0, the DI pin to 0, and next thing, send the BYTE “3F” followed by an ENABLE pulse:

```void InitDisplay(void)
{
DATA_DIR_OUT();
LCD_DI_ClrVal();
LCD_RW_ClrVal();
WR_DATA(0x3F);
ChipSelect(0);
}
```

Now, if we want to turn on a pixel on the screen, it would be enough to send one byte of data. But a moment … one byte? And if I want to light up a single bit? Right, but we’ll talk about later. The question now is: where would appear this pixel? We have not created any function to set the “cursor” position. Let us return then to the datasheet and then add some detail to the functions table:

So we have a command called set page that corresponds to the X axis, and a set address command that corresponds to the Y axis. Both seem to work with RW and DI to zero. Differently, set address is 0 to 63 while set page only goes from 0 to 7 (including zero, then only 8 positions). This is because on the X axis we write 8 bits at a time, our byte! Obviously, in this way we do not need 64 positions, but 64/8 or 8.

Now we can see our position functions and write function for a byte:

```// Page select (x axis divided by eight positions for 8 bit blocks)
void PageSelect(unsigned char page)
{
// RW e DI like suggested by table
LCD_RW_ClrVal();
LCD_DI_ClrVal();
// joining "B8" or 10111 like suggested by table
// with the 3 bits of the page number (0 to 7)
WR_DATA(0xB8 | page);
send_enable();
}

// row select (y axis divided by 64 positions for single bits)
void RowSelect(unsigned char row)
{
// RW e DI like suggested by table
LCD_RW_ClrVal();
LCD_DI_ClrVal();
WR_DATA(0x40 | row);
send_enable();
}
```

Done that, whe need only to send a first byte to the screen, at the 0,0px position, simply changing the main.c file:

```InitDisplay(void);  // LCD initialization
ChipSelect(0);      // obviously chip 0 selection
PageSelect(0);      // x = 0
RowSelect(0);       // y = 0
WriteByte(0xFF);    // lighting up 8 pixel
while(1);           // infinite waiting loop
```

If you did everything correctly, you’ll see a 8px line. Changing 0xFF with for example 0x01 will switch on only one pixel, while 0xAA will show alternating pixels. You can also try changing the values of PageSelect and RowSelect, to see what effect does on the pixel positions.

From this initial result you can start to develop all graphics functions such as writing characters or displaying bitmap images, but I will talk about this in the next article!

## USBDM: a nice solution to flash MCU via SWD using the FRDM-KL25Z

Turn the freedom board KL25Z in a USBDM Debugger interface allows to program various Freescale MCU and other compatible ones (look here):

• RS08
• HCS08,
• HC12,
• Coldfire V1-4 microcontrollers
• MC56F800xx Digital Signal Controllers (very limited range of devices).
• Kinetis ARM-cortex

First of all it is necessary to prepare the hardware as shown in the previous article regarding the KL25Z as an OpenSDA programmer using the P&E Micro firmware (vedi qui). Prepare the board with the necessary hardware changes, but do not load the OpenSDA firmware, follow instead these steps:

Then, when the driver is installed, open this link (check for the last version) for the USBDM software:

Start the setup and during the procedure be sure to enable the installation of the components related to your development environment (in my case Codewarrior 10.6.4), and also the programmer Stand-alone, as I prefer simplicity, or as a plan B in case the development environment is not able to integrate the required plug-ins:

When the setup is completed you just have to prepare your FRDM-KL25Z to proceed with the USBDM firmware update. Browse the default folder for installed software on your PC, you will findPGOand inside this folder the USBDM application one: inside this folder i will find “FlashImages” folder and then MKxx” referring to the micro board in the family. On my computer the full path is “C: \ Program Files (x86)\ pgo\USBDM 4.12.1.70\FlashImages\MKxx”.

Within this folder, we find the “OpenSDAvX.X.bin” file where X stands for the version available at the time. Keep this file handy!

It’s now time to connect the board to the computer with a USB cable, hold down the reset button a second or two, this will boot into bootloader mode and will appear as a USB mass storage device (Bootloader). If you have activated the internet, opening “sda_info.htm” file you can check the bootloader versions currently loaded in the flash app. However, we’re going to upgrade everything, to transform the board into a programmer “semi-universal” via SWD.

So you just need to upload the file “OpenSDAvX.X.bin” in the mass storage device, wait a few seconds, then power cycle the device. At this point, as a confirmation of the successful firmware update, Windows will warn you that “new hardware is found and USBDM drivers will be automatically (probably) loaded, and the device will be recognized as a programmer from CodeWarrior and the stand-alone flash programmer.

Be careful: with Windows 7 and Windows 10 for still unknown reasons this process failed to update the firmware of the board as last step, however, I had here a computer with Windows XP and in that case it worked immediately. This step must be done only once, so I did not study in deep this strange problem.

To check if everything is working fine, you can connect the SWD connector to the target device, plug the board to the usb port and start the stand-alone flash programmer (with my setup in “C:\Program Files (x86)\pgo\USBDM 4.12.1.70\UsbdmFlashProgrammer.exe”):

First of all, in the “Interface” tab via the “Detect” button I checked for a proper recognition of the KL25Z board detected as a SWD programmer. Next step, in the “Target” tab (rightmost image) using the “Detect Chip” function I do a quick check of the device that I have connected via SWD, in this example it is properly recognized as ID and correctly selected from the devices list.

However, initially it was not so simple, because the micro “MKV10” was not recognized, being present in the list but not fully configured. I tried to configure it manually by entering all parameters as per datasheet, but without success. I decided to contact the developer of USBDM, Peter O’Donoghue, who was by chance facing the same problem: so in less than 24 hours we have solved and now it works perfectly! Surely, with older micro or simply with more luck you will not have my same problem.

Stay tuned!

https://mcuoneclipse.com/2013/04/27/debug-external-processors-with-usbdm-and-freedom-board/

## How to use the KL25Z Freedom Board as a cheaper SWD Programmer

Having to develop a project with the Freescale Kinetis series micro, I looked on the net for the most suitable programmers using the SWD protocol (Serial Wire Debug). I didn’t like the solution of expensive programmers such as P&E Micro one’s, so I preferred the classic solution for geeks: I have discovered that is possible to turn FRDM-KL25Z (a demo platform that costs less than 20 €!) In a fast and cheap programmer with OpenSDA.

I have ordered mine from rs-components (look at this link) that ships in 24h in Italy, so the next day I was able to try it immediately. Looking to the schematics, is obviusly necessary to cut the short connection under the jumper J11, just to separate the clock of the internal micro from the external one we want to program by SWD connection:

I did it in a barbaric way, however by inserting a jumper in order to restore the connection if i need to update the on-board mcu.

It is better to prepare some files: you need to download from the website P&E Micro (click here) drivers for OpenSDA and the firmware to upgrade your KL25Z. Installed first of all the P&E Micro drivers (if they are not already on your computer), then extract from the zip “firmware apps” the MSD-DEBUG firmware for the KL25z and keep it at hand!

It’s now time to connect the board to the computer with a USB cable, hold down the reset button a second or two, this make the board boot into bootloader mode and will appear as a USB mass storage device (Bootloader). If you have an internet connection working, opening “sda_info.htm” file you can check the bootloader versions currently loaded in the flash and also the firmware application. However, we‘re going to upgrade everything, to turn the board into a programmer.

So you just need to upload the file “MDS-DEBUG-FRDM-KL25Z_Pemicro_v ***. SDA” in the mass storage device, wait a few seconds, then power cycle the device. At this point, as a confirmation of the successful firmware update, Windows will warn you that “new hardware is found and OpenSDA drivers will be automatically (probably) loaded, and the device will be recognized as a programmer from CodeWarrior.

Be careful: with Windows 7 and Windows 10 for still unknown reasons this process failed to update the firmware of the board as last step, however, I had here a computer with Windows XP and in that case it worked immediately. This step must be done only once, so I did not study in deep this strange problem.

The SWD connector used to program third-party mcu’s is the J6:

The annoying thing of this solution is the OpenSDA firmware, which verifies the CPU target every time: if you try to program a different mcu from KL25Z, CodeWarrior will return a nasty error message. However, having the need to program a different mcus, I still found a solution, even if it took me more time…. I will update with this new solution the next time!