#include "board.h" // #define FINSH_TXBUF_DEPTH (1024) #ifdef FINSH_TXBUF_DEPTH static char TxBuf[FINSH_TXBUF_DEPTH]; static uint16_t TxWaddr = 0; static uint16_t TxRaddr = 0; #endif SerPlot_NxFloat_t SerPlot; // uint16_t SerPlot_Mode = 0x0000u; uint16_t SerPlot_Mode = SERPLOT_DMATX_OFF; uint16_t Finsh_Uart_Mode; uint8_t finsh_txing_flag = 0; // finsh txing set 1 #if !defined(USE_DEBUG_UART) // finsh driver init // GPIO enable for uart // NVIC interrupt enable for lpuart1 void finsh_drv_init(void) { // LPUART1_RX: PC11(AF1) GpioInit(PC11_LPUART1_RXD, GPIO_DIG_IN_NONEUP_NONEDOWN); PeriClk_MutEnable(PeriClk_LpUart1); // infrared lpuart baudrate = 2400Hz even parity M0P_LPUART1->SCON = (0 << 21) | // FEIE, Frame error interrupt 0:close; 1:open; (0 << 17) | // DMATXEN, TX DMAC handshake 0:close; 1:open; (0 << 16) | // DMARXEN, RX DMAC handshake 0:close; 1:open; (0 << 14) | // STOPBIT, Stop bit length, 0:1-bit; 1:1.5-bits; 2:2-bits; 3:RSV (0 << 13) | // PEIE, Parity error interrupt 0:close; 1:open; #ifndef RCL_38p4K_ENABLE (2 << 11) | // SCLKSEL, 0,1:PCLK; 2:XTL; 3:RCL; #else (3 << 11) | // SCLKSEL, 0,1:PCLK; 2:XTL; 3:RCL; #endif (2 << 9) | // OVER, 0:16x-sample; 1:8x-sample; 2:4x-sample; (0 << 8) | // TXEIE, TX empty interrupt 0:close; 1:open; (3 << 6) | // SM, 0:mode0; 1:mode1; 2:mode2; 3:mode3; (1 << 4) | // REN, in mode1 0:TX only; 1:RX/TX (1 << 2) | // B8CONT, 0:SBUF[8]; 1:even; 2:odd; 3:RSV (0 << 1) | // TCIE, Tx completed interrupt 0:close; 1:open; (1 << 0); // RCIE, Rx completed interrupt 0:close; 1:open; // BaudRate = fSCLK/(OVER*SCNT) // fSCLK = 32.768KHz(XTL) or 38.4KHz(RCL) M0P_LPUART1->SCNT = 4; // BaudRate = 32768/(4*4) = 2048Hz(XTL) or 38400/(4*4) = 2400Hz(RCL) // enable interrupt at NVIC side IRQMutEnable(LPUART1_IRQn, NVIC_PRIO_3); // IRQMutEnable(LPUART1_IRQn, NVIC_PRIO_0); // LPUART1_TX: PC10(AF1) GpioInit(PC10_LPUART1_TXD, GPIO_DIG_OUT_STRN_PUSH_NONEUP_NONEDOWN); SerPlot.f.Preamble = 0xFFFFFFFF; } static uart_rx_itf ShellRxItf; static uart_rx_itf CheckRxItf; static ymodem_rx_itf YModemRxItf; static void *YModemArg; void set_shell_rx_itf(uart_rx_itf itf) { ShellRxItf = itf; } void set_check_rx_itf(uart_rx_itf itf) { CheckRxItf = itf; } void set_ymodem_rx_itf(ymodem_rx_itf itf, void *arg) { YModemRxItf = itf; YModemArg = arg; } // interrupt routine void LPUART1_IRQHandler(void) { union { uint32_t ISR; stc_uart_isr_field_t ISR_f; } IRQ; #ifdef FINSH_TXBUF_DEPTH rt_base_t level; #endif IRQ.ISR = M0P_LPUART1->ISR; M0P_LPUART1->ICR = ~IRQ.ISR; // write 0 to clear interrupts // receive a ch if (IRQ.ISR_f.RC) { if (Finsh_Uart_Mode & YMODEM_UPGRADE_ON) { YModemRxItf(M0P_LPUART1->SBUF, YModemArg); } else if (Finsh_Uart_Mode & CHECK_ITF_ON) { CheckRxItf(M0P_LPUART1->SBUF); } else { ShellRxItf(M0P_LPUART1->SBUF); } } if (IRQ.ISR_f.TXE & M0P_LPUART1->SCON_f.TXEIE) { #ifdef FINSH_TXBUF_DEPTH if (TxRaddr == TxWaddr) { // read FIFO to empty M0P_LPUART1->SCON_f.TXEIE = 0; // disable tx interrupt source } else { M0P_LPUART1->SBUF = (uint32_t)TxBuf[TxRaddr]; level = rt_hw_interrupt_disable(); if (TxRaddr >= (FINSH_TXBUF_DEPTH - 1)) { TxRaddr = 0; } else { TxRaddr++; } rt_hw_interrupt_enable(level); } #else M0P_LPUART1->SCON_f.TXEIE = 0; // disable tx interrupt source #endif } // CalExpireTime(120); } uint16_t FinSh_Txbuf_Busy(void) { #ifdef FINSH_TXBUF_DEPTH if (TxWaddr != TxRaddr) { return (0x0001u); } #endif // if (M0P_LPUART1->ISR_f.TXE==0) { // M0P_LPUART1->SCON_f.TXEIE = 1; // enable tx interrupt source // return(0x0001u); // } return (0x0000u); } void print_ch(char ch) { if (((~SerPlot_Mode) & SERPLOT_DMATX_OFF) || (Finsh_Uart_Mode & YMODEM_UPGRADE_ON)) { // SerPlot on return; } #ifdef FINSH_TXBUF_DEPTH // put a ch to TXBUF with nonblocking, drop it if almost full rt_base_t level; uint16_t used; while (1) { used = TxWaddr - TxRaddr; if (TxWaddr < TxRaddr) { used += FINSH_TXBUF_DEPTH; } if (used < (FINSH_TXBUF_DEPTH - 1)) { break; } } TxBuf[TxWaddr] = ch; level = rt_hw_interrupt_disable(); if (TxWaddr >= (FINSH_TXBUF_DEPTH - 1)) { TxWaddr = 0; } else { TxWaddr++; } M0P_LPUART1->SCON_f.TXEIE = 1; // enable tx interrupt source #ifdef SLEEPDEEP_ENABLE SCB->SCR = (0x0 << SCB_SCR_SEVONPEND_Pos) | (0x0 << SCB_SCR_SLEEPDEEP_Pos) | // sleep (0x0 << SCB_SCR_SLEEPONEXIT_Pos); #endif rt_hw_interrupt_enable(level); return; #else // put a ch to TX data register directly, wait if not empty while (M0P_LPUART1->ISR_f.TXE == 0) { // wait until TX empty } M0P_LPUART1->SBUF = (uint32_t)ch; // #ifdef SLEEPDEEP_ENABLE // // wait until TDR is moved to 32.768K clock domain // while (M0P_LPUART1->ISR_f.TXE==0) { // // wait until TX empty // } // #endif return; #endif } // must use Micro LIB at keil option /* int fputc(int ch, FILE* stream) { // fow windows, line end is "\r\n" if (ch=='\n'){ print_ch('\r'); } print_ch((char)ch); return ch; }*/ void print_str(char *str) { char ch; while (1) { ch = *str++; if (ch == '\0') { return; } // fow windows, line end is "\r\n" if (ch == '\n') { print_ch('\r'); } print_ch(ch); } } void DebugPrintStr(char *Str, uint16_t Len) { if ((~SerPlot_Mode) & SERPLOT_DMATX_OFF) { // SerPlot on return; } DMA_ReqClkOn(); // close clock of DMA after interrupt done // enable DMA interrupt at NVIC side IRQMutEnable(DMAC_IRQn, NVIC_PRIO_3); M0P_DMAC->CONF = (1u << 31) | // EN, 0:DMAC off; 1:DMAC on; (0u << 28) | // PRIO, 0:priority of CH0 higher than CH1; 1:round-robin between CH0 and CH1; (0u << 24); // HALT, 0:not halt; others:halt all CH; M0P_DMAC->CONFA1 = (0u << 31) | // ENS, 0:CHx off; 1:CHx on; (0u << 29) | // ST, 0:no soft start DMA; 1:soft start DMA (0x4Fu << 22) | // TRI_SEL, 0x49:UART0 TxBuf empty; 0x4B:UART1 TxBuf empty; 0x4D:LPUART0 TxBuf empty; 0x4F:LPUART1 TxBuf empty; (0u << 16) | // BC, one trigger require 0:one; 1:two; ... 15:sixteen data(8/16/32 bits per data) ((Len - 1u) << 0); // TC = Len - 1, close DAM after (TC+1)*(BC+1) M0P_DMAC->CONFB1 = (0u << 28) | // MODE, 0:Block; 1:Burst(non interruptible between TC+1 Trigger); (0u << 26) | // WIDTH, 0:8 bits; 1:16 bits; 2:32 bits; (0u << 25) | // FS, source address 0:inc; 1:fixed; (1u << 24) | // FD, destination address 0:inc; 1:fixed; (1u << 20) | // ERR_IE, interrupt 0:off; 1:on; when DMA error (1u << 19) | // FIS_IE, interrupt 0:off; 1:on; after DMA done (0u << 0); // MSK, 0:clear ENS 1:keep ENS; after DMA done M0P_DMAC->SRCADR1 = (uint32_t)Str; // memory addresss M0P_DMAC->DSTADR1 = (uint32_t)&(M0P_LPUART1->SBUF); // peripheral addresss, not inc M0P_LPUART1->SCON_f.DMATXEN = 1; M0P_DMAC->CONFA1_f.ENS = 1; #ifdef SLEEPDEEP_ENABLE SCB->SCR = (0x0 << SCB_SCR_SEVONPEND_Pos) | (0x0 << SCB_SCR_SLEEPDEEP_Pos) | // sleep (0x0 << SCB_SCR_SLEEPONEXIT_Pos); #endif } // active DMA for uart TX, and immediately non-blocking return regardless of TX completing void SerPlot_DmaTxAct(char *Ptr, uint16_t Len) { if (SerPlot_Mode & SERPLOT_DMATX_OFF) { return; } DMA_ReqClkOn(); // close clock of DMA after interrupt done // enable DMA interrupt at NVIC side IRQMutEnable(DMAC_IRQn, NVIC_PRIO_3); M0P_DMAC->CONF = (1u << 31) | // EN, 0:DMAC off; 1:DMAC on; (0u << 28) | // PRIO, 0:priority of CH0 higher than CH1; 1:round-robin between CH0 and CH1; (0u << 24); // HALT, 0:not halt; others:halt all CH; M0P_DMAC->CONFA1 = (0u << 31) | // ENS, 0:CHx off; 1:CHx on; (0u << 29) | // ST, 0:no soft start DMA; 1:soft start DMA (0x4Fu << 22) | // TRI_SEL, 0x49:UART0 TxBuf empty; 0x4B:UART1 TxBuf empty; 0x4D:LPUART0 TxBuf empty; 0x4F:LPUART1 TxBuf empty; (0u << 16) | // BC, one trigger require 0:one; 1:two; ... 15:sixteen data(8/16/32 bits per data) ((Len - 1u) << 0); // TC = Len - 1, close DAM after (TC+1)*(BC+1) M0P_DMAC->CONFB1 = (0u << 28) | // MODE, 0:Block; 1:Burst(non interruptible between TC+1 Trigger); (0u << 26) | // WIDTH, 0:8 bits; 1:16 bits; 2:32 bits; (0u << 25) | // FS, source address 0:inc; 1:fixed; (1u << 24) | // FD, destination address 0:inc; 1:fixed; (1u << 20) | // ERR_IE, interrupt 0:off; 1:on; when DMA error (1u << 19) | // FIS_IE, interrupt 0:off; 1:on; after DMA done (0u << 0); // MSK, 0:clear ENS 1:keep ENS; after DMA done M0P_DMAC->SRCADR1 = (uint32_t)Ptr; // memory addresss M0P_DMAC->DSTADR1 = (uint32_t)&(M0P_LPUART1->SBUF); // peripheral addresss, not inc M0P_LPUART1->SCON_f.DMATXEN = 1; M0P_DMAC->CONFA1_f.ENS = 1; #ifdef SLEEPDEEP_ENABLE SCB->SCR = (0x0 << SCB_SCR_SEVONPEND_Pos) | (0x0 << SCB_SCR_SLEEPDEEP_Pos) | // sleep (0x0 << SCB_SCR_SLEEPONEXIT_Pos); #endif } void finsh_tx(volatile uint8_t *data, uint16_t len) { int i; finsh_txing_flag = 1; // when txing, set 1 for (i = 0; i < len; i++) { print_ch(data[i]); } while (M0P_LPUART1->ISR_f.TXE == 0) { // wait until TX empty } rt_thread_mdelay(5); finsh_txing_flag = 0; } void PutChar(char ch) { // put a ch to TX data register directly, wait if not empty while (M0P_LPUART1->ISR_f.TXE == 0) { // wait until TX empty } M0P_LPUART1->SBUF = (uint32_t)ch; // #ifdef SLEEPDEEP_ENABLE // // wait until TDR is moved to 32.768K clock domain // while (M0P_LPUART1->ISR_f.TXE==0) { // // wait until TX empty // } // #endif } #endif