diff --git a/bsp/Inc/UART.h b/bsp/Inc/UART.h index a1f7c870..94add3e2 100644 --- a/bsp/Inc/UART.h +++ b/bsp/Inc/UART.h @@ -108,6 +108,8 @@ uart_status_t uart_deinit(UART_HandleTypeDef* handle); */ uart_status_t uart_send(UART_HandleTypeDef* handle, const uint8_t* data, uint16_t length, TickType_t delay_ticks); +uart_status_t uart_send_buf(UART_HandleTypeDef* handle, const uint8_t* data, uint16_t length, SemaphoreHandle_t release_sem, TickType_t delay_ticks); + /** * @brief Receives data from UART RX queue. * diff --git a/bsp/Src/UART.c b/bsp/Src/UART.c index 1b7b22c8..ba3b82a2 100644 --- a/bsp/Src/UART.c +++ b/bsp/Src/UART.c @@ -1,12 +1,14 @@ #include "UART.h" #include #include +#include "portmacro.h" +#include "stm32f4xx_hal_def.h" #include "stm32xx_hal.h" // Define the size of the data to be transmitted // may need to be configured for support for packets less more than 8 bits #ifndef UART_TX_DATA_SIZE -#define UART_TX_DATA_SIZE (64) +#define UART_TX_DATA_SIZE (16) #endif #ifndef UART_RX_DATA_SIZE @@ -14,7 +16,7 @@ #endif #ifndef UART_SINGLE_TX_SIZE -#define UART_SINGLE_TX_SIZE (64) +#define UART_SINGLE_TX_SIZE (16) #endif // Define the preemption priority for the interrupt @@ -23,9 +25,24 @@ #define UART_NVIC_PREEMPT_PRIO (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1) #endif +typedef enum { + STATIC_BUFFER, + RAW_BYTES +} UART_tx_data_type_t; + typedef struct { - uint8_t data[UART_TX_DATA_SIZE]; // data to be transmitted - uint8_t len; + UART_tx_data_type_t type; + union { + struct { + uint8_t bytes[UART_TX_DATA_SIZE]; // data to be transmitted + uint8_t len; + } raw_bytes; + struct { + const uint8_t *data; + uint16_t len; + SemaphoreHandle_t release_sem; + } static_buffer; + } data; } UART_tx_payload_t; typedef struct { @@ -41,9 +58,10 @@ typedef struct { StaticQueue_t tx_queue_buffer; // static queue info (required for initialization) uint8_t *tx_queue_storage; // storage for tx queue uint8_t *tx_dir_buffer; // buffer for in-progress direct transmission - SemaphoreHandle_t tx_mutex; // used to ensure ordering in case of multiple users of same TX queue - StaticSemaphore_t tx_mutex_buffer; // static mutex info (required for initialization) - volatile bool tx_active; + SemaphoreHandle_t tx_queue_mutex; // used to ensure ordering in case of multiple users of same TX queue + StaticSemaphore_t tx_queue_mutex_buffer; // static mutex info (required for initialization) + SemaphoreHandle_t buf_mtx; // for uart_send_buf + volatile bool tx_active; uint16_t rx_queue_size; // number of UART_rx_payload_t in rx_queue QueueHandle_t rx_queue; // queue handle @@ -53,7 +71,7 @@ typedef struct { } UART_periph_t; // helper to trigger background interrupts -static void uart_transmit(UART_HandleTypeDef *huart); +static void uart_transmit(UART_HandleTypeDef *huart, BaseType_t *higherPriorityTaskWoken); #define UART_STRUCTURE(uart_name, UART_INSTANCE, TX_Q_SIZE, RX_Q_SIZE) \ static uint8_t uart_name##_tx_queue_storage[(TX_Q_SIZE) * sizeof(UART_tx_payload_t)]; \ @@ -495,7 +513,10 @@ uart_status_t uart_init(UART_HandleTypeDef* handle) { uart_periph->rx_queue_storage, &uart_periph->rx_queue_buffer); - uart_periph->tx_mutex = xSemaphoreCreateMutexStatic(&uart_periph->tx_mutex_buffer); + uart_periph->tx_queue_mutex = xSemaphoreCreateMutexStatic(&uart_periph->tx_queue_mutex_buffer); + + // No mutex for static buf sends initially + uart_periph->buf_mtx = NULL; // init HAL if(HAL_UART_Init(handle) != HAL_OK){ @@ -542,13 +563,15 @@ uart_status_t uart_deinit(UART_HandleTypeDef* handle) { * @return uart_status_t */ uart_status_t uart_send(UART_HandleTypeDef* handle, const uint8_t* data, uint16_t length, TickType_t delay_ticks) { - if (length == 0 || !is_uart_initialized(handle)) { // check if UART is initialized and data length is not 0 + if (!data || length == 0 || !is_uart_initialized(handle)) { // check if UART is initialized and data length is not 0 return UART_ERR; } UART_periph_t *uart_periph = get_valid_uart_periph(handle); if(uart_periph == NULL) return UART_ERR; + HAL_StatusTypeDef (*hal_uart_tx)(UART_HandleTypeDef *, const uint8_t *, uint16_t) = (handle->hdmatx)?HAL_UART_Transmit_DMA:HAL_UART_Transmit_IT; + // Try direct transmission if possible portENTER_CRITICAL(); if (!uart_periph->tx_active && @@ -559,7 +582,7 @@ uart_status_t uart_send(UART_HandleTypeDef* handle, const uint8_t* data, uint16_ uart_periph->tx_active = true; portEXIT_CRITICAL(); - if (HAL_UART_Transmit_IT(handle, uart_periph->tx_dir_buffer, length) != HAL_OK) { + if (hal_uart_tx(handle, uart_periph->tx_dir_buffer, length) != HAL_OK) { uart_periph->tx_active = false; return UART_ERR; } @@ -569,39 +592,77 @@ uart_status_t uart_send(UART_HandleTypeDef* handle, const uint8_t* data, uint16_ portEXIT_CRITICAL(); // Send data in chunks based on UART_TX_DATA_SIZE - if(xSemaphoreTake(uart_periph->tx_mutex, delay_ticks) != pdTRUE) return UART_ERR; // if we timeout, err out + if(xSemaphoreTake(uart_periph->tx_queue_mutex, delay_ticks) != pdTRUE) return UART_ERR; // if we timeout, err out for (uint16_t i = 0; i < length; i+=UART_TX_DATA_SIZE) { UART_tx_payload_t payload; + payload.type = RAW_BYTES; // Ensure we only copy UART_TX_DATA_SIZE bytes at a time - payload.len = (length - i < UART_TX_DATA_SIZE) ? (length - i) : UART_TX_DATA_SIZE; + payload.data.raw_bytes.len = (length - i < UART_TX_DATA_SIZE) ? (length - i) : UART_TX_DATA_SIZE; // EX: i=4, length=6, DataSize=4, then chunk_size = 2, instead of usual 4 since we've reached end of length // Copy the appropriate number of bytes to the payload data - memcpy(payload.data, &data[i], payload.len); // Usually chunk_size = UART_TX_DATA_SIZE until end of data length + memcpy(payload.data.raw_bytes.bytes, &data[i], payload.data.raw_bytes.len); // Usually chunk_size = UART_TX_DATA_SIZE until end of data length // If the queue is completely full, and uart tx is NOT active, we deadlock waiting for the queue to open up. // Kickstart here if that's the case so we can keep adding our messages if(!uart_periph->tx_active && uxQueueSpacesAvailable(uart_periph->tx_queue) == 0 ) { + BaseType_t higherPriorityTaskWoken; + portENTER_CRITICAL(); if(!uart_periph->tx_active){ - uart_transmit(handle); + uart_transmit(handle, &higherPriorityTaskWoken); } portEXIT_CRITICAL(); } // Enqueue the payload to be transmitted if (xQueueSend(uart_periph->tx_queue, &payload, delay_ticks) != pdTRUE) { - xSemaphoreGive(uart_periph->tx_mutex); + xSemaphoreGive(uart_periph->tx_queue_mutex); return UART_ERR; } // delay_ticks: 0 = no wait, portMAX_DELAY = wait until space is available } - xSemaphoreGive(uart_periph->tx_mutex); + xSemaphoreGive(uart_periph->tx_queue_mutex); // If the background interrupts are not active we need to kickstart them portENTER_CRITICAL(); if(!uart_periph->tx_active) { - uart_transmit(handle); + BaseType_t higherPriorityTaskWoken = pdFALSE; + uart_transmit(handle, &higherPriorityTaskWoken); + } + portEXIT_CRITICAL(); + + return UART_OK; +} + +/** + * @brief Transmits a mutexed buffer over UART. The mutex must already be acquired before this call. + */ +uart_status_t uart_send_buf(UART_HandleTypeDef* handle, const uint8_t* data, uint16_t length, SemaphoreHandle_t release_sem, TickType_t delay_ticks) { + if (!data || length == 0 || !is_uart_initialized(handle)) { + return UART_ERR; + } + + UART_periph_t *uart_periph = get_valid_uart_periph(handle); + if(uart_periph == NULL) return UART_ERR; + + UART_tx_payload_t payload = { + .type = STATIC_BUFFER, + .data.static_buffer = { + .data = data, + .len = length, + .release_sem = release_sem, + } + }; + + if (xQueueSend(uart_periph->tx_queue, &payload, delay_ticks) != pdTRUE) { + return UART_ERR; + } + + portENTER_CRITICAL(); + if (!uart_periph->tx_active) { + BaseType_t higherPriorityTaskWoken = pdFALSE; + uart_transmit(handle, &higherPriorityTaskWoken); } portEXIT_CRITICAL(); @@ -648,43 +709,73 @@ uart_status_t uart_recv(UART_HandleTypeDef* handle, uint8_t* data, uint16_t leng } // MUST BE CALLED FROM ISR OR CRIT SECTION -static void uart_transmit(UART_HandleTypeDef *huart){ - BaseType_t higherPriorityTaskWoken = pdFALSE; +static void uart_transmit(UART_HandleTypeDef *huart, BaseType_t *higherPriorityTaskWoken){ uint16_t count = 0; UART_periph_t *uart_periph = get_valid_uart_periph(huart); if(uart_periph == NULL) return; + HAL_StatusTypeDef (*hal_uart_tx)(UART_HandleTypeDef *, const uint8_t *, uint16_t) = (huart->hdmatx)?HAL_UART_Transmit_DMA:HAL_UART_Transmit_IT; + // Pull as many bytes as we can fit in the buffer UART_tx_payload_t payload; - while(xQueuePeekFromISR(uart_periph->tx_queue, &payload) == pdTRUE) { // there's still something in queue? - if(count + payload.len > UART_SINGLE_TX_SIZE) break; - else { - xQueueReceiveFromISR(uart_periph->tx_queue, &payload, &higherPriorityTaskWoken); // pop from queue - } - - // Safely copy the data from the payload into the tx_buffer - memcpy(&(uart_periph->tx_dir_buffer[count]), payload.data, payload.len); - count += payload.len; - } - - // If we got any bytes, transmit them - if(count > 0) { - uart_periph->tx_active = true; - if(HAL_UART_Transmit_IT(huart, uart_periph->tx_dir_buffer, count) != HAL_OK){ - uart_periph->tx_active = false; - } - } else { + if (xQueuePeekFromISR(uart_periph->tx_queue, &payload) != pdTRUE) { uart_periph->tx_active = false; + return; } + + switch(payload.type){ + case STATIC_BUFFER: + xQueueReceiveFromISR(uart_periph->tx_queue, &payload, higherPriorityTaskWoken); + uart_periph->buf_mtx = payload.data.static_buffer.release_sem; + if(payload.data.static_buffer.len > 0){ + uart_periph->tx_active = true; + } + + if(hal_uart_tx(&uart_periph->huart, payload.data.static_buffer.data, payload.data.static_buffer.len) != HAL_OK){ + uart_periph->tx_active = false; + uart_periph->buf_mtx = NULL; + xSemaphoreGiveFromISR(payload.data.static_buffer.release_sem, higherPriorityTaskWoken); + } - // Only yield if we're in ISR - if(__get_IPSR() != 0) portYIELD_FROM_ISR(higherPriorityTaskWoken); + break; + + case RAW_BYTES: + while(xQueuePeekFromISR(uart_periph->tx_queue, &payload) == pdTRUE) { // there's still something in queue? + if(payload.type != RAW_BYTES) break; + if(count + payload.data.raw_bytes.len > UART_SINGLE_TX_SIZE) break; + xQueueReceiveFromISR(uart_periph->tx_queue, &payload, higherPriorityTaskWoken); // pop from queue + + // Safely copy the data from the payload into the tx_buffer + memcpy(&(uart_periph->tx_dir_buffer[count]), payload.data.raw_bytes.bytes, payload.data.raw_bytes.len); + count += payload.data.raw_bytes.len; + } + + // If we got any bytes, transmit them + if(count > 0) { + uart_periph->tx_active = true; + if(hal_uart_tx(huart, uart_periph->tx_dir_buffer, count) != HAL_OK){ + uart_periph->tx_active = false; + } + } else { + uart_periph->tx_active = false; + } + break; + } } // Transmit Callback occurs after a transmission if complete (depending on how huart is configure) void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { - uart_transmit(huart); + BaseType_t higherPriorityTaskWoken = pdFALSE; + UART_periph_t *uart_periph = get_valid_uart_periph(huart); + if(uart_periph == NULL) return; + + SemaphoreHandle_t sem = uart_periph->buf_mtx; + uart_periph->buf_mtx = NULL; + uart_transmit(huart, &higherPriorityTaskWoken); + if(sem) xSemaphoreGiveFromISR(sem, &higherPriorityTaskWoken); + + portYIELD_FROM_ISR(higherPriorityTaskWoken); } // Receive Callback occurs after a receive is complete @@ -699,10 +790,10 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { BaseType_t higherPriorityTaskWoken = pdFALSE; - xQueueSendFromISR(uart_periph->rx_queue, &receivedData, &higherPriorityTaskWoken); // Send data from &receivedData(pRxBuffPtr) to rx_queue + xQueueSendFromISR(uart_periph->rx_queue, &receivedData, &higherPriorityTaskWoken); // Trigger the next interrupt - HAL_UART_Receive_IT(huart, uart_periph->rx_buffer.data, UART_RX_DATA_SIZE);// pRxBufferPtr is a pointer to the buffer that will store the received data + HAL_UART_Receive_IT(huart, uart_periph->rx_buffer.data, UART_RX_DATA_SIZE); portYIELD_FROM_ISR(higherPriorityTaskWoken); } diff --git a/driver/Inc/printf.h b/driver/Inc/printf.h index b0520a48..445000ce 100644 --- a/driver/Inc/printf.h +++ b/driver/Inc/printf.h @@ -14,4 +14,4 @@ int printf(const char *fmt, ...); int snprintf(char *buffer, size_t bufsz, char const *fmt, ...); -bool printf_init(UART_HandleTypeDef *huart); +bool printf_init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_uart_tx); diff --git a/driver/Src/printf.c b/driver/Src/printf.c index 3f2ed12a..02a017df 100644 --- a/driver/Src/printf.c +++ b/driver/Src/printf.c @@ -1,5 +1,6 @@ #include "printf.h" #include "UART.h" +#include "stm32f4xx_hal_dma.h" #include "stm32xx_hal.h" #include @@ -11,7 +12,7 @@ #endif #ifndef NUM_PRINTF_BUFFERS -#define NUM_PRINTF_BUFFERS (5) +#define NUM_PRINTF_BUFFERS (15) #endif // How long to wait for a printf buffer to open up @@ -38,14 +39,21 @@ UART_HandleTypeDef *printf_huart = NULL; * @param huart pointer to the UART handle * @return bool true if success */ -bool printf_init(UART_HandleTypeDef *huart) { +bool printf_init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_uart_tx) { printf_huart = huart; printf_pool_mtx = xSemaphoreCreateMutexStatic(&printf_pool_mtx_buf); for(int i=0; ibuffer, (rv > MAX_PRINTF_SIZE)?MAX_PRINTF_SIZE:rv, portMAX_DELAY); - xSemaphoreGive(pbuf->buffer_mtx); + // Should release the buffer mtx once transmission is complete, preventing any changes + uart_status_t status = uart_send_buf(printf_huart, (const uint8_t *)pbuf->buffer, (rv > MAX_PRINTF_SIZE)?MAX_PRINTF_SIZE:rv, pbuf->buffer_mtx, portMAX_DELAY); return (status == UART_OK)?rv:-1; } diff --git a/test/tests/printf_dma_mt_test.c b/test/tests/printf_dma_mt_test.c new file mode 100644 index 00000000..68578883 --- /dev/null +++ b/test/tests/printf_dma_mt_test.c @@ -0,0 +1,302 @@ +#include +#include +#include "stm32xx_hal.h" +#include "printf.h" + +StaticTask_t initTaskBuffer; +StackType_t initTaskStack[configMINIMAL_STACK_SIZE]; + +DMA_HandleTypeDef hdma_usart2_tx; + +void HAL_UART_MspGPIOInit(UART_HandleTypeDef *huart){ + GPIO_InitTypeDef init = {0}; + UNUSED(init); + +#ifdef STM32F4xx + __HAL_RCC_GPIOA_CLK_ENABLE(); + + /* enable port A USART2 gpio + PA2 -> USART2_TX + PA3 -> USART2_RX + */ + init.Pin = GPIO_PIN_2|GPIO_PIN_3; + init.Mode = GPIO_MODE_AF_PP; + init.Pull = GPIO_NOPULL; + init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + init.Alternate = GPIO_AF7_USART2; + HAL_GPIO_Init(GPIOA, &init); +#endif + +#ifdef STM32G4xx + __HAL_RCC_GPIOC_CLK_ENABLE(); + + /* enable port C USART3 gpio + PC10 -> USART3_TX + PC11 -> USART3_RX + */ + init.Pin = GPIO_PIN_10|GPIO_PIN_11; + init.Mode = GPIO_MODE_AF_PP; + init.Pull = GPIO_NOPULL; + init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + init.Alternate = GPIO_AF7_USART3; + HAL_GPIO_Init(GPIOC, &init); +#endif + +#ifdef STM32L4xx + /* Peripheral clock enable */ + __HAL_RCC_USART1_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**USART1 GPIO Configuration + PA9 ------> USART1_TX + PA10 ------> USART1_RX + */ + init.Pin = GPIO_PIN_9 | GPIO_PIN_10; + init.Mode = GPIO_MODE_AF_PP; + init.Pull = GPIO_NOPULL; + init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + init.Alternate = GPIO_AF7_USART1; + HAL_GPIO_Init(GPIOA, &init); +#endif + +} + +#ifdef STM32F4xx +void DMA1_Stream6_IRQHandler(void){ + HAL_DMA_IRQHandler(&hdma_usart2_tx); +} + +#endif +#define THREAD_COUNT 15 +#define DUMP_SIZE 100 + +// static char *messages[] = { +// "This is a message I expect to never interleave!\n\r", +// "The quick brown fox jumped over the lazy dog!\n\r", +// "5.5\n\r", +// "3.777\n\r", +// "I'm going to write a really long message to test long transmission lengths to confirm that interleaving is not a problem with these sorts of messages.\n\r" +// }; + +// If you wanna test with messages that all take the same base amount of time +static char *messages[] = { + "This is a message I expect to never interleave!\n\r", + "This is a message I expect to never interleave!\n\r", + "This is a message I expect to never interleave!\n\r", + "This is a message I expect to never interleave!\n\r", + "This is a message I expect to never interleave!\n\r", +}; + +StaticTask_t txTaskBuffer[THREAD_COUNT]; +StackType_t txTaskStack[THREAD_COUNT][configMINIMAL_STACK_SIZE]; + +static uint32_t time_dump[THREAD_COUNT][DUMP_SIZE] = {0}; +static bool tx_done[THREAD_COUNT] = {}; + +void TxTask(void *argument){ + uint8_t time_ind = 0; + + for(int i=0; iCYCCNT; + printf(messages[((int)argument % (sizeof(messages)/sizeof(char*)))]); + //uart_send(husart2, (const uint8_t *)messages[((int)argument % (sizeof(messages)/sizeof(char*)))], strlen(messages[((int)argument % (sizeof(messages)/sizeof(char*)))]), portMAX_DELAY); + volatile uint32_t time_after = DWT->CYCCNT; + uint32_t time_elapsed = (time_after - time_before); + time_dump[(int)argument][time_ind++] = time_elapsed; + + time_ind = time_ind % DUMP_SIZE; + + portYIELD(); + } + + tx_done[(int)argument] = true; + while(1){vTaskDelay(1000);} +} + +void DWT_Init(void) +{ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0UL; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; +} + +void InitTask(void *argument){ +#ifdef STM32F4xx + /* DMA controller clock enable */ + __HAL_RCC_DMA1_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA1_Stream6_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn); + + husart2->Init.BaudRate = 115200; + husart2->Init.WordLength = UART_WORDLENGTH_8B; + husart2->Init.StopBits = UART_STOPBITS_1; + husart2->Init.Parity = UART_PARITY_NONE; + husart2->Init.Mode = UART_MODE_TX_RX; + husart2->Init.HwFlowCtl = UART_HWCONTROL_NONE; + husart2->Init.OverSampling = UART_OVERSAMPLING_16; + + hdma_usart2_tx.Instance = DMA1_Stream6; + hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4; + hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart2_tx.Init.Mode = DMA_NORMAL; + hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + printf_init(husart2, &hdma_usart2_tx); +#endif + +#ifdef STM32G4xx + husart3->Init.BaudRate = 115200; + husart3->Init.WordLength = UART_WORDLENGTH_8B; + husart3->Init.StopBits = UART_STOPBITS_1; + husart3->Init.Parity = UART_PARITY_NONE; + husart3->Init.Mode = UART_MODE_TX_RX; + husart3->Init.HwFlowCtl = UART_HWCONTROL_NONE; + husart3->Init.OverSampling = UART_OVERSAMPLING_16; + printf_init(husart3); +#endif + +#ifdef STM32L4xx + husart1->Init.BaudRate = 115200; + husart1->Init.WordLength = UART_WORDLENGTH_8B; + husart1->Init.StopBits = UART_STOPBITS_1; + husart1->Init.Parity = UART_PARITY_NONE; + husart1->Init.Mode = UART_MODE_TX_RX; + husart1->Init.HwFlowCtl = UART_HWCONTROL_NONE; + husart1->Init.OverSampling = UART_OVERSAMPLING_16; + + printf_init(husart1); +#endif + + DWT_Init(); + + for(int i=0; i t_max) t_max = t; + t_sum += t; + t_sum_sq += t * t; + + if(t > global_max) global_max = t; + } + + float mean = t_sum / DUMP_SIZE; + float stddev = sqrtf((t_sum_sq / DUMP_SIZE) - (mean * mean)); + + printf(" Msg: \"%s\"\n\r", msg); + printf(" Min: %f ms\n\r", t_min); + printf(" Max: %f ms\n\r", t_max); + printf(" Mean: %f ms\n\r", mean); + printf(" Jitter: %f ms (peak-to-peak)\n\r", t_max - t_min); + printf(" Stddev: %f ms\n\r", stddev); + } + + printf("Global max: %f ms\n\r", global_max); + break; + } + } + + while(1){} +} + +int main(void) { + HAL_Init(); + SystemClock_Config(); + + xTaskCreateStatic(InitTask, + "Init", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 1, + initTaskStack, + &initTaskBuffer); + + vTaskStartScheduler(); + + while (1) { + } +} + +// autogenerated +#ifdef STM32G4xx +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure the main internal regulator output voltage + */ + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2; + RCC_OscInitStruct.PLL.PLLN = 20; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; + RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) + { + Error_Handler(); + } +} +#endif diff --git a/test/tests/printf_dma_test.c b/test/tests/printf_dma_test.c new file mode 100644 index 00000000..e484582f --- /dev/null +++ b/test/tests/printf_dma_test.c @@ -0,0 +1,196 @@ +#include "stm32xx_hal.h" +#include "printf.h" + +StaticTask_t txTaskBuffer; +StackType_t txTaskStack[configMINIMAL_STACK_SIZE]; + +DMA_HandleTypeDef hdma_usart2_tx; + +void HAL_UART_MspGPIOInit(UART_HandleTypeDef *huart){ + GPIO_InitTypeDef init = {0}; + UNUSED(init); + +#ifdef STM32F4xx + __HAL_RCC_GPIOA_CLK_ENABLE(); + + /* enable port A USART2 gpio + PA2 -> USART2_TX + PA3 -> USART2_RX + */ + init.Pin = GPIO_PIN_2|GPIO_PIN_3; + init.Mode = GPIO_MODE_AF_PP; + init.Pull = GPIO_NOPULL; + init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + init.Alternate = GPIO_AF7_USART2; + HAL_GPIO_Init(GPIOA, &init); +#endif + +#ifdef STM32G4xx + __HAL_RCC_GPIOC_CLK_ENABLE(); + + /* enable port C USART3 gpio + PC10 -> USART3_TX + PC11 -> USART3_RX + */ + init.Pin = GPIO_PIN_10|GPIO_PIN_11; + init.Mode = GPIO_MODE_AF_PP; + init.Pull = GPIO_NOPULL; + init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + init.Alternate = GPIO_AF7_USART3; + HAL_GPIO_Init(GPIOC, &init); +#endif + +#ifdef STM32L4xx + /* Peripheral clock enable */ + __HAL_RCC_USART1_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + /**USART1 GPIO Configuration + PA9 ------> USART1_TX + PA10 ------> USART1_RX + */ + init.Pin = GPIO_PIN_9 | GPIO_PIN_10; + init.Mode = GPIO_MODE_AF_PP; + init.Pull = GPIO_NOPULL; + init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + init.Alternate = GPIO_AF7_USART1; + HAL_GPIO_Init(GPIOA, &init); +#endif +} + +#ifdef STM32F4xx +void DMA1_Stream6_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Stream6_IRQn 0 */ + + /* USER CODE END DMA1_Stream6_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_usart2_tx); + /* USER CODE BEGIN DMA1_Stream6_IRQn 1 */ + + /* USER CODE END DMA1_Stream6_IRQn 1 */ +} +#endif + +void TxTask(void *argument){ +#ifdef STM32F4xx + /* DMA controller clock enable */ + __HAL_RCC_DMA1_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA1_Stream6_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn); + + husart2->Init.BaudRate = 115200; + husart2->Init.WordLength = UART_WORDLENGTH_8B; + husart2->Init.StopBits = UART_STOPBITS_1; + husart2->Init.Parity = UART_PARITY_NONE; + husart2->Init.Mode = UART_MODE_TX_RX; + husart2->Init.HwFlowCtl = UART_HWCONTROL_NONE; + husart2->Init.OverSampling = UART_OVERSAMPLING_16; + + hdma_usart2_tx.Instance = DMA1_Stream6; + hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4; + hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart2_tx.Init.Mode = DMA_NORMAL; + hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; + hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + printf_init(husart2, &hdma_usart2_tx); +#endif + +#ifdef STM32G4xx + husart3->Init.BaudRate = 115200; + husart3->Init.WordLength = UART_WORDLENGTH_8B; + husart3->Init.StopBits = UART_STOPBITS_1; + husart3->Init.Parity = UART_PARITY_NONE; + husart3->Init.Mode = UART_MODE_TX_RX; + husart3->Init.HwFlowCtl = UART_HWCONTROL_NONE; + husart3->Init.OverSampling = UART_OVERSAMPLING_16; + printf_init(husart3); +#endif + +#ifdef STM32L4xx + husart1->Init.BaudRate = 115200; + husart1->Init.WordLength = UART_WORDLENGTH_8B; + husart1->Init.StopBits = UART_STOPBITS_1; + husart1->Init.Parity = UART_PARITY_NONE; + husart1->Init.Mode = UART_MODE_TX_RX; + husart1->Init.HwFlowCtl = UART_HWCONTROL_NONE; + husart1->Init.OverSampling = UART_OVERSAMPLING_16; + + printf_init(husart1); +#endif + + while(1){ + printf("Hello World! %s %d %f\n\r", "Test String", 5, 4.4); + vTaskDelay(pdMS_TO_TICKS(100)); + } +} + +int main(void) { + HAL_Init(); + SystemClock_Config(); + + xTaskCreateStatic(TxTask, + "TX", + configMINIMAL_STACK_SIZE, + NULL, + tskIDLE_PRIORITY + 2, + txTaskStack, + &txTaskBuffer); + + vTaskStartScheduler(); + + while (1) { + } +} + +// autogenerated +#ifdef STM32G4xx +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure the main internal regulator output voltage + */ + HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1); + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2; + RCC_OscInitStruct.PLL.PLLN = 20; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; + RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) + { + Error_Handler(); + } +} +#endif diff --git a/test/tests/printf_mt_test.c b/test/tests/printf_mt_test.c index 14aac66e..5fe89fbd 100644 --- a/test/tests/printf_mt_test.c +++ b/test/tests/printf_mt_test.c @@ -1,4 +1,3 @@ -// A simple echo application to test input and output over serial #include #include #include "stm32xx_hal.h" @@ -60,7 +59,7 @@ void HAL_UART_MspGPIOInit(UART_HandleTypeDef *huart){ } -#define THREAD_COUNT 4 +#define THREAD_COUNT 15 #define DUMP_SIZE 100 // static char *messages[] = { diff --git a/test/tests/printf_test.c b/test/tests/printf_test.c index 1121e2fb..7aa79f5d 100644 --- a/test/tests/printf_test.c +++ b/test/tests/printf_test.c @@ -1,4 +1,3 @@ -// A simple echo application to test input and output over serial #include "stm32xx_hal.h" #include "printf.h" @@ -58,7 +57,6 @@ void HAL_UART_MspGPIOInit(UART_HandleTypeDef *huart){ } void TxTask(void *argument){ - #ifdef STM32F4xx husart2->Init.BaudRate = 115200; husart2->Init.WordLength = UART_WORDLENGTH_8B; @@ -67,7 +65,7 @@ void TxTask(void *argument){ husart2->Init.Mode = UART_MODE_TX_RX; husart2->Init.HwFlowCtl = UART_HWCONTROL_NONE; husart2->Init.OverSampling = UART_OVERSAMPLING_16; - printf_init(husart2); + printf_init(husart2, false); #endif #ifdef STM32G4xx