| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- /*
- * Copyright (C) 2009 by Ulrich Prinz (uprinz2@netscape.net)
- * Copyright (C) 2009 by Rittal GmbH & Co. KG. All rights reserved.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * \file dev/spi_7seg.c
- * \brief Routines for 7 segment display.
- *
- * \verbatim
- * $Id: spi_7seg.c,$
- * \endverbatim
- */
- #include <cfg/os.h>
- #include <cfg/arch.h>
- //#include <cfg/board.h>
- #include <compiler.h>
- #include <string.h>
- #include <stdlib.h>
- #ifdef SPI2SEG_DEBUG
- #include <stdio.h>
- #define NPRINTF(args,...) printf(args,##__VA_ARGS__)
- #else
- #define NPRINTF(args,...)
- #endif
- #include <sys/nutdebug.h>
- #include <sys/timer.h>
- #include <stdio.h>
- #include <cfg/memory.h>
- #include <dev/blockdev.h>
- #include <cfg/spi_7seg.h>
- #include <dev/spi_7seg.h>
- #include <cfg/arch/gpio.h>
- #include <dev/spibus_at91.h>
- /* Number of used or connected digits */
- #ifndef SEG7_DIGITS
- #define SEG7_DIGITS 4
- #endif
- #define SEG7_REVERSE
- /* AS1106/7/8 Register Abbreviations */
- #define SEGR_NOOP 0x00
- #define SEGR_DIG0 0x01
- #define SEGR_DIG1 0x02
- #define SEGR_DIG2 0x03
- #define SEGR_DIG3 0x04
- #define SEGR_DIG4 0x05
- #define SEGR_DIG5 0x06
- #define SEGR_DIG6 0x07
- #define SEGR_DIG7 0x08
- #define SEGR_DEC_MODE 0x09
- #define SEGR_INTENSITY 0x0a
- #define SEGR_SCAN_LIM 0x0b
- #define SEGR_SHUTDOWN 0x0c
- #define SEGR_FEATURE 0x0e
- #define SEGR_DSP_TEST 0x0f
- /* Shutdown Register (0x0c) */
- #define SHUTDOWN_RESET 0x00
- #define SHUTDOWN_SOFT 0x80
- #define NORM_OP_RESET 0x01
- #define NORM_OP_SOFT 0x81
- /* Decode Mode Register (0x09) */
- #define NO_DIG_DECODE 0x00
- #define DIG_0_DECODE 0x01
- #define DIG_0_3_DECODE 0x0f
- #define DIG_0_7_DECODE 0xff
- /* feature register (0x0e) */
- #define SEGF_EXTCLK 0x01
- #define SEGF_REGRES 0x02
- #define SEGF_DECSEL 0x04
- #define SEGF_SPIEN 0x08
- #define SEGF_BLINK 0x10
- #define SEGF_BLSLOW 0x20
- #define SEGF_BLSYNC 0x40
- #define SEGF_BLSTART 0x80
- #define SEGF_BLMASK (SEGF_BLINK|SEGF_BLSLOW)
- /* Test Mode register (0x0f) */
- #define TEST_MODE_OFF 0x00
- #define TEST_MODE_ON 0x01
- /* scan limit register (0x0b) */
- #define DISPLAY_LIMIT 2
- #ifndef SPI_RATE_DISP_7SEG
- #define SPI_RATE_DISP_7SEG 400000
- #endif
- #ifndef SPI_MODE_DISP_7SEG
- #define SPI_MODE_DISP_7SEG SPI_MODE_3
- #endif
- /* Bitmask for driver control */
- #define ICMD_UPDATE 0x01
- #define ICMD_INTENS 0x02
- #define ICMD_ESCAPE 0x80
- /*!
- * \brief Device Control Block for 7-Segment Display
- */
- typedef struct {
- uint_fast8_t digit[SEG7_DIGITS]; /*!< Buffer for Display content */
- uint_fast8_t dip; /*!< Actual cursor position */
- uint_fast8_t freg; /*!< mirror of internal feature control register */
- uint_fast8_t icmd; /*!< internal driver control register */
- } DCB_7SEG;
- /*********************************************************************************
- **
- ** 7-Segement Driver: Character Table
- **
- **/
- /* Display Interconnection
- *
- * --A--
- * | |
- * F B Bit: 7 6 5 4 3 2 1 0
- * +--G--+ Led: dp A B C D E F G
- * E C
- * | |
- * --D-- dp
- */
- /* 7 Segment Display Character Table */
- static const uint8_t Seg7CharTab[] = {
- /* ' ' */(0x00),
- /* '!' */(0x28),
- /* '"' */(0x22),
- /* '#' */(0x00),
- /* '$' */(0x5B),
- /* '%' */(0x00),
- /* '&' */(0x6F),
- /* '´' */(0x20),
- /* '(' */(0x4E),
- /* ')' */(0x78),
- /* '*' */(0x00),
- /* '+' */(0x31),
- /* ''' */(0x20),
- /* '-' */(0x01),
- /* '.' */(0x01),
- /* '/' */(0x15),
- /* '0' */(0x7E),
- /* '1' */(0x30),
- /* '2' */(0x6D),
- /* '3' */(0x79),
- /* '4' */(0x33),
- /* '5' */(0x5B),
- /* '6' */(0x5F),
- /* '7' */(0x70),
- /* '8' */(0x7F),
- /* '9' */(0x7B),
- /* ':' */(0x00),
- /* ';' */(0x00),
- /* '<' */(0x00),
- /* '=' */(0x09),
- /* '>' */(0x00),
- /* '?' */(0x65),
- /* '@' */(0x00),
- /* 'A' */(0x77),
- /* 'b' */(0x1F),
- /* 'c' */(0x0D),
- /* 'd' */(0x3D),
- /* 'E' */(0x4F),
- /* 'F' */(0x47),
- /* 'G' */(0x5F),
- /* 'H' */(0x37),
- /* 'i' */(0x10),
- /* 'J' */(0x3C),
- /* 'K' */(0x0F),
- /* 'L' */(0x0E),
- /* 'M' */(0x76),
- /* 'N' */(0x15),
- /* 'O' */(0x1D),
- /* 'P' */(0x67),
- /* 'Q' */(0x73),
- /* 'R' */(0x05),
- /* 'S' */(0x5B),
- /* 'T' */(0x0F),
- /* 'U' */(0x3E),
- /* 'V' */(0x1C),
- /* 'W' */(0x3F),
- /* 'X' */(0x37),
- /* 'Y' */(0x3B),
- /* 'Z' */(0x6D),
- /* '[' */(0x4E),
- /* '\' */(0x13),
- /* ']' */(0x78),
- /* '^' */(0x42),
- /* '_' */(0x01),
- };
- /*********************************************************************************
- **
- ** 7-Segement Driver: Low Level Communication
- **
- **/
- /*!
- * \brief Send 7seg command.
- *
- * \param node Specifies the SPI node.
- * \param addr Optional command parameter.
- * \param txbuf Pointer to the transmit data buffer, may be set to NULL.
- * \param rxbuf Pointer to the receive data buffer, may be set to NULL.
- * \param xlen Number of byte to receive and/or transmit.
- */
- static int disp7segCommand(NUTSPINODE * node, uint8_t addr, const void *txbuf, void *rxbuf, int xlen)
- {
- int rc = -1;
- NUTSPIBUS *bus;
- uint8_t *tmp;
- uint8_t cmd[2];
- NUTASSERT(node != NULL);
- bus = (NUTSPIBUS *) node->node_bus;
- NUTASSERT(bus != NULL);
- NUTASSERT(bus->bus_alloc != NULL);
- NUTASSERT(bus->bus_transfer != NULL);
- NUTASSERT(bus->bus_release != NULL);
- /* write address */
- cmd[0] = addr;
- tmp = (uint8_t *)txbuf;
- /* write data */
- cmd[1] = tmp[0];
- //cmd[1] = (uint8_t )txbuf[0];
- /* write data */
- rc = (*bus->bus_alloc) (node, 1000);
- if (rc == 0) {
- rc = (*bus->bus_transfer) (node, cmd, NULL, 2);
- (*bus->bus_release) (node);
- }
- return rc;
- }
- /*!
- * \brief Push display buffer to display.
- *
- * \param dev Display device.
- */
- void Spi7SegPush( NUTDEVICE * dev)
- {
- uint_fast8_t i;
- DCB_7SEG * dcb;
- NUTSPINODE *node;
- NUTASSERT(dev->dev_dcb != NULL);
- NUTASSERT(dev->dev_icb != NULL);
- dcb = dev->dev_dcb;
- node = dev->dev_icb;
- #ifdef SEG7_REVERSE
- NPRINTF("<");
- for (i=0;i<SEG7_DIGITS;i++)
- {
- /* Display is connected reverse... */
- disp7segCommand( node, SEG7_DIGITS-i, &(dcb->digit[i]), NULL, 1);
- NPRINTF(" %02x",dcb->digit[i]);
- }
- NPRINTF(">\n");
- #else
- disp7segCommand(node, 0, dcb->digit, NULL, SEG7_DIGITS);
- #endif
- }
- /*********************************************************************************
- **
- ** 7-Segement Driver: Character Driver
- **
- **/
- /*!
- * \brief Send single character to 7-Segment Display.
- *
- * A newline character will reset write pointer to digit 0.
- * Carriage return is ignored.
- *
- * \return Number of characters sent.
- */
- int Spi7segPutc(NUTDEVICE * dev, char c)
- {
- DCB_7SEG * dcb;
- NUTSPINODE *node;
- NUTASSERT(dev->dev_dcb != NULL);
- NUTASSERT(dev->dev_icb != NULL);
- dcb = dev->dev_dcb;
- node = dev->dev_icb;
- NPRINTF("[%c]", c);
- if( dcb->icmd & ICMD_ESCAPE) {
- dcb->icmd &= ~ICMD_ESCAPE;
- /* Handle ESC sequences */
- switch( c) {
- case 'b': /* blink slow */
- dcb->freg |= (SEGF_BLINK | SEGF_BLSLOW);
- disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
- return 0;
- break;
- case 'f': /* blink fast */
- dcb->freg &= ~SEGF_BLMASK;
- dcb->freg |= SEGF_BLINK ;
- disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
- return 0;
- break;
- case 'n': /* stop blinking */
- dcb->freg &= ~SEGF_BLMASK;
- disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
- return 0;
- break;
- case 'h': /* home */
- dcb->dip = 0;
- return 0;
- break;
- case 'c': /* clear */
- memset( dcb->digit, 0, SEG7_DIGITS);
- dcb->icmd |= ICMD_UPDATE;
- break;
- case 't': /* test, all digits on */
- memset( dcb->digit, 0xFF, SEG7_DIGITS);
- dcb->icmd |= ICMD_UPDATE;
- break;
- case 'i': /* intensity control */
- dcb->icmd |= ICMD_INTENS;
- return 0;
- break;
- default:
- break;
- }
- }
- else {
- /* Non-ESC Character incoming */
- /* Start ESC Sequence? */
- if( c == 0x1b) {
- dcb->icmd |= ICMD_ESCAPE;
- return 0;
- }
- /* Complete Intensity command */
- if( dcb->icmd & ICMD_INTENS) {
- dcb->icmd &= ~ICMD_INTENS;
- c = (c>'9')?(c-'A'+10):(c-'0');
- disp7segCommand( node, SEGR_INTENSITY, &c, NULL, 1);
- return 0;
- }
- if( c == '\n' ) { /* Return to Digit 0 */
- dcb->dip = 0;
- return 0;
- }
- /* Everything from here down, needs update of display */
- if( c == '.') {
- /* Add decimal point to previous digit */
- if( dcb->dip > 0) dcb->digit[dcb->dip-1] |= 0x80;
- dcb->icmd |= ICMD_UPDATE;
- }
- else if( (c >= ' ') && ( dcb->dip < SEG7_DIGITS)) {
- if( c > 0x5F) c -= 0x20; /* convert lower case to upper case */
- /* Print incoming character */
- dcb->digit[ dcb->dip++] = Seg7CharTab[(c&0xff)-' '];
- dcb->icmd |= ICMD_UPDATE;
- }
- }
- if( dcb->dip > SEG7_DIGITS) dcb->dip = SEG7_DIGITS;
- if( dcb->icmd & ICMD_UPDATE)
- {
- dcb->icmd &= ~ICMD_UPDATE;
- Spi7SegPush( dev);
- }
- return 0;
- }
- /*********************************************************************************
- **
- ** 7-Segement Driver: File Device Handling
- **
- **/
- /*!
- * \brief Handle I/O controls for 7-Segment Display.
- *
- * The 7-Seg Display is controlled by ESC-Sequences only.
- *
- * \return 0.
- */
- static int Spi7SegIOCtl(NUTDEVICE * dev, int req, void *conf)
- {
- return 0;
- }
- /*!
- * \brief Send characters to 7-Segment Display.
- *
- * A newline character will reset write pointer to digit 0.
- * Carriage return is ignored.
- *
- * \return Number of characters sent.
- */
- int Spi7segWrite(NUTFILE * fp, const void *buffer, int len)
- {
- int i=len;
- const char *cp = buffer;
- NUTASSERT(fp->nf_dev != NULL);
- while(i--)
- {
- Spi7segPutc( fp->nf_dev, *cp++);
- }
- return len;
- }
- /*!
- * \brief File Handle for 7-Sefgment Display.
- *
- * \param pos Selects the digit.
- * \param act Selects the action for the digits decimal dot.
- *
- */
- void Spi7segDot(NUTDEVICE * dev, uint8_t pos, uint8_t act)
- {
- DCB_7SEG * dcb;
- NUTASSERT(dev->dev_dcb != NULL);
- dcb = dev->dev_dcb;
- if( pos < SEG7_DIGITS)
- {
- switch( act)
- {
- case DOT_7SEG_FLIP: dcb->digit[pos] ^= 0x80; break;
- case DOT_7SEG_SET: dcb->digit[pos] |= 0x80; break;
- case DOT_7SEG_CLR: dcb->digit[pos] &= ~0x80; break;
- }
- Spi7SegPush( dev);
- }
- }
- /*!
- * \brief Generate File Handle for 7-Sefgment Display.
- *
- * \param dev Specifies the 7seg device.
- *
- * \return 0 on success or -1 if no valid 7seg was found.
- */
- NUTFILE *Spi7SegOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
- {
- NUTFILE *fp;
- NUTASSERT( dev != NULL);
- if ((fp = malloc(sizeof(NUTFILE))) == 0) {
- return NUTFILE_EOF;
- }
- fp->nf_dev = dev;
- fp->nf_fcb = NULL;
- return fp;
- }
- /*!
- * \brief Close 7-Segment Device.
- *
- * \return 0 if closed and was opened before, else -1.
- */
- static int Spi7SegClose(NUTFILE * fp)
- {
- if( fp != NULL) {
- free( fp);
- return 0;
- }
- return -1;
- }
- /*********************************************************************************
- **
- ** 7-Segement Driver: Initialization & Device Description
- **
- **/
- /*!
- * \brief Initialize the 7seg device.
- *
- * This routine determines the 7seg type. It is internally called
- * by Nut/OS during device registration.
- *
- * The driver framework may call this function more than once.
- *
- * \param dev Specifies the 7seg device.
- *
- * \return 0 on success or -1 if no valid 7seg was found.
- */
- int Spi7segInit(NUTDEVICE * dev)
- {
- uint8_t data;
- NUTSPINODE *node;
- DCB_7SEG * dcb;
- NUTASSERT(dev != NULL);
- NUTASSERT(dev->dev_icb != NULL);
- node = dev->dev_icb;
- /* Allocate device control block */
- dcb = malloc( sizeof( DCB_7SEG));
- if( dcb == NULL)
- return -1;
- memset( dcb, 0, sizeof( DCB_7SEG));
- dev->dev_dcb = dcb;
- NPRINTF("INIT %d Digits...\n", SEG7_DIGITS);
- data = TEST_MODE_OFF;
- disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
- disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
- disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
- data = NORM_OP_RESET;
- disp7segCommand(node, SEGR_SHUTDOWN, &data, NULL, 1);
- data = SEG7_DIGITS;
- disp7segCommand(node, SEGR_SCAN_LIM, &data, NULL, 1);
- dcb->freg = NO_DIG_DECODE;
- disp7segCommand(node, SEGR_DEC_MODE, &dcb->freg, NULL, 1);
- data = 0x0F;
- disp7segCommand(node, SEGR_INTENSITY, &data, NULL, 1);
- data = 0;
- disp7segCommand(node, SEGR_DIG0, &data, NULL, 1);
- disp7segCommand(node, SEGR_DIG1, &data, NULL, 1);
- disp7segCommand(node, SEGR_DIG2, &data, NULL, 1);
- return 0;
- }
- /*!
- * \brief 7seg SPI node implementation structure.
- */
- NUTSPINODE nodeSpi7SEG = {
- NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
- NULL, /*!< \brief Pointer to device driver specific settings, node_stat. */
- SPI_RATE_DISP_7SEG, /*!< \brief Initial clock rate, node_rate. */
- SPI_MODE_DISP_7SEG, /*!< \brief Initial mode, node_mode. */
- 8, /*!< \brief Initial data bits, node_bits. */
- 0 /*!< \brief Chip select, node_cs. */
- };
- /*!
- * \brief 7seg device implementation structure.
- */
- NUTDEVICE devSpi7SEG = {
- NULL, /*!< \brief Pointer to next device, dev_next. */
- {'7', 'S', 'E', 'G', 0, 0, 0}, /*!< \brief Unique device name, dev_name. */
- IFTYP_CHAR, /*!< \brief Type of device, dev_type. */
- 0, /*!< \brief Base address, dev_base (not used). */
- 0, /*!< \brief First interrupt number, dev_irq (not used). */
- &nodeSpi7SEG, /*!< \brief Interface control block, dev_icb. */
- 0, /*!< \brief Driver control block, dev_dcb. */
- Spi7segInit, /*!< \brief Driver initialization routine, dev_init. */
- Spi7SegIOCtl, /*!< \brief Driver specific control function, dev_ioctl. */
- 0, /*!< \brief Read from device, dev_read. */
- Spi7segWrite, /*!< \brief Write to device, dev_write. */
- #ifdef __HARVARD_ARCH__
- 0, /*!< \brief Write data from program space to device, dev_write_P. */
- #endif
- Spi7SegOpen, /*!< \brief Mount volume, dev_open. */
- Spi7SegClose, /*!< \brief Unmount volume, dev_close. */
- NULL, /*!< \brief Request file size, dev_size. */
- NULL, /*!< \brief Select function, optional, not yet implemented */
- };
|