Interfacing IoT with embedded using Node.js, part 4: ADC

October 2, 2017 Michael Schmidt

In "Interfacing IoT with embedded using Node.js part 3" we looked at the package for reading the accelerometer, service-mma8451. In part 4, we focus on reading ADC registers.

The service-md28adc package demonstrates how to run C code called from Node.js. This code implements the reading of the i.MX28 ADC registers in the CPU via memory mapping of these registers. This code is adapted directly from the sample code provided by Technologic Systems for the TS-7680. The main addition here is the code to interface Node.js to C.

Node.js uses a C++ interface, therefore the code must be written in C++. Our implementation is in In this file there is an init function, adapted from mx28adcctl.c, which opens /dev/mem and memory maps three regions of the CPU ADC interface to volatile unsigned int pointers. These can be used to access the CPU registers needed to perform ADC functions.

Second is the adcread function, also adapted from mx28adcctl.c, which sets up the ADCs and obtains seven samples. These samples are averaged and placed in the buffer.

An include file for “Native Abstractions for Node.js,” or NAN, must be placed at the top of the file. The interface for creating add-ons has changed as Node.js has matured, and NAN abstracts away these differences to allow the creation of code that works on Node.js versions 0.8, 0.10, 0.12, and 1-7.

The code used to create a Node.js add-on is in the ADC function, which conforms to the parameter requirements of Node.js add-ons. Specifically, it has a prototype that looks like this:

We are taking a single parameter called info. This is of a complicated NAN class we don't need to worry about at this point.

In this function, first declare a buffer to hold the samples from all eight ADCs read by adcread:

Next, call init if has not be called yet. A global variable is used to determine this:

Now call adcread to fill the buffer with samples:

Next, construct a JavaScript array of length 8, and set the value of each element in this array to the corresponding ADC sample value:

Then, set up the array to be the return value as seen by the call into the function from JavaScript. This is slightly more complicated than a simple return statement, as it bridges from C++ back to JavaScript!

In addition to the ADC function, an Init function (note the uppercase “I”, which makes this different from our init function) must be defined. The two important parts here are “get” and ADC. These define the name of the module element on the JavaScript side that is called to access the function, as well as the name of the function on the C++ side that gets called:

Now, invoke a macro to associate the Init function with the module name:

The mx28adc.js file provides a thin wrapper, which responds to requests for the ADC values by calling the addin function defined in to sample the ADCs and then outputs these values on the connection socket.

The beginning of this line sets up the binding node and our C++ add-on:

Specifically, the bindings module returns a function that is called with the relative path of the binary. This will be created during the build process from the C++ source code, and have a suffix of “.node”. The return from the call is a JavaScript object that refers to the add-on. Since the add-on defines one function, get, this function is accessible as an element of the returned object. Calling this function essentially calls into the C++ code.

Next is the Server function. It is a standard express handler function and will be called whenever the endpoint is requested by a client. It logs entry, sets the content type of the response to text/plain, and then calls into the C++ code using mx28adc.get() to retrieve the ADC values. It then takes the array and converts it into a string, with one number per line:

Finally, module.export is set to the initialization function, which checks for an option to change the endpoint string and associates the endpoint with the Server function:

The binding.gyp file has information required to compile the C++ code. The build process is automatically invoked when the package is installed.

In our next and final installment, we will construct a user interface that utilizes the services we have implemented in order to control the board from a web browser.

Technologic Systems







About the Author

Michael Schmidt has worked as an Engineer at Technologic Systems for 11 of your Earth years. In his spare time, he enjoys spending time with his family, architecting software, and writing sci-fi/fantasy. He enjoys creating order out of chaos and making the future better than the past.

More Content by Michael Schmidt
Previous Article
Interfacing IoT with embedded using Node.js, part 3: Accelerometer
Interfacing IoT with embedded using Node.js, part 3: Accelerometer

Let’s look at the package for reading the accelerometer, service-mma8451. We'll be implementing support for...

Next Article
Interfacing IoT with embedded using Node.js, part 5: Web interface
Interfacing IoT with embedded using Node.js, part 5: Web interface

We've implemented a web server in Node.js that provides APIs for controlling GPIOs, sampling accelerometers...