spi_7seg.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. * Copyright (C) 2009 by Ulrich Prinz (uprinz2@netscape.net)
  3. * Copyright (C) 2009 by Rittal GmbH & Co. KG. All rights reserved.
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*!
  36. * \file dev/spi_7seg.c
  37. * \brief Routines for 7 segment display.
  38. *
  39. * \verbatim
  40. * $Id: spi_7seg.c,$
  41. * \endverbatim
  42. */
  43. #include <cfg/os.h>
  44. #include <cfg/arch.h>
  45. //#include <cfg/board.h>
  46. #include <compiler.h>
  47. #include <string.h>
  48. #include <stdlib.h>
  49. #ifdef SPI2SEG_DEBUG
  50. #include <stdio.h>
  51. #define NPRINTF(args,...) printf(args,##__VA_ARGS__)
  52. #else
  53. #define NPRINTF(args,...)
  54. #endif
  55. #include <sys/nutdebug.h>
  56. #include <sys/timer.h>
  57. #include <stdio.h>
  58. #include <cfg/memory.h>
  59. #include <dev/blockdev.h>
  60. #include <cfg/spi_7seg.h>
  61. #include <dev/spi_7seg.h>
  62. #include <cfg/arch/gpio.h>
  63. #include <dev/spibus_at91.h>
  64. /* Number of used or connected digits */
  65. #ifndef SEG7_DIGITS
  66. #define SEG7_DIGITS 4
  67. #endif
  68. #define SEG7_REVERSE
  69. /* AS1106/7/8 Register Abbreviations */
  70. #define SEGR_NOOP 0x00
  71. #define SEGR_DIG0 0x01
  72. #define SEGR_DIG1 0x02
  73. #define SEGR_DIG2 0x03
  74. #define SEGR_DIG3 0x04
  75. #define SEGR_DIG4 0x05
  76. #define SEGR_DIG5 0x06
  77. #define SEGR_DIG6 0x07
  78. #define SEGR_DIG7 0x08
  79. #define SEGR_DEC_MODE 0x09
  80. #define SEGR_INTENSITY 0x0a
  81. #define SEGR_SCAN_LIM 0x0b
  82. #define SEGR_SHUTDOWN 0x0c
  83. #define SEGR_FEATURE 0x0e
  84. #define SEGR_DSP_TEST 0x0f
  85. /* Shutdown Register (0x0c) */
  86. #define SHUTDOWN_RESET 0x00
  87. #define SHUTDOWN_SOFT 0x80
  88. #define NORM_OP_RESET 0x01
  89. #define NORM_OP_SOFT 0x81
  90. /* Decode Mode Register (0x09) */
  91. #define NO_DIG_DECODE 0x00
  92. #define DIG_0_DECODE 0x01
  93. #define DIG_0_3_DECODE 0x0f
  94. #define DIG_0_7_DECODE 0xff
  95. /* feature register (0x0e) */
  96. #define SEGF_EXTCLK 0x01
  97. #define SEGF_REGRES 0x02
  98. #define SEGF_DECSEL 0x04
  99. #define SEGF_SPIEN 0x08
  100. #define SEGF_BLINK 0x10
  101. #define SEGF_BLSLOW 0x20
  102. #define SEGF_BLSYNC 0x40
  103. #define SEGF_BLSTART 0x80
  104. #define SEGF_BLMASK (SEGF_BLINK|SEGF_BLSLOW)
  105. /* Test Mode register (0x0f) */
  106. #define TEST_MODE_OFF 0x00
  107. #define TEST_MODE_ON 0x01
  108. /* scan limit register (0x0b) */
  109. #define DISPLAY_LIMIT 2
  110. #ifndef SPI_RATE_DISP_7SEG
  111. #define SPI_RATE_DISP_7SEG 400000
  112. #endif
  113. #ifndef SPI_MODE_DISP_7SEG
  114. #define SPI_MODE_DISP_7SEG SPI_MODE_3
  115. #endif
  116. /* Bitmask for driver control */
  117. #define ICMD_UPDATE 0x01
  118. #define ICMD_INTENS 0x02
  119. #define ICMD_ESCAPE 0x80
  120. /*!
  121. * \brief Device Control Block for 7-Segment Display
  122. */
  123. typedef struct {
  124. uint_fast8_t digit[SEG7_DIGITS]; /*!< Buffer for Display content */
  125. uint_fast8_t dip; /*!< Actual cursor position */
  126. uint_fast8_t freg; /*!< mirror of internal feature control register */
  127. uint_fast8_t icmd; /*!< internal driver control register */
  128. } DCB_7SEG;
  129. /*********************************************************************************
  130. **
  131. ** 7-Segement Driver: Character Table
  132. **
  133. **/
  134. /* Display Interconnection
  135. *
  136. * --A--
  137. * | |
  138. * F B Bit: 7 6 5 4 3 2 1 0
  139. * +--G--+ Led: dp A B C D E F G
  140. * E C
  141. * | |
  142. * --D-- dp
  143. */
  144. /* 7 Segment Display Character Table */
  145. static const uint8_t Seg7CharTab[] = {
  146. /* ' ' */(0x00),
  147. /* '!' */(0x28),
  148. /* '"' */(0x22),
  149. /* '#' */(0x00),
  150. /* '$' */(0x5B),
  151. /* '%' */(0x00),
  152. /* '&' */(0x6F),
  153. /* '´' */(0x20),
  154. /* '(' */(0x4E),
  155. /* ')' */(0x78),
  156. /* '*' */(0x00),
  157. /* '+' */(0x31),
  158. /* ''' */(0x20),
  159. /* '-' */(0x01),
  160. /* '.' */(0x01),
  161. /* '/' */(0x15),
  162. /* '0' */(0x7E),
  163. /* '1' */(0x30),
  164. /* '2' */(0x6D),
  165. /* '3' */(0x79),
  166. /* '4' */(0x33),
  167. /* '5' */(0x5B),
  168. /* '6' */(0x5F),
  169. /* '7' */(0x70),
  170. /* '8' */(0x7F),
  171. /* '9' */(0x7B),
  172. /* ':' */(0x00),
  173. /* ';' */(0x00),
  174. /* '<' */(0x00),
  175. /* '=' */(0x09),
  176. /* '>' */(0x00),
  177. /* '?' */(0x65),
  178. /* '@' */(0x00),
  179. /* 'A' */(0x77),
  180. /* 'b' */(0x1F),
  181. /* 'c' */(0x0D),
  182. /* 'd' */(0x3D),
  183. /* 'E' */(0x4F),
  184. /* 'F' */(0x47),
  185. /* 'G' */(0x5F),
  186. /* 'H' */(0x37),
  187. /* 'i' */(0x10),
  188. /* 'J' */(0x3C),
  189. /* 'K' */(0x0F),
  190. /* 'L' */(0x0E),
  191. /* 'M' */(0x76),
  192. /* 'N' */(0x15),
  193. /* 'O' */(0x1D),
  194. /* 'P' */(0x67),
  195. /* 'Q' */(0x73),
  196. /* 'R' */(0x05),
  197. /* 'S' */(0x5B),
  198. /* 'T' */(0x0F),
  199. /* 'U' */(0x3E),
  200. /* 'V' */(0x1C),
  201. /* 'W' */(0x3F),
  202. /* 'X' */(0x37),
  203. /* 'Y' */(0x3B),
  204. /* 'Z' */(0x6D),
  205. /* '[' */(0x4E),
  206. /* '\' */(0x13),
  207. /* ']' */(0x78),
  208. /* '^' */(0x42),
  209. /* '_' */(0x01),
  210. };
  211. /*********************************************************************************
  212. **
  213. ** 7-Segement Driver: Low Level Communication
  214. **
  215. **/
  216. /*!
  217. * \brief Send 7seg command.
  218. *
  219. * \param node Specifies the SPI node.
  220. * \param addr Optional command parameter.
  221. * \param txbuf Pointer to the transmit data buffer, may be set to NULL.
  222. * \param rxbuf Pointer to the receive data buffer, may be set to NULL.
  223. * \param xlen Number of byte to receive and/or transmit.
  224. */
  225. static int disp7segCommand(NUTSPINODE * node, uint8_t addr, const void *txbuf, void *rxbuf, int xlen)
  226. {
  227. int rc = -1;
  228. NUTSPIBUS *bus;
  229. uint8_t *tmp;
  230. uint8_t cmd[2];
  231. NUTASSERT(node != NULL);
  232. bus = (NUTSPIBUS *) node->node_bus;
  233. NUTASSERT(bus != NULL);
  234. NUTASSERT(bus->bus_alloc != NULL);
  235. NUTASSERT(bus->bus_transfer != NULL);
  236. NUTASSERT(bus->bus_release != NULL);
  237. /* write address */
  238. cmd[0] = addr;
  239. tmp = (uint8_t *)txbuf;
  240. /* write data */
  241. cmd[1] = tmp[0];
  242. //cmd[1] = (uint8_t )txbuf[0];
  243. /* write data */
  244. rc = (*bus->bus_alloc) (node, 1000);
  245. if (rc == 0) {
  246. rc = (*bus->bus_transfer) (node, cmd, NULL, 2);
  247. (*bus->bus_release) (node);
  248. }
  249. return rc;
  250. }
  251. /*!
  252. * \brief Push display buffer to display.
  253. *
  254. * \param dev Display device.
  255. */
  256. void Spi7SegPush( NUTDEVICE * dev)
  257. {
  258. uint_fast8_t i;
  259. DCB_7SEG * dcb;
  260. NUTSPINODE *node;
  261. NUTASSERT(dev->dev_dcb != NULL);
  262. NUTASSERT(dev->dev_icb != NULL);
  263. dcb = dev->dev_dcb;
  264. node = dev->dev_icb;
  265. #ifdef SEG7_REVERSE
  266. NPRINTF("<");
  267. for (i=0;i<SEG7_DIGITS;i++)
  268. {
  269. /* Display is connected reverse... */
  270. disp7segCommand( node, SEG7_DIGITS-i, &(dcb->digit[i]), NULL, 1);
  271. NPRINTF(" %02x",dcb->digit[i]);
  272. }
  273. NPRINTF(">\n");
  274. #else
  275. disp7segCommand(node, 0, dcb->digit, NULL, SEG7_DIGITS);
  276. #endif
  277. }
  278. /*********************************************************************************
  279. **
  280. ** 7-Segement Driver: Character Driver
  281. **
  282. **/
  283. /*!
  284. * \brief Send single character to 7-Segment Display.
  285. *
  286. * A newline character will reset write pointer to digit 0.
  287. * Carriage return is ignored.
  288. *
  289. * \return Number of characters sent.
  290. */
  291. int Spi7segPutc(NUTDEVICE * dev, char c)
  292. {
  293. DCB_7SEG * dcb;
  294. NUTSPINODE *node;
  295. NUTASSERT(dev->dev_dcb != NULL);
  296. NUTASSERT(dev->dev_icb != NULL);
  297. dcb = dev->dev_dcb;
  298. node = dev->dev_icb;
  299. NPRINTF("[%c]", c);
  300. if( dcb->icmd & ICMD_ESCAPE) {
  301. dcb->icmd &= ~ICMD_ESCAPE;
  302. /* Handle ESC sequences */
  303. switch( c) {
  304. case 'b': /* blink slow */
  305. dcb->freg |= (SEGF_BLINK | SEGF_BLSLOW);
  306. disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
  307. return 0;
  308. break;
  309. case 'f': /* blink fast */
  310. dcb->freg &= ~SEGF_BLMASK;
  311. dcb->freg |= SEGF_BLINK ;
  312. disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
  313. return 0;
  314. break;
  315. case 'n': /* stop blinking */
  316. dcb->freg &= ~SEGF_BLMASK;
  317. disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
  318. return 0;
  319. break;
  320. case 'h': /* home */
  321. dcb->dip = 0;
  322. return 0;
  323. break;
  324. case 'c': /* clear */
  325. memset( dcb->digit, 0, SEG7_DIGITS);
  326. dcb->icmd |= ICMD_UPDATE;
  327. break;
  328. case 't': /* test, all digits on */
  329. memset( dcb->digit, 0xFF, SEG7_DIGITS);
  330. dcb->icmd |= ICMD_UPDATE;
  331. break;
  332. case 'i': /* intensity control */
  333. dcb->icmd |= ICMD_INTENS;
  334. return 0;
  335. break;
  336. default:
  337. break;
  338. }
  339. }
  340. else {
  341. /* Non-ESC Character incoming */
  342. /* Start ESC Sequence? */
  343. if( c == 0x1b) {
  344. dcb->icmd |= ICMD_ESCAPE;
  345. return 0;
  346. }
  347. /* Complete Intensity command */
  348. if( dcb->icmd & ICMD_INTENS) {
  349. dcb->icmd &= ~ICMD_INTENS;
  350. c = (c>'9')?(c-'A'+10):(c-'0');
  351. disp7segCommand( node, SEGR_INTENSITY, &c, NULL, 1);
  352. return 0;
  353. }
  354. if( c == '\n' ) { /* Return to Digit 0 */
  355. dcb->dip = 0;
  356. return 0;
  357. }
  358. /* Everything from here down, needs update of display */
  359. if( c == '.') {
  360. /* Add decimal point to previous digit */
  361. if( dcb->dip > 0) dcb->digit[dcb->dip-1] |= 0x80;
  362. dcb->icmd |= ICMD_UPDATE;
  363. }
  364. else if( (c >= ' ') && ( dcb->dip < SEG7_DIGITS)) {
  365. if( c > 0x5F) c -= 0x20; /* convert lower case to upper case */
  366. /* Print incoming character */
  367. dcb->digit[ dcb->dip++] = Seg7CharTab[(c&0xff)-' '];
  368. dcb->icmd |= ICMD_UPDATE;
  369. }
  370. }
  371. if( dcb->dip > SEG7_DIGITS) dcb->dip = SEG7_DIGITS;
  372. if( dcb->icmd & ICMD_UPDATE)
  373. {
  374. dcb->icmd &= ~ICMD_UPDATE;
  375. Spi7SegPush( dev);
  376. }
  377. return 0;
  378. }
  379. /*********************************************************************************
  380. **
  381. ** 7-Segement Driver: File Device Handling
  382. **
  383. **/
  384. /*!
  385. * \brief Handle I/O controls for 7-Segment Display.
  386. *
  387. * The 7-Seg Display is controlled by ESC-Sequences only.
  388. *
  389. * \return 0.
  390. */
  391. static int Spi7SegIOCtl(NUTDEVICE * dev, int req, void *conf)
  392. {
  393. return 0;
  394. }
  395. /*!
  396. * \brief Send characters to 7-Segment Display.
  397. *
  398. * A newline character will reset write pointer to digit 0.
  399. * Carriage return is ignored.
  400. *
  401. * \return Number of characters sent.
  402. */
  403. int Spi7segWrite(NUTFILE * fp, const void *buffer, int len)
  404. {
  405. int i=len;
  406. const char *cp = buffer;
  407. NUTASSERT(fp->nf_dev != NULL);
  408. while(i--)
  409. {
  410. Spi7segPutc( fp->nf_dev, *cp++);
  411. }
  412. return len;
  413. }
  414. /*!
  415. * \brief File Handle for 7-Sefgment Display.
  416. *
  417. * \param pos Selects the digit.
  418. * \param act Selects the action for the digits decimal dot.
  419. *
  420. */
  421. void Spi7segDot(NUTDEVICE * dev, uint8_t pos, uint8_t act)
  422. {
  423. DCB_7SEG * dcb;
  424. NUTASSERT(dev->dev_dcb != NULL);
  425. dcb = dev->dev_dcb;
  426. if( pos < SEG7_DIGITS)
  427. {
  428. switch( act)
  429. {
  430. case DOT_7SEG_FLIP: dcb->digit[pos] ^= 0x80; break;
  431. case DOT_7SEG_SET: dcb->digit[pos] |= 0x80; break;
  432. case DOT_7SEG_CLR: dcb->digit[pos] &= ~0x80; break;
  433. }
  434. Spi7SegPush( dev);
  435. }
  436. }
  437. /*!
  438. * \brief Generate File Handle for 7-Sefgment Display.
  439. *
  440. * \param dev Specifies the 7seg device.
  441. *
  442. * \return 0 on success or -1 if no valid 7seg was found.
  443. */
  444. NUTFILE *Spi7SegOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
  445. {
  446. NUTFILE *fp;
  447. NUTASSERT( dev != NULL);
  448. if ((fp = malloc(sizeof(NUTFILE))) == 0) {
  449. return NUTFILE_EOF;
  450. }
  451. fp->nf_dev = dev;
  452. fp->nf_fcb = NULL;
  453. return fp;
  454. }
  455. /*!
  456. * \brief Close 7-Segment Device.
  457. *
  458. * \return 0 if closed and was opened before, else -1.
  459. */
  460. static int Spi7SegClose(NUTFILE * fp)
  461. {
  462. if( fp != NULL) {
  463. free( fp);
  464. return 0;
  465. }
  466. return -1;
  467. }
  468. /*********************************************************************************
  469. **
  470. ** 7-Segement Driver: Initialization & Device Description
  471. **
  472. **/
  473. /*!
  474. * \brief Initialize the 7seg device.
  475. *
  476. * This routine determines the 7seg type. It is internally called
  477. * by Nut/OS during device registration.
  478. *
  479. * The driver framework may call this function more than once.
  480. *
  481. * \param dev Specifies the 7seg device.
  482. *
  483. * \return 0 on success or -1 if no valid 7seg was found.
  484. */
  485. int Spi7segInit(NUTDEVICE * dev)
  486. {
  487. uint8_t data;
  488. NUTSPINODE *node;
  489. DCB_7SEG * dcb;
  490. NUTASSERT(dev != NULL);
  491. NUTASSERT(dev->dev_icb != NULL);
  492. node = dev->dev_icb;
  493. /* Allocate device control block */
  494. dcb = malloc( sizeof( DCB_7SEG));
  495. if( dcb == NULL)
  496. return -1;
  497. memset( dcb, 0, sizeof( DCB_7SEG));
  498. dev->dev_dcb = dcb;
  499. NPRINTF("INIT %d Digits...\n", SEG7_DIGITS);
  500. data = TEST_MODE_OFF;
  501. disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
  502. disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
  503. disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
  504. data = NORM_OP_RESET;
  505. disp7segCommand(node, SEGR_SHUTDOWN, &data, NULL, 1);
  506. data = SEG7_DIGITS;
  507. disp7segCommand(node, SEGR_SCAN_LIM, &data, NULL, 1);
  508. dcb->freg = NO_DIG_DECODE;
  509. disp7segCommand(node, SEGR_DEC_MODE, &dcb->freg, NULL, 1);
  510. data = 0x0F;
  511. disp7segCommand(node, SEGR_INTENSITY, &data, NULL, 1);
  512. data = 0;
  513. disp7segCommand(node, SEGR_DIG0, &data, NULL, 1);
  514. disp7segCommand(node, SEGR_DIG1, &data, NULL, 1);
  515. disp7segCommand(node, SEGR_DIG2, &data, NULL, 1);
  516. return 0;
  517. }
  518. /*!
  519. * \brief 7seg SPI node implementation structure.
  520. */
  521. NUTSPINODE nodeSpi7SEG = {
  522. NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
  523. NULL, /*!< \brief Pointer to device driver specific settings, node_stat. */
  524. SPI_RATE_DISP_7SEG, /*!< \brief Initial clock rate, node_rate. */
  525. SPI_MODE_DISP_7SEG, /*!< \brief Initial mode, node_mode. */
  526. 8, /*!< \brief Initial data bits, node_bits. */
  527. 0 /*!< \brief Chip select, node_cs. */
  528. };
  529. /*!
  530. * \brief 7seg device implementation structure.
  531. */
  532. NUTDEVICE devSpi7SEG = {
  533. NULL, /*!< \brief Pointer to next device, dev_next. */
  534. {'7', 'S', 'E', 'G', 0, 0, 0}, /*!< \brief Unique device name, dev_name. */
  535. IFTYP_CHAR, /*!< \brief Type of device, dev_type. */
  536. 0, /*!< \brief Base address, dev_base (not used). */
  537. 0, /*!< \brief First interrupt number, dev_irq (not used). */
  538. &nodeSpi7SEG, /*!< \brief Interface control block, dev_icb. */
  539. 0, /*!< \brief Driver control block, dev_dcb. */
  540. Spi7segInit, /*!< \brief Driver initialization routine, dev_init. */
  541. Spi7SegIOCtl, /*!< \brief Driver specific control function, dev_ioctl. */
  542. 0, /*!< \brief Read from device, dev_read. */
  543. Spi7segWrite, /*!< \brief Write to device, dev_write. */
  544. #ifdef __HARVARD_ARCH__
  545. 0, /*!< \brief Write data from program space to device, dev_write_P. */
  546. #endif
  547. Spi7SegOpen, /*!< \brief Mount volume, dev_open. */
  548. Spi7SegClose, /*!< \brief Unmount volume, dev_close. */
  549. NULL, /*!< \brief Request file size, dev_size. */
  550. NULL, /*!< \brief Select function, optional, not yet implemented */
  551. };