cancel
Showing results for 
Search instead for 
Did you mean: 

MX Init functions overwrite static size_t variable

SStru.1
Associate II

I am working on an embedded application using the STM32F103C8T6 (black pill). I've been slowly adding the functionality I need and adding different peripherals one by one. For USART I was using the excellent code written by Tilen Majerle here. Everything was working great until I added something via CubeMX and my USART 'broke' - stopped sending. I stepped through the code and discovered the issue.

In Tilen Majerle's code

usart_send_string("READY\n");

Calls the following functions:

void
usart_send_string(const char* str) {
	usart_process_data(str, strlen(str));             /* Then try to start transfer */
}
 
void usart_process_data(const void* data, size_t len){
	lwrb_write(&usart_tx_ringbuff, data, len);
	usart_start_tx_dma_transfer();
}
 
uint8_t usart_start_tx_dma_transfer(void){
	uint32_t old_primask;
	uint8_t started = 0;
 
	old_primask = __get_PRIMASK();
	__disable_irq();
 
	if(usart_tx_dma_current_len ==0){
		usart_tx_dma_current_len = lwrb_get_linear_block_read_length(&usart_tx_ringbuff);
		if(usart_tx_dma_current_len>0){
			LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_2);
 
			/* Clear all flags */
			LL_DMA_ClearFlag_TC2(DMA1);
			LL_DMA_ClearFlag_HT2(DMA1);
			LL_DMA_ClearFlag_GI2(DMA1);
			LL_DMA_ClearFlag_TE2(DMA1);
 
			/* Start DMA transfer */
			LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, usart_tx_dma_current_len);
			LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)lwrb_get_linear_block_read_address(&usart_tx_ringbuff));
 
			/* Start new transfer */
			LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
			started = 1;
 
		}
	}
 
	__set_PRIMASK(old_primask);
	return started;
}
 

I noticed in stepping through that the condition statement wasn't getting executed.

if(usart_tx_dma_current_len ==0){
			/* Clear all flags */
			/* Start DMA transfer */
			/* Start new transfer */
		}

 Stepping through the code shows that usart_tx_dma_current_len, which I declared as:

static size_t usart_tx_dma_current_len;

Gets it's value updated after each of the following initialization calls:

 MX_GPIO_Init();
 MX_DMA_Init();
 MX_ADC1_Init();
 MX_TIM1_Init();
 MX_TIM4_Init();
 MX_TIM2_Init();
 MX_USART3_UART_Init();

For instance after MX_DMA, the value in the watch for usart_tx_dma_current_len is 1, after MX_ADC1 it is 536871292, after MX_TIM1 it is 0 and most bizarrely after MX_USART3_UART_Init it is 115200 (the baud rate I selected)...

I can solve the problem by setting usart_tx_dma_current_len = 0 after the initialisation calls but I wondered if anyone had any clue why this might be happening?

2 REPLIES 2
KnarfB
Principal III

Are you sure that the watched values are geniue? I would double-check by showing raw memory data at the variables address. If a global variable is indeed overwritten by function calls, it could be a stack overflow. Therefore I would compare the stack pointer register value against the variables address and check how much headroom is left on the stack.

On my device I had boot 1 pulled high and boot 0 pulled low. When I keep boot 0 and boot 1 pulled low I stop getting really weird behaviour like this so I am assuming that it was something weird happening with the stack.

I'm a complete newbie to STM32 devices. Would you be able to explain to me please how I can compare the stack pointer register value against the variables address. I'm using Atollic TrueStudio - in debug I've located the disassembly which seems to show the memory addresses for each command.