2 * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /******************************************************************************
19 * @brief CSI Source File for usart Driver
22 ******************************************************************************/
25 #include "drv_usart.h"
29 #define ERR_USART(errno) (CSI_DRV_ERRNO_USART_BASE | errno)
32 * setting config may be accessed when the USART is not
33 * busy(USR[0]=0) and the DLAB bit(LCR[7]) is set.
36 #define WAIT_USART_IDLE(addr)\
38 int32_t timecount = 0; \
39 while ((addr->USR & USR_UART_BUSY) && (timecount < UART_BUSY_TIMEOUT)) {\
42 if (timecount >= UART_BUSY_TIMEOUT) {\
43 return ERR_USART(EDRV_TIMEOUT);\
47 #define USART_NULL_PARAM_CHK(para) \
50 return ERR_USART(EDRV_PARAMETER); \
57 usart_event_cb_t cb_event; ///< Event callback
59 uint32_t rx_total_num;
60 uint32_t tx_total_num;
63 volatile uint32_t rx_cnt;
64 volatile uint32_t tx_cnt;
65 volatile uint32_t tx_busy;
66 volatile uint32_t rx_busy;
69 extern int32_t target_usart_init(pin_t tx, pin_t rx, uint32_t *base, uint32_t *irq);
71 static dw_usart_priv_t usart_instance[CONFIG_USART_NUM];
73 static const usart_capabilities_t usart_capabilities = {
74 .asynchronous = 1, /* supports USART (Asynchronous) mode */
75 .synchronous_master = 0, /* supports Synchronous Master mode */
76 .synchronous_slave = 0, /* supports Synchronous Slave mode */
77 .single_wire = 0, /* supports USART Single-wire mode */
78 .event_tx_complete = 1, /* Transmit completed event */
79 .event_rx_timeout = 0, /* Signal receive character timeout event */
83 \brief set the bautrate of usart.
84 \param[in] addr usart base to operate.
86 \param[in] apbfreq the frequence of the apb.
89 static int32_t dw_usart_set_baudrate(dw_usart_reg_t *addr, uint32_t baudrate, uint32_t apbfreq)
91 WAIT_USART_IDLE(addr);
93 /* baudrate=(seriak clock freq)/(16*divisor); algorithm :rounding*/
94 uint32_t divisor = ((apbfreq * 10) / baudrate) >> 4;
96 if ((divisor % 10) >= 5) {
97 divisor = (divisor / 10) + 1;
99 divisor = divisor / 10;
102 addr->LCR |= LCR_SET_DLAB;
103 /* DLL and DLH is lower 8-bits and higher 8-bits of divisor.*/
104 addr->DLL = divisor & 0xff;
105 addr->DLH = (divisor >> 8) & 0xff;
107 * The DLAB must be cleared after the baudrate is setted
108 * to access other registers.
110 addr->LCR &= (~LCR_SET_DLAB);
116 \brief enable or disable parity.
117 \param[in] addr usart base to operate.
118 \param[in] parity ODD=8, EVEN=16, or NONE=0.
122 static int32_t dw_usart_set_parity(dw_usart_reg_t *addr, usart_parity_e parity)
124 WAIT_USART_IDLE(addr);
127 case USART_PARITY_NONE:
128 /*CLear the PEN bit(LCR[3]) to disable parity.*/
129 addr->LCR &= (~LCR_PARITY_ENABLE);
132 case USART_PARITY_ODD:
133 /* Set PEN and clear EPS(LCR[4]) to set the ODD parity. */
134 addr->LCR |= LCR_PARITY_ENABLE;
135 addr->LCR &= LCR_PARITY_ODD;
138 case USART_PARITY_EVEN:
139 /* Set PEN and EPS(LCR[4]) to set the EVEN parity.*/
140 addr->LCR |= LCR_PARITY_ENABLE;
141 addr->LCR |= LCR_PARITY_EVEN;
145 return ERR_USART(EDRV_USART_PARITY);
152 \brief set the stop bit.
153 \param[in] addr usart base to operate.
154 \param[in] stopbit two possible value: USART_STOP_BITS_1 and USART_STOP_BITS_2.
157 static int32_t dw_usart_set_stopbit(dw_usart_reg_t *addr, usart_stop_bits_e stopbit)
159 WAIT_USART_IDLE(addr);
162 case USART_STOP_BITS_1:
163 /* Clear the STOP bit to set 1 stop bit*/
164 addr->LCR &= LCR_STOP_BIT1;
167 case USART_STOP_BITS_2:
169 * If the STOP bit is set "1",we'd gotten 1.5 stop
170 * bits when DLS(LCR[1:0]) is zero, else 2 stop bits.
172 addr->LCR |= LCR_STOP_BIT2;
176 return ERR_USART(EDRV_USART_STOP_BITS);
183 \brief the transmit data length,and we have four choices:5, 6, 7, and 8 bits.
184 \param[in] addr usart base to operate.
185 \param[in] databits the data length that user decides.
188 static int32_t dw_usart_set_databit(dw_usart_reg_t *addr, usart_data_bits_e databits)
190 WAIT_USART_IDLE(addr);
191 /* The word size decides by the DLS bits(LCR[1:0]), and the
192 * corresponding relationship between them is:
201 case USART_DATA_BITS_5:
202 addr->LCR &= LCR_WORD_SIZE_5;
205 case USART_DATA_BITS_6:
207 addr->LCR |= LCR_WORD_SIZE_6;
210 case USART_DATA_BITS_7:
212 addr->LCR |= LCR_WORD_SIZE_7;
215 case USART_DATA_BITS_8:
216 addr->LCR |= LCR_WORD_SIZE_8;
220 return ERR_USART(EDRV_USART_DATA_BITS);
227 \brief get character in query mode.
228 \param[in] instance usart instance to operate.
229 \param[in] the pointer to the recieve charater.
232 int32_t csi_usart_getchar(usart_handle_t handle, uint8_t *ch)
234 dw_usart_priv_t *usart_priv = handle;
235 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
237 while (!(addr->LSR & LSR_DATA_READY));
245 \brief transmit character in query mode.
246 \param[in] instance usart instance to operate.
247 \param[in] ch the input charater
250 int32_t csi_usart_putchar(usart_handle_t handle, uint8_t ch)
252 dw_usart_priv_t *usart_priv = handle;
253 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
255 while ((!(addr->LSR & DW_LSR_TRANS_EMPTY)));
264 \brief interrupt service function for transmitter holding register empty.
265 \param[in] usart_priv usart private to operate.
267 static void dw_usart_intr_threshold_empty(dw_usart_priv_t *usart_priv)
269 if (usart_priv->tx_total_num == 0) {
273 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
275 addr->THR = *((uint8_t *)usart_priv->tx_buf);
276 usart_priv->tx_cnt++;
277 usart_priv->tx_buf++;
279 if (usart_priv->tx_cnt >= usart_priv->tx_total_num) {
280 addr->IER &= (~IER_THRE_INT_ENABLE);
282 while ((!(addr->LSR & DW_LSR_TEMT)));
284 usart_priv->tx_cnt = 0;
285 usart_priv->tx_busy = 0;
286 usart_priv->tx_buf = NULL;
287 usart_priv->tx_total_num = 0;
289 if (usart_priv->cb_event) {
290 usart_priv->cb_event(USART_EVENT_SEND_COMPLETE, usart_priv->cb_arg);
297 \brief interrupt service function for receiver data available.
298 \param[in] usart_priv usart private to operate.
300 static void dw_usart_intr_recv_data(dw_usart_priv_t *usart_priv)
302 if (usart_priv->cb_event && (usart_priv->rx_total_num == 0)) {
303 usart_priv->cb_event(USART_EVENT_RECEIVED, usart_priv->cb_arg);
307 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
308 uint8_t data = addr->RBR;
310 if ((usart_priv->rx_total_num == 0) || (usart_priv->rx_buf == NULL)) {
314 *((uint8_t *)usart_priv->rx_buf) = data;
315 usart_priv->rx_cnt++;
316 usart_priv->rx_buf++;
318 if (usart_priv->rx_cnt >= usart_priv->rx_total_num) {
319 usart_priv->rx_cnt = 0;
320 usart_priv->rx_buf = NULL;
321 usart_priv->rx_busy = 0;
322 usart_priv->rx_total_num = 0;
324 if (usart_priv->cb_event) {
325 usart_priv->cb_event(USART_EVENT_RECEIVE_COMPLETE, usart_priv->cb_arg);
332 \brief the interrupt service function.
333 \param[in] index of usart instance.
335 void dw_usart_irqhandler(int32_t idx)
337 dw_usart_priv_t *usart_priv = &usart_instance[idx];
338 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
340 uint8_t intr_state = addr->IIR & 0xf;
342 switch (intr_state) {
343 case DW_IIR_THR_EMPTY: /* interrupt source:transmitter holding register empty */
344 dw_usart_intr_threshold_empty(usart_priv);
347 case DW_IIR_RECV_DATA: /* interrupt source:receiver data available or receiver fifo trigger level reached */
348 dw_usart_intr_recv_data(usart_priv);
357 \brief Get driver capabilities.
358 \param[in] handle usart handle to operate.
359 \return \ref usart_capabilities_t
361 usart_capabilities_t csi_usart_get_capabilities(usart_handle_t handle)
363 return usart_capabilities;
367 \brief Initialize USART Interface. 1. Initializes the resources needed for the USART interface 2.registers event callback function
368 \param[in] usart pin of tx
369 \param[in] usart pin of rx
370 \param[in] cb_event Pointer to \ref usart_event_cb_t
371 \return return usart handle if success
373 usart_handle_t csi_usart_initialize(pin_t tx, pin_t rx, usart_event_cb_t cb_event, void *cb_arg)
378 int32_t idx = target_usart_init(tx, rx, &base, &irq);
380 if (idx < 0 || idx >= CONFIG_USART_NUM) {
384 dw_usart_priv_t *usart_priv = &usart_instance[idx];
385 usart_priv->base = base;
386 usart_priv->irq = irq;
387 usart_priv->cb_event = cb_event;
388 usart_priv->cb_arg = cb_arg;
390 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
392 /* enable received data available */
393 addr->IER = IER_RDA_INT_ENABLE;
394 drv_nvic_enable_irq(usart_priv->irq);
400 \brief De-initialize UART Interface. stops operation and releases the software resources used by the interface
401 \param[in] handle usart handle to operate.
404 int32_t csi_usart_uninitialize(usart_handle_t handle)
406 USART_NULL_PARAM_CHK(handle);
408 dw_usart_priv_t *usart_priv = handle;
410 drv_nvic_disable_irq(usart_priv->irq);
411 usart_priv->cb_event = NULL;
417 \brief config usart mode.
418 \param[in] handle usart handle to operate.
419 \param[in] sysclk configured system clock.
420 \param[in] mode \ref usart_mode_e
421 \param[in] parity \ref usart_parity_e
422 \param[in] stopbits \ref usart_stop_bits_e
423 \param[in] bits \ref usart_data_bits_e
424 \param[in] baud configured baud
427 int32_t csi_usart_config(usart_handle_t handle,
431 usart_parity_e parity,
432 usart_stop_bits_e stopbits,
433 usart_data_bits_e bits)
435 USART_NULL_PARAM_CHK(handle);
436 dw_usart_priv_t *usart_priv = handle;
437 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
439 /* control the data_bit of the usart*/
440 int32_t ret = dw_usart_set_baudrate(addr, baud, sysclk);
446 /* control the parity of the usart*/
447 ret = dw_usart_set_parity(addr, parity);
453 /* control the stopbit of the usart*/
454 ret = dw_usart_set_stopbit(addr, stopbits);
460 ret = dw_usart_set_databit(addr, bits);
469 \brief config usart default tx value. used in syn mode
470 \param[in] handle usart handle to operate.
471 \param[in] value default tx value
474 int32_t csi_usart_set_default_tx_value(usart_handle_t handle, uint32_t value)
476 USART_NULL_PARAM_CHK(handle);
477 return ERR_USART(EDRV_UNSUPPORTED);
481 \brief Start sending data to UART transmitter,(received data is ignored).
482 The function is non-blocking,UART_EVENT_TRANSFER_COMPLETE is signaled when transfer completes.
483 csi_usart_get_status can indicates if transmission is still in progress or pending
484 \param[in] handle usart handle to operate.
485 \param[in] data Pointer to buffer with data to send to UART transmitter. data_type is : uint8_t for 1..8 data bits, uint16_t for 9..16 data bits,uint32_t for 17..32 data bits,
486 \param[in] num Number of data items to send
489 int32_t csi_usart_send(usart_handle_t handle, const void *data, uint32_t num)
491 USART_NULL_PARAM_CHK(handle);
492 USART_NULL_PARAM_CHK(data);
495 return ERR_USART(EDRV_PARAMETER);
498 dw_usart_priv_t *usart_priv = handle;
499 uint8_t *source = NULL;
500 source = (uint8_t *)data;
502 usart_priv->tx_buf = (uint8_t *)data;
503 usart_priv->tx_total_num = num;
504 usart_priv->tx_cnt = 0;
505 usart_priv->tx_busy = 1;
507 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
508 /* enable the interrupt*/
509 addr->IER |= IER_THRE_INT_ENABLE;
514 \brief Abort Send data to UART transmitter
515 \param[in] handle usart handle to operate.
518 int32_t csi_usart_abort_send(usart_handle_t handle)
520 USART_NULL_PARAM_CHK(handle);
521 dw_usart_priv_t *usart_priv = handle;
523 usart_priv->tx_cnt = usart_priv->tx_total_num;
528 \brief Start receiving data from UART receiver.transmits the default value as specified by csi_usart_set_default_tx_value
529 \param[in] handle usart handle to operate.
530 \param[out] data Pointer to buffer for data to receive from UART receiver
531 \param[in] num Number of data items to receive
534 int32_t csi_usart_receive(usart_handle_t handle, void *data, uint32_t num)
536 USART_NULL_PARAM_CHK(handle);
537 USART_NULL_PARAM_CHK(data);
539 uint8_t *dest = NULL;
540 dw_usart_priv_t *usart_priv = handle;
541 dest = (uint8_t *)data;
543 usart_priv->rx_buf = (uint8_t *)data; // Save receive buffer usart
544 usart_priv->rx_total_num = num; // Save number of data to be received
545 usart_priv->rx_cnt = 0;
546 usart_priv->rx_busy = 1;
553 \brief query data from UART receiver FIFO.
554 \param[in] handle usart handle to operate.
555 \param[out] data Pointer to buffer for data to receive from UART receiver
556 \param[in] num Number of data items to receive
557 \return receive fifo data num
559 int32_t csi_usart_receive_query(usart_handle_t handle, void *data, uint32_t num)
561 USART_NULL_PARAM_CHK(handle);
562 USART_NULL_PARAM_CHK(data);
564 dw_usart_priv_t *usart_priv = handle;
565 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
566 int32_t recv_num = 0;
568 while (addr->LSR & 0x1) {
569 *((uint8_t *)data++) = addr->RBR;
572 if (recv_num >= num) {
582 \brief Abort Receive data from UART receiver
583 \param[in] handle usart handle to operate.
586 int32_t csi_usart_abort_receive(usart_handle_t handle)
588 USART_NULL_PARAM_CHK(handle);
589 dw_usart_priv_t *usart_priv = handle;
591 usart_priv->rx_cnt = usart_priv->rx_total_num;
596 \brief Start sending/receiving data to/from UART transmitter/receiver.
597 \param[in] handle usart handle to operate.
598 \param[in] data_out Pointer to buffer with data to send to USART transmitter
599 \param[out] data_in Pointer to buffer for data to receive from USART receiver
600 \param[in] num Number of data items to transfer
603 int32_t csi_usart_transfer(usart_handle_t handle, const void *data_out, void *data_in, uint32_t num)
605 USART_NULL_PARAM_CHK(handle);
606 return ERR_USART(EDRV_UNSUPPORTED);
610 \brief abort sending/receiving data to/from USART transmitter/receiver.
611 \param[in] handle usart handle to operate.
614 int32_t csi_usart_abort_transfer(usart_handle_t handle)
616 USART_NULL_PARAM_CHK(handle);
617 return ERR_USART(EDRV_UNSUPPORTED);
621 \brief Get USART status.
622 \param[in] handle usart handle to operate.
623 \return USART status \ref usart_status_t
625 usart_status_t csi_usart_get_status(usart_handle_t handle)
627 usart_status_t usart_status;
628 dw_usart_priv_t *usart_priv = handle;
629 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
630 uint32_t line_status_reg = addr->LSR;
632 usart_status.tx_busy = usart_priv->tx_busy;
633 usart_status.rx_busy = usart_priv->rx_busy;
635 if (line_status_reg & DW_LSR_BI) {
636 usart_status.rx_break = 1;
639 if (line_status_reg & DW_LSR_FE) {
640 usart_status.rx_framing_error = 1;
643 if (line_status_reg & DW_LSR_PE) {
644 usart_status.rx_parity_error = 1;
651 \brief control the transmit.
652 \param[in] handle usart handle to operate.
653 \param[in] 1 - enable the transmitter. 0 - disable the transmitter
656 int32_t csi_usart_control_tx(usart_handle_t handle, uint32_t enable)
658 USART_NULL_PARAM_CHK(handle);
663 \brief control the receive.
664 \param[in] handle usart handle to operate.
665 \param[in] 1 - enable the receiver. 0 - disable the receiver
668 int32_t csi_usart_control_rx(usart_handle_t handle, uint32_t enable)
670 USART_NULL_PARAM_CHK(handle);
675 \brief control the break.
676 \param[in] handle usart handle to operate.
677 \param[in] 1- Enable continuous Break transmission,0 - disable continuous Break transmission
680 int32_t csi_usart_control_break(usart_handle_t handle, uint32_t enable)
682 USART_NULL_PARAM_CHK(handle);
683 return ERR_USART(EDRV_UNSUPPORTED);
687 \brief flush receive/send data.
688 \param[in] handle usart handle to operate.
689 \param[in] type \ref usart_flush_type_e.
692 int32_t csi_usart_flush(usart_handle_t handle, usart_flush_type_e type)
694 USART_NULL_PARAM_CHK(handle);
696 dw_usart_priv_t *usart_priv = handle;
697 dw_usart_reg_t *addr = (dw_usart_reg_t *)(usart_priv->base);
699 if (type == USART_FLUSH_WRITE) {
700 while ((!(addr->LSR & DW_LSR_TEMT)));
701 } else if (type == USART_FLUSH_READ) {
702 while (addr->LSR & 0x1) {
706 return ERR_USART(EDRV_PARAMETER);