ssd1306_base.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450
  1. /**************************************************************************************
  2. * drivers/lcd/ssd1306_base.c
  3. * Driver for Univision UG-2864HSWEG01 OLED display or UG-2832HSWEG04 both with the
  4. * Univision SSD1306 controller in SPI mode and Densitron DD-12864WO-4A with SSD1309
  5. * in SPI mode.
  6. *
  7. * Copyright (C) 2012-2013, 2015, 2018 Gregory Nutt. All rights reserved.
  8. * Author: Gregory Nutt <gnutt@nuttx.org>
  9. *
  10. * References:
  11. * 1. Product Specification (Preliminary), Part Name: OEL Display Module, Part ID:
  12. * UG-2864HSWEG01, Doc No: SAS1-9046-B, Univision Technology Inc.
  13. * 2. Product Specification, Part Name: OEL Display Module, Part ID: UG-2832HSWEG04,
  14. * Doc No.: SAS1-B020-B, Univision Technology Inc.
  15. * 3. SSD1306, 128 X 64 Dot Matrix OLED/PLED, Preliminary Segment/Common Driver with
  16. * Controller, Solomon Systech
  17. * 4. SSD1309, 128 x 64 Dot Matrix OLED/PLED Segment/Common Driver with Controller,
  18. * Solomon Systech
  19. *
  20. * Redistribution and use in source and binary forms, with or without
  21. * modification, are permitted provided that the following conditions
  22. * are met:
  23. *
  24. * 1. Redistributions of source code must retain the above copyright
  25. * notice, this list of conditions and the following disclaimer.
  26. * 2. Redistributions in binary form must reproduce the above copyright
  27. * notice, this list of conditions and the following disclaimer in
  28. * the documentation and/or other materials provided with the
  29. * distribution.
  30. * 3. Neither the name NuttX nor the names of its contributors may be
  31. * used to endorse or promote products derived from this software
  32. * without specific prior written permission.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  35. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  36. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  37. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  38. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  39. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  40. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  41. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  42. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  43. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  44. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  45. * POSSIBILITY OF SUCH DAMAGE.
  46. *
  47. **************************************************************************************/
  48. /**************************************************************************************
  49. * Device memory organization:
  50. *
  51. * +----------------------------+
  52. * | Column |
  53. * --------+----+---+---+---+-...-+-----+
  54. * Page | 0 | 1 | 2 | 3 | ... | 127 |
  55. * --------+----+---+---+---+-...-+-----+
  56. * Page 0 | D0 | X | | | | |
  57. * | D1 | X | | | | |
  58. * | D2 | X | | | | |
  59. * | D3 | X | | | | |
  60. * | D4 | X | | | | |
  61. * | D5 | X | | | | |
  62. * | D6 | X | | | | |
  63. * | D7 | X | | | | |
  64. * --------+----+---+---+---+-...-+-----+
  65. * Page 1 | | | | | | |
  66. * --------+----+---+---+---+-...-+-----+
  67. * Page 2 | | | | | | |
  68. * --------+----+---+---+---+-...-+-----+
  69. * Page 3 | | | | | | |
  70. * --------+----+---+---+---+-...-+-----+
  71. * Page 4 | | | | | | |
  72. * --------+----+---+---+---+-...-+-----+
  73. * Page 5 | | | | | | |
  74. * --------+----+---+---+---+-...-+-----+
  75. * Page 6 | | | | | | |
  76. * --------+----+---+---+---+-...-+-----+
  77. * Page 7 | | | | | | |
  78. * --------+----+---+---+---+-...-+-----+
  79. *
  80. * -----------------------------------+---------------------------------------
  81. * Landscape Display: | Reverse Landscape Display:
  82. * --------+-----------------------+ | --------+---------------------------+
  83. * | Column | | | Column |
  84. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  85. * Page 0 | 0 | 1 | 2 | | 127 | | Page 7 | 127 | 126 | 125 | | 0 |
  86. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  87. * Page 1 | V | | Page 6 | ^ |
  88. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  89. * Page 2 | V | | Page 5 | ^ |
  90. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  91. * Page 3 | V | | Page 4 | ^ |
  92. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  93. * Page 4 | V | | Page 3 | ^ |
  94. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  95. * Page 5 | V | | Page 2 | ^ |
  96. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  97. * Page 6 | V | | Page 1 | ^ |
  98. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  99. * Page 7 | V | | Page 0 | ^ |
  100. * --------+---+---+---+-...-+-----+ | --------+-----+-----+-----+-...-+---+
  101. * -----------------------------------+---------------------------------------
  102. *
  103. * -----------------------------------+---------------------------------------
  104. * Portrait Display: | Reverse Portrait Display:
  105. * -----------+---------------------+ | -----------+---------------------+
  106. * | Page | | | Page |
  107. * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+
  108. * Column 0 | 0 | 1 | 2 | | 7 | | Column 127 | 7 | 6 | 5 | | 0 |
  109. * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+
  110. * Column 1 | > > > > > | | Column 126 | |
  111. * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+
  112. * Column 2 | | | Column 125 | |
  113. * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+
  114. * ... | | | ... | |
  115. * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+
  116. * Column 127 | | | Column 0 | < < < < < |
  117. * -----------+---+---+---+-...-+---+ | -----------+---+---+---+-...-+---+
  118. * -----------------------------------+----------------------------------------
  119. **************************************************************************************/
  120. /**************************************************************************************
  121. * Included Files
  122. **************************************************************************************/
  123. #include <nuttx/config.h>
  124. #include <sys/types.h>
  125. #include <stdint.h>
  126. #include <stdbool.h>
  127. #include <string.h>
  128. #include <errno.h>
  129. #include <debug.h>
  130. #include <nuttx/arch.h>
  131. #include <nuttx/i2c/i2c_master.h>
  132. #include <nuttx/spi/spi.h>
  133. #include <nuttx/lcd/lcd.h>
  134. #include <nuttx/lcd/ssd1306.h>
  135. #include <arch/irq.h>
  136. #include "ssd1306.h"
  137. #ifdef CONFIG_LCD_SSD1306
  138. /**************************************************************************************
  139. * Private Function Prototypes
  140. **************************************************************************************/
  141. /* LCD Data Transfer Methods */
  142. static int ssd1306_putrun(fb_coord_t row, fb_coord_t col,
  143. FAR const uint8_t *buffer, size_t npixels);
  144. static int ssd1306_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
  145. size_t npixels);
  146. /* LCD Configuration */
  147. static int ssd1306_getvideoinfo(FAR struct lcd_dev_s *dev,
  148. FAR struct fb_videoinfo_s *vinfo);
  149. static int ssd1306_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
  150. FAR struct lcd_planeinfo_s *pinfo);
  151. /* LCD RGB Mapping */
  152. #ifdef CONFIG_FB_CMAP
  153. # error "RGB color mapping not supported by this driver"
  154. #endif
  155. /* Cursor Controls */
  156. #ifdef CONFIG_FB_HWCURSOR
  157. # error "Cursor control not supported by this driver"
  158. #endif
  159. /* LCD Specific Controls */
  160. static int ssd1306_getpower(struct lcd_dev_s *dev);
  161. static int ssd1306_setpower(struct lcd_dev_s *dev, int power);
  162. static int ssd1306_getcontrast(struct lcd_dev_s *dev);
  163. static int ssd1306_setcontrast(struct lcd_dev_s *dev, unsigned int contrast);
  164. static int ssd1306_do_disponoff(struct ssd1306_dev_s *priv, bool on);
  165. static int ssd1306_configuredisplay(struct ssd1306_dev_s *priv);
  166. static int ssd1306_redrawfb(struct ssd1306_dev_s *priv);
  167. /**************************************************************************************
  168. * Private Data
  169. **************************************************************************************/
  170. /* This is working memory allocated by the LCD driver for each LCD device
  171. * and for each color plane. This memory will hold one raster line of data.
  172. * The size of the allocated run buffer must therefore be at least
  173. * (bpp * xres / 8). Actual alignment of the buffer must conform to the
  174. * bitwidth of the underlying pixel type.
  175. *
  176. * If there are multiple planes, they may share the same working buffer
  177. * because different planes will not be operate on concurrently. However,
  178. * if there are multiple LCD devices, they must each have unique run buffers.
  179. */
  180. static uint8_t g_runbuffer[SSD1306_DEV_ROWSIZE];
  181. /* This structure describes the overall LCD video controller */
  182. static const struct fb_videoinfo_s g_videoinfo =
  183. {
  184. .fmt = SSD1306_DEV_COLORFMT, /* Color format: B&W */
  185. .xres = SSD1306_DEV_XRES, /* Horizontal resolution in pixel columns */
  186. .yres = SSD1306_DEV_YRES, /* Vertical resolution in pixel rows */
  187. .nplanes = 1, /* Number of color planes supported */
  188. };
  189. /* This is the standard, NuttX Plane information object */
  190. static const struct lcd_planeinfo_s g_planeinfo =
  191. {
  192. .putrun = ssd1306_putrun, /* Put a run into LCD memory */
  193. .getrun = ssd1306_getrun, /* Get a run from LCD memory */
  194. .buffer = (FAR uint8_t *)g_runbuffer, /* Run scratch buffer */
  195. .bpp = SSD1306_DEV_BPP, /* Bits-per-pixel */
  196. };
  197. /* This is the outside visible interface for the OLED driver */
  198. static const struct lcd_dev_s g_oleddev_dev =
  199. {
  200. /* LCD Configuration */
  201. .getvideoinfo = ssd1306_getvideoinfo,
  202. .getplaneinfo = ssd1306_getplaneinfo,
  203. /* LCD RGB Mapping -- Not supported */
  204. /* Cursor Controls -- Not supported */
  205. /* LCD Specific Controls */
  206. .getpower = ssd1306_getpower,
  207. .setpower = ssd1306_setpower,
  208. .getcontrast = ssd1306_getcontrast,
  209. .setcontrast = ssd1306_setcontrast,
  210. };
  211. /* This is the OLED driver instance (only a single device is supported for now) */
  212. static struct ssd1306_dev_s g_oleddev;
  213. /**************************************************************************************
  214. * Private Functions
  215. **************************************************************************************/
  216. /**************************************************************************************
  217. * Name: ssd1306_putrun
  218. *
  219. * Description:
  220. * This method can be used to write a partial raster line to the LCD.
  221. *
  222. * Input Parameters:
  223. * row - Starting row to write to (range: 0 <= row < yres)
  224. * col - Starting column to write to (range: 0 <= col <= xres-npixels)
  225. * buffer - The buffer containing the run to be written to the LCD
  226. * npixels - The number of pixels to write to the LCD
  227. * (range: 0 < npixels <= xres-col)
  228. *
  229. **************************************************************************************/
  230. #if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
  231. static int ssd1306_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
  232. size_t npixels)
  233. {
  234. /* Because of this line of code, we will only be able to support a single UG device */
  235. FAR struct ssd1306_dev_s *priv = (FAR struct ssd1306_dev_s *)&g_oleddev;
  236. FAR uint8_t *fbptr;
  237. FAR uint8_t *ptr;
  238. uint8_t devcol;
  239. uint8_t fbmask;
  240. uint8_t page;
  241. uint8_t usrmask;
  242. int pixlen;
  243. uint8_t i;
  244. int ret;
  245. lcdinfo("row: %d col: %d npixels: %d\n", row, col, npixels);
  246. DEBUGASSERT(buffer);
  247. /* Clip the run to the display */
  248. pixlen = npixels;
  249. if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)SSD1306_DEV_XRES)
  250. {
  251. pixlen = (int)SSD1306_DEV_XRES - (int)col;
  252. }
  253. /* Verify that some portion of the run remains on the display */
  254. if (pixlen <= 0 || row > SSD1306_DEV_YRES)
  255. {
  256. return OK;
  257. }
  258. /* Perform coordinate conversion for reverse landscape mode.
  259. * If the rows are reversed then rows are are a mirror reflection of
  260. * top to bottom.
  261. */
  262. #ifdef SSD1306_DEV_REVERSEY
  263. row = (SSD1306_DEV_YRES-1) - row;
  264. #endif
  265. /* If the column is switched then the start of the run is the mirror of
  266. * the end of the run.
  267. *
  268. * col+pixlen-1
  269. * col |
  270. * 0 | | XRES
  271. * . S>>>>>>E .
  272. * . E<<<<<<S .
  273. * | |
  274. * | `-(XRES-1)-col
  275. * ` (XRES-1)-col-(pixlen-1)
  276. */
  277. #ifdef SSD1306_DEV_REVERSEX
  278. col = (SSD1306_DEV_XRES-1) - col;
  279. col -= (pixlen - 1);
  280. #endif
  281. /* Get the page number. The range of 64 lines is divided up into eight
  282. * pages of 8 lines each.
  283. */
  284. page = row >> 3;
  285. /* Update the shadow frame buffer memory. First determine the pixel
  286. * position in the frame buffer memory. Pixels are organized like
  287. * this:
  288. *
  289. * --------+---+---+---+---+-...-+-----+
  290. * Segment | 0 | 1 | 2 | 3 | ... | 131 |
  291. * --------+---+---+---+---+-...-+-----+
  292. * D0 | | X | | | | |
  293. * D1 | | X | | | | |
  294. * D2 | | X | | | | |
  295. * D3 | | X | | | | |
  296. * D4 | | X | | | | |
  297. * D5 | | X | | | | |
  298. * D6 | | X | | | | |
  299. * D7 | | X | | | | |
  300. * --------+---+---+---+---+-...-+-----+
  301. *
  302. * So, in order to draw a white, horizontal line, at row 45. we
  303. * would have to modify all of the bytes in page 45/8 = 5. We
  304. * would have to set bit 45%8 = 5 in every byte in the page.
  305. */
  306. fbmask = 1 << (row & 7);
  307. fbptr = &priv->fb[page * SSD1306_DEV_XRES + col];
  308. #ifdef SSD1306_DEV_REVERSEX
  309. ptr = fbptr + (pixlen - 1);
  310. #else
  311. ptr = fbptr;
  312. #endif
  313. #ifdef CONFIG_LCD_PACKEDMSFIRST
  314. usrmask = MS_BIT;
  315. #else
  316. usrmask = LS_BIT;
  317. #endif
  318. for (i = 0; i < pixlen; i++)
  319. {
  320. /* Set or clear the corresponding bit */
  321. #ifdef SSD1306_DEV_REVERSEX
  322. if ((*buffer & usrmask) != 0)
  323. {
  324. *ptr-- |= fbmask;
  325. }
  326. else
  327. {
  328. *ptr-- &= ~fbmask;
  329. }
  330. #else
  331. if ((*buffer & usrmask) != 0)
  332. {
  333. *ptr++ |= fbmask;
  334. }
  335. else
  336. {
  337. *ptr++ &= ~fbmask;
  338. }
  339. #endif
  340. /* Inc/Decrement to the next source pixel */
  341. #ifdef CONFIG_LCD_PACKEDMSFIRST
  342. if (usrmask == LS_BIT)
  343. {
  344. buffer++;
  345. usrmask = MS_BIT;
  346. }
  347. else
  348. {
  349. usrmask >>= 1;
  350. }
  351. #else
  352. if (usrmask == MS_BIT)
  353. {
  354. buffer++;
  355. usrmask = LS_BIT;
  356. }
  357. else
  358. {
  359. usrmask <<= 1;
  360. }
  361. #endif
  362. }
  363. /* Offset the column position to account for smaller horizontal
  364. * display range.
  365. */
  366. devcol = col + SSD1306_DEV_XOFFSET;
  367. /* Lock and select device */
  368. ssd1306_select(priv, true);
  369. /* Select command transfer */
  370. ssd1306_cmddata(priv, true);
  371. /* Set the starting position for the run */
  372. /* Set the column address to the XOFFSET value */
  373. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLL(devcol & 0x0f));
  374. if (ret < 0)
  375. {
  376. return ret;
  377. }
  378. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLH(devcol >> 4));
  379. if (ret < 0)
  380. {
  381. return ret;
  382. }
  383. /* Set the page address */
  384. ret = ssd1306_sendbyte(priv, SSD1306_PAGEADDR(page));
  385. if (ret < 0)
  386. {
  387. return ret;
  388. }
  389. /* Select data transfer */
  390. ssd1306_cmddata(priv, false);
  391. /* Then transfer all of the data */
  392. ret = ssd1306_sendblk(priv, fbptr, pixlen);
  393. if (ret < 0)
  394. {
  395. return ret;
  396. }
  397. /* De-select and unlock the device */
  398. ssd1306_select(priv, false);
  399. return OK;
  400. }
  401. #else
  402. # error "Configuration not implemented"
  403. #endif
  404. /**************************************************************************************
  405. * Name: ssd1306_getrun
  406. *
  407. * Description:
  408. * This method can be used to read a partial raster line from the LCD.
  409. *
  410. * Description:
  411. * This method can be used to write a partial raster line to the LCD.
  412. *
  413. * row - Starting row to read from (range: 0 <= row < yres)
  414. * col - Starting column to read read (range: 0 <= col <= xres-npixels)
  415. * buffer - The buffer in which to return the run read from the LCD
  416. * npixels - The number of pixels to read from the LCD
  417. * (range: 0 < npixels <= xres-col)
  418. *
  419. **************************************************************************************/
  420. #if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
  421. static int ssd1306_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
  422. size_t npixels)
  423. {
  424. /* Because of this line of code, we will only be able to support a single UG device */
  425. FAR struct ssd1306_dev_s *priv = &g_oleddev;
  426. FAR uint8_t *fbptr;
  427. uint8_t page;
  428. uint8_t fbmask;
  429. uint8_t usrmask;
  430. int pixlen;
  431. uint8_t i;
  432. lcdinfo("row: %d col: %d npixels: %d\n", row, col, npixels);
  433. DEBUGASSERT(buffer);
  434. /* Clip the run to the display */
  435. pixlen = npixels;
  436. if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)SSD1306_DEV_XRES)
  437. {
  438. pixlen = (int)SSD1306_DEV_XRES - (int)col;
  439. }
  440. /* Verify that some portion of the run is actually the display */
  441. if (pixlen <= 0 || row > SSD1306_DEV_YRES)
  442. {
  443. return -EINVAL;
  444. }
  445. /* Perform coordinate conversion for reverse landscape mode.
  446. * If the rows are reversed then rows are are a mirror reflection of
  447. * top to bottom.
  448. */
  449. #ifdef SSD1306_DEV_REVERSEY
  450. row = (SSD1306_DEV_YRES-1) - row;
  451. #endif
  452. /* If the column is switched then the start of the run is the mirror of
  453. * the end of the run.
  454. *
  455. * col+pixlen-1
  456. * col |
  457. * 0 | | XRES
  458. * . S>>>>>>E .
  459. * . E<<<<<<S .
  460. * | |
  461. * | `-(XRES-1)-col
  462. * ` (XRES-1)-col-(pixlen-1)
  463. */
  464. #ifdef SSD1306_DEV_REVERSEX
  465. col = (SSD1306_DEV_XRES-1) - col;
  466. #endif
  467. /* Then transfer the display data from the shadow frame buffer memory */
  468. /* Get the page number. The range of 64 lines is divided up into eight
  469. * pages of 8 lines each.
  470. */
  471. page = row >> 3;
  472. /* Update the shadow frame buffer memory. First determine the pixel
  473. * position in the frame buffer memory. Pixels are organized like
  474. * this:
  475. *
  476. * --------+---+---+---+---+-...-+-----+
  477. * Segment | 0 | 1 | 2 | 3 | ... | 131 |
  478. * --------+---+---+---+---+-...-+-----+
  479. * D0 | | X | | | | |
  480. * D1 | | X | | | | |
  481. * D2 | | X | | | | |
  482. * D3 | | X | | | | |
  483. * D4 | | X | | | | |
  484. * D5 | | X | | | | |
  485. * D6 | | X | | | | |
  486. * D7 | | X | | | | |
  487. * --------+---+---+---+---+-...-+-----+
  488. *
  489. * So, in order to draw a white, horizontal line, at row 45. we
  490. * would have to modify all of the bytes in page 45/8 = 5. We
  491. * would have to set bit 45%8 = 5 in every byte in the page.
  492. */
  493. fbmask = 1 << (row & 7);
  494. fbptr = &priv->fb[page * SSD1306_DEV_XRES + col];
  495. #ifdef CONFIG_LCD_PACKEDMSFIRST
  496. usrmask = MS_BIT;
  497. #else
  498. usrmask = LS_BIT;
  499. #endif
  500. for (i = 0; i < pixlen; i++)
  501. {
  502. /* Set or clear the corresponding bit */
  503. #ifdef SSD1306_DEV_REVERSEX
  504. uint8_t byte = *fbptr--;
  505. #else
  506. uint8_t byte = *fbptr++;
  507. #endif
  508. if ((byte & fbmask) != 0)
  509. {
  510. *buffer |= usrmask;
  511. }
  512. else
  513. {
  514. *buffer &= ~usrmask;
  515. }
  516. /* Inc/Decrement to the next destination pixel. */
  517. #ifdef CONFIG_LCD_PACKEDMSFIRST
  518. if (usrmask == LS_BIT)
  519. {
  520. buffer++;
  521. usrmask = MS_BIT;
  522. }
  523. else
  524. {
  525. usrmask >>= 1;
  526. }
  527. #else
  528. if (usrmask == MS_BIT)
  529. {
  530. buffer++;
  531. usrmask = LS_BIT;
  532. }
  533. else
  534. {
  535. usrmask <<= 1;
  536. }
  537. #endif
  538. }
  539. return OK;
  540. }
  541. #else
  542. # error "Configuration not implemented"
  543. #endif
  544. /**************************************************************************************
  545. * Name: ssd1306_getvideoinfo
  546. *
  547. * Description:
  548. * Get information about the LCD video controller configuration.
  549. *
  550. **************************************************************************************/
  551. static int ssd1306_getvideoinfo(FAR struct lcd_dev_s *dev,
  552. FAR struct fb_videoinfo_s *vinfo)
  553. {
  554. DEBUGASSERT(dev && vinfo);
  555. lcdinfo("fmt: %d xres: %d yres: %d nplanes: %d\n",
  556. g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes);
  557. memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
  558. return OK;
  559. }
  560. /**************************************************************************************
  561. * Name: ssd1306_getplaneinfo
  562. *
  563. * Description:
  564. * Get information about the configuration of each LCD color plane.
  565. *
  566. **************************************************************************************/
  567. static int ssd1306_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
  568. FAR struct lcd_planeinfo_s *pinfo)
  569. {
  570. DEBUGASSERT(pinfo && planeno == 0);
  571. lcdinfo("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp);
  572. memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
  573. return OK;
  574. }
  575. /**************************************************************************************
  576. * Name: ssd1306_getpower
  577. *
  578. * Description:
  579. * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On
  580. * backlit LCDs, this setting may correspond to the backlight setting.
  581. *
  582. **************************************************************************************/
  583. static int ssd1306_getpower(FAR struct lcd_dev_s *dev)
  584. {
  585. FAR struct ssd1306_dev_s *priv = (FAR struct ssd1306_dev_s *)dev;
  586. DEBUGASSERT(priv);
  587. lcdinfo("power: %s\n", priv->on ? "ON" : "OFF");
  588. return priv->on ? CONFIG_LCD_MAXPOWER : 0;
  589. }
  590. /**************************************************************************************
  591. * Name: ssd1306_do_disponoff
  592. *
  593. * Description:
  594. * Enable/disable LCD panel power
  595. *
  596. **************************************************************************************/
  597. static int ssd1306_do_disponoff(struct ssd1306_dev_s *priv, bool on)
  598. {
  599. int ret;
  600. /* Lock and select device */
  601. ssd1306_select(priv, true);
  602. /* Select command transfer */
  603. ssd1306_cmddata(priv, true);
  604. /* Turn the display on/off */
  605. ret = ssd1306_sendbyte(priv, (on ? SSD1306_DISPON : SSD1306_DISPOFF));
  606. /* De-select and unlock the device */
  607. ssd1306_cmddata(priv, false);
  608. ssd1306_select(priv, false);
  609. return ret;
  610. }
  611. /**************************************************************************************
  612. * Name: ssd1306_setpower
  613. *
  614. * Description:
  615. * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
  616. * backlit LCDs, this setting may correspond to the backlight setting.
  617. *
  618. **************************************************************************************/
  619. static int ssd1306_setpower(FAR struct lcd_dev_s *dev, int power)
  620. {
  621. struct ssd1306_dev_s *priv = (struct ssd1306_dev_s *)dev;
  622. int ret;
  623. lcdinfo("power: %d [%d]\n", power, priv->on ? CONFIG_LCD_MAXPOWER : 0);
  624. DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER);
  625. if (power <= 0)
  626. {
  627. /* Turn the display off */
  628. ret = ssd1306_do_disponoff(priv, false);
  629. if (ret < 0)
  630. {
  631. return ret;
  632. }
  633. priv->on = false;
  634. /* Try turn off power completely */
  635. if (priv->board_priv && priv->board_priv->set_vcc)
  636. {
  637. /* Do power off. */
  638. if (priv->board_priv->set_vcc(false))
  639. {
  640. /* Display is completely powered off, not configured anymore. */
  641. priv->is_conf = false;
  642. }
  643. }
  644. }
  645. else
  646. {
  647. if (priv->board_priv && priv->board_priv->set_vcc)
  648. {
  649. /* Do power on. */
  650. (void)priv->board_priv->set_vcc(true);
  651. }
  652. if (!priv->is_conf)
  653. {
  654. /* Configure display and turn the display on */
  655. ret = ssd1306_configuredisplay(priv);
  656. if (ret < 0)
  657. {
  658. return ret;
  659. }
  660. /* Draw the framebuffer */
  661. ret = ssd1306_redrawfb(priv);
  662. }
  663. else
  664. {
  665. /* Turn the display on */
  666. ret = ssd1306_do_disponoff(priv, true);
  667. }
  668. if (ret < 0)
  669. {
  670. return ret;
  671. }
  672. priv->on = true;
  673. }
  674. return OK;
  675. }
  676. /**************************************************************************************
  677. * Name: ssd1306_getcontrast
  678. *
  679. * Description:
  680. * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
  681. *
  682. **************************************************************************************/
  683. static int ssd1306_getcontrast(struct lcd_dev_s *dev)
  684. {
  685. struct ssd1306_dev_s *priv = (struct ssd1306_dev_s *)dev;
  686. DEBUGASSERT(priv);
  687. lcdinfo("contrast: %d\n", priv->contrast);
  688. return priv->contrast;
  689. }
  690. /**************************************************************************************
  691. * Name: ssd1306_setcontrast
  692. *
  693. * Description:
  694. * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
  695. *
  696. **************************************************************************************/
  697. static int ssd1306_setcontrast(struct lcd_dev_s *dev, unsigned int contrast)
  698. {
  699. struct ssd1306_dev_s *priv = (struct ssd1306_dev_s *)dev;
  700. unsigned int scaled;
  701. int ret;
  702. lcdinfo("contrast: %d\n", contrast);
  703. DEBUGASSERT(priv);
  704. /* Verify the contrast value */
  705. #ifdef CONFIG_DEBUG_FEATURES
  706. if (contrast > CONFIG_LCD_MAXCONTRAST)
  707. {
  708. return -EINVAL;
  709. }
  710. #endif
  711. /* Scale contrast: newcontrast = 255 * contrast / CONFIG_LCD_MAXCONTRAST
  712. * Where contrast is in the range {1,255}
  713. */
  714. #if CONFIG_LCD_MAXCONTRAST != 255
  715. scaled = ((contrast << 8) - 1) / CONFIG_LCD_MAXCONTRAST;
  716. #else
  717. scaled = contrast;
  718. #endif
  719. /* Lock and select device */
  720. ssd1306_select(priv, true);
  721. /* Select command transfer */
  722. ssd1306_cmddata(priv, true);
  723. /* Set the contrast */
  724. ret = ssd1306_sendbyte(priv, SSD1306_CONTRAST_MODE); /* Set contrast control register */
  725. if (ret < 0)
  726. {
  727. return ret;
  728. }
  729. ret = ssd1306_sendbyte(priv, SSD1306_CONTRAST(scaled)); /* Data 1: Set 1 of 256 contrast steps */
  730. if (ret < 0)
  731. {
  732. return ret;
  733. }
  734. priv->contrast = contrast;
  735. /* De-select and unlock the device */
  736. ssd1306_select(priv, false);
  737. return OK;
  738. }
  739. /**************************************************************************************
  740. * Name: ssd1306_configuredisplay
  741. *
  742. * Description:
  743. * Setup LCD display.
  744. *
  745. **************************************************************************************/
  746. static int ssd1306_configuredisplay(struct ssd1306_dev_s *priv)
  747. {
  748. int ret;
  749. /* Lock and select device */
  750. ssd1306_select(priv, true);
  751. /* Select command transfer */
  752. ssd1306_cmddata(priv, true);
  753. /* Configure OLED SPI or I/O, must be delayed 1-10ms */
  754. up_mdelay(5);
  755. /* Configure the device */
  756. #ifdef IS_SSD1309
  757. ret = ssd1306_sendbyte(priv, SSD1309_PROTOFF); /* Unlock driver IC */
  758. if (ret < 0)
  759. {
  760. return ret;
  761. }
  762. ret = ssd1306_sendbyte(priv, SSD1306_DISPOFF); /* Display off 0xae */
  763. if (ret < 0)
  764. {
  765. return ret;
  766. }
  767. ret = ssd1306_sendbyte(priv, SSD1309_SETMEMORY); /* Set page addressing mode: 0x0, 0x01 or 0x02 */
  768. if (ret < 0)
  769. {
  770. return ret;
  771. }
  772. ret = ssd1306_sendbyte(priv, SSD1309_MEMADDR(0x02));
  773. if (ret < 0)
  774. {
  775. return ret;
  776. }
  777. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLL(0)); /* Set lower column address 0x00 */
  778. if (ret < 0)
  779. {
  780. return ret;
  781. }
  782. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLH(0)); /* Set higher column address 0x10 */
  783. if (ret < 0)
  784. {
  785. return ret;
  786. }
  787. ret = ssd1306_sendbyte(priv, SSD1306_STARTLINE(0)); /* Set display start line 0x40 */
  788. if (ret < 0)
  789. {
  790. return ret;
  791. }
  792. ret = ssd1306_sendbyte(priv, SSD1306_PAGEADDR(0)); /* Set page address (Can ignore) */
  793. if (ret < 0)
  794. {
  795. return ret;
  796. }
  797. ret = ssd1306_sendbyte(priv, SSD1306_CONTRAST_MODE); /* Contrast control 0x81 */
  798. if (ret < 0)
  799. {
  800. return ret;
  801. }
  802. ret = ssd1306_sendbyte(priv ,SSD1306_CONTRAST(SSD1309_DEV_CONTRAST)); /* Default contrast 0xff */
  803. if (ret < 0)
  804. {
  805. return ret;
  806. }
  807. ret = ssd1306_sendbyte(priv, SSD1306_REMAPPLEFT); /* Set segment remap left 95 to 0 | 0xa1 */
  808. if (ret < 0)
  809. {
  810. return ret;
  811. }
  812. ret = ssd1306_sendbyte(priv, SSD1306_EDISPOFF); /* Normal display off 0xa4 (Can ignore) */
  813. if (ret < 0)
  814. {
  815. return ret;
  816. }
  817. ret = ssd1306_sendbyte(priv, SSD1306_NORMAL); /* Normal (un-reversed) display mode 0xa6 */
  818. if (ret < 0)
  819. {
  820. return ret;
  821. }
  822. ret = ssd1306_sendbyte(priv, SSD1306_MRATIO_MODE); /* Multiplex ratio 0xa8 */
  823. if (ret < 0)
  824. {
  825. return ret;
  826. }
  827. ret = ssd1306_sendbyte(priv, SSD1306_MRATIO(SSD1306_DEV_DUTY)); /* Duty = 1/64 or 1/32 */
  828. if (ret < 0)
  829. {
  830. return ret;
  831. }
  832. ret = ssd1306_sendbyte(priv, SSD1306_SCANFROMCOM0); /* Com scan direction: Scan from COM[0] to COM[n-1] */
  833. if (ret < 0)
  834. {
  835. return ret;
  836. }
  837. ret = ssd1306_sendbyte(priv, SSD1306_DISPOFFS_MODE); /* Set display offset 0xd3 */
  838. if (ret < 0)
  839. {
  840. return ret;
  841. }
  842. ret = ssd1306_sendbyte(priv, SSD1306_DISPOFFS(0));
  843. if (ret < 0)
  844. {
  845. return ret;
  846. }
  847. ret = ssd1306_sendbyte(priv, SSD1306_CLKDIV_SET); /* Set clock divider 0xd5 */
  848. if (ret < 0)
  849. {
  850. return ret;
  851. }
  852. ret = ssd1306_sendbyte(priv, SSD1306_CLKDIV(7,0)); /* 0x70 */
  853. if (ret < 0)
  854. {
  855. return ret;
  856. }
  857. ret = ssd1306_sendbyte(priv, SSD1306_CHRGPER_SET); /* Set pre-charge period 0xd9 */
  858. if (ret < 0)
  859. {
  860. return ret;
  861. }
  862. ret = ssd1306_sendbyte(priv, SSD1306_CHRGPER(0x0f,0x0a)); /* 0xfa: Fh cycles for discharge and Ah cycles for pre-charge */
  863. if (ret < 0)
  864. {
  865. return ret;
  866. }
  867. ret = ssd1306_sendbyte(priv, SSD1306_CMNPAD_CONFIG); /* Set common pads / set com pins hardware configuration 0xda */
  868. if (ret < 0)
  869. {
  870. return ret;
  871. }
  872. ret = ssd1306_sendbyte(priv, SSD1306_CMNPAD(SSD1306_DEV_CMNPAD)); /* 0x12 or 0x02 */
  873. if (ret < 0)
  874. {
  875. return ret;
  876. }
  877. ret = ssd1306_sendbyte(priv, SSD1306_VCOM_SET); /* set vcomh 0xdb */
  878. if (ret < 0)
  879. {
  880. return ret;
  881. }
  882. ret = ssd1306_sendbyte(priv, SSD1306_VCOM(0x3C));
  883. if (ret < 0)
  884. {
  885. return ret;
  886. }
  887. #else
  888. ret = ssd1306_sendbyte(priv, SSD1306_DISPOFF); /* Display off 0xae */
  889. if (ret < 0)
  890. {
  891. return ret;
  892. }
  893. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLL(0)); /* Set lower column address 0x00 */
  894. if (ret < 0)
  895. {
  896. return ret;
  897. }
  898. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLH(0)); /* Set higher column address 0x10 */
  899. if (ret < 0)
  900. {
  901. return ret;
  902. }
  903. ret = ssd1306_sendbyte(priv, SSD1306_STARTLINE(0)); /* Set display start line 0x40 */
  904. if (ret < 0)
  905. {
  906. return ret;
  907. }
  908. #if 0
  909. ret = ssd1306_sendbyte(priv, SSD1306_PAGEADDR(0)); /* Set page address (Can ignore) */
  910. if (ret < 0)
  911. {
  912. return ret;
  913. }
  914. #endif
  915. ret = ssd1306_sendbyte(priv, SSD1306_CONTRAST_MODE); /* Contrast control 0x81 */
  916. if (ret < 0)
  917. {
  918. return ret;
  919. }
  920. ret = ssd1306_sendbyte(priv, SSD1306_CONTRAST(SSD1306_DEV_CONTRAST)); /* Default contrast 0xCF */
  921. if (ret < 0)
  922. {
  923. return ret;
  924. }
  925. ret = ssd1306_sendbyte(priv, SSD1306_REMAPPLEFT); /* Set segment remap left 95 to 0 | 0xa1 */
  926. if (ret < 0)
  927. {
  928. return ret;
  929. }
  930. #if 0
  931. ret = ssd1306_sendbyte(priv, SSD1306_EDISPOFF); /* Normal display off 0xa4 (Can ignore) */
  932. if (ret < 0)
  933. {
  934. return ret;
  935. }
  936. #endif
  937. ret = ssd1306_sendbyte(priv, SSD1306_NORMAL); /* Normal (un-reversed) display mode 0xa6 */
  938. if (ret < 0)
  939. {
  940. return ret;
  941. }
  942. ret = ssd1306_sendbyte(priv, SSD1306_MRATIO_MODE); /* Multiplex ratio 0xa8 */
  943. if (ret < 0)
  944. {
  945. return ret;
  946. }
  947. ret = ssd1306_sendbyte(priv, SSD1306_MRATIO(SSD1306_DEV_DUTY)); /* Duty = 1/64 or 1/32 */
  948. if (ret < 0)
  949. {
  950. return ret;
  951. }
  952. #if 0
  953. ret = ssd1306_sendbyte(priv, SSD1306_SCANTOCOM0); /* Com scan direction: Scan from COM[n-1] to COM[0] (Can ignore) */
  954. if (ret < 0)
  955. {
  956. return ret;
  957. }
  958. #endif
  959. ret = ssd1306_sendbyte(priv, SSD1306_DISPOFFS_MODE); /* Set display offset 0xd3 */
  960. if (ret < 0)
  961. {
  962. return ret;
  963. }
  964. ret = ssd1306_sendbyte(priv, SSD1306_DISPOFFS(0));
  965. if (ret < 0)
  966. {
  967. return ret;
  968. }
  969. ret = ssd1306_sendbyte(priv, SSD1306_CLKDIV_SET); /* Set clock divider 0xd5 */
  970. if (ret < 0)
  971. {
  972. return ret;
  973. }
  974. ret = ssd1306_sendbyte(priv, SSD1306_CLKDIV(8, 0)); /* 0x80 */
  975. if (ret < 0)
  976. {
  977. return ret;
  978. }
  979. ret = ssd1306_sendbyte(priv, SSD1306_CHRGPER_SET); /* Set pre-charge period 0xd9 */
  980. if (ret < 0)
  981. {
  982. return ret;
  983. }
  984. ret = ssd1306_sendbyte(priv, SSD1306_CHRGPER(0x0f, 1)); /* 0xf1 or 0x22 Enhanced mode */
  985. if (ret < 0)
  986. {
  987. return ret;
  988. }
  989. ret = ssd1306_sendbyte(priv, SSD1306_CMNPAD_CONFIG); /* Set common pads / set com pins hardware configuration 0xda */
  990. if (ret < 0)
  991. {
  992. return ret;
  993. }
  994. ret = ssd1306_sendbyte(priv, SSD1306_CMNPAD(SSD1306_DEV_CMNPAD)); /* 0x12 or 0x02 */
  995. if (ret < 0)
  996. {
  997. return ret;
  998. }
  999. ret = ssd1306_sendbyte(priv, SSD1306_VCOM_SET); /* set vcomh 0xdb */
  1000. if (ret < 0)
  1001. {
  1002. return ret;
  1003. }
  1004. ret = ssd1306_sendbyte(priv, SSD1306_VCOM(0x40));
  1005. if (ret < 0)
  1006. {
  1007. return ret;
  1008. }
  1009. ret = ssd1306_sendbyte(priv, SSD1306_CHRPUMP_SET); /* Set Charge Pump enable/disable 0x8d ssd1306 */
  1010. if (ret < 0)
  1011. {
  1012. return ret;
  1013. }
  1014. ret = ssd1306_sendbyte(priv, SSD1306_CHRPUMP_ON); /* 0x14 close 0x10 */
  1015. if (ret < 0)
  1016. {
  1017. return ret;
  1018. }
  1019. #if 0
  1020. ret = ssd1306_sendbyte(priv, SSD1306_DCDC_MODE); /* DC/DC control mode: on (SSD1306 Not supported) */
  1021. if (ret < 0)
  1022. {
  1023. return ret;
  1024. }
  1025. ret = ssd1306_sendbyte(priv, SSD1306_DCDC_ON);
  1026. if (ret < 0)
  1027. {
  1028. return ret;
  1029. }
  1030. #endif
  1031. #endif
  1032. ret = ssd1306_sendbyte(priv, SSD1306_DISPON); /* Display ON 0xaf */
  1033. if (ret < 0)
  1034. {
  1035. return ret;
  1036. }
  1037. /* De-select and unlock the device */
  1038. ssd1306_select(priv, false);
  1039. up_mdelay(100);
  1040. priv->is_conf = true;
  1041. return OK;
  1042. }
  1043. /**************************************************************************************
  1044. * Name: ssd1306_redrawfb
  1045. *
  1046. * Description:
  1047. * Redraw full framebuffer to display
  1048. *
  1049. * Input Parameters:
  1050. * priv - Reference to private driver structure
  1051. *
  1052. * Assumptions:
  1053. * Caller has selected the OLED section.
  1054. *
  1055. **************************************************************************************/
  1056. static int ssd1306_redrawfb(struct ssd1306_dev_s *priv)
  1057. {
  1058. unsigned int page;
  1059. int ret;
  1060. /* Lock and select device */
  1061. ssd1306_select(priv, true);
  1062. /* Visit each page */
  1063. for (page = 0; page < SSD1306_DEV_PAGES; page++)
  1064. {
  1065. /* Select command transfer */
  1066. ssd1306_cmddata(priv, true);
  1067. /* Set the column address to the XOFFSET value */
  1068. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLL(SSD1306_DEV_XOFFSET));
  1069. if (ret < 0)
  1070. {
  1071. return ret;
  1072. }
  1073. ret = ssd1306_sendbyte(priv, SSD1306_SETCOLH(0));
  1074. if (ret < 0)
  1075. {
  1076. return ret;
  1077. }
  1078. /* Set the page address */
  1079. ret = ssd1306_sendbyte(priv, SSD1306_PAGEADDR(page));
  1080. if (ret < 0)
  1081. {
  1082. return ret;
  1083. }
  1084. /* Select data transfer */
  1085. ssd1306_cmddata(priv, false);
  1086. /* Transfer one page of the selected color */
  1087. ret = ssd1306_sendblk(priv, &priv->fb[page * SSD1306_DEV_XRES],
  1088. SSD1306_DEV_XRES);
  1089. if (ret < 0)
  1090. {
  1091. return ret;
  1092. }
  1093. }
  1094. /* De-select and unlock the device */
  1095. ssd1306_select(priv, false);
  1096. return OK;
  1097. }
  1098. /**************************************************************************************
  1099. * Public Functions
  1100. **************************************************************************************/
  1101. /**************************************************************************************
  1102. * Name: ssd1306_initialize
  1103. *
  1104. * Description:
  1105. * Initialize the UG-2864HSWEG01 video hardware. The initial state of the
  1106. * OLED is fully initialized, display memory cleared, and the OLED ready
  1107. * to use, but with the power setting at 0 (full off == sleep mode).
  1108. *
  1109. * Input Parameters:
  1110. *
  1111. * spi - A reference to the SPI driver instance.
  1112. * devno - A value in the range of 0 through CONFIG_SSD1306_NINTERFACES-1.
  1113. * This allows support for multiple OLED devices.
  1114. *
  1115. * Returned Value:
  1116. *
  1117. * On success, this function returns a reference to the LCD object for
  1118. * the specified OLED. NULL is returned on any failure.
  1119. *
  1120. **************************************************************************************/
  1121. #ifdef CONFIG_LCD_SSD1306_SPI
  1122. FAR struct lcd_dev_s *ssd1306_initialize(FAR struct spi_dev_s *dev,
  1123. FAR const struct ssd1306_priv_s *board_priv,
  1124. unsigned int devno)
  1125. #else
  1126. FAR struct lcd_dev_s *ssd1306_initialize(FAR struct i2c_master_s *dev,
  1127. FAR const struct ssd1306_priv_s *board_priv,
  1128. unsigned int devno)
  1129. #endif
  1130. {
  1131. FAR struct ssd1306_dev_s *priv = &g_oleddev;
  1132. priv->dev = g_oleddev_dev;
  1133. DEBUGASSERT(dev && devno == 0);
  1134. priv->on = false;
  1135. priv->is_conf = false;
  1136. /* Register board specific functions */
  1137. priv->board_priv = board_priv;
  1138. #ifdef CONFIG_LCD_SSD1306_SPI
  1139. priv->spi = dev;
  1140. /* Configure the SPI */
  1141. ssd1306_configspi(priv->spi);
  1142. #else
  1143. /* Remember the I2C configuration */
  1144. priv->i2c = dev;
  1145. priv->addr = CONFIG_SSD1306_I2CADDR;
  1146. #endif
  1147. /* Initialize the framebuffer */
  1148. memset(priv->fb, SSD1306_Y1_BLACK & 1 ? 0xff : 0x00, SSD1306_DEV_FBSIZE);
  1149. /* Power on and configure display */
  1150. ssd1306_setpower(&priv->dev, true);
  1151. return &priv->dev;
  1152. }
  1153. /**************************************************************************************
  1154. * Name: ssd1306_fill
  1155. *
  1156. * Description:
  1157. * This non-standard method can be used to clear the entire display by writing one
  1158. * color to the display. This is much faster than writing a series of runs.
  1159. *
  1160. * Input Parameters:
  1161. * priv - Reference to private driver structure
  1162. *
  1163. * Assumptions:
  1164. * Caller has selected the OLED section.
  1165. *
  1166. **************************************************************************************/
  1167. int ssd1306_fill(FAR struct lcd_dev_s *dev, uint8_t color)
  1168. {
  1169. FAR struct ssd1306_dev_s *priv = (struct ssd1306_dev_s *)dev;
  1170. /* Make an 8-bit version of the selected color */
  1171. if (color & 1)
  1172. {
  1173. color = 0xff;
  1174. }
  1175. else
  1176. {
  1177. color = 0;
  1178. }
  1179. /* Initialize the framebuffer */
  1180. memset(priv->fb, color, SSD1306_DEV_FBSIZE);
  1181. /* Draw the framebuffer */
  1182. return ssd1306_redrawfb(priv);
  1183. }
  1184. #endif /* CONFIG_LCD_SSD1306 */