Nut/OS  4.10.3
API Reference
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$
00036  * Revision 1.2  2008/08/11 06:59:17  haraldkipp
00037  * BSD types replaced by stdint types (feature request #1282721).
00038  *
00039  * Revision 1.1  2007/04/12 09:07:54  haraldkipp
00040  * Configurable SPI added.
00041  *
00042  */
00043 
00044 #include <cfg/arch/avr.h>
00045 #include <sys/timer.h>
00046 #include <dev/sppif0.h>
00047 
00048 /* SPI control shadow registers. */
00049 static uint8_t sppi0_spcr[SPPI0_MAX_DEVICES];
00050 
00051 /* SPI status shadow registers. Used to configure the double speed bit. */
00052 #ifdef SPI2X
00053 static uint8_t sppi0_spsr[SPPI0_MAX_DEVICES];
00054 #endif
00055 
00076 int Sppi0SetMode(uint8_t ix, uint8_t mode)
00077 {
00078     if (ix >= SPPI0_MAX_DEVICES || mode > 3) {
00079         return -1;
00080     }
00081 
00082     /* A bit obfuscated, but compact. A simple shift 
00083        correctly sets CPHA and CPOL. */
00084     sppi0_spcr[ix] = _BV(SPE) | _BV(MSTR) | (mode << 2) | _BV(SPR1) | _BV(SPR0);
00085 #if defined(SPI2X)
00086     sppi0_spsr[ix] = 0;
00087 #endif
00088 
00089     return 0;
00090 }
00091 
00099 void Sppi0SetSpeed(uint8_t ix, uint32_t rate)
00100 {
00101     uint32_t fosc;
00102     uint8_t i;
00103 
00104     fosc = NutGetCpuClock();
00105 
00106     sppi0_spcr[ix] &= ~(_BV(SPR1) | _BV(SPR0));
00107     /* Find the frequency that is below or equal the requested 
00108        one, using the double speed bit if available. */
00109 #if defined(SPI2X)
00110     for (i = 0; i < 7; i++) {
00111         fosc >>= 1;
00112         if (fosc <= rate) {
00113             break;
00114         }
00115     }
00116     sppi0_spcr[ix] |= (i >> 1);
00117     if (i < 6) {
00118         sppi0_spsr[ix] = ~i & 1;
00119     }
00120 #else
00121     for (i = 0; i < 3; i++) {
00122         fosc >>= 2;
00123         if (fosc <= rate) {
00124             break;
00125         }
00126     }
00127     sppi0_spcr[ix] |= i;
00128 #endif
00129 }
00130 
00140 void Sppi0Enable(uint8_t ix)
00141 {
00142     /*
00143      * When configured as SPI master, MOSI (PB2) and SCK (PB1) 
00144      * lines are not automatically switched to output.
00145      */
00146     if (sppi0_spcr[ix] & _BV(CPOL)) {
00147         cbi(PORTB, 1);
00148     } else {
00149         sbi(PORTB, 1);
00150     }
00151     sbi(DDRB, 1);
00152     cbi(PORTB, 2);
00153     sbi(DDRB, 2);
00154 
00155     /* Enable MISO pull-up to avoid floating. */
00156     sbi(PORTB, 3);
00157 
00158     /*
00159      * When SS (PB0) is configured as input, we will be forced
00160      * into slave mode if this pin goes low. Enable the pull-up.
00161      */
00162     if (bit_is_clear(DDRB, 0)) {
00163         sbi(PORTB, 0);
00164     }
00165 
00166     /* Set SPI mode and optionally the double speed bit. */
00167     outb(SPCR, sppi0_spcr[ix]);
00168 #if defined(SPI2X)
00169     outb(SPSR, sppi0_spsr[ix]);
00170 #endif
00171 
00172     /* Clean-up the status. */
00173     ix = inb(SPSR);
00174     ix = inb(SPDR);
00175 }
00176 
00187 void Sppi0ChipReset(uint8_t ix, uint8_t hi)
00188 {
00189 #if defined(SPPI0_RST0_BIT)
00190     if (ix == 0) {
00191         if (hi) {
00192             SPPI0_RST0_SET();
00193         } else {
00194             SPPI0_RST0_CLR();
00195         }
00196         SPPI0_RST0_ENA();
00197     }
00198 #endif
00199 #if defined(SPPI0_RST1_BIT)
00200     if (ix == 1) {
00201         if (hi) {
00202             SPPI0_RST1_SET();
00203         } else {
00204             SPPI0_RST1_CLR();
00205         }
00206         SPPI0_RST1_ENA();
00207     }
00208 #endif
00209 #if defined(SPPI0_RST2_BIT)
00210     if (ix == 2) {
00211         if (hi) {
00212             SPPI0_RST2_SET();
00213         } else {
00214             SPPI0_RST2_CLR();
00215         }
00216         SPPI0_RST2_ENA();
00217     }
00218 #endif
00219 #if defined(SPPI0_RST3_BIT)
00220     if (ix == 3) {
00221         if (hi) {
00222             SPPI0_RST3_SET();
00223         } else {
00224             SPPI0_RST3_CLR();
00225         }
00226         SPPI0_RST3_ENA();
00227     }
00228 #endif
00229 }
00230 
00242 void Sppi0ChipSelect(uint8_t ix, uint8_t hi)
00243 {
00244 #if defined(SPPI0_CS0_BIT)
00245     if (ix == 0) {
00246         if (hi) {
00247             SPPI0_CS0_SET();
00248         } else {
00249             SPPI0_CS0_CLR();
00250         }
00251         SPPI0_CS0_ENA();
00252     }
00253 #endif
00254 #if defined(SPPI0_CS1_BIT)
00255     if (ix == 1) {
00256         if (hi) {
00257             SPPI0_CS1_SET();
00258         } else {
00259             SPPI0_CS1_CLR();
00260         }
00261         SPPI0_CS1_ENA();
00262     }
00263 #endif
00264 #if defined(SPPI0_CS2_BIT)
00265     if (ix == 2) {
00266         if (hi) {
00267             SPPI0_CS2_SET();
00268         } else {
00269             SPPI0_CS2_CLR();
00270         }
00271         SPPI0_CS2_ENA();
00272     }
00273 #endif
00274 #if defined(SPPI0_CS3_BIT)
00275     if (ix == 3) {
00276         if (hi) {
00277             SPPI0_CS3_SET();
00278         } else {
00279             SPPI0_CS3_CLR();
00280         }
00281         SPPI0_CS3_ENA();
00282     }
00283 #endif
00284 }
00285 
00297 void Sppi0SelectDevice(uint8_t ix)
00298 {
00299     Sppi0Enable(ix);
00300     Sppi0ChipSelect(ix, 1);
00301 }
00302 
00311 void Sppi0DeselectDevice(uint8_t ix)
00312 {
00313     Sppi0ChipSelect(ix, 0);
00314 }
00315 
00327 void Sppi0NegSelectDevice(uint8_t ix)
00328 {
00329     Sppi0Enable(ix);
00330     Sppi0ChipSelect(ix, 0);
00331 }
00332 
00341 void Sppi0NegDeselectDevice(uint8_t ix)
00342 {
00343     Sppi0ChipSelect(ix, 1);
00344 }
00345 
00353 uint8_t Sppi0Byte(uint8_t data)
00354 {
00355     outb(SPDR, data);
00356     loop_until_bit_is_set(SPSR, SPIF);
00357 
00358     return inb(SPDR);
00359 }
00360 
00377 void Sppi0Transact(CONST void *wdata, void *rdata, size_t len)
00378 {
00379     CONST uint8_t *wp = (CONST uint8_t *)wdata;
00380 
00381     if (rdata) {
00382         uint8_t *rp = (uint8_t *)rdata;
00383 
00384         while(len--) {
00385             *rp++ = Sppi0Byte(*wp);
00386             wp++;
00387         }
00388     } else {
00389         while(len--) {
00390             Sppi0Byte(*wp);
00391             wp++;
00392         }
00393     }
00394 }