Arm Can';t擦除samd21微控制器闪存的第一页

Arm Can';t擦除samd21微控制器闪存的第一页,arm,embedded,microcontroller,cortex-m,Arm,Embedded,Microcontroller,Cortex M,我用的是一个皮质m0+核心的。要引导加载一个新程序,我想删除地址0x0000 0000处的向量表,并在那里写入新数据。我遇到了两个问题: 在地址0上执行擦除操作似乎不会实际擦除任何内容 当我试图写入地址0 我将尝试更改的地址,看看这是否对我有帮助(编辑:没有帮助)。除此之外,是否有人知道: 有一种方法可以告诉微控制器“嘿,我知道我在做什么,让我戳一下这个地址” 写入地址0时的硬故障是Cortex m0+规范中定义的(我找不到任何东西),还是实现定义的行为 编辑 我的引导加载程序位于ma

我用的是一个皮质m0+核心的。要引导加载一个新程序,我想删除地址
0x0000 0000
处的向量表,并在那里写入新数据。我遇到了两个问题:

  • 在地址
    0
    上执行擦除操作似乎不会实际擦除任何内容
  • 当我试图写入地址
    0
我将尝试更改的地址,看看这是否对我有帮助(编辑:没有帮助)。除此之外,是否有人知道:

  • 有一种方法可以告诉微控制器“嘿,我知道我在做什么,让我戳一下这个地址”
  • 写入地址
    0
    时的硬故障是Cortex m0+规范中定义的(我找不到任何东西),还是实现定义的行为
编辑


我的引导加载程序位于
max\u flash-0x1000
。我意识到这可能不是最好的方法,所以我可能会更改一些东西,使引导加载程序(具有自己的向量表)位于
0x0000
。我仍然想知道为什么我不能写地址
0x0000
。cortex m0+文档中没有任何内容表明我不能这么做

我已经检查了以下事项:

  • 我的中断被禁用了吗?(它们是,在我开始戳内存之前,我有一个
    \uuasm\uuuuuuuuuuvolatile(“cpsid if”);
  • 更改
    VTOR
    的值是否会产生差异?(事实并非如此)
  • 我要删除的flash页面是否被锁定?(它不是,
    BOOTPROT
    =7。)
  • 登记册中是否有被列为锁定的区域?(它们不是,
    LOCK
    =
    0xffff
  • 它是否从试图擦除的页面执行?(不,反向跟踪显示在硬故障发生之前,
    pc
    =
    0xf1dc
还有什么需要检查的吗?

不幸的是,阿特梅尔(不能把这归咎于微芯片,这是在它们被同化之前发生的)离开了他们的内置SAM-BA引导程序。取而代之的是,他们提供了一个软件/源代码版本,你可以放置自己和一些额外的控件来保护空间,但没有保护,因此程序解锁、擦除或破坏都是微不足道的。因此,最好是只制作自己的引导程序,一个更简单的nd更易于维护(尽量不要删除),或者使用SWD接口,这是竞争产品上唯一需要的解决方案,如果不是替代方案的话。我最终选择了后者

我发现,不仅很容易擦除和写入该空间,而且非常容易,一旦解锁了一些魔法,你就可以有意或无意地对该空间进行简单存储,以垃圾/覆盖

我将发布我的代码,不管是接受还是放弃,我已经有一段时间没有读过数据表了,而不是今天,我想知道你应该搜索BOOTPROT来查看那些保护位,以及要更改什么寄存器来禁用该保护(如果它甚至打开的话)

put和get只是存储和加载指令抽象

//------------------------------------------------------------------------
//------------------------------------------------------------------------

#include "flash-bin.h"

void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void PUT16 ( unsigned int, unsigned int );
unsigned int GET16 ( unsigned int );
void PUT8 ( unsigned int, unsigned int );
unsigned int GET8 ( unsigned int );
void dummy ( unsigned int );

#define PORT_BASE 0x41004400

#define PORTA_DIRSET (PORT_BASE+0x00+0x08)
#define PORTA_OUTCLR (PORT_BASE+0x00+0x14)
#define PORTA_OUTSET (PORT_BASE+0x00+0x18)
#define PORTA_OUTTGL (PORT_BASE+0x00+0x1C)

#define PORTB_DIRSET (PORT_BASE+0x80+0x08)
#define PORTB_OUTCLR (PORT_BASE+0x80+0x14)
#define PORTB_OUTSET (PORT_BASE+0x80+0x18)
#define PORTB_OUTTGL (PORT_BASE+0x80+0x1C)

#define PORTA_PMUX05    (PORT_BASE+0x00+0x30+5)
#define PORTA_PINCFG10  (PORT_BASE+0x00+0x40+10)
#define PORTA_PINCFG11  (PORT_BASE+0x00+0x40+11)

#define PORTB_PMUX01    (PORT_BASE+0x80+0x30+1)
#define PORTB_PMUX11    (PORT_BASE+0x80+0x30+11)
#define PORTB_PINCFG03  (PORT_BASE+0x80+0x40+3)
#define PORTB_PINCFG22  (PORT_BASE+0x80+0x40+22)
#define PORTB_PINCFG23  (PORT_BASE+0x80+0x40+23)

#define GCLK_BASE       0x40000C00
#define GCLK_CTRL       (GCLK_BASE+0x00)
#define GCLK_STATUS     (GCLK_BASE+0x01)
#define GCLK_CLKCTRL    (GCLK_BASE+0x02)
#define GCLK_GENCTRL    (GCLK_BASE+0x04)
#define GCLK_GENDIV     (GCLK_BASE+0x08)

#define PM_BASE         0x40000400
#define APBCMASK        (PM_BASE+0x20)

#define SYSCTRL_BASE    0x40000800
#define OSC8M           (SYSCTRL_BASE+0x20)

#define SERCOM5_BASE        0x42001C00
#define SERCOM5_CTRLA       (SERCOM5_BASE+0x00)
#define SERCOM5_CTRLB       (SERCOM5_BASE+0x04)
#define SERCOM5_BAUD        (SERCOM5_BASE+0x0C)
#define SERCOM5_INTFLAG     (SERCOM5_BASE+0x18)
#define SERCOM5_SYNCBUSY    (SERCOM5_BASE+0x1C)
#define SERCOM5_DATA        (SERCOM5_BASE+0x28)

#define SERCOM0_BASE        0x42000800
#define SERCOM0_CTRLA       (SERCOM0_BASE+0x00)
#define SERCOM0_CTRLB       (SERCOM0_BASE+0x04)
#define SERCOM0_BAUD        (SERCOM0_BASE+0x0C)
#define SERCOM0_INTFLAG     (SERCOM0_BASE+0x18)
#define SERCOM0_SYNCBUSY    (SERCOM0_BASE+0x1C)
#define SERCOM0_DATA        (SERCOM0_BASE+0x28)

#define STK_CSR 0xE000E010
#define STK_RVR 0xE000E014
#define STK_CVR 0xE000E018
#define STK_MASK 0x00FFFFFF

#define ACTLR 0xE000E008
#define CPUID 0xE000ED00

#define NVMCTRL_BASE 0x41004000
#define NVM_CTRLA   (NVMCTRL_BASE+0x00)
#define NVM_CTRLB   (NVMCTRL_BASE+0x04)
#define NVM_PARAM   (NVMCTRL_BASE+0x08)
#define NVM_INTFLAG (NVMCTRL_BASE+0x14)
#define NVM_STATUS  (NVMCTRL_BASE+0x18)
#define NVM_ADDR    (NVMCTRL_BASE+0x1C)
#define NVM_LOCK    (NVMCTRL_BASE+0x20)

//------------------------------------------------------------------------
static void clock_init ( void )
{
    unsigned int ra;

    ra=GET32(OSC8M);
    ra&=~(3<<8);
    PUT32(OSC8M,ra);
}
//------------------------------------------------------------------------
#ifdef USE_SERCOM0
//TX PA10  SERCOM0 PAD[2] FUNCTION C  SERCOM2 PAD[2]  FUNCTION D
//RX PA11  SERCOM0 PAD[3] FUNCTION C  SERCOM2 PAD[3]  FUNCTION D
//------------------------------------------------------------------------
static void uart_init ( void )
{
    unsigned int ra;

    ra=GET32(APBCMASK);
    ra|=1<<2; //enable SERCOM0
    PUT32(APBCMASK,ra);

    PUT32(GCLK_GENCTRL,0x00010605);

    PUT16(GCLK_CLKCTRL,0x4514);

    PUT8(PORTA_PINCFG10,0x01);
    PUT8(PORTA_PINCFG11,0x01);
    PUT8(PORTA_PMUX05,0x22);

    while(GET32(SERCOM0_SYNCBUSY)) continue;
    PUT32(SERCOM0_CTRLA,0x00000000);
    while(GET32(SERCOM0_SYNCBUSY)) continue;
    PUT32(SERCOM0_CTRLA,0x00000001);
    while(GET32(SERCOM0_SYNCBUSY)) continue;
    PUT32(SERCOM0_CTRLA,0x40310004);
    while(GET32(SERCOM0_SYNCBUSY)) continue;
    PUT32(SERCOM0_CTRLB,0x00030000);
    while(GET32(SERCOM0_SYNCBUSY)) continue;
    PUT16(SERCOM0_BAUD,50436);
    while(GET32(SERCOM0_SYNCBUSY)) continue;
    PUT32(SERCOM0_CTRLA,0x40310006);
    while(GET32(SERCOM0_SYNCBUSY)) continue;
}
//------------------------------------------------------------------------
//static void uart_flush ( void )
//{
    //while(1)
    //{
        //if(GET8(SERCOM0_INTFLAG)&2) break;
    //}
//}
//------------------------------------------------------------------------
static void uart_send ( unsigned int d )
{
    while(1)
    {
        if(GET8(SERCOM0_INTFLAG)&1) break;
    }
    PUT8(SERCOM0_DATA,d&0xFF);
}
//------------------------------------------------------------------------
//static unsigned int uart_recv ( void )
//{
    //while(1)
    //{
        //if(GET8(SERCOM0_INTFLAG)&4) break;
    //}
    //return(GET8(SERCOM0_DATA)&0xFF);
//}
//------------------------------------------------------------------------
#else
//TX PB22   SERCOM5 PAD[2] PORT FUNCTION D
//RX PB23   SERCOM5 PAD[3] PORT FUNCTION D
//------------------------------------------------------------------------
static void uart_init ( void )
{
    unsigned int ra;

    ra=GET32(APBCMASK);
    ra|=1<<7; //enable SERCOM5
    ra|=1<<2; //enable SERCOM0
    PUT32(APBCMASK,ra);

    PUT32(GCLK_GENCTRL,0x00010605);

    PUT16(GCLK_CLKCTRL,0x4519);

    PUT8(PORTB_PINCFG22,0x01);
    PUT8(PORTB_PINCFG23,0x01);
    PUT8(PORTB_PMUX11,0x33);

    while(GET32(SERCOM5_SYNCBUSY)) continue;
    PUT32(SERCOM5_CTRLA,0x00000000);
    while(GET32(SERCOM5_SYNCBUSY)) continue;
    PUT32(SERCOM5_CTRLA,0x00000001);
    while(GET32(SERCOM5_SYNCBUSY)) continue;
    PUT32(SERCOM5_CTRLA,0x40310004);
    while(GET32(SERCOM5_SYNCBUSY)) continue;
    PUT32(SERCOM5_CTRLB,0x00030000);
    while(GET32(SERCOM5_SYNCBUSY)) continue;
    PUT16(SERCOM5_BAUD,50436);
    while(GET32(SERCOM5_SYNCBUSY)) continue;
    PUT32(SERCOM5_CTRLA,0x40310006);
    while(GET32(SERCOM5_SYNCBUSY)) continue;
}
//------------------------------------------------------------------------
//static void uart_flush ( void )
//{
    //while(1)
    //{
        //if(GET8(SERCOM5_INTFLAG)&2) break;
    //}
//}
//------------------------------------------------------------------------
static void uart_send ( unsigned int d )
{
    while(1)
    {
        if(GET8(SERCOM5_INTFLAG)&1) break;
    }
    PUT8(SERCOM5_DATA,d&0xFF);
}
//------------------------------------------------------------------------
//static unsigned int uart_recv ( void )
//{
    //while(1)
    //{
        //if(GET8(SERCOM5_INTFLAG)&4) break;
    //}
    //return(GET8(SERCOM5_DATA)&0xFF);
//}
//------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------
static void hexstrings ( unsigned int d )
{
    //unsigned int ra;
    unsigned int rb;
    unsigned int rc;

    rb=32;
    while(1)
    {
        rb-=4;
        rc=(d>>rb)&0xF;
        if(rc>9) rc+=0x37; else rc+=0x30;
        uart_send(rc);
        if(rb==0) break;
    }
    uart_send(0x20);
}
//------------------------------------------------------------------------
static void hexstring ( unsigned int d )
{
    hexstrings(d);
    uart_send(0x0D);
    uart_send(0x0A);
}
//------------------------------------------------------------------------
static void flash_busy ( void )
{
    while(1)
    {
        if(GET8(NVM_INTFLAG)&(1<<0)) break;
    }
}
//------------------------------------------------------------------------
static void flash_command ( unsigned int cmd )
{
    PUT16(NVM_CTRLA,0xA500+cmd);
    flash_busy();
}
//------------------------------------------------------------------------
#define FLASH_ER 0x02
#define FLASH_WP 0x04
#define FLASH_UR 0x41
#define FLASH_PBC 0x44
#define FLASH_INVALL 0x46
//------------------------------------------------------------------------
int notmain ( void )
{
    unsigned int ra;
    unsigned int addr;
    unsigned int page_size;
    unsigned int row_size;
    unsigned int pages;
    unsigned int rows;


    clock_init();
    uart_init();
    hexstring(0x12345678);
    hexstring(GET32(ACTLR));
    hexstring(GET32(CPUID));
    hexstring(GET32(NVM_PARAM));
    ra=GET32(NVM_PARAM);
    pages=ra&0xFFFF;
    page_size=(ra>>16)&7;
    page_size=8<<page_size;
    row_size=page_size<<2;
    rows=pages>>2;
    hexstring(pages);
    hexstring(page_size);
    hexstring(rows);
    hexstring(row_size);

    flash_busy();
    flash_command(FLASH_INVALL); //where do you use this if at all?
    for(addr=0x0000;addr<0x8000;addr+=0x100)
    {
        hexstrings(addr); hexstring(GET8(NVM_INTFLAG));
        PUT32(NVM_ADDR,addr);
        flash_command(FLASH_UR); //unlock
        flash_command(FLASH_ER); //erase row
    }

    for(ra=0x0000;ra<0x0040;ra+=4)
    {
        hexstrings(ra); hexstring(GET32(ra));
    }

if(1)
{
    flash_command(FLASH_INVALL); //where do you use this if at all?
    flash_command(FLASH_PBC); //page buffer clear
    for(addr=0x0000,ra=0;ra<(0x800>>2);ra++,addr+=4)
    {
        if((addr&0x3F)==0) hexstring(addr);
        PUT32(addr,rom[ra]);
        if((addr&0x3F)==0x3C) flash_busy();
    }
    for(ra=0x0000;ra<0x0040;ra+=4)
    {
        hexstrings(ra); hexstring(GET32(ra));
    }
}

    return(0);
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
sram.ld

MEMORY
{
    ram : ORIGIN = 0x20000000, LENGTH = 0xD00
}

SECTIONS
{
    .text : { *(.text*) } > ram
    .rodata : { *(.rodata*) } > ram
    .bss : { *(.bss*) } > ram
}

你的引导加载器/闪存编程代码驻留在哪个内存中?你读过关于这个特定部分的引导加载器的应用说明吗?@Lundin我没有读过应用说明,因为我没有使用Atmel的引导加载器,我能找到的唯一一个应用说明是关于使用Atmel自己的引导加载器。我编辑了我的评论以澄清发生了什么g继续。我不记得在SAMD上具体怎么做了,但作为所有MCU的经验法则,从您正在编程的同一个flash页面执行代码通常不起作用。也许可以从RWW页面执行代码。希望手册会提到这些事情,您必须阅读第21章的所有肮脏细节。@Lundin感谢您的建议,但在我的情况下,我正在从address ~
0xf000
执行操作,同时尝试擦除
0x0000
。我最初的想法与此类似:“当然,我无法擦除向量表,因为故障可能需要向量表才能执行其业务”,但是更改
VTOR
的值从而使
0x0000
处的向量表无效没有帮助;仍然会生成错误。我已经为这个特定的MCU编写了一个引导加载程序,尽管已经有一段时间了,我不记得具体细节。除了驻留在那里的向量表之外,地址0没有什么神奇之处。你知道吗必须禁用所有中断。但是,即使手册中没有提到这一点,从您试图擦除的同一页运行代码的问题也很可能是真实的。要做的第一件事是将代码重新定位到另一个闪存段。我很快会尝试这一点,但似乎NVMCTRL寄存器与我的代码没有任何不同是的。你能把你的答案添加到PUT32/GET32函数的定义中吗?我99.9%肯定我能猜出它的作用,但我只是想确定一下。也许你的锁在某种程度上与我的锁不同。我很确定我的锁是/曾经是sparkfun的samd21断接板。我试图进入amazon dash按钮samd21,但没有。我没有确定对于写保护问题,如果我没记错的话,我无法让SWD连接,这可能是我弄乱的唯一两个samd2x芯片。
MEMORY
{
    ram : ORIGIN = 0x20000000, LENGTH = 0xD00
}

SECTIONS
{
    .text : { *(.text*) } > ram
    .rodata : { *(.rodata*) } > ram
    .bss : { *(.bss*) } > ram
}