#include "ch32fun_uart.h" extern uint8_t * make_output_buffer(mrb_vm *vm, mrb_value v[], int argc, int start_idx, int *ret_bufsiz); #if !MRBC_USE_STRING extern mrbc_value mrbc_array_new_alloc(mrbc_vm *vm, const uint8_t *c_array, int size); #endif #if defined( CH32X03x ) static volatile uint32_t usart_base[]={USART1_BASE,USART2_BASE,USART3_BASE,USART4_BASE}; static volatile uint32_t dma_rx_base[]={DMA1_Channel5_BASE,DMA1_Channel6_BASE,DMA1_Channel3_BASE,DMA1_Channel8_BASE}; static volatile uint8_t rx_pin_num[]={27,3,51,17}; static volatile uint8_t tx_pin_num[]={26,2,50,16}; #elif defined( CH32V20x ) static volatile uint32_t usart_base[]={USART1_BASE,USART2_BASE,USART3_BASE}; //,UART4_BASE}; static volatile uint32_t dma_rx_base[]={DMA1_Channel5_BASE,DMA1_Channel6_BASE,DMA1_Channel3_BASE}; //,DMA2_Channel3_BASE}; static volatile uint8_t rx_pin_num[]={10,3,27}; //,43}; static volatile uint8_t tx_pin_num[]={9,2,26}; //,42}; #endif #define UART_TIMEOUT_MAX 100000 int usart_write(UART_HANDLE *handle, const char *buf, int size){ USART_TypeDef *usart = ((USART_TypeDef *) usart_base[handle->unit_num-1]); for(int i = 0; i < size; i++){ uint32_t timeout = UART_TIMEOUT_MAX; while( !(usart->STATR & USART_FLAG_TXE) ) { if (--timeout == 0) return -1;} usart->DATAR = *buf++; } return size; } int usart_available(DMA_Channel_TypeDef *dma_rx, uint8_t rx_index){ uint8_t size =(UART_BUF_SIZE - dma_rx->CNTR); //%UART_BUF_SIZE; size -= rx_index; size %= UART_BUF_SIZE; return size; } int usart_read(UART_HANDLE *handle, char *buf, int size){ DMA_Channel_TypeDef *dma_rx = ((DMA_Channel_TypeDef *) dma_rx_base[handle->unit_num-1]); for(int i = 0; i < size; i++){ while(!usart_available(dma_rx,handle->rx_index)); buf[i] = handle->rx_buf[handle->rx_index]; handle->rx_index = (handle->rx_index + 1)%UART_BUF_SIZE; } buf[size] = '\0'; return size; } int usart_can_read_line(UART_HANDLE *handle){ DMA_Channel_TypeDef *dma_rx = ((DMA_Channel_TypeDef *) dma_rx_base[handle->unit_num-1]); uint8_t index = handle->rx_index; uint8_t last = (UART_BUF_SIZE - dma_rx->CNTR)%UART_BUF_SIZE; while( index != last ) { if( handle->rx_buf[index++] == '\n' )return (index - handle->rx_index)%UART_BUF_SIZE; index%=UART_BUF_SIZE; } return 0; } void c_uart_setmode(mrbc_vm *vm, mrbc_value v[], int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; MRBC_KW_ARG( baudrate, baud, data_bits, stop_bits, parity, flow_control, txd_pin, rxd_pin, rts_pin, cts_pin ); int32_t baud_rate = 9600; int datb = 8; int stpb = 1; int prty = 0; if( MRBC_KW_ISVALID(baudrate) ) baud_rate = mrbc_integer(baudrate); if( MRBC_KW_ISVALID(baud) ) baud_rate = mrbc_integer(baud); if( MRBC_KW_ISVALID(data_bits) ) datb = mrbc_integer(data_bits); if( MRBC_KW_ISVALID(stop_bits) ) stpb = mrbc_integer(stop_bits); if( MRBC_KW_ISVALID(parity) ) prty = mrbc_integer(parity); USART_TypeDef *usart = ((USART_TypeDef *) usart_base[handle->unit_num-1]); usart->CTLR1 &= ~( CTLR1_UE_Set ); usart->BRR = ( ( FUNCONF_SYSTEM_CORE_CLOCK ) + baud_rate/2 ) / baud_rate; usart->CTLR3 = USART_DMAReq_Rx | USART_HardwareFlowControl_None | USART_CTLR3_DMAR; usart->CTLR2 = (stpb&2)<<12; // 1:1bit, 2:2bit, //3:0.5, 4:1.5 0213 usart->CTLR1 = USART_WordLength_9b * (prty>0 && datb>7) | (prty&3)<<9 | USART_Mode_Tx | USART_Mode_Rx | CTLR1_UE_Set; MRBC_KW_DELETE( baudrate, baud, data_bits, stop_bits, parity, flow_control, txd_pin, rxd_pin, rts_pin, cts_pin ); } void c_uart_new(mrb_vm *vm, mrb_value *v, int argc){ v[0] = mrbc_instance_new(vm, v[0].cls, sizeof(UART_HANDLE)); int unit_num = 1; if( argc > 0 ) unit_num = GET_INT_ARG(1); MRBC_KW_ARG( unit ); if( MRBC_KW_ISVALID(unit) ) unit_num = mrbc_integer(unit); MRBC_KW_DELETE( unit ); UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; handle->unit_num = unit_num; handle->rx_index = 0; if(handle->unit_num==1){ RCC->APB2PCENR |= RCC_APB2Periph_USART1; //1<<14 }else{ RCC->APB1PCENR |= 1<<(15+handle->unit_num); } uint8_t tx=tx_pin_num[handle->unit_num-1]; uint8_t rx=rx_pin_num[handle->unit_num-1]; //if(handle->unit_num == 3){ //disable SW and remap1 #if defined( CH32X03x ) if(tx>49){ //disable SW and remap1 AFIO->PCFR1 &= ~AFIO_PCFR1_SWJ_CFG; AFIO->PCFR1 |= AFIO_PCFR1_SWJ_CFG_DISABLE; AFIO->PCFR1 &= ~AFIO_PCFR1_USART3_REMAP; AFIO->PCFR1 |= AFIO_PCFR1_USART3_REMAP_0; GPIOC->CFGXR &= ~( 0xF << 4*(tx-48) ); GPIOC->CFGXR |= GPIO_CFGLR_OUT_50Mhz_AF_PP << 4*(tx-48); GPIOC->CFGXR &= ~( 0xF << 4*(rx-48) ); GPIOC->CFGXR |= GPIO_CFGLR_IN_FLOAT << 4*(rx-48); }else{ #endif funPinMode(tx,GPIO_CFGLR_OUT_50Mhz_AF_PP); funPinMode(rx,GPIO_CFGLR_IN_FLOAT); #if defined( CH32X03x ) } #endif USART_TypeDef *usart = ((USART_TypeDef *) usart_base[handle->unit_num-1]); DMA_Channel_TypeDef *dma_rx = ((DMA_Channel_TypeDef *) dma_rx_base[handle->unit_num-1]); RCC->AHBPCENR |= RCC_AHBPeriph_DMA1; dma_rx->CFGR &= ~DMA_CFGR1_EN; dma_rx->MADDR = (uint32_t)handle->rx_buf; dma_rx->PADDR = (uint32_t)&usart->DATAR; dma_rx->CNTR = UART_BUF_SIZE; dma_rx->CFGR = DMA_CFGR1_MINC | DMA_CFGR1_CIRC | DMA_CFGR1_EN; c_uart_setmode( vm, v, argc ); } void c_uart_write(mrb_vm *vm, mrb_value *v, int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; int bufsiz = 0; if(argc>0){ char *buf = (char*) make_output_buffer( vm, v, argc, 1, &bufsiz ); bufsiz=usart_write(handle,buf,bufsiz); } SET_RETURN( mrbc_integer_value(bufsiz) ); } static void c_uart_puts(mrbc_vm *vm, mrbc_value v[], int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; char zero[]="\n"; int bufsiz = 1; if(argc>0){ char *buf = (char*) make_output_buffer( vm, v, argc, 1, &bufsiz ); bufsiz=usart_write(handle,buf,bufsiz); if( bufsiz == 0 || buf[bufsiz-1] != '\n' ){ bufsiz=1; }else{ bufsiz=0; } } if(bufsiz) usart_write(handle,zero,1); SET_NIL_RETURN(); } void c_uart_read(mrb_vm *vm, mrb_value *v, int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; mrbc_value ret = mrbc_nil_value(); if(argc>0){ int size = GET_INT_ARG(1); char *buf = (char*) mrbc_alloc(vm, size); size = usart_read( handle, buf, size ); #if MRBC_USE_STRING ret = mrbc_string_new_alloc(vm, buf, size); #else ret = mrbc_array_new_alloc( vm, (uint8_t*) buf, size); mrbc_free( vm, buf ); #endif } SET_RETURN(ret); } static void c_uart_gets(mrbc_vm *vm, mrbc_value v[], int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; mrbc_value ret = mrbc_nil_value(); int size=0; while( !size ) size = usart_can_read_line(handle); char *buf = (char*) mrbc_alloc(vm, size); size = usart_read( handle, buf, size ); #if MRBC_USE_STRING ret = mrbc_string_new_alloc(vm, buf, size); #else ret = mrbc_array_new_alloc( vm, (uint8_t *) buf, size); mrbc_free( vm, buf ); #endif SET_RETURN(ret); } static void c_uart_bytes_available(mrbc_vm *vm, mrbc_value v[], int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; DMA_Channel_TypeDef *dma_rx = ((DMA_Channel_TypeDef *) dma_rx_base[handle->unit_num-1]); int value=usart_available( dma_rx, handle->rx_index); SET_INT_RETURN(value); } static void c_uart_bytes_to_write(mrbc_vm *vm, mrbc_value v[], int argc){ SET_INT_RETURN( 0 ); } static void c_uart_can_read_line(mrbc_vm *vm, mrbc_value v[], int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; int pos=usart_can_read_line(handle); SET_INT_RETURN( pos ); } static void c_uart_clear_rx_buffer(mrbc_vm *vm, mrbc_value v[], int argc){ UART_HANDLE *handle = (UART_HANDLE *)v[0].instance->data; DMA_Channel_TypeDef *dma_rx = ((DMA_Channel_TypeDef *) dma_rx_base[handle->unit_num-1]); handle->rx_index=(UART_BUF_SIZE - dma_rx->CNTR)%UART_BUF_SIZE; } static void c_uart_nop(mrbc_vm *vm, mrbc_value v[], int argc){ } void mrbc_init_class_uart(void){ mrb_class *uart = mrbc_define_class(0, "UART", mrbc_class_object); mrbc_define_method(0, uart, "new", c_uart_new); mrbc_define_method(0, uart, "setmode", c_uart_setmode); mrbc_define_method(0, uart, "read", c_uart_read); mrbc_define_method(0, uart, "write", c_uart_write); mrbc_define_method(0, uart, "gets", c_uart_gets); mrbc_define_method(0, uart, "puts", c_uart_puts); mrbc_define_method(0, uart, "bytes_available", c_uart_bytes_available); mrbc_define_method(0, uart, "bytes_to_write", c_uart_bytes_to_write); mrbc_define_method(0, uart, "can_read_line", c_uart_can_read_line); mrbc_define_method(0, uart, "flush", c_uart_nop); mrbc_define_method(0, uart, "clear_rx_buffer", c_uart_clear_rx_buffer); mrbc_define_method(0, uart, "clear_tx_buffer", c_uart_nop); mrbc_define_method(0, uart, "send_break", c_uart_nop); mrbc_set_class_const(uart, mrbc_str_to_symid("NONE"), &mrbc_integer_value(0)); mrbc_set_class_const(uart, mrbc_str_to_symid("EVEN"), &mrbc_integer_value(2)); mrbc_set_class_const(uart, mrbc_str_to_symid("ODD"), &mrbc_integer_value(3)); }