Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.

Eric Falsken

Member Since 31 Oct 2011
Offline Last Active Dec 22 2012 07:40 PM
-----

#41312 .NET MF 4.3 RTM ... Where's the new SDK?

Posted by Eric Falsken on 10 December 2012 - 11:47 AM

You can use 4.1/4.2 with Visual Studio 2012


I can confirm this working. After installing the MF 4.3 SDK, Visual Studio 2012 shows all of the .NET Micro Framework versions, so it must include the multi-targeting pack all the way back to 4.2 and 4.1.

I was also able to open my old Netduino project and build+deploy+debug with no problem.

The only thing missing are the Netduino-specific project templates, which you can copy from MyDocuments\Visual Studio 2010\Templates\ProjectTemplates to MyDocuments\Visual Studio 2012\Templates\ProjectTemplates.


#21193 Real-Time Clock (DS1307) for I2C

Posted by Eric Falsken on 01 December 2011 - 12:00 AM

Hey guys, I got one of the DS1307 breakouts from Sparkfun and spent the weekend getting it working.

Attached File  Untitled Sketch 2_bb.png   34.46KB   288 downloads

The 5 wires (from top of the black part) are SDA, SCL, SQW, GND, 5V. The resistors are both 1k Ohm from the SDA/SCL lines to 5V.

For the code, I started with what I found over in the NetduinoHelpers project, but I enhanced and refactored it a lot. The new code supports the 12/24 flag properly. It also will share the I2CDevice with other classes that might need to use it at the same time by locking the I2CDevice instance before interacting with it.

My version of the DS1307 class is attached below too for easy downloading.

using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace netduino.helpers.Hardware {
	/// <summary>
	/// This class implements a complete driver for the Dallas Semiconductors / Maxim DS1307 I2C real-time clock: http://pdfserv.maxim-ic.com/en/ds/DS1307.pdf
	/// </summary>
	public class IcDS1307 : IDisposable
	{
		[Flags]
		// Defines the frequency of the signal on the SQW interrupt pin on the clock when enabled
		public enum SQWFreq { SQW_1Hz, SQW_4kHz, SQW_8kHz, SQW_32kHz, SQW_OFF };

		[Flags]
		// Defines the logic level on the SQW pin when the frequency is disabled
		public enum SQWDisabledOutputControl { Zero, One };

		// Real time clock I2C address
		public const int DS1307_I2C_ADDRESS = 0x68;
		// I2C bus frequency for the clock
		public const int DS1307_I2C_CLOCK_RATE_KHZ = 100;
		
		// Allow 10ms timeouts on all I2C transactions
		public const int DS1307_I2C_TRANSACTION_TIMEOUT_MS = 10;
		
		// Start / End addresses of the date/time registers
		public const byte DS1307_RTC_START_ADDRESS = 0x00;
		public const byte DS1307_RTC_END_ADDRESS = 0x06;
		public const byte DS1307_RTC_SIZE = 7;

		// Square wave frequency generator register address
		public const byte DS1307_SQUARE_WAVE_CTRL_REGISTER_ADDRESS = 0x07;

		// Start / End addresses of the user RAM registers
		public const byte DS1307_RAM_START_ADDRESS = 0x08;
		public const byte DS1307_RAM_END_ADDRESS = 0x3f;

		// Total size of the user RAM block
		public const byte DS1307_RAM_SIZE = 56;

		// Instance of the I2C clock
		readonly bool privateClock = false;
		readonly I2CDevice clock;
		readonly I2CDevice.Configuration config = new I2CDevice.Configuration(DS1307_I2C_ADDRESS, DS1307_I2C_CLOCK_RATE_KHZ);

		public IcDS1307() {
			privateClock = true;
			clock = new I2CDevice(config);
		}

		public IcDS1307(I2CDevice device) {
			clock = device;
		}

		/// <summary>
		/// Gets or Sets the current date / time.
		/// </summary>
		/// <returns>A DateTime object</returns>
		public DateTime CurrentDateTime {
			get {
				byte[] clockData = ReadRegister(DS1307_RTC_START_ADDRESS, DS1307_RTC_SIZE);
				return ParseDate(clockData);
			}
			set {
				WriteRegister(DS1307_RTC_START_ADDRESS, EncodeDate(value, ClockHalt, TwelveHourMode));
			}
		}
  
		private DateTime ParseDate(byte[] clockData) {
			int hour = 0;
			if ((clockData[0x02] & 0x40) == 0x40) { // 12-hour mode
				if ((hour & 0x20) == 0x20)
					hour += 12;
				hour += BcdToDec((byte)(clockData[0x02] & 0x1f)) + 1;
			}
			else { // 24-hour mode
				hour += BcdToDec((byte)(clockData[0x02] & 0x3f));
			}

			return new DateTime(
				BcdToDec(clockData[0x06]) + 2000, // year
				BcdToDec(clockData[0x05]), // month
				BcdToDec(clockData[0x04]), // day
				hour, // hour
				BcdToDec(clockData[0x01]), // minutes
				BcdToDec((byte)(clockData[0x00] & 0x7f)));
		}

		private byte[] EncodeDate(DateTime value, bool clockHalt, bool hourMode) {
			byte seconds = 0x00;
			if (clockHalt) seconds |= 0x80;
			seconds |= (byte)(DecToBcd(value.Second) & 0x7f);

			byte hour = 0x00;
			if (hourMode) { // 12-hour mode
				hour |= 0x40; //set the 12-hour flag
				if (value.Hour >= 12)
					hour |= 0x20;
				hour |= DecToBcd((value.Hour % 12) + 1);
			}
			else { //24-hour mode
				hour |= DecToBcd(value.Hour);
			}

			return new byte[DS1307_RTC_SIZE] { 
				seconds, 
				DecToBcd(value.Minute), 
				hour, 
				DecToBcd((int)value.DayOfWeek), 
				DecToBcd(value.Day), 
				DecToBcd(value.Month), 
				DecToBcd(value.Year - 2000)};
		}

		/// <summary>
		/// Enables / Disables the square wave generation function of the clock.
		/// Requires a pull-up resistor on the clock's SQW pin.
		/// </summary>
		/// <param name="Freq">Desired frequency or disabled</param>
		/// <param name="OutCtrl">Logical level of output pin when the frequency is disabled (zero by default)</param>
		public void SetSquareWave(SQWFreq Freq, SQWDisabledOutputControl OutCtrl = SQWDisabledOutputControl.Zero) {
			byte SqwCtrlReg = (byte) OutCtrl;
			
			SqwCtrlReg <<= 3;   // bit 7 defines the square wave output level when disabled
								// bit 6 & 5 are unused

			if (Freq != SQWFreq.SQW_OFF) {
				SqwCtrlReg |= 1;
			}

			SqwCtrlReg <<= 4; // bit 4 defines if the oscillator generating the square wave frequency is on or off.
							  // bit 3 & 2 are unused
			
			SqwCtrlReg |= (byte) Freq; // bit 1 & 0 define the frequency of the square wave
			
			WriteRegister(DS1307_SQUARE_WAVE_CTRL_REGISTER_ADDRESS, SqwCtrlReg);
		}

		/// <summary>
		/// Halts / Resumes the time-keeping function on the clock.
		/// The value of the seconds register will be preserved.
		/// (True: halt, False: resume)
		/// </summary>
		public bool ClockHalt {
			get {
				var seconds = this[0x00];
				return (seconds & 0x80) == 0x80;
			}
			set {
				lock (clock) {
					var seconds = this[0x00];

					if (value)
						seconds |= 0x80; // Set bit 7
					else
						seconds &= 0x7f; // Reset bit 7

					WriteRegister(0x00, seconds);
				}
			}
		}

		/// <summary>
		/// Gets/Sets the Hour mode.
		/// The current time will be corrected. 
		/// (True: 12-hour, False: 24-hour)
		/// </summary>
		public bool TwelveHourMode {
			get {
				var hours = this[0x02];
				return (hours & 0x40) == 0x40;
			}
			set {
				lock (clock) {
					var rtcBuffer = ReadRegister(DS1307_RTC_START_ADDRESS, 7);
					var currentDate = ParseDate(rtcBuffer);
					rtcBuffer = EncodeDate(currentDate, false, value);

					WriteRegister(0x02, rtcBuffer[0x02]);
				}
			}
		}

		/// <summary>
		/// Writes to the clock's user RAM registers as a block
		/// </summary>
		/// <param name="buffer">A byte buffer of size DS1307_RAM_SIZE</param>
		public void SetRAM(byte[] buffer) {
			if (buffer.Length != DS1307_RAM_SIZE)
				throw new ArgumentOutOfRangeException("Invalid buffer length");

			WriteRegister(DS1307_RAM_START_ADDRESS, buffer);
		}

		/// <summary>
		/// Reads the clock's user RAM registers as a block.
		/// </summary>
		/// <returns>A byte array of size DS1307_RAM_SIZE containing the user RAM data</returns>
		public byte[] GetRAM() {
			return ReadRegister(DS1307_RAM_START_ADDRESS, DS1307_RAM_SIZE);
		}

		public byte this[byte address] {
			get { return ReadRegister(address, 1)[0]; }
			set { WriteRegister(address, value); }
		}

		/// <summary>
		/// Reads an arbitrary RTC or RAM register
		/// </summary>
		/// <param name="address">Register address between 0x00 and 0x3f</param>
		/// <param name="length">The number of bytes to read</param>
		/// <returns>The value of the bytes read at the address</returns>
		public byte[] ReadRegister(byte address, int length = 1) {
			if (length < 1) throw new ArgumentOutOfRangeException("length", "Must read at least 1 byte");
			if (address + length -1 > DS1307_RAM_END_ADDRESS) throw new ArgumentOutOfRangeException("Invalid register address");

			var buffer = new byte[length];

			lock (clock) {
				clock.Config = config;
				// Read the RAM register @ the address
				var transaction = new I2CDevice.I2CTransaction[] {
						I2CDevice.CreateWriteTransaction(new byte[] {address}),
						I2CDevice.CreateReadTransaction(buffer) 
					};

				if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
					throw new Exception("I2C transaction failed");
				}
			}

			return buffer;
		}

		/// <summary>
		/// Writes an arbitrary RTC or RAM register
		/// </summary>
		/// <param name="address">Register address between 0x00 and 0x3f</param>
		/// <param name="val">The value of the byte to write at that address</param>
		public void WriteRegister(byte address, byte data) {
			WriteRegister(address, new byte[] { data });
		}

		public void WriteRegister(byte address, byte[] data) {
			if (address > DS1307_RAM_END_ADDRESS)
				throw new ArgumentOutOfRangeException("Invalid register address");
			if (address + data.Length > DS1307_RAM_END_ADDRESS)
				throw new ArgumentException("Buffer overrun");

			byte[] txData = new byte[data.Length + 1];
			txData[0] = address;
			data.CopyTo(txData, 1);

			lock (clock) {
				clock.Config = config;
				var transaction = new I2CDevice.I2CWriteTransaction[] {
					I2CDevice.CreateWriteTransaction(txData)
				};

				if (clock.Execute(transaction, DS1307_I2C_TRANSACTION_TIMEOUT_MS) == 0) {
					throw new Exception("I2C write transaction failed");
				}
			}
		}

		/// <summary>
		/// Takes a Binary-Coded-Decimal value and returns it as an integer value
		/// </summary>
		/// <param name="val">BCD encoded value</param>
		/// <returns>An integer value</returns>
		protected int BcdToDec(byte val) {
			int ones = (val & 0x0f);
			int tens = (val & 0xf0) >> 4;
			return (tens * 10) + ones;
		}

		/// <summary>
		/// Takes a Decimal value and converts it into a Binary-Coded-Decimal value
		/// </summary>
		/// <param name="val">Value to be converted</param>
		/// <returns>A BCD-encoded value</returns>
		protected byte DecToBcd(int val) {
			byte lowOrder = (byte)(val % 10);
			byte highOrder = (byte)((val / 10) << 4);
			return (byte)(highOrder | lowOrder);
		}
		
		/// <summary>
		/// Releases clock resources
		/// </summary>
		public void Dispose() {
			if(privateClock)
				clock.Dispose();
		}
	}
}

Attached Files




#20826 Mayhew Labs MuxShield and TI 74HC4067

Posted by Eric Falsken on 21 November 2011 - 03:55 PM

As seen on the SparkFun and Mayhew Labs websites. (schematic) The board comes fully assembled with quality components. Very well built. I'm happy to announce that it is 100% Netduino compatible with no flaws, although there is a bit of confusion about what this board is and is not.

  • 3 TI 74HC4067 Analog/Digital Muxer chips allow you to work with analog or digital signals from 2-6V. (but it just passes them through to your Netduino, so more than 5V isn't safe)
  • 48 GPIO pins for the cost of 7 (D2-5, A0-2)
  • All pins are individually addressable (although not all at the same time, and without a "latch")
  • Very convenient 5v and Ground pins adjacent to every header.
  • In a compact, stackable shield.

First the code to drive the 74HC4067. The code below should also compatible with any other 74HC4067 usage. (like the SparkFun breakout)

public class Ic74HC4067 {
	private readonly OutputPort _s0 = null;
	private readonly OutputPort _s1 = null;
	private readonly OutputPort _s2 = null;
	private readonly OutputPort _s3 = null;
	private readonly Port _commonRead = null;
	private readonly OutputPort _commonWrite = null;
	private readonly AnalogInput _analogRead = null;
	private readonly OutputPort _enable = null;

	/// <summary>
	/// A list of all General Purpose Input/Output pins
	/// </summary>
	public enum Pins : byte {
		/// <summary>1st GPO pin</summary>
		GPIO_PIN_00,
		/// <summary>2nd GPO pin</summary>
		GPIO_PIN_01,
		/// <summary>3rd GPO pin</summary>
		GPIO_PIN_02,
		/// <summary>4th GPO pin</summary>
		GPIO_PIN_03,
		/// <summary>5th GPO pin</summary>
		GPIO_PIN_04,
		/// <summary>6th GPO pin</summary>
		GPIO_PIN_05,
		/// <summary>7th GPO pin</summary>
		GPIO_PIN_06,
		/// <summary>8th GPO pin</summary>
		GPIO_PIN_07,
		/// <summary>9th GPO pin</summary>
		GPIO_PIN_08,
		/// <summary>10th GPO pin</summary>
		GPIO_PIN_09,
		/// <summary>11th GPO pin</summary>
		GPIO_PIN_10,
		/// <summary>12th GPO pin</summary>
		GPIO_PIN_11,
		/// <summary>13th GPO pin</summary>
		GPIO_PIN_12,
		/// <summary>14th GPO pin</summary>
		GPIO_PIN_13,
		/// <summary>15th GPO pin</summary>
		GPIO_PIN_14,
		/// <summary>16th GPO pin</summary>
		GPIO_PIN_15,
		/// <summary>Common I/O disabled</summary>
		GPIO_PIN_OFF = 0x10
	}

	public Ic74HC4067(Cpu.Pin s0, Cpu.Pin s1, Cpu.Pin s2, Cpu.Pin s3, Cpu.Pin common, Cpu.Pin enable, bool analog) :
		this(new OutputPort(s0, false), new OutputPort(s1, false), new OutputPort(s2, false), new OutputPort(s3, false)) {
		if (enable != Cpu.Pin.GPIO_NONE)
			_enable = new OutputPort(enable, true);
		if (common != Cpu.Pin.GPIO_NONE) {
			if (analog)
				_analogRead = new AnalogInput(common);
			else {
				_commonWrite = new OutputPort(common, false);
				_commonRead = _commonWrite;
			}
		}
	}

	public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3) : this(s0, s1, s2, s3, null, null) { }

	public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3, Port common) : this(s0, s1, s2, s3, common, null) { }

	public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3, Port common, OutputPort enable) {
		if (s0 == null) throw new ArgumentNullException("s0", "s0 is required");
		if (s1 == null) throw new ArgumentNullException("s1", "s1 is required");
		if (s2 == null) throw new ArgumentNullException("s2", "s2 is required");
		if (s3 == null) throw new ArgumentNullException("s3", "s3 is required");
		_s0 = s0;
		_s1 = s1;
		_s2 = s2;
		_s3 = s3;
		_commonRead = common;
		if(common != null)
			_commonWrite = common as OutputPort;
		_enable = enable;
	}

	public Ic74HC4067(OutputPort s0, OutputPort s1, OutputPort s2, OutputPort s3, AnalogInput common){
		_s0 = s0;
		_s1 = s1;
		_s2 = s2;
		_s3 = s3;
		_analogRead = common;
	}

	/// <summary>
	/// Sets the currently operating GPIO pin.
	/// </summary>
	public Pins CurrentPin {
		get {
			if (_enable != null && _enable.Read())
				return Pins.GPIO_PIN_OFF;

			byte ret = 0;
			if (_s3.Read())
				ret |= 0x08;
			if (_s2.Read())
				ret |= 0x04;
			if (_s1.Read())
				ret |= 0x02;
			if (_s0.Read())
				ret |= 0x01;
			return (Pins)ret; 
		}
		set {
			if (value == Pins.GPIO_PIN_OFF)
				Enabled = false;

			_s3.Write(((byte)value & 0x08) == 0x08);
			_s2.Write(((byte)value & 0x04) == 0x04);
			_s1.Write(((byte)value & 0x02) == 0x02);
			_s0.Write(((byte)value & 0x01) == 0x01);
		}
	}

	/// <summary>
	/// When true, disables all GPIO output pins. (true=low, false=high)
	/// </summary>
	public bool Enabled {
		get {
			if (_enable == null) throw new InvalidOperationException("Enable pin is not specified.");
			return !_enable.Read(); }
		set {
			if (_enable == null) throw new InvalidOperationException("Enable pin is not specified.");
			_enable.Write(!value); 
		}
	}

	public bool ReadBit() {
		if (_commonRead == null) throw new InvalidOperationException("CommonIO pin is not specified or not in digital mode.");
		return _commonRead.Read();
	}

	public void WriteBit(bool value) {
		if (_commonWrite == null) throw new InvalidOperationException("CommonIO pin is not specified or is not writeable.");
		_commonWrite.Write(value);
	}

	public int ReadValue() {
		if (_analogRead == null) throw new InvalidOperationException("CommonIO pin is not specified or not in analog mode.");
		return _analogRead.Read();
	}

	public override string ToString() {
		if (_commonWrite != null)
			return "Ic74HC4067 out=" + (_commonWrite.Read() ? "1" : "0");
		if (_commonRead != null)
			return "Ic74HC4067 dIn=" + (_commonRead.Read() ? "1" : "0");
		if (_analogRead != null)
			return "Ic74HC4067 aIn=" + _analogRead.Read();
		return base.ToString();
	}
}

And now the MuxShield driver class:

public class MuxShield {
	public readonly Ic74HC4067[] muxes = new Ic74HC4067[3];
	public readonly OutputPort S0 = new OutputPort(Pins.GPIO_PIN_D2, false);
	public readonly OutputPort S1 = new OutputPort(Pins.GPIO_PIN_D3, false);
	public readonly OutputPort S2 = new OutputPort(Pins.GPIO_PIN_D4, false);
	public readonly OutputPort S3 = new OutputPort(Pins.GPIO_PIN_D5, false);
	public readonly OutputPort D13LED = new OutputPort(Pins.GPIO_PIN_D13, false);
	const Cpu.Pin GPIO_MUX0 = Pins.GPIO_PIN_A0;
	const Cpu.Pin GPIO_MUX1 = Pins.GPIO_PIN_A1;
	const Cpu.Pin GPIO_MUX2 = Pins.GPIO_PIN_A2;

	public enum MuxMode{
		AnalogInput,
		DigitalInput,
		DigitalOutput
	}

	public MuxShield(MuxMode mode0, MuxMode mode1, MuxMode mode2) {
		muxes[0] = CreateMux(mode0, GPIO_MUX0);
		muxes[1] = CreateMux(mode1, GPIO_MUX1);
		muxes[2] = CreateMux(mode2, GPIO_MUX2);
	}

	protected Ic74HC4067 CreateMux(MuxMode mode, Cpu.Pin iopin) {
		switch (mode) {
			case MuxMode.AnalogInput:
				return new Ic74HC4067(S0, S1, S2, S3, new AnalogInput(iopin));
			case MuxMode.DigitalInput:
				return new Ic74HC4067(S0, S1, S2, S3, new InputPort(iopin, false, Port.ResistorMode.PullDown));
			case MuxMode.DigitalOutput:
				return new Ic74HC4067(S0, S1, S2, S3, new OutputPort(iopin, false));
			default:
				throw new InvalidOperationException();
		}
	}

	/// <summary>
	/// Sets the currently operating pins
	/// </summary>
	public Ic74HC4067.Pins CurrentPin {
		get {
			//On the MuxShield, all Ic74HC4067 chips share the same s0-s3 pins, so setting one of them is good enough.
			return MUX0.CurrentPin; }
		set { MUX0.CurrentPin = value; }
	}

	public Ic74HC4067 this[int index]{
		get{
			return muxes[index];
		}
	}

	public Ic74HC4067 MUX0 { get{return this[0];} }
	public Ic74HC4067 MUX1 { get{return this[1];} }
	public Ic74HC4067 MUX2 { get{return this[2];} }

	public override string ToString() {
		string ret = "MuxShield ";
		ret += (S3.Read() ? "1" : "0");
		ret += (S2.Read() ? "1" : "0");
		ret += (S1.Read() ? "1" : "0");
		ret += (S0.Read() ? "1" : "0");
		ret += " ";
		ret += MUX0.ToString();
		ret += " ";
		ret += MUX1.ToString();
		ret += " ";
		ret += MUX2.ToString();
		return ret;
	}
}

And the sample program to make it blink a handful of LEDs in sequence:

public static void Main() {
	MuxShield shield = new MuxShield(MuxShield.MuxMode.DigitalOutput, MuxShield.MuxMode.DigitalOutput, MuxShield.MuxMode.DigitalOutput);
	//Set the pins high so that as we move through the pins, LEDs will light up
	shield.MUX0.WriteBit(true);
	shield.MUX1.WriteBit(true);
	shield.MUX2.WriteBit(true);

	while (true) {
		for (byte x = 0; x <= 15; x+=2) {
			//itterate over the pins
			shield.CurrentPin = (Ic74HC4067.Pins)x;
			//blink the onboard led
			shield.D13LED.Write(!shield.D13LED.Read());
			Debug.Print(shield.ToString());
			Thread.Sleep(100);
		}
	}
}



home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.