Wixel SDK
uart.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 UART0
11 #endif
12 
13 #if defined(UART0)
14 #include <uart0.h>
15 #define INTERRUPT_PRIORITY_GROUP 2
16 #define ISR_URX() ISR(URX0, 0)
17 #define ISR_UTX() ISR(UTX0, 0)
18 #define UTXNIF UTX0IF
19 #define URXNIF URX0IF
20 #define URXNIE URX0IE
21 #define UNCSR U0CSR
22 #define UNGCR U0GCR
23 #define UNUCR U0UCR
24 #define UNBAUD U0BAUD
25 #define UNDBUF U0DBUF
26 #define BV_UTXNIE (1<<2)
27 #define uartNRxParityErrorOccurred uart0RxParityErrorOccurred
28 #define uartNRxFramingErrorOccurred uart0RxFramingErrorOccurred
29 #define uartNRxBufferFullOccurred uart0RxBufferFullOccurred
30 #define uartNRxAvailable uart0RxAvailable
31 #define uartNTxAvailable uart0TxAvailable
32 #define uartNInit uart0Init
33 #define uartNSetBaudRate uart0SetBaudRate
34 #define uartNSetParity uart0SetParity
35 #define uartNSetStopBits uart0SetStopBits
36 #define uartNTxSend uart0TxSend
37 #define uartNRxReceiveByte uart0RxReceiveByte
38 #define uartNTxSend uart0TxSend
39 #define uartNTxSendByte uart0TxSendByte
40 
41 #elif defined(UART1)
42 #include <uart1.h>
43 #define INTERRUPT_PRIORITY_GROUP 3
44 #define ISR_URX() ISR(URX1, 0)
45 #define ISR_UTX() ISR(UTX1, 0)
46 #define UTXNIF UTX1IF
47 #define URXNIF URX1IF
48 #define URXNIE URX1IE
49 #define UNCSR U1CSR
50 #define UNGCR U1GCR
51 #define UNUCR U1UCR
52 #define UNBAUD U1BAUD
53 #define UNDBUF U1DBUF
54 #define BV_UTXNIE (1<<3)
55 #define uartNRxParityErrorOccurred uart1RxParityErrorOccurred
56 #define uartNRxFramingErrorOccurred uart1RxFramingErrorOccurred
57 #define uartNRxBufferFullOccurred uart1RxBufferFullOccurred
58 #define uartNRxAvailable uart1RxAvailable
59 #define uartNTxAvailable uart1TxAvailable
60 #define uartNInit uart1Init
61 #define uartNSetBaudRate uart1SetBaudRate
62 #define uartNSetParity uart1SetParity
63 #define uartNSetStopBits uart1SetStopBits
64 #define uartNTxSend uart1TxSend
65 #define uartNRxReceiveByte uart1RxReceiveByte
66 #define uartNTxSend uart1TxSend
67 #define uartNTxSendByte uart1TxSendByte
68 #endif
69 
70 static volatile uint8 XDATA uartTxBuffer[256]; // sizeof(uartTxBuffer) must be a power of two
71 static volatile uint8 DATA uartTxBufferMainLoopIndex; // Index of next byte main loop will write.
72 static volatile uint8 DATA uartTxBufferInterruptIndex; // Index of next byte interrupt will read.
73 
74 #define UART_TX_BUFFER_FREE_BYTES() ((uartTxBufferInterruptIndex - uartTxBufferMainLoopIndex - 1) & (sizeof(uartTxBuffer) - 1))
75 
76 static volatile uint8 XDATA uartRxBuffer[256]; // sizeof(uartRxBuffer) must be a power of two
77 static volatile uint8 DATA uartRxBufferMainLoopIndex; // Index of next byte main loop will read.
78 static volatile uint8 DATA uartRxBufferInterruptIndex; // Index of next byte interrupt will write.
79 
80 #define UART_RX_BUFFER_FREE_BYTES() ((uartRxBufferMainLoopIndex - uartRxBufferInterruptIndex - 1) & (sizeof(uartRxBuffer) - 1))
81 #define UART_RX_BUFFER_USED_BYTES() ((uartRxBufferInterruptIndex - uartRxBufferMainLoopIndex) & (sizeof(uartRxBuffer) - 1))
82 
83 volatile BIT uartNRxParityErrorOccurred;
84 volatile BIT uartNRxFramingErrorOccurred;
85 volatile BIT uartNRxBufferFullOccurred;
86 
87 void uartNInit(void)
88 {
89  /* USART0 UART Alt. 1:
90  * TX = P0_3
91  * RX = P0_2
92  */
93 
94  /* USART1 UART Alt. 2:
95  * TX = P1_6
96  * RX = P1_7
97  */
98 
99  uartTxBufferMainLoopIndex = 0;
100  uartTxBufferInterruptIndex = 0;
101  uartRxBufferMainLoopIndex = 0;
102  uartRxBufferInterruptIndex = 0;
103  uartNRxParityErrorOccurred = 0;
104  uartNRxFramingErrorOccurred = 0;
105  uartNRxBufferFullOccurred = 0;
106 
107  // Note: We do NOT set the mode of the RX pin to "peripheral function"
108  // because that seems to have no benefits, and is actually bad because
109  // it disables the internal pull-up resistor.
110 
111 #ifdef UART0
112  P2DIR &= ~0xC0; // P2DIR.PRIP0 (7:6) = 00 : USART0 takes priority over USART1.
113  PERCFG &= ~0x01; // PERCFG.U0CFG (0) = 0 (Alt. 1) : USART0 uses alt. location 1.
114 #else
115  P2SEL |= 0x40; // USART1 takes priority over USART0 on Port 1.
116  PERCFG |= 0x02; // PERCFG.U1CFG (1) = 1 (Alt. 2) : USART1 uses alt. location 2.
117 #endif
118 
119  UNUCR = 0x82; // Stops the "current operation" and resets settings to their defaults.
120  UNCSR |= 0xc0; // Enable UART mode and enable receiver. TODO: change '|=' to '='
121 
122  // Set the mode of the TX pin to "peripheral function". This must be done AFTER
123  // enabling the UART, or else we get a tiny glitch on the TX line.
124 #ifdef UART0
125  P0SEL |= (1<<3); // P0SEL.SELP0_3 = 1
126 #else
127  P1SEL |= (1<<6); // P1SEL.SELP1_6 = 1
128 #endif
129 
130  // Below, we set the priority of the RX and TX interrupts to be 1 (second lowest priority).
131  // They need to be higher than the RF interrupt because that one could take a long time.
132  // The UART0 interrupts are grouped with the T2 interrupt, so its priority also gets set.
133  // The UART1 interrupts are grouped with the T3 interrupts, so its priority also gets set.
134  IP0 |= (1<<INTERRUPT_PRIORITY_GROUP);
135  IP1 &= ~(1<<INTERRUPT_PRIORITY_GROUP);
136 
137  UTXNIF = 1; // Set TX flag so the interrupt fires when we enable it for the first time.
138  URXNIF = 0; // Clear RX flag.
139  URXNIE = 1; // Enable Rx interrupt.
140  EA = 1; // Enable interrupts in general.
141 }
142 
143 void uartNSetBaudRate(uint32 baud)
144 {
145  uint32 baudMPlus256;
146  uint8 baudE = 0;
147 
148  // max baud rate is 1500000 (F/16); min is 23 (baudM = 1)
149  if (baud < 23 || baud > 1500000)
150  return;
151 
152  // 495782 is the largest value that will not overflow the following calculation
153  while (baud > 495782)
154  {
155  baudE++;
156  baud /= 2;
157  }
158 
159  // calculate baud rate - see datasheet 12.14.3
160  // this is derived from (baudM + 256) = baud * 2^28 / 24000000
161  baudMPlus256 = (baud * 11) + (baud * 8663 / 46875);
162 
163  // get baudMPlus256 into the range 256-511 (so BAUD_M is in the range 0-255)
164  while (baudMPlus256 > 0x1ff)
165  {
166  baudE++;
167  baudMPlus256 /= 2;
168  }
169  UNGCR = baudE; // UNGCR.BAUD_E (4:0)
170  UNBAUD = baudMPlus256; // UNBAUD.BAUD_M (7:0) - only the lowest 8 bits of baudMPlus256 are used, so this is effectively baudMPlus256 - 256
171 }
172 
173 void uartNSetParity(uint8 parity)
174 {
175  // parity D9 BIT9 PARITY
176  // 0 None x 0 x
177  // 1 Odd 1 1 1
178  // 2 Even 0 1 1
179  // 3 Mark 1 1 0
180  // 4 Space 0 1 0
181 
182  uint8 tmp = 0;
183 
184  switch(parity)
185  {
186  case PARITY_ODD: tmp = 0b111 << 3; break;
187  case PARITY_EVEN: tmp = 0b011 << 3; break;
188  case PARITY_MARK: tmp = 0b110 << 3; break;
189  case PARITY_SPACE: tmp = 0b010 << 3; break;
190  }
191 
192  UNUCR = (UNUCR & 0b01000111) | tmp;
193 }
194 
195 void uartNSetStopBits(uint8 stopBits)
196 {
197  if (stopBits == STOP_BITS_2)
198  {
199  UNUCR |= (1<<2); // 2 stop bits
200  }
201  else
202  {
203  UNUCR &= ~(1<<2); // 1 stop bit
204  // NOTE: An argument of STOP_BITS_1_5 is treated the same as STOP_BITS_1.
205  }
206 }
207 
208 uint8 uartNTxAvailable(void)
209 {
210  return UART_TX_BUFFER_FREE_BYTES();
211 }
212 
213 void uartNTxSend(const uint8 XDATA * buffer, uint8 size)
214 {
215  // Assumption: uartNTxAvailable() was recently called and it returned a number at least as big as 'size'.
216  // TODO: after DMA memcpy is implemented, use it to make this function faster
217 
218  while (size)
219  {
220  uartTxBuffer[uartTxBufferMainLoopIndex] = *buffer;
221 
222  buffer++;
223  uartTxBufferMainLoopIndex = (uartTxBufferMainLoopIndex + 1) & (sizeof(uartTxBuffer) - 1);
224  size--;
225 
226  IEN2 |= BV_UTXNIE; // Enable TX interrupt
227  }
228 }
229 
230 void uartNTxSendByte(uint8 byte)
231 {
232  // Assumption: uartNTxAvailable() was recently called and it returned a non-zero number.
233 
234  uartTxBuffer[uartTxBufferMainLoopIndex] = byte;
235  uartTxBufferMainLoopIndex = (uartTxBufferMainLoopIndex + 1) & (sizeof(uartTxBuffer) - 1);
236 
237  IEN2 |= BV_UTXNIE; // Enable TX interrupt
238 }
239 
240 uint8 uartNRxAvailable(void)
241 {
242  return UART_RX_BUFFER_USED_BYTES();
243 }
244 
245 uint8 uartNRxReceiveByte(void)
246 {
247  // Assumption: uartNRxAvailable was recently called and it returned a non-zero value.
248 
249  uint8 byte = uartRxBuffer[uartRxBufferMainLoopIndex];
250  uartRxBufferMainLoopIndex = (uartRxBufferMainLoopIndex + 1) & (sizeof(uartRxBuffer) - 1);
251  return byte;
252 }
253 
254 ISR_UTX()
255 {
256  // A byte has just started transmitting on TX and there is room in
257  // the UART's hardware buffer for us to add another byte.
258 
259  if (uartTxBufferInterruptIndex != uartTxBufferMainLoopIndex)
260  {
261  // There more bytes available in our software buffer, so send
262  // the next byte.
263 
264  UTXNIF = 0;
265 
266  UNDBUF = uartTxBuffer[uartTxBufferInterruptIndex];
267  uartTxBufferInterruptIndex = (uartTxBufferInterruptIndex + 1) & (sizeof(uartTxBuffer) - 1);
268  }
269  else
270  {
271  // There are no more bytes to send in our buffer, so disable the TX interrupt.
272  IEN2 &= ~BV_UTXNIE;
273  }
274 }
275 
276 ISR_URX()
277 {
278  uint8 csr;
279 
280  URXNIF = 0;
281 
282  // Read the Control and Status register for the UART.
283  // Reading this register clears the FE and ERR bits,
284  // which we need to check later.
285  csr = UNCSR;
286 
287  // check for frame and parity errors
288  if (!(csr & 0x18)) // UNCSR.FE (4) == 0; UNCSR.ERR (3) == 0
289  {
290  // There were no errors.
291 
292  if (UART_RX_BUFFER_FREE_BYTES())
293  {
294  // The software RX buffer has space, so add this new byte to the buffer.
295  uartRxBuffer[uartRxBufferInterruptIndex] = UNDBUF;
296  uartRxBufferInterruptIndex = (uartRxBufferInterruptIndex + 1) & (sizeof(uartRxBuffer) - 1);
297  }
298  else
299  {
300  // The buffer is full, so discard the received byte and report and overflow error.
301  uartNRxBufferFullOccurred = 1;
302  }
303  }
304  else
305  {
306  if (csr & 0x10) // UNCSR.FE (4) == 1
307  {
308  uartNRxFramingErrorOccurred = 1;
309  }
310  if (csr & 0x08) // UNCSR.ERR (3) == 1
311  {
312  uartNRxParityErrorOccurred = 1;
313  }
314  }
315 }
#define DATA
Definition: cc2511_types.h:52
#define PARITY_ODD
Definition: com.h:88
#define XDATA
Definition: cc2511_types.h:65
unsigned long uint32
Definition: cc2511_types.h:21
__bit BIT
Definition: cc2511_types.h:32
#define PARITY_MARK
Definition: com.h:94
#define PARITY_SPACE
Definition: com.h:97
#define PARITY_EVEN
Definition: com.h:91
unsigned char uint8
Definition: cc2511_types.h:9
#define STOP_BITS_2
Definition: com.h:111