作者归档:softsim

AT91SAM7S MCU点亮LED灯

初始化并行输入输出(PIO)控制器

  1. PMC(电源管理控制器)打开 外围时钟. 如果要将IO引脚配置为输出,起始连时钟都可以不打开。如果配置为输入或者要求中断的化,时钟还是必须打开的
  2. 在 AIC里配置 中断源 (可选操作)
  3. 将对应的PIO引脚,配置为输出(output)
    (1) 往PER(PIO Enable Register)寄存器里写入对应的管脚号。
    (2) PIO的方向是由 OER(Output Enable Register)和ODR(Output Disable Regiser)两个寄存器控制的。
  4.  控制引脚电平的高低:通过写 PIO_SODR ( 置位输出数据寄存器 ) 与 PIO_CODR ( 清零输出数据寄存器 ),可将 I/O 改为电平驱动。写操作对 PIO_ODSR ( 输出数据状态寄存器 ) 分别置位与清零,表示在 I/O 线上的数据驱动。

注意,在每个PIO引脚,都有个独立的内部上拉电阻. 这些上拉电阻默认都是启用的。因为它们在点亮LED上没有用。所以,应该被关掉,以减少电量消耗。可以通过PUDR(Pull Up Disable Register)来关掉。

#include "AT91SAM7S256.h"

#define LED_A (1U<<0) // PA0, pin 48
#define LED_B (1U<<1) // PA1, pin 47

/* Configure the pins as outputs */
AT91C_BASE_PIOA->PIO_OER = (LED_A | LED_B);

/* Enable PIOC control on the pins*/
AT91C_BASE_PIOA->PIO_PER = (LED_A | LED_B);

/* Disable pull-ups */
AT91C_BASE_PIOA->PIO_PPUDR = (LED_A | LED_B);

/* Turn LED on, high level */
AT91C_BASE_PIOA->PIO_SODR = LED_A;

/* Turn LED off, low level */
AT91C_BASE_PIOA->PIO_CODR = LED_A;

ST32微控制器GPIO功能描述

每个GPI/O端口有

两个32位配置寄存器(GPIOx_CRL,GPIOx_CRH),

两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR),

一个32位置位/复位寄存器(GPIOx_BSRR),

一个16位复位寄存器(GPIOx_BRR)

一个32位锁定寄存器(GPIOx_LCKR)。

每个I/O端口位可以自由编程,然而必须按照32位字访问I/O端口寄存器(不允许半字或字节访
问)。GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器进行读/更改的独立访问;这
样,在读和更改访问之间产生IRQ时不会发生危险。

几种配置GPIO的分析

RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //开启 GPIO端口 C 的时钟

GPIOC->CRH=0x33333333; //将 8-15号 GPIO配置成:输出模式,速度50MHz

GPIOC->ODR ^= (1 << 13) // 13号 GPIO输出 高电平


// I/O port C clock enable
RCC->APB2ENR = RCC_APB2ENR_IOPCEN;
// Set PC_12 to output
GPIOC->CRH &= ~(GPIO_CRH_MODE12 | GPIO_CRH_CNF12);
GPIOC->CRH |= GPIO_CRH_MODE12;

while(1)
{
GPIOC->BSRR = (1<<12);
delay();
GPIOC->BRR = (1<<12);
delay();
}


// Enable GPIO port clock
RCC -> APB2ENR |= RCC_APB2ENR_IOPAEN;
// Configure the pins using CRL/CRH GPIO registers
#define GPIO_OUTPUT_2MHz (0b10)
#define GPIO_OUTPUT_PUSH_PULL (0 << 2)
GPIOA -> CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
GPIOA -> CRL |= GPIO_OUTPUT_2MHz | GPIO_OUTPUT_PUSH_PULL;

// Manipulate the output

/* to toggle */
GPIOA -> ODR ^= (1 << pinNummer);

/* to set */
GPIOA -> BSRR = (1 << pinNummer);

/* to reset */
GPIOA -> BRR = (1 << pinNummer);
//or
GPIOA -> BSRR = (1 << (pinNummer + 16));


RCC->APB2ENR |= 0x10; //enable GPIOC clock
GPIOC->CRH = (GPIOC->CRH & 0xFF0FFFF) | 0x00100000; //PC13 output pull-push, 10MHz speed

GPIOC-> BSRR = 0x00002000; //pc13=1, leave others unchanged
GPIOC->BSRR = 0x20000000; //pc13=0, 其他不变
GPIOC->BSRR = 0x20002000; //pc13=1, 其他不变,设置时,忽略清除

GPIOC->BRR = 0x2000; //pc13=0, 其他不变
GPIOC->ODR = 0x00002000; //pc13=1,并且其他所有都设置为0
GPIOC->ODR |= 0x00002000; //pc13=1, 其他不变
GPIOC->ODR = 0x00000000; //pc13=0, 其他位也强制为0
GPIOC->ODR &= ~0x00002000; //pc12=0, 其他位不变


RCC->APB2ENR |= RCC_APB2ENR_IOPCEN //enable APB2_clock GPIOC
GPIOC->CRH |= GPIO_CRH_MODE13_1 //PC13 output
GPIOC->CRH &= ~GPIO_CRH_CNF13 //PC13 push pull


RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;

GPIOC->CRH &= ~GPIO_CRH_CNF13;
GPIOC->CRH |= GPIO_CRH_MODE13_0;

GPIOC->BSRR = GPIO_BSRR_BR13;
sleep(1);
GPIOC->BSRR = GPIO_BSRR_BS13;


RCC->APB2ENR |=
GPIOC->CRH &= ~GPIO_CRH_CNF13;

GPIOC->CRH |= GPIO_CRH_MODE13_0; //set C13 as a general purporse push-pull output

GPIOC->BSRR |= GPIO_BSRR_BR13; // set C13 0

soft_delay(5000000);

GPIOC->BSRR |= GPIO_BSRR_BS13;


// I/O port C clock enable
RCC->APB2ENR = RCC_APB2ENR_IOPCEN;

// Set PC_13 to output
GPIOC->CRH &= ~GPIO_CRH_CNF13;
GPIOC->CRH |= GPIO_CRH_MODE13_0;

while(1)
{
GPIOC->BSRR = GPIO_BSRR_BS13; // LED off
delay(500);

GPIOC->BRR = GPIO_BRR_BR13; // LED on
delay(500);
}

揭开微控制器GPIO设置的神秘面纱

原文 https://embeddedartistry.com/blog/2018/06/04/demystifying-microcontroller-gpio-settings/ 为微控制器编写软件的任何人都必须配置和管理GPIO(通用输入/输出)引脚。从表面上看,GPIO配置看起来很简单:引脚是输入或输出,并且可以为高或低。 但是,不可避免地,您会遇到带有众多配置选项的高档处理器,或者电气工程师会要求您做某种您不了解的引脚设置(比如,使这条线为Hi-Z)。 本指南旨在帮助您了解现代微控制器上提供的不同引脚配置选项。

背景资料

在深入探讨配置选项之前,了解一些与GPIO和IO信号相关的一般描述和术语会很有用。

三态逻辑

大多数现代GPIO线都实现为三态缓冲器。这意味着GPIO线可以有效地采用三个值:
  1. 逻辑0(接地)
  2. 逻辑1(连接到VCC)
  3. 高阻抗(也称为“浮动/悬空”,“ Hi-Z”,“三态”)

高阻抗

当线路处于高阻抗状态时,输出将从电路中有效移除。这允许多个电路或设备共享相同的输出线,并且通常用于实现通信总线。必要时未能利用高阻抗状态会导致IO争用和短路。

浮动/悬空

当信号的状态不确定时,则称该信号为“浮动”,这意味着该信号既未连接至VCC也不接地。信号的电压将“浮动”以匹配残余电压。 术语“浮动”通常 可以同 高阻抗状态 互换使用。

上拉

上拉电阻是将信号连接到VCC的电阻。当信号浮空时,上拉电阻用于设置默认状态。 回想一下,当输入引脚处于高阻抗模式且不受外部电源驱动时,它会浮在残余电压电平上。上拉电阻通过在信号未被主动驱动时将信号强制施加到VCC来防止引脚浮动。当另一个源将信号驱动为低电平(接地)时,上拉电阻被覆盖,输入引脚将读为0。 许多微控制器提供内部上拉配置选项。有时,需要一个特定的上拉电阻值,这需要使用外部上拉而不是芯片的内部上拉。

下拉

下拉电阻是将信号接地的电阻。下拉信号用于在信号浮动时设置默认状态。当另一个信号源将信号驱动为高电平(连接到VCC)时,下拉电阻被覆盖,输入引脚将读为1。 许多微控制器提供内部下拉配置选项。有时,需要特定的下拉电阻值,这需要使用外部下拉电阻而不是芯片的内部下拉电阻。

电流灌入

“灌电流”表示电流正在流入引脚,节点或信号。对于数字IO,current sink提供了到负载的接地连接。

电流源/拉电流

“拉电流”与current sink相反:电流从引脚,节点或信号中流出。对于数字IO,current source为负载提供电压源。 拉电流 和 灌电流 都具有电流流动,但是方向不同。

输入和输出模式

GPIO引脚的主要配置选项是输入输出

GPIO输入模式

将GPIO配置为输入时,可以将其用于读取电信号的状态。将GPIO配置为输入会使该引脚进入高阻抗状态。 通常,主要通过以下三种方式之一配置GPIO输入:
  1. 高阻抗(默认-如果未驱动,则浮动)
  2. 上拉(内部电阻连接到VCC)
  3. 下拉(内部电阻接地)
大多数GPIO输入引脚还具有内部迟滞功能,可防止引脚上的虚假状态改变。通常,迟滞(hysteresis)是内置功能,而不是可配置的设置。

GPIO输出模式

将GPIO配置为输出时,可以将其用于驱动高电平或低电平。GPIO输出主要有两个配置选项:推挽和漏极开路。

推挽输出

在大多数情况下,推挽是默认的GPIO输出设置。推挽式GPIO具有提供和吸收电流的能力。 使用推挽式GPIO,晶体管连接到VCC或GND以驱动高电平或低电平信号。当输出变低时,信号被主动“拉”到地,当输出变高时,信号被主动“推”到VCC。

开漏输出

与推挽不同,开漏输出只能吸收电流。输出具有两种状态:低阻抗和高阻抗。为了在线路上实现逻辑高输出,使用上拉电阻将漏极开路输出连接到所需的输出电压电平。 您可以将漏极开路的GPIO看作是一个接地或断开的开关。 漏极开路GPIO通常可以以两种不同的模式进行配置:
  • 开漏
  • 带内部上拉的漏极开路
大多数利用漏极开路电路的应用都在漏极开路输出上利用外部上拉电路。通常,内部上拉值不足以用于目标电路。 当多个门或引脚连接在一起时,例如通过i2c总线,开漏输出非常有用。当设备不使用总线时,漏极开路输出处于高阻抗模式,并且电压由上拉电阻上拉至高电平。当设备将输出驱动为低电平时,所有连接的线将绑在一起,因此将变为低电平。 开漏输出的另一个常见用途是让多个外部设备驱动微控制器上的单个低电平有效中断引脚。

集电极开路

“集电极开路”在功能上与“漏极开路”相同。“集电极开路”是指在BJT晶体管输出上的电流吸收器,而“开漏”是指在FET输出上的电流吸收器。 我在元器件的数据说明书上遇到的“集电极开路”比在微控制器数据表上遇到的更多。

GPIO速度

GPIO速度控制压摆率,即信号可以在低/高值(“上升时间”和“下降时间”)之间变化的速率。速度配置选项描述为“速度”,“摆率”,“频率”和“高频模式”。 通过提高GPIO速度,可以提高输出电压的变化率(减少上升时间)。但是,电路的功耗和噪声会随着GPIO速度的增加而增加。默认情况下,除非有特殊原因需要提高GPIO速度,否则应将其保持在低速状态。

高驱动

高驱动GPIO是推挽式引脚,能够提供比典型引脚更大的电流。虽然您必须查看每个芯片的数据表以了解引脚的电流容量,但典型的推挽式GPIO可以提供/吸收大约±8mA的电流,而高驱动引脚可以提供/吸收高达±40mA的电流。 高驱动引脚使您的微控制器可以直接驱动需要高于正常电流的IO,例如LED。使用高驱动引脚可以消除外部电流放大电路的需求,从而有助于简化电气设计并降低成本。

用pyOCD和GDB调试micro:bit

安装pyocd apt install openocd python3-pyocd 安装 arm-none-eabi-gdb $ pyocd-gdbserver –persist -t nrf51 -bh -r
0000843:INFO:board:Target type is nrf51
0001221:INFO:dap:DP IDR = 0x0bb11477
0001270:INFO:dap:AP#0 IDR = 0x04770021
0001303:INFO:rom_table:AP#0 ROM table #0 @ 0xf0000000 (designer=244 part=001)
0001329:INFO:rom_table:[0]
0001329:INFO:rom_table: AP#0 ROM table #1 @ 0xe00ff000 (designer=43b part=471)
0001355:INFO:rom_table: [0]
0001373:INFO:rom_table: [1]
0001390:INFO:rom_table: [2]
0001407:INFO:rom_table:[1]
0001424:INFO:cortex_m:CPU core is Cortex-M0 r0p0
0001444:INFO:dwt:2 hardware watchpoints
0001453:INFO:fpb:4 hardware breakpoints, 0 literal comparators
0001480:INFO:semihost:Telnet: server started on port 4444
0001481:INFO:gdbserver:GDB server started at port:3333 https://os.mbed.com/docs/mbed-os/v6.2/debug-test/debug-microbit.html

DAP调试适配器协议

https://microsoft.github.io/debug-adapter-protocol/ 调试适配器协议(DAP)定义了在开发工具(例如IDE或编辑器)和调试器之间使用的抽象协议。

在IDE或编辑器中添加针对新语言的调试器不仅是一项艰巨的工作,而且令人沮丧的是,由于每个工具都使用不同的API来实现相同的功能,因此无法轻易在多个开发工具上分摊此工作。

调试适配器协议(DAP)背后的思想是将开发工具的调试支持与调试器或运行时进行通信的方式抽象为协议。由于假定现有的调试器或运行时在任何时候都采用此协议是不现实的,因此我们假定中介组件(即所谓的调试适配器)使现有的调试器或运行时适应调试适配器协议。

调试适配器协议使为开发工具实现通用调试器成为可能,该工具可以通过调试适配器与不同的调试器进行通信。调试适配器可以在多个开发工具中重复使用,从而大大减少了在不同工具中支持新调试器的工作。

调试适配器协议对调试器提供商和工具提供商而言都是双赢!
CMSIS-DAP是用于将调试端口连接到USB的调试单元的接口固件。 在主机上执行的调试器通过USB连接到调试单元和运行应用程序软件的设备。 调试单元通过JTAG或SW连接到目标设备。 ARM Cortex处理器提供CoreSight调试和跟踪单元。 CMSIS-DAP支持包含一个或多个Cortex处理器的目标设备。 这里,DAP是Debug Access Port的意思 CMSIS-DAP提供了一种通过USB访问ARM Cortex微控制器的Coresight调试访问端口(DAP)的标准化方法。 CMSIS-DAP通常实现为板载接口芯片,通过开发板与一侧运行在主机上的调试器之间通过JTAG(联合测试操作组)或SWD(串行线调试)提供直接USB连接。 目标设备访问另一台上的Coresight DAP。 为什么需要CMSIS-DAP?
有关引入CMSIS-DAP的原因有很多: 在CMSIS-DAP标准之前,许多USB wigglers都实现了自己的协议。使用这种配置,主机调试器必须了解这些不同的协议,并且必须实现所有这些协议,这会产生很多碎片并重新发明轮子。同时,协议通常是在JTAG级别定义的,这意味着它们很慢。 CMSIS-DAP为调试器提供了标准化的接口,该接口在Coresight DAP级别上定义,允许使用标准接口和快速的无驱动程序实现。
借助新的CMSIS-DAP层,主机调试器可以通过SWD或JTAG调试目标,而无需实现这两个协议
USB连接使用HID驱动程序类。由于每个操作系统都内置了HID驱动程序,因此无需在主机上安装特定的驱动程序。 CMSIS-DAP如何集成?
如前所述,CMSIS-DAP必须在接口芯片上实现。该芯片提供了主机计算机(例如,通过USB)和必须调试的目标(通过SWD或JTAG)之间的链接。 CMSIS-DAP标准概述
数据包在主机调试器和接口芯片之间交换。基本上,主机发送命令,调试单元发送命令响应。

主机可以发出不同类型的命令:

通用命令:请求信息并控制调试单元。也用于连接/断开调试单元。
常见的SWD / JTAG命令:例如用于设置时钟速度
SWD特定命令:配置SWD模式的参数
JTAG特定命令:配置JTAG设备链
传输命令:读/写CoreSight寄存器。这些命令与传输方式无关(SWD或JTAG)
示例:通过CMSIS-DAP读取内存
假设调试器需要读取内存中特定位置的值。主机必须发送以下命令:

传输命令:写入CSW寄存器(控制/状态字寄存器)。这将配置传输(32位/ 16位/ 8位传输)
传输命令:使用存储单元的地址写入TAR寄存器(传输地址寄存器)
传输命令:读取DRW寄存器(数据读取/写入寄存器)以读取先前指定位置的值
结论
CMSIS-DAP为调试器提供了标准化的接口。它可能会成为调试器和调试单元将要实现的实际标准。

JTAG/SWD口作为GPIO使用而不能调试

JTAG/SWD口作为GPIO使用 导致无法找到JTAG/W设备, 也就无法下载和调试程序 解决办法: 存储器采用固定的存储器映射,代码区域起始地址为 0x0000 0000(通过 ICode/DCode 总线访问),而 数据区域起始地址为 0x2000 0000(通 过 系 统 总 线 访 问)。Cortex-M4F CPU 始终通过 ICode 总线获取复位向量,这意味着只有代码区域(通常为 Flash)可以提供自举空间。STM32F4xx 微控制器实施一种特殊机制,可以从其它存储器(如内部 SRAM)进行自举。
在 STM32F4xx 中,可通过 BOOT[1:0] 引脚选择三种不同的自举模式 boot0 = 0, 主Flash boot0=1, boot1=0 系统存储器 boot0=1, boot1=1 嵌入式SRAM 复位后,在 SYSCLK 的第四个上升沿锁存 BOOT 引脚的值。复位后,用户可以通过设置BOOT1 和 BOOT0 引脚来选择需要的自举模式。BOOT0 为专用引脚,而 BOOT1 则与 GPIO 引脚共用。一旦完成对 BOOT1 的采样,相应GPIO 引脚即进入空闲状态,可用于其它用途。器件退出待机模式时,还会对 BOOT 引脚重新采样。因此,当器件处于待机模式时,这些引脚必须保持所需的自举模式配置。这样的启动延迟结束后,CPU 将从地址 0x0000 0000 获取栈顶值,然后从始于 0x0000 0004 的自举存储器开始执行代码。 注意:

如果器件从 SRAM 自举,在应用程序初始化代码中,需要使用 NVIC 异常及中断向量表和偏移寄存器来重新分配 SRAM 中的向量表。 64 KB CCM (内核耦合存储器)数据 RAM 不属于总线矩阵, 只能通过 CPU 对其进行访问(CPU D总线) 选择自举引脚后,应用程序软件可以将某些存储器设定为从代码空间进行访问(这样,可通过ICode 总线而非系统总线执行代码)。这样的修改通过在 SYSCFG 控制器中编程 SYSCFG 存储器重映射寄存器 (SYSCFG_MEMRMP) 来实现。
  1. 使用两个位来配置可在地址 0x0000 0000 访问的存储器区域。从而通过软件选择物理重映射,而旁路 BOOT 引脚。
  2. 这两个位的复位值和复位时 BOOT 引脚的设置相同。当 BOOT 引脚设为 10 [(BOOT1,BOOT0)= (1,0)] 从主 Flash 中自举时,寄存器值为 0x00. 也就是boot引脚的值,被忽略,用寄存器的值代替。
灵活的静态存储控制器 (FSMC) 当把 FSMC 重映射到地址 0x0000 0000 时,只有 FSMC 的 Bank1 的前两个区域(NOR/PSRAM 1和 NOR/PSRAM 2)可被重映射到低端地址。在重映射模式下,CPU 可以通过 ICode 总线(而不是 System 总线)访问外部存储器来提高性能。
偏移地址:0x00
复位值:0x0000 000X(X 和 BOOT 引脚的设置相同) STM32F4xx 内核集成了串行 /JTAG 调试端口 (SWJ-DP) 默认调试接口是 JTAG 接口。如果调试工具想要切换到 SW-DP, 它必须在 TMS/TCK(分别映射到 SWDIO 和 SWCLK)
上提供专用的 JTAG 序列, 用于禁止 JTAG-DP 并使能 SW-DP。这样便可仅使用 SWCLK和 SWDIO 引脚来激活 SWDP。
该序列为:
  1. 输出超过 50 个 TCK 周期的 TMS (SWDIO) = 1 信号
  2. 输出 16 个 TMS (SWDIO) 信号 0111100111100111 (MSB)
  3. 输出超过 50 个 TCK 周期的 TMS (SWDIO) = 1 信号
复位(SYSRESETn 或 PORESETn)后,会将用于 SWJ-DP 的全部 5 个引脚指定为专用引
脚,可供调试工具立即使用(请注意,除非由调试工具明确编程,否则不分配跟踪输出)。
但是,STM32F4xx MCU 可以禁止部分或全部 SWJ-DP 端口,进而释放相关引脚以用作通
用 IO (GPIO)。 调试时,主机执行以下操作:
注意:
● 在系统复位状态下,分配所有 SWJ 引脚 (JTAG-DP + SW-DP)。
● 在系统复位状态下,调试主机发送 JTAG 序列,以从 JTAG-DP 切换到 SW-DP。
● 仍然在系统复位状态下,调试主机在复位地址处设置断点。
● 释放复位信号,内核停止在复位地址处。
● 从此所有调试通信均使用 SW-DP 完成。然后通过用户软件将其它 JTAG 引脚重新分配为 GPIO。

SWD调试接口

Jtag 是20PIN接口(非常多的接地PIN),太多的PIN会导致一些小型的PCB板很拥挤,也会增加布线的难度。 使用SWD接口下载调试,只需要要使用2-6个PIN: VCC, GND, RST, SWDIO, SWCLK, SWO 其中, SWDIO, SWCLK是必须的 国内仿制 ULINK2 非常好的支持 SWD 模式, 速度可以达到 10M。 ULINK2 需要的硬件接口为: GND, RST, SWDIO, SWCLK Ulink2将JTAG的1、7、9、20分别与自己的开发板上JTAG的VCC、JTMS/SWDIO、JTCK/SWCLK GND用杜邦线相连即可 JLink按SWD方式来调试,实际需要接1,7,9,15,20脚,某些资料上说的需要6个脚(第13脚SWO也需要连上)是不对的,SWO不需要连接。SWO是调试数据,log可以从这里打印。 SEGGER Embedded Studio can use SWO for printf Output to the Debug Terminal and for code profiling and execution trace. https://wiki.segger.com/Configure_SWO_in_Embedded_Studio 有些开发板,没有引出RST线。那么 不接第15脚,即RESET脚,仅接4条引线,即Vref,SWDIO, SWCLK, GND。 在MDK 中 设置时Reset位选择:AutoDetect,可以正常下载,仿真。 如果Reset位选选择:HW Reset ,则不能正常下载。 这是正常的,硬件reset信号都没连接,自然不能硬件复位。 小程序 都是在RAM中调试的,而且只接三根线GND SWDIO SWCLK (VCC 直接接JTAG内部的),很爽利。不过今天要试IIS 要放一个大的数据进去,于是要烧到FLASH中去, 发现很快进度条走完, 然后显示失败,放狗一搜,说要接RESET,于是接上,果然下进去了。 在MDK仿真器的设置里面不使用硬件复位,而是用system reset或者vect reset,前者适用的范围更广 因为SWD有软件复位协议,不需要硬件RST信号,也可以复位系统。

SEGGER Embedded Studio链接与段布置

Linking and section placement 可执行程序包含很多段(section). 典型地,有代码程序段, 初始化数据段,清0数据段等。通常,在程序中有多个段,并且,必须将它们放在内存的指定地址。 为了描述你的程序的程序段在内存中如何定位,SEGGER Embedded Studio项目系统使用内存映射文件 和 段布置文件。 内存映射文件,指定了 目标内存段(target memory segment)的起始地址和大小。 段布置文件,指定在 目标内存段(segment)的 什么位置防止 程序段(section). 将内存映射 与 段布置方案 分开, 可以让一个硬件描述 在多个项目中共享。也可以让一个项目,用不同的硬件描述来建立。

以AT91SAM7S256为例用Keil MDK创建从RAM启动的简单应用

安装MDK5 和 ARM7/ARM9支持包
https://armkeil.blob.core.windows.net/eval/MDK531.EXE
https://armkeil.blob.core.windows.net/legacy/MDK79525.EXE

准备 RAM.ini

FUNC void Setup (void) {
  PC = 0x00200000;
}

_WDWORD(0xFFFFFD44, 0x00008000);     // WDT_WDMR: Disable Watchdog

// Switching from Slow Clock to Main Oscillator for faster Download
_WDWORD(0xFFFFFC20, 0x00000601);     // PMC_MOR: Enable Main Oscillator
_sleep_(10);                         // Wait for stable Main Oscillator
_WDWORD(0xFFFFFC30, 0x00000001);     // PMC_MCKR: Switch to Main Oscillator

LOAD %L INCREMENTAL       // Download

Setup();                             // Setup for Running

g, main
准备Main.c
此应用是一个MCU的hello world, 用GPIO驱动LED闪烁
#include "AT91SAM7S256.h"
#define LED_A (1U<<0) // PA0, pin 48
#define LED_B (1U<<1) // PA1, pin 47

void sleep_ms(unsigned int msec)
{
  volatile unsigned int i;
  for (i = 0; i < 1000 * msec; i++) {
    __asm ("NOP");
  }
}

int main(void) {
  /* Configure the pins as outputs */
  AT91C_BASE_PIOA->PIO_OER = (LED_A | LED_B);
  /* Enable PIOC control on the pins*/
  AT91C_BASE_PIOA->PIO_PER = (LED_A | LED_B);
  /* Disable pull-ups */
  AT91C_BASE_PIOA->PIO_PPUDR = (LED_A | LED_B);

  while(1)
  {
    /* Turn LED on, high level */
    AT91C_BASE_PIOA->PIO_SODR = LED_A;
    sleep_ms(1);

    /* Turn LED off, low level */
    AT91C_BASE_PIOA->PIO_CODR = LED_A;
    sleep_ms(1);
  }
}

开启MDK,新建Project,选择存储位置
选择设备,从Legacy Device Database里选取AT91SAM7S256
同意复制启动文件SAM7.s到项目中
在 左侧项目管理选择Target1, 右键选取Manage Project Items
双击Target1,将其改名为Flash, 新增加一个RAM的Target. 将Source Group 1改名为Startup, 新增一个Source的Group,并增加一个Main.c的文件
项目左侧,选中RAM这个Target,右键选取Options for RAM Target
切换到Linker这个标签页
取消选中Use Memory Layout from Target Dialog, 在右侧设置R/O Base为0x00200000, R/W Base为0x00202000, 删除Scatter File, 也就是留空
切换到Debug标签
选中 Use ULink2/ME ARM Debugger,   取消 选择 Load Application at Startup,  添加Initilization File, 选择 RAM.ini
切换到Utilities, 取消Update Target before Debugging
点击菜单栏,Project–Build Target, 然后,Debug–Start Debug Session即可开始调试