Contiki 2.6

sam7s-spi.c

00001 #include <AT91SAM7S64.h>
00002 #include <stdint.h>
00003 #include <dev/spi.h>
00004 #include <sam7s-spi.h>
00005 
00006 /* Prevents interrupts using SPI at inappropriate times */
00007 unsigned char spi_busy = 0;
00008 
00009 #define SPI_SPEED 1000000  /* 1MHz clock*/
00010 #define SPI_DLYBCT 1
00011 #define SPI_DLYBS 20
00012 
00013 #define SPI_TRANSFER (AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK)
00014 
00015 #define SPI_CS (AT91C_PA11_NPCS0 | AT91C_PA31_NPCS1)
00016 
00017 void
00018 spi_init()
00019 {
00020   static uint8_t initialised = 0;
00021   if (!initialised) {
00022     *AT91C_SPI_CR = AT91C_SPI_SPIDIS | AT91C_SPI_SWRST;
00023     *AT91C_PMC_PCER = (1 << AT91C_ID_SPI);
00024     *AT91C_PIOA_ASR = SPI_TRANSFER | SPI_CS;
00025     *AT91C_PIOA_PDR = SPI_TRANSFER | SPI_CS;
00026     *AT91C_PIOA_PPUER = AT91C_PA12_MISO | SPI_CS;
00027     *AT91C_SPI_MR = (AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED
00028                      | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
00029 
00030     /* It seems necessary to set the clock speed for chip select 0
00031        even if it's not used. */
00032     AT91C_SPI_CSR[0] = (MCK/SPI_SPEED)<<8;
00033 
00034     *AT91C_SPI_CR = AT91C_SPI_SPIEN;
00035     initialised = 1;
00036   }
00037 }
00038 
00039 void
00040 spi_init_chip_select(unsigned int chip, unsigned int speed,
00041                      unsigned int dlybct,
00042                      unsigned int dlybs, unsigned int phase,
00043                      unsigned int polarity)
00044 {
00045   spi_init();
00046 
00047   AT91C_SPI_CSR[chip] =
00048     ((dlybct<<24) | (dlybs<<16) | (((MCK+speed/2)/speed)<<8)
00049      | (phase?AT91C_SPI_NCPHA:0) | (polarity?AT91C_SPI_CPOL:0)
00050      | AT91C_SPI_BITS_8 | AT91C_SPI_CSAAT);
00051 }
00052 
00053 #if 0
00054 #define DBG_SEND dbg_blocking_putchar('>');
00055 #define DBG_RECV dbg_blocking_putchar('<');
00056 #else
00057 #define DBG_SEND
00058 #define DBG_RECV
00059 #endif
00060 
00061 void
00062 spi_transfer(unsigned int chip, const struct spi_block *block, unsigned int blocks)
00063 {
00064   spi_busy = 1;
00065   while(!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)); /* wait unti previous transfer is done */
00066   
00067   /* Clear any data left in the receiver */
00068   (void)*AT91C_SPI_RDR;
00069   (void)*AT91C_SPI_RDR;
00070 
00071   /* Select chip */
00072   *AT91C_SPI_MR = ((*AT91C_SPI_MR & ~AT91C_SPI_PCS)
00073                    | ((~(1<<chip) & 0x0f) << 16));
00074   
00075   while(blocks-- > 0) {
00076     struct spi_block current = *block++;
00077     if (current.send) {
00078       if (current.receive) {
00079         /* Send and receive */
00080         while(current.len-- > 0) {
00081           while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
00082           *AT91C_SPI_TDR = *current.send++;
00083           DBG_SEND;
00084           while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
00085           *current.receive++ = *AT91C_SPI_RDR;
00086           DBG_RECV;
00087         }
00088       } else {
00089         /* Send only */
00090         while(current.len-- > 0) {
00091           while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
00092           *AT91C_SPI_TDR = *current.send++;
00093           DBG_SEND;
00094           while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
00095           (void)*AT91C_SPI_RDR;
00096           DBG_RECV;
00097         }
00098       }
00099     } else {
00100       if (current.receive) {
00101         /* Receive only */
00102         while(current.len-- > 0) {
00103           while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
00104           *AT91C_SPI_TDR = 0;
00105           DBG_SEND;
00106           while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
00107           *current.receive++ = *AT91C_SPI_RDR;
00108           DBG_RECV;
00109         }
00110       } else {
00111         /* Clock only */
00112         while(current.len-- > 0) {
00113           while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
00114           *AT91C_SPI_TDR = 0;
00115           DBG_SEND;
00116           while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
00117           (void)*AT91C_SPI_RDR;
00118           DBG_RECV;
00119         }
00120       }
00121     } 
00122   }
00123   *AT91C_SPI_CR = AT91C_SPI_LASTXFER;
00124     
00125   spi_busy = 0;
00126 }