Is it safe to attempt (and fail) to write to a const on an STM32?
up vote
0
down vote
favorite
So, we are experimenting with an approach to perform some matrix math. This is embedded, so memory is limited, and we will have large matrices so it helps us to keep some of them stored in flash rather than RAM.
I've written a matrix structure, two arrays (one const/flash and the other RAM), and a "modify" and "get" function. One matrix, I initialize to the RAM data, and the other matrix I initialize to the flash data, using a cast from const *f32 to *f32.
What I find is that when I run this code on my STM32 embedded processor, the RAM matrix is modifiable, and the matrix pointing to the flash data simply doesn't change (the set to 12.0 doesn't "take", the value remains 2.0).
(before change) a=2, b=2, (after change) c=2, d=12
This is acceptable behavior, by design we will not attempt to modify matrices of flash data, but if we make a mistake we don't want it to crash.
If I run the same code on my windows machine with Visual C++, however, I get an "access violation" when I attempt to run the code below, when I try to modify the const array to 12.0.
This is not surprising that Windows would object, but I'd like to understand the difference in behavior better. This seems related to CPU architecture. Is it safe, on our STM32, to let the code attempt to write to a const array and let it have no effect? Or are there side effects, or reasons to avoid this?
static const f32 constarray[9] = {1,2,3,1,2,3,1,2,3};
static f32 ramarray[9] = {1,2,3,1,2,3,1,2,3};
typedef struct {
u16 rows;
u16 cols;
f32 * mat;
} matrix_versatile;
void modify_versatile_matrix(matrix_versatile * m, uint16_t r, uint16_t c, double new_value)
{
m->mat[r * m->cols + c] = new_value;
}
double get_versatile_matrix_value(matrix_versatile * m, uint16_t r, uint16_t c)
{
return m->mat[r * m->cols + c];
}
double a;
double b;
double c;
double d;
int main(void)
{
matrix_versatile matrix_with_const_data;
matrix_versatile matrix_with_ram_data;
matrix_with_const_data.cols = 3;
matrix_with_const_data.rows = 3;
matrix_with_const_data.mat = (f32 *) constarray;
matrix_with_ram_data.cols = 3;
matrix_with_ram_data.rows = 3;
matrix_with_ram_data.mat = ramarray;
a = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
b = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
modify_versatile_matrix(&matrix_with_const_data, 1, 1, 12.0);
modify_versatile_matrix(&matrix_with_ram_data, 1, 1, 12.0);
c = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
d = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
visual-c++ embedded stm32
add a comment |
up vote
0
down vote
favorite
So, we are experimenting with an approach to perform some matrix math. This is embedded, so memory is limited, and we will have large matrices so it helps us to keep some of them stored in flash rather than RAM.
I've written a matrix structure, two arrays (one const/flash and the other RAM), and a "modify" and "get" function. One matrix, I initialize to the RAM data, and the other matrix I initialize to the flash data, using a cast from const *f32 to *f32.
What I find is that when I run this code on my STM32 embedded processor, the RAM matrix is modifiable, and the matrix pointing to the flash data simply doesn't change (the set to 12.0 doesn't "take", the value remains 2.0).
(before change) a=2, b=2, (after change) c=2, d=12
This is acceptable behavior, by design we will not attempt to modify matrices of flash data, but if we make a mistake we don't want it to crash.
If I run the same code on my windows machine with Visual C++, however, I get an "access violation" when I attempt to run the code below, when I try to modify the const array to 12.0.
This is not surprising that Windows would object, but I'd like to understand the difference in behavior better. This seems related to CPU architecture. Is it safe, on our STM32, to let the code attempt to write to a const array and let it have no effect? Or are there side effects, or reasons to avoid this?
static const f32 constarray[9] = {1,2,3,1,2,3,1,2,3};
static f32 ramarray[9] = {1,2,3,1,2,3,1,2,3};
typedef struct {
u16 rows;
u16 cols;
f32 * mat;
} matrix_versatile;
void modify_versatile_matrix(matrix_versatile * m, uint16_t r, uint16_t c, double new_value)
{
m->mat[r * m->cols + c] = new_value;
}
double get_versatile_matrix_value(matrix_versatile * m, uint16_t r, uint16_t c)
{
return m->mat[r * m->cols + c];
}
double a;
double b;
double c;
double d;
int main(void)
{
matrix_versatile matrix_with_const_data;
matrix_versatile matrix_with_ram_data;
matrix_with_const_data.cols = 3;
matrix_with_const_data.rows = 3;
matrix_with_const_data.mat = (f32 *) constarray;
matrix_with_ram_data.cols = 3;
matrix_with_ram_data.rows = 3;
matrix_with_ram_data.mat = ramarray;
a = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
b = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
modify_versatile_matrix(&matrix_with_const_data, 1, 1, 12.0);
modify_versatile_matrix(&matrix_with_ram_data, 1, 1, 12.0);
c = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
d = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
visual-c++ embedded stm32
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
So, we are experimenting with an approach to perform some matrix math. This is embedded, so memory is limited, and we will have large matrices so it helps us to keep some of them stored in flash rather than RAM.
I've written a matrix structure, two arrays (one const/flash and the other RAM), and a "modify" and "get" function. One matrix, I initialize to the RAM data, and the other matrix I initialize to the flash data, using a cast from const *f32 to *f32.
What I find is that when I run this code on my STM32 embedded processor, the RAM matrix is modifiable, and the matrix pointing to the flash data simply doesn't change (the set to 12.0 doesn't "take", the value remains 2.0).
(before change) a=2, b=2, (after change) c=2, d=12
This is acceptable behavior, by design we will not attempt to modify matrices of flash data, but if we make a mistake we don't want it to crash.
If I run the same code on my windows machine with Visual C++, however, I get an "access violation" when I attempt to run the code below, when I try to modify the const array to 12.0.
This is not surprising that Windows would object, but I'd like to understand the difference in behavior better. This seems related to CPU architecture. Is it safe, on our STM32, to let the code attempt to write to a const array and let it have no effect? Or are there side effects, or reasons to avoid this?
static const f32 constarray[9] = {1,2,3,1,2,3,1,2,3};
static f32 ramarray[9] = {1,2,3,1,2,3,1,2,3};
typedef struct {
u16 rows;
u16 cols;
f32 * mat;
} matrix_versatile;
void modify_versatile_matrix(matrix_versatile * m, uint16_t r, uint16_t c, double new_value)
{
m->mat[r * m->cols + c] = new_value;
}
double get_versatile_matrix_value(matrix_versatile * m, uint16_t r, uint16_t c)
{
return m->mat[r * m->cols + c];
}
double a;
double b;
double c;
double d;
int main(void)
{
matrix_versatile matrix_with_const_data;
matrix_versatile matrix_with_ram_data;
matrix_with_const_data.cols = 3;
matrix_with_const_data.rows = 3;
matrix_with_const_data.mat = (f32 *) constarray;
matrix_with_ram_data.cols = 3;
matrix_with_ram_data.rows = 3;
matrix_with_ram_data.mat = ramarray;
a = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
b = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
modify_versatile_matrix(&matrix_with_const_data, 1, 1, 12.0);
modify_versatile_matrix(&matrix_with_ram_data, 1, 1, 12.0);
c = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
d = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
visual-c++ embedded stm32
So, we are experimenting with an approach to perform some matrix math. This is embedded, so memory is limited, and we will have large matrices so it helps us to keep some of them stored in flash rather than RAM.
I've written a matrix structure, two arrays (one const/flash and the other RAM), and a "modify" and "get" function. One matrix, I initialize to the RAM data, and the other matrix I initialize to the flash data, using a cast from const *f32 to *f32.
What I find is that when I run this code on my STM32 embedded processor, the RAM matrix is modifiable, and the matrix pointing to the flash data simply doesn't change (the set to 12.0 doesn't "take", the value remains 2.0).
(before change) a=2, b=2, (after change) c=2, d=12
This is acceptable behavior, by design we will not attempt to modify matrices of flash data, but if we make a mistake we don't want it to crash.
If I run the same code on my windows machine with Visual C++, however, I get an "access violation" when I attempt to run the code below, when I try to modify the const array to 12.0.
This is not surprising that Windows would object, but I'd like to understand the difference in behavior better. This seems related to CPU architecture. Is it safe, on our STM32, to let the code attempt to write to a const array and let it have no effect? Or are there side effects, or reasons to avoid this?
static const f32 constarray[9] = {1,2,3,1,2,3,1,2,3};
static f32 ramarray[9] = {1,2,3,1,2,3,1,2,3};
typedef struct {
u16 rows;
u16 cols;
f32 * mat;
} matrix_versatile;
void modify_versatile_matrix(matrix_versatile * m, uint16_t r, uint16_t c, double new_value)
{
m->mat[r * m->cols + c] = new_value;
}
double get_versatile_matrix_value(matrix_versatile * m, uint16_t r, uint16_t c)
{
return m->mat[r * m->cols + c];
}
double a;
double b;
double c;
double d;
int main(void)
{
matrix_versatile matrix_with_const_data;
matrix_versatile matrix_with_ram_data;
matrix_with_const_data.cols = 3;
matrix_with_const_data.rows = 3;
matrix_with_const_data.mat = (f32 *) constarray;
matrix_with_ram_data.cols = 3;
matrix_with_ram_data.rows = 3;
matrix_with_ram_data.mat = ramarray;
a = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
b = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
modify_versatile_matrix(&matrix_with_const_data, 1, 1, 12.0);
modify_versatile_matrix(&matrix_with_ram_data, 1, 1, 12.0);
c = get_versatile_matrix_value(&matrix_with_const_data, 1, 1);
d = get_versatile_matrix_value(&matrix_with_ram_data, 1, 1);
visual-c++ embedded stm32
visual-c++ embedded stm32
edited Nov 8 at 20:21
Clifford
58k858124
58k858124
asked Nov 8 at 20:00
Chris
111222
111222
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
up vote
5
down vote
but if we make a mistake we don't want it to crash.
Attempting to write to ROM will not in itself cause a crash, but the code attempting to write it is by definition buggy and may crash in any case, and will certainly not behave as intended.
It is almost entirely wrong thinking; if you have a bug, you really want it to crash during development, and not after deployment. If it silently does the wrong thing, you may never notice the bug, or the crash might occur somewhere other than in proximity of the bug, so be very hard to find.
Architectures an MMU or MPU may issue an exception if you attempt to write to memory marked as read-only. That is what is happening in Windows. In that case it can be a useful debug aid given an exception handler that reports such errors by some means. In this case the error is reported exactly when it occurs, rather than crashing some time later when some invalid data is accessed or incorrect result acted upon.
Some, but mot all STM32 parts include the MPU (application note)
Got it. Yes, at development time we will check and double check that we are never attempting to modify a FLASH-based matrix. But I'm curious, you say our STM32 "may crash in any case"... can you expand on that, what might happen?
– Chris
Nov 8 at 20:37
In short, I guess I assumed that this was a feature, that the CPU was smart enough to realize that it was modifying FLASH and it would noop instead. But this is speculation. What is really happening, and how would it fail?
– Chris
Nov 8 at 20:43
Oh, and further on the development philosophy I think we will add a boolean to our matrix structure to indicate RW or RO, for further protection, so that even in the event of a mixup we do not attempt to write to FLASH and rely on this "noop" behavior. So mostly at this point I'm just curious: why does it have no effect, is this a feature, can we count on it, or is this behavior undefined, indeterminate, and could bite us? And if it bites us, how?
– Chris
Nov 8 at 20:48
1
@Chris The behaviour is determinate, documented, so you can count on it as a feature. The effect of writing a known value to a known address is completely predictable. RAM: value changes, FLASH: no change and status bit is set, memory mapped register: see the Reference Manual, unmapped area: Bus Fault. Problems start to happen when the address or the value is not predictable.
– berendi
Nov 8 at 22:04
1
@chris Defensive code is one thing, but your approach makes no sense - you are writing _more_software to check for software errors. What makes you think that if you expect to write broken software, writing yet more software will detect it!? A system of asserts on results or reconditions and unit testing is a more robust approach. You are proposing writing code to detect one specific type of code error; what about all the more likely errors. Moreover the error you have exemplified is down to poor coding practice - casting away a const. If you don't do that the compiler will catch it.
– Clifford
Nov 9 at 7:15
|
show 7 more comments
up vote
1
down vote
The answer may depend on the series (STM32F1, STM32F4, STM32L1 etc), as they have somewhat different flash controllers.
I've once made the same mistake on an STM32F429, and investigated a bit, so I can tell what would happen on an STM32F4.
Probably nothing.
The flash is by default protected, in order to be somewhat resilient to those kind of programming errors. In order to modify the flash, one has to write certain values to the FLASH->KEYR
register. If the wrong value is written, then the flash will be locked until reset, so nothing really bad can happen unless the program writes 64 bits of correct values. No unexpected interrupts can happen, because the interrupt enable bit is protected by this key too. The attempt will set some error bits in FLASH->SR
, so a program can check it and warn the user (preferably the tester).
However if there is some code there (e.g. a bootloader, or logging something into flash) that is supposed to write something in the flash, i.e. it unlocks the flash with the correct keys, then bad things can happen.
If the flash is left unlocked after a preceding write operation, then writing to a previously programmed area will change bits from 1
to 0
, but not from 0
to 1
. It means that the flash will contain the bitwise AND
of the old and the newly written value.
If the failed write attempt occurs first, and unlocked afterwards, then no legitimate write or erase operation would succeed unless the status bits are properly cleared first.
If the intended and unintended accesses occur interleaved, e.g. in interrupt handlers, then all bets are off.
Even if the values are in immutable flash memory, there can still be unexpected result. Consider this code
int foo(int *array) {
array[0] = 1;
array[1] = 3;
array[2] = 5;
return array[0];
}
An optimizing compiler might recognize that the return value should always be 1
, and emit code to that effect. Or it might not, and reload array[0]
from wherever it is stored, possibly a different value from flash. It may behave differently in debug and release builds, or when the function is called from different places, as it might be inlined differently.
If the pointer points to an unmapped area, neither RAM nor FLASH nor some memory mapped register, then a a fault will occur, and as the default fault handlers contain just an infinite loop, the program will hang unless it has a fault handler installed that can deal with the situation. Needless to say, overwriting random RAM areas or registers can result in barely predictable behaviour.
UPDATE
I've tried your code on actual hardware. When I ran it verbatim, the compiler (gcc-arm-none-eabi-7-2018-q2-update -O3 -lto
) optimized away everything, since the variables were not used afterwards. Marking a, b, c, d
as volatile
resulted in c=2
and d=12
, it was still considering the first array const
, and no accesses to the arrays were generated. constarray
did not show up in the map file at all, the linker had eliminated it completely.
So I've tried a few things one at a time to force the optimizer to generate code that would actually access the arrays.
- Disablig optimization (
-O0
) - Making all variables
volatile
- Inserting a couple of compile-time memory barriers (
asm volatile("":::"memory");
- Doing some complex calculations in the middle
Any of these has produced varying effects on different MCUs, but they were always consistent on a single platform.
STM32F103
: Hard Fault. Only halfword (16 bit) write accesses are allowed to the flash, 8 or 32 bits always result in a fault. When I've changed the data types toshort
, the code ran, of course without any effect on the flash.
STM32F417
: Code runs, with no effects on the flash contents, but bits 6 and 7,PGPERR
andPGSERR
inFLASH->SR
were set a few cycles after the first write attempt toconstarray
.
STM32L151
: Code runs, with no effects on the flash controller status.
The question appears to be about write access to a read-only address rather then more specifically about failure to write to flash memory because it is explicitly write-protected. Write protection is only relevant when programming flash; when not in programming mode, the access has no effect at all, unless the part has an MPU and the region is marked read-only. The title and code example refer toconst
rather then specifically flash memory an flash programming.
– Clifford
Nov 9 at 7:35
@Cliffordconst
arrays are placed in the flash by the linker, unless one uses some really weird linker script or startup code. If theconst
qualifier is lost when passing the array address to a function that expects a non-const pointer parameter, and attempts to write to an array element, then it will try to write a value to an address in flash. Of course the flash contents would be left unchanged, but the flash controller sees it as a failed programming attempt, and sets the error flag in its status register.
– berendi
Nov 9 at 7:55
@Clifford It has once got me wondering why my code that deliberately writes the flash stops working when a certain unrelated function is invoked. Turned out the unrelated function had the same kind of bug as the code example in the question. Flash programming started to work when I've clearedFLASH->SR
, and monitoring the status register has helped me to find the real bug.
– berendi
Nov 9 at 8:22
I disagree, there is no attempt to program the flash memory at runtime in the question. It is an important consideration if you are programming flash at runtime (a practice that has particular issues in STM32 in any case), but it clearly does not relate to this question.
– Clifford
Nov 9 at 9:02
@Clifford I've tried it on actual hardware, see my updated answer. The flash controller does not really care what the programmer was attempting to do, it sets the flags on write accesses. Or raises a fault.
– berendi
Nov 11 at 13:35
|
show 1 more comment
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
5
down vote
but if we make a mistake we don't want it to crash.
Attempting to write to ROM will not in itself cause a crash, but the code attempting to write it is by definition buggy and may crash in any case, and will certainly not behave as intended.
It is almost entirely wrong thinking; if you have a bug, you really want it to crash during development, and not after deployment. If it silently does the wrong thing, you may never notice the bug, or the crash might occur somewhere other than in proximity of the bug, so be very hard to find.
Architectures an MMU or MPU may issue an exception if you attempt to write to memory marked as read-only. That is what is happening in Windows. In that case it can be a useful debug aid given an exception handler that reports such errors by some means. In this case the error is reported exactly when it occurs, rather than crashing some time later when some invalid data is accessed or incorrect result acted upon.
Some, but mot all STM32 parts include the MPU (application note)
Got it. Yes, at development time we will check and double check that we are never attempting to modify a FLASH-based matrix. But I'm curious, you say our STM32 "may crash in any case"... can you expand on that, what might happen?
– Chris
Nov 8 at 20:37
In short, I guess I assumed that this was a feature, that the CPU was smart enough to realize that it was modifying FLASH and it would noop instead. But this is speculation. What is really happening, and how would it fail?
– Chris
Nov 8 at 20:43
Oh, and further on the development philosophy I think we will add a boolean to our matrix structure to indicate RW or RO, for further protection, so that even in the event of a mixup we do not attempt to write to FLASH and rely on this "noop" behavior. So mostly at this point I'm just curious: why does it have no effect, is this a feature, can we count on it, or is this behavior undefined, indeterminate, and could bite us? And if it bites us, how?
– Chris
Nov 8 at 20:48
1
@Chris The behaviour is determinate, documented, so you can count on it as a feature. The effect of writing a known value to a known address is completely predictable. RAM: value changes, FLASH: no change and status bit is set, memory mapped register: see the Reference Manual, unmapped area: Bus Fault. Problems start to happen when the address or the value is not predictable.
– berendi
Nov 8 at 22:04
1
@chris Defensive code is one thing, but your approach makes no sense - you are writing _more_software to check for software errors. What makes you think that if you expect to write broken software, writing yet more software will detect it!? A system of asserts on results or reconditions and unit testing is a more robust approach. You are proposing writing code to detect one specific type of code error; what about all the more likely errors. Moreover the error you have exemplified is down to poor coding practice - casting away a const. If you don't do that the compiler will catch it.
– Clifford
Nov 9 at 7:15
|
show 7 more comments
up vote
5
down vote
but if we make a mistake we don't want it to crash.
Attempting to write to ROM will not in itself cause a crash, but the code attempting to write it is by definition buggy and may crash in any case, and will certainly not behave as intended.
It is almost entirely wrong thinking; if you have a bug, you really want it to crash during development, and not after deployment. If it silently does the wrong thing, you may never notice the bug, or the crash might occur somewhere other than in proximity of the bug, so be very hard to find.
Architectures an MMU or MPU may issue an exception if you attempt to write to memory marked as read-only. That is what is happening in Windows. In that case it can be a useful debug aid given an exception handler that reports such errors by some means. In this case the error is reported exactly when it occurs, rather than crashing some time later when some invalid data is accessed or incorrect result acted upon.
Some, but mot all STM32 parts include the MPU (application note)
Got it. Yes, at development time we will check and double check that we are never attempting to modify a FLASH-based matrix. But I'm curious, you say our STM32 "may crash in any case"... can you expand on that, what might happen?
– Chris
Nov 8 at 20:37
In short, I guess I assumed that this was a feature, that the CPU was smart enough to realize that it was modifying FLASH and it would noop instead. But this is speculation. What is really happening, and how would it fail?
– Chris
Nov 8 at 20:43
Oh, and further on the development philosophy I think we will add a boolean to our matrix structure to indicate RW or RO, for further protection, so that even in the event of a mixup we do not attempt to write to FLASH and rely on this "noop" behavior. So mostly at this point I'm just curious: why does it have no effect, is this a feature, can we count on it, or is this behavior undefined, indeterminate, and could bite us? And if it bites us, how?
– Chris
Nov 8 at 20:48
1
@Chris The behaviour is determinate, documented, so you can count on it as a feature. The effect of writing a known value to a known address is completely predictable. RAM: value changes, FLASH: no change and status bit is set, memory mapped register: see the Reference Manual, unmapped area: Bus Fault. Problems start to happen when the address or the value is not predictable.
– berendi
Nov 8 at 22:04
1
@chris Defensive code is one thing, but your approach makes no sense - you are writing _more_software to check for software errors. What makes you think that if you expect to write broken software, writing yet more software will detect it!? A system of asserts on results or reconditions and unit testing is a more robust approach. You are proposing writing code to detect one specific type of code error; what about all the more likely errors. Moreover the error you have exemplified is down to poor coding practice - casting away a const. If you don't do that the compiler will catch it.
– Clifford
Nov 9 at 7:15
|
show 7 more comments
up vote
5
down vote
up vote
5
down vote
but if we make a mistake we don't want it to crash.
Attempting to write to ROM will not in itself cause a crash, but the code attempting to write it is by definition buggy and may crash in any case, and will certainly not behave as intended.
It is almost entirely wrong thinking; if you have a bug, you really want it to crash during development, and not after deployment. If it silently does the wrong thing, you may never notice the bug, or the crash might occur somewhere other than in proximity of the bug, so be very hard to find.
Architectures an MMU or MPU may issue an exception if you attempt to write to memory marked as read-only. That is what is happening in Windows. In that case it can be a useful debug aid given an exception handler that reports such errors by some means. In this case the error is reported exactly when it occurs, rather than crashing some time later when some invalid data is accessed or incorrect result acted upon.
Some, but mot all STM32 parts include the MPU (application note)
but if we make a mistake we don't want it to crash.
Attempting to write to ROM will not in itself cause a crash, but the code attempting to write it is by definition buggy and may crash in any case, and will certainly not behave as intended.
It is almost entirely wrong thinking; if you have a bug, you really want it to crash during development, and not after deployment. If it silently does the wrong thing, you may never notice the bug, or the crash might occur somewhere other than in proximity of the bug, so be very hard to find.
Architectures an MMU or MPU may issue an exception if you attempt to write to memory marked as read-only. That is what is happening in Windows. In that case it can be a useful debug aid given an exception handler that reports such errors by some means. In this case the error is reported exactly when it occurs, rather than crashing some time later when some invalid data is accessed or incorrect result acted upon.
Some, but mot all STM32 parts include the MPU (application note)
edited Nov 9 at 7:23
answered Nov 8 at 20:21
Clifford
58k858124
58k858124
Got it. Yes, at development time we will check and double check that we are never attempting to modify a FLASH-based matrix. But I'm curious, you say our STM32 "may crash in any case"... can you expand on that, what might happen?
– Chris
Nov 8 at 20:37
In short, I guess I assumed that this was a feature, that the CPU was smart enough to realize that it was modifying FLASH and it would noop instead. But this is speculation. What is really happening, and how would it fail?
– Chris
Nov 8 at 20:43
Oh, and further on the development philosophy I think we will add a boolean to our matrix structure to indicate RW or RO, for further protection, so that even in the event of a mixup we do not attempt to write to FLASH and rely on this "noop" behavior. So mostly at this point I'm just curious: why does it have no effect, is this a feature, can we count on it, or is this behavior undefined, indeterminate, and could bite us? And if it bites us, how?
– Chris
Nov 8 at 20:48
1
@Chris The behaviour is determinate, documented, so you can count on it as a feature. The effect of writing a known value to a known address is completely predictable. RAM: value changes, FLASH: no change and status bit is set, memory mapped register: see the Reference Manual, unmapped area: Bus Fault. Problems start to happen when the address or the value is not predictable.
– berendi
Nov 8 at 22:04
1
@chris Defensive code is one thing, but your approach makes no sense - you are writing _more_software to check for software errors. What makes you think that if you expect to write broken software, writing yet more software will detect it!? A system of asserts on results or reconditions and unit testing is a more robust approach. You are proposing writing code to detect one specific type of code error; what about all the more likely errors. Moreover the error you have exemplified is down to poor coding practice - casting away a const. If you don't do that the compiler will catch it.
– Clifford
Nov 9 at 7:15
|
show 7 more comments
Got it. Yes, at development time we will check and double check that we are never attempting to modify a FLASH-based matrix. But I'm curious, you say our STM32 "may crash in any case"... can you expand on that, what might happen?
– Chris
Nov 8 at 20:37
In short, I guess I assumed that this was a feature, that the CPU was smart enough to realize that it was modifying FLASH and it would noop instead. But this is speculation. What is really happening, and how would it fail?
– Chris
Nov 8 at 20:43
Oh, and further on the development philosophy I think we will add a boolean to our matrix structure to indicate RW or RO, for further protection, so that even in the event of a mixup we do not attempt to write to FLASH and rely on this "noop" behavior. So mostly at this point I'm just curious: why does it have no effect, is this a feature, can we count on it, or is this behavior undefined, indeterminate, and could bite us? And if it bites us, how?
– Chris
Nov 8 at 20:48
1
@Chris The behaviour is determinate, documented, so you can count on it as a feature. The effect of writing a known value to a known address is completely predictable. RAM: value changes, FLASH: no change and status bit is set, memory mapped register: see the Reference Manual, unmapped area: Bus Fault. Problems start to happen when the address or the value is not predictable.
– berendi
Nov 8 at 22:04
1
@chris Defensive code is one thing, but your approach makes no sense - you are writing _more_software to check for software errors. What makes you think that if you expect to write broken software, writing yet more software will detect it!? A system of asserts on results or reconditions and unit testing is a more robust approach. You are proposing writing code to detect one specific type of code error; what about all the more likely errors. Moreover the error you have exemplified is down to poor coding practice - casting away a const. If you don't do that the compiler will catch it.
– Clifford
Nov 9 at 7:15
Got it. Yes, at development time we will check and double check that we are never attempting to modify a FLASH-based matrix. But I'm curious, you say our STM32 "may crash in any case"... can you expand on that, what might happen?
– Chris
Nov 8 at 20:37
Got it. Yes, at development time we will check and double check that we are never attempting to modify a FLASH-based matrix. But I'm curious, you say our STM32 "may crash in any case"... can you expand on that, what might happen?
– Chris
Nov 8 at 20:37
In short, I guess I assumed that this was a feature, that the CPU was smart enough to realize that it was modifying FLASH and it would noop instead. But this is speculation. What is really happening, and how would it fail?
– Chris
Nov 8 at 20:43
In short, I guess I assumed that this was a feature, that the CPU was smart enough to realize that it was modifying FLASH and it would noop instead. But this is speculation. What is really happening, and how would it fail?
– Chris
Nov 8 at 20:43
Oh, and further on the development philosophy I think we will add a boolean to our matrix structure to indicate RW or RO, for further protection, so that even in the event of a mixup we do not attempt to write to FLASH and rely on this "noop" behavior. So mostly at this point I'm just curious: why does it have no effect, is this a feature, can we count on it, or is this behavior undefined, indeterminate, and could bite us? And if it bites us, how?
– Chris
Nov 8 at 20:48
Oh, and further on the development philosophy I think we will add a boolean to our matrix structure to indicate RW or RO, for further protection, so that even in the event of a mixup we do not attempt to write to FLASH and rely on this "noop" behavior. So mostly at this point I'm just curious: why does it have no effect, is this a feature, can we count on it, or is this behavior undefined, indeterminate, and could bite us? And if it bites us, how?
– Chris
Nov 8 at 20:48
1
1
@Chris The behaviour is determinate, documented, so you can count on it as a feature. The effect of writing a known value to a known address is completely predictable. RAM: value changes, FLASH: no change and status bit is set, memory mapped register: see the Reference Manual, unmapped area: Bus Fault. Problems start to happen when the address or the value is not predictable.
– berendi
Nov 8 at 22:04
@Chris The behaviour is determinate, documented, so you can count on it as a feature. The effect of writing a known value to a known address is completely predictable. RAM: value changes, FLASH: no change and status bit is set, memory mapped register: see the Reference Manual, unmapped area: Bus Fault. Problems start to happen when the address or the value is not predictable.
– berendi
Nov 8 at 22:04
1
1
@chris Defensive code is one thing, but your approach makes no sense - you are writing _more_software to check for software errors. What makes you think that if you expect to write broken software, writing yet more software will detect it!? A system of asserts on results or reconditions and unit testing is a more robust approach. You are proposing writing code to detect one specific type of code error; what about all the more likely errors. Moreover the error you have exemplified is down to poor coding practice - casting away a const. If you don't do that the compiler will catch it.
– Clifford
Nov 9 at 7:15
@chris Defensive code is one thing, but your approach makes no sense - you are writing _more_software to check for software errors. What makes you think that if you expect to write broken software, writing yet more software will detect it!? A system of asserts on results or reconditions and unit testing is a more robust approach. You are proposing writing code to detect one specific type of code error; what about all the more likely errors. Moreover the error you have exemplified is down to poor coding practice - casting away a const. If you don't do that the compiler will catch it.
– Clifford
Nov 9 at 7:15
|
show 7 more comments
up vote
1
down vote
The answer may depend on the series (STM32F1, STM32F4, STM32L1 etc), as they have somewhat different flash controllers.
I've once made the same mistake on an STM32F429, and investigated a bit, so I can tell what would happen on an STM32F4.
Probably nothing.
The flash is by default protected, in order to be somewhat resilient to those kind of programming errors. In order to modify the flash, one has to write certain values to the FLASH->KEYR
register. If the wrong value is written, then the flash will be locked until reset, so nothing really bad can happen unless the program writes 64 bits of correct values. No unexpected interrupts can happen, because the interrupt enable bit is protected by this key too. The attempt will set some error bits in FLASH->SR
, so a program can check it and warn the user (preferably the tester).
However if there is some code there (e.g. a bootloader, or logging something into flash) that is supposed to write something in the flash, i.e. it unlocks the flash with the correct keys, then bad things can happen.
If the flash is left unlocked after a preceding write operation, then writing to a previously programmed area will change bits from 1
to 0
, but not from 0
to 1
. It means that the flash will contain the bitwise AND
of the old and the newly written value.
If the failed write attempt occurs first, and unlocked afterwards, then no legitimate write or erase operation would succeed unless the status bits are properly cleared first.
If the intended and unintended accesses occur interleaved, e.g. in interrupt handlers, then all bets are off.
Even if the values are in immutable flash memory, there can still be unexpected result. Consider this code
int foo(int *array) {
array[0] = 1;
array[1] = 3;
array[2] = 5;
return array[0];
}
An optimizing compiler might recognize that the return value should always be 1
, and emit code to that effect. Or it might not, and reload array[0]
from wherever it is stored, possibly a different value from flash. It may behave differently in debug and release builds, or when the function is called from different places, as it might be inlined differently.
If the pointer points to an unmapped area, neither RAM nor FLASH nor some memory mapped register, then a a fault will occur, and as the default fault handlers contain just an infinite loop, the program will hang unless it has a fault handler installed that can deal with the situation. Needless to say, overwriting random RAM areas or registers can result in barely predictable behaviour.
UPDATE
I've tried your code on actual hardware. When I ran it verbatim, the compiler (gcc-arm-none-eabi-7-2018-q2-update -O3 -lto
) optimized away everything, since the variables were not used afterwards. Marking a, b, c, d
as volatile
resulted in c=2
and d=12
, it was still considering the first array const
, and no accesses to the arrays were generated. constarray
did not show up in the map file at all, the linker had eliminated it completely.
So I've tried a few things one at a time to force the optimizer to generate code that would actually access the arrays.
- Disablig optimization (
-O0
) - Making all variables
volatile
- Inserting a couple of compile-time memory barriers (
asm volatile("":::"memory");
- Doing some complex calculations in the middle
Any of these has produced varying effects on different MCUs, but they were always consistent on a single platform.
STM32F103
: Hard Fault. Only halfword (16 bit) write accesses are allowed to the flash, 8 or 32 bits always result in a fault. When I've changed the data types toshort
, the code ran, of course without any effect on the flash.
STM32F417
: Code runs, with no effects on the flash contents, but bits 6 and 7,PGPERR
andPGSERR
inFLASH->SR
were set a few cycles after the first write attempt toconstarray
.
STM32L151
: Code runs, with no effects on the flash controller status.
The question appears to be about write access to a read-only address rather then more specifically about failure to write to flash memory because it is explicitly write-protected. Write protection is only relevant when programming flash; when not in programming mode, the access has no effect at all, unless the part has an MPU and the region is marked read-only. The title and code example refer toconst
rather then specifically flash memory an flash programming.
– Clifford
Nov 9 at 7:35
@Cliffordconst
arrays are placed in the flash by the linker, unless one uses some really weird linker script or startup code. If theconst
qualifier is lost when passing the array address to a function that expects a non-const pointer parameter, and attempts to write to an array element, then it will try to write a value to an address in flash. Of course the flash contents would be left unchanged, but the flash controller sees it as a failed programming attempt, and sets the error flag in its status register.
– berendi
Nov 9 at 7:55
@Clifford It has once got me wondering why my code that deliberately writes the flash stops working when a certain unrelated function is invoked. Turned out the unrelated function had the same kind of bug as the code example in the question. Flash programming started to work when I've clearedFLASH->SR
, and monitoring the status register has helped me to find the real bug.
– berendi
Nov 9 at 8:22
I disagree, there is no attempt to program the flash memory at runtime in the question. It is an important consideration if you are programming flash at runtime (a practice that has particular issues in STM32 in any case), but it clearly does not relate to this question.
– Clifford
Nov 9 at 9:02
@Clifford I've tried it on actual hardware, see my updated answer. The flash controller does not really care what the programmer was attempting to do, it sets the flags on write accesses. Or raises a fault.
– berendi
Nov 11 at 13:35
|
show 1 more comment
up vote
1
down vote
The answer may depend on the series (STM32F1, STM32F4, STM32L1 etc), as they have somewhat different flash controllers.
I've once made the same mistake on an STM32F429, and investigated a bit, so I can tell what would happen on an STM32F4.
Probably nothing.
The flash is by default protected, in order to be somewhat resilient to those kind of programming errors. In order to modify the flash, one has to write certain values to the FLASH->KEYR
register. If the wrong value is written, then the flash will be locked until reset, so nothing really bad can happen unless the program writes 64 bits of correct values. No unexpected interrupts can happen, because the interrupt enable bit is protected by this key too. The attempt will set some error bits in FLASH->SR
, so a program can check it and warn the user (preferably the tester).
However if there is some code there (e.g. a bootloader, or logging something into flash) that is supposed to write something in the flash, i.e. it unlocks the flash with the correct keys, then bad things can happen.
If the flash is left unlocked after a preceding write operation, then writing to a previously programmed area will change bits from 1
to 0
, but not from 0
to 1
. It means that the flash will contain the bitwise AND
of the old and the newly written value.
If the failed write attempt occurs first, and unlocked afterwards, then no legitimate write or erase operation would succeed unless the status bits are properly cleared first.
If the intended and unintended accesses occur interleaved, e.g. in interrupt handlers, then all bets are off.
Even if the values are in immutable flash memory, there can still be unexpected result. Consider this code
int foo(int *array) {
array[0] = 1;
array[1] = 3;
array[2] = 5;
return array[0];
}
An optimizing compiler might recognize that the return value should always be 1
, and emit code to that effect. Or it might not, and reload array[0]
from wherever it is stored, possibly a different value from flash. It may behave differently in debug and release builds, or when the function is called from different places, as it might be inlined differently.
If the pointer points to an unmapped area, neither RAM nor FLASH nor some memory mapped register, then a a fault will occur, and as the default fault handlers contain just an infinite loop, the program will hang unless it has a fault handler installed that can deal with the situation. Needless to say, overwriting random RAM areas or registers can result in barely predictable behaviour.
UPDATE
I've tried your code on actual hardware. When I ran it verbatim, the compiler (gcc-arm-none-eabi-7-2018-q2-update -O3 -lto
) optimized away everything, since the variables were not used afterwards. Marking a, b, c, d
as volatile
resulted in c=2
and d=12
, it was still considering the first array const
, and no accesses to the arrays were generated. constarray
did not show up in the map file at all, the linker had eliminated it completely.
So I've tried a few things one at a time to force the optimizer to generate code that would actually access the arrays.
- Disablig optimization (
-O0
) - Making all variables
volatile
- Inserting a couple of compile-time memory barriers (
asm volatile("":::"memory");
- Doing some complex calculations in the middle
Any of these has produced varying effects on different MCUs, but they were always consistent on a single platform.
STM32F103
: Hard Fault. Only halfword (16 bit) write accesses are allowed to the flash, 8 or 32 bits always result in a fault. When I've changed the data types toshort
, the code ran, of course without any effect on the flash.
STM32F417
: Code runs, with no effects on the flash contents, but bits 6 and 7,PGPERR
andPGSERR
inFLASH->SR
were set a few cycles after the first write attempt toconstarray
.
STM32L151
: Code runs, with no effects on the flash controller status.
The question appears to be about write access to a read-only address rather then more specifically about failure to write to flash memory because it is explicitly write-protected. Write protection is only relevant when programming flash; when not in programming mode, the access has no effect at all, unless the part has an MPU and the region is marked read-only. The title and code example refer toconst
rather then specifically flash memory an flash programming.
– Clifford
Nov 9 at 7:35
@Cliffordconst
arrays are placed in the flash by the linker, unless one uses some really weird linker script or startup code. If theconst
qualifier is lost when passing the array address to a function that expects a non-const pointer parameter, and attempts to write to an array element, then it will try to write a value to an address in flash. Of course the flash contents would be left unchanged, but the flash controller sees it as a failed programming attempt, and sets the error flag in its status register.
– berendi
Nov 9 at 7:55
@Clifford It has once got me wondering why my code that deliberately writes the flash stops working when a certain unrelated function is invoked. Turned out the unrelated function had the same kind of bug as the code example in the question. Flash programming started to work when I've clearedFLASH->SR
, and monitoring the status register has helped me to find the real bug.
– berendi
Nov 9 at 8:22
I disagree, there is no attempt to program the flash memory at runtime in the question. It is an important consideration if you are programming flash at runtime (a practice that has particular issues in STM32 in any case), but it clearly does not relate to this question.
– Clifford
Nov 9 at 9:02
@Clifford I've tried it on actual hardware, see my updated answer. The flash controller does not really care what the programmer was attempting to do, it sets the flags on write accesses. Or raises a fault.
– berendi
Nov 11 at 13:35
|
show 1 more comment
up vote
1
down vote
up vote
1
down vote
The answer may depend on the series (STM32F1, STM32F4, STM32L1 etc), as they have somewhat different flash controllers.
I've once made the same mistake on an STM32F429, and investigated a bit, so I can tell what would happen on an STM32F4.
Probably nothing.
The flash is by default protected, in order to be somewhat resilient to those kind of programming errors. In order to modify the flash, one has to write certain values to the FLASH->KEYR
register. If the wrong value is written, then the flash will be locked until reset, so nothing really bad can happen unless the program writes 64 bits of correct values. No unexpected interrupts can happen, because the interrupt enable bit is protected by this key too. The attempt will set some error bits in FLASH->SR
, so a program can check it and warn the user (preferably the tester).
However if there is some code there (e.g. a bootloader, or logging something into flash) that is supposed to write something in the flash, i.e. it unlocks the flash with the correct keys, then bad things can happen.
If the flash is left unlocked after a preceding write operation, then writing to a previously programmed area will change bits from 1
to 0
, but not from 0
to 1
. It means that the flash will contain the bitwise AND
of the old and the newly written value.
If the failed write attempt occurs first, and unlocked afterwards, then no legitimate write or erase operation would succeed unless the status bits are properly cleared first.
If the intended and unintended accesses occur interleaved, e.g. in interrupt handlers, then all bets are off.
Even if the values are in immutable flash memory, there can still be unexpected result. Consider this code
int foo(int *array) {
array[0] = 1;
array[1] = 3;
array[2] = 5;
return array[0];
}
An optimizing compiler might recognize that the return value should always be 1
, and emit code to that effect. Or it might not, and reload array[0]
from wherever it is stored, possibly a different value from flash. It may behave differently in debug and release builds, or when the function is called from different places, as it might be inlined differently.
If the pointer points to an unmapped area, neither RAM nor FLASH nor some memory mapped register, then a a fault will occur, and as the default fault handlers contain just an infinite loop, the program will hang unless it has a fault handler installed that can deal with the situation. Needless to say, overwriting random RAM areas or registers can result in barely predictable behaviour.
UPDATE
I've tried your code on actual hardware. When I ran it verbatim, the compiler (gcc-arm-none-eabi-7-2018-q2-update -O3 -lto
) optimized away everything, since the variables were not used afterwards. Marking a, b, c, d
as volatile
resulted in c=2
and d=12
, it was still considering the first array const
, and no accesses to the arrays were generated. constarray
did not show up in the map file at all, the linker had eliminated it completely.
So I've tried a few things one at a time to force the optimizer to generate code that would actually access the arrays.
- Disablig optimization (
-O0
) - Making all variables
volatile
- Inserting a couple of compile-time memory barriers (
asm volatile("":::"memory");
- Doing some complex calculations in the middle
Any of these has produced varying effects on different MCUs, but they were always consistent on a single platform.
STM32F103
: Hard Fault. Only halfword (16 bit) write accesses are allowed to the flash, 8 or 32 bits always result in a fault. When I've changed the data types toshort
, the code ran, of course without any effect on the flash.
STM32F417
: Code runs, with no effects on the flash contents, but bits 6 and 7,PGPERR
andPGSERR
inFLASH->SR
were set a few cycles after the first write attempt toconstarray
.
STM32L151
: Code runs, with no effects on the flash controller status.
The answer may depend on the series (STM32F1, STM32F4, STM32L1 etc), as they have somewhat different flash controllers.
I've once made the same mistake on an STM32F429, and investigated a bit, so I can tell what would happen on an STM32F4.
Probably nothing.
The flash is by default protected, in order to be somewhat resilient to those kind of programming errors. In order to modify the flash, one has to write certain values to the FLASH->KEYR
register. If the wrong value is written, then the flash will be locked until reset, so nothing really bad can happen unless the program writes 64 bits of correct values. No unexpected interrupts can happen, because the interrupt enable bit is protected by this key too. The attempt will set some error bits in FLASH->SR
, so a program can check it and warn the user (preferably the tester).
However if there is some code there (e.g. a bootloader, or logging something into flash) that is supposed to write something in the flash, i.e. it unlocks the flash with the correct keys, then bad things can happen.
If the flash is left unlocked after a preceding write operation, then writing to a previously programmed area will change bits from 1
to 0
, but not from 0
to 1
. It means that the flash will contain the bitwise AND
of the old and the newly written value.
If the failed write attempt occurs first, and unlocked afterwards, then no legitimate write or erase operation would succeed unless the status bits are properly cleared first.
If the intended and unintended accesses occur interleaved, e.g. in interrupt handlers, then all bets are off.
Even if the values are in immutable flash memory, there can still be unexpected result. Consider this code
int foo(int *array) {
array[0] = 1;
array[1] = 3;
array[2] = 5;
return array[0];
}
An optimizing compiler might recognize that the return value should always be 1
, and emit code to that effect. Or it might not, and reload array[0]
from wherever it is stored, possibly a different value from flash. It may behave differently in debug and release builds, or when the function is called from different places, as it might be inlined differently.
If the pointer points to an unmapped area, neither RAM nor FLASH nor some memory mapped register, then a a fault will occur, and as the default fault handlers contain just an infinite loop, the program will hang unless it has a fault handler installed that can deal with the situation. Needless to say, overwriting random RAM areas or registers can result in barely predictable behaviour.
UPDATE
I've tried your code on actual hardware. When I ran it verbatim, the compiler (gcc-arm-none-eabi-7-2018-q2-update -O3 -lto
) optimized away everything, since the variables were not used afterwards. Marking a, b, c, d
as volatile
resulted in c=2
and d=12
, it was still considering the first array const
, and no accesses to the arrays were generated. constarray
did not show up in the map file at all, the linker had eliminated it completely.
So I've tried a few things one at a time to force the optimizer to generate code that would actually access the arrays.
- Disablig optimization (
-O0
) - Making all variables
volatile
- Inserting a couple of compile-time memory barriers (
asm volatile("":::"memory");
- Doing some complex calculations in the middle
Any of these has produced varying effects on different MCUs, but they were always consistent on a single platform.
STM32F103
: Hard Fault. Only halfword (16 bit) write accesses are allowed to the flash, 8 or 32 bits always result in a fault. When I've changed the data types toshort
, the code ran, of course without any effect on the flash.
STM32F417
: Code runs, with no effects on the flash contents, but bits 6 and 7,PGPERR
andPGSERR
inFLASH->SR
were set a few cycles after the first write attempt toconstarray
.
STM32L151
: Code runs, with no effects on the flash controller status.
edited Nov 11 at 13:30
answered Nov 8 at 21:34
berendi
3,8911624
3,8911624
The question appears to be about write access to a read-only address rather then more specifically about failure to write to flash memory because it is explicitly write-protected. Write protection is only relevant when programming flash; when not in programming mode, the access has no effect at all, unless the part has an MPU and the region is marked read-only. The title and code example refer toconst
rather then specifically flash memory an flash programming.
– Clifford
Nov 9 at 7:35
@Cliffordconst
arrays are placed in the flash by the linker, unless one uses some really weird linker script or startup code. If theconst
qualifier is lost when passing the array address to a function that expects a non-const pointer parameter, and attempts to write to an array element, then it will try to write a value to an address in flash. Of course the flash contents would be left unchanged, but the flash controller sees it as a failed programming attempt, and sets the error flag in its status register.
– berendi
Nov 9 at 7:55
@Clifford It has once got me wondering why my code that deliberately writes the flash stops working when a certain unrelated function is invoked. Turned out the unrelated function had the same kind of bug as the code example in the question. Flash programming started to work when I've clearedFLASH->SR
, and monitoring the status register has helped me to find the real bug.
– berendi
Nov 9 at 8:22
I disagree, there is no attempt to program the flash memory at runtime in the question. It is an important consideration if you are programming flash at runtime (a practice that has particular issues in STM32 in any case), but it clearly does not relate to this question.
– Clifford
Nov 9 at 9:02
@Clifford I've tried it on actual hardware, see my updated answer. The flash controller does not really care what the programmer was attempting to do, it sets the flags on write accesses. Or raises a fault.
– berendi
Nov 11 at 13:35
|
show 1 more comment
The question appears to be about write access to a read-only address rather then more specifically about failure to write to flash memory because it is explicitly write-protected. Write protection is only relevant when programming flash; when not in programming mode, the access has no effect at all, unless the part has an MPU and the region is marked read-only. The title and code example refer toconst
rather then specifically flash memory an flash programming.
– Clifford
Nov 9 at 7:35
@Cliffordconst
arrays are placed in the flash by the linker, unless one uses some really weird linker script or startup code. If theconst
qualifier is lost when passing the array address to a function that expects a non-const pointer parameter, and attempts to write to an array element, then it will try to write a value to an address in flash. Of course the flash contents would be left unchanged, but the flash controller sees it as a failed programming attempt, and sets the error flag in its status register.
– berendi
Nov 9 at 7:55
@Clifford It has once got me wondering why my code that deliberately writes the flash stops working when a certain unrelated function is invoked. Turned out the unrelated function had the same kind of bug as the code example in the question. Flash programming started to work when I've clearedFLASH->SR
, and monitoring the status register has helped me to find the real bug.
– berendi
Nov 9 at 8:22
I disagree, there is no attempt to program the flash memory at runtime in the question. It is an important consideration if you are programming flash at runtime (a practice that has particular issues in STM32 in any case), but it clearly does not relate to this question.
– Clifford
Nov 9 at 9:02
@Clifford I've tried it on actual hardware, see my updated answer. The flash controller does not really care what the programmer was attempting to do, it sets the flags on write accesses. Or raises a fault.
– berendi
Nov 11 at 13:35
The question appears to be about write access to a read-only address rather then more specifically about failure to write to flash memory because it is explicitly write-protected. Write protection is only relevant when programming flash; when not in programming mode, the access has no effect at all, unless the part has an MPU and the region is marked read-only. The title and code example refer to
const
rather then specifically flash memory an flash programming.– Clifford
Nov 9 at 7:35
The question appears to be about write access to a read-only address rather then more specifically about failure to write to flash memory because it is explicitly write-protected. Write protection is only relevant when programming flash; when not in programming mode, the access has no effect at all, unless the part has an MPU and the region is marked read-only. The title and code example refer to
const
rather then specifically flash memory an flash programming.– Clifford
Nov 9 at 7:35
@Clifford
const
arrays are placed in the flash by the linker, unless one uses some really weird linker script or startup code. If the const
qualifier is lost when passing the array address to a function that expects a non-const pointer parameter, and attempts to write to an array element, then it will try to write a value to an address in flash. Of course the flash contents would be left unchanged, but the flash controller sees it as a failed programming attempt, and sets the error flag in its status register.– berendi
Nov 9 at 7:55
@Clifford
const
arrays are placed in the flash by the linker, unless one uses some really weird linker script or startup code. If the const
qualifier is lost when passing the array address to a function that expects a non-const pointer parameter, and attempts to write to an array element, then it will try to write a value to an address in flash. Of course the flash contents would be left unchanged, but the flash controller sees it as a failed programming attempt, and sets the error flag in its status register.– berendi
Nov 9 at 7:55
@Clifford It has once got me wondering why my code that deliberately writes the flash stops working when a certain unrelated function is invoked. Turned out the unrelated function had the same kind of bug as the code example in the question. Flash programming started to work when I've cleared
FLASH->SR
, and monitoring the status register has helped me to find the real bug.– berendi
Nov 9 at 8:22
@Clifford It has once got me wondering why my code that deliberately writes the flash stops working when a certain unrelated function is invoked. Turned out the unrelated function had the same kind of bug as the code example in the question. Flash programming started to work when I've cleared
FLASH->SR
, and monitoring the status register has helped me to find the real bug.– berendi
Nov 9 at 8:22
I disagree, there is no attempt to program the flash memory at runtime in the question. It is an important consideration if you are programming flash at runtime (a practice that has particular issues in STM32 in any case), but it clearly does not relate to this question.
– Clifford
Nov 9 at 9:02
I disagree, there is no attempt to program the flash memory at runtime in the question. It is an important consideration if you are programming flash at runtime (a practice that has particular issues in STM32 in any case), but it clearly does not relate to this question.
– Clifford
Nov 9 at 9:02
@Clifford I've tried it on actual hardware, see my updated answer. The flash controller does not really care what the programmer was attempting to do, it sets the flags on write accesses. Or raises a fault.
– berendi
Nov 11 at 13:35
@Clifford I've tried it on actual hardware, see my updated answer. The flash controller does not really care what the programmer was attempting to do, it sets the flags on write accesses. Or raises a fault.
– berendi
Nov 11 at 13:35
|
show 1 more comment
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53215281%2fis-it-safe-to-attempt-and-fail-to-write-to-a-const-on-an-stm32%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown