Wixel SDK
spi_master.c
Go to the documentation of this file.
1 
6 #include <cc2511_map.h>
7 #include <cc2511_types.h>
8 
9 #if defined(__CDT_PARSER__)
10 #define SPI0
11 #endif
12 
13 #if defined(SPI0)
14 #include <spi0_master.h>
15 #define INTERRUPT_PRIORITY_GROUP 2
16 #define ISR_URX() ISR(URX0, 0)
17 #define URXNIF URX0IF
18 #define URXNIE URX0IE
19 #define UNGCR U0GCR
20 #define UNBAUD U0BAUD
21 #define UNDBUF U0DBUF
22 #define spiNMasterInit spi0MasterInit
23 #define spiNMasterSetFrequency spi0MasterSetFrequency
24 #define spiNMasterSetClockPolarity spi0MasterSetClockPolarity
25 #define spiNMasterSetClockPhase spi0MasterSetClockPhase
26 #define spiNMasterSetBitOrder spi0MasterSetBitOrder
27 #define spiNMasterBusy spi0MasterBusy
28 #define spiNMasterBytesLeft spi0MasterBytesLeft
29 #define spiNMasterTransfer spi0MasterTransfer
30 #define spiNMasterSendByte spi0MasterSendByte
31 #define spiNMasterReceiveByte spi0MasterReceiveByte
32 
33 #elif defined(SPI1)
34 #include <spi1_master.h>
35 #define INTERRUPT_PRIORITY_GROUP 3
36 #define ISR_URX() ISR(URX1, 0)
37 #define URXNIF URX1IF
38 #define URXNIE URX1IE
39 #define UNGCR U1GCR
40 #define UNBAUD U1BAUD
41 #define UNDBUF U1DBUF
42 #define spiNMasterInit spi1MasterInit
43 #define spiNMasterSetFrequency spi1MasterSetFrequency
44 #define spiNMasterSetClockPolarity spi1MasterSetClockPolarity
45 #define spiNMasterSetClockPhase spi1MasterSetClockPhase
46 #define spiNMasterSetBitOrder spi1MasterSetBitOrder
47 #define spiNMasterBusy spi1MasterBusy
48 #define spiNMasterBytesLeft spi1MasterBytesLeft
49 #define spiNMasterTransfer spi1MasterTransfer
50 #define spiNMasterSendByte spi1MasterSendByte
51 #define spiNMasterReceiveByte spi1MasterReceiveByte
52 #endif
53 
54 // txPointer points to the last byte that was written to SPI.
55 static volatile const uint8 XDATA * DATA txPointer = 0;
56 
57 // rxPointer points to the location to store the next byte received from SPI.
58 static volatile uint8 XDATA * DATA rxPointer = 0;
59 
60 // bytesLeft is the number of bytes we still need to send to/receive from SPI.
61 static volatile uint16 DATA bytesLeft = 0;
62 
63 void spiNMasterInit(void)
64 {
65  /* From datasheet Table 50 */
66 
67  /* USART0 SPI Alt. 1:
68  * SCK = P0_5
69  * MOSI = P0_3
70  * MISO = P0_2
71  */
72 
73  /* USART1 SPI Alt. 2:
74  * SCK = P1_5
75  * MOSI = P1_6
76  * MISO = P1_7
77  */
78 
79  /* 12.14.2.1: In SPI master mode, only the MOSI, MISO, and SCK should be
80  * configured as peripherals (see Section 12.4.6.1 and Section 12.4.6.2). If
81  * the external slave requires a slave select signal (SSN) this can be
82  * implemented by using a general-purpose I/O pin and control from SW.
83  */
84 
85  // Note: We do NOT set the mode of the RX pin to "peripheral function"
86  // because that seems to have no benefits, and is actually bad because
87  // it disables the internal pull-up resistor.
88 
89 #ifdef SPI0
90  P2DIR &= ~0xC0; // P2DIR.PRIP0 (7:6) = 00 : USART0 takes priority over USART1.
91  PERCFG &= ~0x01; // PERCFG.U0CFG (0) = 0 (Alt. 1) : USART0 uses alt. location 1.
92 #else
93  P2SEL |= 0x40; // USART1 takes priority over USART0 on Port 1.
94  PERCFG |= 0x02; // PERCFG.U1CFG (1) = 1 (Alt. 2) : USART1 uses alt. location 2.
95 #endif
96 
97  // Assumption: The MODE and SLAVE bits in U0CSR/U1CSR are 0 (the default) so
98  // the USART is already in SPI Master mode.
99 
100  // Set the mode of the SCK and MOSI pins to "peripheral function".
101 #ifdef SPI0
102  P0SEL |= ((1<<5) | (1<<3)); // P0SEL.SELP0_5 = 1, P0SEL.SELP0_3 = 1
103 #else
104  P1SEL |= ((1<<5) | (1<<6)); // P1SEL.SELP1_5 = 1, P1SEL.SELP1_6 = 1
105 #endif
106 
107  // Below, we set the priority of the RX and TX interrupts to be 1 (second lowest priority).
108  // They need to be higher than the RF interrupt because that one could take a long time.
109  // The SPI0 interrupts are grouped with the T2 interrupt, so its priority also gets set.
110  // The SPI1 interrupts are grouped with the T3 interrupts, so its priority also gets set.
111  IP0 |= (1<<INTERRUPT_PRIORITY_GROUP);
112  IP1 &= ~(1<<INTERRUPT_PRIORITY_GROUP);
113 
114  URXNIF = 0; // Clear RX flag.
115  EA = 1; // Enable interrupts in general.
116 }
117 
118 void spiNMasterSetFrequency(uint32 freq)
119 {
120  uint32 baudMPlus256;
121  uint8 baudE = 0;
122 
123  // max baud rate is 3000000 (F/8); min is 23 (baudM = 1)
124  if (freq < 23 || freq > 3000000)
125  return;
126 
127  // 495782 is the largest value that will not overflow the following calculation
128  while (freq > 495782)
129  {
130  baudE++;
131  freq /= 2;
132  }
133 
134  // calculate baud rate - see datasheet 12.14.3
135  // this is derived from (baudM + 256) = baud * 2^28 / 24000000
136  baudMPlus256 = (freq * 11) + (freq * 8663 / 46875);
137 
138  // get baudMPlus256 into the range 256-511 (so BAUD_M is in the range 0-255)
139  while (baudMPlus256 > 0x1ff)
140  {
141  baudE++;
142  baudMPlus256 /= 2;
143  }
144  UNGCR &= 0xE0; // preserve CPOL, CPHA, ORDER (7:5)
145  UNGCR |= baudE; // UNGCR.BAUD_E (4:0)
146  UNBAUD = baudMPlus256; // UNBAUD.BAUD_M (7:0) - only the lowest 8 bits of baudMPlus256 are used, so this is effectively baudMPlus256 - 256
147 }
148 
149 void spiNMasterSetClockPolarity(BIT polarity)
150 {
151  if (polarity == SPI_POLARITY_IDLE_LOW)
152  {
153  UNGCR &= ~(1<<7); // SCK idle low (negative polarity)
154  }
155  else
156  {
157  UNGCR |= (1<<7); // SCK idle high (positive polarity)
158  }
159 }
160 
161 void spiNMasterSetClockPhase(BIT phase)
162 {
163  if (phase == SPI_PHASE_EDGE_LEADING)
164  {
165  UNGCR &= ~(1<<6); // data centered on leading (first) edge - rising for idle low, falling for idle high
166  }
167  else
168  {
169  UNGCR |= (1<<6); // data centered on trailing (second) edge - falling for idle low, rising for idle high
170  }
171 }
172 
173 void spiNMasterSetBitOrder(BIT bitOrder)
174 {
175  if (bitOrder == SPI_BIT_ORDER_LSB_FIRST)
176  {
177  UNGCR &= ~(1<<5); // LSB first
178  }
179  else
180  {
181  UNGCR |= (1<<5); // MSB first
182  }
183 }
184 
185 BIT spiNMasterBusy(void)
186 {
187  return URXNIE;
188 }
189 
190 uint16 spiNMasterBytesLeft(void)
191 {
192  uint16 bytes;
193 
194  // bytesLeft is 16 bits, so it takes more than one instruction to read. Disable interrupts so it's not updated while we do this
195  URXNIE = 0;
196  bytes = bytesLeft;
197  if (bytes) URXNIE = 1;
198 
199  return bytes;
200 }
201 
202 void spiNMasterTransfer(const uint8 XDATA * txBuffer, uint8 XDATA * rxBuffer, uint16 size)
203 {
204  if (size)
205  {
206  txPointer = txBuffer;
207  rxPointer = rxBuffer;
208  bytesLeft = size;
209 
210  UNDBUF = *txBuffer; // transmit first byte
211  URXNIE = 1; // Enable RX interrupt.
212  }
213 }
214 
215 uint8 spiNMasterSendByte(uint8 XDATA byte)
216 {
217  uint8 XDATA rxByte;
218 
219  rxPointer = &rxByte;
220  bytesLeft = 1;
221 
222  UNDBUF = byte;
223  URXNIE = 1; // Enable RX interrupt.
224 
225  while (bytesLeft);
226  return rxByte;
227 }
228 
229 uint8 spiNMasterReceiveByte(void)
230 {
231  return spiNMasterSendByte(0xFF);
232 }
233 
234 ISR_URX()
235 {
236  URXNIF = 0;
237 
238  *rxPointer = UNDBUF;
239  rxPointer++;
240  bytesLeft--;
241 
242  if (bytesLeft)
243  {
244  txPointer++;
245  UNDBUF = *txPointer;
246  }
247  else
248  {
249  URXNIE = 0;
250  }
251 }
#define DATA
Definition: cc2511_types.h:52
#define XDATA
Definition: cc2511_types.h:65
#define SPI_PHASE_EDGE_LEADING
Definition: spi.h:14
unsigned long uint32
Definition: cc2511_types.h:21
__bit BIT
Definition: cc2511_types.h:32
unsigned short uint16
Definition: cc2511_types.h:15
#define SPI_POLARITY_IDLE_LOW
Definition: spi.h:9
unsigned char uint8
Definition: cc2511_types.h:9
#define SPI_BIT_ORDER_LSB_FIRST
Definition: spi.h:22