Custom Command Example

This is 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


Any LINX Device. In this case, a chipKIT WF32 is used.

Software


Firmware IDE Used
Device FamilyIDE
chipKIT MPIDE

Procedure


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

  1. Generate Firmware
  2. 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)
  3. The examples are read only so save a copy somewhere.
  4. At the bottom of the firmware, after the void loop, the custom function is added. 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 and then write the input from LabVIEW onto the LCD display. 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);
  
int Channels[8] = {34, 35, 36, 37, 30, 31, 32, 33}; //This array contains the data bus pins from DB0 to DB7.

int variable[8]; //use for dummy array in order to bit shift each input byte

// 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!!


//convert input to bytes
for(int i = 0; i < (numInputBytes); i++)
  {
    input[i] = byte(input[i]);
  }
  
//Read each byte from the input array and write each channel high or low for each bit position in the data bus.
for (int j=0; j < (numInputBytes); j++)
  {
    digitalWrite(E, HIGH); //prepare for a new letter or number by writing E HIGH and the following RS,RW values
    digitalWrite(RS, HIGH);
    digitalWrite(RW, LOW);
    for (int i=0; i<8; i++)
    {
      variable[i] = input[j] & 1;
      if (variable[i] == 1)
     {
        digitalWrite(Channels[i], HIGH);
     }
     else
     {
       digitalWrite(Channels[i], LOW);
     }
    input[j] = input [j] >> 1;
   }
  digitalWrite(E, LOW); //enable the display to show this input
  delayMicroseconds(50); //time needed for command to run
  }
  response[0]=0;
  *numResponseBytes = 1;
  return 0;

}

  1. Now the custom command function needs a forward declaration. Above void setup(), add int clp();
  2. Next, the custom command is attached to a LINX Listener so it 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. In this case, 0 is used.
    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, clp);

  1. Next, firmware is uploaded to the device.
  2. The Custom Command VI (Functions Palette»MakerHub»LINX»Utilities»Custom Command) is used to call the custom function.
  3. Below are the resulting block diagram and front panel for the given code above as well as the LCD display.
  4. There are only 16 spaces that can be filled on the LCD display, so the code only allows for a size less than or equal to 16.

True Case: False Case:

Summary


This tutorial provides an example 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.