Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
396 lines (249 sloc) 18.5 KB

#Programming with Hardware Pins for Kinoma Element

This document describes how to program Kinoma Element's hardware pins, and serves as a handy reference to the pin types supported by Kinoma Element.

##About the Pins

Kinoma Element has 16 hardware pins. These pins implement Digital Input/Output, Analog Input, Pulse Width Modulation (PWM), Serial Input/Output, and I2C.

The pins are divided into left and right groups of eight pins each. These pins are user-configurable, using either the Front Pins app in Kinoma Code or the Pins module in an application. All pins operate at 3.3 volts.

Figure 1. Kinoma Element Pins

Pin map

##Introducing BLL Modules

All hardware pin programming is done in JavaScript. The code for each hardware module (sensor, LED, button, motor, and so on) is contained in a JavaScript module called a BLL. BLLs communicate directly with hardware pins. The application communicates with the BLL using the Pins module.

Note: "BLL" stands for Blinking Light Library, but a BLL is not limited to blinking an LED; a BLL can be used to interact with all kinds of hardware modules.

Developers either implement their own BLL to support the hardware modules they have connected to Kinoma Element or use an existing BLL implementation. Sample BLL implementations for common hardware modules are available in our collection of sample apps on GitHub. In addition, the Pins module includes built-in BLLs for each hardware protocol, and you can also find their source code on GitHub; they are the files with names of the form bll_x.js, where x is the name of the relevant hardware protocol (for example, bll_Analog.js and bll_PWM.js).

Application Programming with Pins

Applications first configure the BLLs they will use, and then issue single or repeating commands to the BLL. The Pins module is used to send configuration and commands from the application to BLLs. (See also the document Using the Pins Module to Interact with Sensors on Kinoma Element.)

The call to Pins.configure lists the BLLs the application uses together with the pins that each BLL uses to communicate to its hardware module.

The following code configures the hardware pins to work with BLLs named buttonBLL and ledBLL. The BLL code is stored in files named buttonBLL.js and ledBLL.js. The second argument of Pins.configure is a callback function that is invoked whether or not the configuration is successful.

Pins.configure({
	greenButton: {
		require: "buttonBLL",
		pins: {
			button: { pin: 1 },
			power: { pin: 2 },
			ground: { pin: 3 },
		}
	},
	redLED: {
		require: "ledBLL",
		pins: {
			led: { pin: 8 },
			ground: { pin: 9 },
		}
	}
}, success => {
	if (success)
		trace("Configured pins.\n");
	else
		trace("Failed to configure pins.\n");
});

Applications assign a unique name to each hardware module in the configuration. In the preceding example, the button BLL is named greenButton and the LED BLL is named redLED. The application uses these names to send commands to the corresponding hardware module.

The require and pins properties are defined by the application. The value of the require property is the name of the BLL file corresponding to the hardware module. The names of the properties inside the pins objects (in this example, led, button, power, and ground) are defined by each individual BLL.

While not evident from the application code, the button BLL uses a Digital Input pin, and the LED BLL uses a Digital Output pin. By convention, the application code specifies the pin numbering and the BLL defines the type of pins (Digital Input, Digital Output, PWM, Serial, and so on) that are used. The next section covers how to specify the pin type.

The LED BLL is bound to pins 8 and 9 and the button BLL to pins 1 through 3, as defined in the pins object.

Once the pins are configured, an application can invoke BLL functions using the Pins.invoke function.

Pins.invoke("/redLED/write", 1);  // Turn LED on

Pins.invoke("/redLED/write", 0);  // Turn LED off

Applications retrieve values from BLLs in a similar way: calling Pins.invoke with the name of the target hardware module and the name of the command in the path. Also passed in is a callback function, which will be called with the value returned.

Pins.invoke("/greenButton/get", value => {
	trace("Button value: " + value + "\n");
});

Note: The format of the value returned from the BLL is determined by the author of the BLL. In the preceding example, the type of the returned value is Number, but it may be any valid JavaScript object.

Applications establish repeated polling of a hardware module at a specified interval using the Pins.repeat function. The following example polls the button at 50-millisecond intervals.

Pins.repeat("/greenButton/get", 50, value => {
	trace("Button value: " + value + "\n");
});

If you would like to take a closer look at the Pins module for Kinoma Element, you can find its source codeon GitHub.

BLL Programming with Pins

As mentioned earlier, a BLL is a JavaScript module that communicates directly with hardware pins. The BLL is configured by the application, which communicates with the BLL exclusively using the Pins module.

As illustrated in the simple example below, all BLLs must export the following:

  • A pins object that defines the types of pins it uses

  • A configure function that initializes each of the objects by calling the object's init function

  • A close function that is called automatically when the host application exits and that typically closes the objects used to communicate with pins

You can define and export additional functions required for working with the module to interact with the sensors.

Here are the pins exports corresponding to ledBLL and buttonBLL (respectively) as introduced earlier:

exports.pins = {
	led: { type: "Digital", direction: "output" },
	ground: { type: "Ground" }
};

exports.pins = {
	button: { type: "Digital", direction: "input" }
	power: { type: "Power" },
	ground: { type: "Ground" }
};

When Pins.configure is called, the configuration data provided by the application (highlighted in green below) is merged with the properties of the pins object exported by the BLL (highlighted in blue), to arrive at the following complete configurations:

redLED_configuration = {
	led: { type: "Digital", pin: 8, direction: "output" },
	ground: { type: "Ground", pin: 9 }
}

greenButton_configuration = {
	button: { type: "Digital", pin: 1, direction: "input" },
	power: { type: "Power", pin: 2 },
	ground: { type: "Ground", pin: 3 }
}

The appropriate BLLs are then loaded using the require function, and JavaScript objects to communicate with the hardware pins are instantiated. In this example, two Digital pin objects are instantiated: one configured as an input and the other as an output. The input is bound to pin 1 and the output to pin 8. These JavaScript objects are assigned to the module using the property names given by the BLL (led and button in this example).

Once the objects are instantiated and bound, the configure function of each BLL is called. The configure function must initialize each of the objects by calling the object's init function, and it can do any additional work required by the BLL. Note that Power and Ground pins do not need to be initialized.

exports.configure = function() {
	this.led.init();
}

exports.configure = function() {
	this.button.init();
}

The BLL also defines a close function, which is called automatically when the host application exits. The close function typically closes the objects used to communicate with pins, as follows:

exports.close = function() {
	this.led.close();
}

exports.close = function() {
	this.button.close();
}

The BLL author may define additional functions required for working with the module. Here are sample read and write functions for the led and button objects:

exports.read = function() {
	return this.button.read();
}

exports.write = function(value) {
	this.led.write(value ? 1 : 0);
}

Hardware Pins Reference

This section describes the pins data format that an application uses to configure a BLL. For each of the pin types that are programmatically supported by Kinoma Element--Digital, Analog, PWM, Serial, and I2C--the following reference details are provided:

  • Pins Object -- The full pin configuration data, specified in the pins object with properties that define the type of pin and the pin number used. Data in blue is defined by the BLL; data in green, by the application.
  • Functions, Values -- The functions and value properties supported by the pin type.

The object for each pin type has an init function that reserves any hardware resources required by the object, and a close function to release the resources used by the object. The object will not operate properly until the init function is called.

Note: This reference section refers to chunks, but use of chunks has been deprecated.

###Digital

####Pins Object

{type: "Digital", pin: 2, direction: "input"};
{type: "Digital", pin: 3, direction: "output"};

####Functions

#####digital.read() Returns 0 or 1, or undefined if the read fails. This function is used to retrieve either the value of an input pin or the value being sent by an output pin.

#####digital.write(value) value must be 0 or 1. This property can be read or written to change the direction.

####Values

#####digital.direction Value is the string input or output.

###Analog

####Pins Object

{type: "Analog", pin: 3};

Analog is available only on pins 1 through 8.

####Functions

#####analog.read() Returns a floating-point value from 0 to 1.0

###PWM

####Pins Object

{type: "PWM", pin: 9};

PWM is available only on pins 9 through 16. All PWMs can be active simultaneously.

####Functions

#####pwm.write(value) Sets the duty cycle (percentage of time spent "high") to value (a floating-point value from 0 to 1.0). The frequency is 50 Hz (period 20 ms).

#####pwm.write(value, period)

Sets the PWM output pulse width to value and the period (cycle duration, or 1/frequency) to period, both specified in milliseconds. Pulse width and period can also be specified as an array, as in pwm.write([width, period]). The minimum pulse width is .00002 ms (20 ns). The maximum frequency is 5 kHz--that is, a period of .2 ms, or 200 µs. Very long periods (greater than one hour) are supported.

#####Examples

this.pwm.write(0.5);       // 50% duty cycle
this.pwm.write(0.5, 5);    // 0.5 ms pulse width, 5 ms period (10% @ 200 Hz)
this.pwm.write([0.5, 5]);  // Same as preceding example

###Serial

####Pins Object

{type: "Serial", rx: 1, tx: 2, baud: 38400};

Serial RX and TX pins must be used in adjacent pairs; the options are 1-2, 5-6, and 12-11.

If the serial device is read-only or write-only, the unused pin property, rx or tx, may be excluded from the pin configuration data.

####Functions

#####serial.read(format) Reads data from the serial input. Pass one of the following strings for the format parameter:

  • String to return a string. The data read into a string must be valid UTF-8 data, otherwise an exception is thrown.

  • ArrayBuffer to return an array buffer.

#####serial.read(format, maximumBytes) Same as serial.read(format) but reads no more than maximumBytes. This call does not block, so only immediately available bytes are returned.

#####serial.read(format, maximumBytes, msToWait) Same as serial.read(format, maximumBytes) but waits up to msToWait milliseconds for maximumBytes to arrive

#####serial.write(value) Writes the specified value to the output. value can be a number, string, array, or array buffer.

###I2C

####Pins Object

{type: "I2C", sda: 13, clock: 14, address: 0x36};

I2C pins must be used in adjacent pairs; the options are 13-14 and 15-16.

The address property is the I2C slave address. The data sheet for some I2C devices specifies different slave addresses for reading and writing, differing only in the least significant bit; if this is the case, use the most significant seven bits for the slave address here.

####Functions

#####i2c.readByte() Reads one byte

#####i2c.readBlock(count, format) Reads the number of bytes specified by count. Pass a string for the format parameter: Chunk to return the data in a chunk, or Array to return an array of integer character codes from 0 to 255.

#####i2c.readByteDataSMB(register) Reads one byte from the specified register

#####i2c.readWordDataSMB(register) Reads two bytes from the specified register

#####i2c.readBlockDataSMB(register, count, format) Reads count bytes starting at the specified register. Pass a string for the format parameter: Chunk to return the data in a chunk, or Array to return an array of integer character codes from 0 to 255.

#####i2c.writeByte(value) Writes one byte.

#####i2c.writeBlock(value...) Writes the specified value(s), which are treated in the same way as by serial.write.

#####i2c.writeByteDataSMB(register, value) Writes one byte to the specified register

#####i2c.writeWordDataSMB(register, value) Writes two bytes to the specified register

#####i2c.writeBlockDataSMB(register, value...) Writes up to 32 bytes starting at the specified register. The value(s) are treated in the same way as serial.write.

#####i2c.writeQuickSMB(value) Sends the low bit of value using the I2C write_quick command

#####i2c.processCallSMB(register, value) Writes two bytes to specified register; after the write completes, reads two bytes and returns the resulting data word.