diff --git a/bsp/stm32f40x/drivers/usart.c b/bsp/stm32f40x/drivers/usart.c index b14b2945e4..539ea5fafc 100644 --- a/bsp/stm32f40x/drivers/usart.c +++ b/bsp/stm32f40x/drivers/usart.c @@ -13,6 +13,7 @@ * 2010-03-29 Bernard remove interrupt Tx and DMA Rx mode * 2012-02-08 aozima update for F4. * 2012-07-28 aozima update for ART board. + * 2016-05-28 armink add DMA Rx mode */ #include "stm32f4xx.h" @@ -29,8 +30,6 @@ #define UART1_GPIO GPIOB #define UART1_GPIO_RCC RCC_AHB1Periph_GPIOB #define RCC_APBPeriph_UART1 RCC_APB2Periph_USART1 -#define UART1_TX_DMA DMA1_Channel4 -#define UART1_RX_DMA DMA1_Channel5 #define UART2_GPIO_TX GPIO_Pin_2 #define UART2_TX_PIN_SOURCE GPIO_PinSource2 @@ -39,8 +38,6 @@ #define UART2_GPIO GPIOA #define UART2_GPIO_RCC RCC_AHB1Periph_GPIOA #define RCC_APBPeriph_UART2 RCC_APB1Periph_USART2 -#define UART2_TX_DMA DMA1_Channel4 -#define UART2_RX_DMA DMA1_Channel5 #define UART3_GPIO_TX GPIO_Pin_8 #define UART3_TX_PIN_SOURCE GPIO_PinSource8 @@ -49,19 +46,51 @@ #define UART3_GPIO GPIOD #define UART3_GPIO_RCC RCC_AHB1Periph_GPIOD #define RCC_APBPeriph_UART3 RCC_APB1Periph_USART3 -#define UART3_TX_DMA DMA1_Stream1 -#define UART3_RX_DMA DMA1_Stream3 + +#define UART4_GPIO_TX GPIO_Pin_10 +#define UART4_TX_PIN_SOURCE GPIO_PinSource10 +#define UART4_GPIO_RX GPIO_Pin_11 +#define UART4_RX_PIN_SOURCE GPIO_PinSource11 +#define UART4_GPIO GPIOC +#define UART4_GPIO_RCC RCC_AHB1Periph_GPIOC +#define RCC_APBPeriph_UART4 RCC_APB1Periph_UART4 + +#define UART5_GPIO_TX GPIO_Pin_12 +#define UART5_TX_PIN_SOURCE GPIO_PinSource12 +#define UART5_GPIO_RX GPIO_Pin_2 +#define UART5_RX_PIN_SOURCE GPIO_PinSource2 +#define UART5_TX GPIOC +#define UART5_RX GPIOD +#define UART5_GPIO_RCC_TX RCC_AHB1Periph_GPIOB +#define UART5_GPIO_RCC_RX RCC_AHB1Periph_GPIOD +#define RCC_APBPeriph_UART5 RCC_APB1Periph_UART5 /* STM32 uart driver */ struct stm32_uart { USART_TypeDef *uart_device; IRQn_Type irq; + struct stm32_uart_dma { + /* dma stream */ + DMA_Stream_TypeDef *rx_stream; + /* dma channel */ + uint32_t rx_ch; + /* dma flag */ + uint32_t rx_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_index; + } dma; }; +static void DMA_Configuration(struct rt_serial_device *serial); + static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg) { - struct stm32_uart *uart; + struct stm32_uart* uart; USART_InitTypeDef USART_InitStructure; RT_ASSERT(serial != RT_NULL); @@ -69,20 +98,28 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c uart = (struct stm32_uart *)serial->parent.user_data; - if (cfg->baud_rate == BAUD_RATE_9600) - USART_InitStructure.USART_BaudRate = 9600; - else if (cfg->baud_rate == BAUD_RATE_115200) - USART_InitStructure.USART_BaudRate = 115200; + USART_InitStructure.USART_BaudRate = cfg->baud_rate; - if (cfg->data_bits == DATA_BITS_8) + if (cfg->data_bits == DATA_BITS_8){ USART_InitStructure.USART_WordLength = USART_WordLength_8b; + } else if (cfg->data_bits == DATA_BITS_9) { + USART_InitStructure.USART_WordLength = USART_WordLength_9b; + } - if (cfg->stop_bits == STOP_BITS_1) + if (cfg->stop_bits == STOP_BITS_1){ USART_InitStructure.USART_StopBits = USART_StopBits_1; - else if (cfg->stop_bits == STOP_BITS_2) + } else if (cfg->stop_bits == STOP_BITS_2){ USART_InitStructure.USART_StopBits = USART_StopBits_2; + } + + if (cfg->parity == PARITY_NONE){ + USART_InitStructure.USART_Parity = USART_Parity_No; + } else if (cfg->parity == PARITY_ODD) { + USART_InitStructure.USART_Parity = USART_Parity_Odd; + } else if (cfg->parity == PARITY_EVEN) { + USART_InitStructure.USART_Parity = USART_Parity_Even; + } - USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(uart->uart_device, &USART_InitStructure); @@ -95,7 +132,8 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg) { - struct stm32_uart *uart; + struct stm32_uart* uart; + rt_uint32_t ctrl_arg = (rt_uint32_t)(arg); RT_ASSERT(serial != RT_NULL); uart = (struct stm32_uart *)serial->parent.user_data; @@ -114,6 +152,11 @@ static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *ar /* enable interrupt */ USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE); break; + /* USART config */ + case RT_DEVICE_CTRL_CONFIG : + if (ctrl_arg == RT_DEVICE_FLAG_DMA_RX) { + DMA_Configuration(serial); + } } return RT_EOK; @@ -149,6 +192,125 @@ static int stm32_getc(struct rt_serial_device *serial) return ch; } +/** + * DMA initialize by DMA_InitStruct structure + * + * @param serial serial device + * @param setting_recv_len setting receive length + * @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) { + struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; + DMA_InitTypeDef DMA_InitStructure; + + /* rx dma config */ + uart->dma.setting_recv_len = setting_recv_len; + DMA_DeInit(uart->dma.rx_stream); + while (DMA_GetCmdStatus(uart->dma.rx_stream) != DISABLE); + DMA_InitStructure.DMA_Channel = uart->dma.rx_ch; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(uart->uart_device->DR); + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)mem_base_addr; + DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; + DMA_InitStructure.DMA_BufferSize = uart->dma.setting_recv_len; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(uart->dma.rx_stream, &DMA_InitStructure); +} + +/** + * Serial port receive idle process. This need add to uart idle ISR. + * + * @param serial serial device + */ +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; + + recv_total_index = uart->dma.setting_recv_len - DMA_GetCurrDataCounter(uart->dma.rx_stream); + 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; + + 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 receive done process. This need add to DMA receive done ISR. + * + * @param serial serial device + */ +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; + + if (DMA_GetFlagStatus(uart->dma.rx_stream, uart->dma.rx_flag) != RESET) { + /* disable dma, stop receive data */ + DMA_Cmd(uart->dma.rx_stream, DISABLE); + + recv_total_index = uart->dma.setting_recv_len - DMA_GetCurrDataCounter(uart->dma.rx_stream); + 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; + + 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); + } +} + +/** + * Uart common interrupt process. This need add to uart ISR. + * + * @param serial serial device + */ +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); + + if(USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) + { + rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_RXNE); + } + if(USART_GetITStatus(uart->uart_device, USART_IT_IDLE) != RESET) + { + dma_uart_rx_idle_isr(serial); + } + if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) + { + /* clear interrupt */ + USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); + } + if (USART_GetFlagStatus(uart->uart_device, USART_FLAG_ORE) == SET) + { + stm32_getc(serial); + } +} + + static const struct rt_uart_ops stm32_uart_ops = { stm32_configure, @@ -163,26 +325,32 @@ struct stm32_uart uart1 = { USART1, USART1_IRQn, + { + DMA2_Stream5, + DMA_Channel_4, + DMA_FLAG_TCIF5, + DMA2_Stream5_IRQn, + 0, + }, }; struct rt_serial_device serial1; void USART1_IRQHandler(void) { - struct stm32_uart *uart; - - uart = &uart1; - /* enter interrupt */ rt_interrupt_enter(); - if (USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) - { - rt_hw_serial_isr(&serial1, RT_SERIAL_EVENT_RX_IND); - } - if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) - { - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); - } + + uart_isr(&serial1); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +void DMA2_Stream5_IRQHandler(void) { + /* enter interrupt */ + rt_interrupt_enter(); + + dma_rx_done_isr(&serial1); /* leave interrupt */ rt_interrupt_leave(); @@ -195,26 +363,33 @@ struct stm32_uart uart2 = { USART2, USART2_IRQn, + { + DMA1_Stream5, + DMA_Channel_4, + DMA_FLAG_TCIF5, + DMA1_Stream5_IRQn, + 0, + 0, + }, }; struct rt_serial_device serial2; void USART2_IRQHandler(void) { - struct stm32_uart *uart; - - uart = &uart2; - /* enter interrupt */ rt_interrupt_enter(); - if (USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) - { - rt_hw_serial_isr(&serial2, RT_SERIAL_EVENT_RX_IND); - } - if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) - { - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); - } + + uart_isr(&serial2); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +void DMA1_Stream5_IRQHandler(void) { + /* enter interrupt */ + rt_interrupt_enter(); + + dma_rx_done_isr(&serial2); /* leave interrupt */ rt_interrupt_leave(); @@ -227,32 +402,117 @@ struct stm32_uart uart3 = { USART3, USART3_IRQn, + { + DMA1_Stream1, + DMA_Channel_4, + DMA_FLAG_TCIF1, + DMA1_Stream1_IRQn, + 0, + 0, + }, }; struct rt_serial_device serial3; void USART3_IRQHandler(void) { - struct stm32_uart *uart; - - uart = &uart3; - /* enter interrupt */ rt_interrupt_enter(); - if (USART_GetITStatus(uart->uart_device, USART_IT_RXNE) != RESET) - { - rt_hw_serial_isr(&serial3, RT_SERIAL_EVENT_RX_IND); - } - if (USART_GetITStatus(uart->uart_device, USART_IT_TC) != RESET) - { - /* clear interrupt */ - USART_ClearITPendingBit(uart->uart_device, USART_IT_TC); - } + + uart_isr(&serial3); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +void DMA1_Stream1_IRQHandler(void) { + /* enter interrupt */ + rt_interrupt_enter(); + + dma_rx_done_isr(&serial3); /* leave interrupt */ rt_interrupt_leave(); } #endif /* RT_USING_UART3 */ +#if defined(RT_USING_UART4) +/* UART4 device driver structure */ +struct stm32_uart uart4 = +{ + UART4, + UART4_IRQn, + { + DMA1_Stream2, + DMA_Channel_4, + DMA_FLAG_TCIF2, + DMA1_Stream2_IRQn, + 0, + 0, + }, +}; +struct rt_serial_device serial4; + +void UART4_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + uart_isr(&serial4); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +void DMA1_Stream2_IRQHandler(void) { + /* enter interrupt */ + rt_interrupt_enter(); + + dma_rx_done_isr(&serial4); + + /* leave interrupt */ + rt_interrupt_leave(); +} +#endif /* RT_USING_UART4 */ + +#if defined(RT_USING_UART5) +/* UART5 device driver structure */ +struct stm32_uart uart5 = +{ + UART5, + UART5_IRQn, + { + DMA1_Stream0, + DMA_Channel_4, + DMA_FLAG_TCIF0, + DMA1_Stream0_IRQn, + 0, + 0, + }, +}; +struct rt_serial_device serial5; + +void UART5_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + uart_isr(&serial5); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +void DMA1_Stream0_IRQHandler(void) { + /* enter interrupt */ + rt_interrupt_enter(); + + dma_rx_done_isr(&serial5); + + /* leave interrupt */ + rt_interrupt_leave(); +} +#endif /* RT_USING_UART5 */ + static void RCC_Configuration(void) { #ifdef RT_USING_UART1 @@ -275,6 +535,20 @@ static void RCC_Configuration(void) /* Enable UART3 clock */ RCC_APB1PeriphClockCmd(RCC_APBPeriph_UART3, ENABLE); #endif /* RT_USING_UART3 */ + +#ifdef RT_USING_UART4 + /* Enable UART4 GPIO clocks */ + RCC_AHB1PeriphClockCmd(UART4_GPIO_RCC, ENABLE); + /* Enable UART4 clock */ + RCC_APB1PeriphClockCmd(RCC_APBPeriph_UART4, ENABLE); +#endif /* RT_USING_UART4 */ + +#ifdef RT_USING_UART5 + /* Enable UART5 GPIO clocks */ + RCC_AHB1PeriphClockCmd(UART5_GPIO_RCC_TX | UART5_GPIO_RCC_RX, ENABLE); + /* Enable UART5 clock */ + RCC_APB1PeriphClockCmd(RCC_APBPeriph_UART5, ENABLE); +#endif /* RT_USING_UART5 */ } static void GPIO_Configuration(void) @@ -315,6 +589,28 @@ static void GPIO_Configuration(void) GPIO_PinAFConfig(UART3_GPIO, UART3_TX_PIN_SOURCE, GPIO_AF_USART3); GPIO_PinAFConfig(UART3_GPIO, UART3_RX_PIN_SOURCE, GPIO_AF_USART3); #endif /* RT_USING_UART3 */ + +#ifdef RT_USING_UART4 + /* Configure USART4 Rx/tx PIN */ + GPIO_InitStructure.GPIO_Pin = UART4_GPIO_TX | UART4_GPIO_RX; + GPIO_Init(UART4_GPIO, &GPIO_InitStructure); + + /* Connect alternate function */ + GPIO_PinAFConfig(UART4_GPIO, UART4_TX_PIN_SOURCE, GPIO_AF_UART4); + GPIO_PinAFConfig(UART4_GPIO, UART4_RX_PIN_SOURCE, GPIO_AF_UART4); +#endif /* RT_USING_UART4 */ + +#ifdef RT_USING_UART5 + /* Configure USART5 Rx/tx PIN */ + GPIO_InitStructure.GPIO_Pin = UART5_GPIO_TX; + GPIO_Init(UART5_TX, &GPIO_InitStructure); + GPIO_InitStructure.GPIO_Pin = UART5_GPIO_RX; + GPIO_Init(UART5_RX, &GPIO_InitStructure); + + /* Connect alternate function */ + GPIO_PinAFConfig(UART5_TX, UART5_TX_PIN_SOURCE, GPIO_AF_UART5); + GPIO_PinAFConfig(UART5_RX, UART5_RX_PIN_SOURCE, GPIO_AF_UART5); +#endif /* RT_USING_UART5 */ } static void NVIC_Configuration(struct stm32_uart *uart) @@ -329,6 +625,34 @@ static void NVIC_Configuration(struct stm32_uart *uart) NVIC_Init(&NVIC_InitStructure); } +static void DMA_Configuration(struct rt_serial_device *serial) { + struct stm32_uart *uart = (struct stm32_uart *) serial->parent.user_data; + struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; + NVIC_InitTypeDef NVIC_InitStructure; + + /* enable transmit idle interrupt */ + USART_ITConfig(uart->uart_device, USART_IT_IDLE , ENABLE); + + /* DMA clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + + /* rx dma config */ + dma_uart_config(serial, serial->config.bufsz, rx_fifo->buffer); + + DMA_ClearFlag(uart->dma.rx_stream, uart->dma.rx_flag); + DMA_ITConfig(uart->dma.rx_stream, DMA_IT_TC, ENABLE); + USART_DMACmd(uart->uart_device, USART_DMAReq_Rx, ENABLE); + DMA_Cmd(uart->dma.rx_stream, ENABLE); + + /* rx dma interrupt config */ + NVIC_InitStructure.NVIC_IRQChannel = uart->dma.rx_irq_ch; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); +} + int stm32_hw_usart_init(void) { struct stm32_uart *uart; @@ -348,7 +672,7 @@ int stm32_hw_usart_init(void) /* register UART1 device */ rt_hw_serial_register(&serial1, "uart1", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX, uart); #endif /* RT_USING_UART1 */ @@ -363,7 +687,7 @@ int stm32_hw_usart_init(void) /* register UART1 device */ rt_hw_serial_register(&serial2, "uart2", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX, uart); #endif /* RT_USING_UART2 */ @@ -378,10 +702,39 @@ int stm32_hw_usart_init(void) /* register UART3 device */ rt_hw_serial_register(&serial3, "uart3", - RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX, uart); #endif /* RT_USING_UART3 */ +#ifdef RT_USING_UART4 + uart = &uart4; + + serial4.ops = &stm32_uart_ops; + serial4.config = config; + + NVIC_Configuration(&uart4); + + /* register UART4 device */ + rt_hw_serial_register(&serial4, + "uart4", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX, + uart); +#endif /* RT_USING_UART4 */ + +#ifdef RT_USING_UART5 + uart = &uart5; + + serial5.ops = &stm32_uart_ops; + serial5.config = config; + + NVIC_Configuration(&uart5); + + /* register UART5 device */ + rt_hw_serial_register(&serial5, + "uart5", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX, + uart); +#endif /* RT_USING_UART5 */ return 0; } INIT_BOARD_EXPORT(stm32_hw_usart_init);