Nut/OS  4.10.3
API Reference
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 
00482     NUTASSERT(dev->dev_dcb != NULL);
00483 
00484     dcb  = dev->dev_dcb;
00485 
00486         if( pos < SEG7_DIGITS)
00487         {
00488                 switch( act)
00489                 {
00490                         case DOT_7SEG_FLIP:     dcb->digit[pos] ^= 0x80; break;
00491                         case DOT_7SEG_SET:      dcb->digit[pos] |= 0x80; break;
00492                         case DOT_7SEG_CLR:      dcb->digit[pos] &= ~0x80; break;
00493                 }
00494                 Spi7SegPush( dev);
00495         }
00496 
00497 }
00498 
00506 NUTFILE *Spi7SegOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00507 {
00508     NUTFILE *fp;
00509 
00510     NUTASSERT( dev != NULL);
00511 
00512     if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00513         return NUTFILE_EOF;
00514     }
00515 
00516     fp->nf_fcb = 0;
00517     fp->nf_dev = dev;
00518     fp->nf_next = 0;
00519 
00520     return fp;
00521 
00522 }
00523 
00529 static int Spi7SegClose(NUTFILE * fp)
00530 {
00531     if( fp != NULL) {
00532         free( fp);
00533         return 0;
00534     }
00535     return -1;
00536 }
00537 
00538 /*********************************************************************************
00539  **
00540  **         7-Segement Driver: Initialization & Device Description
00541  **
00542  **/
00543 
00556 int Spi7segInit(NUTDEVICE * dev)
00557 {
00558         uint8_t data;
00559     NUTSPINODE *node;
00560     DCB_7SEG * dcb;
00561 
00562     NUTASSERT(dev != NULL);
00563     NUTASSERT(dev->dev_icb != NULL);
00564     node = dev->dev_icb;
00565 
00566     /* Allocate device control block */
00567     dcb = malloc( sizeof( DCB_7SEG));
00568     if( dcb == NULL)
00569         return -1;
00570     memset( dcb, 0, sizeof( DCB_7SEG));
00571     dev->dev_dcb = dcb;
00572 
00573     NPRINTF("INIT %d Digits...\n", SEG7_DIGITS);
00574 
00575         data = TEST_MODE_OFF;
00576         disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
00577         disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
00578         disp7segCommand(node, SEGR_DSP_TEST, &data, NULL, 1);
00579 
00580         data = NORM_OP_RESET;
00581         disp7segCommand(node, SEGR_SHUTDOWN, &data, NULL, 1);
00582 
00583         data = SEG7_DIGITS;
00584         disp7segCommand(node, SEGR_SCAN_LIM, &data, NULL, 1);
00585 
00586         dcb->freg = NO_DIG_DECODE;
00587         disp7segCommand(node, SEGR_DEC_MODE, &dcb->freg, NULL, 1);
00588 
00589         data = 0x0F;
00590         disp7segCommand(node, SEGR_INTENSITY, &data, NULL, 1);
00591 
00592         data = 0;
00593         disp7segCommand(node, SEGR_DIG0, &data, NULL, 1);
00594         disp7segCommand(node, SEGR_DIG1, &data, NULL, 1);
00595         disp7segCommand(node, SEGR_DIG2, &data, NULL, 1);
00596 
00597         return 0;
00598 
00599 }
00600 
00604 NUTSPINODE nodeSpi7SEG = {
00605     NULL,                   
00606     NULL,                   
00607     SPI_RATE_DISP_7SEG,     
00608     SPI_MODE_DISP_7SEG,     
00609     8,                      
00610     0                       
00611 };
00612 
00616 NUTDEVICE devSpi7SEG = {
00617     NULL,                               
00618     {'7', 'S', 'E', 'G', 0, 0, 0},  
00619     IFTYP_CHAR,                         
00620     0,                                  
00621     0,                                  
00622     &nodeSpi7SEG,                       
00623     0,                              
00624     Spi7segInit,                        
00625     Spi7SegIOCtl,                   
00626         0,                                                              
00627     Spi7segWrite,                   
00628 #ifdef __HARVARD_ARCH__
00629     0,                                                          
00630 #endif
00631     Spi7SegOpen,                                
00632     Spi7SegClose,                               
00633     0                                                           
00634 };
00635