Subversion Repositories libSSD1306

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*********************************************************************
  2.  This is a library for our Monochrome OLEDs based on SSD1306 drivers
  3.  
  4.  Pick one up today in the adafruit shop!
  5.  ------> http://www.adafruit.com/category/63_98
  6.  
  7.  These displays use SPI to communicate, 4 or 5 pins are required to
  8.  interface
  9.  
  10.  Adafruit invests time and resources providing this open source code,
  11.  please support Adafruit and open-source hardware by purchasing
  12.  products from Adafruit!
  13.  
  14.  Written by Limor Fried/Ladyada  for Adafruit Industries.
  15.  BSD license, check license.txt for more information
  16.  All text above, and the splash screen below must be included in any redistribution
  17.  
  18.  This code is taken from the ADAfruit library - it is used for playing with an OLED screen
  19.  
  20.  *********************************************************************/
  21.  
  22. #include <stdint.h>
  23. #include <string.h>
  24. #include "libSSD1306/SSD1306.h"
  25. #include "libSSD1306/spiInterface.h"
  26.  
  27. #define swap(x,y) { typeof(x)t = x; x=y; y=t; }
  28. #define abs(x)      ((x)>0?(x):-(x))
  29.  
  30. static uint8_t rotation = 0;
  31. const uint16_t WIDTH = SSD1306_LCDWIDTH;
  32. const uint16_t HEIGHT = SSD1306_LCDHEIGHT;
  33.  
  34. // the memory buffer for the LCD
  35.  
  36. // pointer to the current display - affects buffer used and also chipselect
  37.  
  38. uint8_t display_buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8];
  39.  
  40. inline uint8_t*
  41. display_address (void)
  42. {
  43.   return (uint8_t*) (&display_buffer[0]);
  44. }
  45.  
  46. inline uint8_t
  47. getRotation (void)
  48. {
  49.   return rotation;
  50. }
  51.  
  52. inline int16_t
  53. width (void)
  54. {
  55.   switch (rotation)
  56.     {
  57.     case 0:
  58.       return WIDTH;
  59.       break;
  60.     case 1:
  61.       return WIDTH;
  62.       break;
  63.     case 2:
  64.       return HEIGHT;
  65.       break;
  66.     case 3:
  67.       return -WIDTH;
  68.       break;
  69.     }
  70.   return 0;
  71. }
  72.  
  73. inline int16_t
  74. height (void)
  75. {
  76.   switch (rotation)
  77.     {
  78.     case 0:
  79.       return HEIGHT;
  80.       break;
  81.     case 1:
  82.       return HEIGHT;
  83.       break;
  84.     case 2:
  85.       return WIDTH;
  86.       break;
  87.     case 3:
  88.       return -HEIGHT;
  89.       break;
  90.     }
  91.   return 0;
  92. }
  93.  
  94. // the most basic function, set a single pixel
  95. inline void
  96. drawPixel (int16_t x, int16_t y, uint16_t color)
  97. {
  98.   if ((x < 0) || (x >= width ()) || (y < 0) || (y >= height ()))
  99.     return;
  100.  
  101.   // check rotation, move pixel around if necessary
  102.   switch (getRotation ())
  103.     {
  104.     case 1:
  105.       swap(x, y)
  106.       ;
  107.       x = WIDTH - x - 1;
  108.       break;
  109.     case 2:
  110.       x = WIDTH - x - 1;
  111.       y = HEIGHT - y - 1;
  112.       break;
  113.     case 3:
  114.       swap(x, y)
  115.       ;
  116.       y = HEIGHT - y - 1;
  117.       break;
  118.     }
  119.  
  120.   // x is which column
  121.   switch (color)
  122.     {
  123.     case BLACK:
  124.       display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] &= ~(1 << (y & 7));
  125.       break;
  126.  
  127.     default:
  128.     case WHITE:
  129.       display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] |= (1 << (y & 7));
  130.       break;
  131.  
  132.     case INVERT:
  133.       display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] ^= (1 << (y & 7));
  134.       break;
  135.     }
  136. }
  137.  
  138. void
  139. ssd1306_begin (uint8_t vccstate, uint8_t i2caddr)
  140. {
  141.  
  142.   (void) i2caddr;
  143.   ssd1306resetDisplay ();
  144.  
  145.   // Init sequence for 128x32 or 128x64  OLED module
  146.   ssd1306commandSPIwrite (SSD1306_DISPLAYOFF); // 0xAE
  147.   ssd1306commandSPIwrite (SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
  148.   ssd1306commandSPIwrite (0x80); // the suggested ratio 0x80
  149.   ssd1306commandSPIwrite (SSD1306_SETMULTIPLEX); // 0xA8
  150.   ssd1306commandSPIwrite (SSD1306_LCDHEIGHT - 1);
  151.   ssd1306commandSPIwrite (SSD1306_SETDISPLAYOFFSET); // 0xD3
  152.   ssd1306commandSPIwrite (0x0); // no offset
  153.   ssd1306commandSPIwrite (SSD1306_SETSTARTLINE | 0x0); // line #0
  154.   ssd1306commandSPIwrite (SSD1306_CHARGEPUMP); // 0x8D
  155.   if (vccstate == SSD1306_EXTERNALVCC)
  156.     {
  157.       ssd1306commandSPIwrite (0x10);
  158.     }
  159.   else
  160.     {
  161.       ssd1306commandSPIwrite (0x14);
  162.     }
  163.   ssd1306commandSPIwrite (SSD1306_MEMORYMODE);                    // 0x20
  164.   ssd1306commandSPIwrite (0x00);                    // 0x0 act like ks0108
  165.   ssd1306commandSPIwrite (SSD1306_SEGREMAP | 0x1);
  166.   ssd1306commandSPIwrite (SSD1306_COMSCANDEC);
  167.   ssd1306commandSPIwrite (SSD1306_SETCOMPINS);                    // 0xDA
  168.   ssd1306commandSPIwrite (SSD1306_LCDHEIGHT == 32 ? 0x02 : 0x12);
  169.   ssd1306commandSPIwrite (SSD1306_SETCONTRAST);                    // 0x81
  170.   if (vccstate == SSD1306_EXTERNALVCC)
  171.     {
  172.       ssd1306commandSPIwrite (0x9F);
  173.     }
  174.   else
  175.     {
  176.       ssd1306commandSPIwrite (0xCF);
  177.     }
  178.   ssd1306commandSPIwrite (SSD1306_SETPRECHARGE);                    // 0xd9
  179.   if (vccstate == SSD1306_EXTERNALVCC)
  180.     {
  181.       ssd1306commandSPIwrite (0x22);
  182.     }
  183.   else
  184.     {
  185.       ssd1306commandSPIwrite (0xF1);
  186.     }
  187.   ssd1306commandSPIwrite (SSD1306_SETVCOMDETECT);                 // 0xDB
  188.   ssd1306commandSPIwrite (0x40);
  189.   ssd1306commandSPIwrite (SSD1306_DISPLAYALLON_RESUME);                 // 0xA4
  190.   ssd1306commandSPIwrite (SSD1306_NORMALDISPLAY);                 // 0xA6
  191.  
  192.   ssd1306commandSPIwrite (SSD1306_DISPLAYON);             //--turn on oled panel
  193.  
  194. }
  195.  
  196. void
  197. invertDisplay (uint8_t i)
  198. {
  199.   if (i)
  200.     {
  201.       ssd1306commandSPIwrite (SSD1306_INVERTDISPLAY);
  202.     }
  203.   else
  204.     {
  205.       ssd1306commandSPIwrite (SSD1306_NORMALDISPLAY);
  206.     }
  207. }
  208.  
  209. // startscrollright
  210. // Activate a right handed scroll for rows start through stop
  211. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  212. // display.scrollright(0x00, 0x0F)
  213. void
  214. startscrollright (uint8_t start, uint8_t stop)
  215. {
  216.   ssd1306commandSPIwrite (SSD1306_RIGHT_HORIZONTAL_SCROLL);
  217.   ssd1306commandSPIwrite (0X00);
  218.   ssd1306commandSPIwrite (start);
  219.   ssd1306commandSPIwrite (0X00);
  220.   ssd1306commandSPIwrite (stop);
  221.   ssd1306commandSPIwrite (0X00);
  222.   ssd1306commandSPIwrite (0XFF);
  223.   ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
  224. }
  225.  
  226. // startscrollleft
  227. // Activate a right handed scroll for rows start through stop
  228. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  229. // display.scrollright(0x00, 0x0F)
  230. void
  231. startscrollleft (uint8_t start, uint8_t stop)
  232. {
  233.   ssd1306commandSPIwrite (SSD1306_LEFT_HORIZONTAL_SCROLL);
  234.   ssd1306commandSPIwrite (0X00);
  235.   ssd1306commandSPIwrite (start);
  236.   ssd1306commandSPIwrite (0X00);
  237.   ssd1306commandSPIwrite (stop);
  238.   ssd1306commandSPIwrite (0X00);
  239.   ssd1306commandSPIwrite (0XFF);
  240.   ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
  241. }
  242.  
  243. // startscrolldiagright
  244. // Activate a diagonal scroll for rows start through stop
  245. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  246. // display.scrollright(0x00, 0x0F)
  247. void
  248. startscrolldiagright (uint8_t start, uint8_t stop)
  249. {
  250.   ssd1306commandSPIwrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
  251.   ssd1306commandSPIwrite (0X00);
  252.   ssd1306commandSPIwrite (SSD1306_LCDHEIGHT);
  253.   ssd1306commandSPIwrite (SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
  254.   ssd1306commandSPIwrite (0X00);
  255.   ssd1306commandSPIwrite (start);
  256.   ssd1306commandSPIwrite (0X00);
  257.   ssd1306commandSPIwrite (stop);
  258.   ssd1306commandSPIwrite (0X01);
  259.   ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
  260. }
  261.  
  262. // startscrolldiagleft
  263. // Activate a diagonal scroll for rows start through stop
  264. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  265. // display.scrollright(0x00, 0x0F)
  266. void
  267. startscrolldiagleft (uint8_t start, uint8_t stop)
  268. {
  269.   ssd1306commandSPIwrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
  270.   ssd1306commandSPIwrite (0X00);
  271.   ssd1306commandSPIwrite (SSD1306_LCDHEIGHT);
  272.   ssd1306commandSPIwrite (SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
  273.   ssd1306commandSPIwrite (0X00);
  274.   ssd1306commandSPIwrite (start);
  275.   ssd1306commandSPIwrite (0X00);
  276.   ssd1306commandSPIwrite (stop);
  277.   ssd1306commandSPIwrite (0X01);
  278.   ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
  279. }
  280.  
  281. void
  282. stopscroll (void)
  283. {
  284.   ssd1306commandSPIwrite (SSD1306_DEACTIVATE_SCROLL);
  285. }
  286.  
  287. // Dim the display
  288. // dim = true: display is dimmed
  289. // dim = false: display is normal
  290. void
  291. dim (uint8_t contrast)
  292. {
  293.  
  294.   // the range of contrast to too small to be really useful
  295.   // it is useful to dim the display
  296.   ssd1306commandSPIwrite (SSD1306_SETCONTRAST);
  297.   ssd1306commandSPIwrite (contrast);
  298. }
  299.  
  300. void
  301. display (void)
  302. {
  303.  
  304.   // select entire display as window to write into
  305.   ssd1306commandSPIwrite (SSD1306_COLUMNADDR);
  306.   ssd1306commandSPIwrite (0);   // Column start address (0 = reset)
  307.   ssd1306commandSPIwrite (SSD1306_RAMWIDTH - 1); // Column end address (127 = reset)
  308.  
  309.   ssd1306commandSPIwrite (SSD1306_PAGEADDR);
  310.   ssd1306commandSPIwrite (0); // Page start address (0 = reset)
  311.   ssd1306commandSPIwrite ((SSD1306_LCDHEIGHT == 64) ? 7 : 3); // Page end address
  312.  
  313.   int row;
  314.  
  315.   int col = SSD1306_RAMWIDTH == 132 ? 2 : 0;
  316.   for (row = 0; row < SSD1306_LCDHEIGHT / 8; row++)
  317.     {
  318.       // set the cursor to
  319.       ssd1306commandSPIwrite (0xB0 + row); //set page address
  320.       ssd1306commandSPIwrite (col & 0xf); //set lower column address
  321.       ssd1306commandSPIwrite (0x10 | (col >> 4)); //set higher column address
  322.  
  323.       ssd1306SendDisplay (
  324.           (uint8_t*) (&display_buffer[0]) + row * SSD1306_LCDWIDTH,
  325.           SSD1306_LCDWIDTH);
  326.  
  327.     }
  328.  
  329. }
  330.  
  331. // clear everything
  332. void
  333. clearDisplay (void)
  334. {
  335.   memset (&display_buffer, 0, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
  336. }
  337.  
  338. /* using Bresenham draw algorithm */
  339. void
  340. drawLine (int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
  341. {
  342.   int16_t x, y, dx, dy,    //deltas
  343.       dx2, dy2, //scaled deltas
  344.       ix, iy,   //increase rate on the x and y axis
  345.       err;      //the error term
  346.   uint16_t i;           //looping variable
  347.  
  348.   // identify the first pixel
  349.   x = x1;
  350.   y = y1;
  351.  
  352.   // difference between starting and ending points
  353.   dx = x2 - x1;
  354.   dy = y2 - y1;
  355.  
  356.   // calculate direction of the vector and store in ix and iy
  357.   if (dx >= 0)
  358.     ix = 1;
  359.  
  360.   if (dx < 0)
  361.     {
  362.       ix = -1;
  363.       dx = abs(dx);
  364.     }
  365.  
  366.   if (dy >= 0)
  367.     iy = 1;
  368.  
  369.   if (dy < 0)
  370.     {
  371.       iy = -1;
  372.       dy = abs(dy);
  373.     }
  374.  
  375.   // scale deltas and store in dx2 and dy2
  376.   dx2 = dx * 2;
  377.   dy2 = dy * 2;
  378.  
  379. // all  variables are set and it's time to enter the main loop.
  380.  
  381.   if (dx > dy)  // dx is the major axis
  382.     {
  383.       // initialize the error term
  384.       err = dy2 - dx;
  385.  
  386.       for (i = 0; i <= dx; i++)
  387.         {
  388.           drawPixel (x, y, color);
  389.           if (err >= 0)
  390.             {
  391.               err -= dx2;
  392.               y += iy;
  393.             }
  394.           err += dy2;
  395.           x += ix;
  396.         }
  397.     }
  398.  
  399.   else          // dy is the major axis
  400.     {
  401.       // initialize the error term
  402.       err = dx2 - dy;
  403.  
  404.       for (i = 0; i <= dy; i++)
  405.         {
  406.           drawPixel (x, y, color);
  407.           if (err >= 0)
  408.             {
  409.               err -= dy2;
  410.               x += ix;
  411.             }
  412.           err += dx2;
  413.           y += iy;
  414.         }
  415.     }
  416. }
  417.