Contiki 2.5
sam7s-spi.c
1 #include <AT91SAM7S64.h>
2 #include <stdint.h>
3 #include <dev/spi.h>
4 #include <sam7s-spi.h>
5 
6 /* Prevents interrupts using SPI at inappropriate times */
7 unsigned char spi_busy = 0;
8 
9 #define SPI_SPEED 1000000 /* 1MHz clock*/
10 #define SPI_DLYBCT 1
11 #define SPI_DLYBS 20
12 
13 #define SPI_TRANSFER (AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK)
14 
15 #define SPI_CS (AT91C_PA11_NPCS0 | AT91C_PA31_NPCS1)
16 
17 void
18 spi_init()
19 {
20  static uint8_t initialised = 0;
21  if (!initialised) {
22  *AT91C_SPI_CR = AT91C_SPI_SPIDIS | AT91C_SPI_SWRST;
23  *AT91C_PMC_PCER = (1 << AT91C_ID_SPI);
24  *AT91C_PIOA_ASR = SPI_TRANSFER | SPI_CS;
25  *AT91C_PIOA_PDR = SPI_TRANSFER | SPI_CS;
26  *AT91C_PIOA_PPUER = AT91C_PA12_MISO | SPI_CS;
27  *AT91C_SPI_MR = (AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED
28  | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
29 
30  /* It seems necessary to set the clock speed for chip select 0
31  even if it's not used. */
32  AT91C_SPI_CSR[0] = (MCK/SPI_SPEED)<<8;
33 
34  *AT91C_SPI_CR = AT91C_SPI_SPIEN;
35  initialised = 1;
36  }
37 }
38 
39 void
40 spi_init_chip_select(unsigned int chip, unsigned int speed,
41  unsigned int dlybct,
42  unsigned int dlybs, unsigned int phase,
43  unsigned int polarity)
44 {
45  spi_init();
46 
47  AT91C_SPI_CSR[chip] =
48  ((dlybct<<24) | (dlybs<<16) | (((MCK+speed/2)/speed)<<8)
49  | (phase?AT91C_SPI_NCPHA:0) | (polarity?AT91C_SPI_CPOL:0)
50  | AT91C_SPI_BITS_8 | AT91C_SPI_CSAAT);
51 }
52 
53 #if 0
54 #define DBG_SEND dbg_blocking_putchar('>');
55 #define DBG_RECV dbg_blocking_putchar('<');
56 #else
57 #define DBG_SEND
58 #define DBG_RECV
59 #endif
60 
61 void
62 spi_transfer(unsigned int chip, const struct spi_block *block, unsigned int blocks)
63 {
64  spi_busy = 1;
65  while(!(*AT91C_SPI_SR & AT91C_SPI_TXEMPTY)); /* wait unti previous transfer is done */
66 
67  /* Clear any data left in the receiver */
68  (void)*AT91C_SPI_RDR;
69  (void)*AT91C_SPI_RDR;
70 
71  /* Select chip */
72  *AT91C_SPI_MR = ((*AT91C_SPI_MR & ~AT91C_SPI_PCS)
73  | ((~(1<<chip) & 0x0f) << 16));
74 
75  while(blocks-- > 0) {
76  struct spi_block current = *block++;
77  if (current.send) {
78  if (current.receive) {
79  /* Send and receive */
80  while(current.len-- > 0) {
81  while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
82  *AT91C_SPI_TDR = *current.send++;
83  DBG_SEND;
84  while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
85  *current.receive++ = *AT91C_SPI_RDR;
86  DBG_RECV;
87  }
88  } else {
89  /* Send only */
90  while(current.len-- > 0) {
91  while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
92  *AT91C_SPI_TDR = *current.send++;
93  DBG_SEND;
94  while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
95  (void)*AT91C_SPI_RDR;
96  DBG_RECV;
97  }
98  }
99  } else {
100  if (current.receive) {
101  /* Receive only */
102  while(current.len-- > 0) {
103  while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
104  *AT91C_SPI_TDR = 0;
105  DBG_SEND;
106  while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
107  *current.receive++ = *AT91C_SPI_RDR;
108  DBG_RECV;
109  }
110  } else {
111  /* Clock only */
112  while(current.len-- > 0) {
113  while(!(*AT91C_SPI_SR & AT91C_SPI_TDRE));
114  *AT91C_SPI_TDR = 0;
115  DBG_SEND;
116  while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
117  (void)*AT91C_SPI_RDR;
118  DBG_RECV;
119  }
120  }
121  }
122  }
123  *AT91C_SPI_CR = AT91C_SPI_LASTXFER;
124 
125  spi_busy = 0;
126 }