I am working on a function for an STM32 Micro-controller that sends a string of a given length through a uart port. To handle uart communication, I have created a Serial class that has a transmission and receive buffer that are popped and transmitted in an interrupt handler. The function I am currently working on is actually an overload of a function that I wrote earlier that works. Below is the working function:
void Serial::sendString(char* str) {
// Writes a string to txBuffer. If Transmit interrupts are enabled, and
// the Data register is empty, the txBuffer will be popped into the DR to
// prime the interrupts.
__HAL_UART_DISABLE_IT(uart, UART_IT_TXE); // Keeps our spaghetti straightened out...
while (*str != '\0') { // While char is not a null terminator...
txBuffer->push(*str); // Push first char into queue as we know it is valid
str++; // Pointer goes to next char in string
}
uint32_t isrflags = READ_REG(uart->Instance->SR); // Reads the flags and control register
//uint32_t cr1its = READ_REG(uart->Instance->CR1); // Into variables
// If the DR is empty and Transmission interrupts are disabled...
if ((isrflags & USART_SR_TXE) != RESET) {
uart->Instance->DR = txBuffer->pop(); // Reenable interrupts and prime the DR
}
__HAL_UART_ENABLE_IT(uart, UART_IT_TXE); // Alright, time to cook the pasta
}
The overload is the function I am having issues on. For some reason, the debugger shows that the variable "i" initializes with value "14", and won't increment when stepping with the debugger. In fact, the debugger won't allow me to step into the for loop at all. Here is the overload:
void Serial::sendString(char* str, unsigned int len) {
// Writes a string to txBuffer. If Transmit interrupts are enabled, and
// the Data register is empty, the txBuffer will be popped into the DR to
// prime the interrupts.
// Rather than being terminated by a null character, this method instead
// sends each char in an array of a specified length. Note that this overload
// MUST be used in any situation that a null terminator might appear in a char
// array!
__HAL_UART_DISABLE_IT(uart, UART_IT_TXE); // Keeps our spaghetti straightened out...
for (unsigned int i = 0; i < len; i++) { // While char is not a null terminator...
txBuffer->push(str[i]); // Push first char into queue as we know it is valid
//str++; // Pointer goes to next char in string
}
uint32_t isrflags = READ_REG(uart->Instance->SR); // Reads the flags and control register
// uint32_t cr1its = READ_REG(uart->Instance->CR1); // Into variables
// If the DR is empty...
if ((isrflags & USART_SR_TXE) != RESET) {
uart->Instance->DR = txBuffer->pop();
}
__HAL_UART_ENABLE_IT(uart, UART_IT_TXE); // Alright, time to cook the pasta
}
These functions are called within a terminal while loop in main. When debugging, the issues happens immediately; I am not able to run through the overload at all. My code appears to just hit a dead-stop at this location.
I have been able to run the overload successfully before. This bug only appeared when I was trying to address another bug in the function where the first character in the string was only getting transmitted half of the time. I set a breakpoint and set out to debug and now it won't work at all....
It sounds like the compiler has optimized away your loop control variables.
If you have a high level of optimization enabled then the loop could be unrolled or if you are calling the function from the same file where it is defined then it could be inlined allowing to eliminate the loop control variables.
You haven't actually described what the problem is that you are trying to debug. Rather than expecting the debug experience to be perfect just try to solve the problem that you have in spite of i always being 14!
Looking just at the code you have posted I can't see any great problem. There could of course be a bug in the code you don't show.
I disagree strongly with the unhelpful comment that this code is fundamentally rubbish. Turning interrupts on and off to access shared data is old fashioned and inefficient, but also simple to do and may be good enough for your purposes.
Writing the first byte to the UART in this function does save you the cost of one interrupt, but if you are writing a string of 20 bytes, do you really care whether 20 or 19 interrupts are required to do it? A good design principle is that you should only make the code more complicated if it gains you something that you don't want to be without.