From afe3b16106292a36b442691a62dab7315bb4b065 Mon Sep 17 00:00:00 2001 From: armink Date: Fri, 17 Mar 2017 13:25:19 +0800 Subject: [PATCH 1/3] [DeviceDrivers] Enhanced serial DMA rx driver reliability. --- components/drivers/serial/serial.c | 78 ++++++++++++++++++------------ 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/components/drivers/serial/serial.c b/components/drivers/serial/serial.c index c55406bcd6..cc6a8bfe91 100644 --- a/components/drivers/serial/serial.c +++ b/components/drivers/serial/serial.c @@ -166,14 +166,15 @@ rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t * * * @return length */ -static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial) { - static rt_size_t rx_length; - struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; +static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial) +{ + rt_size_t rx_length; + struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); - rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index): - (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index)); + rx_length = (rx_fifo->put_index >= rx_fifo->get_index) ? (rx_fifo->put_index - rx_fifo->get_index): + (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index)); return rx_length; } @@ -183,14 +184,16 @@ static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial) { * @param serial serial device * @param len get data length for this operate */ -static void rt_dma_recv_update_get_index(struct rt_serial_device *serial, rt_size_t len) { - struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; +static void rt_dma_recv_update_get_index(struct rt_serial_device *serial, rt_size_t len) +{ + struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; RT_ASSERT(rx_fifo != RT_NULL); RT_ASSERT(len <= rt_dma_calc_recved_len(serial)); rx_fifo->get_index += len; - if (rx_fifo->get_index > serial->config.bufsz ) { + if (rx_fifo->get_index > serial->config.bufsz) + { rx_fifo->get_index -= serial->config.bufsz; } } @@ -201,37 +204,41 @@ static void rt_dma_recv_update_get_index(struct rt_serial_device *serial, rt_siz * @param serial serial device * @param len received length for this transmit */ -static void rt_dma_recv_update_put_index(struct rt_serial_device *serial, rt_size_t len) { +static void rt_dma_recv_update_put_index(struct rt_serial_device *serial, rt_size_t len) +{ struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; - rt_size_t i; RT_ASSERT(rx_fifo != RT_NULL); - if (rx_fifo->get_index <= rx_fifo->put_index) { + if (rx_fifo->get_index <= rx_fifo->put_index) + { rx_fifo->put_index += len; /* beyond the fifo end */ - if (rx_fifo->put_index >= serial->config.bufsz) { - for (i = 0; i <= len / serial->config.bufsz; i++) { - rx_fifo->put_index -= serial->config.bufsz; - } + if (rx_fifo->put_index >= serial->config.bufsz) + { + rx_fifo->put_index %= serial->config.bufsz; /* force overwrite get index */ - if (rx_fifo->put_index >= rx_fifo->get_index) { + if (rx_fifo->put_index >= rx_fifo->get_index) + { rx_fifo->get_index = rx_fifo->put_index + 1; } } - } else { + } + else + { rx_fifo->put_index += len; - if(rx_fifo->put_index >= rx_fifo->get_index) { + if (rx_fifo->put_index >= rx_fifo->get_index) + { /* beyond the fifo end */ - if(rx_fifo->put_index >= serial->config.bufsz) { - for (i = 0; i <= len / serial->config.bufsz; i++) { - rx_fifo->put_index -= serial->config.bufsz; - } + if (rx_fifo->put_index >= serial->config.bufsz) + { + rx_fifo->put_index %= serial->config.bufsz; } /* force overwrite get index */ rx_fifo->get_index = rx_fifo->put_index + 1; } } + if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; } /* @@ -607,17 +614,17 @@ static rt_err_t rt_serial_control(struct rt_device *dev, if (args) { struct serial_configure *pconfig = (struct serial_configure *) args; - if(pconfig->bufsz != serial->config.bufsz && serial->parent.ref_count) + if (pconfig->bufsz != serial->config.bufsz && serial->parent.ref_count) { /*can not change buffer size*/ return RT_EBUSY; } /* set serial configure */ serial->config = *pconfig; - if(serial->parent.ref_count) + if (serial->parent.ref_count) { /* serial device has been opened, to configure it */ - serial->ops->configure(serial, (struct serial_configure *)args); + serial->ops->configure(serial, (struct serial_configure *) args); } } @@ -754,25 +761,36 @@ void rt_hw_serial_isr(struct rt_serial_device *serial, int event) case RT_SERIAL_EVENT_RX_DMADONE: { int length; + rt_base_t level; /* get DMA rx length */ length = (event & (~0xff)) >> 8; - if (serial->config.bufsz == 0) { + if (serial->config.bufsz == 0) + { struct rt_serial_rx_dma* rx_dma; - rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx; + rx_dma = (struct rt_serial_rx_dma*) serial->serial_rx; RT_ASSERT(rx_dma != RT_NULL); RT_ASSERT(serial->parent.rx_indicate != RT_NULL); serial->parent.rx_indicate(&(serial->parent), length); rx_dma->activated = RT_FALSE; - } else { + } + else + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); /* update fifo put index */ rt_dma_recv_update_put_index(serial, length); + /* calculate received total length */ + length = rt_dma_calc_recved_len(serial); + /* enable interrupt */ + rt_hw_interrupt_enable(level); /* invoke callback */ - if (serial->parent.rx_indicate != RT_NULL) { - serial->parent.rx_indicate(&(serial->parent), rt_dma_calc_recved_len(serial)); + if (serial->parent.rx_indicate != RT_NULL) + { + serial->parent.rx_indicate(&(serial->parent), length); } } break; From cebbee7908053618c5a4d03b3169b4d5765bce84 Mon Sep 17 00:00:00 2001 From: armink Date: Fri, 17 Mar 2017 13:31:47 +0800 Subject: [PATCH 2/3] [BSP] Enhanced stm32f40x serial DMA rx driver reliability. --- bsp/stm32f40x/drivers/usart.c | 56 ++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/bsp/stm32f40x/drivers/usart.c b/bsp/stm32f40x/drivers/usart.c index 539ea5fafc..d9d0f74c6c 100644 --- a/bsp/stm32f40x/drivers/usart.c +++ b/bsp/stm32f40x/drivers/usart.c @@ -70,7 +70,8 @@ struct stm32_uart { USART_TypeDef *uart_device; IRQn_Type irq; - struct stm32_uart_dma { + struct stm32_uart_dma + { /* dma stream */ DMA_Stream_TypeDef *rx_stream; /* dma channel */ @@ -200,7 +201,8 @@ static int stm32_getc(struct rt_serial_device *serial) * @param mem_base_addr memory 0 base address for DMA stream */ static void dma_uart_config(struct rt_serial_device *serial, uint32_t setting_recv_len, - void *mem_base_addr) { + void *mem_base_addr) +{ struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; DMA_InitTypeDef DMA_InitStructure; @@ -234,16 +236,26 @@ static void dma_uart_config(struct rt_serial_device *serial, uint32_t setting_re static void dma_uart_rx_idle_isr(struct rt_serial_device *serial) { struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; rt_size_t recv_total_index, recv_len; + rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); recv_total_index = uart->dma.setting_recv_len - DMA_GetCurrDataCounter(uart->dma.rx_stream); - if (recv_total_index >= uart->dma.last_recv_index) { + if (recv_total_index >= uart->dma.last_recv_index) + { recv_len = recv_total_index - uart->dma.last_recv_index; - } else { + } + else + { recv_len = uart->dma.setting_recv_len - uart->dma.last_recv_index + recv_total_index; } - uart->dma.last_recv_index = recv_total_index; - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); + uart->dma.last_recv_index = recv_total_index; + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + if (recv_len) rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); /* read a data for clear receive idle interrupt flag */ USART_ReceiveData(uart->uart_device); @@ -254,28 +266,35 @@ static void dma_uart_rx_idle_isr(struct rt_serial_device *serial) { * * @param serial serial device */ -static void dma_rx_done_isr(struct rt_serial_device *serial) { +static void dma_rx_done_isr(struct rt_serial_device *serial) +{ struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; rt_size_t recv_total_index, recv_len; + rt_base_t level; - if (DMA_GetFlagStatus(uart->dma.rx_stream, uart->dma.rx_flag) != RESET) { - /* disable dma, stop receive data */ - DMA_Cmd(uart->dma.rx_stream, DISABLE); + if (DMA_GetFlagStatus(uart->dma.rx_stream, uart->dma.rx_flag) != RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); recv_total_index = uart->dma.setting_recv_len - DMA_GetCurrDataCounter(uart->dma.rx_stream); - if (recv_total_index >= uart->dma.last_recv_index) { + if (recv_total_index >= uart->dma.last_recv_index) + { recv_len = recv_total_index - uart->dma.last_recv_index; - } else { - recv_len = uart->dma.setting_recv_len - uart->dma.last_recv_index + recv_total_index; - uart->dma.last_recv_index = recv_total_index; } - uart->dma.last_recv_index = recv_total_index; + else + { + recv_len = uart->dma.setting_recv_len - uart->dma.last_recv_index + recv_total_index; + } - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); + uart->dma.last_recv_index = recv_total_index; + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + if (recv_len) rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); /* start receive data */ DMA_ClearFlag(uart->dma.rx_stream, uart->dma.rx_flag); - DMA_Cmd(uart->dma.rx_stream, ENABLE); } } @@ -284,7 +303,8 @@ static void dma_rx_done_isr(struct rt_serial_device *serial) { * * @param serial serial device */ -static void uart_isr(struct rt_serial_device *serial) { +static void uart_isr(struct rt_serial_device *serial) +{ struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; RT_ASSERT(uart != RT_NULL); From 82930906a2d5537f2ad24edf50e38d9522eb323e Mon Sep 17 00:00:00 2001 From: armink Date: Fri, 17 Mar 2017 16:45:23 +0800 Subject: [PATCH 3/3] [BSP] Enhanced stm32f10x serial DMA rx driver reliability. --- bsp/stm32f10x/drivers/usart.c | 87 +++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/bsp/stm32f10x/drivers/usart.c b/bsp/stm32f10x/drivers/usart.c index 4853b2cbae..e5418c14a4 100644 --- a/bsp/stm32f10x/drivers/usart.c +++ b/bsp/stm32f10x/drivers/usart.c @@ -48,15 +48,18 @@ struct stm32_uart { USART_TypeDef *uart_device; IRQn_Type irq; - struct stm32_uart_dma { + struct stm32_uart_dma + { /* dma channel */ DMA_Channel_TypeDef *rx_ch; /* dma global flag */ uint32_t rx_gl_flag; /* dma irq channel */ uint8_t rx_irq_ch; + /* setting receive len */ + rt_size_t setting_recv_len; /* last receive index */ - rt_size_t last_recv_len; + rt_size_t last_recv_index; } dma; }; @@ -145,15 +148,15 @@ static int stm32_putc(struct rt_serial_device *serial, char c) RT_ASSERT(serial != RT_NULL); uart = (struct stm32_uart *)serial->parent.user_data; - if(serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX) + if (serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX) { - if(!(uart->uart_device->SR & USART_FLAG_TXE)) - { - USART_ITConfig(uart->uart_device, USART_IT_TC, ENABLE); - return -1; - } - uart->uart_device->DR = c; - USART_ITConfig(uart->uart_device, USART_IT_TC, ENABLE); + if (!(uart->uart_device->SR & USART_FLAG_TXE)) + { + USART_ITConfig(uart->uart_device, USART_IT_TC, ENABLE); + return -1; + } + uart->uart_device->DR = c; + USART_ITConfig(uart->uart_device, USART_IT_TC, ENABLE); } else { @@ -188,24 +191,31 @@ static int stm32_getc(struct rt_serial_device *serial) */ static void dma_uart_rx_idle_isr(struct rt_serial_device *serial) { struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; - rt_size_t recv_total_len, recv_len; - /* disable dma, stop receive data */ - DMA_Cmd(uart->dma.rx_ch, DISABLE); + rt_size_t recv_total_index, recv_len; + rt_base_t level; - recv_total_len = serial->config.bufsz - DMA_GetCurrDataCounter(uart->dma.rx_ch); - if (recv_total_len > uart->dma.last_recv_len) { - recv_len = recv_total_len - uart->dma.last_recv_len; - } else { - recv_len = recv_total_len; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + recv_total_index = uart->dma.setting_recv_len - DMA_GetCurrDataCounter(uart->dma.rx_ch); + if (recv_total_index >= uart->dma.last_recv_index) + { + recv_len = recv_total_index - uart->dma.last_recv_index; + } + else + { + recv_len = uart->dma.setting_recv_len - uart->dma.last_recv_index + recv_total_index; } - uart->dma.last_recv_len = recv_total_len; - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); + uart->dma.last_recv_index = recv_total_index; + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + if (recv_len) rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); /* read a data for clear receive idle interrupt flag */ USART_ReceiveData(uart->uart_device); DMA_ClearFlag(uart->dma.rx_gl_flag); - DMA_Cmd(uart->dma.rx_ch, ENABLE); } /** @@ -215,24 +225,29 @@ static void dma_uart_rx_idle_isr(struct rt_serial_device *serial) { */ static void dma_rx_done_isr(struct rt_serial_device *serial) { struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; - rt_size_t recv_total_len, recv_len; - /* disable dma, stop receive data */ - DMA_Cmd(uart->dma.rx_ch, DISABLE); + rt_size_t recv_total_index, recv_len; + rt_base_t level; - recv_total_len = serial->config.bufsz - DMA_GetCurrDataCounter(uart->dma.rx_ch); - if (recv_total_len > uart->dma.last_recv_len) { - recv_len = recv_total_len - uart->dma.last_recv_len; - } else { - recv_len = recv_total_len; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + recv_total_index = uart->dma.setting_recv_len - DMA_GetCurrDataCounter(uart->dma.rx_ch); + if (recv_total_index >= uart->dma.last_recv_index) + { + recv_len = recv_total_index - uart->dma.last_recv_index; + } + else + { + recv_len = uart->dma.setting_recv_len - uart->dma.last_recv_index + recv_total_index; } - uart->dma.last_recv_len = recv_total_len; - rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); + uart->dma.last_recv_index = recv_total_index; + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + if (recv_len) rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8)); DMA_ClearFlag(uart->dma.rx_gl_flag); - /* reload */ - DMA_SetCurrDataCounter(uart->dma.rx_ch, serial->config.bufsz); - DMA_Cmd(uart->dma.rx_ch, ENABLE); } /** @@ -527,6 +542,8 @@ static void DMA_Configuration(struct rt_serial_device *serial) { DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; + uart->dma.setting_recv_len = serial->config.bufsz; + /* enable transmit idle interrupt */ USART_ITConfig(uart->uart_device, USART_IT_IDLE , ENABLE); @@ -544,7 +561,7 @@ static void DMA_Configuration(struct rt_serial_device *serial) { DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(uart->dma.rx_ch, &DMA_InitStructure);