Merge pull request #98 from UweBonnes/stm32l4
Add STM32L4 handling. No option write handling yet.
This commit is contained in:
commit
7e5a664df9
|
@ -11,7 +11,7 @@ endif
|
|||
CFLAGS=-Os -std=gnu99 -mcpu=cortex-m0 -mthumb -I../libopencm3/include
|
||||
ASFLAGS=-mcpu=cortex-m3 -mthumb
|
||||
|
||||
all: lmi.stub stm32f4.stub nrf51.stub stm32f1.stub
|
||||
all: lmi.stub stm32f4.stub stm32l4.stub nrf51.stub stm32f1.stub
|
||||
|
||||
stm32f1.o: stm32f1.c
|
||||
$(Q)echo " CC $<"
|
||||
|
@ -21,6 +21,10 @@ stm32f4.o: stm32f4.c
|
|||
$(Q)echo " CC $<"
|
||||
$(Q)$(CC) $(CFLAGS) -DSTM32F4 -o $@ -c $<
|
||||
|
||||
stm32l4.o: stm32l4.c
|
||||
$(Q)echo " CC $<"
|
||||
$(Q)$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
%.o: %.s
|
||||
$(Q)echo " AS $<"
|
||||
$(Q)$(AS) $(ASFLAGS) -o $@ $<
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2015 Black Sphere Technologies Ltd.
|
||||
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "stub.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* No STM32L4 definitions in libopencm3 yet */
|
||||
#define FLASH_SR ((volatile uint32_t *) 0x40022010)
|
||||
#define FLASH_SR_EOP (1 << 0)
|
||||
#define SR_ERROR_MASK 0xC3FA
|
||||
#define FLASH_SR_BSY (1 << 16)
|
||||
|
||||
#define FLASH_CR ((volatile uint32_t *) 0x40022014)
|
||||
#define FLASH_CR_PG (1 << 0)
|
||||
#define FLASH_CR_EOPIE (1 << 24)
|
||||
#define FLASH_CR_ERRIE (1 << 25)
|
||||
#define FLASH_SR_EOP (1 << 0)
|
||||
|
||||
void __attribute__((naked))
|
||||
stm32l4_flash_write_stub(uint32_t *dest, uint32_t *src, uint32_t size)
|
||||
{
|
||||
if ((size & 7) || ((uint32_t)dest & 7))
|
||||
stub_exit(1);
|
||||
for (int i = 0; i < size; i += 8) {
|
||||
*FLASH_CR = FLASH_CR_EOPIE | FLASH_CR_ERRIE | FLASH_CR_PG;
|
||||
*dest++ = *src++;
|
||||
*dest++ = *src++;
|
||||
__asm("dsb");
|
||||
while (*FLASH_SR & FLASH_SR_BSY)
|
||||
;
|
||||
if ((*FLASH_SR & SR_ERROR_MASK) || !(*FLASH_SR & FLASH_SR_EOP))
|
||||
stub_exit(1);
|
||||
*FLASH_SR |= FLASH_SR_EOP;
|
||||
}
|
||||
*FLASH_CR = 0;
|
||||
stub_exit(0);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
0x1C04, 0x4314, 0x2300, 0x0764, 0xD011, 0xBE01, 0xE00F, 0x4C11, 0x6825, 0x03ED, 0xD4FB, 0x6826, 0x4D0F, 0x422E, 0xD115, 0x6825, 0x07ED, 0xD512, 0x2601, 0x6825, 0x3308, 0x4335, 0x6025, 0x4C0B, 0x4293, 0xD20C, 0x4D0A, 0x6025, 0x58CC, 0x50C4, 0x18CC, 0x6865, 0x18C4, 0x6065, 0xF3BF, 0x8F4F, 0xE7E1, 0xBE01, 0xE7EA, 0x2300, 0x6023, 0xBE00, 0x2010, 0x4002, 0xC3FA, 0x0000, 0x2014, 0x4002, 0x0001, 0x0300,
|
|
@ -41,6 +41,7 @@ SRC = \
|
|||
stm32f1.c \
|
||||
stm32f4.c \
|
||||
stm32l0.c \
|
||||
stm32l4.c \
|
||||
swdptap.c \
|
||||
target.c \
|
||||
|
||||
|
|
|
@ -243,6 +243,7 @@ bool cortexm_probe(target *t)
|
|||
PROBE(stm32f1_probe);
|
||||
PROBE(stm32f4_probe);
|
||||
PROBE(stm32l0_probe); /* STM32L0xx & STM32L1xx */
|
||||
PROBE(stm32l4_probe);
|
||||
PROBE(lpc11xx_probe);
|
||||
PROBE(lpc43xx_probe);
|
||||
PROBE(sam3x_probe);
|
||||
|
|
|
@ -263,6 +263,7 @@ bool stm32f1_probe(target *t);
|
|||
bool stm32f4_probe(target *t);
|
||||
bool stm32l0_probe(target *t);
|
||||
bool stm32l1_probe(target *t);
|
||||
bool stm32l4_probe(target *t);
|
||||
bool lmi_probe(target *t);
|
||||
bool lpc11xx_probe(target *t);
|
||||
bool lpc43xx_probe(target *t);
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* This file is part of the Black Magic Debug project.
|
||||
*
|
||||
* Copyright (C) 2015 Uwe Bonnes
|
||||
* Written by Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file implements STM32L4 target specific functions for detecting
|
||||
* the device, providing the XML memory map and Flash memory programming.
|
||||
*
|
||||
* On L4, flash and options are written in DWORDs (8-Byte) only.
|
||||
*
|
||||
* Refereces:
|
||||
* ST doc - RM0351
|
||||
* Reference manual
|
||||
* STM32L4x6 advanced ARM®-based 32-bit MCUs
|
||||
*
|
||||
*/
|
||||
|
||||
#include "general.h"
|
||||
#include "adiv5.h"
|
||||
#include "target.h"
|
||||
#include "cortexm.h"
|
||||
#include "command.h"
|
||||
#include "gdb_packet.h"
|
||||
|
||||
static bool stm32l4_cmd_erase_mass(target *t);
|
||||
static bool stm32l4_cmd_erase_bank1(target *t);
|
||||
static bool stm32l4_cmd_erase_bank2(target *t);
|
||||
static bool stm32l4_cmd_option(target *t, int argc, char *argv[]);
|
||||
|
||||
const struct command_s stm32l4_cmd_list[] = {
|
||||
{"erase_mass", (cmd_handler)stm32l4_cmd_erase_mass, "Erase entire flash memory"},
|
||||
{"erase_bank1", (cmd_handler)stm32l4_cmd_erase_bank1, "Erase entire bank1 flash memory"},
|
||||
{"erase_bank2", (cmd_handler)stm32l4_cmd_erase_bank2, "Erase entire bank2 flash memory"},
|
||||
{"option", (cmd_handler)stm32l4_cmd_option, "Manipulate option bytes"},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len);
|
||||
static int stm32l4_flash_write(struct target_flash *f,
|
||||
uint32_t dest, const void *src, size_t len);
|
||||
|
||||
static const char stm32l4_driver_str[] = "STM32L4xx";
|
||||
|
||||
#define PAGE_SIZE 0x800
|
||||
/* Flash Program ad Erase Controller Register Map */
|
||||
#define FPEC_BASE 0x40022000
|
||||
#define FLASH_ACR (FPEC_BASE+0x00)
|
||||
#define FLASH_KEYR (FPEC_BASE+0x08)
|
||||
#define FLASH_OPTKEYR (FPEC_BASE+0x0c)
|
||||
#define FLASH_SR (FPEC_BASE+0x10)
|
||||
#define FLASH_CR (FPEC_BASE+0x14)
|
||||
#define FLASH_OPTR (FPEC_BASE+0x20)
|
||||
//#define FLASH_OPTCR (FPEC_BASE+0x14)
|
||||
|
||||
#define FLASH_CR_PG (1 << 0)
|
||||
#define FLASH_CR_PER (1 << 1)
|
||||
#define FLASH_CR_MER1 (1 << 2)
|
||||
#define FLASH_CR_PAGE_SHIFT 3
|
||||
#define FLASH_CR_BKER (1 << 11)
|
||||
#define FLASH_CR_MER2 (1 << 15)
|
||||
#define FLASH_CR_STRT (1 << 16)
|
||||
#define FLASH_CR_OPTSTRT (1 << 17)
|
||||
#define FLASH_CR_FSTPG (1 << 18)
|
||||
#define FLASH_CR_EOPIE (1 << 24)
|
||||
#define FLASH_CR_ERRIE (1 << 25)
|
||||
#define FLASH_CR_OPTLOCK (1 << 30)
|
||||
#define FLASH_CR_LOCK (1 << 31)
|
||||
|
||||
#define FLASH_SR_EOP (1 << 0)
|
||||
#define FLASH_SR_OPERR (1 << 1)
|
||||
#define FLASH_SR_PROGERR (1 << 3)
|
||||
#define FLASH_SR_WRPERR (1 << 4)
|
||||
#define FLASH_SR_PGAERR (1 << 5)
|
||||
#define FLASH_SR_SIZERR (1 << 6)
|
||||
#define FLASH_SR_PGSERR (1 << 7)
|
||||
#define FLASH_SR_MSERR (1 << 8)
|
||||
#define FLASH_SR_FASTERR (1 << 9)
|
||||
#define FLASH_SR_RDERR (1 << 14)
|
||||
#define FLASH_SR_OPTVERR (1 << 15)
|
||||
#define FLASH_SR_ERROR_MASK 0xC3FA
|
||||
#define FLASH_SR_BSY (1 << 16)
|
||||
|
||||
#define KEY1 0x45670123
|
||||
#define KEY2 0xCDEF89AB
|
||||
|
||||
#define OPTKEY1 0x08192A3B
|
||||
#define OPTKEY2 0x4C5D6E7F
|
||||
|
||||
#define SR_ERROR_MASK 0xF2
|
||||
|
||||
#define OR_DUALBANK (1 << 21)
|
||||
|
||||
#define DBGMCU_IDCODE 0xE0042000
|
||||
#define FLASH_SIZE_REG 0x1FFF75E0
|
||||
#define FLASH_SIZE_REG 0x1FFF75E0
|
||||
|
||||
/* This routine is uses double word access.*/
|
||||
static const uint16_t stm32l4_flash_write_stub[] = {
|
||||
#include "../flashstub/stm32l4.stub"
|
||||
};
|
||||
|
||||
#define SRAM_BASE 0x20000000
|
||||
#define STUB_BUFFER_BASE ALIGN(SRAM_BASE + sizeof(stm32l4_flash_write_stub), 8)
|
||||
|
||||
struct stm32l4_flash {
|
||||
struct target_flash f;
|
||||
uint32_t bank1_start;
|
||||
};
|
||||
|
||||
static void stm32l4_add_flash(target *t,
|
||||
uint32_t addr, size_t length, size_t blocksize,
|
||||
uint32_t bank1_start)
|
||||
{
|
||||
struct stm32l4_flash *sf = calloc(1, sizeof(*sf));
|
||||
struct target_flash *f = &sf->f;
|
||||
f->start = addr;
|
||||
f->length = length;
|
||||
f->blocksize = blocksize;
|
||||
f->erase = stm32l4_flash_erase;
|
||||
f->write = stm32l4_flash_write;
|
||||
f->align = 8;
|
||||
f->erased = 0xff;
|
||||
sf->bank1_start = bank1_start;
|
||||
target_add_flash(t, f);
|
||||
}
|
||||
|
||||
bool stm32l4_probe(target *t)
|
||||
{
|
||||
uint32_t idcode;
|
||||
uint32_t size;
|
||||
uint32_t options;
|
||||
uint32_t bank1_start = 0x08040000;
|
||||
|
||||
idcode = target_mem_read32(t, DBGMCU_IDCODE);
|
||||
switch(idcode & 0xFFF) {
|
||||
case 0x415: /* */
|
||||
t->driver = stm32l4_driver_str;
|
||||
target_add_ram(t, 0x10000000, 1 << 15);
|
||||
target_add_ram(t, 0x20000000, 3 << 15);
|
||||
size = (target_mem_read32(t, FLASH_SIZE_REG) & 0xffff);
|
||||
options = target_mem_read32(t, FLASH_OPTR);
|
||||
if ((size < 0x400) && (options & OR_DUALBANK))
|
||||
bank1_start = 0x08000000 + (size << 9);
|
||||
stm32l4_add_flash(t, 0x08000000, size << 10, PAGE_SIZE, bank1_start);
|
||||
target_add_commands(t, stm32l4_cmd_list, "STM32L4");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void stm32l4_flash_unlock(target *t)
|
||||
{
|
||||
if (target_mem_read32(t, FLASH_CR) & FLASH_CR_LOCK) {
|
||||
/* Enable FPEC controller access */
|
||||
target_mem_write32(t, FLASH_KEYR, KEY1);
|
||||
target_mem_write32(t, FLASH_KEYR, KEY2);
|
||||
}
|
||||
}
|
||||
|
||||
static int stm32l4_flash_erase(struct target_flash *f, uint32_t addr, size_t len)
|
||||
{
|
||||
target *t = f->t;
|
||||
uint16_t sr;
|
||||
uint32_t bank1_start = ((struct stm32l4_flash *)f)->bank1_start;
|
||||
uint32_t page;
|
||||
|
||||
stm32l4_flash_unlock(t);
|
||||
|
||||
page = (addr - 0x08000000) / PAGE_SIZE;
|
||||
while(len) {
|
||||
uint32_t cr;
|
||||
|
||||
cr = FLASH_CR_PER | (page << FLASH_CR_PAGE_SHIFT );
|
||||
if (addr >= bank1_start)
|
||||
cr |= FLASH_CR_BKER;
|
||||
/* Flash page erase instruction */
|
||||
target_mem_write32(t, FLASH_CR, cr);
|
||||
/* write address to FMA */
|
||||
cr |= FLASH_CR_STRT;
|
||||
target_mem_write32(t, FLASH_CR, cr);
|
||||
|
||||
/* Read FLASH_SR to poll for BSY bit */
|
||||
while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
|
||||
if(target_check_error(t))
|
||||
return -1;
|
||||
|
||||
len -= PAGE_SIZE;
|
||||
addr += PAGE_SIZE;
|
||||
page++;
|
||||
}
|
||||
|
||||
/* Check for error */
|
||||
sr = target_mem_read32(t, FLASH_SR);
|
||||
if(sr & FLASH_SR_ERROR_MASK)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32l4_flash_write(struct target_flash *f,
|
||||
uint32_t dest, const void *src, size_t len)
|
||||
{
|
||||
/* Write buffer to target ram call stub */
|
||||
target_mem_write(f->t, SRAM_BASE, stm32l4_flash_write_stub,
|
||||
sizeof(stm32l4_flash_write_stub));
|
||||
target_mem_write(f->t, STUB_BUFFER_BASE, src, len);
|
||||
return cortexm_run_stub(f->t, SRAM_BASE, dest,
|
||||
STUB_BUFFER_BASE, len, 0);
|
||||
}
|
||||
|
||||
static bool stm32l4_cmd_erase(target *t, uint32_t action)
|
||||
{
|
||||
const char spinner[] = "|/-\\";
|
||||
int spinindex = 0;
|
||||
|
||||
gdb_out("Erasing flash... This may take a few seconds. ");
|
||||
stm32l4_flash_unlock(t);
|
||||
|
||||
/* Flash erase action start instruction */
|
||||
target_mem_write32(t, FLASH_CR, action);
|
||||
target_mem_write32(t, FLASH_CR, action | FLASH_CR_STRT);
|
||||
|
||||
/* Read FLASH_SR to poll for BSY bit */
|
||||
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) {
|
||||
gdb_outf("\b%c", spinner[spinindex++ % 4]);
|
||||
if(target_check_error(t)) {
|
||||
gdb_out("\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
gdb_out("\n");
|
||||
|
||||
/* Check for error */
|
||||
uint16_t sr = target_mem_read32(t, FLASH_SR);
|
||||
if (sr & FLASH_SR_ERROR_MASK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool stm32l4_cmd_erase_mass(target *t)
|
||||
{
|
||||
return stm32l4_cmd_erase(t, FLASH_CR_MER1 | FLASH_CR_MER2);
|
||||
}
|
||||
|
||||
static bool stm32l4_cmd_erase_bank1(target *t)
|
||||
{
|
||||
return stm32l4_cmd_erase(t, FLASH_CR_MER1);
|
||||
}
|
||||
|
||||
static bool stm32l4_cmd_erase_bank2(target *t)
|
||||
{
|
||||
return stm32l4_cmd_erase(t, FLASH_CR_MER2);
|
||||
}
|
||||
|
||||
static bool stm32l4_cmd_option(target *t, int argc, char *argv[])
|
||||
{
|
||||
uint32_t addr, val;
|
||||
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
for (int i = 0; i < 0x23; i += 8) {
|
||||
addr = 0x1fff7800 + i;
|
||||
val = target_mem_read32(t, addr);
|
||||
gdb_outf("0x%08X: 0x%08x\n", addr, val);
|
||||
}
|
||||
for (int i = 8; i < 0x23; i += 8) {
|
||||
addr = 0x1ffff800 + i;
|
||||
val = target_mem_read32(t, addr);
|
||||
gdb_outf("0x%08X: 0x%08X\n", addr, val);
|
||||
}
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue