/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes */ #include <rthw.h> #include <rtthread.h> #include <rtdevice.h> #include "board.h" #include "uart.h" #include <stdint.h> #include <stdbool.h> #include "r_pdl_sci.h" /* General RPDL function definitions */ #include "r_pdl_definitions.h" #include "intrinsics.h" #include "iorx62n.h" //#include <string.h> /* Clock selection control */ #define SCI_CKS_MIN 0 #define SCI_CKS_MAX 3 #define SCI_CKS_STEP 1 #define IPR_ADDRESS(a) ((volatile unsigned char *)&ICU.IPR[IPR_SCI0_ + a]) //#define IER_ADDRESS(a) ((volatile unsigned char *)&(ICU.IER[IER_SCI0_ERI0 + a])/sizeof(unsigned char)) #define ERI_ADDRESS(a) ((volatile unsigned char *)&ICU.IR[IR_SCI0_ERI0] + ((4 * a) / sizeof(unsigned char)) ) #define IER_ADDRESS(a) ((volatile unsigned char *)&ICU.IER[IER_SCI0_ERI0] + ((4 * a) / sizeof(unsigned char)) ) #define RXI_ADDRESS(a) ((volatile unsigned char *)&ICU.IR[IR_SCI0_RXI0] + ((4 * a) / sizeof(unsigned char)) ) #define TXI_ADDRESS(a) ((volatile unsigned char *)&ICU.IR[IR_SCI0_TXI0] + ((4 * a) / sizeof(unsigned char)) ) #define TEI_ADDRESS(a) ((volatile unsigned char *)&ICU.IR[IR_SCI0_TEI0] + ((4 * a) / sizeof(unsigned char)) ) #define RXI_DTCER_ADDRESS(a) (( volatile unsigned char *)&ICU.DTCER[IR_SCI0_RXI0]+ ((4*a)/sizeof(unsigned char))) #define TXI_DTCER_ADDRESS(a) (( volatile unsigned char *)&ICU.DTCER[IR_SCI0_TXI0]+ ((4*a) / sizeof(unsigned char))) //#define SCI1_USE_B //#define SCI2_USE_B //#define SCI3_USE_B //#define SCI6_USE_B #define SourceClk 12000000 #define rpdl_CGC_f_pclk SourceClk * 4 /* Idle output options */ #define SPACE 0 #define MARK 1 typedef int UART_ID_Type; typedef int IRQn_Type; #define SCI2_USE_B struct rx_uart { UART_ID_Type UART; volatile struct st_sci __sfr * sci; }; static rt_err_t rx_configure(struct rt_serial_device *serial, struct serial_configure *cfg) { #if 1 struct rx_uart *uart; unsigned char smr_copy; unsigned char semr_copy; unsigned char scr_copy; unsigned char scmr_copy; unsigned long brr_divider; unsigned long bit_interval_counter; RT_ASSERT(serial != RT_NULL); uart = (struct rx_uart *)serial->parent.user_data; if (uart->UART > 6) { return RT_ERROR; } /* Initialise the working copies */ smr_copy = 0x00u; scr_copy = 0x00u; semr_copy = 0x00u; scmr_copy = 0x72u; brr_divider = 0; switch (uart->UART) { case 0: SYSTEM.MSTPCRB.BIT.MSTPB31 = 0; /* Enable the input buffer */ PORT2.ICR.BIT.B2 = 1; /* Ensure the pin is set to input */ PORT2.DDR.BIT.B2 = 0; /* Disable the USB0_DRPD output */ IOPORT.PFKUSB.BIT.USBE = 0; /* Disable the MTIOC3B-A output */ MTU3.TIORH.BIT.IOB = 0; /* Disable the TMO0 output */ TMR0.TCSR.BIT.OSA = 0; TMR0.TCSR.BIT.OSB = 0; /* Disable the MTIOC1A output */ MTU1.TIOR.BIT.IOA = 0; /* Set the idle state direction */ PORT2.DDR.BIT.B0 = 1; PORT2.DR.BIT.B0 = 1; PORT2.ICR.BIT.B0 = 1; PORT2.ICR.BIT.B1 = 1; break; case 1: SYSTEM.MSTPCRB.BIT.MSTPB30 = 0; /* Disable the CS6#-C output */ IOPORT.PF0CSE.BIT.CS6E = 0; /* Disable the MOSIB-A output */ IOPORT.PFHSPI.BIT.MOSIE = 0; /* Disable the MTIOC2A output */ MTU2.TIOR.BIT.IOA = 0; /* Disable the TMO1 output */ TMR1.TCSR.BYTE = 0xF0u; #ifdef SCI1_USE_B IOPORT.PFFSCI.BIT.SCI1S = 1; PORTF.DDR.BIT.B2 = 0; PORTF.ICR.BIT.B2 = 1; PORTF.DDR.BIT.B0 = 1; PORTF.DR.BIT.B0 = 1; #else IOPORT.PFFSCI.BIT.SCI1S = 0; /* Set the idle state direction */ PORT2.DDR.BIT.B6 = 1; PORT2.DR.BIT.B6 = 1; // PORT2.DR.BIT.B6 = 1; /* Enable the input buffer */ //PORT3.ICR.BIT.B0 = 1; /* Ensure the pin is set to input */ PORT3.DDR.BIT.B0 = 0; #endif break; case 2: SYSTEM.MSTPCRB.BIT.MSTPB29 = 0; /* Disable the SSLB2-A output */ IOPORT.PFHSPI.BIT.SSL2E = 0; #ifdef SCI2_USE_B IOPORT.PFFSCI.BIT.SCI2S = 1; PORT5.DDR.BIT.B0 = 1; PORT5.DR.BIT.B0 = 1; PORT5.DDR.BIT.B2 = 0; PORT5.ICR.BIT.B2 = 1; /* Disable the SSLB1-A output */ IOPORT.PFHSPI.BIT.SSL1E = 0; #else IOPORT.PFFSCI.BIT.SCI2S = 0; /* Enable the input buffer */ PORT1.ICR.BIT.B2 = 1; /* Ensure the pin is set to input */ PORT1.DDR.BIT.B2 = 0; PORT1.DDR.BIT.B3 = 1; PORT1.DR.BIT.B3 = 1; /* Disable the TMO3 output */ TMR3.TCSR.BYTE = 0xF0u; #endif break; case 3: SYSTEM.MSTPCRB.BIT.MSTPB28 = 0; #ifdef SCI3_USE_B IOPORT.PFFSCI.BIT.SCI3S = 1; PORT2.DDR.BIT.B5 = 0; PORT2.ICR.BIT.B5 = 1; PORT2.DDR.BIT.B3 = 1; PORT2.DR.BIT.B3 = 1; IOPORT.PF0CSE.BIT.CS4E = 0; /* Disable the USB0_VBUSEN-A output */ IOPORT.PFKUSB.BIT.USBE = 0; /* Disable the MTIOC4A-A output */ MTU4.TIORH.BIT.IOA = 0; /* Disable the USB0_DPUPE-A output */ IOPORT.PFKUSB.BIT.USBE = 0; /* Disable the EDACK0-B output */ EXDMAC0.EDMOMD.BIT.DACKE = 0; /* Disable the MTIOC3D-A output */ MTU3.TIORL.BIT.IOD = 0; #else IOPORT.PFFSCI.BIT.SCI3S = 0; /* Disable the MTIOC0B output */ MTU0.TIORH.BIT.IOB = 0; PORT1.DDR.BIT.B6 = 0; PORT1.ICR.BIT.B6 = 1; PORT1.DDR.BIT.B7 = 1; PORT1.DR.BIT.B7 = 1; MTU3.TIORH.BIT.IOA = 0; /* Set the idle state direction */ #endif break; //case UartPort4: // SYSTEM.MSTPCRB.BIT.MSTPB27 = 0; // break; case 5: SYSTEM.MSTPCRB.BIT.MSTPB26 = 0; /* Enable the input buffer */ PORTC.ICR.BIT.B1 = 1; /* Ensure the pin is set to input */ PORTC.DDR.BIT.B1 = 0; PORTC.DDR.BIT.B3 = 1; PORTC.DR.BIT.B3 = 1; /* Disable the A17-A output */ IOPORT.PF3BUS.BIT.A17E = 0; break; case 6: SYSTEM.MSTPCRB.BIT.MSTPB25 = 0; #ifdef SCI6_USE_B IOPORT.PFFSCI.BIT.SCI6S = 1; PORT3.DDR.BIT.B3 = 0; //PORT3.ICR.BIT.B3 = 1; PORT3.DDR.BIT.B2 = 1; PORT3.DR.BIT.B2 = 1; /* Disable the MTIOC0A output */ MTU0.TIORH.BIT.IOA = 0; /* Disable the CTX0 output */ IOPORT.PFJCAN.BIT.CAN0E = 0; /* Disable the MTIOC0C output */ MTU0.TIORL.BIT.IOC = 0; #else IOPORT.PFFSCI.BIT.SCI6S = 0; PORT0.DDR.BIT.B0 = 1; PORT0.DR.BIT.B0 = 1; PORT0.ICR.BIT.B1 = 1; PORT0.DDR.BIT.B1 = 0; #endif break; default: break; } /*stop bit*/ if (cfg->stop_bits == STOP_BITS_2) { smr_copy |= BIT_3; } else if (cfg->stop_bits != STOP_BITS_1) { return RT_ERROR; } /*data bit*/ if (cfg->data_bits == 7) { smr_copy |= BIT_6; } else if (cfg->data_bits != DATA_BITS_8) { return RT_ERROR; } /*parity*/ if (cfg->parity == PARITY_ODD) smr_copy |= BIT_5; else if (cfg->parity == PARITY_EVEN) smr_copy |= BIT_4 | BIT_5; brr_divider = rpdl_CGC_f_pclk / cfg->baud_rate; /* There is a fixed division by 2 */ brr_divider /= 16; /* Select 8 base clock cycles (ABCS = 1) */ semr_copy |= (unsigned char)BIT_4; //brr_divider /= 8; /* More division required? */ if (brr_divider > 256) { /* Select 16 base clock cycles (ABCS = 0) */ semr_copy &= (unsigned char)INV_BIT_4; brr_divider /= 2; } /* Load the BRR reset value */ //brr_copy = 0xFFu; /* Ensure bits TIE, RIE, TE, RE and TEIE in the SCR are 0 */ uart->sci->SCR.BYTE = 0x00; /* Configure the CKE & MPIE bits */ uart->sci->SCR.BYTE = scr_copy & (BIT_0 | BIT_1 | BIT_3); /* Configure the SMR register */ uart->sci->SMR.BYTE = smr_copy; /* Configure the SCMR register */ uart->sci->SCMR.BYTE = scmr_copy; /* Configure the SEMR register */ uart->sci->SEMR.BYTE = semr_copy; /* Configure the BRR register */ uart->sci->BRR = brr_divider - 1; bit_interval_counter = rpdl_CGC_f_pclk / cfg->baud_rate; /* Wait for at least a 1-bit duration */ do { bit_interval_counter--; }while (bit_interval_counter != 0); scr_copy = 0x00u; /*enable rx an tx*/ scr_copy |= BIT_5 | BIT_4 ; uart->sci->SCR.BYTE &= 0x5B; uart->sci->SCR.BYTE |= scr_copy; *(IPR_ADDRESS(uart->UART)) = 5; uart->sci->SSR.BYTE = 0xC0; uart->sci->SSR.BYTE &= INV_BIT_5; while (uart->sci->SSR.BYTE & BIT_4); uart->sci->SSR.BYTE &= INV_BIT_3; #else struct rx_uart *uart; /* Declare error flag */ bool err = true; uint32_t flag = 0; RT_ASSERT(serial != RT_NULL); uart = (struct rx_uart *)serial->parent.user_data; /* Configure the pin selection of SCI channel */ err &= R_SCI_Set ( PDL_SCI_PIN_SCI2_B ); uart->sci->SCR.BYTE |= BIT_4 | BIT_5; switch (cfg->parity) { case PARITY_ODD: flag |= PDL_SCI_PARITY_ODD; break; case PARITY_EVEN: flag |= PDL_SCI_PARITY_EVEN; break; default: flag |= PDL_SCI_PARITY_NONE; break; } switch (cfg->data_bits) { case DATA_BITS_7: flag |= PDL_SCI_7_BIT_LENGTH; break; case DATA_BITS_8: flag |= PDL_SCI_8_BIT_LENGTH; break; } switch (cfg->stop_bits) { case STOP_BITS_1: flag |= PDL_SCI_STOP_1; break; case STOP_BITS_2: flag |= PDL_SCI_STOP_2; break; } flag |= PDL_SCI_ASYNC | PDL_SCI_TX_CONNECTED | PDL_SCI_RX_CONNECTED | PDL_SCI_CLK_INT_IO ; /* Configure the RS232 port */ err &= R_SCI_Create( uart->UART, flag, cfg->baud_rate, 5); uart->sci->SCR.BYTE |= BIT_4|BIT_5; __enable_interrupt(); #endif switch (uart->UART) { case 0: //ier_copy |= BIT_6 | BIT_7; ICU.IER[IER_SCI0_ERI0].BIT.IEN_SCI0_ERI0 = 1; ICU.IER[IER_SCI0_RXI0].BIT.IEN_SCI0_RXI0 = 1; ICU.IER[IER_SCI0_TEI0].BIT.IEN_SCI0_TEI0 = 1; ICU.IER[IER_SCI0_TXI0].BIT.IEN_SCI0_TXI0 = 1; break; case 1: ICU.IER[IER_SCI1_ERI1].BIT.IEN_SCI1_ERI1 = 1; ICU.IER[IER_SCI1_RXI1].BIT.IEN_SCI1_RXI1 = 1; //ICU.IER[IER_SCI1_TEI1].BIT.IEN_SCI1_TEI1 = 1; //ICU.IER[IER_SCI1_TXI1].BIT.IEN_SCI1_TXI1 = 1; break; case 2: ICU.IER[IER_SCI2_ERI2].BIT.IEN_SCI2_ERI2 = 1; ICU.IER[IER_SCI2_RXI2].BIT.IEN_SCI2_RXI2 = 1; ICU.IER[IER_SCI2_RXI2].BIT.IEN_SCI2_TEI2 = 0; ICU.IER[IER_SCI2_TXI2].BIT.IEN_SCI2_TXI2 = 0; break; case 3: ICU.IER[IER_SCI3_ERI3].BIT.IEN_SCI3_ERI3 = 1; ICU.IER[IER_SCI3_RXI3].BIT.IEN_SCI3_RXI3 = 1; ICU.IER[IER_SCI3_TEI3].BIT.IEN_SCI3_TEI3 = 1; ICU.IER[IER_SCI3_TXI3].BIT.IEN_SCI3_TXI3 = 1; break; case 5: ICU.IER[IER_SCI5_ERI5].BIT.IEN_SCI5_ERI5 = 1; ICU.IER[IER_SCI5_RXI5].BIT.IEN_SCI5_RXI5 = 1; ICU.IER[IER_SCI5_TEI5].BIT.IEN_SCI5_TEI5 = 1; ICU.IER[IER_SCI5_TXI5].BIT.IEN_SCI5_TXI5 = 1; break; case 6: ICU.IER[IER_SCI6_ERI6].BIT.IEN_SCI6_ERI6 = 1; ICU.IER[IER_SCI6_RXI6].BIT.IEN_SCI6_RXI6 = 1; ICU.IER[IER_SCI6_TEI6].BIT.IEN_SCI6_TEI6 = 1; ICU.IER[IER_SCI6_TXI6].BIT.IEN_SCI6_TXI6 = 1; break; } return RT_EOK; } static rt_err_t rx_control(struct rt_serial_device *serial, int cmd, void *arg) { struct rx_uart *uart; RT_ASSERT(serial != RT_NULL); uart = (struct rx_uart *)serial->parent.user_data; switch (cmd) { case RT_DEVICE_CTRL_CLR_INT: /* disable rx irq */ uart->sci->SCR.BIT.RIE = 0; break; case RT_DEVICE_CTRL_SET_INT: /* enable rx irq */ (void)(uart->sci->RDR); uart->sci->SCR.BIT.RIE = 1; break; } return RT_EOK; } static int rx_putc(struct rt_serial_device *serial, char c) { struct rx_uart *uart; uart = (struct rx_uart *)serial->parent.user_data; while (uart->sci->SSR.BIT.TDRE == 0); uart->sci->TDR = c; return 1; } static int rx_getc(struct rt_serial_device *serial) { struct rx_uart *uart; uart = (struct rx_uart *)serial->parent.user_data; if (uart->sci->SSR.BIT.RDRF) return (int) (uart->sci->RDR); return -1; } static const struct rt_uart_ops rx_uart_ops = { rx_configure, rx_control, rx_putc, rx_getc, }; #if defined(RT_USING_UART2) /* UART0 device driver structure */ struct rx_uart uart2 = { 2, &SCI2, }; struct rt_serial_device serial2; #pragma vector = VECT_SCI2_ERI2 __interrupt void Interrupt_SCI2_ERI2(void) { /* Will the user handle the errors? */ /* Clear the error flags */ SCI2.SSR.BYTE = (uint8_t)(BIT_7 | BIT_6); } #pragma vector = VECT_SCI2_RXI2 __interrupt void Interrupt_SCI2_RXI2(void) { rt_interrupt_enter(); rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND); rt_interrupt_leave(); } #endif void rt_hw_uart_init(void) { struct rx_uart *uart; struct serial_configure config; #ifdef RT_USING_UART2 uart = &uart2; config.baud_rate = BAUD_RATE_38400; config.bit_order = BIT_ORDER_LSB; config.data_bits = DATA_BITS_8; config.parity = PARITY_NONE; config.stop_bits = STOP_BITS_1; config.invert = NRZ_NORMAL; config.bufsz = RT_SERIAL_RB_BUFSZ; serial2.ops = &rx_uart_ops; serial2.config = config; /* register UART1 device */ rt_hw_serial_register(&serial2, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM, uart); #endif }