Previous posts

Post 1 - Introduction

Post 2 - Installing OpenCV - Prerequisites

Post 3 - Installing OpenCV

Post 4 - Installing Pygaze

Post 5 - Installing eye tracker

Post 6 - SPI communication

Post 7 - SPI communication in Python

EyeLiner - Post 8 - Getting started with Kinetis

EyeLiner - Post 9 - Mechanical design

EyeLiner - Post 10 - Mechanical design: the plotter

EyeLiner - Post 11 - Eye tracker software

EyeLiner - Post 12 - Getting started with the kit



In my previous post, I introduced the KMS software package.

However, it resulted in a project that was a bit difficult to understand and modify. So I restarted from scratch and used another NXP tool: MCRSP_PMSM

This tool includes a motor control library (FreeMaster)  that is much easier to use. So here are the steps I followed


Import the project into Kinetis Design Studio workspace

MCRSP includes some ready-to-use demo applications. I started from that to create my own project. In KDS, I clicked File->Import and browsed to the MCRSP installation folder (in my case C:\NXP\MCRSP_PMSM_V1.1.1) and selected the appropriate project folder (c:\NXP\MCRSP_PMSM_V1.1.1\src\projects\frdm-kv31f)

The imported project contains link to the files in the installation folder (C:\NXP\MCRSP_PMSM_V1.1.1), so I replaced the files I’m going to edit (main.h and main.cpp) with my own files. To accomplish this, I first removed the existing links in the project and then right-clicked on the src folder and selected File -> New

I finally entered the name of the file to import and clicked OK


KDS New file.png



Hardware resources

The following peripherals are going to be used

  1. Low limit switch: this digital input is connected to a switch that closes when the cursor reaches the lowest allowed position
  2. High limit switch: this digital input is connected to a switch that closes when the cursor reaches the highest allowed position
  3. Configuration switch: this digital input is used to determine whether the board is controlling the left or right motor. It is closed on the board that controls the left motor, and left open on the board that controls the right motor.
  4. UART Interface: UART interface for communication with the Raspberry Pi board. I initially wanted to use an SPI interface but, unfortunately,  on the Freedom board some the pins required for SPI operations are connected to other peripherals


In order not to interfere with the motor control algorithm, no peripherals use interrupts: all of them are polled

So here is the pin assignment




Port E, Pin 0

Low limit switch

Port E, Pin 1

High limit switch

Port E, Pin 5

Configuration jumper

Port C, Pin 3



Set up the GPIOs

The three GPIO pins (Port E pin 0, 1, and 5) will be configured for input. Here are the instructions required to configure such pins

  1. Set the proper pin function. According to datasheet (see picture below), GPIO function is function ALT1

PORT_WR_PCR_MUX(PORTE, 0, 1); /* Set PORTE, port 1, MUX 1 - GPIO */


  • Enable the pull-up resistor
PORT_WR_PCR_PE(PORTE, 0, TRUE); /* Pull-up resistor enabled */
  • Select the pull-up resistor
PORT_WR_PCR_PS(PORTE, 0, TRUE); /* Pull-up resistor selected */
  1. Enable the passive filter to filter glitches
PORT_WR_PCR_PFE(PORTE, 0, TRUE); /* Enable passive filter */

Setup the UART communication

This is the code the initialize the UART1


void InitUART1(uint32_t u32UClockSpeedinHz, uint32_t u32BaudRate)
    register uint16_t ubd;
    register uint16_t brfa;

    /* Enable the clock to the selected UART */

    /* Calculate baud settings */
    ubd = (uint16_t)((u32UClockSpeedinHz)/(u32BaudRate * 16));

    /* Enable the UART1_TXD function on PTB17 */
    PORT_WR_PCR_MUX(PORTC, 4, 3); /* UART is alt3 function for this pin */
    /* Enable the UART1_RXD function on PTB16 */
    PORT_WR_PCR_MUX(PORTC, 3, 3); /* UART is alt3 function for this pin */

    /* Make sure that the transmitter and reciever are disabled while we change settings. */
    UART_WR_C2_TE(UART1, FALSE); /* Disable transmitter */
    UART_WR_C2_RE(UART1, FALSE); /* Disable reciever */

    /* Configure the UART for 8-bit mode, no parity */
    UART_WR_C1(UART1, 0x00); /* We need all default settings, so entire register is cleared */

    /* Set calculated values to BDx registers */
    UART_WR_BDH_SBR(UART1, ((ubd & 0x1F00) >> 8));
    UART_WR_BDL(UART1, (uint8_t)(ubd));

    /* Fine baud rate adjust */
    brfa = (((u32UClockSpeedinHz*32000)/(u32BaudRate * 16)) - (ubd * 32));
    UART_WR_C4_BRFA(UART1, brfa);

    /* Enable receiver and transmitter */
    UART_WR_C2_TE(UART1, TRUE); /* Enable transmitter */
    UART_WR_C2_RE(UART1, TRUE); /* Enable reciever */


To receive a character on the serial port, the following function is invoked


uint8_t UART1_receive(uint8_t* ch)
    uint8_t dummy;

    /* Check if a character is available */
    if (! (UART_S1_REG(UART1) & UART_S1_RDRF_MASK))
        return 0;

    /* Read out character */
    *ch = UART_D_REG(UART1);

    /* Clear possible Overrun condition that will prevent other chars
       From being received */
        dummy = UART_S1_REG(UART1);
        dummy = UART_D_REG(UART1);
        dummy++; /* For unused variable warning */

    return 1;


The expected serial message has the following format




X Pos (high byte)

X Pos (low byte)

Y Pos (high byte)

Y Pos (low byte)


The 0xFF 0xFF marker has been added to mark the start of frame. This should prevent any loss of synchronization between sender and receiver.


Some notes about the software

The structure of the software is simple. The application has three main phases

  1. Homing down: the motors are driven until the cursor hits the low limit switch
  2. Homing up: the motors are driven until the cursor hits the high limit switch
  3. Move to Center: given the time the cursor has taken to move from low limit to high limit switch, the cursor is moved to the center position
  4. Run: the application starts reading the UART interface. When a valid message has been read, coordinates are extracted and motor speeds are set