From 179a29e07bc92ae859a862a91db816072673595b Mon Sep 17 00:00:00 2001 From: adustm Date: Thu, 7 Jan 2016 11:06:43 +0100 Subject: [PATCH 1/5] [B96B_Serial_Async] Add asynchronous feature for the platform B96B --- .../TARGET_B96B_F446VE/device.h | 4 +- .../TARGET_B96B_F446VE/objects.h | 3 + .../TARGET_STM/TARGET_STM32F4/serial_api.c | 789 ++++++++++++++++-- 3 files changed, 742 insertions(+), 54 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/device.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/device.h index c4ba64b581..112494dfd6 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/device.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/device.h @@ -40,8 +40,8 @@ #define DEVICE_ANALOGOUT 1 #define DEVICE_SERIAL 1 -#define DEVICE_SERIAL_ASYNCH 0 -#define DEVICE_SERIAL_ASYNCH_DMA 0 +#define DEVICE_SERIAL_ASYNCH 1 +#define DEVICE_SERIAL_ASYNCH_DMA 1 #define DEVICE_SERIAL_FC 0 #define DEVICE_I2C 1 diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/objects.h b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/objects.h index 0116da688c..1b1c0a4ecc 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/objects.h +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/TARGET_B96B_F446VE/objects.h @@ -74,6 +74,9 @@ struct serial_s { uint32_t parity; PinName pin_tx; PinName pin_rx; +#if DEVICE_SERIAL_ASYNCH + uint32_t events; +#endif }; struct spi_s { diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c index db69e2eef1..b432fd6e29 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c @@ -39,36 +39,100 @@ #include "mbed_error.h" #define UART_NUM (8) +#define UART_STATE_RX_ACTIVE 0x20 +#define UART_STATE_TX_ACTIVE 0x10 static uint32_t serial_irq_ids[UART_NUM] = {0, 0, 0, 0, 0, 0, 0, 0}; +#if DEVICE_SERIAL_ASYNCH_DMA +static const uint32_t DMA_UartRx_Channel[UART_NUM] = {DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_5, DMA_CHANNEL_5, DMA_CHANNEL_5}; +static const uint32_t DMA_UartRx_Stream[UART_NUM] = {(uint32_t)DMA2_Stream5, (uint32_t) DMA1_Stream5, (uint32_t) DMA1_Stream1, (uint32_t) DMA1_Stream2, (uint32_t) DMA1_Stream0, (uint32_t) DMA2_Stream5, (uint32_t) DMA1_Stream3, (uint32_t) DMA1_Stream6}; +static const uint32_t DMA_UartTx_Channel[UART_NUM] = {DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_4, DMA_CHANNEL_5, DMA_CHANNEL_5, DMA_CHANNEL_5}; +static const uint32_t DMA_UartTx_Stream[UART_NUM] = {(uint32_t)DMA2_Stream7, (uint32_t) DMA1_Stream6, (uint32_t) DMA1_Stream3, (uint32_t) DMA1_Stream4, (uint32_t) DMA1_Stream7, (uint32_t) DMA2_Stream6, (uint32_t) DMA1_Stream1, (uint32_t) DMA1_Stream0}; + +#endif static uart_irq_handler irq_handler; +DMA_HandleTypeDef DmaHandle; UART_HandleTypeDef UartHandle; int stdio_uart_inited = 0; serial_t stdio_uart; +#if DEVICE_SERIAL_ASYNCH +#define SERIAL_OBJ(X) (obj->serial.X) +#else +#define SERIAL_OBJ(X) (obj->X) +#endif + static void init_uart(serial_t *obj) { - UartHandle.Instance = (USART_TypeDef *)(obj->uart); +#if DEVICE_SERIAL_ASYNCH_DMA + static DMA_HandleTypeDef hdma_tx; + static DMA_HandleTypeDef hdma_rx; +#endif - UartHandle.Init.BaudRate = obj->baudrate; - UartHandle.Init.WordLength = obj->databits; - UartHandle.Init.StopBits = obj->stopbits; - UartHandle.Init.Parity = obj->parity; + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); + + UartHandle.Init.BaudRate = SERIAL_OBJ(baudrate); + UartHandle.Init.WordLength = SERIAL_OBJ(databits); + UartHandle.Init.StopBits = SERIAL_OBJ(stopbits); + UartHandle.Init.Parity = SERIAL_OBJ(parity); UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; + UartHandle.Init.OverSampling = UART_OVERSAMPLING_16; - if (obj->pin_rx == NC) { + if (SERIAL_OBJ(pin_rx) == NC) { UartHandle.Init.Mode = UART_MODE_TX; - } else if (obj->pin_tx == NC) { + } else if (SERIAL_OBJ(pin_tx) == NC) { UartHandle.Init.Mode = UART_MODE_RX; } else { UartHandle.Init.Mode = UART_MODE_TX_RX; } +#if DEVICE_SERIAL_ASYNCH_DMA + // set DMA in the UartHandle + /* Configure the DMA handler for Transmission process */ + hdma_tx.Instance = (DMA_Stream_TypeDef *)DMA_UartTx_Stream[SERIAL_OBJ(index)]; + hdma_tx.Init.Channel = DMA_UartTx_Channel[SERIAL_OBJ(index)]; + hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_tx.Init.Mode = DMA_NORMAL; + hdma_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_tx.Init.MemBurst = DMA_MBURST_INC4; + hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4; + + HAL_DMA_Init(&hdma_tx); + + /* Associate the initialized DMA handle to the UART handle */ + __HAL_LINKDMA(&UartHandle, hdmatx, hdma_tx); + + /* Configure the DMA handler for reception process */ + hdma_rx.Instance = (DMA_Stream_TypeDef *)DMA_UartRx_Stream[SERIAL_OBJ(index)]; + hdma_rx.Init.Channel = DMA_UartRx_Channel[SERIAL_OBJ(index)]; + hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_rx.Init.Mode = DMA_NORMAL; + hdma_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_rx.Init.MemBurst = DMA_MBURST_INC4; + hdma_rx.Init.PeriphBurst = DMA_PBURST_INC4; + + HAL_DMA_Init(&hdma_rx); + + /* Associate the initialized DMA handle to the UART handle */ + __HAL_LINKDMA(&UartHandle, hdmarx, hdma_rx); +#endif if (HAL_UART_Init(&UartHandle) != HAL_OK) { - error("Cannot initialize UART"); + error("Cannot initialize UART\n"); } } @@ -79,53 +143,78 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); // Get the peripheral name (UART_1, UART_2, ...) from the pin and assign it to the object - obj->uart = (UARTName)pinmap_merge(uart_tx, uart_rx); - MBED_ASSERT(obj->uart != (UARTName)NC); + SERIAL_OBJ(uart) = (UARTName)pinmap_merge(uart_tx, uart_rx); + + MBED_ASSERT(SERIAL_OBJ(uart) != (UARTName)NC); // Enable USART clock - switch (obj->uart) { + switch (SERIAL_OBJ(uart)) { case UART_1: __HAL_RCC_USART1_CLK_ENABLE(); - obj->index = 0; + SERIAL_OBJ(index) = 0; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA2_CLK_ENABLE(); +#endif break; case UART_2: __HAL_RCC_USART2_CLK_ENABLE(); - obj->index = 1; + SERIAL_OBJ(index) = 1; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA1_CLK_ENABLE(); +#endif break; #if defined(USART3_BASE) case UART_3: __HAL_RCC_USART3_CLK_ENABLE(); - obj->index = 2; + SERIAL_OBJ(index) = 2; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA1_CLK_ENABLE(); +#endif break; #endif #if defined(UART4_BASE) case UART_4: __HAL_RCC_UART4_CLK_ENABLE(); - obj->index = 3; + SERIAL_OBJ(index) = 3; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA1_CLK_ENABLE(); +#endif break; #endif #if defined(UART5_BASE) case UART_5: __HAL_RCC_UART5_CLK_ENABLE(); - obj->index = 4; + SERIAL_OBJ(index) = 4; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA1_CLK_ENABLE(); +#endif break; #endif #if defined(USART6_BASE) case UART_6: __HAL_RCC_USART6_CLK_ENABLE(); - obj->index = 5; + SERIAL_OBJ(index) = 5; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA2_CLK_ENABLE(); +#endif break; #endif #if defined(UART7_BASE) case UART_7: __HAL_RCC_UART7_CLK_ENABLE(); - obj->index = 6; + SERIAL_OBJ(index) = 6; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA1_CLK_ENABLE(); +#endif break; #endif #if defined(UART8_BASE) case UART_8: __HAL_RCC_UART8_CLK_ENABLE(); - obj->index = 7; + SERIAL_OBJ(index) = 7; +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA1_CLK_ENABLE(); +#endif break; #endif } @@ -133,6 +222,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) // Configure the UART pins pinmap_pinout(tx, PinMap_UART_TX); pinmap_pinout(rx, PinMap_UART_RX); + if (tx != NC) { pin_mode(tx, PullUp); } @@ -141,18 +231,18 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) } // Configure UART - obj->baudrate = 9600; - obj->databits = UART_WORDLENGTH_8B; - obj->stopbits = UART_STOPBITS_1; - obj->parity = UART_PARITY_NONE; + SERIAL_OBJ(baudrate) = 9600; + SERIAL_OBJ(databits) = UART_WORDLENGTH_8B; + SERIAL_OBJ(stopbits) = UART_STOPBITS_1; + SERIAL_OBJ(parity) = UART_PARITY_NONE; - obj->pin_tx = tx; - obj->pin_rx = rx; + SERIAL_OBJ(pin_tx) = tx; + SERIAL_OBJ(pin_rx) = rx; init_uart(obj); // For stdio management - if (obj->uart == STDIO_UART) { + if (SERIAL_OBJ(uart) == STDIO_UART) { stdio_uart_inited = 1; memcpy(&stdio_uart, obj, sizeof(serial_t)); } @@ -161,7 +251,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) void serial_free(serial_t *obj) { // Reset UART and disable clock - switch (obj->uart) { + switch (SERIAL_OBJ(uart)) { case UART_1: __USART1_FORCE_RESET(); __USART1_RELEASE_RESET(); @@ -184,6 +274,9 @@ void serial_free(serial_t *obj) __UART4_FORCE_RESET(); __UART4_RELEASE_RESET(); __UART4_CLK_DISABLE(); +#if DEVICE_SERIAL_ASYNCH_DMA + __HAL_RCC_DMA1_CLK_DISABLE(); +#endif break; #endif #if defined(UART5_BASE) @@ -216,44 +309,44 @@ void serial_free(serial_t *obj) #endif } // Configure GPIOs - pin_function(obj->pin_tx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); - pin_function(obj->pin_rx, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + pin_function(SERIAL_OBJ(pin_tx), STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); + pin_function(SERIAL_OBJ(pin_rx), STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)); - serial_irq_ids[obj->index] = 0; + serial_irq_ids[SERIAL_OBJ(index)] = 0; } void serial_baud(serial_t *obj, int baudrate) { - obj->baudrate = baudrate; + SERIAL_OBJ(baudrate) = baudrate; init_uart(obj); } void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) { if (data_bits == 9) { - obj->databits = UART_WORDLENGTH_9B; + SERIAL_OBJ(databits) = UART_WORDLENGTH_9B; } else { - obj->databits = UART_WORDLENGTH_8B; + SERIAL_OBJ(databits) = UART_WORDLENGTH_8B; } switch (parity) { case ParityOdd: case ParityForced0: - obj->parity = UART_PARITY_ODD; + SERIAL_OBJ(parity) = UART_PARITY_ODD; break; case ParityEven: case ParityForced1: - obj->parity = UART_PARITY_EVEN; + SERIAL_OBJ(parity) = UART_PARITY_EVEN; break; default: // ParityNone - obj->parity = UART_PARITY_NONE; + SERIAL_OBJ(parity) = UART_PARITY_NONE; break; } if (stop_bits == 2) { - obj->stopbits = UART_STOPBITS_2; + SERIAL_OBJ(stopbits) = UART_STOPBITS_2; } else { - obj->stopbits = UART_STOPBITS_1; + SERIAL_OBJ(stopbits) = UART_STOPBITS_1; } init_uart(obj); @@ -277,6 +370,23 @@ static void uart_irq(UARTName name, int id) } } } +#if DEVICE_SERIAL_ASYNCH_DMA +static void dma_irq(DMAName name, int id) +{ + // TO DO + DmaHandle.Instance = (DMA_Stream_TypeDef *)name; + if (serial_irq_ids[id] != 0) { + if (__HAL_DMA_GET_TC_FLAG_INDEX(&DmaHandle) != RESET) { + irq_handler(serial_irq_ids[id], TxIrq); + __HAL_DMA_CLEAR_FLAG(&DmaHandle, DMA_FLAG_TCIF0_4); + } + if (__HAL_DMA_GET_TC_FLAG_INDEX(&DmaHandle) != RESET) { + irq_handler(serial_irq_ids[id], RxIrq); + __HAL_DMA_CLEAR_FLAG(&DmaHandle, DMA_FLAG_TCIF2_6); + } + } +} +#endif static void uart1_irq(void) { @@ -300,6 +410,19 @@ static void uart4_irq(void) { uart_irq(UART_4, 3); } +#if DEVICE_SERIAL_ASYNCH_DMA + +static void dma1_stream2_irq(void) +{ + dma_irq(DMA_1, 3 /* TO DO : ??? WHAT IS THIS 3 ??? */); +} + + +static void dma1_stream4_irq(void) +{ + dma_irq(DMA_1, 3 /* TO DO : ??? WHAT IS THIS 3 ??? */); +} +#endif #endif #if defined(UART5_BASE) @@ -333,17 +456,21 @@ static void uart8_irq(void) void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) { irq_handler = handler; - serial_irq_ids[obj->index] = id; + serial_irq_ids[SERIAL_OBJ(index)] = id; } void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { IRQn_Type irq_n = (IRQn_Type)0; uint32_t vector = 0; +#if DEVICE_SERIAL_ASYNCH_DMA + IRQn_Type irqn_dma = (IRQn_Type)0; + uint32_t vector_dma = 0; +#endif - UartHandle.Instance = (USART_TypeDef *)(obj->uart); + UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); - switch (obj->uart) { + switch (SERIAL_OBJ(uart)) { case UART_1: irq_n = USART1_IRQn; vector = (uint32_t)&uart1_irq; @@ -363,6 +490,15 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) case UART_4: irq_n = UART4_IRQn; vector = (uint32_t)&uart4_irq; +#if DEVICE_SERIAL_ASYNCH_DMA + if (irq == RxIrq) { + irqn_dma = DMA1_Stream2_IRQn; + vector_dma = (uint32_t)&dma1_stream2_irq; + } else { + irqn_dma = DMA1_Stream4_IRQn; + vector_dma = (uint32_t)&dma1_stream4_irq; + } +#endif break; #endif #if defined(UART5_BASE) @@ -395,13 +531,24 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) if (irq == RxIrq) { __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_RXNE); +#if DEVICE_SERIAL_ASYNCH_DMA + NVIC_SetVector(irq_n, vector_dma); + NVIC_EnableIRQ(irq_n); + NVIC_SetVector(irqn_dma, vector_dma); + NVIC_EnableIRQ(irqn_dma); +#else + NVIC_SetVector(irq_n, vector); + NVIC_EnableIRQ(irq_n); +#endif } else { // TxIrq __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_TC); + NVIC_SetVector(irq_n, vector); + NVIC_EnableIRQ(irq_n); +#if DEVICE_SERIAL_ASYNCH_DMA + NVIC_SetVector(irqn_dma, vector_dma); + NVIC_EnableIRQ(irqn_dma); +#endif } - - NVIC_SetVector(irq_n, vector); - NVIC_EnableIRQ(irq_n); - } else { // disable int all_disabled = 0; @@ -416,7 +563,12 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) if ((UartHandle.Instance->CR1 & USART_CR1_RXNEIE) == 0) all_disabled = 1; } - if (all_disabled) NVIC_DisableIRQ(irq_n); + if (all_disabled) { + NVIC_DisableIRQ(irq_n); +#if DEVICE_SERIAL_ASYNCH_DMA + NVIC_DisableIRQ(irqn_dma); +#endif + } } } @@ -427,14 +579,14 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) int serial_getc(serial_t *obj) { - USART_TypeDef *uart = (USART_TypeDef *)(obj->uart); + USART_TypeDef *uart = (USART_TypeDef *)(SERIAL_OBJ(uart)); while (!serial_readable(obj)); return (int)(uart->DR & 0x1FF); } void serial_putc(serial_t *obj, int c) { - USART_TypeDef *uart = (USART_TypeDef *)(obj->uart); + USART_TypeDef *uart = (USART_TypeDef *)(SERIAL_OBJ(uart)); while (!serial_writable(obj)); uart->DR = (uint32_t)(c & 0x1FF); } @@ -442,7 +594,7 @@ void serial_putc(serial_t *obj, int c) int serial_readable(serial_t *obj) { int status; - UartHandle.Instance = (USART_TypeDef *)(obj->uart); + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); // Check if data is received status = ((__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE) != RESET) ? 1 : 0); return status; @@ -451,7 +603,7 @@ int serial_readable(serial_t *obj) int serial_writable(serial_t *obj) { int status; - UartHandle.Instance = (USART_TypeDef *)(obj->uart); + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); // Check if data is transmitted status = ((__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_TXE) != RESET) ? 1 : 0); return status; @@ -459,7 +611,7 @@ int serial_writable(serial_t *obj) void serial_clear(serial_t *obj) { - UartHandle.Instance = (USART_TypeDef *)(obj->uart); + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); __HAL_UART_CLEAR_FLAG(&UartHandle, UART_FLAG_TXE); __HAL_UART_CLEAR_FLAG(&UartHandle, UART_FLAG_RXNE); } @@ -471,7 +623,7 @@ void serial_pinout_tx(PinName tx) void serial_break_set(serial_t *obj) { - UartHandle.Instance = (USART_TypeDef *)(obj->uart); + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); HAL_LIN_SendBreak(&UartHandle); } @@ -479,4 +631,537 @@ void serial_break_clear(serial_t *obj) { } +//######################################################################################## + +#if DEVICE_SERIAL_ASYNCH + +//---------------------------------------------------------------------------------------- +// LOCAL HELPER FUNCTIONS +//---------------------------------------------------------------------------------------- + +/** Configure the TX buffer for an asynchronous write serial transaction + * + * @param obj The serial object. + * @param tx The buffer for sending. + * @param tx_length The number of words to transmit. + */ +void h_serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width) +{ + // We only support byte buffers for now + MBED_ASSERT(width == 8); + UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); + + // Exit if a transmit is already on-going + if (serial_tx_active(obj)) return; + + obj->tx_buff.buffer = tx; + obj->tx_buff.length = tx_length; + obj->tx_buff.pos = 0; + + return; +} + +/** Configure the RX buffer for an asynchronous write serial transaction + * + * @param obj The serial object. + * @param tx The buffer for sending. + * @param tx_length The number of words to transmit. + */ +void h_serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + MBED_ASSERT(rx != (void*)0); + // We only support byte buffers for now + MBED_ASSERT(width == 8); + + // Exit if a reception is already on-going + if (serial_rx_active(obj)) return; + + obj->rx_buff.buffer = rx; + obj->rx_buff.length = rx_length; + obj->rx_buff.pos = 0; + + return; +} + +/** Configure TX events + * + * @param obj The serial object + * @param event The logical OR of the TX events to configure + * @param enable Set to non-zero to enable events, or zero to disable them + */ +void h_serial_tx_enable_event(serial_t *obj, int event, uint8_t enable) +{ + // Shouldn't have to enable TX interrupt here, just need to keep track of the requested events. + if (enable) SERIAL_OBJ(events) |= event; + else SERIAL_OBJ(events) &= ~event; +} + +/** Configure RX events + * + * @param obj The serial object + * @param event The logical OR of the RX events to configure + * @param enable Set to non-zero to enable events, or zero to disable them + */ +void h_serial_rx_enable_event(serial_t *obj, int event, uint8_t enable) +{ + // Shouldn't have to enable RX interrupt here, just need to keep track of the requested events. + if (enable) SERIAL_OBJ(events) |= event; + else SERIAL_OBJ(events) &= ~event; +} + +/** +* Get index of serial object TX IRQ, relating it to the physical peripheral. +* +* @param obj pointer to serial object +* @return internal NVIC TX IRQ index of U(S)ART peripheral +*/ +IRQn_Type h_serial_get_irq_index(serial_t *obj) +{ + IRQn_Type irq_n = (IRQn_Type)0; + + UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); + + switch (SERIAL_OBJ(uart)) { +#if defined(USART1_BASE) + case UART_1: + irq_n = USART1_IRQn; + break; +#endif +#if defined(USART2_BASE) + case UART_2: + irq_n = USART2_IRQn; + break; +#endif +#if defined(USART3_BASE) + case UART_3: + irq_n = USART3_IRQn; + break; +#endif +#if defined(UART4_BASE) + case UART_4: + irq_n = UART4_IRQn; + break; +#endif +#if defined(UART5_BASE) + case UART_5: + irq_n = UART5_IRQn; + break; +#endif +#if defined(USART6_BASE) + case UART_6: + irq_n = USART6_IRQn; + break; +#endif +#if defined(UART7_BASE) + case UART_7: + irq_n = UART7_IRQn; + break; +#endif +#if defined(UART8_BASE) + case UART_8: + irq_n = UART8_IRQn; + break; +#endif + default: + irq_n = (IRQn_Type)0; + } + + return irq_n; +} + +#if DEVICE_SERIAL_ASYNCH_DMA + +/** The asynchronous TX and RX handler. + * + * @param obj The serial object + * @return Returns event flags if a TX/RX transfer termination condition was met or 0 otherwise + */ +void h_serial_txdma_irq_handler_asynch() +{ + HAL_DMA_IRQHandler(UartHandle.hdmatx); +} +/** The asynchronous TX and RX handler. + * + * @param obj The serial object + * @return Returns event flags if a TX/RX transfer termination condition was met or 0 otherwise + */ +void h_serial_rxdma_irq_handler_asynch(serial_t *obj) +{ +// UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); + HAL_DMA_IRQHandler(UartHandle.hdmarx); +} + +/** +* Get index of serial object TX DMA IRQ, relating it to the physical peripheral. +* +* @param obj pointer to serial object +* @return internal NVIC TX DMA IRQ index of U(S)ART peripheral +*/ +IRQn_Type h_serial_tx_get_irqdma_index(serial_t *obj) +{ + IRQn_Type irq_n = (IRQn_Type)0; + + UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); + + switch (SERIAL_OBJ(uart)) { +#if defined(USART1_BASE) + case UART_1: + irq_n = DMA2_Stream7_IRQn; + break; +#endif +#if defined(USART2_BASE) + case UART_2: + irq_n = DMA1_Stream6_IRQn; + break; +#endif +#if defined(USART3_BASE) + case UART_3: + irq_n = DMA1_Stream3_IRQn; + break; +#endif +#if defined(UART4_BASE) + case UART_4: + irq_n = DMA1_Stream4_IRQn; + break; +#endif +#if defined(UART5_BASE) + case UART_5: + irq_n = DMA1_Stream7_IRQn; + break; +#endif +#if defined(USART6_BASE) + case UART_6: + irq_n = DMA2_Stream6_IRQn; + break; +#endif +#if defined(UART7_BASE) + case UART_7: + irq_n = DMA1_Stream1_IRQn; + break; +#endif +#if defined(UART8_BASE) + case UART_8: + irq_n = DMA1_Stream0_IRQn; + break; +#endif + default: + irq_n = (IRQn_Type)0; + } + + return irq_n; +} +/** +* Get index of serial object RX DMA IRQ, relating it to the physical peripheral. +* +* @param obj pointer to serial object +* @return internal NVIC RX DMA IRQ index of U(S)ART peripheral +*/ +IRQn_Type h_serial_rx_get_irqdma_index(serial_t *obj) +{ + IRQn_Type irq_n = (IRQn_Type)0; + + UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); + + switch (SERIAL_OBJ(uart)) { +#if defined(USART1_BASE) + case UART_1: + irq_n = DMA2_Stream5_IRQn; + break; +#endif +#if defined(USART2_BASE) + case UART_2: + irq_n = DMA1_Stream5_IRQn; + break; +#endif +#if defined(USART3_BASE) + case UART_3: + irq_n = DMA1_Stream1_IRQn; + break; +#endif +#if defined(UART4_BASE) + case UART_4: + irq_n = DMA1_Stream2_IRQn; + break; +#endif +#if defined(UART5_BASE) + case UART_5: + irq_n = DMA1_Stream0_IRQn; + break; +#endif +#if defined(USART6_BASE) + case UART_6: + irq_n = DMA2_Stream2_IRQn; + break; +#endif +#if defined(UART7_BASE) + case UART_7: + irq_n = DMA1_Stream3_IRQn; + break; +#endif +#if defined(UART8_BASE) + case UART_8: + irq_n = DMA1_Stream6_IRQn; + break; +#endif + default: + irq_n = (IRQn_Type)0; + } + + return irq_n; +} +#endif +//---------------------------------------------------------------------------------------- +// MBED API FUNCTIONS +//---------------------------------------------------------------------------------------- + +/** Begin asynchronous TX transfer. The used buffer is specified in the serial object, + * tx_buff + * + * @param obj The serial object + * @param tx The buffer for sending + * @param tx_length The number of words to transmit + * @param tx_width The bit width of buffer word + * @param handler The serial handler + * @param event The logical OR of events to be registered + * @param hint A suggestion for how to use DMA with this transfer + * @return Returns number of data transfered, or 0 otherwise + */ +int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint) +{ + + uint32_t tmpstatus = 0; + + // Check buffer is ok + MBED_ASSERT(tx != (void*)0); + MBED_ASSERT(tx_width == 8); // support only 8b width + + if (tx_length == 0) return 0; + + // Set up buffer + h_serial_tx_buffer_set(obj, (void *)tx, tx_length, tx_width); + + // Set up events + h_serial_tx_enable_event(obj, SERIAL_EVENT_TX_ALL, 0); // Clear all events + h_serial_tx_enable_event(obj, event, 1); // Set only the wanted events + + // Enable interrupt + IRQn_Type irqn = h_serial_get_irq_index(obj); + NVIC_ClearPendingIRQ(irqn); + NVIC_DisableIRQ(irqn); + NVIC_SetPriority(irqn, 1); + NVIC_SetVector(irqn, (uint32_t)handler); + UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); + NVIC_EnableIRQ(irqn); + +#if DEVICE_SERIAL_ASYNCH_DMA + // Enable DMA interrupt + irqn = h_serial_tx_get_irqdma_index(obj); + NVIC_ClearPendingIRQ(irqn); + NVIC_DisableIRQ(irqn); + NVIC_SetPriority(irqn, 1); +// NVIC_SetVector(irqn, (uint32_t)&h_serial_txdma_irq_handler_asynch); + NVIC_SetVector(irqn, (uint32_t)handler); + NVIC_EnableIRQ(irqn); + + // the following function will enable program and enable the DMA transfer + if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)tx, tx_length) != HAL_OK) + { + /* Transfer error in transmission process */ + return 0; + } +#else + // the following function will enable UART_IT_TXE and error interrupts + if (HAL_UART_Transmit_IT(&UartHandle, (uint8_t*)tx, tx_length) != HAL_OK) + { + /* Transfer error in transmission process */ + return 0; + } +#endif + + while ((tmpstatus == HAL_UART_STATE_BUSY_TX) || (tmpstatus == HAL_UART_STATE_BUSY_TX_RX)){ + tmpstatus = HAL_UART_GetState(&UartHandle); + } + + return tx_length; +} + +/** Begin asynchronous RX transfer (enable interrupt for data collecting) + * The used buffer is specified in the serial object - rx_buff + * + * @param obj The serial object + * @param rx The buffer for sending + * @param rx_length The number of words to transmit + * @param rx_width The bit width of buffer word + * @param handler The serial handler + * @param event The logical OR of events to be registered + * @param handler The serial handler + * @param char_match A character in range 0-254 to be matched + * @param hint A suggestion for how to use DMA with this transfer + */ +void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint) +{ + /* Sanity check arguments */ + MBED_ASSERT(obj); + MBED_ASSERT(rx != (void*)0); + MBED_ASSERT(rx_width == 8); // support only 8b width + + h_serial_rx_enable_event(obj, SERIAL_EVENT_RX_ALL, 0); + h_serial_rx_enable_event(obj, event, 1); + // set CharMatch + if (char_match != SERIAL_RESERVED_CHAR_MATCH) { + obj->char_match = char_match; + } + h_serial_rx_buffer_set(obj, rx, rx_length, rx_width); + + IRQn_Type irqn = h_serial_get_irq_index(obj); + NVIC_ClearPendingIRQ(irqn); + NVIC_DisableIRQ(irqn); + NVIC_SetPriority(irqn, 0); + NVIC_SetVector(irqn, (uint32_t)handler); + NVIC_EnableIRQ(irqn); + + UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); +#if DEVICE_SERIAL_ASYNCH_DMA + // Enable DMA interrupt + irqn = h_serial_rx_get_irqdma_index(obj); + NVIC_ClearPendingIRQ(irqn); + NVIC_DisableIRQ(irqn); + NVIC_SetPriority(irqn, 1); + NVIC_SetVector(irqn, (uint32_t)handler); + + NVIC_EnableIRQ(irqn); + // following HAL function will program and enable the DMA transfer + HAL_UART_Receive_DMA(&UartHandle, (uint8_t*)rx, rx_length); +#else + // following HAL function will enable the RXNE interrupt + error interrupts + HAL_UART_Receive_IT(&UartHandle, (uint8_t*)rx, rx_length); +#endif + + return; +} + +/** Attempts to determine if the serial peripheral is already in use for TX + * + * @param obj The serial object + * @return Non-zero if the TX transaction is ongoing, 0 otherwise + */ +uint8_t serial_tx_active(serial_t *obj) +{ + MBED_ASSERT(obj); + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); + return ((HAL_UART_GetState(&UartHandle) & UART_STATE_TX_ACTIVE) ? 1 : 0); +} + +/** Attempts to determine if the serial peripheral is already in use for RX + * + * @param obj The serial object + * @return Non-zero if the RX transaction is ongoing, 0 otherwise + */ +uint8_t serial_rx_active(serial_t *obj) +{ + MBED_ASSERT(obj); + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); + return ((HAL_UART_GetState(&UartHandle) & UART_STATE_RX_ACTIVE) ? 1 : 0); + +} + +/** The asynchronous TX and RX handler. + * + * @param obj The serial object + * @return Returns event flags if a TX/RX transfer termination condition was met or 0 otherwise + */ +int serial_irq_handler_asynch(serial_t *obj) +{ + volatile int return_event = 0; + uint8_t *buf = (uint8_t*)obj->rx_buff.buffer; + + // Irq handler is common to Tx and Rx + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); +#if DEVICE_SERIAL_ASYNCH_DMA + if ((UartHandle.Instance->CR3 & USART_CR3_DMAT) !=0) { + // call dma tx interrupt + HAL_DMA_IRQHandler(UartHandle.hdmatx); + } + if ((UartHandle.Instance->CR3 & USART_CR3_DMAR) !=0) { + // call dma rx interrupt + HAL_DMA_IRQHandler(UartHandle.hdmarx); + } +#endif + HAL_UART_IRQHandler(&UartHandle); + // TX PART: + if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_TC) != RESET) { + __HAL_UART_CLEAR_FLAG(&UartHandle, UART_FLAG_TC); + // return event SERIAL_EVENT_TX_COMPLETE if requested + if ((SERIAL_OBJ(events) & SERIAL_EVENT_TX_COMPLETE ) != 0){ + return_event |= SERIAL_EVENT_TX_COMPLETE & obj->serial.events; + } + } + // handle error events: + if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_PE)) { + __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_PE); + return_event |= SERIAL_EVENT_RX_PARITY_ERROR & obj->serial.events; + } + if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_NE)) { + __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_NE); + // not supported by mbed + } + if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_FE)) { + __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_FE); + return_event |= SERIAL_EVENT_RX_FRAMING_ERROR & obj->serial.events; + } + if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_ORE)) { + __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_ORE); + return_event |= SERIAL_EVENT_RX_OVERRUN_ERROR & obj->serial.events; + } + + //RX PART + // increment rx_buff.pos + if (UartHandle.RxXferSize !=0) { + obj->rx_buff.pos = UartHandle.RxXferSize - UartHandle.RxXferCount; + } + if ((UartHandle.RxXferCount==0)&&(obj->rx_buff.pos >= (obj->rx_buff.length - 1))) { + return_event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events; + } + if ((buf != NULL) && (buf[obj->rx_buff.pos-1] == obj->char_match) && (SERIAL_OBJ(events) & SERIAL_EVENT_RX_CHARACTER_MATCH)) { + return_event |= SERIAL_EVENT_RX_CHARACTER_MATCH & obj->serial.events; + } + return return_event; +} + +/** Abort the ongoing TX transaction. It disables the enabled interupt for TX and + * flush TX hardware buffer if TX FIFO is used + * + * @param obj The serial object + */ +void serial_tx_abort_asynch(serial_t *obj) +{ + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); + __HAL_UART_DISABLE_IT(&UartHandle, UART_IT_TC|UART_IT_TXE); + UartHandle.Instance = 0; + + obj->tx_buff.buffer = 0; + obj->tx_buff.length = 0; + +} + +/** Abort the ongoing RX transaction It disables the enabled interrupt for RX and + * flush RX hardware buffer if RX FIFO is used + * + * @param obj The serial object + */ +void serial_rx_abort_asynch(serial_t *obj) +{ + UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); + __HAL_UART_DISABLE_IT(&UartHandle, UART_IT_RXNE); + UartHandle.Instance = 0; + + obj->rx_buff.buffer = 0; + obj->rx_buff.length = 0; + +} + +#endif + #endif From 016976b79dc29ca5e5b0f5511a3c0256ad15544e Mon Sep 17 00:00:00 2001 From: adustm Date: Thu, 21 Jan 2016 15:54:36 +0100 Subject: [PATCH 2/5] [B96B_F446VE] bug fix for serial_async unitary test do not initialise dma tx/rx when it is not activated. --- .../TARGET_STM/TARGET_STM32F4/serial_api.c | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c index b432fd6e29..d17af1d276 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c @@ -89,27 +89,30 @@ static void init_uart(serial_t *obj) UartHandle.Init.Mode = UART_MODE_TX_RX; } #if DEVICE_SERIAL_ASYNCH_DMA - // set DMA in the UartHandle - /* Configure the DMA handler for Transmission process */ - hdma_tx.Instance = (DMA_Stream_TypeDef *)DMA_UartTx_Stream[SERIAL_OBJ(index)]; - hdma_tx.Init.Channel = DMA_UartTx_Channel[SERIAL_OBJ(index)]; - hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; - hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_tx.Init.MemInc = DMA_MINC_ENABLE; - hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_tx.Init.Mode = DMA_NORMAL; - hdma_tx.Init.Priority = DMA_PRIORITY_LOW; - hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; - hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - hdma_tx.Init.MemBurst = DMA_MBURST_INC4; - hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4; + if (SERIAL_OBJ(pin_tx) != NC) { + // set DMA in the UartHandle + /* Configure the DMA handler for Transmission process */ + hdma_tx.Instance = (DMA_Stream_TypeDef *)DMA_UartTx_Stream[SERIAL_OBJ(index)]; + hdma_tx.Init.Channel = DMA_UartTx_Channel[SERIAL_OBJ(index)]; + hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_tx.Init.Mode = DMA_NORMAL; + hdma_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_tx.Init.MemBurst = DMA_MBURST_INC4; + hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4; HAL_DMA_Init(&hdma_tx); /* Associate the initialized DMA handle to the UART handle */ __HAL_LINKDMA(&UartHandle, hdmatx, hdma_tx); - + } + + if (SERIAL_OBJ(pin_rx) != NC) { /* Configure the DMA handler for reception process */ hdma_rx.Instance = (DMA_Stream_TypeDef *)DMA_UartRx_Stream[SERIAL_OBJ(index)]; hdma_rx.Init.Channel = DMA_UartRx_Channel[SERIAL_OBJ(index)]; @@ -129,6 +132,7 @@ static void init_uart(serial_t *obj) /* Associate the initialized DMA handle to the UART handle */ __HAL_LINKDMA(&UartHandle, hdmarx, hdma_rx); + } #endif if (HAL_UART_Init(&UartHandle) != HAL_OK) { From 2582578e6bd7c7e761522676be8b76a54d356926 Mon Sep 17 00:00:00 2001 From: adustm Date: Tue, 26 Jan 2016 11:30:55 +0100 Subject: [PATCH 3/5] [B96B_ASYNC] some fixes to pass serial_asynch.cpp test Flush errors and current data register at reading start Allow separate serial obj for TX and RX (= do not initialize [TX/RX]_DMA when not needed. Char_match: make it work with long buffers and return the correct position of the char_match. --- .../TARGET_STM/TARGET_STM32F4/serial_api.c | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c index d17af1d276..2e35b0f841 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c @@ -106,32 +106,32 @@ static void init_uart(serial_t *obj) hdma_tx.Init.MemBurst = DMA_MBURST_INC4; hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4; - HAL_DMA_Init(&hdma_tx); + HAL_DMA_Init(&hdma_tx); - /* Associate the initialized DMA handle to the UART handle */ - __HAL_LINKDMA(&UartHandle, hdmatx, hdma_tx); + /* Associate the initialized DMA handle to the UART handle */ + __HAL_LINKDMA(&UartHandle, hdmatx, hdma_tx); } if (SERIAL_OBJ(pin_rx) != NC) { - /* Configure the DMA handler for reception process */ - hdma_rx.Instance = (DMA_Stream_TypeDef *)DMA_UartRx_Stream[SERIAL_OBJ(index)]; - hdma_rx.Init.Channel = DMA_UartRx_Channel[SERIAL_OBJ(index)]; - hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; - hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_rx.Init.MemInc = DMA_MINC_ENABLE; - hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_rx.Init.Mode = DMA_NORMAL; - hdma_rx.Init.Priority = DMA_PRIORITY_HIGH; - hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; - hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - hdma_rx.Init.MemBurst = DMA_MBURST_INC4; - hdma_rx.Init.PeriphBurst = DMA_PBURST_INC4; + /* Configure the DMA handler for reception process */ + hdma_rx.Instance = (DMA_Stream_TypeDef *)DMA_UartRx_Stream[SERIAL_OBJ(index)]; + hdma_rx.Init.Channel = DMA_UartRx_Channel[SERIAL_OBJ(index)]; + hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_rx.Init.Mode = DMA_NORMAL; + hdma_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_rx.Init.MemBurst = DMA_MBURST_INC4; + hdma_rx.Init.PeriphBurst = DMA_PBURST_INC4; - HAL_DMA_Init(&hdma_rx); + HAL_DMA_Init(&hdma_rx); - /* Associate the initialized DMA handle to the UART handle */ - __HAL_LINKDMA(&UartHandle, hdmarx, hdma_rx); + /* Associate the initialized DMA handle to the UART handle */ + __HAL_LINKDMA(&UartHandle, hdmarx, hdma_rx); } #endif @@ -1027,6 +1027,8 @@ void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_widt NVIC_EnableIRQ(irqn); UartHandle.Instance = (USART_TypeDef *)SERIAL_OBJ(uart); + // flush current data + error flags + __HAL_UART_CLEAR_PEFLAG(&UartHandle); #if DEVICE_SERIAL_ASYNCH_DMA // Enable DMA interrupt irqn = h_serial_rx_get_irqdma_index(obj); @@ -1042,7 +1044,9 @@ void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_widt // following HAL function will enable the RXNE interrupt + error interrupts HAL_UART_Receive_IT(&UartHandle, (uint8_t*)rx, rx_length); #endif - + /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ + __HAL_UART_ENABLE_IT(&UartHandle, UART_IT_ERR); + return; } @@ -1078,8 +1082,9 @@ uint8_t serial_rx_active(serial_t *obj) */ int serial_irq_handler_asynch(serial_t *obj) { - volatile int return_event = 0; - uint8_t *buf = (uint8_t*)obj->rx_buff.buffer; + volatile int return_event = 0; + uint8_t *buf = (uint8_t*)obj->rx_buff.buffer; + uint8_t i = 0; // Irq handler is common to Tx and Rx UartHandle.Instance = (USART_TypeDef *)(SERIAL_OBJ(uart)); @@ -1107,15 +1112,15 @@ int serial_irq_handler_asynch(serial_t *obj) __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_PE); return_event |= SERIAL_EVENT_RX_PARITY_ERROR & obj->serial.events; } - if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_NE)) { + if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_NE)||(UartHandle.ErrorCode & HAL_UART_ERROR_NE)!=0) { __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_NE); // not supported by mbed } - if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_FE)) { + if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_FE)||(UartHandle.ErrorCode & HAL_UART_ERROR_FE)!=0) { __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_FE); return_event |= SERIAL_EVENT_RX_FRAMING_ERROR & obj->serial.events; } - if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_ORE)) { + if (__HAL_UART_GET_FLAG(&UartHandle, HAL_UART_ERROR_ORE)||(UartHandle.ErrorCode & HAL_UART_ERROR_ORE)!=0) { __HAL_UART_CLEAR_FLAG(&UartHandle, HAL_UART_ERROR_ORE); return_event |= SERIAL_EVENT_RX_OVERRUN_ERROR & obj->serial.events; } @@ -1128,8 +1133,18 @@ int serial_irq_handler_asynch(serial_t *obj) if ((UartHandle.RxXferCount==0)&&(obj->rx_buff.pos >= (obj->rx_buff.length - 1))) { return_event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events; } - if ((buf != NULL) && (buf[obj->rx_buff.pos-1] == obj->char_match) && (SERIAL_OBJ(events) & SERIAL_EVENT_RX_CHARACTER_MATCH)) { - return_event |= SERIAL_EVENT_RX_CHARACTER_MATCH & obj->serial.events; + // Chek if Char_match is present + if (SERIAL_OBJ(events) & SERIAL_EVENT_RX_CHARACTER_MATCH) { + if (buf != NULL){ + while((buf[i] != obj->char_match)&&(ichar_match{ + //} + } + if (irx_buff.pos = i; + return_event |= SERIAL_EVENT_RX_CHARACTER_MATCH & obj->serial.events; + } + } } return return_event; } From ff127d2da474107cd54d36e71458d55fe7823aa8 Mon Sep 17 00:00:00 2001 From: adustm Date: Tue, 26 Jan 2016 13:12:42 +0100 Subject: [PATCH 4/5] [B96B_F446VE] use of static functions --- .../hal/TARGET_STM/TARGET_STM32F4/serial_api.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c index 2e35b0f841..4bef2523e9 100644 --- a/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c +++ b/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F4/serial_api.c @@ -649,7 +649,7 @@ void serial_break_clear(serial_t *obj) * @param tx The buffer for sending. * @param tx_length The number of words to transmit. */ -void h_serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width) +static void h_serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width) { // We only support byte buffers for now MBED_ASSERT(width == 8); @@ -671,7 +671,7 @@ void h_serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t widt * @param tx The buffer for sending. * @param tx_length The number of words to transmit. */ -void h_serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width) +static void h_serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width) { /* Sanity check arguments */ MBED_ASSERT(obj); @@ -695,7 +695,7 @@ void h_serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t widt * @param event The logical OR of the TX events to configure * @param enable Set to non-zero to enable events, or zero to disable them */ -void h_serial_tx_enable_event(serial_t *obj, int event, uint8_t enable) +static void h_serial_tx_enable_event(serial_t *obj, int event, uint8_t enable) { // Shouldn't have to enable TX interrupt here, just need to keep track of the requested events. if (enable) SERIAL_OBJ(events) |= event; @@ -708,7 +708,7 @@ void h_serial_tx_enable_event(serial_t *obj, int event, uint8_t enable) * @param event The logical OR of the RX events to configure * @param enable Set to non-zero to enable events, or zero to disable them */ -void h_serial_rx_enable_event(serial_t *obj, int event, uint8_t enable) +static void h_serial_rx_enable_event(serial_t *obj, int event, uint8_t enable) { // Shouldn't have to enable RX interrupt here, just need to keep track of the requested events. if (enable) SERIAL_OBJ(events) |= event; @@ -721,7 +721,7 @@ void h_serial_rx_enable_event(serial_t *obj, int event, uint8_t enable) * @param obj pointer to serial object * @return internal NVIC TX IRQ index of U(S)ART peripheral */ -IRQn_Type h_serial_get_irq_index(serial_t *obj) +static IRQn_Type h_serial_get_irq_index(serial_t *obj) { IRQn_Type irq_n = (IRQn_Type)0; @@ -782,7 +782,7 @@ IRQn_Type h_serial_get_irq_index(serial_t *obj) * @param obj The serial object * @return Returns event flags if a TX/RX transfer termination condition was met or 0 otherwise */ -void h_serial_txdma_irq_handler_asynch() +static void h_serial_txdma_irq_handler_asynch() { HAL_DMA_IRQHandler(UartHandle.hdmatx); } @@ -803,7 +803,7 @@ void h_serial_rxdma_irq_handler_asynch(serial_t *obj) * @param obj pointer to serial object * @return internal NVIC TX DMA IRQ index of U(S)ART peripheral */ -IRQn_Type h_serial_tx_get_irqdma_index(serial_t *obj) +static IRQn_Type h_serial_tx_get_irqdma_index(serial_t *obj) { IRQn_Type irq_n = (IRQn_Type)0; @@ -862,7 +862,7 @@ IRQn_Type h_serial_tx_get_irqdma_index(serial_t *obj) * @param obj pointer to serial object * @return internal NVIC RX DMA IRQ index of U(S)ART peripheral */ -IRQn_Type h_serial_rx_get_irqdma_index(serial_t *obj) +static IRQn_Type h_serial_rx_get_irqdma_index(serial_t *obj) { IRQn_Type irq_n = (IRQn_Type)0; From df025eeac0eda631d0223129c6c9acf15ad4c6b8 Mon Sep 17 00:00:00 2001 From: adustm Date: Tue, 26 Jan 2016 13:13:19 +0100 Subject: [PATCH 5/5] [B96B_F446VE] Add this platform to UT_SERIAL_ASYNCH unitary test --- .../utest/serial_asynch/serial_asynch.cpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/libraries/tests/utest/serial_asynch/serial_asynch.cpp b/libraries/tests/utest/serial_asynch/serial_asynch.cpp index 9d55c7d4b4..25143fb64a 100644 --- a/libraries/tests/utest/serial_asynch/serial_asynch.cpp +++ b/libraries/tests/utest/serial_asynch/serial_asynch.cpp @@ -39,6 +39,10 @@ #define TEST_SERIAL_ONE_TX_PIN PE10 // usart0 #define TEST_SERIAL_TWO_RX_PIN PC1 // usart1 +#elif defined(TARGET_B96B_F446VE) +#define TEST_SERIAL_ONE_TX_PIN D1 // UART2 +#define TEST_SERIAL_TWO_RX_PIN D4 // UART5 + #else #error Target not supported @@ -199,7 +203,13 @@ TEST(Serial_Asynchronous, rx_parity_error) while ((!tx_complete) || (!rx_complete)); CHECK_EQUAL(SERIAL_EVENT_TX_COMPLETE, tx_event_flag); +#if defined(TARGET_B96B_F446VE) + CHECK_EQUAL((SERIAL_EVENT_RX_COMPLETE|SERIAL_EVENT_RX_PARITY_ERROR), rx_event_flag); + serial_rx->format(8, SerialBase::None, 1); + serial_tx->format(8, SerialBase::None, 1); +#else CHECK_EQUAL(SERIAL_EVENT_RX_PARITY_ERROR, rx_event_flag); +#endif } TEST(Serial_Asynchronous, rx_framing_error) @@ -213,7 +223,12 @@ TEST(Serial_Asynchronous, rx_framing_error) while ((!tx_complete) || (!rx_complete)); CHECK_EQUAL(SERIAL_EVENT_TX_COMPLETE, tx_event_flag); +#if defined(TARGET_B96B_F446VE) + CHECK_EQUAL((SERIAL_EVENT_RX_COMPLETE|SERIAL_EVENT_RX_FRAMING_ERROR), rx_event_flag); + serial_tx->baud(9600); +#else CHECK_EQUAL(SERIAL_EVENT_RX_FRAMING_ERROR, rx_event_flag); +#endif } TEST(Serial_Asynchronous, char_matching_success) @@ -225,9 +240,16 @@ TEST(Serial_Asynchronous, char_matching_success) while ((!tx_complete) || (!rx_complete)); CHECK_EQUAL(SERIAL_EVENT_TX_COMPLETE, tx_event_flag); +#if defined(TARGET_B96B_F446VE) + // DMA is launched on LONG_XFR size. RX Complete event occurs. + CHECK_EQUAL((SERIAL_EVENT_RX_COMPLETE | SERIAL_EVENT_RX_CHARACTER_MATCH), rx_event_flag); + + cmpnbuf(tx_buf, rx_buf, 0, LONG_XFR, __FILE__, __LINE__); +#else CHECK_EQUAL(SERIAL_EVENT_RX_CHARACTER_MATCH, rx_event_flag); cmpnbufc(TEST_BYTE_RX, rx_buf, 5, sizeof(rx_buf), __FILE__, __LINE__); +#endif } TEST(Serial_Asynchronous, char_matching_failed)