max7219.c 24 KB

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