ChibiOS/RT
2.5.1
serial_lld.c
Go to the documentation of this file.
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 /** @} */