sppif0.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log: sppif0.c,v $
00036  * Revision 1.1  2007/04/12 09:07:54  haraldkipp
00037  * Configurable SPI added.
00038  *
00039  */
00040 
00041 #include <cfg/arch/avr.h>
00042 #include <sys/timer.h>
00043 #include <dev/sppif0.h>
00044 
00045 /* SPI control shadow registers. */
00046 static u_char sppi0_spcr[SPPI0_MAX_DEVICES];
00047 
00048 /* SPI status shadow registers. Used to configure the double speed bit. */
00049 #ifdef SPI2X
00050 static u_char sppi0_spsr[SPPI0_MAX_DEVICES];
00051 #endif
00052 
00073 int Sppi0SetMode(u_char ix, u_char mode)
00074 {
00075     if (ix >= SPPI0_MAX_DEVICES || mode > 3) {
00076         return -1;
00077     }
00078 
00079     /* A bit obfuscated, but compact. A simple shift 
00080        correctly sets CPHA and CPOL. */
00081     sppi0_spcr[ix] = _BV(SPE) | _BV(MSTR) | (mode << 2) | _BV(SPR1) | _BV(SPR0);
00082 #if defined(SPI2X)
00083     sppi0_spsr[ix] = 0;
00084 #endif
00085 
00086     return 0;
00087 }
00088 
00096 void Sppi0SetSpeed(u_char ix, u_long rate)
00097 {
00098     u_long fosc;
00099     u_char i;
00100 
00101     fosc = NutGetCpuClock();
00102 
00103     sppi0_spcr[ix] &= ~(_BV(SPR1) | _BV(SPR0));
00104     /* Find the frequency that is below or equal the requested 
00105        one, using the double speed bit if available. */
00106 #if defined(SPI2X)
00107     for (i = 0; i < 7; i++) {
00108         fosc >>= 1;
00109         if (fosc <= rate) {
00110             break;
00111         }
00112     }
00113     sppi0_spcr[ix] |= (i >> 1);
00114     if (i < 6) {
00115         sppi0_spsr[ix] = ~i & 1;
00116     }
00117 #else
00118     for (i = 0; i < 3; i++) {
00119         fosc >>= 2;
00120         if (fosc <= rate) {
00121             break;
00122         }
00123     }
00124     sppi0_spcr[ix] |= i;
00125 #endif
00126 }
00127 
00137 void Sppi0Enable(u_char ix)
00138 {
00139     /*
00140      * When configured as SPI master, MOSI (PB2) and SCK (PB1) 
00141      * lines are not automatically switched to output.
00142      */
00143     if (sppi0_spcr[ix] & _BV(CPOL)) {
00144         cbi(PORTB, 1);
00145     } else {
00146         sbi(PORTB, 1);
00147     }
00148     sbi(DDRB, 1);
00149     cbi(PORTB, 2);
00150     sbi(DDRB, 2);
00151 
00152     /* Enable MISO pull-up to avoid floating. */
00153     sbi(PORTB, 3);
00154 
00155     /*
00156      * When SS (PB0) is configured as input, we will be forced
00157      * into slave mode if this pin goes low. Enable the pull-up.
00158      */
00159     if (bit_is_clear(DDRB, 0)) {
00160         sbi(PORTB, 0);
00161     }
00162 
00163     /* Set SPI mode and optionally the double speed bit. */
00164     outb(SPCR, sppi0_spcr[ix]);
00165 #if defined(SPI2X)
00166     outb(SPSR, sppi0_spsr[ix]);
00167 #endif
00168 
00169     /* Clean-up the status. */
00170     ix = inb(SPSR);
00171     ix = inb(SPDR);
00172 }
00173 
00184 void Sppi0ChipReset(u_char ix, u_char hi)
00185 {
00186 #if defined(SPPI0_RST0_BIT)
00187     if (ix == 0) {
00188         if (hi) {
00189             SPPI0_RST0_SET();
00190         } else {
00191             SPPI0_RST0_CLR();
00192         }
00193         SPPI0_RST0_ENA();
00194     }
00195 #endif
00196 #if defined(SPPI0_RST1_BIT)
00197     if (ix == 1) {
00198         if (hi) {
00199             SPPI0_RST1_SET();
00200         } else {
00201             SPPI0_RST1_CLR();
00202         }
00203         SPPI0_RST1_ENA();
00204     }
00205 #endif
00206 #if defined(SPPI0_RST2_BIT)
00207     if (ix == 2) {
00208         if (hi) {
00209             SPPI0_RST2_SET();
00210         } else {
00211             SPPI0_RST2_CLR();
00212         }
00213         SPPI0_RST2_ENA();
00214     }
00215 #endif
00216 #if defined(SPPI0_RST3_BIT)
00217     if (ix == 3) {
00218         if (hi) {
00219             SPPI0_RST3_SET();
00220         } else {
00221             SPPI0_RST3_CLR();
00222         }
00223         SPPI0_RST3_ENA();
00224     }
00225 #endif
00226 }
00227 
00239 void Sppi0ChipSelect(u_char ix, u_char hi)
00240 {
00241 #if defined(SPPI0_CS0_BIT)
00242     if (ix == 0) {
00243         if (hi) {
00244             SPPI0_CS0_SET();
00245         } else {
00246             SPPI0_CS0_CLR();
00247         }
00248         SPPI0_CS0_ENA();
00249     }
00250 #endif
00251 #if defined(SPPI0_CS1_BIT)
00252     if (ix == 1) {
00253         if (hi) {
00254             SPPI0_CS1_SET();
00255         } else {
00256             SPPI0_CS1_CLR();
00257         }
00258         SPPI0_CS1_ENA();
00259     }
00260 #endif
00261 #if defined(SPPI0_CS2_BIT)
00262     if (ix == 2) {
00263         if (hi) {
00264             SPPI0_CS2_SET();
00265         } else {
00266             SPPI0_CS2_CLR();
00267         }
00268         SPPI0_CS2_ENA();
00269     }
00270 #endif
00271 #if defined(SPPI0_CS3_BIT)
00272     if (ix == 3) {
00273         if (hi) {
00274             SPPI0_CS3_SET();
00275         } else {
00276             SPPI0_CS3_CLR();
00277         }
00278         SPPI0_CS3_ENA();
00279     }
00280 #endif
00281 }
00282 
00294 void Sppi0SelectDevice(u_char ix)
00295 {
00296     Sppi0Enable(ix);
00297     Sppi0ChipSelect(ix, 1);
00298 }
00299 
00308 void Sppi0DeselectDevice(u_char ix)
00309 {
00310     Sppi0ChipSelect(ix, 0);
00311 }
00312 
00324 void Sppi0NegSelectDevice(u_char ix)
00325 {
00326     Sppi0Enable(ix);
00327     Sppi0ChipSelect(ix, 0);
00328 }
00329 
00338 void Sppi0NegDeselectDevice(u_char ix)
00339 {
00340     Sppi0ChipSelect(ix, 1);
00341 }
00342 
00350 u_char Sppi0Byte(u_char data)
00351 {
00352     outb(SPDR, data);
00353     loop_until_bit_is_set(SPSR, SPIF);
00354 
00355     return inb(SPDR);
00356 }
00357 
00374 void Sppi0Transact(CONST void *wdata, void *rdata, size_t len)
00375 {
00376     CONST u_char *wp = (CONST u_char *)wdata;
00377 
00378     if (rdata) {
00379         u_char *rp = (u_char *)rdata;
00380 
00381         while(len--) {
00382             *rp++ = Sppi0Byte(*wp);
00383             wp++;
00384         }
00385     } else {
00386         while(len--) {
00387             Sppi0Byte(*wp);
00388             wp++;
00389         }
00390     }
00391 }

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/