Sunday, 26 March 2017

i.MX6SX - Pulse oximetry with MAX30100, SSD1306 and UDOO NEO

In this blog I demonstrate how the cortex m4 on the imx6sx could be used to develop a Pulse Oximeter.



I chose the max30100 because its features an integrated pulse oximetry and heart-rate monitor sensor. Unfortunately Maximi provide little documentation or application notes covering how best to determine heart rate or spo2 values using the data returned from the sensor. The sensor hosts an IR and RED LED that can be adjusted to provide pulses for spo2 and heart rate measurements. As a trade off between adequate data samples, i2c bus speed and post measurement hr/spo2 calculation processing the max30100 was configured to return 100 IR and RED values per second. Below is a graph showing raw data values gathered from the NEO at a 100 readings per second.



For spo2 calculation we have taken a simplified approach of taking the AC components of both signals and determining the ratio. The ratio is referenced in an memory table containing empirical sp02 values. Hence the spo2 isn't clinically accurate, for greater accuracy the table would normally be based on experimental measurements from healthy patients cross referenced against clinically accurate readings.

As shown in the graph the IR values are smoother than RED values possible due to secondary emissions from the RED LED. For this reason the IR value are normally used to determine the heart rate. The heart rate is calculated by feeding the IR values in to a first order 6Hz low pass filter which in turn are used to calculate the time interval between 2 peaks. Sample output of applying the low pass filter is shown below ignore the graph labels, top is IR values, bottom is low pass filter.




I also hooked up a  SSD1306 oled display to the same i2c bus so that the calculated heart rate and spo2 values are displayed. The main challenge of this exercise has been to be ensure the code running on the M4 is as efficient as possible because there are many time critical elements such reading data samples, hr/spo2 calculation and display updates which can interfere with the output results. As with my previous examples on the imx6sx this was developed using the FreeRTOS sdk.

Tuesday, 24 January 2017

Adding a DS3231 Real Time Clock to UDOO NEO/QUAD

Its well know that the in-built RTC on the imx6 processor isn't the best in terms of battery life (performance).  Using an external RTC provides better battery life and fortunately the process isn't too complicated implement. The DS3231 is a popular RTC especially with the RPI community given ease of integration (via I2C) and accuracy. There's a few variations of the DS3231 for the RPI and the one I using is the one below which can be easily sourced.


In the image I have highlighted the pin out to simplify wiring. I'm going to take the UDOO NEO as a example and use I2C4 (alternatively you can use I2C2). For I2C4 wire SDA to pin 35 and SCL to pin 34 on header J5, 3.3v and GND are available on J7. On power up you can verify the DS3231 is visible by executing:

udooneo:~# i2cdetect 3

which should return the DS3231 at address 0x68.

WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-3.
I will probe address range 0x03-0x77.
Continue? [Y/n] Y
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- UU --
20: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

                        
Next step is to enable kernel support by enabling the Dallas/Maxim DS1307 driver as below.


Build the kernel and modules (this is important). Lastly we need add the DS3231 to the device tree to I2C4, below is an example,

diff --git a/arch/arm/boot/dts/imx6sx-udoo-neo.dtsi b/arch/arm/boot/dts/imx6sx-udoo-neo.dtsi
index abbf0d8..2ffa6cb 100644
--- a/arch/arm/boot/dts/imx6sx-udoo-neo.dtsi
+++ b/arch/arm/boot/dts/imx6sx-udoo-neo.dtsi
@@ -298,6 +298,11 @@
                compatible = "fsl,fxas2100x";
                reg = <0x20>;
        };
+
+       rtc@68 {
+               compatible = "dallas,ds1307";
+               reg = <0x68>;
+       };
 };


Rebuild the relevant dtb file depending on your set-up. Deploy the newly generated kernel, modules and dtb to the NEO.

On power up the kernel output should include the following lines ( try dmesg | grep ds1307)

[    8.095963] rtc-ds1307 3-0068: rtc core: registered ds1307 as rtc0
[    8.095989] rtc-ds1307 3-0068: 56 bytes nvram


If all is ok we can query the clock for it current time by using the hwclock utility:

udooneo:~# hwclock -r
Tue 24 Jan 2017 12:32:25 PM UTC  -0.858087 seconds


We can sync with the ntp time:

udooneo:~# hwclock -s

On reboots the RTC time may become corrupt with the udooubuntu release to overcome this ntp service needs to be disabled with the following commands:

echo manual | sudo tee /etc/init/ntp.override
timedatectl set-ntp false

The timedatectl command is extremely useful as it provides a complete picture of the system and rtc times. For example to sync RTC with system time:

udooneo:~# timedatectl
      Local time: Fri 2016-01-01 01:18:06 UTC
  Universal time: Fri 2016-01-01 01:18:06 UTC
        RTC time: Tue 2017-01-24 12:40:36
        Timezone: Etc/UTC (UTC, +0000)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a
udooneo:~# hwclock -s
udooneo:~# timedatectl
      Local time: Tue 2017-01-24 12:42:03 UTC
  Universal time: Tue 2017-01-24 12:42:03 UTC
        RTC time: Tue 2017-01-24 12:42:03
        Timezone: Etc/UTC (UTC, +0000)
     NTP enabled: no
NTP synchronized: no
 RTC in local TZ: no
      DST active: n/a


Wednesday, 18 January 2017

i.MX6SX - Prototype VW (VAG) vehicle diagnostic adapter for KWP2000 services (UDOO NEO)


An interesting use case for the i.mx6sx is as vehicle diagnostic (or interface) adapter. In this blog I will demonstrate how we can re-purpose a UDOO NEO as a prototype diagnostic adapter.



The adapter targets VW vehicles supporting KWP2000 services. Typically an adapter requires a real time interface to the vehicle in order to keep the diagnostic session alive after establishing communications with an ECU.  The real time needs can easily be met on the M4 and we can exploit the A9 side to offer data transformation and API services, for example to make the data available a Mobile application. The end goal is demonstrated in the video where a custom developed Android Application retrieves diagnostic information from the vehicle in real time. The application communicates over Wifi with the NEO which in turn is connected to the vehicles OBD-II port.

The application is first used to query the vehicle for a list of available ECUs (modern vehicles can contain tens of ECUs). For each ECU the physical address and overall status is displayed (OK or has DTC errors).

Subsequently after selecting an individual ECU the application retrieves information about the ECU including the short/long coding value (if applicable).



Although the video demonstrate a few KWP2000 services being invoked, its actually possible to invoke most if not all of the services available. Furthermore it could be enhanced to support UDS services.


At a hardware level VW KWP2000 is supported through CAN (some older vehicles use K-Line) and is accessible through the vehicles on board 16-pin OBD-II connector. For the prototype (in the photo to right) the NEO is simply connected to a SN65HVD230 which in turn is connected to the CAN pins of the OBD-II connector.


Typically VW KWP2000 services are supported over VW's proprietary TP2.0 protocol. TP2.0 is used to establish a session and pass datagrams between 2 ECUs, one of which is our case is the NEO and normally referred to as the 'tester'. Implementing TP2.0 is a challenge as accurate timings are required to correctly deal with time out and error scenarios in addition to implementing logic to cater for varying ECU behaviours depending on their age.  Above TP2.0 is the KWP2000 protocol which implements a simpler request response model. As shown the diagram below a complete TP2.0 and KWP2000 stack was developed to run on the M4.



On the A9 side KWP2000 services are exposed through a custom API interface that when invoked communicate with the M4 over a bidirectional link. The A9 allows the data to be enriched and transformed eg XML/JSON before being exposed via a number of network interfaces such as bluetooth, wifi or even ethernet. For the demo its done by enabling a  Wifi Access Point on the NEO. For those sharp eyed readers you will notice the prototype uses a NEO Basic which has no on board wifi support, instead a wifi dongle was plugged into the USB port to create the Access Point.

Friday, 12 August 2016

i.MX6SX - Realtime CAN interfacing Part 3 (UDOO Neo)





In the last post we covered how the RX8 instrument cluster could be controlled from the A9 side. Given the A9 side is feature rich in its capabilities if offers numerous possibilities. As a simple demonstration we will attempt to replicate the RPM and Speed gauges and two warning indicators on the hdmi (720p) display to represent a simplified virtual instrument cluster. The main challenges here are:

1. On screen widget need high performance.
2. Keeping the on screen gauges/warning indicators in sync with the instrument cluster.
3. Minimising CPU usage.



In the video, the on screen RPM gauge (on left fairly) accurately tracks the RPM needle on the instrument cluster. The on screen Speed gauge (on the right tracks) the digital Speed indicator. We also toggle the battery and oil warning indicators on the screen and cluster. Notice that the cluster_gauges application is consuming rough 10% of the CPU.

In order to deliver the necessary performance the on screen gauges were rendered using custom Open GL ES 2.0 code. Note the graphic images used for gauges are modified versions derived from this Android Ardunio project. Compared to the previous post there is now a single application (cluster_gauges) on the A9 side which renders the widgets but also controls the instrument cluster through the M4.




I hope through these 3 blog posts have I managed to demonstrate how the M4 and A9 processor can be combined to provide a rich real-time interface and data distribution mechanism for your applications.



Thursday, 11 August 2016

i.MX6SX - Realtime CAN interfacing Part 2 (UDOO Neo)

As mentioned in my previous post the next stage of development with the RX8 instrument cluster is to offer the ability to control the gauges/indicators on the cluster from the A9 side. In the last post I also pointed out that to keep the cluster active the M4 side has the responsibility of regularly sending/receiving CAN messages from/to the cluster. Hence we can't use the CAN interface from the A9, instead we get the A9 'to talk to' the M4. Within the i.mx6sx the Messaging Unit module enables the two processors to communicate with each other by coordinated passing message. We can make use of this feature to send messages to the M4 from A9 to ask it to update the cluster and use the M4 to forward CAN messages received from the cluster to the A9. By the way, this all happens while the M4 also is feeding the cluster with its own CAN messages. For the i.mx6sx the inter-processor communication is abstracted and implemented through the Remote Procedure Messaging (RPMSG) framework which is supported both in the Linux and FreeRTOS BSP.



Compared to the last demonstration, the main change to the configuration is the introduction of a relay board so that the instrument can be powered on and off (the Power Control box in the diagram) by the M4.


The M4 firmware has been amended to accept commands from the A9 via RPMSG. On the A9 side we have 2 applications:

1. read_can - Which constantly reads CAN messages sent from the instrument cluster via the M4 .
2. cluster_control - Controls the instrument cluster via the M4.

cluster_control has the following capabilities through a number of command line options:

-i  - turns the instrument on/off
-r  - set the RPM
-s  - set the SPEED (in kilometres although display is in mph)
-b  - set Battery Warning indicator
-o  - set Oil Warning indicator
-c  - set Cruise control indicator


The short video demonstrates two applications running on the A9, read_can is running in the window on the left and on the right cluster_control is used to manipulate the cluster. Note that prior the 2 applications being launched, the M4 was preloaded with new firmware and RPMSG initialised on the A9 side. Once cluster_control changes the cluster state, the M4 is responsible for continuing updating the instrument cluster with the new state until the next change. 

Now that we have the ability to control the cluster and receive messages from the A9 side, in the final post I will demonstrate how another feature of i.mx6sx can be used with it.

Wednesday, 3 August 2016

i.MX6SX - Realtime CAN interfacing Part 1 (UDOO Neo)

One of the most promising capabilities of the i.mx6sx is combing the Cortex M4 with the on board CAN interfaces. This feature opens up a number of possibilities for deploying the i.mx6sx for a varied range of automotive solutions where real-time processing of CAN messages is handled by the M4 and the A9 kept for non-critical processing. To demonstrate this, lets take a simple use case of driving an automotive instrument cluster.  In a series of blog posts I will cover how we can drive the instrument cluster initially from the M4, then from the A9 communicating via MU (Messaging Unit) to M4 and finally by a on screen virtual dials mimicking the actual instrument cluster dials.



For this exercise we used an instrument cluster pulled from a Mazda RX8. The RX8 instrument cluster interface is partially analogue and partially digital. The digital interface is provided through a high speed CAN (500 Kbps) interface that drives the dials (RPM, Oil, Temperature) , digital speedometer and a number of warning indicators. Time pending I may cover the RX8 instrument cluster CAN interface in more detail in another blog. The target board for development was the UDOO NEO complemented with SN65HVD230 CAN Transceivers.

For this first demonstration a FreeRTOS application was developed to run on the M4 that regularly sends CAN messages to the cluster and dumped CAN messages generated on the bus from the cluster to the serial port. In order to drive the dials and suppress the warning indicators, the instrument cluster requires a regular feed of CAN messages sent at 10 milliseconds intervals. When the cluster is active it also generates CAN messages roughly at 50 millisecond intervals.

The video above shows the application (rx8_can) being launched from Uboot, before launching the application notice that all warning indicators lights are active on the instrument cluster. After the application is launched all warning indicators are cleared and the RPM gauge and speedometer are active. The application also dumps the instrument cluster generated CAN messages to the serial port (shown in the terminal to the right). After launching the application we boot to a Linux console to demonstrate the A9 is unaffected while the M4 continues to control the instrument cluster.

In the next post I aim to demonstrate how we can utilise the Message Unit to allow the A9 to control the instrument cluster by communicating with the M4.

Sunday, 28 February 2016

i.MX6SX - Video processing via VADC & PXP (UDOO Neo)

Unlike the rest of the i.mx6 family, the i.mx6sx has limited hardware video decoding support for example there is no h.264 or mpeg support. The i.mx6sx hosts a simpler video analogue to digital converter (VADC) which allows the conversion of a NTSC or PAL signal to a YUV444 format. The YUV444 is slightly unusual in that its encoded as a 32 bit value which equates to YUV32 in V4L2 terms. Given the unusual YUV32 output decoding becomes more interesting because it heavily relies on the PXP (Pixel Pipeline) engine for colour space conversion and onward rendering to a display. The PXP can be considered a smaller brother of the IPU (Image Processing Unit) as found on the rest of i.mx6 family. In addition to colour space conversion the PXP has the capability to flip (horizontal/vertically), scale and blend/overlay images from multiple sources. The one caveat is that PXP on the i.mx6sx has limited input and output formats that it can accept.



Engine check sensor image
To give you an idea of the what the PXP can do, the video above shows the output of a NTSC camera blended with a graphics overlay. The camera is actually a parking (reversing) camera (courtesy of the UDOO team), this is highlighted by the red/yellow/green lines and the blinking 'STOP' text which form part of the camera output. Given the automotive theme the graphics overlay represents a engine check sensor dash. The output video (720x480) fits nicely on the UDOO 7" LVDS display. As the UDOO Neo is targeted towards sensor technology (IOT),  we use the tilt angle from the gyroscope to determine the amount of alpha blending to apply (the graphics fade away or become fully visible).  Furthermore depending on axis of the tilt the combined video output is flipped horizontally or vertically (in real time) noticeable by the 'STOP' text and graphics appearing reversed or upside down.

Given the above, I have put together a simple example that demonstrates to how read the camera output and pass it to the PXP for onward processing. The example is partially based on existing freescale code snippets but modified to use the PXP and then simply renders to a frame buffer. The example will only run against a frame buffer and not on X11. Unlike the above video, the example does not use GPU hardware acceleration therefore the CPU usage will be high. In order to build the example you require PXP header/library to be built and installed which are part of the imx-lib package.

To build:

make clean
make

To run:

./imx6sx_vdac_pxp

Optional parameters

-t Time in seconds to run
-h flip image horizontally
-v flip image vertically
-i invert colours