diff options
Diffstat (limited to 'lib/chibios-contrib/os/hal/ports/MSP430X/hal_serial_lld.c')
-rw-r--r-- | lib/chibios-contrib/os/hal/ports/MSP430X/hal_serial_lld.c | 668 |
1 files changed, 668 insertions, 0 deletions
diff --git a/lib/chibios-contrib/os/hal/ports/MSP430X/hal_serial_lld.c b/lib/chibios-contrib/os/hal/ports/MSP430X/hal_serial_lld.c new file mode 100644 index 000000000..acd0208d6 --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/MSP430X/hal_serial_lld.c | |||
@@ -0,0 +1,668 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2016 Andrew Wygle aka awygle | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file MSP430X/hal_serial_lld.c | ||
19 | * @brief MSP430X serial subsystem low level driver source. | ||
20 | * | ||
21 | * @addtogroup SERIAL | ||
22 | * @{ | ||
23 | */ | ||
24 | |||
25 | #include "hal.h" | ||
26 | |||
27 | #if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) | ||
28 | |||
29 | /*===========================================================================*/ | ||
30 | /* Driver local definitions. */ | ||
31 | /*===========================================================================*/ | ||
32 | |||
33 | /*===========================================================================*/ | ||
34 | /* Driver exported variables. */ | ||
35 | /*===========================================================================*/ | ||
36 | |||
37 | /** @brief USART0 serial driver identifier.*/ | ||
38 | #if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__) | ||
39 | #ifndef __MSP430_HAS_EUSCI_A0__ | ||
40 | #error "Cannot find USCI module to use for SD0" | ||
41 | #endif | ||
42 | #ifdef MSP430X_USCI_A0_USED | ||
43 | #error "USCI module A0 already in use - USART0 not available" | ||
44 | #endif | ||
45 | SerialDriver SD0; | ||
46 | #define MSP430X_USCI_A0_USED | ||
47 | #endif | ||
48 | |||
49 | /** @brief USART1 serial driver identifier.*/ | ||
50 | #if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__) | ||
51 | #ifndef __MSP430_HAS_EUSCI_A1__ | ||
52 | #error "Cannot find USCI module to use for SD1" | ||
53 | #endif | ||
54 | #ifdef MSP430X_USCI_A1_USED | ||
55 | #error "USCI module A1 already in use - USART1 not available" | ||
56 | #endif | ||
57 | SerialDriver SD1; | ||
58 | #define MSP430X_USCI_A1_USED | ||
59 | #endif | ||
60 | |||
61 | /** @brief USART2 serial driver identifier.*/ | ||
62 | #if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__) | ||
63 | #ifndef __MSP430_HAS_EUSCI_A2__ | ||
64 | #error "Cannot find USCI module to use for SD2" | ||
65 | #endif | ||
66 | #ifdef MSP430X_USCI_A2_USED | ||
67 | #error "USCI module A2 already in use - USART2 not available" | ||
68 | #endif | ||
69 | SerialDriver SD2; | ||
70 | #define MSP430X_USCI_A2_USED | ||
71 | #endif | ||
72 | |||
73 | /** @brief USART3 serial driver identifier.*/ | ||
74 | #if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__) | ||
75 | #ifndef __MSP430_HAS_EUSCI_A3__ | ||
76 | #error "Cannot find USCI module to use for SD3" | ||
77 | #endif | ||
78 | #ifdef MSP430X_USCI_A3_USED | ||
79 | #error "USCI module A3 already in use - USART3 not available" | ||
80 | #endif | ||
81 | SerialDriver SD3; | ||
82 | #define MSP430X_USCI_A3_USED | ||
83 | #endif | ||
84 | |||
85 | /*===========================================================================*/ | ||
86 | /* Driver local variables and types. */ | ||
87 | /*===========================================================================*/ | ||
88 | |||
89 | /** | ||
90 | * @brief Driver default configuration. | ||
91 | */ | ||
92 | static const SerialConfig default_config = { SERIAL_DEFAULT_BITRATE }; | ||
93 | |||
94 | /*===========================================================================*/ | ||
95 | /* Driver local functions. */ | ||
96 | /*===========================================================================*/ | ||
97 | |||
98 | /** | ||
99 | * @brief UCBRS calculation. | ||
100 | * @details This function calculates the UCBRS value for oversampled baud | ||
101 | * rates. | ||
102 | * | ||
103 | * @param[in] frac Fractional part of baud rate division, times 10000. | ||
104 | */ | ||
105 | static uint8_t UCBRS(uint16_t frac) { | ||
106 | /* TODO there must be a better way */ | ||
107 | if (frac < 529) | ||
108 | return 0x00; | ||
109 | else if (frac < 715) | ||
110 | return 0x01; | ||
111 | else if (frac < 835) | ||
112 | return 0x02; | ||
113 | else if (frac < 1001) | ||
114 | return 0x04; | ||
115 | else if (frac < 1252) | ||
116 | return 0x08; | ||
117 | else if (frac < 1430) | ||
118 | return 0x10; | ||
119 | else if (frac < 1670) | ||
120 | return 0x20; | ||
121 | else if (frac < 2147) | ||
122 | return 0x11; | ||
123 | else if (frac < 2224) | ||
124 | return 0x21; | ||
125 | else if (frac < 2503) | ||
126 | return 0x22; | ||
127 | else if (frac < 3000) | ||
128 | return 0x44; | ||
129 | else if (frac < 3335) | ||
130 | return 0x25; | ||
131 | else if (frac < 3575) | ||
132 | return 0x49; | ||
133 | else if (frac < 3753) | ||
134 | return 0x4A; | ||
135 | else if (frac < 4003) | ||
136 | return 0x52; | ||
137 | else if (frac < 4286) | ||
138 | return 0x92; | ||
139 | else if (frac < 4378) | ||
140 | return 0x53; | ||
141 | else if (frac < 5002) | ||
142 | return 0x55; | ||
143 | else if (frac < 5715) | ||
144 | return 0xAA; | ||
145 | else if (frac < 6003) | ||
146 | return 0x6B; | ||
147 | else if (frac < 6254) | ||
148 | return 0xAD; | ||
149 | else if (frac < 6432) | ||
150 | return 0xB5; | ||
151 | else if (frac < 6667) | ||
152 | return 0xB6; | ||
153 | else if (frac < 7001) | ||
154 | return 0xD6; | ||
155 | else if (frac < 7147) | ||
156 | return 0xB7; | ||
157 | else if (frac < 7503) | ||
158 | return 0xBB; | ||
159 | else if (frac < 7861) | ||
160 | return 0xDD; | ||
161 | else if (frac < 8004) | ||
162 | return 0xED; | ||
163 | else if (frac < 8333) | ||
164 | return 0xEE; | ||
165 | else if (frac < 8464) | ||
166 | return 0xBF; | ||
167 | else if (frac < 8572) | ||
168 | return 0xDF; | ||
169 | else if (frac < 8751) | ||
170 | return 0xEF; | ||
171 | else if (frac < 9004) | ||
172 | return 0xF7; | ||
173 | else if (frac < 9170) | ||
174 | return 0xFB; | ||
175 | else if (frac < 9288) | ||
176 | return 0xFD; | ||
177 | else | ||
178 | return 0xFE; | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * @brief Modulation control word calculator. | ||
183 | * @details This function calculates the modulation control word from the | ||
184 | * input clock frequency and the requested baud rate. | ||
185 | * | ||
186 | * @param[in] baud Requested baud rate | ||
187 | * @param[in] freq Frequency of the clock driving the USCI module | ||
188 | */ | ||
189 | static uint16_t UCAxMCTLW(uint32_t baud, uint32_t freq) { | ||
190 | |||
191 | uint16_t n = freq / baud; | ||
192 | /*uint16_t frac = (freq * 10000 / baud) - ((freq / baud) * 10000);*/ | ||
193 | uint16_t frac = (freq - (n * baud)) * 10000 / baud; | ||
194 | if (n > 16) { | ||
195 | while (n > 16) { | ||
196 | n -= 16; | ||
197 | } | ||
198 | return (UCBRS(frac) << 8) | (n << 4) | UCOS16; | ||
199 | } | ||
200 | return UCBRS(frac) << 8; | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * @brief UCBRW calculation. | ||
205 | * @details This function calculates the UCBRW value for all baud | ||
206 | * rates. | ||
207 | * | ||
208 | * @param[in] baud Requested baud rate | ||
209 | * @param[in] freq Frequency of the clock driving the USCI module | ||
210 | */ | ||
211 | static uint16_t UCAxBRW(uint32_t baud, uint32_t freq) { | ||
212 | uint16_t n = freq / baud; | ||
213 | if (n > 16) { | ||
214 | return n >> 4; | ||
215 | } | ||
216 | return n; | ||
217 | } | ||
218 | |||
219 | #if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__) | ||
220 | static void usart0_init(const SerialConfig * config) { | ||
221 | UCA0BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ); | ||
222 | UCA0MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART0_CLK_FREQ); | ||
223 | UCA0STATW = 0; | ||
224 | UCA0ABCTL = 0; | ||
225 | UCA0IRCTL = 0; | ||
226 | UCA0CTLW0 = (MSP430X_USART0_PARITY << 14) | (MSP430X_USART0_ORDER << 13) | | ||
227 | (MSP430X_USART0_SIZE << 12) | (MSP430X_USART0_STOP << 11) | | ||
228 | (MSP430X_USART0_UCSSEL); | ||
229 | UCA0IE = UCRXIE; | ||
230 | } | ||
231 | #endif | ||
232 | |||
233 | #if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__) | ||
234 | static void usart1_init(const SerialConfig * config) { | ||
235 | UCA1BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ); | ||
236 | UCA1MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART1_CLK_FREQ); | ||
237 | UCA1STATW = 0; | ||
238 | UCA1ABCTL = 0; | ||
239 | UCA1IRCTL = 0; | ||
240 | UCA1CTLW0 = (MSP430X_USART1_PARITY << 14) | (MSP430X_USART1_ORDER << 13) | | ||
241 | (MSP430X_USART1_SIZE << 12) | (MSP430X_USART1_STOP << 11) | | ||
242 | (MSP430X_USART1_UCSSEL); | ||
243 | UCA1IE = UCRXIE; | ||
244 | } | ||
245 | #endif | ||
246 | |||
247 | #if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__) | ||
248 | static void usart2_init(const SerialConfig * config) { | ||
249 | UCA2BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART2_CLK_FREQ); | ||
250 | UCA2MCTLW = UCAxMCTLW(config->sc_bitrate); | ||
251 | UCA2STATW = 0; | ||
252 | UCA2ABCTL = 0; | ||
253 | UCA2IRCTL = 0; | ||
254 | UCA2CTLW0 = (MSP430X_USART2_PARITY << 14) | (MSP430X_USART2_ORDER << 13) | | ||
255 | (MSP430X_USART2_SIZE << 12) | (MSP430X_USART2_STOP << 11) | | ||
256 | (MSP430X_USART2_UCSSEL); | ||
257 | UCA2IE = UCRXIE; | ||
258 | } | ||
259 | #endif | ||
260 | |||
261 | #if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__) | ||
262 | static void usart3_init(const SerialConfig * config) { | ||
263 | UCA3BRW = UCAxBRW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ); | ||
264 | UCA3MCTLW = UCAxMCTLW(config->sc_bitrate, MSP430X_USART3_CLK_FREQ); | ||
265 | UCA3STATW = 0; | ||
266 | UCA3ABCTL = 0; | ||
267 | UCA3IRCTL = 0; | ||
268 | UCA3CTLW0 = (MSP430X_USART3_PARITY << 14) | (MSP430X_USART3_ORDER << 13) | | ||
269 | (MSP430X_USART3_SIZE << 12) | (MSP430X_USART3_STOP << 11) | | ||
270 | (MSP430X_USART3_UCSSEL); | ||
271 | UCA3IE = UCRXIE; | ||
272 | } | ||
273 | #endif | ||
274 | |||
275 | #if (MSP430X_SERIAL_USE_USART0 == TRUE) || defined(__DOXYGEN__) | ||
276 | static void notify0(io_queue_t * qp) { | ||
277 | |||
278 | (void)qp; | ||
279 | UCA0IE |= UCTXIE; | ||
280 | } | ||
281 | #endif | ||
282 | |||
283 | #if (MSP430X_SERIAL_USE_USART1 == TRUE) || defined(__DOXYGEN__) | ||
284 | static void notify1(io_queue_t * qp) { | ||
285 | |||
286 | (void)qp; | ||
287 | UCA1IE |= UCTXIE; | ||
288 | } | ||
289 | #endif | ||
290 | |||
291 | #if (MSP430X_SERIAL_USE_USART2 == TRUE) || defined(__DOXYGEN__) | ||
292 | static void notify2(io_queue_t * qp) { | ||
293 | |||
294 | (void)qp; | ||
295 | UCA2IE |= UCTXIE; | ||
296 | } | ||
297 | #endif | ||
298 | |||
299 | #if (MSP430X_SERIAL_USE_USART3 == TRUE) || defined(__DOXYGEN__) | ||
300 | static void notify3(io_queue_t * qp) { | ||
301 | |||
302 | (void)qp; | ||
303 | UCA3IE |= UCTXIE; | ||
304 | } | ||
305 | #endif | ||
306 | |||
307 | /** | ||
308 | * @brief Error handling routine. | ||
309 | * | ||
310 | * @param[in] sra USCI status register containing errors | ||
311 | * @param[in] sdp pointer to a @p SerialDriver object | ||
312 | */ | ||
313 | static void set_error(uint16_t sra, SerialDriver * sdp) { | ||
314 | eventflags_t sts = 0; | ||
315 | |||
316 | if (sra & UCOE) | ||
317 | sts |= SD_OVERRUN_ERROR; | ||
318 | if (sra & UCPE) | ||
319 | sts |= SD_PARITY_ERROR; | ||
320 | if (sra & UCFE) | ||
321 | sts |= SD_FRAMING_ERROR; | ||
322 | osalSysLockFromISR(); | ||
323 | chnAddFlagsI(sdp, sts); | ||
324 | osalSysUnlockFromISR(); | ||
325 | } | ||
326 | |||
327 | /*===========================================================================*/ | ||
328 | /* Driver interrupt handlers. */ | ||
329 | /*===========================================================================*/ | ||
330 | |||
331 | #if MSP430X_SERIAL_USE_USART0 || defined(__DOXYGEN__) | ||
332 | /** | ||
333 | * @brief USART0 interrupt handler. | ||
334 | * | ||
335 | * @isr | ||
336 | */ | ||
337 | PORT_IRQ_HANDLER(USCI_A0_VECTOR) { | ||
338 | msg_t b; | ||
339 | |||
340 | OSAL_IRQ_PROLOGUE(); | ||
341 | |||
342 | switch (__even_in_range(UCA0IV, USCI_UART_UCTXCPTIFG)) { | ||
343 | case USCI_UART_UCRXIFG: /* RX interrupt */ | ||
344 | |||
345 | /* Detect errors */ | ||
346 | if (UCA0STATW & UCRXERR) | ||
347 | set_error(UCA0STATW, &SD0); | ||
348 | |||
349 | /* Data available */ | ||
350 | osalSysLockFromISR(); | ||
351 | sdIncomingDataI(&SD0, UCA0RXBUF); | ||
352 | osalSysUnlockFromISR(); | ||
353 | break; | ||
354 | |||
355 | case USCI_UART_UCTXIFG: /* TX interrupt */ | ||
356 | |||
357 | /* Transmission buffer empty */ | ||
358 | osalSysLockFromISR(); | ||
359 | b = sdRequestDataI(&SD0); | ||
360 | if (b < Q_OK) { | ||
361 | chnAddFlagsI(&SD0, CHN_OUTPUT_EMPTY); | ||
362 | UCA0IE = (UCA0IE & ~UCTXIE) | UCTXCPTIE; | ||
363 | UCA0IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ | ||
364 | } | ||
365 | else | ||
366 | UCA0TXBUF = b; | ||
367 | osalSysUnlockFromISR(); | ||
368 | break; | ||
369 | |||
370 | case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ | ||
371 | |||
372 | /* Physical transmission end */ | ||
373 | osalSysLockFromISR(); | ||
374 | if (oqIsEmptyI(&SD0.oqueue)) | ||
375 | chnAddFlagsI(&SD0, CHN_TRANSMISSION_END); | ||
376 | UCA0IE &= ~UCTXCPTIE; | ||
377 | osalSysUnlockFromISR(); | ||
378 | break; | ||
379 | |||
380 | default: /* other interrupts */ | ||
381 | osalDbgAssert(false, "unhandled serial interrupt"); | ||
382 | break; | ||
383 | } | ||
384 | |||
385 | OSAL_IRQ_EPILOGUE(); | ||
386 | } | ||
387 | #endif | ||
388 | |||
389 | #if MSP430X_SERIAL_USE_USART1 || defined(__DOXYGEN__) | ||
390 | /** | ||
391 | * @brief USART1 interrupt handler. | ||
392 | * | ||
393 | * @isr | ||
394 | */ | ||
395 | PORT_IRQ_HANDLER(USCI_A1_VECTOR) { | ||
396 | msg_t b; | ||
397 | |||
398 | OSAL_IRQ_PROLOGUE(); | ||
399 | |||
400 | switch (__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG)) { | ||
401 | case USCI_UART_UCRXIFG: /* RX interrupt */ | ||
402 | |||
403 | /* Detect errors */ | ||
404 | if (UCA1STATW & UCRXERR) | ||
405 | set_error(UCA1STATW, &SD1); | ||
406 | |||
407 | /* Data available */ | ||
408 | osalSysLockFromISR(); | ||
409 | sdIncomingDataI(&SD1, UCA1RXBUF); | ||
410 | osalSysUnlockFromISR(); | ||
411 | break; | ||
412 | |||
413 | case USCI_UART_UCTXIFG: /* TX interrupt */ | ||
414 | |||
415 | /* Transmission buffer empty */ | ||
416 | osalSysLockFromISR(); | ||
417 | b = sdRequestDataI(&SD1); | ||
418 | if (b < Q_OK) { | ||
419 | chnAddFlagsI(&SD1, CHN_OUTPUT_EMPTY); | ||
420 | UCA1IE = (UCA1IE & ~UCTXIE) | UCTXCPTIE; | ||
421 | UCA1IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ | ||
422 | } | ||
423 | else | ||
424 | UCA1TXBUF = b; | ||
425 | osalSysUnlockFromISR(); | ||
426 | break; | ||
427 | |||
428 | case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ | ||
429 | |||
430 | /* Physical transmission end */ | ||
431 | osalSysLockFromISR(); | ||
432 | if (oqIsEmptyI(&SD1.oqueue)) | ||
433 | chnAddFlagsI(&SD1, CHN_TRANSMISSION_END); | ||
434 | UCA1IE &= ~UCTXCPTIE; | ||
435 | osalSysUnlockFromISR(); | ||
436 | break; | ||
437 | |||
438 | default: /* other interrupts */ | ||
439 | osalDbgAssert(false, "unhandled serial interrupt"); | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | OSAL_IRQ_EPILOGUE(); | ||
444 | } | ||
445 | #endif | ||
446 | |||
447 | #if MSP430X_SERIAL_USE_USART2 || defined(__DOXYGEN__) | ||
448 | /** | ||
449 | * @brief USART2 interrupt handler. | ||
450 | * | ||
451 | * @isr | ||
452 | */ | ||
453 | PORT_IRQ_HANDLER(USCI_A2_VECTOR) { | ||
454 | msg_t b; | ||
455 | |||
456 | OSAL_IRQ_PROLOGUE(); | ||
457 | |||
458 | switch (__even_in_range(UCA2IV, USCI_UART_UCTXCPTIFG)) { | ||
459 | case USCI_UART_UCRXIFG: /* RX interrupt */ | ||
460 | |||
461 | /* Detect errors */ | ||
462 | if (UCA2STATW & UCRXERR) | ||
463 | set_error(UCA2STATW, &SD2); | ||
464 | |||
465 | /* Data available */ | ||
466 | osalSysLockFromISR(); | ||
467 | sdIncomingDataI(&SD2, UCA2RXBUF); | ||
468 | osalSysUnlockFromISR(); | ||
469 | break; | ||
470 | |||
471 | case USCI_UART_UCTXIFG: /* TX interrupt */ | ||
472 | |||
473 | /* Transmission buffer empty */ | ||
474 | osalSysLockFromISR(); | ||
475 | b = sdRequestDataI(&SD2); | ||
476 | if (b < Q_OK) { | ||
477 | chnAddFlagsI(&SD2, CHN_OUTPUT_EMPTY); | ||
478 | UCA2IE = (UCA2IE & ~UCTXIE) | UCTXCPTIE; | ||
479 | UCA2IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ | ||
480 | } | ||
481 | else | ||
482 | UCA2TXBUF = b; | ||
483 | osalSysUnlockFromISR(); | ||
484 | break; | ||
485 | |||
486 | case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ | ||
487 | |||
488 | /* Physical transmission end */ | ||
489 | osalSysLockFromISR(); | ||
490 | if (oqIsEmptyI(&SD2.oqueue)) | ||
491 | chnAddFlagsI(&SD2, CHN_TRANSMISSION_END); | ||
492 | UCA2IE &= ~UCTXCPTIE; | ||
493 | osalSysUnlockFromISR(); | ||
494 | break; | ||
495 | |||
496 | default: /* other interrupts */ | ||
497 | osalDbgAssert(false, "unhandled serial interrupt"); | ||
498 | break; | ||
499 | } | ||
500 | |||
501 | OSAL_IRQ_EPILOGUE(); | ||
502 | } | ||
503 | #endif | ||
504 | |||
505 | #if MSP430X_SERIAL_USE_USART3 || defined(__DOXYGEN__) | ||
506 | /** | ||
507 | * @brief USART3 interrupt handler. | ||
508 | * | ||
509 | * @isr | ||
510 | */ | ||
511 | PORT_IRQ_HANDLER(USCI_A3_VECTOR) { | ||
512 | msg_t b; | ||
513 | |||
514 | OSAL_IRQ_PROLOGUE(); | ||
515 | |||
516 | switch (__even_in_range(UCA3IV, USCI_UART_UCTXCPTIFG)) { | ||
517 | case USCI_UART_UCRXIFG: /* RX interrupt */ | ||
518 | |||
519 | /* Detect errors */ | ||
520 | if (UCA3STATW & UCRXERR) | ||
521 | set_error(UCA3STATW, &SD3); | ||
522 | |||
523 | /* Data available */ | ||
524 | osalSysLockFromISR(); | ||
525 | sdIncomingDataI(&SD3, UCA3RXBUF); | ||
526 | osalSysUnlockFromISR(); | ||
527 | break; | ||
528 | |||
529 | case USCI_UART_UCTXIFG: /* TX interrupt */ | ||
530 | |||
531 | /* Transmission buffer empty */ | ||
532 | osalSysLockFromISR(); | ||
533 | b = sdRequestDataI(&SD3); | ||
534 | if (b < Q_OK) { | ||
535 | chnAddFlagsI(&SD3, CHN_OUTPUT_EMPTY); | ||
536 | UCA3IE = (UCA3IE & ~UCTXIE) | UCTXCPTIE; | ||
537 | UCA3IFG |= UCTXIFG; /* If we don't write to TXBUF, IFG won't get set */ | ||
538 | } | ||
539 | else | ||
540 | UCA3TXBUF = b; | ||
541 | osalSysUnlockFromISR(); | ||
542 | break; | ||
543 | |||
544 | case USCI_UART_UCTXCPTIFG: /* TX complete interrupt */ | ||
545 | |||
546 | /* Physical transmission end */ | ||
547 | osalSysLockFromISR(); | ||
548 | if (oqIsEmptyI(&SD3.oqueue)) | ||
549 | chnAddFlagsI(&SD3, CHN_TRANSMISSION_END); | ||
550 | UCA3IE &= ~UCTXCPTIE; | ||
551 | osalSysUnlockFromISR(); | ||
552 | break; | ||
553 | |||
554 | default: /* other interrupts */ | ||
555 | osalDbgAssert(false, "unhandled serial interrupt"); | ||
556 | break; | ||
557 | } | ||
558 | |||
559 | OSAL_IRQ_EPILOGUE(); | ||
560 | } | ||
561 | #endif | ||
562 | |||
563 | /*===========================================================================*/ | ||
564 | /* Driver exported functions. */ | ||
565 | /*===========================================================================*/ | ||
566 | |||
567 | /** | ||
568 | * @brief Low level serial driver initialization. | ||
569 | * | ||
570 | * @notapi | ||
571 | */ | ||
572 | void sd_lld_init(void) { | ||
573 | |||
574 | #if MSP430X_SERIAL_USE_USART0 == TRUE | ||
575 | sdObjectInit(&SD0, NULL, notify0); | ||
576 | #endif | ||
577 | |||
578 | #if MSP430X_SERIAL_USE_USART1 == TRUE | ||
579 | sdObjectInit(&SD1, NULL, notify1); | ||
580 | #endif | ||
581 | |||
582 | #if MSP430X_SERIAL_USE_USART2 == TRUE | ||
583 | sdObjectInit(&SD2, NULL, notify2); | ||
584 | #endif | ||
585 | |||
586 | #if MSP430X_SERIAL_USE_USART3 == TRUE | ||
587 | sdObjectInit(&SD3, NULL, notify3); | ||
588 | #endif | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * @brief Low level serial driver configuration and (re)start. | ||
593 | * | ||
594 | * @param[in] sdp pointer to a @p SerialDriver object | ||
595 | * @param[in] config the architecture-dependent serial driver configuration. | ||
596 | * If this parameter is set to @p NULL then a default | ||
597 | * configuration is used. | ||
598 | * | ||
599 | * @notapi | ||
600 | */ | ||
601 | void sd_lld_start(SerialDriver * sdp, const SerialConfig * config) { | ||
602 | |||
603 | if (config == NULL) { | ||
604 | config = &default_config; | ||
605 | } | ||
606 | |||
607 | if (sdp->state == SD_STOP) { | ||
608 | #if MSP430X_SERIAL_USE_USART0 == TRUE | ||
609 | if (&SD0 == sdp) { | ||
610 | usart0_init(config); | ||
611 | } | ||
612 | #endif | ||
613 | #if MSP430X_SERIAL_USE_USART1 == TRUE | ||
614 | if (&SD1 == sdp) { | ||
615 | usart1_init(config); | ||
616 | } | ||
617 | #endif | ||
618 | #if MSP430X_SERIAL_USE_USART2 == TRUE | ||
619 | if (&SD2 == sdp) { | ||
620 | usart2_init(config); | ||
621 | } | ||
622 | #endif | ||
623 | #if MSP430X_SERIAL_USE_USART3 == TRUE | ||
624 | if (&SD3 == sdp) { | ||
625 | usart3_init(config); | ||
626 | } | ||
627 | #endif | ||
628 | } | ||
629 | } | ||
630 | |||
631 | /** | ||
632 | * @brief Low level serial driver stop. | ||
633 | * @details De-initializes the USART, stops the associated clock, resets the | ||
634 | * interrupt vector. | ||
635 | * | ||
636 | * @param[in] sdp pointer to a @p SerialDriver object | ||
637 | * | ||
638 | * @notapi | ||
639 | */ | ||
640 | void sd_lld_stop(SerialDriver * sdp) { | ||
641 | |||
642 | if (sdp->state == SD_READY) { | ||
643 | #if MSP430X_SERIAL_USE_USART0 == TRUE | ||
644 | if (&SD0 == sdp) { | ||
645 | UCA0CTLW0 = UCSWRST; | ||
646 | } | ||
647 | #endif | ||
648 | #if MSP430X_SERIAL_USE_USART1 == TRUE | ||
649 | if (&SD1 == sdp) { | ||
650 | UCA1CTLW0 = UCSWRST; | ||
651 | } | ||
652 | #endif | ||
653 | #if MSP430X_SERIAL_USE_USART2 == TRUE | ||
654 | if (&SD2 == sdp) { | ||
655 | UCA2CTLW0 = UCSWRST; | ||
656 | } | ||
657 | #endif | ||
658 | #if MSP430X_SERIAL_USE_USART3 == TRUE | ||
659 | if (&SD3 == sdp) { | ||
660 | UCA3CTLW0 = UCSWRST; | ||
661 | } | ||
662 | #endif | ||
663 | } | ||
664 | } | ||
665 | |||
666 | #endif /* HAL_USE_SERIAL == TRUE */ | ||
667 | |||
668 | /** @} */ | ||