spi_7seg.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 by Ulrich Prinz (uprinz2@netscape.net)
00003  * Copyright (C) 2009 by Rittal GmbH & Co. KG. All rights reserved.
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  */
00035 
00044 //#define SPI2SEG_DEBUG
00045 
00046 #include <cfg/os.h>
00047 #include <cfg/arch.h>
00048 //#include <cfg/board.h>
00049 #include <compiler.h>
00050 #include <string.h>
00051 #include <stdlib.h>
00052 
00053 #ifdef SPI2SEG_DEBUG
00054 #include <stdio.h>
00055 #define NPRINTF(args,...) printf(args,##__VA_ARGS__)
00056 #else
00057 #define NPRINTF(args,...)
00058 #endif
00059 
00060 
00061 #include <sys/nutdebug.h>
00062 #include <sys/timer.h>
00063 
00064 #include <stdio.h>
00065 
00066 #include <cfg/memory.h>
00067 
00068 #include <dev/blockdev.h>
00069 #include <cfg/spi_7seg.h>
00070 #include <dev/spi_7seg.h>
00071 
00072 #include <cfg/arch/gpio.h>
00073 #include <dev/spibus_at91.h>
00074 
00075 /* Number of used or connected digits */
00076 #ifndef SEG7_DIGITS
00077 #define SEG7_DIGITS 4
00078 #endif
00079 
00080 #define SEG7_REVERSE
00081 
00082 /* AS1108 Register Abbreviations */
00083 #define SEGR_NOOP       0x00
00084 #define SEGR_DIG0       0x01
00085 #define SEGR_DIG1       0x02
00086 #define SEGR_DIG2       0x03
00087 #define SEGR_DIG3       0x04
00088 #define SEGR_DIG4       0x05
00089 #define SEGR_DIG5       0x06
00090 #define SEGR_DIG6       0x07
00091 #define SEGR_DIG7       0x08
00092 
00093 #define SEGR_DEC_MODE   0x09
00094 #define SEGR_INTENSITY  0x0a
00095 #define SEGR_SCAN_LIM   0x0b
00096 #define SEGR_SHUTDOWN   0x0c
00097 #define SEGR_FEATURE    0x0e
00098 #define SEGR_DSP_TEST   0x0f
00099 
00100 /* Shutdown Register (0x0c) */
00101 #define SHUTDOWN_RESET  0x00
00102 #define SHUTDOWN_SOFT   0x80
00103 #define NORM_OP_RESET   0x01
00104 #define NORM_OP_SOFT    0x81
00105 
00106 /* Decode Mode Register (0x09) */
00107 #define NO_DIG_DECODE   0x00
00108 #define DIG_0_DECODE    0x01
00109 #define DIG_0_3_DECODE  0x0f
00110 #define DIG_0_7_DECODE  0xff
00111 
00112 /* feature register (0x0e) */
00113 #define SEGF_EXTCLK     0x01
00114 #define SEGF_REGRES     0x02
00115 #define SEGF_DECSEL     0x04
00116 #define SEGF_SPIEN      0x08
00117 #define SEGF_BLINK      0x10
00118 #define SEGF_BLSLOW     0x20
00119 #define SEGF_BLSYNC     0x40
00120 #define SEGF_BLSTART    0x80
00121 
00122 #define SEGF_BLMASK     (SEGF_BLINK|SEGF_BLSLOW)
00123 
00124 /* Test Mode register (0x0f) */
00125 #define TEST_MODE_OFF   0x00
00126 #define TEST_MODE_ON    0x01
00127 
00128 /* scan limit register (0x0b) */
00129 #define DISPLAY_LIMIT   2
00130 
00131 #ifndef SPI_RATE_DISP_7SEG
00132 #define SPI_RATE_DISP_7SEG  400000
00133 #endif
00134 
00135 #ifndef SPI_MODE_DISP_7SEG
00136 #define SPI_MODE_DISP_7SEG SPI_MODE_3
00137 #endif
00138 
00139 /* Bitmask for driver control */
00140 #define ICMD_UPDATE     0x01
00141 #define ICMD_INTENS     0x02
00142 #define ICMD_ESCAPE     0x80
00143 
00147 typedef struct {
00148     uint_fast8_t  digit[SEG7_DIGITS]; 
00149     uint_fast8_t  dip;        
00150     uint_fast8_t  freg;      
00151     uint_fast8_t  icmd;      
00152 } DCB_7SEG;
00153 
00154 /*********************************************************************************
00155  **
00156  **         7-Segement Driver: Character Table
00157  **
00158  **/
00159 
00160 /* Display Interconnection
00161  *
00162  *      --A--
00163  *     |     |
00164  *     F     B      Bit:  7 6 5 4 3 2 1 0
00165  *     +--G--+      Led: dp A B C D E F G
00166  *     E     C
00167  *     |     |
00168  *      --D--  dp
00169  */
00170 /* 7 Segment Display Character Table */
00171 static CONST uint8_t Seg7CharTab[] = {
00172     /* ' ' */(0x00),
00173     /* '!' */(0x28),
00174     /* '"' */(0x22),
00175     /* '#' */(0x00),
00176     /* '$' */(0x5B),
00177     /* '%' */(0x00),
00178     /* '&' */(0x6F),
00179     /* '´' */(0x20),
00180     /* '(' */(0x4E),
00181     /* ')' */(0x78),
00182     /* '*' */(0x00),
00183     /* '+' */(0x31),
00184     /* ''' */(0x20),
00185     /* '-' */(0x01),
00186     /* '.' */(0x01),
00187     /* '/' */(0x15),
00188     /* '0' */(0x7E),
00189     /* '1' */(0x30),
00190     /* '2' */(0x6D),
00191     /* '3' */(0x79),
00192     /* '4' */(0x33),
00193     /* '5' */(0x5B),
00194     /* '6' */(0x5F),
00195     /* '7' */(0x70),
00196     /* '8' */(0x7F),
00197     /* '9' */(0x7B),
00198     /* ':' */(0x00),
00199     /* ';' */(0x00),
00200     /* '<' */(0x00),
00201     /* '=' */(0x09),
00202     /* '>' */(0x00),
00203     /* '?' */(0x65),
00204     /* '@' */(0x00),
00205     /* 'A' */(0x77),
00206     /* 'b' */(0x1F),
00207     /* 'c' */(0x0D),
00208     /* 'd' */(0x3D),
00209     /* 'E' */(0x4F),
00210     /* 'F' */(0x47),
00211     /* 'G' */(0x5F),
00212     /* 'H' */(0x37),
00213     /* 'i' */(0x10),
00214     /* 'J' */(0x3C),
00215     /* 'K' */(0x0F),
00216     /* 'L' */(0x0E),
00217     /* 'M' */(0x76),
00218     /* 'N' */(0x15),
00219     /* 'O' */(0x1D),
00220     /* 'P' */(0x67),
00221     /* 'Q' */(0x73),
00222     /* 'R' */(0x05),
00223     /* 'S' */(0x5B),
00224     /* 'T' */(0x0F),
00225     /* 'U' */(0x3E),
00226     /* 'V' */(0x1C),
00227     /* 'W' */(0x3F),
00228     /* 'X' */(0x37),
00229     /* 'Y' */(0x3B),
00230     /* 'Z' */(0x6D),
00231     /* '[' */(0x4E),
00232     /* '\' */(0x13),
00233     /* ']' */(0x78),
00234     /* '^' */(0x42),
00235     /* '_' */(0x01),
00236 };
00237 
00238 /*********************************************************************************
00239  **
00240  **         7-Segement Driver: Low Level Communication
00241  **
00242  **/
00243 
00253 static int disp7segCommand(NUTSPINODE * node, uint8_t addr, CONST void *txbuf, void *rxbuf, int xlen)
00254 {
00255     int rc = -1;
00256     NUTSPIBUS *bus;
00257     uint8_t *tmp;
00258     uint8_t cmd[2];
00259 
00260     NUTASSERT(node != NULL);
00261     bus = (NUTSPIBUS *) node->node_bus;
00262     NUTASSERT(bus != NULL);
00263     NUTASSERT(bus->bus_alloc != NULL);
00264     NUTASSERT(bus->bus_transfer != NULL);
00265     NUTASSERT(bus->bus_release != NULL);
00266 
00267     /* write address */
00268      cmd[0] = addr;
00269 
00270     tmp = (uint8_t *)txbuf;
00271     /* write data */
00272      cmd[1] = tmp[0];
00273     //cmd[1] = (uint8_t )txbuf[0];
00274     /* write data */
00275     rc = (*bus->bus_alloc) (node, 1000);
00276     if (rc == 0) {
00277         rc = (*bus->bus_transfer) (node, cmd, NULL, 2);
00278 
00279         (*bus->bus_release) (node);
00280     }
00281     return rc;
00282 }
00283 
00289 void Spi7SegPush( NUTDEVICE * dev)
00290 {
00291     uint_fast8_t i;
00292     DCB_7SEG * dcb;
00293     NUTSPINODE *node;
00294 
00295     NUTASSERT(dev->dev_dcb != NULL);
00296     NUTASSERT(dev->dev_icb != NULL);
00297 
00298     dcb  = dev->dev_dcb;
00299     node = dev->dev_icb;
00300 
00301 #ifdef SEG7_REVERSE
00302     NPRINTF("<");
00303     for (i=0;i<SEG7_DIGITS;i++)
00304     {
00305         /* Display is connected reverse... */
00306         disp7segCommand( node, SEG7_DIGITS-i, &(dcb->digit[i]), NULL, 1);
00307         NPRINTF(" %02x",dcb->digit[i]);
00308     }
00309     NPRINTF(">\n");
00310 #else
00311     disp7segCommand(node, 0, dcb->digit, NULL, SEG7_DIGITS);
00312 #endif
00313 }
00314 
00315 /*********************************************************************************
00316  **
00317  **         7-Segement Driver: Character Driver
00318  **
00319  **/
00320 
00329 int Spi7segPutc(NUTDEVICE * dev, char c)
00330 {
00331     DCB_7SEG * dcb;
00332     NUTSPINODE *node;
00333 
00334     NUTASSERT(dev->dev_dcb != NULL);
00335     NUTASSERT(dev->dev_icb != NULL);
00336 
00337     dcb  = dev->dev_dcb;
00338     node = dev->dev_icb;
00339 
00340     NPRINTF("[%c]", c);
00341 
00342     if( dcb->icmd & ICMD_ESCAPE) {
00343 
00344         dcb->icmd &= ~ICMD_ESCAPE;
00345         /* Handle ESC sequences */
00346         switch( c) {
00347             case 'b':       /* blink slow */
00348                 dcb->freg |= (SEGF_BLINK | SEGF_BLSLOW);
00349                 disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
00350                 return 0;
00351                 break;
00352             case 'f':       /* blink fast */
00353                 dcb->freg &= ~SEGF_BLMASK;
00354                 dcb->freg |= SEGF_BLINK ;
00355                 disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
00356                 return 0;
00357                 break;
00358             case 'n':       /* stop blinking */
00359                 dcb->freg &= ~SEGF_BLMASK;
00360                 disp7segCommand( node, SEGR_FEATURE, &dcb->freg, NULL, 1);
00361                 return 0;
00362                 break;
00363             case 'h':       /* home */
00364                 dcb->dip = 0;
00365                 return 0;
00366                 break;
00367             case 'c':       /* clear */
00368                 memset( dcb->digit, 0, SEG7_DIGITS);
00369                 dcb->icmd |= ICMD_UPDATE;
00370                 break;
00371             case 't':       /* test, all digits on */
00372                 memset( dcb->digit, 0xFF, SEG7_DIGITS);
00373                 dcb->icmd |= ICMD_UPDATE;
00374                 break;
00375             case 'i':       /* intensity control */
00376                 dcb->icmd |= ICMD_INTENS;
00377                 return 0;
00378                 break;
00379             default:
00380                 break;
00381         }
00382 
00383     }
00384     else {
00385         /* Non-ESC Character incoming */
00386 
00387         /* Start ESC Sequence? */
00388         if( c == 0x1b) {
00389             dcb->icmd |= ICMD_ESCAPE;
00390             return 0;
00391         }
00392 
00393         /* Complete Intensity command */
00394         if( dcb->icmd & ICMD_INTENS) {
00395             dcb->icmd &= ~ICMD_INTENS;
00396             c = (c>'9')?(c-'A'+10):(c-'0');
00397             disp7segCommand( node, SEGR_INTENSITY, &c, NULL, 1);
00398             return 0;
00399         }
00400 
00401         if( c == '\n' ) {  /* Return to Digit 0 */
00402             dcb->dip = 0;
00403             return 0;
00404         }
00405 
00406         /* Everything from here down, needs update of display */
00407 
00408         if( c == '.') {
00409             /* Add decimal point to previous digit */
00410             if( dcb->dip > 0) dcb->digit[dcb->dip-1] |= 0x80;
00411             dcb->icmd |= ICMD_UPDATE;
00412         }
00413         else if( (c >= ' ') && ( dcb->dip < SEG7_DIGITS)) {
00414             if( c > 0x5F) c -= 0x20;  /* convert lower case to upper case */
00415             /* Print incoming character */
00416             dcb->digit[ dcb->dip++] = Seg7CharTab[(c&0xff)-' '];
00417             dcb->icmd |= ICMD_UPDATE;
00418         }
00419     }
00420 
00421     if( dcb->dip > SEG7_DIGITS) dcb->dip = SEG7_DIGITS;
00422 
00423     if( dcb->icmd & ICMD_UPDATE)
00424     {
00425         dcb->icmd &= ~ICMD_UPDATE;
00426         Spi7SegPush( dev);
00427     }
00428         return 0;
00429 }
00430 
00431 /*********************************************************************************
00432  **
00433  **         7-Segement Driver: File Device Handling
00434  **
00435  **/
00436 
00444 static int Spi7SegIOCtl(NUTDEVICE * dev, int req, void *conf)
00445 {
00446     return 0;
00447 }
00448 
00457 int Spi7segWrite(NUTFILE * fp, CONST void *buffer, int len)
00458 {
00459     int i=len;
00460     CONST char *cp = buffer;
00461 
00462     NUTASSERT(fp->nf_dev != NULL);
00463 
00464     while(i--)
00465     {
00466         Spi7segPutc( fp->nf_dev, *cp++);
00467     }
00468     return len;
00469 }
00470 
00478 void Spi7segDot(NUTDEVICE * dev, uint8_t pos, uint8_t act)
00479 {
00480     DCB_7SEG * dcb;
00481     NUTSPINODE *node;
00482 
00483     NUTASSERT(dev->dev_dcb != NULL);
00484     NUTASSERT(dev->dev_icb != NULL);
00485 
00486     dcb  = dev->dev_dcb;
00487     node = dev->dev_icb;
00488 
00489     if( pos < SEG7_DIGITS)
00490     {
00491         switch( act)
00492         {
00493             case DOT_7SEG_FLIP: dcb->digit[pos] ^= 0x80; break;
00494             case DOT_7SEG_SET:  dcb->digit[pos] |= 0x80; break;
00495             case DOT_7SEG_CLR:  dcb->digit[pos] &= ~0x80; break;
00496         }
00497         Spi7SegPush( dev);
00498     }
00499 
00500 }
00501 
00509 NUTFILE *Spi7SegOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00510 {
00511     NUTFILE *fp;
00512 
00513     NUTASSERT( dev != NULL);
00514 
00515     if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00516         return NUTFILE_EOF;
00517     }
00518 
00519     fp->nf_fcb = 0;
00520     fp->nf_dev = dev;
00521     fp->nf_next = 0;
00522 
00523     return fp;
00524 
00525 }
00526 
00532 static int Spi7SegClose(NUTFILE * fp)
00533 {
00534     if( fp != NULL) {
00535         free( fp);
00536         return 0;
00537     }
00538     return -1;
00539 }
00540 
00541 /*********************************************************************************
00542  **
00543  **         7-Segement Driver: Initialization & Device Description
00544  **
00545  **/
00546 
00559 int Spi7segInit(NUTDEVICE * dev)
00560 {
00561     uint8_t data;
00562     NUTSPINODE *node;
00563     DCB_7SEG * dcb;
00564 
00565     NUTASSERT(dev != NULL);
00566     NUTASSERT(dev->dev_icb != NULL);
00567     node = dev->dev_icb;
00568 
00569     /* Allocate device control block */
00570     dcb = malloc( sizeof( DCB_7SEG));
00571     if( dcb == NULL)
00572         return -1;
00573     memset( dcb, 0, sizeof( DCB_7SEG));
00574     dev->dev_dcb = dcb;
00575 
00576     NPRINTF("INIT %d Digits...\n", SEG7_DIGITS);
00577 
00578     data = TEST_MODE_OFF;
00579     disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
00580     disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
00581     disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
00582 
00583     data = NORM_OP_RESET;
00584     disp7segCommand(node, SEGR_SHUTDOWN, &data, NULL, 1);
00585 
00586     data = SEG7_DIGITS;
00587     disp7segCommand(node, SEGR_SCAN_LIM, &data, NULL, 1);
00588 
00589     dcb->freg = NO_DIG_DECODE;
00590     disp7segCommand(node, SEGR_DEC_MODE, &dcb->freg, NULL, 1);
00591 
00592     data = 0x0F;
00593     disp7segCommand(node, SEGR_INTENSITY, &data, NULL, 1);
00594 
00595     data = 0;
00596     disp7segCommand(node, SEGR_DIG0, &data, NULL, 1);
00597     disp7segCommand(node, SEGR_DIG1, &data, NULL, 1);
00598     disp7segCommand(node, SEGR_DIG2, &data, NULL, 1);
00599 
00600     return 0;
00601 
00602 }
00603 
00607 NUTSPINODE nodeSpi7SEG = {
00608     NULL,                   
00609     NULL,                   
00610     SPI_RATE_DISP_7SEG,     
00611     SPI_MODE_DISP_7SEG,     
00612     8,                      
00613     0                       
00614 };
00615 
00619 NUTDEVICE devSpi7SEG = {
00620     NULL,                           
00621     {'7', 'S', 'E', 'G', 0, 0, 0},  
00622     IFTYP_CHAR,                     
00623     0,                              
00624     0,                              
00625     &nodeSpi7SEG,                   
00626     0,                              
00627     Spi7segInit,                    
00628     Spi7SegIOCtl,                   
00629     0,                              
00630     Spi7segWrite,                   
00631 #ifdef __HARVARD_ARCH__
00632     0,                              
00633 #endif
00634     Spi7SegOpen,                    
00635     Spi7SegClose,                   
00636     0                               
00637 };
00638 

© 2000-2010 by contributors - visit http://www.ethernut.de/