|
ChibiOS/RT
2.5.1 |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, 00003 2011,2012 Giovanni Di Sirio. 00004 00005 This file is part of ChibiOS/RT. 00006 00007 ChibiOS/RT is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 ChibiOS/RT is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 /** 00022 * @file STM8S/serial_lld.c 00023 * @brief STM8S low level serial driver code. 00024 * 00025 * @addtogroup SERIAL 00026 * @{ 00027 */ 00028 00029 #include "ch.h" 00030 #include "hal.h" 00031 00032 #if HAL_USE_SERIAL || defined(__DOXYGEN__) 00033 00034 /*===========================================================================*/ 00035 /* Driver exported variables. */ 00036 /*===========================================================================*/ 00037 00038 /** 00039 * @brief UART1 serial driver identifier. 00040 */ 00041 #if STM8S_SERIAL_USE_UART1 || defined(__DOXYGEN__) 00042 SerialDriver SD1; 00043 #endif 00044 00045 /** 00046 * @brief UART2 serial driver identifier. 00047 */ 00048 #if STM8S_SERIAL_USE_UART2 || defined(__DOXYGEN__) 00049 SerialDriver SD2; 00050 #endif 00051 00052 /** 00053 * @brief UART3 serial driver identifier. 00054 */ 00055 #if STM8S_SERIAL_USE_UART3 || defined(__DOXYGEN__) 00056 SerialDriver SD3; 00057 #endif 00058 00059 /*===========================================================================*/ 00060 /* Driver local variables. */ 00061 /*===========================================================================*/ 00062 00063 /** 00064 * @brief Driver default configuration. 00065 */ 00066 static ROMCONST SerialConfig default_config = { 00067 BRR(SERIAL_DEFAULT_BITRATE), 00068 SD_MODE_PARITY_NONE | SD_MODE_STOP_1 00069 }; 00070 00071 /*===========================================================================*/ 00072 /* Driver local functions. */ 00073 /*===========================================================================*/ 00074 00075 static void set_error(SerialDriver *sdp, uint8_t sr) { 00076 flagsmask_t sts = 0; 00077 00078 /* Note, SR register bit definitions are equal for all UARTs so using 00079 the UART1 definitions is fine.*/ 00080 if (sr & UART1_SR_OR) 00081 sts |= SD_OVERRUN_ERROR; 00082 if (sr & UART1_SR_NF) 00083 sts |= SD_NOISE_ERROR; 00084 if (sr & UART1_SR_FE) 00085 sts |= SD_FRAMING_ERROR; 00086 if (sr & UART1_SR_PE) 00087 sts |= SD_PARITY_ERROR; 00088 chSysLockFromIsr(); 00089 chnAddFlagsI(sdp, sts); 00090 chSysUnlockFromIsr(); 00091 } 00092 00093 #if STM8S_SERIAL_USE_UART1 || defined(__DOXYGEN__) 00094 static void notify1(GenericQueue *qp) { 00095 00096 (void)qp; 00097 UART1->CR2 |= UART1_CR2_TIEN; 00098 } 00099 00100 /** 00101 * @brief UART1 initialization. 00102 * 00103 * @param[in] config architecture-dependent serial driver configuration 00104 */ 00105 static void uart1_init(const SerialConfig *config) { 00106 00107 UART1->BRR2 = (uint8_t)(((uint8_t)(config->sc_brr >> 8) & (uint8_t)0xF0) | 00108 ((uint8_t)config->sc_brr & (uint8_t)0x0F)); 00109 UART1->BRR1 = (uint8_t)(config->sc_brr >> 4); 00110 UART1->CR1 = (uint8_t)(config->sc_mode & 00111 SD_MODE_PARITY); /* PIEN included. */ 00112 UART1->CR2 = UART1_CR2_RIEN | UART1_CR2_TEN | UART1_CR2_REN; 00113 UART1->CR3 = (uint8_t)(config->sc_mode & SD_MODE_STOP); 00114 UART1->CR4 = 0; 00115 UART1->CR5 = 0; 00116 UART1->PSCR = 1; 00117 (void)UART1->SR; 00118 (void)UART1->DR; 00119 } 00120 00121 /** 00122 * @brief UART1 de-initialization. 00123 */ 00124 static void uart1_deinit(void) { 00125 00126 UART1->CR1 = UART1_CR1_UARTD; 00127 UART1->CR2 = 0; 00128 UART1->CR3 = 0; 00129 UART1->CR4 = 0; 00130 UART1->CR5 = 0; 00131 UART1->PSCR = 0; 00132 } 00133 #endif /* STM8S_SERIAL_USE_UART1 */ 00134 00135 #if STM8S_SERIAL_USE_UART2 || defined(__DOXYGEN__) 00136 static void notify2(GenericQueue *qp) { 00137 00138 (void)qp; 00139 UART2->CR2 |= UART2_CR2_TIEN; 00140 } 00141 00142 /** 00143 * @brief UART2 initialization. 00144 * 00145 * @param[in] config architecture-dependent serial driver configuration 00146 */ 00147 static void uart2_init(const SerialConfig *config) { 00148 00149 UART2->BRR2 = (uint8_t)(((uint8_t)(config->sc_brr >> 8) & (uint8_t)0xF0) | 00150 ((uint8_t)config->sc_brr & (uint8_t)0x0F)); 00151 UART2->BRR1 = (uint8_t)(config->sc_brr >> 4); 00152 UART2->CR1 = (uint8_t)(config->sc_mode & 00153 SD_MODE_PARITY); /* PIEN included. */ 00154 UART2->CR2 = UART2_CR2_RIEN | UART2_CR2_TEN | UART2_CR2_REN; 00155 UART2->CR3 = (uint8_t)(config->sc_mode & SD_MODE_STOP); 00156 UART2->CR4 = 0; 00157 UART2->CR5 = 0; 00158 UART2->CR6 = 0; 00159 UART2->PSCR = 1; 00160 (void)UART2->SR; 00161 (void)UART2->DR; 00162 } 00163 00164 /** 00165 * @brief UART1 de-initialization. 00166 */ 00167 static void uart2_deinit(void) { 00168 00169 UART2->CR1 = UART2_CR1_UARTD; 00170 UART2->CR2 = 0; 00171 UART2->CR3 = 0; 00172 UART2->CR4 = 0; 00173 UART2->CR5 = 0; 00174 UART2->CR6 = 0; 00175 UART2->PSCR = 0; 00176 } 00177 #endif /* STM8S_SERIAL_USE_UART1 */ 00178 00179 #if STM8S_SERIAL_USE_UART3 || defined(__DOXYGEN__) 00180 static void notify3(GenericQueue *qp) { 00181 00182 (void)qp; 00183 UART3->CR2 |= UART3_CR2_TIEN; 00184 } 00185 00186 /** 00187 * @brief UART3 initialization. 00188 * 00189 * @param[in] config architecture-dependent serial driver configuration 00190 */ 00191 static void uart3_init(const SerialConfig *config) { 00192 00193 UART3->BRR2 = (uint8_t)(((uint8_t)(config->sc_brr >> 8) & (uint8_t)0xF0) | 00194 ((uint8_t)config->sc_brr & (uint8_t)0x0F)); 00195 UART3->BRR1 = (uint8_t)(config->sc_brr >> 4); 00196 UART3->CR1 = (uint8_t)(config->sc_mode & 00197 SD_MODE_PARITY); /* PIEN included. */ 00198 UART3->CR2 = UART3_CR2_RIEN | UART3_CR2_TEN | UART3_CR2_REN; 00199 UART3->CR3 = (uint8_t)(config->sc_mode & SD_MODE_STOP); 00200 UART3->CR4 = 0; 00201 UART3->CR6 = 0; 00202 (void)UART3->SR; 00203 (void)UART3->DR; 00204 } 00205 00206 /** 00207 * @brief UART3 de-initialization. 00208 */ 00209 static void uart3_deinit(void) { 00210 00211 UART3->CR1 = UART3_CR1_UARTD; 00212 UART3->CR2 = 0; 00213 UART3->CR3 = 0; 00214 UART3->CR4 = 0; 00215 UART3->CR6 = 0; 00216 } 00217 #endif /* STM8S_SERIAL_USE_UART3 */ 00218 00219 /*===========================================================================*/ 00220 /* Driver interrupt handlers. */ 00221 /*===========================================================================*/ 00222 00223 #if STM8S_SERIAL_USE_UART1 || defined(__DOXYGEN__) 00224 /** 00225 * @brief IRQ 17 service routine. 00226 * 00227 * @isr 00228 */ 00229 CH_IRQ_HANDLER(17) { 00230 msg_t b; 00231 00232 CH_IRQ_PROLOGUE(); 00233 00234 chSysLockFromIsr(); 00235 b = sdRequestDataI(&SD1); 00236 chSysUnlockFromIsr(); 00237 if (b < Q_OK) 00238 UART1->CR2 &= (uint8_t)~UART1_CR2_TIEN; 00239 else 00240 UART1->DR = (uint8_t)b; 00241 00242 CH_IRQ_EPILOGUE(); 00243 } 00244 00245 /** 00246 * @brief IRQ 18 service routine. 00247 * 00248 * @isr 00249 */ 00250 CH_IRQ_HANDLER(18) { 00251 uint8_t sr = UART1->SR; 00252 00253 CH_IRQ_PROLOGUE(); 00254 00255 if ((sr = UART1->SR) & (UART1_SR_OR | UART1_SR_NF | 00256 UART1_SR_FE | UART1_SR_PE)) 00257 set_error(&SD1, sr); 00258 chSysLockFromIsr(); 00259 sdIncomingDataI(&SD1, UART1->DR); 00260 chSysUnlockFromIsr(); 00261 00262 CH_IRQ_EPILOGUE(); 00263 } 00264 #endif /* STM8S_SERIAL_USE_UART1 */ 00265 00266 #if STM8S_SERIAL_USE_UART2 || defined(__DOXYGEN__) 00267 /** 00268 * @brief IRQ 20 service routine. 00269 * 00270 * @isr 00271 */ 00272 CH_IRQ_HANDLER(20) { 00273 msg_t b; 00274 00275 CH_IRQ_PROLOGUE(); 00276 00277 chSysLockFromIsr(); 00278 b = sdRequestDataI(&SD2); 00279 chSysUnlockFromIsr(); 00280 if (b < Q_OK) 00281 UART2->CR2 &= (uint8_t)~UART2_CR2_TIEN; 00282 else 00283 UART2->DR = (uint8_t)b; 00284 00285 CH_IRQ_EPILOGUE(); 00286 } 00287 00288 /** 00289 * @brief IRQ 21 service routine. 00290 * 00291 * @isr 00292 */ 00293 CH_IRQ_HANDLER(21) { 00294 uint8_t sr = UART2->SR; 00295 00296 CH_IRQ_PROLOGUE(); 00297 00298 if ((sr = UART2->SR) & (UART2_SR_OR | UART2_SR_NF | 00299 UART2_SR_FE | UART2_SR_PE)) 00300 set_error(&SD2, sr); 00301 chSysLockFromIsr(); 00302 sdIncomingDataI(&SD2, UART2->DR); 00303 chSysUnlockFromIsr(); 00304 00305 CH_IRQ_EPILOGUE(); 00306 } 00307 #endif /* STM8S_SERIAL_USE_UART2 */ 00308 00309 #if STM8S_SERIAL_USE_UART3 || defined(__DOXYGEN__) 00310 /** 00311 * @brief IRQ 20 service routine. 00312 * 00313 * @isr 00314 */ 00315 CH_IRQ_HANDLER(20) { 00316 msg_t b; 00317 00318 CH_IRQ_PROLOGUE(); 00319 00320 chSysLockFromIsr(); 00321 b = sdRequestDataI(&SD3); 00322 chSysUnlockFromIsr(); 00323 if (b < Q_OK) 00324 UART3->CR2 &= (uint8_t)~UART3_CR2_TIEN; 00325 else 00326 UART3->DR = (uint8_t)b; 00327 00328 CH_IRQ_EPILOGUE(); 00329 } 00330 00331 /** 00332 * @brief IRQ 21 service routine. 00333 * 00334 * @isr 00335 */ 00336 CH_IRQ_HANDLER(21) { 00337 uint8_t sr = UART3->SR; 00338 00339 CH_IRQ_PROLOGUE(); 00340 00341 if ((sr = UART3->SR) & (UART3_SR_OR | UART3_SR_NF | 00342 UART3_SR_FE | UART3_SR_PE)) 00343 set_error(&SD3, sr); 00344 chSysLockFromIsr(); 00345 sdIncomingDataI(&SD3, UART3->DR); 00346 chSysUnlockFromIsr(); 00347 00348 CH_IRQ_EPILOGUE(); 00349 } 00350 #endif /* STM8S_SERIAL_USE_UART3 */ 00351 00352 /*===========================================================================*/ 00353 /* Driver exported functions. */ 00354 /*===========================================================================*/ 00355 00356 /** 00357 * @brief Low level serial driver initialization. 00358 * 00359 * @notapi 00360 */ 00361 void sd_lld_init(void) { 00362 00363 #if STM8S_SERIAL_USE_UART1 00364 sdObjectInit(&SD1, NULL, notify1); 00365 CLK->PCKENR1 |= CLK_PCKENR1_UART1; /* PCKEN12, clock source. */ 00366 UART1->CR1 = UART1_CR1_UARTD; /* UARTD (low power). */ 00367 #endif 00368 00369 #if STM8S_SERIAL_USE_UART2 00370 sdObjectInit(&SD2, NULL, notify2); 00371 CLK->PCKENR1 |= CLK_PCKENR1_UART2; /* PCKEN13, clock source. */ 00372 UART2->CR1 = UART2_CR1_UARTD; /* UARTD (low power). */ 00373 #endif 00374 00375 #if STM8S_SERIAL_USE_UART3 00376 sdObjectInit(&SD3, NULL, notify3); 00377 CLK->PCKENR1 |= CLK_PCKENR1_UART3; /* PCKEN13, clock source. */ 00378 UART3->CR1 = UART3_CR1_UARTD; /* UARTD (low power). */ 00379 #endif 00380 } 00381 00382 /** 00383 * @brief Low level serial driver configuration and (re)start. 00384 * 00385 * @param[in] sdp pointer to a @p SerialDriver object 00386 * @param[in] config the architecture-dependent serial driver configuration. 00387 * If this parameter is set to @p NULL then a default 00388 * configuration is used. 00389 * 00390 * @notapi 00391 */ 00392 void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { 00393 00394 if (config == NULL) 00395 config = &default_config; 00396 00397 #if STM8S_SERIAL_USE_UART1 00398 if (&SD1 == sdp) { 00399 uart1_init(config); 00400 return; 00401 } 00402 #endif 00403 #if STM8S_SERIAL_USE_UART2 00404 if (&SD2 == sdp) { 00405 uart2_init(config); 00406 return; 00407 } 00408 #endif 00409 #if STM8S_SERIAL_USE_UART3 00410 if (&SD3 == sdp) { 00411 uart3_init(config); 00412 return; 00413 } 00414 #endif 00415 } 00416 00417 /** 00418 * @brief Low level serial driver stop. 00419 * @details De-initializes the USART, stops the associated clock, resets the 00420 * interrupt vector. 00421 * 00422 * @param[in] sdp pointer to a @p SerialDriver object 00423 * 00424 * @notapi 00425 */ 00426 void sd_lld_stop(SerialDriver *sdp) { 00427 00428 #if STM8S_SERIAL_USE_UART1 00429 if (&SD1 == sdp) { 00430 uart1_deinit(); 00431 return; 00432 } 00433 #endif 00434 #if STM8S_SERIAL_USE_UART2 00435 if (&SD2 == sdp) { 00436 uart2_deinit(); 00437 return; 00438 } 00439 #endif 00440 #if STM8S_SERIAL_USE_UART3 00441 if (&SD3 == sdp) { 00442 uart3_deinit(); 00443 return; 00444 } 00445 #endif 00446 } 00447 00448 #endif /* HAL_USE_SERIAL */ 00449 00450 /** @} */