where are constant variables stored in microcontroller?
The answer to your question is specific to the particularly architecture you are using. Since you have mentioned ARM, I'll give you an answer based on this.

The ARM Cortex is a register based design, so basically any operands (const or not) must some how make their way into one of the internal registers before they can be used by program instructions. This is central to answering your question, because there are a couple of different ways the architecture allows this to be done.

For small constants (typically less than 8 or 10-bits), the value can be encoded directly into certain instructions. For example, there is an ADD #imm instruction that will add a 12-bit value encoded into the instruction word to a register. This can be used to directly specify a constant in your program. If you were adding the same constant in various different places in your code, and the value was 12-bits or less, then the compiler would just use an ADD #imm instruction everywhere your constant was required. In other words, the actual const will be replicated in multiple locations throughout the code that is stored in FLASH.

If the constant is large then this won't work, so the value will have to be stored in its own dedicated FLASH memory location. The chip has another instruction, called LDR which it uses to move a value from a memory location into the internal registers where it can be used. This instruction does not care whether the value is physically stored in FLASH or RAM, it just pulls the value from a specific address in memory and puts it into a register. Note that compared to the situation with small constants, this requires an extra instruction cycle, but if the constant is used repeatedly in a block of code then the compiler will cache it by putting it into a spare register if one is available.

However now we run into a potential problem. On most Cortex chips the FLASH memory runs at the same speed or slower than the CPU core. If we attempt to execute an LDR instruction from a FLASH location, this read operation of the physical memory must compete with the reading of the next instruction. This creates a bottleneck, which causes the CPU to have to stall until the data has been read. Even worse, on many implementations, the FLASH runs very slow and a pipeline cache is used to feed instructions to the CPU faster. In these devices reading, say, a table of constant values can expose the fundamental FLASH access bottleneck causing severe loss of performance.

For this reason, many compilers will look to copy any constant data into spare RAM locations if possible. This will prevent such issues, and since RAM is normally faster to access than FLASH can prevent a lot of performance bottlenecks. If there is unused RAM in your program anyway, then it is virtually no overhead for the compiler to do this.

So there is most definitely a logic to how the compiler allocates constant data to physical memory, but thankfully in most situations the chip and compiler designers have done all this hard work for you, and you can just trust that it is doing whatever is best for your particular code and optimization level.