2020-10-04 05:09 AM
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?
2020-10-04 05:26 AM
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.
2020-10-05 12:13 PM
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.