Thursday, 28 December 2017

i.mx6sx - M4 SD Card access on the UDOO NEO

In this post I demonstrate that it is possible to interface the M4 to a SD card shield (similar to using an Arduino SD card shield) in order to retrieve or save data locally (without relying on the A9). This work is the result of a larger data logger project, where the A9 remains in sleep mode to conserve power while the M4 performs data logging from numerous sensors.



In the video an SD card shield is interfaced to the UDOO NEO and accessed from the M4. The code initialises the SD card, mounts and reads the FAT32 partition. Subsequently we read bitmap files from the FAT32 partition and display the contents to the LCD display (320x240). Code is written using the FreeRTOS bsp and exeutes on the M4 while the A9 boots linux. Each bitmap file is 230400 bytes and when reading 720 byte blocks  throughput is around 230KB/sec. If we increase the block size to 23040 bytes then throughput is around 340KB/sec.

NEO Connectivty

I chose to use a WeMos data logger shield over a Arduino SD card shield mainly for the following reasons:

1. 3.3v compatible
2. An RTC (plus battery backup) is available on the shield, although the accuracy of the DS1307 compared to DS3231 is questionable.
3. Nice stackable design for inclusion of additional WeMos shields

The shield (just the Arduino equivalent) supports an SPI interface. The Phyical Layer of the SD Card Specification mentions that the primary hardware interface is the SD bus which is implemented through 4 data lines and one command line. On power up the native operating mode of the card is SD bus however it possible to switch the card to SPI bus which is considered a secondary operating mode. The main disadvantages of SPI mode versus SD mode are:

1. The loss of performance single data line versus 4 data lines .
2. Only a subset of the SD commands and functions are supported.
3. The maximum SPI clock speed is limited to 25Mhz regardless of the SD card Class.


Minimum connectivity from a host MCU for SPI mode requires 3 SPI pins plus a GPIO pin for CS.


From the NEO the shield can be connected to ECSPI 2 plus a arbitrary GPIO pin and 3.3v, see above (NEO Connectivity) image for wiring.

Power up and initialisation of the card along with commands and responses are well documented in the Phyical Layer of the SD Card Specification. After powering up the card it should be initialised by applying 74 clock cycles (eg. sending 10 bytes with 0xff as the payload). Followed by CMD0 as the first command to send the card to SPI mode, a positive R1 response will contain 0x01. Next step is to interrogate SD version support by sending CMD8 and lastly we can use ACMD41 to set or determine :

1. Card is initialised
2. Card capacity type (SDHC or SDXC)
3. Switch to 1.8V signal voltage

After initialising the card we can interrogate the card data for example:

1. Read the Card Identification (CID) Register, a 16 byte code that contains information that uniquely identifies the SD card, including the card serial number (PSN), manufacturer ID number (MID) and manufacture date (MDT).

2. Read the Card Specific Data (CSD) Register which defines the data format, error correction type, maximum data access time .. etc



Subsequently I built a simple library to read FAT32 partitions and their file contents as shown in the above screen shot.

In order to improve performance we would need to see if we can enable DMA for the SPI transfers however this represents a challenge as the DMA engine is initialised on the A9 therefore we would need to wait for Linux to boot before accessing the DMA engine.







Monday, 3 July 2017

i.mx6sx - Tiny NEO Scope



This project span from two requirements, firstly testing the performance of the ADC (analogue to digital) and ECSPI interfaces when running against the M4. Secondly as a diagnostic aid to verify low bandwidth clock signs (<100Khz) from the PWM or clock/GPIO pins were correctly mux'd from the A9 side. The end result is a simple low bandwidth (<100Khz) oscilloscope. In the above video we first demonstrate the capture of the 50Khz PWM (50% duty cycle) which is generated from the A9 side, see how scope manages to display the signal and correctly calculate the frequency. Secondly we feed the scope a PWM ranging from 3Khz to 95Khz to demonstrate its ability to track and best calculate the input frequency of the signal.

The imx6sx ADC is rated to produce up to 1 Million samples per seconds, however the Reference Manual isn't particularly clear on settings to get this level of performance. It's clear that the fastest conversion are only possible in 8 bit mode (lowest precision) using the IPG clock. From our testing we roughly achieved 500 thousand samples per second by applying no hardware averaging and no clock divider ratio. By disabling hardware averaging we trade off precision for speed in 8 bit mode.

The scope simply consist of reading an ADC pin (in our case A3), buffering 128 samples, outputting samples to the OLED display through the ECSPI interface clocked at 8Mhz. A primitive trigger mechanism is implemented to catch start of a rising signal. This is complemented with high precision EPIT timer to calculate the frequency of input signal for display.
 

Saturday, 10 June 2017

i.mx6sx - SPI interfacing an OLED display for fast updates using the cortex M4 on the UDOO Neo



It has taken me a considerable amount of time to prove that the SPI interface can be made to work with cortex M4 on the UDOO Neo. To demonstrate the speed of SPI I chose to interface with a SSD1306 OLED which can be driven at a clock speed of 8Mhz. Which theoretically should allow a complete RAM buffer to transmitted to the SSD1306 in a very short time period hence offering fast screen updates. To control the speed of screen updates I hooked up an old potentiometer to the ADC input. By varying the potentiometer we control the rate of updates from slow to fast as shown in the video.

The SPI interface is configured for Master mode using interrupts for data transmission resulting in acceptable performance. To reduce interrupt latency further, DMA could be used to transmit the whole RAM buffer in one go.
 
I chose to use ECSPI 2 (normally allocated to the A9 side) and not ECSPI 5 because after reviewing the schematics I think there is a hardware bug with ECSPI 5 as the ECSPI5_SCLK line is shared with Red on board LED (see SPI3_CLK on J6 connector).

This is a C application developed using i.mx6sx FreeRTOS SDK. The graphics rendering code was converted from the Haricord example by hwiguna.

Friday, 19 May 2017

i.mx6sx - One Wire Digital Temperature gauge using DS18B20 + UDOO Neo + LCD




The challenge here was to implement the Dallas one wire protocol so that two DS18B20 sensors could be wired to the cortex M4 to form the basis for a temperature gauge. I recycled the LCD display from the previous post to display temperature readings using 'ring meter' widgets. The end result is that the M4 is used for reading DS18D20 sensors and updating the 'ring meter' widgets. In the video we have one sensor in a 3 pin TO-92 package reading room temperature and the other as a waterproof probe dipped into hot/cold water.

The DS18D20 one wire protocol simply requires a gpio pin that can be toggled between input and output modes albeit using precise timings to the microsecond (between 1 and 480 microseconds). The protocol and timings are described in the DS18B20 datasheet. To achieve the necessary level of time precision we utilised the imx6 Enhanced Periodic Interrupt Timer (EPIT) timers sourced from a 24Mhz clock. Since there are two DS18B20 sensors on the one wire bus we first query for the address of the sensors and then in turn poll for the temperature from each which takes approximately 480 microseconds.

Sunday, 30 April 2017

i.MX6SX - Using the cortex M4 on a UDOO NEO to drive a $4 Touch Screen

The challenge here was to see if a ultra cheap touch screen could be made to work with the cortex M4 on the UDOO NEO. The video (below) demonstrates its possible, the M4 is controlling the display and a simple UI allows the toggling of the green LED.


I managed to pick up a 2.0" touch screen for around $4, although the screen is on the slightly small side, it still manages to support a resolution of 320x240. Normally these type of screens are sold into a secondary market with the hope that they can be interfaced to an Arduino, their primary use seems to a PDA or home communication device given the imprinted icons (which aren't removable).


The display supports a 8 bit parallel LCD interface (using the S6D1125) along with a 4 wire resistive touch. The downside with using such a display is that it requires a large number of pins, in our case 12 GPIO pins and 2 analogue pins (for resistive touch).

The code to drive the display was built using the i.mx6sx FreeRTOS sdk.

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.