This is an old revision of the document!


Custom Command Example

This guide will go over an example on how to use a custom command to control an LCD display. The LCD display used is the PmodCLP by Digilent.

Prerequisites

Hardware

Software


Firmware IDE
Device FamilyIDE
Arduino Arduino IDE
chipKIT MPIDE

Procedure


The idea for this example was to write a string constant, convert into a U8 array, and display what you wrote in the string constant on the LCD display using MPIDE and the chipKIT WF32.

  1. Make sure you're using LINX 1.2 or later.
  2. Generate the LINX firmware libraries in the appropriate location for your device's IDE by opening LabVIEW and under the Tools tab go to MakerHub –> LINX –> Generate Firmware Libraries.
  3. Generally for MPIDE you want to generate the firmware library in C:\users\*your name*\My Documents\mpide\libraries)
  4. Restart the device IDE
  5. In the device IDE open the LINX example for the device and interface you're using. (In this case, File»Examples»LINX»ChipKIT_WF32_Serial)
  6. The examples are read only so save a copy somewhere. This will be your custom firmware.
  7. At the bottom of the firmware, after the void loop, add your custom function. The function must return an int and must have 4 parameters: unsigned char, unsigned char*, unsigned char*, unsigned char*. Below is the function used.

 
int clp(unsigned char numInputBytes, unsigned char* input, unsigned char* numResponseBytes, unsigned char* response)
{

}

  1. numInputBytes is the number of bytes in the input array (from LabVIEW)
  2. input is a U8 array which contains the data bytes sent from LabVIEW using the Custom Command VI.
  3. numResponseBytes needs to be set to the number of bytes you want to send back to LabVIEW.
  4. response is a U8 array. Fill this with the data bytes you want to send back to LabVIEW.
  5. The function should return 0 (or use the L_OK constant) if everything went well, or an error number otherwise.
  6. The following is the code required to initialize the display for 8-bit interface mode. This includes function set, turning the display on, clearing the display, and setting the entry mode. After this initialization process, the cursor will point to the first entry on the LCD display and will be ready to write. Since the function must return at least 1 value, the response variable has one entry (0) and the number of response bytes is 1.

int clp(unsigned char numInputBytes, unsigned char* input, unsigned char* numResponseBytes, unsigned char* response)
{
#define RS 26
#define RW 27
#define E 28
#define DB0 34
#define DB1 35
#define DB2 36
#define DB3 37
#define DB4 30
#define DB5 31
#define DB6 32
#define DB7 33
 
  pinMode(RS, OUTPUT);
  pinMode(RW, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(DB0, OUTPUT);
  pinMode(DB1, OUTPUT);
  pinMode(DB2, OUTPUT);
  pinMode(DB2, OUTPUT);
  pinMode(DB3, OUTPUT);
  pinMode(DB4, OUTPUT);
  pinMode(DB5, OUTPUT);
  pinMode(DB6, OUTPUT);
  pinMode(DB7, OUTPUT);
  
// FUNCTION SET
delay(30);
digitalWrite(E, HIGH);
digitalWrite(RS, LOW);
digitalWrite(RW, LOW);
digitalWrite(DB7, LOW);
digitalWrite(DB6, LOW);
digitalWrite(DB5, HIGH);
digitalWrite(DB4, HIGH);
digitalWrite(DB3, HIGH);
digitalWrite(DB2, HIGH);
digitalWrite(E, LOW);
delayMicroseconds(39);

// DISPLAY ON/OFF CONTROL
digitalWrite(E, HIGH);
digitalWrite(RS, LOW);
digitalWrite(RW, LOW);
digitalWrite(DB7, LOW);
digitalWrite(DB6, LOW);
digitalWrite(DB5, LOW);
digitalWrite(DB4, LOW);
digitalWrite(DB3, HIGH);
digitalWrite(DB2, HIGH);
digitalWrite(DB1, LOW);
digitalWrite(DB0, LOW);
digitalWrite(E, LOW);
delayMicroseconds(39);

// DISPLAY CLEAR
digitalWrite(E, HIGH);
digitalWrite(RS, LOW);
digitalWrite(RW, LOW);
digitalWrite(DB7, LOW);
digitalWrite(DB6, LOW);
digitalWrite(DB5, LOW);
digitalWrite(DB4, LOW);
digitalWrite(DB3, LOW);
digitalWrite(DB2, LOW);
digitalWrite(DB1, LOW);
digitalWrite(DB0, HIGH);
digitalWrite(E, LOW);
delayMicroseconds(1540);

// ENTRY MODE SET
digitalWrite(E, HIGH);
digitalWrite(RS, LOW);
digitalWrite(RW, LOW);
digitalWrite(DB7, LOW);
digitalWrite(DB6, LOW);
digitalWrite(DB5, LOW);
digitalWrite(DB4, LOW);
digitalWrite(DB3, LOW);
digitalWrite(DB2, HIGH);
digitalWrite(DB1, HIGH);
digitalWrite(DB0, LOW);
digitalWrite(E, LOW);
delay(2);

//end Initialization!!

response[0]=0;
*numResponseBytes = 1;
return 0;
}

  1. Now the custom command function needs a forward declaration. Above void setup(), add “int myCustomCommand();”
  2. Next, custom commands need to be attached to a LINX Listener so they can be called from LabVIEW. This is accomplished using the AttachCustomCommand() function of the LINX Listener.
  3. The AttachCustomCommand() takes two arguments:
    1. The first is the custom command number (0-63). This is the number you'll use in LabVIEW to call this command.
    2. The second is the custom function.
  4. Add the following code to the setup() function to attach the custom command to the LINX Listener (in this case called LinxSerialConnection)

 LinxSerialConnection.AttachCustomCommand(0, myCustomCommand);

  1. Build and deploy/upload the firmware to the device.
  2. Use the Custom Command VI (Functions Palette»MakerHub»LINX»Utilities»Custom Command) to call the custom function.
  3. Below are the resulting block diagram and front panel for the given code above.

Summary


This tutorial describes the process for adding a custom command to a LINX device. It's important to remember that deploying the firmware from the firmware wizard will overwrite the device firmware with the stock version which will not contain your custom commands. If you have any questions about adding customs commands please post on the LINX forums. If you've successfully added a LINX command, consider sharing your work with the community in the forums.