Because the MEMS Sensor board has an Arduino compatible footprint, it means it is also hardware compatible with any of the Freescale Freedom boards. There is already code for FRDM-KL25Z that works with this sensor evaluation board, but I wanted to port it to the FRDM-KL26Z I had laying around.
There are two ways one could do this. One would be to modify the sample code written for the FRDM-KL25Z to work on the FRDM-KL26Z.
The other option would be to take the default KL26Z sample code and import in the necessary sensor code. I chose to do the latter, as I figured it’d be a little bit easier since all the clock and chip initiation would already be done for the KL26Z, and it would make this guide more generic for other Freedom boards that someone might want to use the MEMS Sensor board with.
Thus the first step was to download both the sensor board code for the FRDM-KL25Z, and the sample code for the FRDM-KL26Z, along with their associated schematics (FRDM-KL25Z and FRDM-KL26Z).
Looking at the schematics, both of the boards use the same I2C pins (I2C1 on PTE0 and PTE1) and UART pins (UART0 on PTA1 and PTA2). This will help simplify the amount of changes needed. The LED pins are different though, so I’ll need to make a note to change that in the code.
Part I: Importing Sensor Code
Looking through the sensor code, there are some I2C and sensor drivers that are used that will need to brought into the KL26Z project.
First I copied the three sensor driver folders (MAG3110, MMA8491Q, and MPL3115) in Sensor_Source_code\src\drivers to FRDM-KL26Z_Sensor\klxx-sc-baremetal\src\drivers
<html><head><title>Jive SBS</title></head>
<body><font face="arial,helvetica,sans-serif">
<b>Error</b><br><font size="-1">
An general error occurred while processing your request.
</font></font></body></html>
Then I copied the HAL I2C drivers from Sensor_Source_code\src\drivers\I2C and put them in FRDM-KL26Z_Sensor\klxx-sc-baremetal\src\drivers\i2c
<html><head><title>Jive SBS</title></head>
<body><font face="arial,helvetica,sans-serif">
<b>Error</b><br><font size="-1">
An general error occurred while processing your request.
</font></font></body></html>
The FRDM-KL26Z sample code already contains some I2C drivers in the bare-metal code, but the sensor board source files expect a slightly different API, hence the need to copy over the hal_I2C.c and hal_I2C.h files.
With those files copied over, they need to be added to the project. To make things simpler, I’m using the default “hello_world” project in IAR as a starting base. So in IAR, go to File->Open->Workspace and open up the project FRDM-KL26Z_Sensor\FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\build\iar\hello_world\hello_world.eww
Once the project is opened, you need to add the various sensor files. You do this by right clicking on a folder in the project window and selecting “Add Files”.
<html><head><title>Jive SBS</title></head>
<body><font face="arial,helvetica,sans-serif">
<b>Error</b><br><font size="-1">
An general error occurred while processing your request.
</font></font></body></html>
You can also do “Add Group…” to group similar files together, to mimic the underlying folder system. After you’ve added all the sensor device drivers and I2C drivers, it should look something like this:
<html><head><title>Jive SBS</title></head>
<body><font face="arial,helvetica,sans-serif">
<b>Error</b><br><font size="-1">
An general error occurred while processing your request.
</font></font></body></html>
Then we need to add these new directory paths to the project settings. Right click on the “hello_world_freedom” header and select “Options…”.
In the C/C++ Compiler category, scroll over to “Preprocessor” and add the paths to the four directories where these new drivers are located. Then click on “OK” to save the changes.
$PROJ_DIR$\..\..\..\src\drivers\MAG3110
$PROJ_DIR$\..\..\..\src\drivers\MMA8491Q
$PROJ_DIR$\..\..\..\src\drivers\MPL3115
$PROJ_DIR$\..\..\..\src\drivers\i2c
Part 2: Changes for Sensor Code
Now that all the files have been added to the project, the next step is to get the imported code to compile correctly. This involves adding the following #includes into the common.h file, which is found at: \FRDM-KL26Z_Sensor\FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\src\common\common.h
These #includes should go below the typedef definitions already in the file. The relevant section is below, with the part in red newly added:
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
#include "vectors.h"
#include "project.h"
#include "uart.h"
#include "hal_i2c.h"
#include "mag3110.h"
#include "mpl3115a2.h"
#include "MMA8491Q.h"
#include "terminal.h"
Also due to the use of special terminal commands, the UART initialization needs to be modified to be changed from polling (as is done by default in the FRDM-KL26Z sample code) to interrupt driven. This can be done by replacing the uart0_init function found in \FRDM-KL26Z_Sensor\FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\src\drivers\uart\uart.c with the uart0_init function in the Sensor sample code at \Sensor_Source_Code\src\drivers\uart\uart.c
void uart0_init (UART0_MemMapPtr uartch, int uart0clk, int baud)
{
register uint16 sbr;
uint8 temp;
SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;
/* Make sure that the transmitter and receiver are disabled while we
* change settings.
*/
UART0_C2_REG(uartch) &= ~(UART0_C2_TE_MASK
| UART0_C2_RE_MASK );
/* Configure the uart for 8-bit mode, no parity */
UART0_C1_REG(uartch) = 0; /* We need all default settings, so entire register is cleared */
/* Calculate baud settings */
temp = UART0_C4;
temp = (temp & UART0_C4_OSR_MASK) + 1;
sbr = (uint16)((uart0clk*1000)/(baud * (temp)));
/* Save off the current value of the uartx_BDH except for the SBR field */
temp = UART0_BDH_REG(uartch) & ~(UART0_BDH_SBR(0x1F));
UART0_BDH_REG(uartch) = temp | UART0_BDH_SBR(((sbr & 0x1F00) >> 8));
UART0_BDL_REG(uartch) = (uint8)(sbr & UART0_BDL_SBR_MASK);
/* Enable receiver and transmitter */
UART0_C2_REG(uartch) |= (UART0_C2_TE_MASK
| UART0_C2_RE_MASK);
/* Enable interrupt for uart0 */
UART0_C2_REG(uartch) |= UART0_C2_RIE_MASK;
enable_irq(UART0SE_irq_no);
}
Note that if UART0 is not being used, the other UART initialization function (uart_init) would need to be modified in the same manner to be interrupt driven.
And this point you should be able to compile the code and not have any errors. If you do, double check the path settings in the Project Options (done in Part 1) and that you made all the necessary code changes in common.h and put it at the proper place in that file.
Part 3: Board Level Changes
The next step is to change any board specific items. This would mean any I2C, UART, and LEDs that might have changed between the FRDM-KL25Z and the board being ported to. It also involves setting up the UART vector in the code properly.
LEDS:
One of the main board differences between the FRDM-KL25Z and FRDM-KL26Z is which GPIO pins are connected to the 3 color LED. By looking at the schematics, you can see how it changed:
| FRDM-KL25Z | FRDM-KL26Z |
Red | PTB18 | PTE29 |
Green | PTB19 | PTE31 |
Blue | PTD1 | PTD5 |
Thus the #defines for the GPIO need to be updated inside of \FRDM-KL26Z_Sensor\FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\src\projects\hello_world\sensors.c:
#define RED 29
#define RED_SHIFT (1U << 29)
#define GREEN 31
#define GREEN_SHIFT (1U << 31)
#define BLUE 5
#define BLUE_SHIFT (1U << 5)
#define RED_ON (GPIOE_PCOR = RED_SHIFT)
#define RED_OFF (GPIOE_PSOR = RED_SHIFT)
#define RED_TOGGLE (GPIOE_PTOR = RED_SHIFT)
#define GREEN_ON (GPIOE_PCOR = GREEN_SHIFT)
#define GREEN_OFF (GPIOE_PSOR = GREEN_SHIFT)
#define GREEN_TOGGLE (GPIOE_PTOR = GREEN_SHIFT)
#define BLUE_ON (GPIOD_PCOR = BLUE_SHIFT)
#define BLUE_OFF (GPIOD_PSOR = BLUE_SHIFT)
#define BLUE_TOGGLE (GPIOD_PTOR = BLUE_SHIFT)
The GPIO init code inside of main() will also need to be updated to initialize the correct GPIO pins:
/*
* Initialize the Red LED (PTE29)
*/
{
/* Turn on clock to PortB module */
SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;
/* Set the PTB18 pin multiplexer to GPIO mode */
PORTE_PCR29 = PORT_PCR_MUX(1);
/* Set the initial output state to high */
GPIOE_PSOR |= RED_SHIFT;
/* Set the pins direction to output */
GPIOE_PDDR |= RED_SHIFT;
}
/*
* Initialize the Green LED (PTE31)
*/
{
/* Turn on clock to PortB module */
SIM_SCGC5 |= SIM_SCGC5_PORTE_MASK;
/* Set the PTB19 pin multiplexer to GPIO mode */
PORTE_PCR31 = PORT_PCR_MUX(1);
/* Set the initial output state to high */
GPIOE_PSOR |= GREEN_SHIFT;
/* Set the pins direction to output */
GPIOE_PDDR |= GREEN_SHIFT;
}
/*
* Initialize the Blue LED (PTD5)
*/
{
/* Turn on clock to PortB module */
SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK;
/* Set the PTD1 pin multiplexer to GPIO mode */
PORTD_PCR5 = PORT_PCR_MUX(1);
/* Set the initial output state to high */
GPIOD_PSOR = BLUE_SHIFT;
/* Set the pins direction to output */
GPIOD_PDDR |= BLUE_SHIFT;
}
UART Pins:
Both the FRDM-KL25Z and FRDM-KL26Z use the same UART module (UART0) with the same UART pins (PTA1 and PTA2) and thus no changes need to be made. However if you did need to use a different UART, the pins and UART module used are defined at the bottom of freedom.h located at \FRDM-KL26Z_Sensor\FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\src\platforms\freedom.h
Also if UART0 was not used, then the uart_init function (different than the uart0_init function) as described in Part 2 would also need to be modified to have it use an interrupt-driven UART instead of polled-driven.
UART Interrupt Vector:
In isr.h, we need to change the default ISR for Interrupt vector 28 to point to the terminal ISR defined in terminal.h. Use the example of the Low Power Timer (LPT) vector that is commented out in isr.h as an example. The vector number can be found in the Reference Manual for the particular device being used, and needs to match up with the particular UART that is being used (which is UART0 in our case):
#undef VECTOR_028
#define VECTOR_028 isr_termial_RX
extern void isr_termial_RX();
I2C:
Both the FRDM-KL25Z and FRDM-KL26Z use the same I2C1 module with the same I2C pins on PTE0 and PTE1 and thus no changes are necessary for this port to the FRDM-KL26Z.
However if a change was necessary when porting some other Freedom board, the init code that needs to change is in sensors.c:
PORTE_PCR0 = PORT_PCR_MUX(6);
PORTE_PCR1 = PORT_PCR_MUX(6);
hal_i2c_init(I2C1_BASE_PTR);
Unfortunately if your board does not use I2C1 to connect to the MEMS Sensor board, the I2C module define isn’t universal across the files (like it is for the UART). Thus you’ll also need to search through the driver files and other code for all the uses of I2C1 and replace it with the correct I2C module (I2C0 and I2C2) that is being used your particular Freedom board.
Part 4: Download and Run!
The last part is trying out all the changes and making sure it works. Do one last compile and connect the FRDM-KL26Z to your computer using the OpenSDA USB port (J10). It should enumerate as a mass storage device. Drag and drop the SREC file created in \FRDM-KL26Z_SC_Rev_1.0\klxx-sc-baremetal\build\iar\hello_world\FLASH_128KB\Exe\hello_world_freedom.srec to the board.
You could also use the IAR debugger to connect to the board by pressing the Download and Debug button:
Open up a terminal window (19200 baud, 8-data, no parity, 1 stop bit), hit reset on the board, and see if you see any output and a blinking green LED.
If you do, type “S2” to see the output from the accelerometer (MMA8491Q). If all went well, you should see the following with a rapidly blinking blue LED:
You can move the board around and see the values change.
You can try out the other sensors by hitting “Enter” to stop the stream, and then trying “s0” and “s1” to test out the other sensors.
The IAR 6.70.3 project used for the FRDM-KL26Z is attached, and a binary you can drag and drop into the FRDM-KL26Z that works with the MEMS Sensor Evaluation Board is also located in the zip file.