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

MCP23008 I2C Port Expander by Savitch

Mar. 7, 2012   |   Snippet   |   Unlicensed   |   2567 views

MCP23008 8bit port expander using I2C. This is similar function to the MCP23017 16bit version and has the same wide variety of configuration options.



Author Version Date
Savitch 1 05/04 '12 at 01:44pm
1 — Source
  1. using System;
  2. using System.Threading;
  3. using Microsoft.SPOT;
  4. using Microsoft.SPOT.Hardware;
  5.  
  6. namespace PortExpander {
  7. public enum Register {
  8. /// <summary>
  9. /// I/O Direction
  10. /// 0 = output
  11. /// 1 = input
  12. /// </summary>
  13. IODIR = 0x00,
  14.  
  15. /// <summary>
  16. /// Input polarity
  17. /// 0 = normal
  18. /// 1 = invert
  19. /// </summary>
  20. IPOL = 0x01,
  21.  
  22. /// <summary>
  23. /// Interrupt on change
  24. /// 0 = disable
  25. /// 1 = enable
  26. /// </summary>
  27. GPINTEN = 0x02,
  28.  
  29. /// <summary>
  30. /// Default Compare for interrupt
  31. /// </summary>
  32. DEFVAL = 0x03,
  33.  
  34. /// <summary>
  35. /// Interrupt Control
  36. /// 0 = compare with previous value
  37. /// 1 = compare with DEFVAL
  38. /// </summary>
  39. INTCON = 0x04,
  40.  
  41. /// <summary>
  42. /// Config Register
  43. /// default is 0x00
  44. /// </summary>
  45. IOCON = 0x05,
  46.  
  47. /// <summary>
  48. /// Pull-Up Resistor
  49. /// 0 = disabled
  50. /// 1 = enabled
  51. /// </summary>
  52. GPPU = 0x06,
  53.  
  54. /// <summary>
  55. /// Interrupt Flag, read GPIO or INTCAP to clear
  56. /// </summary>
  57. INTF = 0x07,
  58.  
  59. /// <summary>
  60. /// Interrupt Capture
  61. /// GPIO value at the time of interrupt
  62. /// </summary>
  63. INTCAP = 0x08,
  64.  
  65. /// <summary>
  66. /// IO Port
  67. /// Writing will only set pins configured as output
  68. /// </summary>
  69. GPIO = 0x09,
  70.  
  71. /// <summary>
  72. /// Output Latch
  73. /// </summary>
  74. OLAT = 0x0A,
  75. }
  76.  
  77. public enum Pin {
  78. GP0 = 0x01,
  79. GP1 = 0x02,
  80. GP2 = 0x04,
  81. GP3 = 0x08,
  82. GP4 = 0x10,
  83. GP5 = 0x20,
  84. GP6 = 0x40,
  85. GP7 = 0x80,
  86. ALL = 0xFF,
  87. }
  88.  
  89. public enum Direction {
  90. Output = 0x00,
  91. Input = 0x01,
  92. }
  93.  
  94. public enum Polarity {
  95. Normal = 0x00,
  96. Invert = 0x01,
  97. }
  98.  
  99. public enum InterruptControl {
  100. PreviousValue = 0x00,
  101. DefaultValue = 0x01,
  102. }
  103.  
  104. public enum ConfigRegister {
  105. /// <summary>
  106. /// Sequential Operation
  107. /// 0 = enabled(default)
  108. /// 1 = disabled
  109. /// </summary>
  110. SEQOP = 0x20,
  111.  
  112. /// <summary>
  113. /// SDA Slew Rate
  114. /// 0 = enabled(default)
  115. /// 1 = disabled
  116. /// </summary>
  117. DISSLW = 0x10,
  118.  
  119. /// <summary>
  120. /// Hardware Address Enable for MCP23S08 SPI version only
  121. /// 0 = disabled(default)
  122. /// 1 = enabled
  123. /// </summary>
  124. HAEN = 0x08,
  125.  
  126. /// <summary>
  127. /// INT pin as open-drain
  128. /// 0 = Active driver output(default)
  129. /// 1 = Open-drain output
  130. /// </summary>
  131. ODR = 0x04,
  132.  
  133. /// <summary>
  134. /// INT polarity
  135. /// 0 = Active-low(default)
  136. /// 1 = Active-high
  137. /// </summary>
  138. INTPOL = 0x02,
  139. }
  140.  
  141. public class MCP23008 {
  142. I2CDevice i2c = null;
  143. I2CDevice.I2CTransaction[] writeTrans = new I2CDevice.I2CTransaction[1];
  144. I2CDevice.I2CTransaction[] readTrans = new I2CDevice.I2CTransaction[2];
  145. OutputPort resetPin;
  146. byte[] singleCommand = new byte[1];
  147. byte[] writeBuffer = new byte[2];
  148. byte[] readBuffer = new byte[1];
  149.  
  150. /// <summary>
  151. /// Init with I2C address and optional hardware reset pin
  152. /// Set reset pin 6 high if not used
  153. /// </summary>
  154. /// <param name="address">0x20 to 0x27</param>
  155. /// <param name="resetPin">set null if not used</param>
  156. public MCP23008(byte address, OutputPort resetPin) {
  157. this.i2c = new I2CDevice(new I2CDevice.Configuration(address, 400));
  158. this.resetPin = resetPin;
  159. Init();
  160. }
  161.  
  162. public MCP23008() {
  163. this.i2c = new I2CDevice(new I2CDevice.Configuration(0x20, 400));
  164. this.resetPin = null;
  165. Init();
  166. }
  167.  
  168. private void Init() {
  169. Reset();
  170. ClearInterrupt();
  171. }
  172.  
  173. /// <summary>
  174. /// Write single register
  175. /// </summary>
  176. /// <param name="reg">Register name</param>
  177. /// <param name="val">Register value</param>
  178. public void Write(Register reg, byte val) {
  179. writeBuffer[0] = (byte)reg;
  180. writeBuffer[1] = val;
  181. writeTrans[0] = I2CDevice.CreateWriteTransaction(writeBuffer);
  182. i2c.Execute(writeTrans, 100);
  183. }
  184.  
  185. /// <summary>
  186. /// Read single register
  187. /// </summary>
  188. /// <param name="reg">Register name</param>
  189. /// <returns>Register value</returns>
  190. public byte Read(Register reg) {
  191. singleCommand[0] = (byte)reg;
  192. readTrans[0] = I2CDevice.CreateWriteTransaction(singleCommand);
  193. readTrans[1] = I2CDevice.CreateReadTransaction(readBuffer);
  194. i2c.Execute(readTrans, 100);
  195. return readBuffer[0];
  196. }
  197.  
  198. /// <summary>
  199. /// Hardware or software reset
  200. /// </summary>
  201. public void Reset() {
  202. if (resetPin != null) {
  203. resetPin.Write(false);
  204. Thread.Sleep(5);
  205. resetPin.Write(true);
  206. Thread.Sleep(5);
  207. } else {
  208. //set default Reset values if not using hardware reset pin
  209. Write(Register.IODIR, 0xFF);
  210. Write(Register.IPOL, 0x00);
  211. Write(Register.GPINTEN, 0x00);
  212. Write(Register.DEFVAL, 0x00);
  213. Write(Register.INTCON, 0x00);
  214. Write(Register.IOCON, 0x00);
  215. Write(Register.GPPU, 0x00);
  216. Write(Register.INTF, 0x00);
  217. Write(Register.INTCAP, 0x00);
  218. Write(Register.GPIO, 0x00);
  219. Write(Register.OLAT, 0x00);
  220. }
  221. }
  222.  
  223. /// <summary>
  224. /// Write GPIO pin(s)
  225. /// </summary>
  226. /// <param name="pin">pin</param>
  227. /// <param name="value">value</param>
  228. public void WritePin(Pin pinMask, bool value) {
  229. SetRegisterForPin(Register.GPIO, pinMask, value);
  230. }
  231.  
  232. /// <summary>
  233. /// Read single GPIO pin
  234. /// </summary>
  235. /// <param name="pin">pin</param>
  236. /// <returns>pin value</returns>
  237. public bool ReadPin(Pin pin) {
  238. byte current_GPIO = Read(Register.GPIO);
  239. if ((current_GPIO & (byte)pin) > 0) {
  240. return true;
  241. } else {
  242. return false;
  243. }
  244. }
  245.  
  246. /// <summary>
  247. /// Read GPIO pin(s)
  248. /// </summary>
  249. /// <param name="pin">pin mask</param>
  250. /// <returns>masked value</returns>
  251. public byte ReadPins(Pin pinMask) {
  252. byte current_GPIO = Read(Register.GPIO);
  253. current_GPIO &= (byte)pinMask;
  254. return current_GPIO;
  255. }
  256.  
  257. /// <summary>
  258. /// Set pin direction mask
  259. /// </summary>
  260. /// <param name="pin">pin</param>
  261. /// <param name="dir">direction</param>
  262. public void PinDirection(Pin pinMask, Direction dir) {
  263. bool value = false;
  264. if (dir == Direction.Input) {
  265. value = true;
  266. }
  267. SetRegisterForPin(Register.IODIR, pinMask, value);
  268. }
  269.  
  270. /// <summary>
  271. /// Set pin input polarity mask
  272. /// </summary>
  273. /// <param name="pin">pin</param>
  274. /// <param name="pol">polarity</param>
  275. public void PinPolarity(Pin pinMask, Polarity pol) {
  276. bool value = false;
  277. if (pol == Polarity.Invert) {
  278. value = true;
  279. }
  280. SetRegisterForPin(Register.GPINTEN, pinMask, value);
  281. }
  282.  
  283. /// <summary>
  284. /// Set pin interrupt on change mask
  285. /// </summary>
  286. /// <param name="pin">pin</param>
  287. /// <param name="value">value</param>
  288. public void PinInterruptOnChange(Pin pinMask, bool value) {
  289. SetRegisterForPin(Register.GPINTEN, pinMask, value);
  290. }
  291.  
  292. /// <summary>
  293. /// Set pin mask default value to cause interrupt
  294. /// </summary>
  295. /// <param name="pin">pin</param>
  296. /// <param name="value">value</param>
  297. public void PinDefaultValue(Pin pinMask, bool value) {
  298. SetRegisterForPin(Register.DEFVAL, pinMask, value);
  299. }
  300.  
  301. /// <summary>
  302. /// Set pin pullup resistor mask
  303. /// </summary>
  304. /// <param name="pin">pin</param>
  305. /// <param name="value">value</param>
  306. public void PinPullup(Pin pinMask, bool value) {
  307. SetRegisterForPin(Register.GPPU, pinMask, value);
  308. }
  309.  
  310. /// <summary>
  311. /// Set interrupt compare mode
  312. /// </summary>
  313. /// <param name="pinMask">pins</param>
  314. /// <param name="ic">mode</param>
  315. public void PinInterruptControl(Pin pinMask, InterruptControl ic) {
  316. bool value = false;
  317. if (ic == InterruptControl.DefaultValue) {
  318. value = true;
  319. }
  320. SetRegisterForPin(Register.INTCON, pinMask, value);
  321. }
  322.  
  323. /// <summary>
  324. /// Set pin value mask
  325. /// </summary>
  326. /// <param name="reg">register</param>
  327. /// <param name="pin">pin</param>
  328. /// <param name="value">value</param>
  329. private void SetRegisterForPin(Register reg, Pin pinMask, bool value) {
  330. byte current = Read(reg);
  331. if (value) {
  332. current |= (byte)pinMask;
  333. } else {
  334. current &= (byte)((int)~pinMask);
  335. }
  336. Write(reg, current);
  337. }
  338.  
  339. /// <summary>
  340. /// Set configuration
  341. /// </summary>
  342. /// <param name="cr">config</param>
  343. public void SetConfigRegister(ConfigRegister cr) {
  344. Write(Register.IOCON, (byte)cr);
  345. }
  346.  
  347. /// <summary>
  348. /// Clear INTF by reading INTCAP
  349. /// </summary>
  350. public void ClearInterrupt() {
  351. Read(Register.INTCAP);
  352. }
  353.  
  354. }
  355. }
  356.  
  357.