Rotary H1 Module

I am a newbie to gadgeteer. I just purchased an Rotary H1 Module to go with my FEZ Hydra. However, I notice there is no entry for this module in the Visual Studio 2012 tool box, nor are there any references in the project for this.

Obviously, the sample code on page: “https://www.ghielectronics.com/docs/202/rotary-h1-module” will not work for me.

How to I add the missing item from the toolbar or references?

hi rulonv, welcome to the forums !

The H1 module is a very new module, and I expect that the driver will be included in the very next SDK delivery, which while there’s no “firm” date for it’s release, the GHI team have reported that it’s likely to be in the next week or so - they may come along and qualify that :slight_smile:

So unfortunately, there isn’t even a driver uploaded to the codeplex site http://gadgeteer.codeplex.com/SourceControl/latest which is where you can also get the driver source code for the other established modules. Right now the only way is to either wait, or work on a driver yourself.

It’s long for a forum posting but here is driver.

#define USE_SOFTWARE_SPI

using System.Threading;
using GT = Gadgeteer;
using GTI = Gadgeteer.Interfaces;
using GTM = Gadgeteer.Modules;

namespace Gadgeteer.Modules.GHIElectronics
{
    /// <summary>
	/// A RotaryH1 module for Microsoft .NET Gadgeteer
    /// </summary>
    public class RotaryH1 : GTM.Module
	{
		private byte[] write1 = new byte[1];
		private byte[] write2 = new byte[2];
		private byte[] read2 = new byte[2];
		private byte[] read4 = new byte[4];

 #if USE_SOFTWARE_SPI
        private GTI.DigitalInput MISO;
        private GTI.DigitalOutput MOSI;
        private GTI.DigitalOutput CLOCK;
        private GTI.DigitalOutput CS;
 #else
        private readonly GTI.SPI.Configuration config;
        private readonly GTI.SPI spi;
 #endif

		/// <summary>Constructs a new instance of the RotaryH1 module.</summary>
        /// <param name="socketNumber">The socket that this module is plugged in to.</param>
		public RotaryH1(int socketNumber)
        {
            Socket socket = Socket.GetSocket(socketNumber, true, this, null);

 #if USE_SOFTWARE_SPI
            socket.EnsureTypeIsSupported('Y', this);

			this.CS = new GTI.DigitalOutput(socket, Socket.Pin.Six, true, this);
			this.MISO = new GTI.DigitalInput(socket, Socket.Pin.Eight, GTI.GlitchFilterMode.Off, GTI.ResistorMode.Disabled, this);
			this.MOSI = new GTI.DigitalOutput(socket, Socket.Pin.Seven, false, this);
			this.CLOCK = new GTI.DigitalOutput(socket, Socket.Pin.Nine, false, this);
 #else
            socket.EnsureTypeIsSupported('S', this);

            this.config = new GTI.SPI.Configuration(false, 0, 0, false, true, 1000);
			this.spi = new GTI.SPI(socket, this.config, GTI.SPI.Sharing.Shared, socket, GT.Socket.Pin.Six, this);
 #endif
            
			this.Initialize();
		}

		/// <summary>
		/// Gets the current count of the encoder.
		/// </summary>
		/// <returns>An integer representing the count.</returns>
		public int GetCount()
		{
			int count = this.Read2((byte)Commands.LS7366_READ | (byte)Registers.LS7366_CNTR);

			if ((this.ReadStatusReg() & 0x1) > 0) // native number
			{
				count = ~count;
				count &= 0x7FFF;
				count *= (-1);
			}

			return count;
		}

		/// <summary>
		/// Gets the current direction that the encoder count is going.
		/// </summary>
		/// <returns>The direction the encoder count is going.</returns>
		public Direction GetDirection()
		{
			return ((this.ReadStatusReg() & 0x2) >> 1) > 0 ? Direction.Up : Direction.Down;
		}

        private void Initialize()
        {
            this.Write((byte)Commands.LS7366_CLEAR | (byte)Registers.LS7366_MDR0);
			this.Write((byte)Commands.LS7366_CLEAR | (byte)Registers.LS7366_MDR1);
			this.Write((byte)Commands.LS7366_CLEAR | (byte)Registers.LS7366_STR);
			this.Write((byte)Commands.LS7366_CLEAR | (byte)Registers.LS7366_CNTR);
			this.Write((byte)Commands.LS7366_LOAD | (byte)Registers.LS7366_OTR);

            this.Write((byte)Commands.LS7366_WRITE | (byte)Registers.LS7366_MDR0,
                               (byte)MDR0Mode.LS7366_MDR0_QUAD1   // none quadrature mode
                             | (byte)MDR0Mode.LS7366_MDR0_FREER   // modulo-n counting 
                             | (byte)MDR0Mode.LS7366_MDR0_DIDX
                             | (byte)MDR0Mode.LS7366_MDR0_FFAC2);

			this.Write((byte)Commands.LS7366_WRITE | (byte)Registers.LS7366_MDR1,
                               (byte)MDR1Mode.LS7366_MDR1_2BYTE     // 2 byte counter mode
                             | (byte)MDR1Mode.LS7366_MDR1_ENCNT);   // enable counting
        }

		private byte ReadStatusReg()
		{
			return this.Read1((byte)((byte)Commands.LS7366_READ | (byte)Registers.LS7366_STR));
		}

        private byte Read1(byte register)
        {
			write1[0] = register;

 #if USE_SOFTWARE_SPI
            this.SoftwareSPI_WriteRead(write1, read2);
 #else
			this.spi.WriteRead(write1, read2);
 #endif
			return read2[1];
        }

		private short Read2(byte register)
        {
			write1[0] = register;

 #if USE_SOFTWARE_SPI
            this.SoftwareSPI_WriteRead(write1, read4);
 #else
			this.spi.WriteRead(write1, read4);
 #endif

			return (short)((read4[1] << 8) + read4[2]);
        }

        private void Write(byte register)
        {
			write1[0] = register;

 #if USE_SOFTWARE_SPI
            this.SoftwareSPI_WriteRead(write1, null);
 #else
			this.spi.Write(write1);
 #endif
		}

        private void Write(byte register, byte command)
        {
            write2[0] = register;
			write2[1] = command;

 #if USE_SOFTWARE_SPI
            this.SoftwareSPI_WriteRead(write2, null);
 #else
			this.spi.Write(write2);
 #endif
		}

 #if USE_SOFTWARE_SPI
        private void SoftwareSPI_WriteRead(byte[] write, byte[] read)
        {
            int writeLen = write.Length;
            int readLen = 0;

            if (read != null)
            {
                readLen = read.Length;

                for (int i = 0; i < readLen; i++)
                {
                    read[i] = 0;
                }
            }

            int loopLen = (writeLen < readLen ? readLen : writeLen);

            byte w = 0;

            CS.Write(false);

            // per byte
            for (int len = 0; len < loopLen; len++)
            {
                if (len < writeLen)
                    w = write[len];

                byte mask = 0x80;

                // per bit
                for (int i = 0; i < 8; i++)
                {
                    CLOCK.Write(false);

                    if ((w & mask) == mask)
                        MOSI.Write(true);
                    else
                        MOSI.Write(false);

                    CLOCK.Write(true);

                    if (true == MISO.Read())
                        if (read != null)
                            read[len] |= mask;

                    mask >>= 1;
                }

                MOSI.Write(false);
                CLOCK.Write(false);
            }

            Thread.Sleep(20);
            CS.Write(true);
        }
 #endif

		/// <summary>
		/// The direction the encoder is being turned.
		/// </summary>
		public enum Direction : byte
		{
			/// <summary>
			/// The count is going up.
			/// </summary>
			Up,
			/// <summary>
			/// The count is going down.
			/// </summary>
			Down
		}

		private enum Commands : byte
		{
			LS7366_CLEAR = 0x00, // clear register
			LS7366_READ = 0x40, // read register
			LS7366_WRITE = 0x80, // write register
			LS7366_LOAD = 0xC0, // load register
		}

		private enum Registers : byte
		{
			LS7366_MDR0 = 0x08, // select MDR0
			LS7366_MDR1 = 0x10, // select MDR1
			LS7366_DTR = 0x18, // select DTR
			LS7366_CNTR = 0x20, // select CNTR
			LS7366_OTR = 0x28, // select OTR
			LS7366_STR = 0x30, // select STR
		}

		private enum MDR0Mode : byte
		{
			LS7366_MDR0_QUAD0 = 0x00, // none quadrature mode
			LS7366_MDR0_QUAD1 = 0x01, // quadrature x1 mode
			LS7366_MDR0_QUAD2 = 0x02, // quadrature x2 mode
			LS7366_MDR0_QUAD4 = 0x03, // quadrature x4 mode

			LS7366_MDR0_FREER = 0x00, // free run mode
			LS7366_MDR0_SICYC = 0x04, // single cycle count mode
			LS7366_MDR0_RANGE = 0x08, // range limit count mode (0-DTR-0)
			// counting freezes at limits but 
			// resumes on direction reverse
			LS7366_MDR0_MODTR = 0x0C, // modulo-n count (n=DTR both dirs)

			LS7366_MDR0_DIDX = 0x00, // disable index
			LS7366_MDR0_LDCNT = 0x10, // config IDX as load DTR to CNTR
			LS7366_MDR0_RECNT = 0x20, // config IDX as reset CNTR (=0)
			LS7366_MDR0_LDOTR = 0x30, // config IDX as load CNTR to OTR  

			LS7366_MDR0_ASIDX = 0x00, // asynchronous index
			LS7366_MDR0_SYINX = 0x40, // synchronous IDX (if !NQUAD)

			LS7366_MDR0_FFAC1 = 0x00, // filter clock division factor=1
			LS7366_MDR0_FFAC2 = 0x80, // filter clock division factor=2

			LS7366_MDR0_NOFLA = 0x00, // no flags
		}

		private enum CountMode : byte
		{
			NoneQuad = 0x00, // none quadrature mode
			Quad1 = 0x01, // quadrature x1 mode
			Quad2 = 0x02, // quadrature x2 mode
			Quad4 = 0x03, // quadrature x4 mode
		}

		private enum MDR1Mode : byte
		{
			LS7366_MDR1_4BYTE = 0x00, // 4 byte counter mode
			LS7366_MDR1_3BYTE = 0x01, // 3 byte counter mode
			LS7366_MDR1_2BYTE = 0x02, // 2 byte counter mode
			LS7366_MDR1_1BYTE = 0x03, // 1 byte counter mode
			LS7366_MDR1_ENCNT = 0x00, // enable counting
			LS7366_MDR1_DICNT = 0x04, // disable counting
			LS7366_MDR1_FLIDX = 0x20, // FLAG on IDX (index)
			LS7366_MDR1_FLCMP = 0x40, // FLAG on CMP (compare)
			LS7366_MDR1_FLCY = 0x80, // FLAG on CY (carry)
		}
    }
}

hi
I’m measuring distances with Rotary H1, can not I get the same value for the same distance, for example, if I measure 1 metro, the value returned me sometimes is 270 other 325,190,170,250 … I tested with 4 rotary, is there any way correct this? I use rotaryH1.getCount().
Could you tell me what parameters I have to put the driver to always count on positive and obtain a long value instead of int for getCount () function

thank you very much

@ garrido00 - You should create a new thread for your issue since it isn’t related to this thread.