Previous posts
Post 2 - Installing OpenCV - Prerequisites
Post 5 - Installing eye tracker
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
Hardware resources
The following peripherals are going to be used
- Low limit switch: this digital input is connected to a switch that closes when the cursor reaches the lowest allowed position
- High limit switch: this digital input is connected to a switch that closes when the cursor reaches the highest allowed position
- 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.
- 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
Pin | Function |
Port E, Pin 0 | Low limit switch |
Port E, Pin 1 | High limit switch |
Port E, Pin 5 | Configuration jumper |
Port C, Pin 3 | UART1 Rx |
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
- 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 */
- 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 */ SIM_WR_SCGC4_UART1(SIM, TRUE); SIM_WR_SCGC4_UART2(SIM, TRUE); /* 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 */ UART_S1_REG(UART1); *ch = UART_D_REG(UART1); /* Clear possible Overrun condition that will prevent other chars From being received */ if (UART_S1_REG(UART1) & UART_S1_OR_MASK) { 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
0xFF | 0xFF | 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
- Homing down: the motors are driven until the cursor hits the low limit switch
- Homing up: the motors are driven until the cursor hits the high limit switch
- 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
- Run: the application starts reading the UART interface. When a valid message has been read, coordinates are extracted and motor speeds are set