#include "uart.h" #include "bsp/shark_bsp.h" #include "libs/shark_libs.h" #define SHARK_UART_BAUDRATE 38400 #define SHARK_UART0_com USART0 #define SHARK_UART0_tx_port GPIOA #define SHARK_UART0_tx_pin GPIO_PIN_9 #define SHARK_UART0_rx_port GPIOA #define SHARK_UART0_rx_pin GPIO_PIN_10 #define SHARK_UART0_irq USART0_IRQn #define SHARK_UART0_clk RCU_USART0 #define SHARK_UART0_tx_gpio_clk RCU_GPIOA #define SHARK_UART0_rx_gpio_clk RCU_GPIOA #define SHARK_UART0_tx_dma DMA #define SHARK_UART0_tx_dma_ch DMA_CH1 #define SHARK_UART0_tx_dma_clk RCU_DMA #define SHARK_UART0_rx_dma DMA #define SHARK_UART0_rx_dma_ch DMA_CH2 #define SHARK_UART0_rx_dma_clk RCU_DMA #define SHARK_UART1_com USART1 #define SHARK_UART1_tx_port GPIOA #define SHARK_UART1_tx_pin GPIO_PIN_2 #define SHARK_UART1_rx_port GPIOA #define SHARK_UART1_rx_pin GPIO_PIN_3 #define SHARK_UART1_irq USART1_IRQn #define SHARK_UART1_clk RCU_USART1 #define SHARK_UART1_tx_gpio_clk RCU_GPIOA #define SHARK_UART1_rx_gpio_clk RCU_GPIOA #define SHARK_UART1_tx_dma DMA #define SHARK_UART1_tx_dma_ch DMA_CH3 #define SHARK_UART1_tx_dma_clk RCU_DMA #define SHARK_UART1_rx_dma DMA #define SHARK_UART1_rx_dma_ch DMA_CH4 #define SHARK_UART1_rx_dma_clk RCU_DMA #define SHARK_UART_com SHARK_UART0_com #define SHARK_UART_tx_port SHARK_UART0_tx_port #define SHARK_UART_tx_pin SHARK_UART0_tx_pin #define SHARK_UART_rx_port SHARK_UART0_rx_port #define SHARK_UART_rx_pin SHARK_UART0_rx_pin #define SHARK_UART_irq SHARK_UART0_irq #define SHARK_UART_clk SHARK_UART0_clk #define SHARK_UART_tx_gpio_clk SHARK_UART0_tx_gpio_clk #define SHARK_UART_rx_gpio_clk SHARK_UART0_rx_gpio_clk // #define SHARK_UART_tx_dma SHARK_UART0_tx_dma #define SHARK_UART_tx_dma_ch SHARK_UART0_tx_dma_ch #define SHARK_UART_tx_dma_clk SHARK_UART0_tx_dma_clk // #define SHARK_UART_rx_dma SHARK_UART0_rx_dma #define SHARK_UART_rx_dma_ch SHARK_UART0_rx_dma_ch #define SHARK_UART_rx_dma_clk SHARK_UART0_rx_dma_clk // ================================================================================ #define SHARK_UART_CACHE_SIZE \ (SHARK_UART_TX_MEM_SIZE + SHARK_UART_RX_MEM_SIZE) #define SHARK_UART_DMA_ADDR(index) \ (SHARK_UART_com + 0x04) #define SHARK_UART_DMA_CHCTL_TX() \ DMA_CHCTL(SHARK_UART_tx_dma_ch) #define SHARK_UART_DMA_CHCNT_TX() \ DMA_CHCNT(SHARK_UART_tx_dma_ch) #define SHARK_UART_DMA_CHMADDR_TX() \ DMA_CHMADDR(SHARK_UART_tx_dma_ch) #define SHARK_UART_DMA_CHCTL_RX() \ DMA_CHCTL(SHARK_UART_rx_dma_ch) #define SHARK_UART_DMA_CHCNT_RX() \ DMA_CHCNT(SHARK_UART_rx_dma_ch) #define SHARK_UART_DMA_CHMADDR_RX() \ DMA_CHMADDR(SHARK_UART_rx_dma_ch) // ================================================================================ static u8 shark_uart_tx_cache[SHARK_UART_TX_MEM_SIZE]; static u8 shark_uart_rx_cache[SHARK_UART_RX_MEM_SIZE]; static u16 shark_uart_tx_length; static u16 shark_uart_tx_crc16; static u16 shark_uart_rx_index; static byte_queue_t shark_uart_tx_queue; // ================================================================================ static bool shark_uart_on_frame_received(u8 *buff, u16 length) { u16 crc0 = shark_decode_u16(buff + length); u16 crc1 = shark_crc16_check(buff, length); if (crc0 != crc1) { return false; } return true; } static void shark_uart_on_data_received(u8 *buff, u16 size) { static bool escape = false; static u8 length = 0xFF; static u8 frame[16]; u8 *buff_end; for (buff_end = buff + size; buff < buff_end; buff++) { u8 value = *buff; switch (value) { case CH_START: length = 0; escape = false; break; case CH_END: if (length > 2 && length != 0xFF) { shark_uart_on_frame_received(frame, length - 2); } length = 0xFF; break; case CH_ESC: escape = true; break; default: if (escape) { escape = false; switch (value) { case CH_ESC_START: value = CH_START; break; case CH_ESC_END: value = CH_END; break; case CH_ESC_ESC: value = CH_ESC; break; default: length = 0xFF; } } if (length < sizeof(frame)) { frame[length] = value; length++; } else { length = 0xFF; } } } } static void shark_uart_dma_tx(void) { u32 value = SHARK_UART_DMA_CHCTL_TX(); if (value & DMA_CHXCTL_CHEN) { if (SET != dma_flag_get(SHARK_UART_tx_dma_ch, DMA_FLAG_FTF)) { return; } byte_queue_skip(&shark_uart_tx_queue, shark_uart_tx_length); SHARK_UART_DMA_CHCTL_TX() = value & (~DMA_CHXCTL_CHEN); } shark_uart_tx_length = byte_queue_peek(&shark_uart_tx_queue); if (shark_uart_tx_length > 0) { SHARK_UART_DMA_CHCNT_TX() = shark_uart_tx_length; SHARK_UART_DMA_CHMADDR_TX() = (u32) byte_queue_head(&shark_uart_tx_queue); dma_flag_clear(SHARK_UART_tx_dma_ch, DMA_FLAG_FTF); SHARK_UART_DMA_CHCTL_TX() = value | DMA_CHXCTL_CHEN; } } static void shark_uart_dma_rx(void) { u16 index = shark_uart_rx_index; shark_uart_rx_index = sizeof(shark_uart_rx_cache) - SHARK_UART_DMA_CHCNT_RX(); if (shark_uart_rx_index < index) { shark_uart_on_data_received(shark_uart_rx_cache + index, sizeof(shark_uart_rx_cache) - index); shark_uart_on_data_received(shark_uart_rx_cache, shark_uart_rx_index); } else { shark_uart_on_data_received(shark_uart_rx_cache + index, shark_uart_rx_index - index); } } void shark_uart_write(const u8 *buff, u16 size) { while (size > 0) { u16 length = byte_queue_write(&shark_uart_tx_queue, buff, size); if (length == size) { break; } shark_uart_dma_tx(); buff += length; size -= length; } } void shark_uart_write_byte(u8 value) { shark_uart_write(&value, 1); } void shark_uart_dma_init(dma_channel_enum channelx, u8 direction, u32 periph_addr, void *memory_addr, u16 length) { u32 ctl; DMA_CHCTL(channelx) &= ~DMA_CHXCTL_CHEN; /* configure peripheral base address */ DMA_CHPADDR(channelx) = periph_addr; /* configure memory base address */ DMA_CHMADDR(channelx) = (u32) memory_addr; /* configure the number of remaining data to be transferred */ DMA_CHCNT(channelx) = length; /* configure peripheral transfer width,memory transfer width and priority */ ctl = DMA_CHCTL(channelx); ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO); ctl |= (DMA_PERIPHERAL_WIDTH_8BIT | DMA_MEMORY_WIDTH_8BIT | DMA_PRIORITY_ULTRA_HIGH); DMA_CHCTL(channelx) = ctl; /* configure peripheral increasing mode */ DMA_CHCTL(channelx) &= ~DMA_CHXCTL_PNAGA; /* configure memory increasing mode */ DMA_CHCTL(channelx) |= DMA_CHXCTL_MNAGA; /* configure the direction of data transfer */ if (DMA_PERIPHERAL_TO_MEMORY == direction) { DMA_CHCTL(channelx) &= ~DMA_CHXCTL_DIR; } else { DMA_CHCTL(channelx) |= DMA_CHXCTL_DIR; } } static u32 shark_uart_handler(void) { shark_uart_dma_rx(); shark_uart_dma_tx(); return 0; } static shark_task_t shark_uart_task = { .handler = shark_uart_handler }; void shark_uart_init(void) { byte_queue_init(&shark_uart_tx_queue, shark_uart_tx_cache, sizeof(shark_uart_tx_cache)); rcu_periph_clock_enable(SHARK_UART_clk); rcu_periph_clock_enable(SHARK_UART_rx_gpio_clk); rcu_periph_clock_enable(SHARK_UART_tx_gpio_clk); gpio_mode_set(SHARK_UART_tx_port, GPIO_MODE_AF, GPIO_PUPD_NONE, SHARK_UART_tx_pin); gpio_mode_set(SHARK_UART_rx_port, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, SHARK_UART_rx_pin); usart_deinit(SHARK_UART_com); usart_baudrate_set(SHARK_UART_com, SHARK_UART_BAUDRATE); usart_word_length_set(SHARK_UART_com, USART_WL_8BIT); usart_stop_bit_set(SHARK_UART_com, USART_STB_1BIT); usart_parity_config(SHARK_UART_com, USART_PM_NONE); usart_hardware_flow_rts_config(SHARK_UART_com, USART_RTS_DISABLE); usart_hardware_flow_cts_config(SHARK_UART_com, USART_CTS_DISABLE); usart_receive_config(SHARK_UART_com, USART_RECEIVE_ENABLE); usart_transmit_config(SHARK_UART_com, USART_TRANSMIT_ENABLE); rcu_periph_clock_enable(SHARK_UART_tx_dma_clk); shark_uart_dma_init(SHARK_UART_tx_dma_ch, DMA_MEMORY_TO_PERIPHERAL, SHARK_UART_DMA_ADDR(), shark_uart_tx_cache, 0); dma_circulation_disable(SHARK_UART_tx_dma_ch); usart_dma_transmit_config(SHARK_UART_com, USART_DENT_ENABLE); rcu_periph_clock_enable(SHARK_UART_rx_dma_clk); shark_uart_dma_init(SHARK_UART_rx_dma_ch, DMA_PERIPHERAL_TO_MEMORY, SHARK_UART_DMA_ADDR(), shark_uart_rx_cache, sizeof(shark_uart_rx_cache)); dma_circulation_enable(SHARK_UART_rx_dma_ch); dma_channel_enable(SHARK_UART_rx_dma_ch); usart_dma_receive_config(SHARK_UART_com, USART_DENR_ENABLE); usart_enable(SHARK_UART_com); shark_task_add(&shark_uart_task); } void shark_uart_write_byte_esc(u8 value) { switch (value) { case CH_START: shark_uart_write_byte(CH_ESC); value = CH_ESC_START; break; case CH_END: shark_uart_write_byte(CH_ESC); value = CH_ESC_END; break; case CH_ESC: shark_uart_write_byte(CH_ESC); value = CH_ESC_ESC; break; } shark_uart_write_byte(value); } void shark_uart_write_esc(const u8 *buff, u16 length) { const u8 *buff_end; for (buff_end = buff + length; buff < buff_end; buff++) { shark_uart_write_byte_esc(*buff); } } void shark_uart_tx_start(void) { shark_uart_write_byte(CH_START); shark_uart_tx_crc16 = 0; } void shark_uart_tx_continue(const void *buff, u16 length) { shark_uart_write_esc((const u8 *) buff, length); shark_uart_tx_crc16 = shark_crc16_update(shark_uart_tx_crc16, (const u8 *) buff, length); } void shark_uart_tx_end(void) { shark_uart_write_esc((u8 *) &shark_uart_tx_crc16, sizeof(shark_uart_tx_crc16)); shark_uart_write_byte(CH_END); }