This entry's latest version is outdated and must be revised. Please see the documentation for the latest API.

I2C EEPROM/HUB module by Bec a Fuel

Oct. 11, 2012   |   Snippet   |   Licensed as Apache 2.0   |   1557 views

This is the driver (and example code) for the modules shown here : http://www.tinyclr.com/forum/topic?id=9084 and here : http://www.tinyclr.com/forum/topic?id=8905&page=2#msg88791

The modules contain an EEPROM and are also acting as a I2C hub, both for Gadgeteer I2C modules (Compass, Accelerometer, and so on).
Both modules can be chained together to extend the I2C line.

The smallest one is a very simple module and is using Gadgeteer sockets, standard 0.1" headers and screw-terminals for connecting devices.

The second one is a shield version and can be put on a PandaII (or Domino, Panda). It will then use the Arduino headers to connect to the I2C lines of the board and share it to the outside world using Gadgeteer headers, screw-terminals and 0.1" PTH headers.

It is programmed in plain NETMF because it can't be a Gadgeteer module (no sharing allowed for I2C in the Gadgeteer world).
It's working with NETMF 4.1 & 4.2.

Comments or questions?   Discuss on the forum.



Author Version Date
Bec a Fuel 2 10/17 '12 at 04:57pm
Bec a Fuel 1 10/11 '12 at 06:19pm
1 — Source
  1. /*
  2. Copyright 2012 Christophe Gerbier
  3. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
  4. http://www.apache.org/licenses/LICENSE-2.0
  5. Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
  6. */
  7.  
  8. /*
  9. References to add to the project :
  10. Microsoft.SPOT.Hardware
  11. Microsoft.SPOT.Native
  12. mscorlib
  13. */
  14.  
  15. using System;
  16. using System.Collections;
  17. using System.Threading;
  18. using I2CExtensions;
  19. using Microsoft.SPOT;
  20. using Microsoft.SPOT.Hardware;
  21.  
  22. namespace Becafuel
  23. {
  24. /// <summary>
  25. /// BafModule driver
  26. /// </summary>
  27. public class BafModule
  28. {
  29. private ArrayList DevList;
  30. private ArrayList CacheDevList;
  31. private I2CDevice MyI2CDevice;
  32. private I2CDevice.Configuration EEpromConfig;
  33.  
  34. /// <summary>
  35. /// Initializes a new instance of the <see cref="BafModule"/> class with the default address 0x50 (all dip-switches off).
  36. /// </summary>
  37. public BafModule() : this(0x50) { }
  38.  
  39. /// <summary>
  40. /// Initializes a new instance of the <see cref="BafModule"/> class.
  41. /// </summary>
  42. /// <param name="Address">Address of the onboard EEPROM set by dip-switches.</param>
  43. public BafModule(Byte Address)
  44. {
  45. EEpromConfig = new I2CDevice.Configuration((UInt16)(Address), 400);
  46. MyI2CDevice = new I2CDevice(EEpromConfig);
  47. DevList = new ArrayList();
  48. CacheDevList = new ArrayList();
  49. AddDevice("eeprom", EEpromConfig);
  50. }
  51.  
  52. #region Eeprom methods
  53. /// <summary>
  54. /// Writes a byte value into the onboard EEPROM
  55. /// </summary>
  56. /// <param name="Address">The address to write to.</param>
  57. /// <param name="data">The byte value to store.</param>
  58. public void EEWrite(Int32 Address, Byte data)
  59. {
  60. EEWrite(EEpromConfig, Address, data);
  61. }
  62.  
  63. /// <summary>
  64. /// Writes a byte value into another module's EEPROM
  65. /// </summary>
  66. /// <param name="Config">The I2CDevice.Configuration of the EEPROM</param>
  67. /// <param name="Address">The address to write to.</param>
  68. /// <param name="data">The byte value to store.</param>
  69. public void EEWrite(I2CDevice.Configuration Config, Int32 Address, Byte data)
  70. {
  71. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(new Byte[] { (Byte)(Address >> 8), (Byte)(Address & 0xFF), data }) }, 1000);
  72. Thread.Sleep(5);
  73. }
  74.  
  75. /// <summary>
  76. /// Writes an Int32 value into the onboard EEPROM
  77. /// </summary>
  78. /// <param name="Address">The address to write to.</param>
  79. /// <param name="data">The Int32 value to store.</param>
  80. public void EEWrite(Int32 Address, Int32 data)
  81. {
  82. EEWrite(EEpromConfig, Address, data);
  83. }
  84.  
  85. /// <summary>
  86. /// Writes an Int32 value into another module's EEPROM
  87. /// </summary>
  88. /// <param name="Config">The I2CDevice.Configuration of the EEPROM</param>
  89. /// <param name="Address">The address to write to.</param>
  90. /// <param name="data">The Int32 value to store.</param>
  91. public void EEWrite(I2CDevice.Configuration Config, Int32 Address, Int32 data)
  92. {
  93. Byte[] TabTmp = new Byte[4];
  94. TabTmp[0] = (Byte)data;
  95. TabTmp[1] = (Byte)(data >> 8);
  96. TabTmp[2] = (Byte)(data >> 16);
  97. TabTmp[3] = (Byte)(data >> 24);
  98. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(new Byte[] { (Byte)(Address >> 8), (Byte)(Address & 0xFF), TabTmp[0], TabTmp[1], TabTmp[2], TabTmp[3] }) }, 1000);
  99. Thread.Sleep(5);
  100. }
  101.  
  102. /// <summary>
  103. /// Writes a String value into the onboard EEPROM
  104. /// </summary>
  105. /// <param name="Address">The address to write to.</param>
  106. /// <param name="Text">The String value to store.</param>
  107. public void EEWrite(Int32 Address, String Text)
  108. {
  109. EEWrite(EEpromConfig, Address, Text);
  110. }
  111.  
  112. /// <summary>
  113. /// Writes a String value into another module's EEPROM.
  114. /// </summary>
  115. /// <param name="Config">The I2CDevice.Configuration of the EEPROM.</param>
  116. /// <param name="Address">The address to write to.</param>
  117. /// <param name="Text">The String value to store.</param>
  118. public void EEWrite(I2CDevice.Configuration Config, Int32 Address, String Text)
  119. {
  120. var Addr = Address;
  121. Byte[] Buffer = System.Text.Encoding.UTF8.GetBytes("00" + Text); // the "00" String reserves the room for the 2 Bytes address that follows
  122. Buffer[0] = (Byte)(Address >> 8);
  123. Buffer[1] = (Byte)(Address & 0xFF);
  124. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(Buffer) }, 1000);
  125. Thread.Sleep(5);
  126. }
  127.  
  128. /// <summary>
  129. /// Reads a byte value from the onboard EEPROM.
  130. /// </summary>
  131. /// <param name="Address">The address to read from.</param>
  132. /// <returns>The Byte value stored @ Address.</returns>
  133. public Byte EEReadByte(Int32 Address)
  134. {
  135. return EEReadByte(EEpromConfig, Address);
  136. }
  137.  
  138. /// <summary>
  139. /// Reads a byte value from another module's EEPROM.
  140. /// </summary>
  141. /// <param name="Config">The I2CDevice.Configuration of the EEPROM.</param>
  142. /// <param name="Address">The address to read from.</param>
  143. /// <returns>The Byte value stored @ Address.</returns>
  144. public Byte EEReadByte(I2CDevice.Configuration Config, Int32 Address)
  145. {
  146. var Data = new Byte[1];
  147. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(new Byte[2] { (Byte)(Address >> 8), (Byte)(Address & 0xFF) }) }, 1000);
  148. Thread.Sleep(5);
  149. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateReadTransaction(Data) }, 1000);
  150.  
  151. return Data[0];
  152. }
  153.  
  154. /// <summary>
  155. /// Reads an Int32 value from the onboard EEPROM.
  156. /// </summary>
  157. /// <param name="Address">The address to read from.</param>
  158. /// <returns>The Int32 value stored @ Address.</returns>
  159. public Int32 EEReadInt32(Int32 Address)
  160. {
  161. return EEReadInt32(EEpromConfig, Address);
  162. }
  163.  
  164. /// <summary>
  165. /// Reads an Int32 value from another module's EEPROM.
  166. /// </summary>
  167. /// <param name="Config">The I2CDevice.Configuration of the EEPROM.</param>
  168. /// <param name="Address">The address to read from.</param>
  169. /// <returns>The Int32 value stored @ Address.</returns>
  170. public Int32 EEReadInt32(I2CDevice.Configuration Config, Int32 Address)
  171. {
  172. var Data = EEReadBytes(Config, Address, 4);
  173. return (Int32)(Data[0] + (Data[1] << 8) + (Data[2] << 16) + (Data[3] << 24));
  174. }
  175.  
  176. /// <summary>
  177. /// Reads a Byte array from the onboard EEPROM.
  178. /// </summary>
  179. /// <param name="Address">The address to read from.</param>
  180. /// <param name="pNbre">Number of Bytes to read.</param>
  181. /// <returns>The Byte array stored @ Address.</returns>
  182. public Byte[] EEReadBytes(Int32 Address, Int32 pNbre)
  183. {
  184. return EEReadBytes(EEpromConfig, Address, pNbre);
  185. }
  186.  
  187. /// <summary>
  188. /// Reads a Byte array from another module's EEPROM.
  189. /// </summary>
  190. /// <param name="Config">The I2CDevice.Configuration of the EEPROM.</param>
  191. /// <param name="Address">The address to read from.</param>
  192. /// <param name="pNbre">Number of Bytes to read.</param>
  193. /// <returns>The Byte array stored @ Address.</returns>
  194. public Byte[] EEReadBytes(I2CDevice.Configuration Config, Int32 Address, Int32 pNbre)
  195. {
  196. var Data = new Byte[pNbre];
  197. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(new Byte[2] { (Byte)(Address >> 8), (Byte)(Address & 0xFF) }) }, 1000);
  198. Thread.Sleep(5);
  199. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateReadTransaction(Data) }, 1000);
  200.  
  201. return Data;
  202. }
  203.  
  204. /// <summary>
  205. /// Reads a String from the onboard EEPROM.
  206. /// </summary>
  207. /// <param name="Address">The address to read from.</param>
  208. /// <param name="pLength">Length of the String to read.</param>
  209. /// <returns>The String stored @ Address</returns>
  210. public String EEReadString(Int32 Address, Int32 pLength)
  211. {
  212. return EEReadString(EEpromConfig, Address, pLength);
  213. }
  214.  
  215. /// <summary>
  216. /// Reads a String from another module's EEPROM.
  217. /// </summary>
  218. /// <param name="Config">The I2CDevice.Configuration of the EEPROM.</param>
  219. /// <param name="Address">The address to read from.</param>
  220. /// <param name="pLength">Length of the String to read.</param>
  221. /// <returns>The String stored @ Address.</returns>
  222. public String EEReadString(I2CDevice.Configuration Config, Int32 Address, Int32 pLength)
  223. {
  224. var Data = new Byte[pLength];
  225. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(new Byte[2] { (Byte)(Address >> 8), (Byte)(Address & 0xFF) }) }, 1000);
  226. Thread.Sleep(5);
  227. MyI2CDevice.Execute(Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateReadTransaction(Data) }, 1000);
  228. String StrTmp = new String(System.Text.Encoding.UTF8.GetChars(Data));
  229.  
  230. return StrTmp;
  231. }
  232. #endregion
  233.  
  234. #region Class methods
  235. /// <summary>
  236. /// Sends commands to the device specified by its friendly name.
  237. /// </summary>
  238. /// <param name="DeviceName">Name of the device previously created by the <see cref="AddDevice"/> method.</param>
  239. /// <param name="Commands">The command(s) to send to the device.</param>
  240. /// <param name="Delay">Optional : delay after the Write transaction. Mandatory for some devices.</param>
  241. public void Write(String DeviceName, Byte[] Commands, Byte Delay = 0)
  242. {
  243. Write(CacheDevList.IndexOf(DeviceName), Commands, Delay);
  244. }
  245.  
  246. /// <summary>
  247. /// Sends commands to the device specified by its index.
  248. /// </summary>
  249. /// <param name="DeviceIndex">Index of the device previously created by the <see cref="AddDevice"/> method, starting at 1</param>
  250. /// <param name="Commands">The command(s) to send to the device.</param>
  251. /// <param name="Delay">Optional : delay after the Write transaction. Mandatory for some devices.</param>
  252. public void Write(Int32 DeviceIndex, Byte[] Commands, Byte Delay = 0)
  253. {
  254. MyI2CDevice.Execute((DevList[DeviceIndex] as BafModuleDevice).Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateWriteTransaction(Commands) }, 1000);
  255. Thread.Sleep(Delay);
  256. }
  257.  
  258. /// <summary>
  259. /// Reads data from the device specified by its friendly name.
  260. /// </summary>
  261. /// <param name="DeviceName">Name of the device.</param>
  262. /// <param name="Length">Length of data to read. Depends on device.</param>
  263. /// <returns>A Byte array containing the device answer.</returns>
  264. public Byte[] Read(String DeviceName, Int32 Length)
  265. {
  266. return Read(CacheDevList.IndexOf(DeviceName), Length);
  267. }
  268.  
  269. /// <summary>
  270. /// Reads data from the device specified by its index.
  271. /// </summary>
  272. /// <param name="DeviceIndex">Index of the device previously created by the <see cref="AddDevice"/> method, starting at 1</param>
  273. /// <param name="Length">Length of data to read. Depends on device.</param>
  274. /// <returns>A Byte array containing the device answer.</returns>
  275. public Byte[] Read(Int32 DeviceIndex, Int32 Length)
  276. {
  277. Byte[] Data = new Byte[Length];
  278. MyI2CDevice.Execute((DevList[DeviceIndex] as BafModuleDevice).Config, new I2CDevice.I2CTransaction[1] { I2CDevice.CreateReadTransaction(Data) }, 1000);
  279.  
  280. return Data;
  281. }
  282.  
  283. /// <summary>
  284. /// Adds (attach) a device to the i2c module.
  285. /// </summary>
  286. /// <param name="Name">Friendly name of the device.</param>
  287. /// <param name="pConfig">The I2CDevice.Configuration for this device.</param>
  288. /// <returns>True if device was successfully added, false otherwise.</returns>
  289. public Boolean AddDevice(String Name, I2CDevice.Configuration pConfig)
  290. {
  291. foreach (BafModuleDevice Device in DevList)
  292. {
  293. if (Device.Address == pConfig.Address)
  294. {
  295. throw new Exception("Address " + Device.Address + " already assigned to device '" + Device.Name + "'");
  296. }
  297. if (Device.Name == Name)
  298. {
  299. throw new Exception("Name '" + Device.Name + "' already assigned to device @ " + Device.Address);
  300. }
  301. }
  302. DevList.Add(new BafModuleDevice(Name, pConfig));
  303. CacheDevList.Add(Name);
  304.  
  305. return true;
  306. }
  307.  
  308. /// <summary>
  309. /// Removes (detach) a device from the i2c module.
  310. /// </summary>
  311. /// <param name="Name">The name of the device to detach.</param>
  312. /// <returns>True if device was successfully detached, false otherwise.</returns>
  313. public Boolean RemoveDevice(String Name)
  314. {
  315. Boolean RemoveOK = false;
  316.  
  317. foreach (BafModuleDevice Device in DevList)
  318. {
  319. if (Device.Name == Name)
  320. {
  321. DevList.Remove(Device);
  322. CacheDevList.Remove(Name);
  323. Debug.GC(true);
  324. RemoveOK = true;
  325. break;
  326. }
  327. }
  328.  
  329. return RemoveOK;
  330. }
  331.  
  332. #endregion
  333. }
  334.  
  335. internal class BafModuleDevice
  336. {
  337. public String Name;
  338. public Byte Address;
  339. public I2CDevice.Configuration Config;
  340.  
  341. public BafModuleDevice(String pName, I2CDevice.Configuration pI2CConfig)
  342. {
  343. Name = pName;
  344. Address = (Byte)pI2CConfig.Address;
  345. Config = pI2CConfig;
  346. }
  347.  
  348. }
  349. }
  350.  
  351. namespace System.Runtime.CompilerServices
  352. {
  353. [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
  354. public sealed class ExtensionAttribute : Attribute { }
  355. }
  356.  
  357. namespace I2CExtensions
  358. {
  359. /// <summary>
  360. /// Extension of the internal I2C class.
  361. /// </summary>
  362. public static class I2CBus
  363. {
  364. /// <summary>
  365. /// Executes I2C commands to a specific device.
  366. /// </summary>
  367. /// <param name="pDev">The current I2C bus. Not used as a parameter since it's an extension method.</param>
  368. /// <param name="pConfig">the I2CDevice.Configuration to which commands will be sent.</param>
  369. /// <param name="xActions">Commands to send.</param>
  370. /// <param name="timeout">Timeout for the transaction(s).</param>
  371. /// <returns></returns>
  372. public static Int32 Execute(this I2CDevice pDev, I2CDevice.Configuration pConfig, I2CDevice.I2CTransaction[] xActions, Int32 timeout)
  373. {
  374. var ConfigSav = pDev.Config;
  375. pDev.Config = pConfig;
  376. var RetVal = pDev.Execute(xActions, timeout);
  377. pDev.Config = ConfigSav;
  378. return RetVal;
  379. }
  380. }
  381. }