您正在为AVR8架构使用GPIO示例。AVR32架构完全不同,将GPIO模块作为通过PBA连接的单独硬件块引入 (我认为)。没有像...这样的寄存器DDRC
您可以将AVR32架构视为子组件网络,其中MCU内核只是模块之一。有 2 条主总线PBA和PBB ,每条连接到不同的模块。
要使AVR32固件正常工作,您需要执行以下操作:
配置并启动您要使用的主 MCU 内核时钟
AVR32 MCU 内核通常在复位后以 32KHz 的低时钟运行。为了获得更好的性能,您需要高达 66MHz 的更高时钟。我通常以某个通用频率启动PLL ,然后将所有时钟( CPU、PBA、PBB、HSB)分频。作为PLL的源,您需要一些时钟,例如内部RC或由外部晶振驱动的振荡器。如果您还想要USB,那么您需要记住它需要特定的频率,因此需要妥协……有关更多信息,请查看数据表和/或示例中的SCIF模块。
正确启动时切换到它
等待一下(100ms)或检查时钟是否直接运行(我认为SCIF模块有一些功能)。
配置/启动使用的硬件模块
现在做你的事
引导程序
您需要注意的另一件事是引导加载程序。我不喜欢JTAG,因为我对它的体验很糟糕(炒它不需要太多,用它编程真的很不舒服)。使用JTAG,您可以轻松清除引导加载程序(每个芯片都附带它)并相信我让它恢复工作真的很讨厌。
另一方面,引导加载程序简单而优雅。例如,我使用FLIP并且有用于编程芯片的简单命令行文件。然后我只是打开命令提示符执行它。在每次重建/编程时,我只需按向上箭头重复提示中的最后一个命令,然后按 Enter。与使用JTAG的多次点击相比,这更快、更简单。这里的cmd示例:
avr32-objcopy -O ihex AT32UC3L064.elf AT32UC3L064.hex
Batchisp -device AT32UC3L064 -hardware RS232 -port COM1 -baudrate 115200 -operation onfail abort memory flash erase f blankcheck loadbuffer AT32UC3L064.hex program start reset 0
位于avr32-objcopy.exe
AVR 工作室的 bin 目录中。
使用引导加载程序,您需要告诉编译器您的程序没有开始,0x0000
因为这将与引导加载程序重叠。为此,请参阅蹦床示例。
这就是我的AVR32应用程序通常的样子:
#include <avr32/io.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "intc.c"
#include "gpio.c"
#include "pm_uc3l.c"
#include "scif_uc3l.c"
#include "adcifb.c"
#include "flashcdw.c"
#include "pdca.c"
//#include "pwma.c"
#include "tc.c"
#include "usart.c"
#include "eic.c"
#include "genclk.h"
#include "osc.c"
#include "dfll.c"
#include "sysclk.c"
#include "status_codes.h"
#include "cycle_counter.h"
#include "sleep.h"
#include "delay.c"
#define cpu_clk 30000000
#define _LED AVR32_PIN_PA04
void system_init()
{
delay_init(115000);
Disable_global_interrupt();
INTC_init_interrupts();
scif_start_rc120M();
delay_ms(100);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_CPU,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_PBA,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_PBB,PM_CKSEL_DIVRATIO_4);
pm_set_clk_domain_div((pm_clk_domain_t)AVR32_PM_CLK_GRP_HSB,PM_CKSEL_DIVRATIO_4);
pm_set_all_cksel(SCIF_RC120M_FREQ_HZ,cpu_clk,cpu_clk,cpu_clk);
flashcdw_set_flash_waitstate_and_readmode(cpu_clk);
pm_set_mclk_source(PM_CLK_SRC_RC120M);
delay_init(cpu_clk);
}
//------------------------------------------------------------------------------------------------
void wait_ms(U32 dt)
{
U32 t0,t1;
t0=Get_system_register(AVR32_COUNT);
dt=((dt*cpu_clk)+999)/1000;
t0&=RDTSC_mask;
for (;;)
{
t1=Get_system_register(AVR32_COUNT);
t1&=RDTSC_mask;
if (t0>t1) t1+=RDTSC_mask+1;
if ((t1-t0)>=dt) break;
}
}
//------------------------------------------------------------------------------------------------
void wait_us(U32 dt)
{
U32 t0,t1;
t0=Get_system_register(AVR32_COUNT);
dt=((dt*cpu_clk)+999999)/1000000;
t0&=RDTSC_mask;
for (;;)
{
t1=Get_system_register(AVR32_COUNT);
t1&=RDTSC_mask;
if (t0>t1) t1+=RDTSC_mask+1;
if ((t1-t0)>=dt) break;
}
}
//------------------------------------------------------------------------------------------------
int main(void)
{
system_init();
// here init what you need
gpio_configure_pin(_LED,GPIO_DIR_OUTPUT|GPIO_INIT_HIGH);
for (;;)
{
// here do your stuff
gpio_tgl_gpio_pin(_LED);
wait_ms(200);
}
//------------------------------------------------------------------------------------------------
我不使用框架管理器,而是我自己包含这些东西......并且我的框架被重写以避免不必要的包含和编译速度减慢。另请注意,框架更新并不总是兼容,因此有时更新后您的代码将无法编译……最好拥有一个可靠的框架,除非您确实需要,否则不要更新它。
仅选择您需要的模块(无需全部包含)。例如,您需要intc,gpio,scif
等我包含的内容来自更大的项目,因此其中许多对您无用,而且并非所有头/模块都可用于所有AVR32芯片。
我有点跑题了(我认为有必要)所以回到 GPIO
API和架构完全改变。不要被引脚名称所迷惑。例如pinPA35
不代表端口A
pin 35
!!!没有端口PA
这只是命名约定,对架构没有任何实际意义,这有点愚蠢,我花了一段时间才适应它。有尽可能多的端口来覆盖所有引脚。每个端口都支持32
引脚和引脚号是您需要知道的真实内容。
每个引脚都在某处avr32/io.h
定义为类似定义AVR32_PIN_PA04
,它包含芯片 GPIO 中引脚位置的数值。要获取 gpio 端口/掩码,您只需执行以下操作:
port = pin>>5
mask = 1<<(pin&31)
现在要直接访问GPIO寄存器,我建议查看gpio.c
. 您可以一次设置、解析、测试、读取 32 个引脚以加快速度(如果它们位于同一端口)。速度主要取决于总线时钟(通常是GPIO的PBA),因此如果您的时钟较低,则不要期望高切换率。当心GPIO访问速度很慢,如果不明智地使用会破坏代码的性能......
如果为您的应用程序选择的硬件引脚做得很好,您可以拥有非常快的速度。例如,我的切换速度约为 2-5 MHz !!!
这里设置一个引脚的示例gpio.c
void gpio_set_gpio_pin(uint32_t pin)
{
U32 bit= 1 << (pin & 0x1F);
volatile avr32_gpio_port_t *gpio_port = &GPIO.port[pin >> 5];
gpio_port->ovrs = bit; // Value to be driven on the I/O line: 1.
gpio_port->oders = bit; // The GPIO output driver is enabled for that pin.
gpio_port->gpers = bit; // The GPIO module controls that pin.
}
您可以使用它在同一个端口设置多个引脚,只需bit
与您要设置的所有引脚的掩码交换...
如果您使用GPIO的中断,请注意中断控制器INTC也是通过总线连接的单独模块,错误设置时钟或等待状态可能会导致巨大问题。