cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Printf UART does not wait for transmission to complete

ÇSerp.1
Associate II

Hi, I am trying to implement printf with UART using DMA. The problem is when i use consecutive printf's in my code, transmission of the first data is not being waited. I implemented a control block to check if the transmission is completed but it does not work. At first, i wrote this control block by changing dmi.sending flag. It did not work, so i decided to get the state directly from huart. It did not work either. When i debug the code and add breakpoint to 

HAL_UART_Transmit_DMA(dmi.huart, (uint8_t*) ptr, len);

then the execution is successfull. I can see "123456\ntest\n" in the terminal. But when i stop debugging and run the code, i get this in the terminal:

1est
6
test

test

test

 

Why i can't control if the data is transmitted yet or not?

 

Here is my code

uart_write.c:

 

 

 

#include <ring_buffer.h>
#include "main.h"
#include <stdbool.h>
#include <uart_write.h>

struct dma_printf_info dmi;

void dma_printf_init(UART_HandleTypeDef *printf_huart) {
	dmi.huart = printf_huart;
	ring_init(&dmi.tx_ring);
	dmi.sending = false;
}

void dma_printf_putc(char *ptr, int len) {
	if (dmi.sending == false && ring_filled_space(&dmi.tx_ring) == 0) {
		dmi.sending = true;
		HAL_UART_Transmit_DMA(dmi.huart, (uint8_t*) ptr, len);
	} else {
		if (ring_empty_space(&dmi.tx_ring) >= len) {
			for (int i = 0; i < len; i++)
				ring_push(&dmi.tx_ring, ptr[i]);
		} else { //BUF OVFL
			while (1)
				;
		}
	}
}

void dma_printf_send_it(UART_HandleTypeDef *printf_huart) {
	if (dmi.huart != printf_huart) return;
	if (ring_filled_space(&dmi.tx_ring) > 0) {
		HAL_UART_Transmit_DMA(dmi.huart, (uint8_t*) dmi.tx_ring.buf, ring_filled_space(&dmi.tx_ring));
		ring_empty_out(&dmi.tx_ring);
	} else dmi.sending = false;
}

 

 

 

 

uart_write.h

 

 

 

#ifndef HAL_DMA_PRINTF_DMA_PRINTF_H
#define HAL_DMA_PRINTF_DMA_PRINTF_H
#include <ring_buffer.h>
#include "main.h"

struct dma_printf_info {
    struct dma_ring_buf tx_ring;
    volatile int sending;
    UART_HandleTypeDef *huart;
};

void dma_printf_init(UART_HandleTypeDef *printf_huart);
void dma_printf_putc(char* ptr, int len);
void dma_printf_send_it(UART_HandleTypeDef *printf_huart);
#endif //HAL_DMA_PRINTF_DMA_PRINTF_H

 

 

 

 

main.c

 

 

 

/* USER CODE BEGIN 0 */
int _write(int file, char *ptr, int len) {
	dma_printf_putc(ptr, len);
	return len;
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
	dma_printf_send_it(huart);
}
/* USER CODE END 0 */

int main(void) {
	/* USER CODE BEGIN 1 */

	/* USER CODE END 1 */

	/* MCU Configuration--------------------------------------------------------*/

	/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
	HAL_Init();

	/* USER CODE BEGIN Init */

	/* USER CODE END Init */

	/* Configure the system clock */
	SystemClock_Config();

	/* USER CODE BEGIN SysInit */

	/* USER CODE END SysInit */

	/* Initialize all configured peripherals */
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_UART4_Init();
	/* USER CODE BEGIN 2 */
	dma_printf_init(&huart4);
	dma_scanf_init(&huart4);
	printf("123456\n");
	/* USER CODE END 2 */

	/* Infinite loop */
	/* USER CODE BEGIN WHILE */
	while (1) {
		/* USER CODE END WHILE */

		/* USER CODE BEGIN 3 */
		printf("test\n");
		HAL_Delay(1000);
	}
	/* USER CODE END 3 */
}

 

 

 

 

3 REPLIES 3

Well you can't guarantee the scope of the buffer during the transfer.

You probably want to always put data in the ring buffer. And then serve the data from the ring, managing the chaining in the call back, and handling the wrapping cases.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
ÇSerp.1
Associate II

UPDATE

 

I am toggling two LEDs hooked up to my oscilloscope to see if the data is sent to dma immideately or buffered before sending.

 

uart_write.c

#include <ring_buffer.h>
#include "main.h"
#include <stdbool.h>
#include <uart_write.h>

struct dma_printf_info dmi;

void dma_printf_init(UART_HandleTypeDef *printf_huart) {
	dmi.huart = printf_huart;
	ring_init(&dmi.tx_ring);
	dmi.sending = false;
}

void dma_printf_putc(char *ptr, int len) {
	if (dmi.sending == false && ring_filled_space(&dmi.tx_ring) == 0) {
		dmi.sending = true;
		HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
		HAL_UART_Transmit_DMA(dmi.huart, (uint8_t*) ptr, len);
	} else if (dmi.sending == true) {
		if (ring_empty_space(&dmi.tx_ring) >= len) {
			HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
			for (int i = 0; i < len; i++)
				ring_push(&dmi.tx_ring, ptr[i]);
		} else { //BUF OVFL
			while (1)
				;
		}
	}
}

void dma_printf_send_it(UART_HandleTypeDef *printf_huart) {
	if (dmi.huart != printf_huart) return;

	if (ring_filled_space(&dmi.tx_ring) > 0) {
		HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
		HAL_UART_Transmit_DMA(dmi.huart, (uint8_t*) dmi.tx_ring.buf, ring_filled_space(&dmi.tx_ring));
		ring_empty_out(&dmi.tx_ring);
	} else {
		dmi.sending = false;
		HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
	}
}

 

 

main.c

  /* USER CODE BEGIN WHILE */
	while (1) {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		printf("123456\n");
		printf("test\n");
		HAL_Delay(1000);
	}
  /* USER CODE END 3 */

 

123456 should be sent immediately since the buffer is empty at the beginning. If execution of printf("test\n") is before the transmission of "123456\n", then test should be buffered and i should be able to see this on pin LED2. If the execution of printf("test\n") is after the transmission of "123456\n", it should be printed out immediately as well. So there are two options:

1- I need to see 2 pulses in LED1 indicating data is sent immediately two times.

2- I need to see LED1 rising and shortly after LED2 rising and LED1/2 falling at the same time when all the data is sent.

 

When i check the waveform on the oscilloscope, I get only one pulse at LED1. which is absurd.

 

Could you please elaborate a bit more? What does "can't guarantee the scope of the buffer during the transfer" mean and why it's not guaranteed in this example? If i put the printf data always to ring buffer, how can i understand when to print?