/* Copyright (c) 2016 Michael Pralow http://programmicha.de/. See the file LICENSE for copying permission. */ /** * Represents an SSD1606 Display Driver with Controller. * Right now it works out of the box with the GDE021A1 e-paper display. */ /** * GDE021A1 display data. * This display data is based on specification version 'A/0(For SLC 505a FH E21002-DL Ver02 TFT' from 22.10.2012. * RAM x address end at 11h(17)->72, because otherwise it would default to 1Fh(31)->128, * which is too large for this display. * RAM y address end at ABh(171)->172, because otherwise it default to B3h(179)->180 * which is too large for this display. * LUT Register data is the needed waveform for this display. * Max screenbytes are 172*72 / 4 = 3096 bytes (4 Pixels per byte). */ var C = { GDE021A1: { bpp : 2, displaySizeX : 72, displaySizeY : 172, lutRegisterData : new Uint8Array([ 0x00,0x00,0x00,0x55,0x00,0x00,0x55,0x55,0x00,0x55,0x55,0x55,0xAA,0xAA,0xAA,0xAA, 0x15,0x15,0x15,0x15,0x05,0x05,0x05,0x05,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x22,0xFB,0x22,0x1B,0x00,0x00,0x00,0x00,0x00,0x00 ]), maxScreenBytes : 3096, ramXStartAddress : 0x00, ramXEndAddress : 0x11, ramYStartAddress : 0x00, ramYEndAddress : 0xAB } }; /** * Represents an SSD1606 Display Driver with Controller. * All functions are based on spefication version 1.1 from 10/2011. * Informations: * * @constructor * @param config - configuration with displayType, SPI and additional pins. */ function SSD1606(config) { if (config.displayType === 'GDE021A1') { this.display = C.GDE021A1; } else { if(config.display) { this.display = config.display; } else { return new Error('Unknown display type "' + config.displayType + '"" and no display configuration provided!'); } } this.spi = config.spi; this.bs1Pin = config.bs1Pin; this.cs1Pin = config.cs1Pin; this.dcPin = config.dcPin; this.busyPin = config.busyPin; this.resetPin = config.resetPin; this.powerPin = config.powerPin; this.g = this.grfx(); if (config.clearScreenTimeOut) { this.csbTimeOut = config.clearScreenTimeOut; } else { this.csbTimeOut = 100; } if (config.clearScreenTimeOut) { this.hwResetTimeOut = config.hardwareResetTimeOut; } else { this.hwResetTimeOut = 100; } } /** Sets registers to power-on values (not needed by default) */ SSD1606.prototype.reset = function() { this.scd(0x01, 0xB3); this.scd(0x03, 0xEA); this.scd(0x04, 0x0A); this.scd(0x3A, 0x04); this.scd(0x3B, 0x08); this.scd(0x2C, 0xA0); this.scd(0x3C, 0x73); this.scd(0x11, 0x03); this.scd(0x4E, 0x00); this.scd(0x4F, 0x00); this.scd(0xF0, 0x1F); }; /** * Power on the display, using the provided powerPin. */ SSD1606.prototype.on = function() { if(this.powerPin) { digitalWrite(this.powerPin, 1); } }; /** * Power off the display, using the provided powerPin. */ SSD1606.prototype.off = function() { if(this.powerPin) { digitalWrite(this.powerPin, 0); } }; /** * Use resetPin to make a hardware reset. * @param {Function} callback - callback function */ SSD1606.prototype.hwReset = function(callback) { digitalWrite(this.resetPin, 0); digitalWrite(this.resetPin, 1); return setTimeout(callback, this.hwResetTimeOut); // is that even needed? }; /** * Initialize display. * If set it uses the provided bs1Pin to configure the SPI mode between to use 4 lines. * Initializing sequence: *
    *
  1. Exit deep sleep mode
  2. *
  3. Set data entry mode - 0000 0011 means AM=0 means 'x-mode' and ID=11 means 'x:increment and y:increment'
  4. *
  5. Set RAM X start and end addresses
  6. *
  7. Set RAM Y start and end addresses
  8. *
  9. Set RAM X counter
  10. *
  11. Set RAM Y counter
  12. *
  13. Set booster feedback selection
  14. *
  15. Set display update sequence option - enable sequence: clk -> CP
  16. *
  17. Write LUT register
  18. *
  19. Write VCOM register
  20. *
  21. Set border waveform control
  22. *
  23. Set display update sequence option - enable sequence: clk -> CP -> LUT -> initial display -> pattern display
  24. *
* @param {Object} options - provided options, useBs1Pin and clearScreenColor * @param {Function} callback - callback function */ SSD1606.prototype.init = function(callback, options) { if(this.bs1Pin) { digitalWrite(this.bs1Pin, 0); } this.scd(0x10, 0x00); this.scd(0x11, 0x03); // 0x03 für alten Wert this.scd(0x44,[this.display.ramXStartAddress, this.display.ramXEndAddress]); this.scd(0x45,[this.display.ramYStartAddress, this.display.ramYEndAddress]); this.scd(0x4E, 0x00); this.scd(0x4F, 0x00); this.scd(0xF0, 0x1F); this.scd(0x22, 0xC0); this.scd(0x32, this.display.lutRegisterData); this.scd(0x2C, 0xA0); this.scd(0x3C, 0x63); this.scd(0x22, 0xC4); if(options && options.clearScreenColor){ return this.csb(callback, options.clearScreenColor); } else { return callback(); } }; /** * Send a command to the display, uses the cs1Pin (chip select). * Uses the dcPin if spimode is set to 4-lines, otherwise add a bit to the * left to signal a command. * Possible commands: *
    *
  1. 0x01 - Driver output control
  2. *
  3. 0x02 - Reserve
  4. *
  5. 0x03 - Gate driving voltage control
  6. *
  7. 0x04 - Source driving voltage control
  8. *
  9. 0x05 - Reserve
  10. *
  11. 0x06 - Reserve
  12. *
  13. 0x07 - Display control
  14. *
  15. 0x08 - Reserve
  16. *
  17. 0x09 - Reserve
  18. *
  19. 0x0A - Reserve
  20. *
  21. 0x0B - Gate and source non overlap period control
  22. *
  23. 0x0C - Reserve
  24. *
  25. 0x0D - Reserve
  26. *
  27. 0x0E - Reserve
  28. *
  29. 0x0F - Gate scan start position
  30. *
  31. 0x10 - Deep sleep mode
  32. *
  33. 0x11 - Data entry mode setting
  34. *
  35. 0x12 - Software reset
  36. *
  37. 0x13 - Reserve
  38. *
  39. 0x14 - Reserve
  40. *
  41. 0x15 - Reserve
  42. *
  43. 0x16 - Reserve
  44. *
  45. 0x17 - Reserve
  46. *
  47. 0x18 - Reserve
  48. *
  49. 0x19 - Reserve
  50. *
  51. 0x1A - Write to temperature register
  52. *
  53. 0x1B - Read to temperature register
  54. *
  55. 0x1C - Write command to temperature sensor
  56. *
  57. 0x1D - Load temperature register with temperature sensor reading
  58. *
  59. 0x1E - Reserve
  60. *
  61. 0x1F - Reserve
  62. *
  63. 0x20 - Master acvitvation
  64. *
  65. 0x21 - Display update 1
  66. *
  67. 0x22 - Display update 2
  68. *
  69. 0x23 - Reserve
  70. *
  71. 0x24 - Write RAM
  72. *
  73. 0x25 - Read RAM
  74. *
  75. 0x26 - Reserve
  76. *
  77. 0x27 - Reserve
  78. *
  79. 0x28 - VCOM sense
  80. *
  81. 0x29 - VCOM sense duration
  82. *
  83. 0x2A - Program VCOM OTP
  84. *
  85. 0x2B - Reserve
  86. *
  87. 0x2C - Write VCOM register
  88. *
  89. 0x2D - Read OTP Register
  90. *
  91. 0x2E - Reserve
  92. *
  93. 0x2F - Reserve
  94. *
  95. 0x30 - Program WS OTP
  96. *
  97. 0x31 - Reserve
  98. *
  99. 0x32 - Write LUT register
  100. *
  101. 0x33 - Read LUT register
  102. *
  103. 0x34 - Reserve
  104. *
  105. 0x35 - Reserve
  106. *
  107. 0x36 - Program OTP selection
  108. *
  109. 0x37 - OTP selection control
  110. *
  111. 0x38 - Reserve
  112. *
  113. 0x39 - Reserve
  114. *
  115. 0x3A - Set dummy line period
  116. *
  117. 0x3B - Set gate line width
  118. *
  119. 0x3C - Border waveform control
  120. *
  121. 0x3D - Reserve
  122. *
  123. 0x3E - Reserve
  124. *
  125. 0x3F - Reserve
  126. *
  127. 0x40 - Reserve
  128. *
  129. 0x41 - Reserve
  130. *
  131. 0x42 - Reserve
  132. *
  133. 0x43 - Reserve
  134. *
  135. 0x44 - Set RAM X address position
  136. *
  137. 0x45 - Set RAM Y address position
  138. *
  139. 0x46 - Reserve
  140. *
  141. 0x47 - Reserve
  142. *
  143. 0x48 - Reserve
  144. *
  145. 0x49 - Reserve
  146. *
  147. 0x4A - Reserve
  148. *
  149. 0x4B - Reserve
  150. *
  151. 0x4C - Reserve
  152. *
  153. 0x4D - Reserve
  154. *
  155. 0x4E - Set RAM X address counter
  156. *
  157. 0x4F - Set RAM Y address counter
  158. *
  159. 0xF0 - Booster feedback selection
  160. *
  161. 0xFF - no operation NOP
  162. *
* @param {number} command - a command */ SSD1606.prototype.sc = function(command) { digitalWrite(this.dcPin, 0); this.spi.write(command, this.cs1Pin); }; /** * Prepare send data, prepares the controller to receive data. */ SSD1606.prototype.psd = function() { digitalWrite(this.dcPin, 1); }; /** * Send data to the controller. * @param data - the data */ SSD1606.prototype.sd = function(data) { this.spi.write(data, this.cs1Pin); }; /** * Send command and data to the controller. * @param command - the command * @param data - the data */ SSD1606.prototype.scd = function(command, data) { this.sc(command); this.psd(); this.sd(data); }; /** * Checks the busyPin and runs the callback, wenn the busyPin is LOW. * @param {Function} callback - the callback function */ SSD1606.prototype.cbp = function(callback) { return setWatch(callback, this.busyPin, { repeat:false, edge:'falling' }); }; /** * Clears the display screenbuffer with desired color. * Possible color values: * * Right now it sends each 4-pixel byte individually, but does not need an * internal buffer array. * The display driver handles the X and Y RAM counters itself, so it is save to * just write the bytes. * To leave the write RAM mode a 'NOP' command is sent. * According to specification a check of the BusyPin is needed, but this does not work here. * It seems the display driver encapsulates this behaviour. * @param {Function} callback - the callback function, will be called, when finished * @param {number} clearScreenColor - the color to set */ SSD1606.prototype.csb = function(callback, clearScreenColor) { this.scd(0x44, 0x00); this.scd(0x45, 0x00); this.sc(0x24); this.psd(); for (var i = 0; i < this.display.maxScreenBytes; i++) { this.sd(clearScreenColor); } this.sc(0xFF); return setTimeout(callback, this.csbTimeOut); }; /** * Refresh the screen, need to be called by application every time the screen changed. * Refresh sequence: *
    *
  1. Master activation
  2. *
  3. Display update 2 - part of closebump in specification
  4. *
  5. Master activation - part of closebump in specification
  6. *
  7. check BusyPin before the display can receive further commands or data. Part of closebump in specification
  8. *
* @param {Function} callback - callback is called, when busy pin is ready. */ SSD1606.prototype.refreshScreen = function(callback) { this.sc(0x20); this.scd(0x22, 0x03); this.sc(0x20); return this.cbp(callback); }; /** * Sets the X and Y RAM counter. * @param {number} xCount - X RAM counter * @param {number} yCount - Y RAM counter */ SSD1606.prototype.sxyc = function(xCount, yCount) { this.scd(0x4E, xCount); this.scd(0x4F, yCount); }; /** * Creates the Graphics object with Graphics.createArrayBuffer(...). * Sets the display x size, y size, bits per pixel and msb:true. * Provides a clear function to fill in-memory buffer with one color for each pixel. * Provides a flip function to flush in-memory buffer to display buffer. */ SSD1606.prototype.grfx = function(){ var _display = this; var g = Graphics.createArrayBuffer( this.display.displaySizeX, this.display.displaySizeY, this.display.bpp, {msb: true} ); g.clear = function(clearColor){ new Uint8Array(this.buffer).fill(clearColor); }; g.flip = function(){ _display.sxyc(0, 0); _display.scd(0x24, this.buffer); _display.sc(0xFF); }; return g; }; /** * Export the module. */ exports.connect = function (options) { return new SSD1606(options); };