1

I am experiencing extremely bizarre behavior where variables are randomly changing.

I have distilled it to the simplest example, encoder_1_position and encoder_2_position get updated with randomly values inside the NVIC_SetPriority(UART_IRQn,2); function. I have reordered declarations of the global variables in the file and I noticed it makes a difference as to what/if garbage gets added to them. I since disabled "remove unused sections" in the linker command and it seemed to fix the problem(apparently the BSS section was being tossed out) but I don't understand why particularly since every global variable I have is declared with volatile.

Reducing the buffer size from 1000 to 100 seems to correct the random change to the encoder variables, but I'm not confident it's an actual fix nor should it be required. The SAM3X8E has 65kbytes of ram - the stack shouldn't overflow regardless.

#include "sam.h"

#define HEAP_SIZE 0x500
#define STACK_SIZE 0x3500

int encoder_1_position = 0;
int encoder_2_position = 0;

void IntializeWatchdogTimer(void)
{
    // disable watchdog timer
    WDT->WDT_MR =  WDT_MR_WDDIS;
}

void InitializeUart(void)
{
    PMC->PMC_PCER0 = PMC_PCER0_PID8;// ID_UART 8
    // baud rate is 84Mhz/(16*45) = 116667
    UART->UART_BRGR = uint32_t(45);
    // set to no parity
    UART->UART_MR = UART_MR_PAR_NO;
    // Enable transmit and receive
    UART->UART_CR = UART_CR_TXEN|UART_CR_RXEN;
    // Enable UART control of port A pin 8, 9
    PIOA->PIO_PDR = PIO_PER_P8|PIO_PER_P9;
    // Enable UART interrupt on RX RDY
    UART->UART_IER = UART_IER_RXRDY;
    
    // Set priority
    NVIC_SetPriority(UART_IRQn,2);
    NVIC_EnableIRQ(UART_IRQn);
}




int main(void)
{
    __disable_irq();
    IntializeWatchdogTimer();
    SystemInit();
    InitializeUart();
    __enable_irq();
    /* Initialize the SAM system */
    
    //char* RX_message;
    char TX_message[1000];
    
    while (true)
    {
        int a = encoder_1_position;
        int b = encoder_2_position;
    }

}

readelf output:

Elf file type is EXEC (Executable file)
Entry point 0x80000
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x00080000 0x00080000 0x02a58 0x02a58 R E 0x10000
  LOAD           0x020000 0x20000000 0x00082a58 0x001d4 0x00808 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text
   01     .relocate .bss .stack .heap
artless noise
  • 21,212
  • 6
  • 68
  • 105
FourierFlux
  • 439
  • 5
  • 13
  • Please provide the test code or method used to reach the conclusion that the variables are changing unexpectedly. – kaylum Jan 10 '22 at 00:51
  • I'm debugging using a jlink in Atmel Studio 7 and stepping through the code line by line. I watch the variables change in real time. – FourierFlux Jan 10 '22 at 00:53
  • Have you tried with optimisations turned off? Nothing actually uses those two variables so perhaps the compiler has optimised those out? – kaylum Jan 10 '22 at 00:54
  • I disabled all optimizations (optimization level 0). The final thing I changed was disabling the "remove unused sections" command which seemed to have a positive effect. – FourierFlux Jan 10 '22 at 00:55
  • You'll have _undefined behavior_ as soon as those `encoder_1_position` and `encoder_2_position` reaches `INT_MAX` and goes beyon (unless the implementation you use actually _has_ defined what'll happen then) – Ted Lyngmo Jan 10 '22 at 00:57
  • You misunderstand, the values become random before they even reach the while loop. – FourierFlux Jan 10 '22 at 00:58
  • `#include ` (similar for string,stdio, and math) – wildplasser Jan 10 '22 at 00:59
  • I was using a different ISR to increase/decrease them which I removed since it wasn't relevant to the core problem which is random junk getting added to them in unrelated code. – FourierFlux Jan 10 '22 at 01:02
  • 1
    @FourierFlux "_the values become random before they even reach the while loop_" - How did you observe this behavior? – Ted Lyngmo Jan 10 '22 at 01:13
  • Not knowing anything else about how this is supposed to work, my first thought would be that either the receive buffer is too small, or an index or pointer is going past the end. Hopefully it's the first thing you checked? – John Bayko Jan 10 '22 at 01:26
  • Thanks, I checked and that's no a problem in this example since the buffers are never used. Basically none of the listed variables get used for anything in this code but the encoder_1 variable gets changed. I suppose it's possible my debugger is freaking out also, segger is supposed to be top but I have had nothing but problems with AS7 and Jlink. – FourierFlux Jan 10 '22 at 01:29
  • The value `134217728` shown in the edit is hex `8000000`. Also shown is the filename `main.cpp` but the Q is tagged C. – Weather Vane Jan 10 '22 at 01:50
  • Looking at the disassembler view it appears it's doing this on purpose, very odd. – FourierFlux Jan 10 '22 at 02:09
  • Even stranger, after the store it does a load and then some random compare and then it jumps to a section of code where the viewer says "unknown instructions". – FourierFlux Jan 10 '22 at 02:18
  • Try to insert a piece of code which reads encoder_x_position in a way not optimizable out and, maybe, also assign cyclically encoder_x_position to some other variable. I think that test is interesting. – linuxfan says Reinstate Monica Jan 10 '22 at 08:19
  • How did you create your project? I don't remember the details of Atmel Studio, but most embedded IDEs have the option to create a "minimal"/"fast" start-up code. This is a common but non-standard setting, as opposed to "ANSI/ISO C project" or some such. If minimal start-up is enabled, the C run-time will _not_ initialize the `.data` and `.bss` sections regardless if your code provides initializers for them or not. Instead, all variables residing in those sections have to be set in "run-time". – Lundin Jan 10 '22 at 09:17
  • 1
    Also those arrays are _huge_. How large is your `.bss` section in the linker script? Also you declared a 1000 bytes large array on the stack, which is bad practice even on hosted systems and this ain't a PC. How large is your stack? When variables change auto-magically, always suspect stack overflow. – Lundin Jan 10 '22 at 09:19
  • I was able to make an even simpler example without the arrays which did the same thing. I am using the minimal startup code but the issue isn't initialization, the compiler is purposefully putting junk in that variables location for unknown reasons. – FourierFlux Jan 10 '22 at 16:33
  • 1
    Can you edit in your cut-down program, and a **textual** (not a screenshot) assembly dump of the **entire executable** for the cut-down program, please? The **complete and unedited** output of whatever the equivalent of `readelf --program-headers a.out` is, would also be useful. – zwol Jan 10 '22 at 18:59
  • done. I noticed changing the buffer size from 1000 to 100 did stop the random change, but it shouldn't have made a difference. Something fishy is going on. – FourierFlux Jan 12 '22 at 00:21
  • Also interestingly based upon Weather Vanes statement it appears to load the entry point into the variable. – FourierFlux Jan 12 '22 at 00:22
  • Looking at the disassembly between the two, the assembler output looks the same in the region the abberant behavior happens. – FourierFlux Jan 12 '22 at 00:39
  • I figured it out I think, for some reason my linker was not processing my #define on the stack_size so no matter how big I made it. I tried editing it in the linker file directly and the issue appears to be gone. It's still extremely strange. Do you know what could be the issue? – FourierFlux Jan 12 '22 at 01:16
  • @FourierFlux The linker doesn't know about pre-processor directives. You have to reserve space for the stack somewhere in the linker script. Since it's a Cortex M, the sp gets set upon reset so why does your source even need to know the size of the stack? – Lundin Jan 12 '22 at 10:05
  • Why wouldn't it appear as a symbol, particularly since C preprocessor runs first? – FourierFlux Jan 12 '22 at 16:07

1 Answers1

2

I since disabled "remove unused sections" in the linker command and it seemed to fix the problem(apparently the BSS section was being tossed out)

This is just a guess, but that could mean that your program loader is not processing the BSS section correctly. It is supposed to allocate and zero the memory region the linker assigned to the BSS, even if there are no bits to copy from the executable image to that range. (It's a little more complicated than that, but unless you are stuck writing the loader yourself, that should give you enough of an idea.)

but I don't understand why particularly since every global variable I have is declared with volatile.

volatile doesn't do what you think it does. (More detail.)

zwol
  • 135,547
  • 38
  • 252
  • 361
  • It's totally bizarre since no variables get changed in the code, none. If it was a buffer overrun or something I could understand, but there is zero reason this memory location should be changing at all since no sram locations are updated. – FourierFlux Jan 10 '22 at 01:51