max7219.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. /****************************************************************************
  2. * drivers/lcd/max7219.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /* Driver for the Maxim MAX7219 used for driver 8x8 LED display chains. */
  21. /****************************************************************************
  22. * Included Files
  23. ****************************************************************************/
  24. #include <nuttx/config.h>
  25. #include <sys/types.h>
  26. #include <stdint.h>
  27. #include <stdbool.h>
  28. #include <string.h>
  29. #include <assert.h>
  30. #include <errno.h>
  31. #include <debug.h>
  32. #include <nuttx/arch.h>
  33. #include <nuttx/spi/spi.h>
  34. #include <nuttx/lcd/lcd.h>
  35. #include <nuttx/lcd/max7219.h>
  36. /****************************************************************************
  37. * Pre-processor Definitions
  38. ****************************************************************************/
  39. /* Configuration ************************************************************/
  40. /* MAX7219 Configuration Settings:
  41. *
  42. * CONFIG_MAX7219_NHORIZONTALBLKS - Specifies the number of physical
  43. * MAX7219 devices that are connected together horizontally.
  44. *
  45. * CONFIG_MAX7219_NVERTICALBLKS - Specifies the number of physical
  46. * MAX7219 devices that are connected together vertically.
  47. *
  48. * CONFIG_LCD_INTENSITY - Defines the default bright of LEDs.
  49. *
  50. * Required LCD driver settings:
  51. * CONFIG_LCD_MAX7219 - Enable MAX7219 support
  52. *
  53. */
  54. /* Verify that all configuration requirements have been met */
  55. /* SPI frequency */
  56. #ifndef CONFIG_MAX7219_FREQUENCY
  57. # define CONFIG_MAX7219_FREQUENCY 10000000
  58. #endif
  59. /* MAX7219_NHORIZONTALBLKS determines the number of physical 8x8 LEDs
  60. * matrices that are used connected horizontally.
  61. */
  62. #ifndef CONFIG_MAX7219_NHORIZONTALBLKS
  63. # define CONFIG_MAX7219_NHORIZONTALBLKS 1
  64. #endif
  65. /* MAX7219_NVERTICALBLKS determines the number of physical 8x8 LEDs
  66. * matrices that are used connected vertically.
  67. */
  68. #ifndef CONFIG_MAX7219_NVERTICALBLKS
  69. # define CONFIG_MAX7219_NVERTICALBLKS 1
  70. #endif
  71. #if CONFIG_LCD_MAXCONTRAST > 15
  72. # undef CONFIG_LCD_MAXCONTRAST
  73. # define CONFIG_LCD_MAXCONTRAST 15
  74. #endif
  75. /* Color Properties *********************************************************/
  76. /* The MAX7219 chip can handle resolution of 8x8, 16x8, 8x16, 16x16, 24x8,
  77. * etc.
  78. */
  79. /* Display Resolution */
  80. #define MAX7219_XRES (8 * CONFIG_MAX7219_NHORIZONTALBLKS)
  81. #define MAX7219_YRES (8 * CONFIG_MAX7219_NVERTICALBLKS)
  82. /* Color depth and format */
  83. #define MAX7219_BPP 1
  84. #define MAX7219_COLORFMT FB_FMT_Y1
  85. /* Bytes per logical row and actual device row */
  86. #define MAX7219_XSTRIDE (MAX7219_XRES >> 3) /* Pixels arrange "horizontally for user" */
  87. #define MAX7219_YSTRIDE (MAX7219_YRES >> 3) /* Pixels arrange "vertically for user" */
  88. /* The size of the shadow frame buffer */
  89. #define MAX7219_FBSIZE (MAX7219_XRES * MAX7219_YSTRIDE) + 1
  90. /* Bit helpers */
  91. #define LS_BIT (1 << 0)
  92. #define MS_BIT (1 << 7)
  93. #define BIT(nr) (1 << (nr))
  94. #define BITS_PER_BYTE 8
  95. #define BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE))
  96. #define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
  97. /****************************************************************************
  98. * Private Type Definition
  99. ****************************************************************************/
  100. /* This structure describes the state of this driver */
  101. struct max7219_dev_s
  102. {
  103. /* Publicly visible device structure */
  104. struct lcd_dev_s dev;
  105. /* Private LCD-specific information follows */
  106. FAR struct spi_dev_s *spi;
  107. uint8_t contrast;
  108. uint8_t powered;
  109. /* The MAX7219 does not support reading from the display memory in SPI
  110. * mode. Since there is 1 BPP and access is byte-by-byte, it is necessary
  111. * to keep a shadow copy of the framebuffer memory.
  112. */
  113. uint8_t fb[MAX7219_FBSIZE];
  114. };
  115. /****************************************************************************
  116. * Private Function Protototypes
  117. ****************************************************************************/
  118. /* SPI helpers */
  119. static void max7219_select(FAR struct spi_dev_s *spi);
  120. static void max7219_deselect(FAR struct spi_dev_s *spi);
  121. /* LCD Data Transfer Methods */
  122. static int max7219_putrun(fb_coord_t row, fb_coord_t col,
  123. FAR const uint8_t *buffer, size_t npixels);
  124. static int max7219_getrun(fb_coord_t row, fb_coord_t col,
  125. FAR uint8_t *buffer, size_t npixels);
  126. /* LCD Configuration */
  127. static int max7219_getvideoinfo(FAR struct lcd_dev_s *dev,
  128. FAR struct fb_videoinfo_s *vinfo);
  129. static int max7219_getplaneinfo(FAR struct lcd_dev_s *dev,
  130. unsigned int planeno, FAR struct lcd_planeinfo_s *pinfo);
  131. /* LCD RGB Mapping */
  132. #ifdef CONFIG_FB_CMAP
  133. # error "RGB color mapping not supported by this driver"
  134. #endif
  135. /* Cursor Controls */
  136. #ifdef CONFIG_FB_HWCURSOR
  137. # error "Cursor control not supported by this driver"
  138. #endif
  139. /* LCD Specific Controls */
  140. static int max7219_getpower(FAR struct lcd_dev_s *dev);
  141. static int max7219_setpower(FAR struct lcd_dev_s *dev, int power);
  142. static int max7219_getcontrast(FAR struct lcd_dev_s *dev);
  143. static int max7219_setcontrast(FAR struct lcd_dev_s *dev,
  144. unsigned int contrast);
  145. /* Initialization */
  146. static inline void up_clear(FAR struct max7219_dev_s *priv);
  147. /****************************************************************************
  148. * Private Data
  149. ****************************************************************************/
  150. /* This is working memory allocated by the LCD driver for each LCD device
  151. * and for each color plane. This memory will hold one raster line of data.
  152. * The size of the allocated run buffer must therefore be at least
  153. * (bpp * xres / 8). Actual alignment of the buffer must conform to the
  154. * bitwidth of the underlying pixel type.
  155. *
  156. * If there are multiple planes, they may share the same working buffer
  157. * because different planes will not be operate on concurrently. However,
  158. * if there are multiple LCD devices, they must each have unique run buffers.
  159. */
  160. static uint8_t g_runbuffer[MAX7219_XSTRIDE + 1];
  161. /* This structure describes the overall LCD video controller */
  162. static const struct fb_videoinfo_s g_videoinfo =
  163. {
  164. MAX7219_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
  165. MAX7219_XRES, /* Horizontal resolution in pixel columns */
  166. MAX7219_YRES, /* Vertical resolution in pixel rows */
  167. 1, /* Number of color planes supported */
  168. };
  169. /* This is the standard, NuttX Plane information object */
  170. static const struct lcd_planeinfo_s g_planeinfo =
  171. {
  172. .putrun = max7219_putrun, /* Put a run into LCD memory */
  173. .getrun = max7219_getrun, /* Get a run from LCD memory */
  174. .buffer = (FAR uint8_t *)g_runbuffer, /* Run scratch buffer */
  175. .bpp = MAX7219_BPP, /* Bits-per-pixel */
  176. };
  177. /* This is the standard, NuttX LCD driver object */
  178. static struct max7219_dev_s g_max7219dev =
  179. {
  180. /* struct lcd_dev_s */
  181. {
  182. /* LCD Configuration */
  183. max7219_getvideoinfo,
  184. max7219_getplaneinfo,
  185. #ifdef CONFIG_FB_CMAP
  186. /* LCD RGB Mapping -- Not supported */
  187. NULL,
  188. NULL,
  189. #endif
  190. #ifdef CONFIG_FB_HWCURSOR
  191. /* Cursor Controls -- Not supported */
  192. NULL,
  193. NULL,
  194. #endif
  195. /* LCD Specific Controls */
  196. max7219_getpower,
  197. max7219_setpower,
  198. max7219_getcontrast,
  199. max7219_setcontrast,
  200. },
  201. };
  202. /****************************************************************************
  203. * Private Functions
  204. ****************************************************************************/
  205. /****************************************************************************
  206. * __set_bit - Set a bit in memory
  207. *
  208. * nr - The bit to set
  209. * addr - The address to start counting from
  210. *
  211. * Unlike set_bit(), this function is non-atomic and may be reordered.
  212. * If it's called on the same region of memory simultaneously, the effect
  213. * may be that only one operation succeeds.
  214. *
  215. ****************************************************************************/
  216. static inline void __set_bit(int nr, uint8_t * addr)
  217. {
  218. uint8_t mask = BIT_MASK(nr);
  219. uint8_t *p = ((uint8_t *) addr) + BIT_BYTE(nr);
  220. *p |= mask;
  221. }
  222. static inline void __clear_bit(int nr, uint8_t * addr)
  223. {
  224. uint8_t mask = BIT_MASK(nr);
  225. uint8_t *p = ((uint8_t *) addr) + BIT_BYTE(nr);
  226. *p &= ~mask;
  227. }
  228. static inline int __test_bit(int nr, const volatile uint8_t * addr)
  229. {
  230. return 1 & (addr[BIT_BYTE(nr)] >> (nr & (BITS_PER_BYTE - 1)));
  231. }
  232. /****************************************************************************
  233. * Name: max7219_powerstring
  234. *
  235. * Description:
  236. * Convert the power setting to a string.
  237. *
  238. ****************************************************************************/
  239. static inline FAR const char *max7219_powerstring(uint8_t power)
  240. {
  241. if (power == MAX7219_POWER_OFF)
  242. {
  243. return "OFF";
  244. }
  245. else if (power == MAX7219_POWER_ON)
  246. {
  247. return "ON";
  248. }
  249. else
  250. {
  251. return "ERROR";
  252. }
  253. }
  254. /****************************************************************************
  255. * Name: max7219_select
  256. *
  257. * Description:
  258. * Select the SPI, locking and re-configuring if necessary
  259. *
  260. * Input Parameters:
  261. * spi - Reference to the SPI driver structure
  262. *
  263. * Returned Value:
  264. * None
  265. *
  266. ****************************************************************************/
  267. static void max7219_select(FAR struct spi_dev_s *spi)
  268. {
  269. /* Select MAX7219 chip (locking the SPI bus in case there are multiple
  270. * devices competing for the SPI bus
  271. */
  272. SPI_LOCK(spi, true);
  273. SPI_SELECT(spi, SPIDEV_DISPLAY(0), true);
  274. /* Now make sure that the SPI bus is configured for the MAX7219 (it
  275. * might have gotten configured for a different device while unlocked)
  276. */
  277. SPI_SETMODE(spi, SPIDEV_MODE0);
  278. SPI_SETBITS(spi, 8);
  279. SPI_HWFEATURES(spi, 0);
  280. SPI_SETFREQUENCY(spi, CONFIG_MAX7219_FREQUENCY);
  281. }
  282. /****************************************************************************
  283. * Name: max7219_deselect
  284. *
  285. * Description:
  286. * De-select the SPI
  287. *
  288. * Input Parameters:
  289. * spi - Reference to the SPI driver structure
  290. *
  291. * Returned Value:
  292. * None
  293. *
  294. ****************************************************************************/
  295. static void max7219_deselect(FAR struct spi_dev_s *spi)
  296. {
  297. /* De-select MAX7219 chip and relinquish the SPI bus. */
  298. SPI_SELECT(spi, SPIDEV_DISPLAY(0), false);
  299. SPI_LOCK(spi, false);
  300. }
  301. /****************************************************************************
  302. * Name: max7219_putrun
  303. *
  304. * Description:
  305. * This method can be used to write a partial raster line to the LCD:
  306. *
  307. * row - Starting row to write to (range: 0 <= row < yres)
  308. * col - Starting column to write to (range: 0 <= col <= xres-npixels)
  309. * buffer - The buffer containing the run to be written to the LCD
  310. * npixels - The number of pixels to write to the LCD
  311. * (range: 0 < npixels <= xres-col)
  312. *
  313. ****************************************************************************/
  314. static int max7219_putrun(fb_coord_t row, fb_coord_t col,
  315. FAR const uint8_t *buffer, size_t npixels)
  316. {
  317. /* Because of this line of code, we will only be able to support a single
  318. * MAX7219 device .
  319. */
  320. FAR struct max7219_dev_s *priv = &g_max7219dev;
  321. FAR uint8_t *fbptr;
  322. FAR uint8_t *ptr;
  323. uint16_t data;
  324. uint8_t usrmask;
  325. int i;
  326. int pixlen;
  327. int newrow;
  328. ginfo("row: %d col: %d npixels: %d\n", row, col, npixels);
  329. DEBUGASSERT(buffer);
  330. /* Clip the run to the display */
  331. pixlen = npixels;
  332. if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)MAX7219_XRES)
  333. {
  334. pixlen = (int)MAX7219_XRES - (int)col;
  335. }
  336. /* Verify that some portion of the run remains on the display */
  337. if (pixlen <= 0 || row > MAX7219_YRES)
  338. {
  339. return OK;
  340. }
  341. /* Get real row position in the strip */
  342. newrow = (int) (row % 8);
  343. /* Divide row by 8 */
  344. row = (row >> 3);
  345. col = col + (row * MAX7219_XRES);
  346. row = newrow;
  347. #ifdef CONFIG_LCD_PACKEDMSFIRST
  348. usrmask = MS_BIT;
  349. #else
  350. usrmask = LS_BIT;
  351. #endif
  352. #ifdef CONFIG_LCD_PACKEDMSFIRST
  353. usrmask = MS_BIT;
  354. #else
  355. usrmask = LS_BIT;
  356. #endif
  357. fbptr = &priv->fb[row * MAX7219_XSTRIDE * MAX7219_YSTRIDE];
  358. ptr = fbptr + (col >> 3);
  359. for (i = 0; i < pixlen; i++)
  360. {
  361. if ((*buffer & usrmask) != 0)
  362. {
  363. __set_bit(col % 8 + i, ptr);
  364. }
  365. else
  366. {
  367. __clear_bit(col % 8 + i, ptr);
  368. }
  369. #ifdef CONFIG_LCD_PACKEDMSFIRST
  370. if (usrmask == LS_BIT)
  371. {
  372. buffer++;
  373. usrmask = MS_BIT;
  374. }
  375. else
  376. {
  377. usrmask >>= 1;
  378. }
  379. #else
  380. if (usrmask == MS_BIT)
  381. {
  382. buffer++;
  383. usrmask = LS_BIT;
  384. }
  385. else
  386. {
  387. usrmask <<= 1;
  388. }
  389. #endif
  390. }
  391. /* Lock and select the device */
  392. max7219_select(priv->spi);
  393. /* We need to send last row/column first to avoid mirror image */
  394. for (i = (MAX7219_XSTRIDE * MAX7219_YSTRIDE) - 1; i >= 0; i--)
  395. {
  396. /* Setup the row data */
  397. data = (8 - row) | (*(fbptr + i) << 8);
  398. /* Then transfer all 8 columns of data */
  399. SPI_SNDBLOCK(priv->spi, &data, 2);
  400. }
  401. /* Unlock */
  402. max7219_deselect(priv->spi);
  403. return OK;
  404. }
  405. /****************************************************************************
  406. * Name: max7219_getrun
  407. *
  408. * Description:
  409. * This method can be used to read a partial raster line from the LCD:
  410. *
  411. * row - Starting row to read from (range: 0 <= row < yres)
  412. * col - Starting column to read read (range: 0 <= col <= xres-npixels)
  413. * buffer - The buffer in which to return the run read from the LCD
  414. * npixels - The number of pixels to read from the LCD
  415. * (range: 0 < npixels <= xres-col)
  416. *
  417. ****************************************************************************/
  418. static int max7219_getrun(fb_coord_t row, fb_coord_t col,
  419. FAR uint8_t *buffer, size_t npixels)
  420. {
  421. /* Because of this line of code, we will only be able to support a single
  422. * MAX7219 device.
  423. */
  424. FAR struct max7219_dev_s *priv = &g_max7219dev;
  425. FAR uint8_t *fbptr;
  426. FAR uint8_t *ptr;
  427. uint8_t usrmask;
  428. int i;
  429. int pixlen;
  430. ginfo("row: %d col: %d npixels: %d\n", row, col, npixels);
  431. DEBUGASSERT(buffer);
  432. /* Clip the run to the display */
  433. pixlen = npixels;
  434. if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)MAX7219_XRES)
  435. {
  436. pixlen = (int)MAX7219_XRES - (int)col;
  437. }
  438. /* Verify that some portion of the run is actually the display */
  439. if (pixlen <= 0 || row > MAX7219_YRES)
  440. {
  441. return -EINVAL;
  442. }
  443. #ifdef CONFIG_LCD_PACKEDMSFIRST
  444. usrmask = MS_BIT;
  445. #else
  446. usrmask = LS_BIT;
  447. #endif
  448. fbptr = &priv->fb[row * MAX7219_XSTRIDE];
  449. ptr = fbptr + (col >> 3);
  450. for (i = 0; i < pixlen; i++)
  451. {
  452. if (__test_bit(col % 8 + i, ptr))
  453. {
  454. *buffer |= usrmask;
  455. }
  456. else
  457. {
  458. *buffer &= ~usrmask;
  459. }
  460. #ifdef CONFIG_LCD_PACKEDMSFIRST
  461. if (usrmask == LS_BIT)
  462. {
  463. buffer++;
  464. usrmask = MS_BIT;
  465. }
  466. else
  467. {
  468. usrmask >>= 1;
  469. }
  470. #else
  471. if (usrmask == MS_BIT)
  472. {
  473. buffer++;
  474. usrmask = LS_BIT;
  475. }
  476. else
  477. {
  478. usrmask <<= 1;
  479. }
  480. #endif
  481. }
  482. return OK;
  483. }
  484. /****************************************************************************
  485. * Name: max7219_getvideoinfo
  486. *
  487. * Description:
  488. * Get information about the LCD video controller configuration.
  489. *
  490. ****************************************************************************/
  491. static int max7219_getvideoinfo(FAR struct lcd_dev_s *dev,
  492. FAR struct fb_videoinfo_s *vinfo)
  493. {
  494. DEBUGASSERT(dev && vinfo);
  495. ginfo("fmt: %d xres: %d yres: %d nplanes: %d\n",
  496. g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres,
  497. g_videoinfo.nplanes);
  498. memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
  499. return OK;
  500. }
  501. /****************************************************************************
  502. * Name: max7219_getplaneinfo
  503. *
  504. * Description:
  505. * Get information about the configuration of each LCD color plane.
  506. *
  507. ****************************************************************************/
  508. static int max7219_getplaneinfo(FAR struct lcd_dev_s *dev,
  509. unsigned int planeno,
  510. FAR struct lcd_planeinfo_s *pinfo)
  511. {
  512. DEBUGASSERT(dev && pinfo && planeno == 0);
  513. ginfo("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp);
  514. memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
  515. return OK;
  516. }
  517. /****************************************************************************
  518. * Name: max7219_getpower
  519. *
  520. * Description:
  521. * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full
  522. * on). On backlit LCDs, this setting may correspond to the backlight
  523. * setting.
  524. *
  525. ****************************************************************************/
  526. static int max7219_getpower(struct lcd_dev_s *dev)
  527. {
  528. struct max7219_dev_s *priv = (struct max7219_dev_s *)dev;
  529. DEBUGASSERT(priv);
  530. ginfo("powered: %s\n", max7219_powerstring(priv->powered));
  531. return priv->powered;
  532. }
  533. /****************************************************************************
  534. * Name: max7219_setpower
  535. *
  536. * Description:
  537. * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full
  538. * on). On backlit LCDs, this setting may correspond to the backlight
  539. * setting.
  540. *
  541. ****************************************************************************/
  542. static int max7219_setpower(struct lcd_dev_s *dev, int power)
  543. {
  544. struct max7219_dev_s *priv = (struct max7219_dev_s *)dev;
  545. uint16_t data;
  546. DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER);
  547. ginfo("power: %s powered: %s\n",
  548. max7219_powerstring(power), max7219_powerstring(priv->powered));
  549. /* Select and lock the device */
  550. max7219_select(priv->spi);
  551. if (power <= MAX7219_POWER_OFF)
  552. {
  553. data = (MAX7219_SHUTDOWN) | (MAX7219_POWER_OFF << 8);
  554. /* Turn the display off (power-down) */
  555. SPI_SNDBLOCK(priv->spi, &data, 2);
  556. priv->powered = MAX7219_POWER_OFF;
  557. }
  558. else
  559. {
  560. data = (MAX7219_SHUTDOWN) | (MAX7219_POWER_ON << 8);
  561. /* Leave the power-down */
  562. SPI_SNDBLOCK(priv->spi, &data, 2);
  563. priv->powered = MAX7219_POWER_ON;
  564. }
  565. /* Let go of the SPI lock and de-select the device */
  566. max7219_deselect(priv->spi);
  567. return OK;
  568. }
  569. /****************************************************************************
  570. * Name: max7219_getcontrast
  571. *
  572. * Description:
  573. * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
  574. *
  575. ****************************************************************************/
  576. static int max7219_getcontrast(struct lcd_dev_s *dev)
  577. {
  578. struct max7219_dev_s *priv = (struct max7219_dev_s *)dev;
  579. DEBUGASSERT(priv);
  580. return (int)priv->contrast;
  581. }
  582. /****************************************************************************
  583. * Name: max7219_setcontrast
  584. *
  585. * Description:
  586. * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
  587. *
  588. ****************************************************************************/
  589. static int max7219_setcontrast(struct lcd_dev_s *dev, unsigned int contrast)
  590. {
  591. struct max7219_dev_s *priv = (struct max7219_dev_s *)dev;
  592. uint16_t data;
  593. ginfo("contrast: %d\n", contrast);
  594. DEBUGASSERT(priv);
  595. if (contrast > 15)
  596. {
  597. return -EINVAL;
  598. }
  599. /* Save the contrast */
  600. priv->contrast = contrast;
  601. /* Select and lock the device */
  602. max7219_select(priv->spi);
  603. /* Configure the contrast/intensity */
  604. data = (MAX7219_INTENSITY) | (DISPLAY_INTENSITY(contrast) << 8);
  605. /* Set the contrast */
  606. SPI_SNDBLOCK(priv->spi, &data, 2);
  607. /* Let go of the SPI lock and de-select the device */
  608. max7219_deselect(priv->spi);
  609. return OK;
  610. }
  611. /****************************************************************************
  612. * Name: up_clear
  613. *
  614. * Description:
  615. * Clear the display.
  616. *
  617. ****************************************************************************/
  618. static inline void up_clear(FAR struct max7219_dev_s *priv)
  619. {
  620. FAR struct spi_dev_s *spi = priv->spi;
  621. uint16_t data;
  622. int row;
  623. int i;
  624. /* Clear the framebuffer */
  625. memset(priv->fb, MAX7219_BLACK, MAX7219_FBSIZE);
  626. /* Go throw max7219 all 8 rows */
  627. for (row = 0, i = 0; i < 8; i++)
  628. {
  629. /* Select and lock the device */
  630. max7219_select(priv->spi);
  631. /* Setup the row data */
  632. data = (row + 1) | (priv->fb[row] << 8);
  633. /* Then transfer all 8 columns of data */
  634. SPI_SNDBLOCK(priv->spi, &data, 2);
  635. /* Unlock and de-select the device */
  636. max7219_deselect(spi);
  637. }
  638. }
  639. /****************************************************************************
  640. * Public Functions
  641. ****************************************************************************/
  642. /****************************************************************************
  643. * Name: max7219_initialize
  644. *
  645. * Description:
  646. * Initialize the MAX7219 device as a LCD interface.
  647. *
  648. * Input Parameters:
  649. * spi - An instance of the SPI interface to use to communicate
  650. * with the MAX7219.
  651. * devno - Device number to identify current display.
  652. *
  653. * Returned Value:
  654. * Zero (OK) on success; a negated errno value on failure.
  655. *
  656. ****************************************************************************/
  657. FAR struct lcd_dev_s *max7219_initialize(FAR struct spi_dev_s *spi,
  658. unsigned int devno)
  659. {
  660. /* Configure and enable LCD */
  661. FAR struct max7219_dev_s *priv = &g_max7219dev;
  662. uint16_t data;
  663. ginfo("Initializing\n");
  664. DEBUGASSERT(spi && devno == 0);
  665. /* Save the reference to the SPI device */
  666. priv->spi = spi;
  667. /* Select and lock the device */
  668. max7219_select(spi);
  669. /* Leave the shutdown mode */
  670. data = (MAX7219_SHUTDOWN) | (MAX7219_POWER_ON << 8);
  671. SPI_SNDBLOCK(priv->spi, &data, 2);
  672. max7219_deselect(spi);
  673. max7219_select(spi);
  674. /* Disable 7 segment decoding */
  675. data = (MAX7219_DECODE_MODE) | (DISABLE_DECODE << 8);
  676. SPI_SNDBLOCK(priv->spi, &data, 2);
  677. max7219_deselect(spi);
  678. max7219_select(spi);
  679. /* Set scan limit for all digits */
  680. data = (MAX7219_SCAN_LIMIT) | (DEFAULT_SCAN_LIMIT << 8);
  681. SPI_SNDBLOCK(priv->spi, &data, 2);
  682. max7219_deselect(spi);
  683. max7219_select(spi);
  684. /* Set intensity level configured by the user */
  685. data = (MAX7219_INTENSITY) |
  686. (DISPLAY_INTENSITY(CONFIG_LCD_MAXCONTRAST) << 8);
  687. SPI_SNDBLOCK(priv->spi, &data, 2);
  688. /* Let go of the SPI lock and de-select the device */
  689. max7219_deselect(spi);
  690. /* Clear the framebuffer */
  691. up_clear(priv);
  692. return &priv->dev;
  693. }