Friday, December 9, 2016

Caveat: multimaster I2C on 32-bit Arduino's

For a new project I'm working on, it was necessary to allow for bidirectional communication on a shared I2C bus between a bunch of Arduino's (more specifically, a healthy mix of Arduino MKR1000's and Adafruit Feather M0's). After some quick researching, I found a few easy looking examples on how to use some mixture of master/slave settings in a "multimaster" mode with Arduino's Wire library (the TwoWire/I2C implementation). You can read them here, here and here, and they basically all do the following "trick" during initialization:
 Wire.begin(MY_ADDRESS);
 Wire.onReceive(receiveI2C);
and then for sending data, they use:
 Wire.beginTransmission(DEST_ADDRESS);
 Wire.write(0x30);
 Wire.endTransmission();
So what's happening here?

  • Basically, if you use Wire.begin(MY_ADDRESS) you are initializing the I2C bus in slave mode, and by registering the "onReceive" interrupt service handler, you define what needs to happen when the slave receives data. 
  • Next up, these examples all start sending data as a MASTER (despite being configured as a slave) by initializing the transmission, writing the data and then putting the data on the bus with the endTransmission() call. 
This works on 8-bit AVR Arduino's (and a bunch of other devices) because of how the Wire library is implemented on these devices. Just have a look at the following files (from your Arduino IDE installation folder):
  • hardware\arduino\avr\libraries\Wire\src\Wire.cpp
  • hardware\arduino\avr\libraries\Wire\src\utility\twi.c
You can see endTransmission() calls the twi_WriteTo() function from twi.c (yes, Wire is merely a wrapper around some C implementation of I2C). What does twi_WriteTo() do? It attempts to become the master on the I2C bus and then sends data.  That's actually a very good way of combining master & slave functionality on a single device on the I2C bus, and most definitely the way to go.

Now cue the Wire implementation on the 32-bit Atmel processors. These use the hardware SERCOM's of the SAMD21 processors, and directly use the corresponding I2C (well.. SERCOM) hardware registers to put the MCU in I2C master or slave mode... Unfortunately, there is no corresponding temporary promotion to a master going on in this implementation. Let's have a look at the SAMD21 implementation of Wire, which you can find in your %LOCALAPPDATA%\Arduino15\packages\arduino\hardware\samd\1.6.8\libraries\Wire folder:
  • The endTransmission() implementation directly calls SERCOM->startTransmissionWIRE(), which is from the the %LOCALAPPDATA%\Arduino15\packages\arduino\hardware\samd\1.6.8\cores\arduino\SERCOM.cpp file.
  • That startTransmissionWIRE() function first checks if the I2C bus is idle (multimaster collision protection) or whether it already owns the I2C bus using:

    while ( !isBusIdleWIRE() && !isBusOwnerWIRE() );
Unfortunately, both these functions assume the SERCOM was initialized as a master, and since the Wire.begin() was called with a slave address and hence the entire MCU was initialized as a slave. I haven't worked out the details yet but you'll see that the sketch remains stuck in this while loop because the conditions are never met.

This is one of the many differences between AVR & SAMD based Arduino's that you'll encounter when diving into the details. The solution is to do extend your code and do your own proper promotion towards I2C master when you need to send data, and depromote yourself to slave in case you don't need to send anything... basically mimicing the behaviour of the original twi.c that all started it.


Friday, September 16, 2016

MKR1000 support in the Arduino IDE

I started experimenting with the Arduino/Genuino MKR1000 board that I received today for another IoT project that we're working on at ThingTank. There are a few caveats when trying to access the board that you might run into:

  • First of all, be sure to use the Arduino.cc IDE and not the Arduino.org IDE. At the time of writing you can distinguish them in the version number; you'll need the 1.6.x releases and not the 1.7.x releases. It might seem like you're using an "older" version but that is not the case; they are just different branches of a very similar IDE.

    The biggest difference is that the Arduino.org IDE at the moment does not have the simple "Board Manager" user interface to enable other boards than the standard Atmel AVR boards.
  • Then, use the "Board Manager" to install the "Arduino SAMD" toolchain. When starting the board manager, I received a "package_index.json file signature verification failed" error message.

    Not sure what caused this (remnant of my previous 1.7.x Arduino IDE installation?), but I had a remnant package_index.json.sig file in the Arduino AppData folder (%APPDATA%/Local/Arduino15/). After deleting that file, I was able to search and install in the Board Manager correctly.
After installation of the Arduino SAMD Boards support, you can now select the MKR1000 as one of the boards in the IDE and start fiddling around! Hurray!

Sunday, October 4, 2015

VMware Workstation: scripting unity mode

When trying to keep a whole bunch of legacy programs running at a case appointed to me, it was necessary to use Windows 7 running in a virtual machine under VMware Workstation (running on Windows 10). To prevent the VM's of staying on after the program execution finished, I wrote a small batch file on the virtualization host to start and suspend the VM:

@echo off
cd C:\Program Files (x86)\VMware\VMware Workstation

vmrun start C:\VMs\Win7\Win7.vmx

vmrun -T ws -gu -gp runProgramInGuest C:\VMs\Win7\Win7.vmx -activeWindow -interactive "C:\Program Files\MyLegacyApp\Legacy.exe"

vmrun suspend C:\VMs\Win7\Win7.vmx

This works fine, since the vmrun "runProgramInGuest" runs synchronously, only terminating after the application inside the guest VM has finished -- which then nicely calls a "suspend" to freeze the VM for the next time the batch file is called on the host.

However, to improve even further the user experience, I wanted to use VMware Workstation's unity feature. That turned out to be more difficult in my setting than I had expected: whether Unity was used the last time in the VM or not, the script above always opens the VMware Workstation GUI and just shows the VM starting. I also read about adding the following lines to the VMX file:

gui.fullScreenAtPowerOn = "FALSE"
gui.lastPoweredViewMode = "unity"
gui.viewModeAtPowerOn = "unity"

Yet that didn't work either... 

So instead, I decide to use a workaround that does both the scripted & synchronous execution of the program I need in the guest, and enables Unity at the same time:
  • I run a dummy program in "Unity" which puts the (running) VM in Unity view mode -- notice that vmware-unity-helper.exe works asynchronously, hence immediately returns.
  • Afterwards, I start the Legacy.exe using vmrun.
To complicate matters further, also multiple users have to be able to run the program in the same Workstation VM, so some "preconfiguration" for Unity is required for every user.

In a nutshell:
  • vmware-unity-helper.exe on Windows seems to only run predefined commands on predefined VMs. The configuration is under %LOCALAPPDATA%\VMware\unity-helper.xml.
  • This file looks (in my case) as follows:

    <unity_helper version="1">
      <ghilaunch>
        <apps nextid="3">
          <app id="1" uri="file:///d:/dummy.lnk">
        </apps>
        <vms nextid="2">
          <vm id="1" path="C:\VMs\Win7\Win7.vmx">
        </vms>
      </ghilaunch>
    </unity_helper>
  • You can see in the XML file:
    • First, all applications that Unity can start are defined using an App ID and the URI on where the file is located.
    • Then, a list of all known VMs is provided, with the path to the VMX file.
  • An application is then started with vmware-unity-helper.exe as follows:

    vmware-unity-helper.exe -r -G:1 -V:1

    where the "G" parameter specifies the app ID and the V parameter the VM ID.
So in order to have any user utilize Unity, I modified the script above as follows:

@echo off
C:
cd C:\Program Files (x86)\VMware\VMware Workstation

REM Prepare unity
copy /Y C:\VMs\unity-helper.xml %LOCALAPPDATA%\VMware\unity-helper.xml >NUL

REM Start VM
vmrun start C:\VMs\Win7\Win7.vmx nogui

REM Now run application 
vmware-unity-helper.exe -r -G:1 -V:1
vmrun -T ws -gu Adobe -gp adobe runProgramInGuest C:\VMs\Win7\Win7.vmx -activeWindow -interactive "D:\Program Files\MyLegacyApp\Legacy.exe"

REM Now suspend VM
vmrun suspend C:\VMs\Win7\Win7.vmx

This script:
  1. First copies the predefined XML file to the %LOCALAPPDATA% folder (overwriting anything there -- my users don't use Unity for other purposes, so if you need to support that too you'll need to do some more magic).
  2. Then we start the VM as before
  3. Next step is to run "a dummy application" using Unity, which sets the already running VM in Unity mode. More on this dummy application in a second.
  4. Then we starts the application again using vmrun, wait for it to end, and nicely close the VM as before.

The dummy application inside the VM is just a batch file "dummy.bat" with contents "@echo off" and "exit". I created a shortcut "dummy.lnk" to this "dummy.bat" so I can keep the command prompt window minimized (properties of shortcut) -- this prevents a unity window popping up & disappearing into view.

This works great and runs the application in Unity, nicely starting & stopping the VM as needed. Obviously the script should be extended to check if the VM is already running by another user, but that'll be for another time :). The only disadvantage is that you briefly still see the VMware Workstation window -- unfortunately using the "nogui" option with vmrun start does not seem to fix this...

As a sidenote, to top it of I:
  • Enabled "Shared Files" to make available the data directories of the users to the users under the guest OS, under a mapped network drive.
  • I disabled all unnecessary services in the VM for a very fast startup.
  • I've hidden all disk drives (C:, D:, E:) in the guest VM using group policy (https://support.microsoft.com/kb/231289) - to ensure the users can only see the "Shared Folders" and never mistakenly save data inside the guest.
  • The VM was located on a SSD disk so the Windows 7 in the guest starts incredibly fast 

Tuesday, August 18, 2015

Erratic mouse movement in VMware Workstation on a second screen

I heavily rely on VMware workstation for running all flavours of OS's (from Linux to older Windows versions, and there might even be a MacOSX for iOS development running somewhere, maybe). After upgrading to Windows 10 on my new laptop (with a 1080p screen compared to the previous device I was using), I noticed that all of my machines were behaving strange, to the point that basically none of them were useful anymore.

Symptoms:

  • Mouse pointer "flickers" around the screen, when clicking/dragging, the mouse pointer jumps to the upper left corner.
  • This only happens when VMware Workstation is running on the second screen attached to the computer, not on the native screen.
  • It happens on ALL operating systems, Linux, Windows, and perhaps also on Mac OS X.
Been looking around a bit to found out what was causing this behaviour, and it turns out that it is a generic problem with Workstation itself.

Resolution:

Thank you VMware forums, the solution is to disable "Display scaling on high DPI settings" on the vmware.exe in the C:\Program Files (x86)\VMware\VMware Workstation folder. 

One of those issues that can drive you crazy, have you reinstalling your VM's a dozen of times thinking it is you doing something wrong, etc etc... so hope it helps :).

Friday, February 20, 2015

Removing OneDrive from Windows Explorer in Windows 10 TP

I've been using Windows 10 Technical Preview for a few months already, and installed the latest build 9926 a few days ago. Since I hardly use OneDrive (but instead a combination of... DropBox, Google Drive and my own OwnCloud), I prefer not to have it visibly polluting my Explorer windows.

In Windows 8.1, there was plenty of documentation on what registry keys to modify in order to hide OneDrive from explorer, see for example here. Unfortunately, the class ID for OneDrive changed in Windows 10 -- use the following registry location instead:

HKEY_CLASSES_ROOT\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}\ShellFolder

As described in the original EightForums article, set the "Attributes" key to f090004d. I've also discovered that in Windows 10 it is not necessary to perform the "64-bit" actions (no similar key exists under the Wow6432Node).

That already visually removes OneDrive. Next up, make sure it doesn't start again by modifying the "OneDrive" application settings. As back in the pre-Windows 8.1 era, OneDrive can again be disabled by rightclicking the OneDrive icon in the notification area, going to settings and disabling...


Finally, don't forget to enable "Save to Computer by default" in the various Office applications to prevent Office of trying to find that OneDrive folder again...



Et voila, at least in this Technical Preview OneDrive can be circumvented this way. No guarantees whether this will still be the case in future TP's or the RTM version of Windows 10 though...

Please note that this does have an impact on functionality, as Microsoft still has big plans to use OneDrive as to share data & settings across the entire Windows 10 platform - read Paul Thurrott's view on it here.

Tuesday, October 30, 2012

Windows 8 DNS resolution issues and IPv6

One small issue that I faced already a few times, is that the Windows TCP/IP stack does not seem to be able to properly resolve a DNS hostname (FQDN) despite that nslookup returns a perfectly fine result. The same system was running fine in the same network under Windows 7.

The solution was to disable IPv6 on the network adapters of the system. This is just another example of strange issues with IPv6 that find their origin in the fact that the IPv6 code is in fact used very intensively throughout the Windows components. That is also the reason why Microsoft recommends against disabling IPv6. Well.. it helped me anyway, and was easier than configuring IPv6 addresses for my DNS server :).

Friday, September 21, 2012

Upgrading Windows 7 Ultimate to Windows 8 Enterprise

Unfortunately, Microsoft does not support performing an in-place upgrade of a Windows 7 Ultimate installation to a Windows 8 Enterprise edition; Windows 7 Ultimate can only be upgraded to Windows 8 Professional (since Windows 8 does not come with an Ultimate edition). True, there might be little added value for a home user in Windows 8 Enterprise, but since it was the only version I had ready on a bootable USB stick, I tried to fool the installer to continue anyway.

This was surprisingly easy. It suffices to modify the "EditionID" and "ProductName" registry keys in the following location:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Current Version

from "Ultimate" and "Windows 7 Ultimate" to "Enterprise" and "Windows 7 Enterprise" respectively, to let the installation proceed.