Browse Source

Revisions on Gareth's comments.

o Implemented byte writes to EEPROM now that the emulator has a
  byte-wide target write.
o Added comment describing the reason that mass erase doesn't work.
o Removed all unused code.
o Changed to Linux kernel indent style.
o Changed to Linux kernel function to parenthesis style.
o Stub generation doesn't use Perl, switched to sed.  Also, only
  including the instructions instead of the source and the instructions.
o Handling unaligned destination writes.
pull/75/head
Marc Singer 10 years ago
parent
commit
bf1cb71eb7
  1. 6
      flashstub/README
  2. 24
      flashstub/code-to-array.pl
  3. 11
      flashstub/dump-to-array.sh
  4. 80
      flashstub/stm32l05x-nvm-prog-erase.cc
  5. 226
      flashstub/stm32l05x-nvm-prog-erase.stub
  6. 105
      flashstub/stm32l05x-nvm-prog-write.cc
  7. 300
      flashstub/stm32l05x-nvm-prog-write.stub
  8. 246
      src/include/stm32lx-nvm.h
  9. 1624
      src/stm32l0.c

6
flashstub/README

@ -11,3 +11,9 @@ of half-words for inclusion in the target driver. The use of a higher
level language allows more detailed code and for easy revisions.
These stubs communicate with the driver through a structure defined in
the src/include/stm32l0-nvm.h header.
The dump-to-array.sh helper script uses sed to transform the output of
'objdump -d' into a half-word array of the instructions that may be
included in C code to declare the stub. FWIW, objcopy doesn't produce
the same output as objdump. It omits some of the instructions,
probably because the object file isn't linked.

24
flashstub/code-to-array.pl

@ -1,24 +0,0 @@
#!/usr/bin/perl
#
# Convert the output of objdump to an array of bytes are can include
# into our program.
while (<>) {
if (m/^\s*([0-9a-fA-F]+):\s*([0-9a-fA-F]+)(.*)/) {
my $addr = "0x$1";
my $value = $2;
if (length ($value) == 4) {
print " [$addr/2] = 0x$value, // $_";
}
else {
my $lsb = substr ($value, 4, 4);
my $msb = substr ($value, 0, 4);
print " [$addr/2] = 0x$lsb, // $_";
print " [$addr/2 + 1] = 0x$msb,\n";
}
}
else {
print "// ", $_;
}
}

11
flashstub/dump-to-array.sh

@ -0,0 +1,11 @@
#!/bin/sh
#
# Convert the output of objdump to an array of half-words that can be
# included into C code to represent the stub.
#
# Invoke with something like this:
#
# objdump -z -d FILE.o | dump-to-array.sh > FILE.stub
#
sed -E "/^[ ][ ]*[0-9a-fA-F]+:/!d; s/([0-9a-fA-F]+):[ \t]+([0-9a-fA-F]+).*/[0x\1\/2] = 0x\2,/ ; s/0x(....)(....),/0x\2, 0x\1,/"

80
flashstub/stm32l05x-nvm-prog-erase.cc

@ -42,52 +42,52 @@
/* Erase a region of flash. In the event that the erase is misaligned
with respect to pages, it will erase the pages that contain the
requested range of bytes. */
extern "C" void __attribute((naked)) stm32l05x_nvm_prog_erase () {
// Leave room for INFO at second word of routine
__asm volatile ("b 0f\n\t"
".align 2\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
"0:");
auto& nvm = Nvm (Info.nvm);
// Align to the start of the first page so that we make sure to erase
// all of the target pages.
auto remainder = reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size - 1);
Info.size += remainder;
Info.destination -= remainder/sizeof (*Info.destination);
if (!unlock (nvm))
goto quit;
nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
// Enable erasing
nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE;
if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
!= (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
goto quit;
while (Info.size > 0) {
*Info.destination = 0; // Initiate erase
Info.destination += Info.page_size/sizeof (*Info.destination);
Info.size -= Info.page_size;
}
extern "C" void __attribute((naked)) stm32l05x_nvm_prog_erase() {
// Leave room for INFO at second word of routine
__asm volatile ("b 0f\n\t"
".align 2\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
"0:");
auto& nvm = Nvm (Info.nvm);
// Align to the start of the first page so that we make sure to erase
// all of the target pages.
auto remainder = reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size - 1);
Info.size += remainder;
Info.destination -= remainder/sizeof (*Info.destination);
if (!unlock(nvm))
goto quit;
nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
// Enable erasing
nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE;
if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
!= (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
goto quit;
while (Info.size > 0) {
*Info.destination = 0; // Initiate erase
Info.destination += Info.page_size/sizeof (*Info.destination);
Info.size -= Info.page_size;
}
quit:
lock (nvm);
__asm volatile ("bkpt");
lock(nvm);
__asm volatile ("bkpt");
}
/*
Local Variables:
compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-erase.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-erase.lst stm32l05x-nvm-prog-erase.cc ; /opt/arm/arm-none-eabi-objdump -S stm32l05x-nvm-prog-erase.o | ./code-to-array.pl > stm32l05x-nvm-prog-erase.stub"
compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-erase.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-erase.lst stm32l05x-nvm-prog-erase.cc ; /opt/arm/arm-none-eabi-objdump -d -z stm32l05x-nvm-prog-erase.o | ./dump-to-array.sh > stm32l05x-nvm-prog-erase.stub"
End:
*/

226
flashstub/stm32l05x-nvm-prog-erase.stub

@ -1,159 +1,67 @@
//
// stm32l05x-nvm-prog-erase.o: file format elf32-littlearm
//
//
// Disassembly of section .text:
//
// 00000000 <stm32l05x_nvm_prog_erase>:
// ".word 0\n\t"
// ".word 0\n\t"
// ".word 0\n\t"
// ".word 0\n\t"
// ".word 0\n\t"
// "0:");
[0x0/2] = 0xe00a, // 0: e00a b.n 18 <stm32l05x_nvm_prog_erase+0x18>
[0x2/2] = 0x46c0, // 2: 46c0 nop ; (mov r8, r8)
// ...
//
// auto& nvm = Nvm (Info.nvm);
[0x18/2] = 0x491a, // 18: 491a ldr r1, [pc, #104] ; (84 <stm32l05x_nvm_prog_erase+0x84>)
//
// // Align to the start of the first page so that we make sure to erase
// // all of the target pages.
// auto remainder = reinterpret_cast<uint32_t> (Info.destination)
// & (Info.page_size - 1);
[0x1a/2] = 0x8a08, // 1a: 8a08 ldrh r0, [r1, #16]
[0x1c/2] = 0x680c, // 1c: 680c ldr r4, [r1, #0]
// Info.size += remainder;
[0x1e/2] = 0x684d, // 1e: 684d ldr r5, [r1, #4]
// auto& nvm = Nvm (Info.nvm);
//
// // Align to the start of the first page so that we make sure to erase
// // all of the target pages.
// auto remainder = reinterpret_cast<uint32_t> (Info.destination)
// & (Info.page_size - 1);
[0x20/2] = 0x1e42, // 20: 1e42 subs r2, r0, #1
[0x22/2] = 0x4022, // 22: 4022 ands r2, r4
// Info.size += remainder;
[0x24/2] = 0x1955, // 24: 1955 adds r5, r2, r5
// Info.destination -= remainder/sizeof (*Info.destination);
[0x26/2] = 0x0892, // 26: 0892 lsrs r2, r2, #2
[0x28/2] = 0x0092, // 28: 0092 lsls r2, r2, #2
[0x2a/2] = 0x1aa2, // 2a: 1aa2 subs r2, r4, r2
[0x2c/2] = 0x600a, // 2c: 600a str r2, [r1, #0]
// #define Nvm(nvm) (*reinterpret_cast<STM32::NVM*>(nvm))
// #define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS))
//
// namespace {
// inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) {
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; // Lock to guarantee unlock
[0x2e/2] = 0x2201, // 2e: 2201 movs r2, #1
// ".word 0\n\t"
// ".word 0\n\t"
// ".word 0\n\t"
// "0:");
//
// auto& nvm = Nvm (Info.nvm);
[0x30/2] = 0x68cb, // 30: 68cb ldr r3, [r1, #12]
//
// // Align to the start of the first page so that we make sure to erase
// // all of the target pages.
// auto remainder = reinterpret_cast<uint32_t> (Info.destination)
// & (Info.page_size - 1);
// Info.size += remainder;
[0x32/2] = 0x604d, // 32: 604d str r5, [r1, #4]
[0x34/2] = 0x605a, // 34: 605a str r2, [r3, #4]
// nvm.pkeyr = STM32::NVM::PKEY1;
[0x36/2] = 0x4a14, // 36: 4a14 ldr r2, [pc, #80] ; (88 <stm32l05x_nvm_prog_erase+0x88>)
[0x38/2] = 0x60da, // 38: 60da str r2, [r3, #12]
// nvm.pkeyr = STM32::NVM::PKEY2;
[0x3a/2] = 0x4a14, // 3a: 4a14 ldr r2, [pc, #80] ; (8c <stm32l05x_nvm_prog_erase+0x8c>)
[0x3c/2] = 0x60da, // 3c: 60da str r2, [r3, #12]
// nvm.prgkeyr = STM32::NVM::PRGKEY1;
[0x3e/2] = 0x4a14, // 3e: 4a14 ldr r2, [pc, #80] ; (90 <stm32l05x_nvm_prog_erase+0x90>)
[0x40/2] = 0x611a, // 40: 611a str r2, [r3, #16]
// nvm.prgkeyr = STM32::NVM::PRGKEY2;
[0x42/2] = 0x4a14, // 42: 4a14 ldr r2, [pc, #80] ; (94 <stm32l05x_nvm_prog_erase+0x94>)
[0x44/2] = 0x611a, // 44: 611a str r2, [r3, #16]
// return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK);
[0x46/2] = 0x685a, // 46: 685a ldr r2, [r3, #4]
// Info.destination -= remainder/sizeof (*Info.destination);
//
// if (!unlock (nvm))
[0x48/2] = 0x0792, // 48: 0792 lsls r2, r2, #30
[0x4a/2] = 0xd502, // 4a: d502 bpl.n 52 <stm32l05x_nvm_prog_erase+0x52>
// }
// inline __attribute((always_inline)) void lock (STM32::NVM& nvm) {
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; }
[0x4c/2] = 0x2201, // 4c: 2201 movs r2, #1
[0x4e/2] = 0x605a, // 4e: 605a str r2, [r3, #4]
// Info.size -= Info.page_size;
// }
//
// quit:
// lock (nvm);
// __asm volatile ("bkpt");
[0x50/2] = 0xbe00, // 50: be00 bkpt 0x0000
// Info.destination -= remainder/sizeof (*Info.destination);
//
// if (!unlock (nvm))
// goto quit;
//
// nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
[0x52/2] = 0x4a11, // 52: 4a11 ldr r2, [pc, #68] ; (98 <stm32l05x_nvm_prog_erase+0x98>)
[0x54/2] = 0x619a, // 54: 619a str r2, [r3, #24]
//
// // Enable erasing
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE;
[0x56/2] = 0x2282, // 56: 2282 movs r2, #130 ; 0x82
[0x58/2] = 0x0092, // 58: 0092 lsls r2, r2, #2
[0x5a/2] = 0x605a, // 5a: 605a str r2, [r3, #4]
// if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
[0x5c/2] = 0x685c, // 5c: 685c ldr r4, [r3, #4]
[0x5e/2] = 0x4014, // 5e: 4014 ands r4, r2
[0x60/2] = 0x4294, // 60: 4294 cmp r4, r2
[0x62/2] = 0xd1f3, // 62: d1f3 bne.n 4c <stm32l05x_nvm_prog_erase+0x4c>
// goto quit;
//
// while (Info.size > 0) {
// *Info.destination = 0; // Initiate erase
//
// Info.destination += Info.page_size/sizeof (*Info.destination);
[0x64/2] = 0x0884, // 64: 0884 lsrs r4, r0, #2
[0x66/2] = 0x00a4, // 66: 00a4 lsls r4, r4, #2
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE;
// if ((nvm.pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
// != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
// goto quit;
//
// while (Info.size > 0) {
[0x68/2] = 0x684d, // 68: 684d ldr r5, [r1, #4]
[0x6a/2] = 0x4a06, // 6a: 4a06 ldr r2, [pc, #24] ; (84 <stm32l05x_nvm_prog_erase+0x84>)
[0x6c/2] = 0x2d00, // 6c: 2d00 cmp r5, #0
[0x6e/2] = 0xdded, // 6e: dded ble.n 4c <stm32l05x_nvm_prog_erase+0x4c>
// *Info.destination = 0; // Initiate erase
[0x70/2] = 0x2600, // 70: 2600 movs r6, #0
[0x72/2] = 0x6815, // 72: 6815 ldr r5, [r2, #0]
[0x74/2] = 0x602e, // 74: 602e str r6, [r5, #0]
//
// Info.destination += Info.page_size/sizeof (*Info.destination);
[0x76/2] = 0x6815, // 76: 6815 ldr r5, [r2, #0]
[0x78/2] = 0x192d, // 78: 192d adds r5, r5, r4
[0x7a/2] = 0x6015, // 7a: 6015 str r5, [r2, #0]
// Info.size -= Info.page_size;
[0x7c/2] = 0x6855, // 7c: 6855 ldr r5, [r2, #4]
[0x7e/2] = 0x1a2d, // 7e: 1a2d subs r5, r5, r0
[0x80/2] = 0x6055, // 80: 6055 str r5, [r2, #4]
[0x82/2] = 0xe7f1, // 82: e7f1 b.n 68 <stm32l05x_nvm_prog_erase+0x68>
[0x84/2] = 0x0004, // 84: 20000004 .word 0x20000004
[0x84/2 + 1] = 0x2000,
[0x88/2] = 0xcdef, // 88: 89abcdef .word 0x89abcdef
[0x88/2 + 1] = 0x89ab,
[0x8c/2] = 0x0405, // 8c: 02030405 .word 0x02030405
[0x8c/2 + 1] = 0x0203,
[0x90/2] = 0xaebf, // 90: 8c9daebf .word 0x8c9daebf
[0x90/2 + 1] = 0x8c9d,
[0x94/2] = 0x1516, // 94: 13141516 .word 0x13141516
[0x94/2 + 1] = 0x1314,
[0x98/2] = 0x0700, // 98: 00010700 .word 0x00010700
[0x98/2 + 1] = 0x0001,
[0x0/2] = 0xe00a,
[0x2/2] = 0x46c0,
[0x4/2] = 0x0000, 0x0000,
[0x8/2] = 0x0000, 0x0000,
[0xc/2] = 0x0000, 0x0000,
[0x10/2] = 0x0000, 0x0000,
[0x14/2] = 0x0000, 0x0000,
[0x18/2] = 0x491a,
[0x1a/2] = 0x8a08,
[0x1c/2] = 0x680c,
[0x1e/2] = 0x684d,
[0x20/2] = 0x1e42,
[0x22/2] = 0x4022,
[0x24/2] = 0x1955,
[0x26/2] = 0x0892,
[0x28/2] = 0x0092,
[0x2a/2] = 0x1aa2,
[0x2c/2] = 0x600a,
[0x2e/2] = 0x2201,
[0x30/2] = 0x68cb,
[0x32/2] = 0x604d,
[0x34/2] = 0x605a,
[0x36/2] = 0x4a14,
[0x38/2] = 0x60da,
[0x3a/2] = 0x4a14,
[0x3c/2] = 0x60da,
[0x3e/2] = 0x4a14,
[0x40/2] = 0x611a,
[0x42/2] = 0x4a14,
[0x44/2] = 0x611a,
[0x46/2] = 0x685a,
[0x48/2] = 0x0792,
[0x4a/2] = 0xd502,
[0x4c/2] = 0x2201,
[0x4e/2] = 0x605a,
[0x50/2] = 0xbe00,
[0x52/2] = 0x4a11,
[0x54/2] = 0x619a,
[0x56/2] = 0x2282,
[0x58/2] = 0x0092,
[0x5a/2] = 0x605a,
[0x5c/2] = 0x685c,
[0x5e/2] = 0x4014,
[0x60/2] = 0x4294,
[0x62/2] = 0xd1f3,
[0x64/2] = 0x0884,
[0x66/2] = 0x00a4,
[0x68/2] = 0x684d,
[0x6a/2] = 0x4a06,
[0x6c/2] = 0x2d00,
[0x6e/2] = 0xdded,
[0x70/2] = 0x2600,
[0x72/2] = 0x6815,
[0x74/2] = 0x602e,
[0x76/2] = 0x6815,
[0x78/2] = 0x192d,
[0x7a/2] = 0x6015,
[0x7c/2] = 0x6855,
[0x7e/2] = 0x1a2d,
[0x80/2] = 0x6055,
[0x82/2] = 0xe7f1,
[0x84/2] = 0x0004, 0x2000,
[0x88/2] = 0xcdef, 0x89ab,
[0x8c/2] = 0x0405, 0x0203,
[0x90/2] = 0xaebf, 0x8c9d,
[0x94/2] = 0x1516, 0x1314,
[0x98/2] = 0x0700, 0x0001,

105
flashstub/stm32l05x-nvm-prog-write.cc

@ -43,70 +43,71 @@
/* Write a block of bytes to flash. The called is responsible for
making sure that the address are aligned and that the count is an
even multiple of words. */
extern "C" void __attribute((naked)) stm32l05x_nvm_prog_write () {
extern "C" void __attribute((naked)) stm32l05x_nvm_prog_write() {
// Leave room for INFO at second word of routine
__asm volatile ("b 0f\n\t"
".align 2\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
"0:");
__asm volatile ("b 0f\n\t"
".align 2\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
".word 0\n\t"
"0:");
auto& nvm = Nvm (Info.nvm);
auto& nvm = Nvm (Info.nvm);
if (!unlock (nvm))
goto quit;
if (!unlock(nvm))
goto quit;
nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
while (Info.size > 0) {
while (Info.size > 0) {
// Either we're not half-page aligned or we have less than a half
// page to write
if (Info.size < Info.page_size/2
|| (reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size/2 - 1))) {
nvm.pecr = (Info.options & OPT_STM32L1) ? 0
: STM32Lx_NVM_PECR_PROG; // Word programming
size_t c = Info.page_size/2
- (reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size/2 - 1));
if (c > Info.size)
c = Info.size;
Info.size -= c;
c /= 4;
while (c--) {
uint32_t v = *Info.source++;
*Info.destination++ = v;
if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
goto quit;
}
}
// Or we are writing a half-page(s)
else {
nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg
size_t c = Info.size & ~(Info.page_size/2 - 1);
Info.size -= c;
c /= 4;
while (c--) {
uint32_t v = *Info.source++;
*Info.destination++ = v;
}
if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
goto quit;
}
}
// Either we're not half-page aligned or we have less
// than a half page to write
if (Info.size < Info.page_size/2
|| (reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size/2 - 1))) {
nvm.pecr = (Info.options & OPT_STM32L1) ? 0
: STM32Lx_NVM_PECR_PROG; // Word programming
size_t c = Info.page_size/2
- (reinterpret_cast<uint32_t> (Info.destination)
& (Info.page_size/2 - 1));
if (c > Info.size)
c = Info.size;
Info.size -= c;
c /= 4;
while (c--) {
uint32_t v = *Info.source++;
*Info.destination++ = v;
if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
goto quit;
}
}
// Or we are writing a half-page(s)
else {
nvm.pecr = STM32Lx_NVM_PECR_PROG
| STM32Lx_NVM_PECR_FPRG; // Half-page prg
size_t c = Info.size & ~(Info.page_size/2 - 1);
Info.size -= c;
c /= 4;
while (c--) {
uint32_t v = *Info.source++;
*Info.destination++ = v;
}
if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
goto quit;
}
}
quit:
lock (nvm);
__asm volatile ("bkpt");
lock(nvm);
__asm volatile ("bkpt");
}
/*
Local Variables:
compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-write.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-write.lst stm32l05x-nvm-prog-write.cc ; /opt/arm/arm-none-eabi-objdump -S stm32l05x-nvm-prog-write.o | ./code-to-array.pl > stm32l05x-nvm-prog-write.stub"
compile-command: "/opt/arm/arm-none-eabi-g++ -mcpu=cortex-m0plus -g -c -std=c++11 -mthumb -o stm32l05x-nvm-prog-write.o -Os -Wa,-ahndl=stm32l05x-nvm-prog-write.lst stm32l05x-nvm-prog-write.cc ; /opt/arm/arm-none-eabi-objdump -d -z stm32l05x-nvm-prog-write.o | ./dump-to-array.sh > stm32l05x-nvm-prog-write.stub"
End:
*/

300
flashstub/stm32l05x-nvm-prog-write.stub

@ -1,201 +1,99 @@
//
// stm32l05x-nvm-prog-write.o: file format elf32-littlearm
//
//
// Disassembly of section .text:
//
// 00000000 <stm32l05x_nvm_prog_write>:
// ".word 0\n\t"
// ".word 0\n\t"
// ".word 0\n\t"
// ".word 0\n\t"
// ".word 0\n\t"
// "0:");
[0x0/2] = 0xe00a, // 0: e00a b.n 18 <stm32l05x_nvm_prog_write+0x18>
[0x2/2] = 0x46c0, // 2: 46c0 nop ; (mov r8, r8)
// ...
// #define Nvm(nvm) (*reinterpret_cast<STM32::NVM*>(nvm))
// #define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS))
//
// namespace {
// inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) {
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; // Lock to guarantee unlock
[0x18/2] = 0x2201, // 18: 2201 movs r2, #1
//
// auto& nvm = Nvm (Info.nvm);
[0x1a/2] = 0x4b2a, // 1a: 4b2a ldr r3, [pc, #168] ; (c4 <stm32l05x_nvm_prog_write+0xc4>)
[0x1c/2] = 0x68d9, // 1c: 68d9 ldr r1, [r3, #12]
[0x1e/2] = 0x604a, // 1e: 604a str r2, [r1, #4]
// nvm.pkeyr = STM32::NVM::PKEY1;
[0x20/2] = 0x4a29, // 20: 4a29 ldr r2, [pc, #164] ; (c8 <stm32l05x_nvm_prog_write+0xc8>)
[0x22/2] = 0x60ca, // 22: 60ca str r2, [r1, #12]
// nvm.pkeyr = STM32::NVM::PKEY2;
[0x24/2] = 0x4a29, // 24: 4a29 ldr r2, [pc, #164] ; (cc <stm32l05x_nvm_prog_write+0xcc>)
[0x26/2] = 0x60ca, // 26: 60ca str r2, [r1, #12]
// nvm.prgkeyr = STM32::NVM::PRGKEY1;
[0x28/2] = 0x4a29, // 28: 4a29 ldr r2, [pc, #164] ; (d0 <stm32l05x_nvm_prog_write+0xd0>)
[0x2a/2] = 0x610a, // 2a: 610a str r2, [r1, #16]
// nvm.prgkeyr = STM32::NVM::PRGKEY2;
[0x2c/2] = 0x4a29, // 2c: 4a29 ldr r2, [pc, #164] ; (d4 <stm32l05x_nvm_prog_write+0xd4>)
[0x2e/2] = 0x610a, // 2e: 610a str r2, [r1, #16]
// return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK);
[0x30/2] = 0x684a, // 30: 684a ldr r2, [r1, #4]
//
// if (!unlock (nvm))
[0x32/2] = 0x0792, // 32: 0792 lsls r2, r2, #30
[0x34/2] = 0xd502, // 34: d502 bpl.n 3c <stm32l05x_nvm_prog_write+0x3c>
// }
// inline __attribute((always_inline)) void lock (STM32::NVM& nvm) {
// nvm.pecr = STM32Lx_NVM_PECR_PELOCK; }
[0x36/2] = 0x2301, // 36: 2301 movs r3, #1
[0x38/2] = 0x604b, // 38: 604b str r3, [r1, #4]
// }
// }
//
// quit:
// lock (nvm);
// __asm volatile ("bkpt");
[0x3a/2] = 0xbe00, // 3a: be00 bkpt 0x0000
// auto& nvm = Nvm (Info.nvm);
//
// if (!unlock (nvm))
// goto quit;
//
// nvm.sr = STM32Lx_NVM_SR_ERR_M; // Clear errors
[0x3c/2] = 0x4826, // 3c: 4826 ldr r0, [pc, #152] ; (d8 <stm32l05x_nvm_prog_write+0xd8>)
[0x3e/2] = 0x6188, // 3e: 6188 str r0, [r1, #24]
//
// while (Info.size > 0) {
[0x40/2] = 0x685d, // 40: 685d ldr r5, [r3, #4]
[0x42/2] = 0x4e20, // 42: 4e20 ldr r6, [pc, #128] ; (c4 <stm32l05x_nvm_prog_write+0xc4>)
[0x44/2] = 0x2d00, // 44: 2d00 cmp r5, #0
[0x46/2] = 0xddf6, // 46: ddf6 ble.n 36 <stm32l05x_nvm_prog_write+0x36>
//
// // Either we're not half-page aligned or we have less than a half
// // page to write
// if (Info.size < Info.page_size/2
[0x48/2] = 0x8a32, // 48: 8a32 ldrh r2, [r6, #16]
[0x4a/2] = 0x0852, // 4a: 0852 lsrs r2, r2, #1
[0x4c/2] = 0x1e54, // 4c: 1e54 subs r4, r2, #1
[0x4e/2] = 0x4295, // 4e: 4295 cmp r5, r2
[0x50/2] = 0xdb02, // 50: db02 blt.n 58 <stm32l05x_nvm_prog_write+0x58>
// || (reinterpret_cast<uint32_t> (Info.destination)
[0x52/2] = 0x6837, // 52: 6837 ldr r7, [r6, #0]
[0x54/2] = 0x4227, // 54: 4227 tst r7, r4
[0x56/2] = 0xd01d, // 56: d01d beq.n 94 <stm32l05x_nvm_prog_write+0x94>
// & (Info.page_size/2 - 1))) {
// nvm.pecr = (Info.options & OPT_STM32L1) ? 0
// : STM32Lx_NVM_PECR_PROG; // Word programming
[0x58/2] = 0x2602, // 58: 2602 movs r6, #2
// // Either we're not half-page aligned or we have less than a half
// // page to write
// if (Info.size < Info.page_size/2
// || (reinterpret_cast<uint32_t> (Info.destination)
// & (Info.page_size/2 - 1))) {
// nvm.pecr = (Info.options & OPT_STM32L1) ? 0
[0x5a/2] = 0x8a5f, // 5a: 8a5f ldrh r7, [r3, #18]
// : STM32Lx_NVM_PECR_PROG; // Word programming
[0x5c/2] = 0x4037, // 5c: 4037 ands r7, r6
[0x5e/2] = 0x427e, // 5e: 427e negs r6, r7
[0x60/2] = 0x417e, // 60: 417e adcs r6, r7
[0x62/2] = 0x00f6, // 62: 00f6 lsls r6, r6, #3
[0x64/2] = 0x604e, // 64: 604e str r6, [r1, #4]
// size_t c = Info.page_size/2
// - (reinterpret_cast<uint32_t> (Info.destination)
// & (Info.page_size/2 - 1));
[0x66/2] = 0x681e, // 66: 681e ldr r6, [r3, #0]
[0x68/2] = 0x4034, // 68: 4034 ands r4, r6
[0x6a/2] = 0x1b12, // 6a: 1b12 subs r2, r2, r4
[0x6c/2] = 0x42aa, // 6c: 42aa cmp r2, r5
[0x6e/2] = 0xd900, // 6e: d900 bls.n 72 <stm32l05x_nvm_prog_write+0x72>
[0x70/2] = 0x1c2a, // 70: 1c2a adds r2, r5, #0
// if (c > Info.size)
// c = Info.size;
// Info.size -= c;
[0x72/2] = 0x1aad, // 72: 1aad subs r5, r5, r2
[0x74/2] = 0x605d, // 74: 605d str r5, [r3, #4]
// c /= 4;
[0x76/2] = 0x0892, // 76: 0892 lsrs r2, r2, #2
// while (c--) {
[0x78/2] = 0x3a01, // 78: 3a01 subs r2, #1
[0x7a/2] = 0xd3e1, // 7a: d3e1 bcc.n 40 <stm32l05x_nvm_prog_write+0x40>
// uint32_t v = *Info.source++;
[0x7c/2] = 0x689c, // 7c: 689c ldr r4, [r3, #8]
[0x7e/2] = 0x1d25, // 7e: 1d25 adds r5, r4, #4
[0x80/2] = 0x609d, // 80: 609d str r5, [r3, #8]
[0x82/2] = 0x6825, // 82: 6825 ldr r5, [r4, #0]
// *Info.destination++ = v;
[0x84/2] = 0x681c, // 84: 681c ldr r4, [r3, #0]
[0x86/2] = 0x1d26, // 86: 1d26 adds r6, r4, #4
[0x88/2] = 0x601e, // 88: 601e str r6, [r3, #0]
[0x8a/2] = 0x6025, // 8a: 6025 str r5, [r4, #0]
// if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
[0x8c/2] = 0x698c, // 8c: 698c ldr r4, [r1, #24]
[0x8e/2] = 0x4204, // 8e: 4204 tst r4, r0
[0x90/2] = 0xd0f2, // 90: d0f2 beq.n 78 <stm32l05x_nvm_prog_write+0x78>
[0x92/2] = 0xe7d0, // 92: e7d0 b.n 36 <stm32l05x_nvm_prog_write+0x36>
// goto quit;
// }
// }
// // Or we are writing a half-page(s)
// else {
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg
[0x94/2] = 0x2481, // 94: 2481 movs r4, #129 ; 0x81
// size_t c = Info.size & ~(Info.page_size/2 - 1);
[0x96/2] = 0x4252, // 96: 4252 negs r2, r2
[0x98/2] = 0x402a, // 98: 402a ands r2, r5
// Info.size -= c;
[0x9a/2] = 0x1aad, // 9a: 1aad subs r5, r5, r2
// goto quit;
// }
// }
// // Or we are writing a half-page(s)
// else {
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg
[0x9c/2] = 0x00e4, // 9c: 00e4 lsls r4, r4, #3
[0x9e/2] = 0x604c, // 9e: 604c str r4, [r1, #4]
// size_t c = Info.size & ~(Info.page_size/2 - 1);
// Info.size -= c;
// c /= 4;
[0xa0/2] = 0x0892, // a0: 0892 lsrs r2, r2, #2
// }
// // Or we are writing a half-page(s)
// else {
// nvm.pecr = STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG; // Half-page prg
// size_t c = Info.size & ~(Info.page_size/2 - 1);
// Info.size -= c;
[0xa2/2] = 0x6075, // a2: 6075 str r5, [r6, #4]
// c /= 4;
// while (c--) {
[0xa4/2] = 0x3a01, // a4: 3a01 subs r2, #1
[0xa6/2] = 0xd308, // a6: d308 bcc.n ba <stm32l05x_nvm_prog_write+0xba>
// uint32_t v = *Info.source++;
[0xa8/2] = 0x689c, // a8: 689c ldr r4, [r3, #8]
[0xaa/2] = 0x1d25, // aa: 1d25 adds r5, r4, #4
[0xac/2] = 0x609d, // ac: 609d str r5, [r3, #8]
[0xae/2] = 0x6825, // ae: 6825 ldr r5, [r4, #0]
// *Info.destination++ = v;
[0xb0/2] = 0x681c, // b0: 681c ldr r4, [r3, #0]
[0xb2/2] = 0x1d26, // b2: 1d26 adds r6, r4, #4
[0xb4/2] = 0x601e, // b4: 601e str r6, [r3, #0]
[0xb6/2] = 0x6025, // b6: 6025 str r5, [r4, #0]
[0xb8/2] = 0xe7f4, // b8: e7f4 b.n a4 <stm32l05x_nvm_prog_write+0xa4>
// }
// if (nvm.sr & STM32Lx_NVM_SR_ERR_M)
[0xba/2] = 0x698a, // ba: 698a ldr r2, [r1, #24]
[0xbc/2] = 0x4202, // bc: 4202 tst r2, r0
[0xbe/2] = 0xd0bf, // be: d0bf beq.n 40 <stm32l05x_nvm_prog_write+0x40>
[0xc0/2] = 0xe7b9, // c0: e7b9 b.n 36 <stm32l05x_nvm_prog_write+0x36>
[0xc2/2] = 0x46c0, // c2: 46c0 nop ; (mov r8, r8)
[0xc4/2] = 0x0004, // c4: 20000004 .word 0x20000004
[0xc4/2 + 1] = 0x2000,
[0xc8/2] = 0xcdef, // c8: 89abcdef .word 0x89abcdef
[0xc8/2 + 1] = 0x89ab,
[0xcc/2] = 0x0405, // cc: 02030405 .word 0x02030405
[0xcc/2 + 1] = 0x0203,
[0xd0/2] = 0xaebf, // d0: 8c9daebf .word 0x8c9daebf
[0xd0/2 + 1] = 0x8c9d,
[0xd4/2] = 0x1516, // d4: 13141516 .word 0x13141516
[0xd4/2 + 1] = 0x1314,
[0xd8/2] = 0x0700, // d8: 00010700 .word 0x00010700
[0xd8/2 + 1] = 0x0001,
[0x0/2] = 0xe00a,
[0x2/2] = 0x46c0,
[0x4/2] = 0x0000, 0x0000,
[0x8/2] = 0x0000, 0x0000,
[0xc/2] = 0x0000, 0x0000,
[0x10/2] = 0x0000, 0x0000,
[0x14/2] = 0x0000, 0x0000,
[0x18/2] = 0x2201,
[0x1a/2] = 0x4b2a,
[0x1c/2] = 0x68d9,
[0x1e/2] = 0x604a,
[0x20/2] = 0x4a29,
[0x22/2] = 0x60ca,
[0x24/2] = 0x4a29,
[0x26/2] = 0x60ca,
[0x28/2] = 0x4a29,
[0x2a/2] = 0x610a,
[0x2c/2] = 0x4a29,
[0x2e/2] = 0x610a,
[0x30/2] = 0x684a,
[0x32/2] = 0x0792,
[0x34/2] = 0xd502,
[0x36/2] = 0x2301,
[0x38/2] = 0x604b,
[0x3a/2] = 0xbe00,
[0x3c/2] = 0x4826,
[0x3e/2] = 0x6188,
[0x40/2] = 0x685d,
[0x42/2] = 0x4e20,
[0x44/2] = 0x2d00,
[0x46/2] = 0xddf6,
[0x48/2] = 0x8a32,
[0x4a/2] = 0x0852,
[0x4c/2] = 0x1e54,
[0x4e/2] = 0x4295,
[0x50/2] = 0xdb02,
[0x52/2] = 0x6837,
[0x54/2] = 0x4227,
[0x56/2] = 0xd01d,
[0x58/2] = 0x2602,
[0x5a/2] = 0x8a5f,
[0x5c/2] = 0x4037,
[0x5e/2] = 0x427e,
[0x60/2] = 0x417e,
[0x62/2] = 0x00f6,
[0x64/2] = 0x604e,
[0x66/2] = 0x681e,
[0x68/2] = 0x4034,
[0x6a/2] = 0x1b12,
[0x6c/2] = 0x42aa,
[0x6e/2] = 0xd900,
[0x70/2] = 0x1c2a,
[0x72/2] = 0x1aad,
[0x74/2] = 0x605d,
[0x76/2] = 0x0892,
[0x78/2] = 0x3a01,
[0x7a/2] = 0xd3e1,
[0x7c/2] = 0x689c,
[0x7e/2] = 0x1d25,
[0x80/2] = 0x609d,
[0x82/2] = 0x6825,
[0x84/2] = 0x681c,
[0x86/2] = 0x1d26,
[0x88/2] = 0x601e,
[0x8a/2] = 0x6025,
[0x8c/2] = 0x698c,
[0x8e/2] = 0x4204,
[0x90/2] = 0xd0f2,
[0x92/2] = 0xe7d0,
[0x94/2] = 0x2481,
[0x96/2] = 0x4252,
[0x98/2] = 0x402a,
[0x9a/2] = 0x1aad,
[0x9c/2] = 0x00e4,
[0x9e/2] = 0x604c,
[0xa0/2] = 0x0892,
[0xa2/2] = 0x6075,
[0xa4/2] = 0x3a01,
[0xa6/2] = 0xd308,
[0xa8/2] = 0x689c,
[0xaa/2] = 0x1d25,
[0xac/2] = 0x609d,
[0xae/2] = 0x6825,
[0xb0/2] = 0x681c,
[0xb2/2] = 0x1d26,
[0xb4/2] = 0x601e,
[0xb6/2] = 0x6025,
[0xb8/2] = 0xe7f4,
[0xba/2] = 0x698a,
[0xbc/2] = 0x4202,
[0xbe/2] = 0xd0bf,
[0xc0/2] = 0xe7b9,
[0xc2/2] = 0x46c0,
[0xc4/2] = 0x0004, 0x2000,
[0xc8/2] = 0xcdef, 0x89ab,
[0xcc/2] = 0x0405, 0x0203,
[0xd0/2] = 0xaebf, 0x8c9d,
[0xd4/2] = 0x1516, 0x1314,
[0xd8/2] = 0x0700, 0x0001,

246
src/include/stm32lx-nvm.h

@ -31,108 +31,108 @@
/* ----- Types */
enum {
STM32Lx_STUB_PHYS = 0x20000000ul,
STM32Lx_STUB_INFO_PHYS = 0x20000004ul,
STM32Lx_STUB_DATA_PHYS = (0x20000000ul + 1024),
STM32Lx_STUB_DATA_MAX = 2048,
STM32Lx_NVM_OPT_PHYS = 0x1ff80000ul,
STM32Lx_NVM_EEPROM_PHYS = 0x08080000ul,
STM32L0_NVM_PHYS = 0x40022000ul,
STM32L0_NVM_PROG_PAGE_SIZE = 128,
STM32L0_NVM_DATA_PAGE_SIZE = 4,
STM32L0_NVM_OPT_SIZE = 12,
STM32L0_NVM_EEPROM_SIZE = 2*1024,
STM32L1_NVM_PHYS = 0x40023c00ul,
STM32L1_NVM_PROG_PAGE_SIZE = 256,
STM32L1_NVM_DATA_PAGE_SIZE = 4,
STM32L1_NVM_OPT_SIZE = 32,
STM32L1_NVM_EEPROM_SIZE = 16*1024,
STM32Lx_NVM_PEKEY1 = 0x89abcdeful,
STM32Lx_NVM_PEKEY2 = 0x02030405ul,
STM32Lx_NVM_PRGKEY1 = 0x8c9daebful,
STM32Lx_NVM_PRGKEY2 = 0x13141516ul,
STM32Lx_NVM_OPTKEY1 = 0xfbead9c8ul,
STM32Lx_NVM_OPTKEY2 = 0x24252627ul,
STM32Lx_NVM_PECR_OBL_LAUNCH = (1<<18),
STM32Lx_NVM_PECR_ERRIE = (1<<17),
STM32Lx_NVM_PECR_EOPIE = (1<<16),
STM32Lx_NVM_PECR_FPRG = (1<<10),
STM32Lx_NVM_PECR_ERASE = (1<< 9),
STM32Lx_NVM_PECR_FIX = (1<< 8), /* FTDW */
STM32Lx_NVM_PECR_DATA = (1<< 4),
STM32Lx_NVM_PECR_PROG = (1<< 3),
STM32Lx_NVM_PECR_OPTLOCK = (1<< 2),
STM32Lx_NVM_PECR_PRGLOCK = (1<< 1),
STM32Lx_NVM_PECR_PELOCK = (1<< 0),
STM32Lx_NVM_SR_FWWERR = (1<<17),
STM32Lx_NVM_SR_NOTZEROERR = (1<<16),
STM32Lx_NVM_SR_RDERR = (1<<13),
STM32Lx_NVM_SR_OPTVER = (1<<11),
STM32Lx_NVM_SR_SIZERR = (1<<10),
STM32Lx_NVM_SR_PGAERR = (1<<9),
STM32Lx_NVM_SR_WRPERR = (1<<8),
STM32Lx_NVM_SR_READY = (1<<3),
STM32Lx_NVM_SR_HWOFF = (1<<2),
STM32Lx_NVM_SR_EOP = (1<<1),
STM32Lx_NVM_SR_BSY = (1<<0),
STM32Lx_NVM_SR_ERR_M = ( STM32Lx_NVM_SR_WRPERR
| STM32Lx_NVM_SR_PGAERR
| STM32Lx_NVM_SR_SIZERR
| STM32Lx_NVM_SR_NOTZEROERR),
STM32L0_NVM_OPTR_BOOT1 = (1<<31),
STM32L0_NVM_OPTR_WDG_SW = (1<<20),
STM32L0_NVM_OPTR_WPRMOD = (1<<8),
STM32L0_NVM_OPTR_RDPROT_S = (0),
STM32L0_NVM_OPTR_RDPROT_M = (0xff),
STM32L0_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L0_NVM_OPTR_RDPROT_2 = (0xcc),
STM32L1_NVM_OPTR_nBFB2 = (1<<23),
STM32L1_NVM_OPTR_nRST_STDBY = (1<<22),
STM32L1_NVM_OPTR_nRST_STOP = (1<<21),
STM32L1_NVM_OPTR_WDG_SW = (1<<20),
STM32L1_NVM_OPTR_BOR_LEV_S = (16),
STM32L1_NVM_OPTR_BOR_LEV_M = (0xf),
STM32L1_NVM_OPTR_SPRMOD = (1<<8),
STM32L1_NVM_OPTR_RDPROT_S = (0),
STM32L1_NVM_OPTR_RDPROT_M = (0xff),
STM32L1_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L1_NVM_OPTR_RDPROT_2 = (0xcc),
STM32Lx_STUB_PHYS = 0x20000000ul,
STM32Lx_STUB_INFO_PHYS = 0x20000004ul,
STM32Lx_STUB_DATA_PHYS = (0x20000000ul + 1024),
STM32Lx_STUB_DATA_MAX = 2048,
STM32Lx_NVM_OPT_PHYS = 0x1ff80000ul,
STM32Lx_NVM_EEPROM_PHYS = 0x08080000ul,
STM32L0_NVM_PHYS = 0x40022000ul,
STM32L0_NVM_PROG_PAGE_SIZE = 128,
STM32L0_NVM_DATA_PAGE_SIZE = 4,
STM32L0_NVM_OPT_SIZE = 12,
STM32L0_NVM_EEPROM_SIZE = 2*1024,
STM32L1_NVM_PHYS = 0x40023c00ul,
STM32L1_NVM_PROG_PAGE_SIZE = 256,
STM32L1_NVM_DATA_PAGE_SIZE = 4,
STM32L1_NVM_OPT_SIZE = 32,
STM32L1_NVM_EEPROM_SIZE = 16*1024,
STM32Lx_NVM_PEKEY1 = 0x89abcdeful,
STM32Lx_NVM_PEKEY2 = 0x02030405ul,
STM32Lx_NVM_PRGKEY1 = 0x8c9daebful,
STM32Lx_NVM_PRGKEY2 = 0x13141516ul,
STM32Lx_NVM_OPTKEY1 = 0xfbead9c8ul,
STM32Lx_NVM_OPTKEY2 = 0x24252627ul,
STM32Lx_NVM_PECR_OBL_LAUNCH = (1<<18),
STM32Lx_NVM_PECR_ERRIE = (1<<17),
STM32Lx_NVM_PECR_EOPIE = (1<<16),
STM32Lx_NVM_PECR_FPRG = (1<<10),
STM32Lx_NVM_PECR_ERASE = (1<< 9),
STM32Lx_NVM_PECR_FIX = (1<< 8), /* FTDW */
STM32Lx_NVM_PECR_DATA = (1<< 4),
STM32Lx_NVM_PECR_PROG = (1<< 3),
STM32Lx_NVM_PECR_OPTLOCK = (1<< 2),
STM32Lx_NVM_PECR_PRGLOCK = (1<< 1),
STM32Lx_NVM_PECR_PELOCK = (1<< 0),
STM32Lx_NVM_SR_FWWERR = (1<<17),
STM32Lx_NVM_SR_NOTZEROERR = (1<<16),
STM32Lx_NVM_SR_RDERR = (1<<13),
STM32Lx_NVM_SR_OPTVER = (1<<11),
STM32Lx_NVM_SR_SIZERR = (1<<10),
STM32Lx_NVM_SR_PGAERR = (1<<9),
STM32Lx_NVM_SR_WRPERR = (1<<8),
STM32Lx_NVM_SR_READY = (1<<3),
STM32Lx_NVM_SR_HWOFF = (1<<2),
STM32Lx_NVM_SR_EOP = (1<<1),
STM32Lx_NVM_SR_BSY = (1<<0),
STM32Lx_NVM_SR_ERR_M = ( STM32Lx_NVM_SR_WRPERR
| STM32Lx_NVM_SR_PGAERR
| STM32Lx_NVM_SR_SIZERR
| STM32Lx_NVM_SR_NOTZEROERR),
STM32L0_NVM_OPTR_BOOT1 = (1<<31),
STM32L0_NVM_OPTR_WDG_SW = (1<<20),
STM32L0_NVM_OPTR_WPRMOD = (1<<8),
STM32L0_NVM_OPTR_RDPROT_S = (0),
STM32L0_NVM_OPTR_RDPROT_M = (0xff),
STM32L0_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L0_NVM_OPTR_RDPROT_2 = (0xcc),
STM32L1_NVM_OPTR_nBFB2 = (1<<23),
STM32L1_NVM_OPTR_nRST_STDBY = (1<<22),
STM32L1_NVM_OPTR_nRST_STOP = (1<<21),
STM32L1_NVM_OPTR_WDG_SW = (1<<20),
STM32L1_NVM_OPTR_BOR_LEV_S = (16),
STM32L1_NVM_OPTR_BOR_LEV_M = (0xf),
STM32L1_NVM_OPTR_SPRMOD = (1<<8),
STM32L1_NVM_OPTR_RDPROT_S = (0),
STM32L1_NVM_OPTR_RDPROT_M = (0xff),
STM32L1_NVM_OPTR_RDPROT_0 = (0xaa),
STM32L1_NVM_OPTR_RDPROT_2 = (0xcc),
};
#if defined (__cplusplus)
namespace STM32 {
struct NVM {
volatile uint32_t acr;
volatile uint32_t pecr;
volatile uint32_t pdkeyr;
volatile uint32_t pkeyr;
volatile uint32_t prgkeyr;
volatile uint32_t optkeyr;
volatile uint32_t sr;
volatile uint32_t optr;
volatile uint32_t wrprot;
static constexpr uint32_t PKEY1 = 0x89abcdef;
static constexpr uint32_t PKEY2 = 0x02030405;
static constexpr uint32_t PRGKEY1 = 0x8c9daebf;
static constexpr uint32_t PRGKEY2 = 0x13141516;
static constexpr uint32_t OPTKEY1 = 0xfbead9c8;
static constexpr uint32_t OPTKEY2 = 0x24252627;
static constexpr uint32_t PDKEY1 = 0x04152637;
static constexpr uint32_t PDKEY2 = 0xfafbfcfd;
};
static_assert(sizeof (NVM) == 9*4, "NVM size error");
struct NVM {
volatile uint32_t acr;
volatile uint32_t pecr;
volatile uint32_t pdkeyr;
volatile uint32_t pkeyr;
volatile uint32_t prgkeyr;
volatile uint32_t optkeyr;
volatile uint32_t sr;
volatile uint32_t optr;
volatile uint32_t wrprot;
static constexpr uint32_t PKEY1 = 0x89abcdef;
static constexpr uint32_t PKEY2 = 0x02030405;
static constexpr uint32_t PRGKEY1 = 0x8c9daebf;
static constexpr uint32_t PRGKEY2 = 0x13141516;
static constexpr uint32_t OPTKEY1 = 0xfbead9c8;
static constexpr uint32_t OPTKEY2 = 0x24252627;
static constexpr uint32_t PDKEY1 = 0x04152637;
static constexpr uint32_t PDKEY2 = 0xfafbfcfd;
};
static_assert(sizeof (NVM) == 9*4, "NVM size error");
}
using stm32lx_stub_pointer_t = uint32_t*;
@ -140,16 +140,18 @@ using stm32lx_stub_pointer_t = uint32_t*;
#define Info (*reinterpret_cast<stm32lx_nvm_stub_info*>(STM32Lx_STUB_INFO_PHYS))
namespace {
inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) {
nvm.pecr = STM32Lx_NVM_PECR_PELOCK; // Lock to guarantee unlock
nvm.pkeyr = STM32::NVM::PKEY1;
nvm.pkeyr = STM32::NVM::PKEY2;
nvm.prgkeyr = STM32::NVM::PRGKEY1;
nvm.prgkeyr = STM32::NVM::PRGKEY2;
return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK);
}
inline __attribute((always_inline)) void lock (STM32::NVM& nvm) {
nvm.pecr = STM32Lx_NVM_PECR_PELOCK; }
inline __attribute((always_inline)) bool unlock (STM32::NVM& nvm) {
// Lock guarantees unlock
nvm.pecr = STM32Lx_NVM_PECR_PELOCK;
nvm.pkeyr = STM32::NVM::PKEY1;
nvm.pkeyr = STM32::NVM::PKEY2;
nvm.prgkeyr = STM32::NVM::PRGKEY1;
nvm.prgkeyr = STM32::NVM::PRGKEY2;
return !(nvm.pecr & STM32Lx_NVM_PECR_PRGLOCK);
}
inline __attribute((always_inline)) void lock (STM32::NVM& nvm) {
nvm.pecr = STM32Lx_NVM_PECR_PELOCK; }
}
@ -158,15 +160,15 @@ namespace {
typedef uint32_t stm32lx_stub_pointer_t;
struct stm32lx_nvm {
volatile uint32_t acr;
volatile uint32_t pecr;
volatile uint32_t pdkeyr;
volatile uint32_t pekeyr;
volatile uint32_t prgkeyr;
volatile uint32_t optkeyr;
volatile uint32_t sr;
volatile uint32_t optr; /* or obr */
volatile uint32_t wrprot; /* or wprot1 */
volatile uint32_t acr;
volatile uint32_t pecr;
volatile uint32_t pdkeyr;
volatile uint32_t pekeyr;
volatile uint32_t prgkeyr;
volatile uint32_t optkeyr;
volatile uint32_t sr;
volatile uint32_t optr; /* or obr */
volatile uint32_t wrprot; /* or wprot1 */
};
#define STM32Lx_NVM(p) (*(struct stm32lx_nvm*) (p))
@ -180,16 +182,16 @@ struct stm32lx_nvm {
#endif
enum {
OPT_STM32L1 = 1<<1,
OPT_STM32L1 = 1<<1,
};
struct stm32lx_nvm_stub_info {
stm32lx_stub_pointer_t destination;
int32_t size;
stm32lx_stub_pointer_t source;
uint32_t nvm;
uint16_t page_size;
uint16_t options;
stm32lx_stub_pointer_t destination;
int32_t size;
stm32lx_stub_pointer_t source;
uint32_t nvm;
uint16_t page_size;
uint16_t options;
} __attribute__((packed));
/* ----- Globals */

1624
src/stm32l0.c

File diff suppressed because it is too large
Loading…
Cancel
Save