/****************************************************************************** * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK") * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *****************************************************************************/ /******************************************************************************************************** * @file uart.c * * @brief This is the source file for B91 * * @author Driver Group * *******************************************************************************************************/ #include "uart.h" /********************************************************************************************************************** * local constants * *********************************************************************************************************************/ /********************************************************************************************************************** * local macro * *********************************************************************************************************************/ /********************************************************************************************************************** * local data type * *********************************************************************************************************************/ /********************************************************************************************************************** * global variable * *********************************************************************************************************************/ dma_config_t uart_tx_dma_config[2]={ { .dst_req_sel = DMA_REQ_UART0_TX,//tx req .src_req_sel = 0, .dst_addr_ctrl = DMA_ADDR_FIX, .src_addr_ctrl = DMA_ADDR_INCREMENT,//increment .dstmode = DMA_HANDSHAKE_MODE,//handshake .srcmode = DMA_NORMAL_MODE, .dstwidth = DMA_CTR_WORD_WIDTH,//must be word .srcwidth = DMA_CTR_WORD_WIDTH,//must be word .src_burst_size = 0,//must be 0 .read_num_en = 0, .priority = 0, .write_num_en = 0, .auto_en = 0,//must be 0 }, { .dst_req_sel = DMA_REQ_UART1_TX,//tx req .src_req_sel = 0, .dst_addr_ctrl = DMA_ADDR_FIX, .src_addr_ctrl = DMA_ADDR_INCREMENT,//increment .dstmode = DMA_HANDSHAKE_MODE,//handshake .srcmode = DMA_NORMAL_MODE, .dstwidth = DMA_CTR_WORD_WIDTH,//must be word .srcwidth = DMA_CTR_WORD_WIDTH,//must be word .src_burst_size = 0,//must be 0 .read_num_en = 0, .priority = 0, .write_num_en = 0, .auto_en = 0,//must be 0 } }; dma_config_t uart_rx_dma_config[2]={ { .dst_req_sel = 0,//tx req .src_req_sel = DMA_REQ_UART0_RX, .dst_addr_ctrl = DMA_ADDR_INCREMENT, .src_addr_ctrl = DMA_ADDR_FIX, .dstmode = DMA_NORMAL_MODE, .srcmode = DMA_HANDSHAKE_MODE, .dstwidth = DMA_CTR_WORD_WIDTH,//must be word .srcwidth = DMA_CTR_WORD_WIDTH,////must be word .src_burst_size = 0, .read_num_en = 0, .priority = 0, .write_num_en = 0, .auto_en = 0,//must be 0 }, { .dst_req_sel = 0,//tx req .src_req_sel = DMA_REQ_UART1_RX, .dst_addr_ctrl = DMA_ADDR_INCREMENT, .src_addr_ctrl = DMA_ADDR_FIX, .dstmode = DMA_NORMAL_MODE, .srcmode = DMA_HANDSHAKE_MODE, .dstwidth = DMA_CTR_WORD_WIDTH,//must be word .srcwidth = DMA_CTR_WORD_WIDTH,////must be word .src_burst_size = 0, .read_num_en = 0, .priority = 0, .write_num_en = 0, .auto_en = 0,//must be 0 } }; /********************************************************************************************************************** * local variable * *********************************************************************************************************************/ static unsigned char uart_dma_tx_chn[2]; static unsigned char uart_dma_rx_chn[2]; static unsigned int uart_dma_rev_size=0; /********************************************************************************************************************** * local function prototype * *********************************************************************************************************************/ /** * @brief This function is used to look for the prime.if the prime is finded,it will return 1, or return 0. * @param[in] n - the calue to judge. * @return 0 or 1 */ static unsigned char uart_is_prime(unsigned int n); /** * @brief This function serves to set pin for UART fuction. * @param tx_pin - To set TX pin. * @param rx_pin - To set RX pin. * @return none */ static void uart_set_fuc_pin(uart_tx_pin_e tx_pin,uart_rx_pin_e rx_pin); /********************************************************************************************************************** * global function implementation * *********************************************************************************************************************/ /** * @brief This function initializes the UART module. * @param[in] uart_num - UART0 or UART1. * @param[in] div - uart clock divider. * @param[in] bwpc - bitwidth, should be set to larger than 2. * @param[in] parity - selected parity type for UART interface. * @param[in] stop_bit - selected length of stop bit for UART interface. * @return none * @note sys_clk baudrate g_uart_div g_bwpc * * 16Mhz 9600 118 13 * 19200 118 6 * 115200 9 13 * * 24Mhz 9600 249 9 * 19200 124 9 * 115200 12 15 * * 32Mhz 9600 235 13 * 19200 235 6 * 115200 17 13 * * 48Mhz 9600 499 9 * 19200 249 9 * 115200 25 15 */ void uart_init(uart_num_e uart_num,unsigned short div, unsigned char bwpc, uart_parity_e parity, uart_stop_bit_e stop_bit) { reg_uart_ctrl0(uart_num) &= ~ (FLD_UART_BPWC_O); reg_uart_ctrl0(uart_num) |= bwpc; //set bwpc reg_uart_clk_div(uart_num) = (div | FLD_UART_CLK_DIV_EN); //set div_clock //parity config if (parity) { reg_uart_ctrl1(uart_num) |= FLD_UART_PARITY_ENABLE; //enable parity function if (UART_PARITY_EVEN == parity) { reg_uart_ctrl1(uart_num) &= (~FLD_UART_PARITY_POLARITY); //enable even parity } else if (UART_PARITY_ODD == parity) { reg_uart_ctrl1(uart_num) |= FLD_UART_PARITY_POLARITY; //enable odd parity } } else { reg_uart_ctrl1(uart_num) &= (~FLD_UART_PARITY_ENABLE); //disable parity function } //stop bit config reg_uart_ctrl1(uart_num) &= (~FLD_UART_STOP_SEL); reg_uart_ctrl1(uart_num) |= stop_bit; } /*********************************************************** * @brief This function serves to calculate the best bwpc(bit width) .i.e reg0x96. * @param[in] baudrate - baut rate of UART. * @param[in] pclk - system clock. * @param[out] div - uart clock divider. * @param[out] bwpc - bitwidth, should be set to larger than 2. * @return none * @note BaudRate*(div+1)*(bwpc+1) = system clock * simplify the expression: div*bwpc = constant(z) * bwpc range from 3 to 15.so loop and get the minimum one decimal point */ void uart_cal_div_and_bwpc(unsigned int baudrate, unsigned int pclk, unsigned short* div, unsigned char *bwpc) { unsigned char i = 0, j= 0; unsigned int primeInt = 0; unsigned char primeDec = 0; unsigned int D_intdec[13],D_int[13]; unsigned char D_dec[13]; primeInt = pclk/baudrate; primeDec = 10*pclk/baudrate - 10*primeInt; if(uart_is_prime(primeInt)){ // primeInt is prime primeInt += 1; //+1 must be not prime. and primeInt must be larger than 2. } else{ if(primeDec > 5){ // >5 primeInt += 1; if(uart_is_prime(primeInt)){ primeInt -= 1; } } } for(i=3;i<=15;i++){ D_intdec[i-3] = (10*primeInt)/(i+1);////get the LSB D_dec[i-3] = D_intdec[i-3] - 10*(D_intdec[i-3]/10);///get the decimal section D_int[i-3] = D_intdec[i-3]/10;///get the integer section } //find the max and min one decimation point unsigned char position_min = 0,position_max = 0; unsigned int min = 0xffffffff,max = 0x00; for(j=0;j<13;j++){ if((D_dec[j] <= min)&&(D_int[j] != 0x01)){ min = D_dec[j]; position_min = j; } if(D_dec[j]>=max){ max = D_dec[j]; position_max = j; } } if((D_dec[position_min]<5) && (D_dec[position_max]>=5)){ if(D_dec[position_min]<(10-D_dec[position_max])){ *bwpc = position_min + 3; *div = D_int[position_min]-1; } else{ *bwpc = position_max + 3; *div = D_int[position_max]; } } else if((D_dec[position_min]<5) && (D_dec[position_max]<5)){ *bwpc = position_min + 3; *div = D_int[position_min] - 1; } else{ *bwpc = position_max + 3; *div = D_int[position_max]; } } /** * @brief This function serves to set r_rxtimeout. this setting is transfer one bytes need cycles base on uart_clk. * For example, if transfer one bytes (1start bit+8bits data+1 priority bit+2stop bits) total 12 bits, * this register setting should be (bpwc+1)*12. * @param[in] uart_num - UART0 or UART1. * @param[in] bwpc - bitwidth, should be set to larger than 2. * @param[in] bit_cnt - bit number. * @param[in] mul - mul. * @return none */ void uart_set_dma_rx_timeout(uart_num_e uart_num,unsigned char bwpc, unsigned char bit_cnt, uart_timeout_mul_e mul) { reg_uart_rx_timeout0(uart_num) = (bwpc+1) * bit_cnt; //one byte includes 12 bits at most reg_uart_rx_timeout1(uart_num) &= (~FLD_UART_TIMEOUT_MUL); reg_uart_rx_timeout1(uart_num) |= mul; //if over 2*(tmp_bwpc+1),one transaction end. } unsigned char uart_tx_byte_index[2] = {0}; /** * @brief This function serves to send data by byte with not DMA method. * @param[in] uart_num - UART0 or UART1. * @param[in] tx_data - the data to be send. * @return none */ void uart_send_byte(uart_num_e uart_num, unsigned char tx_data) { while(uart_get_txfifo_num(uart_num)>7); reg_uart_data_buf(uart_num, uart_tx_byte_index[uart_num]) = tx_data; uart_tx_byte_index[uart_num] ++; (uart_tx_byte_index[uart_num]) &= 0x03; } unsigned char uart_rx_byte_index[2]={0}; /** * @brief This function serves to receive uart data by byte with not DMA method. * @param[in] uart_num - UART0 or UART1. * @return none */ unsigned char uart_read_byte(uart_num_e uart_num) { unsigned char rx_data = reg_uart_data_buf(uart_num, uart_rx_byte_index[uart_num]) ; uart_rx_byte_index[uart_num]++; uart_rx_byte_index[uart_num] &= 0x03 ; return rx_data; } /** * @brief This function serves to judge if the transmission of uart is done. * @param[in] uart_num - UART0 or UART1. * @return return the tx status. * - 0:tx is done 1:tx isn't done */ unsigned char uart_tx_is_busy(uart_num_e uart_num) { return ( (reg_uart_status2(uart_num) & FLD_UART_TX_DONE) ? 0 : 1) ; } /** * @brief This function serves to send uart0 data by halfword with not DMA method. * @param[in] uart_num - UART0 or UART1. * @param[in] data - the data to be send. * @return none */ void uart_send_hword(uart_num_e uart_num, unsigned short data) { static unsigned char uart_tx_hword_index[2]={0}; while(uart_get_txfifo_num(uart_num)>6); reg_uart_data_hword_buf(uart_num, uart_tx_hword_index[uart_num]) = data; uart_tx_hword_index[uart_num]++ ; uart_tx_hword_index[uart_num] &= 0x01 ; } /** * @brief This function serves to send data by word with not DMA method. * @param[in] uart_num - UART0 or UART1. * @param[in] data - the data to be send. * @return none */ void uart_send_word(uart_num_e uart_num, unsigned int data) { while (uart_get_txfifo_num(uart_num)>4); reg_uart_data_word_buf(uart_num) = data; } /** * @brief This function serves to set the RTS pin's level manually. * @param[in] uart_num - UART0 or UART1. * @param[in] polarity - set the output of RTS pin(only for manual mode). * @return none */ void uart_set_rts_level(uart_num_e uart_num, unsigned char polarity) { if (polarity) { reg_uart_ctrl2(uart_num) |= FLD_UART_RTS_MANUAL_V; } else { reg_uart_ctrl2(uart_num) &= (~FLD_UART_RTS_MANUAL_V); } } /** * @brief This function serves to set pin for UART0 cts function . * @param[in] cts_pin -To set cts pin. * @return none */ void uart_set_cts_pin(uart_cts_pin_e cts_pin) { unsigned char val = 0; unsigned char mask = 0xff; if(cts_pin == UART0_CTS_PA1) { mask= (unsigned char)~(BIT(2)|BIT(3)); val = BIT(2); } else if(cts_pin == UART0_CTS_PB6) { mask = (unsigned char)~(BIT(4)|BIT(5)); val = BIT(5); reg_gpio_pad_mul_sel|=BIT(0); } else if(cts_pin == UART0_CTS_PD0) { mask = (unsigned char)~(BIT(0)|BIT(1)); val = 0; } else if(cts_pin == UART1_CTS_PC4) { mask= (unsigned char)~(BIT(0)|BIT(1)); val = BIT(1); reg_gpio_pad_mul_sel|=BIT(0); } else if(cts_pin == UART1_CTS_PD4) { mask = (unsigned char)~(BIT(0)|BIT(1)); val = 0; } else if(cts_pin == UART1_CTS_PE1) { mask = (unsigned char)~(BIT(2)|BIT(3)); val = BIT(2); } reg_gpio_func_mux(cts_pin)=(reg_gpio_func_mux(cts_pin)& mask)|val; gpio_function_dis(cts_pin); } /** * @brief This function serves to set pin for UART0 rts function . * @param[in] rts_pin - To set rts pin. * @return none */ void uart_set_rts_pin(uart_rts_pin_e rts_pin) { unsigned char val = 0; unsigned char mask = 0xff; if(rts_pin == UART0_RTS_PA2) { mask= (unsigned char)~(BIT(4)|BIT(5)); val = BIT(4); } else if(rts_pin == UART0_RTS_PB4) { mask = (unsigned char)~(BIT(0)|BIT(1)); val = BIT(1); reg_gpio_pad_mul_sel|=BIT(0); } else if(rts_pin == UART0_RTS_PD1) { mask = (unsigned char)~(BIT(2)|BIT(3)); val = 0; } else if(rts_pin == UART1_RTS_PC5) { mask= (unsigned char)~(BIT(2)|BIT(3)); val = BIT(3); reg_gpio_pad_mul_sel|=BIT(0); } else if(rts_pin == UART1_RTS_PD5) { mask = (unsigned char)~(BIT(2)|BIT(3)); val = 0; } else if(rts_pin == UART1_RTS_PE3) { mask = (unsigned char)~(BIT(6)|BIT(7)); val = BIT(6); } reg_gpio_func_mux(rts_pin)=(reg_gpio_func_mux(rts_pin)& mask)|val; gpio_function_dis(rts_pin); } /** * @brief This function serves to select pin for UART module. * @param[in] tx_pin - the pin to send data. * @param[in] rx_pin - the pin to receive data. * @return none */ void uart_set_pin(uart_tx_pin_e tx_pin,uart_rx_pin_e rx_pin) { gpio_set_up_down_res(tx_pin, GPIO_PIN_PULLUP_10K); gpio_set_up_down_res(rx_pin, GPIO_PIN_PULLUP_10K); uart_set_fuc_pin(tx_pin,rx_pin);//set tx and rx pin gpio_input_en(tx_pin); gpio_input_en(rx_pin); } /** * @brief This function serves to set rtx pin for UART module. * @param[in] rx_pin - the rtx pin need to set. * @return none */ void uart_set_rtx_pin(uart_rx_pin_e rx_pin) { unsigned char val = 0; unsigned char mask = 0xff; gpio_set_up_down_res(rx_pin, GPIO_PIN_PULLUP_10K); if(rx_pin == UART0_RX_PA4) { mask= (unsigned char)~(BIT(1)|BIT(0)); val = BIT(0); } else if(rx_pin == UART0_RX_PB3) { mask = (unsigned char)~(BIT(7)|BIT(6)); val = BIT(7); reg_gpio_pad_mul_sel|=BIT(0); } else if(rx_pin ==UART0_RX_PD3) { mask = (unsigned char)~(BIT(7)|BIT(6)); val = 0; } else if(rx_pin == UART1_RX_PC7) { mask = (unsigned char)~(BIT(7)|BIT(6)); val = BIT(7); reg_gpio_pad_mul_sel|=BIT(0); } else if(rx_pin == UART1_RX_PD7) { mask = (unsigned char)~(BIT(7)|BIT(6)); val = 0; } else if(rx_pin == UART1_RX_PE2) { mask = (unsigned char)~(BIT(5)|BIT(4)); val = BIT(4); } reg_gpio_func_mux(rx_pin)=(reg_gpio_func_mux(rx_pin)& mask)|val; gpio_input_en(rx_pin); gpio_function_dis(rx_pin); } /** * @brief This function serves to send data with not DMA method. * @param[in] uart_num - UART0 or UART1. * @param[in] addr - pointer to the buffer containing data need to send. * @param[in] len - NDMA transmission length. * @return 1 */ unsigned char uart_send(uart_num_e uart_num, unsigned char * addr, unsigned char len ) { for(unsigned char i=0;i