AT32F435 入门使用
- 🔖这里以
AT32F435RGT7
作为测试对象,创建基于Keil平台编译的代码工程。 - 📍相关篇《基于AT32_Work_Bench配置AT32工程》
- ✨由于
AT32F435RGT7
(LQFP-64封装)引脚与STM32F405RGT6TR
引脚兼容程度:96.875%.不兼容的两个引脚为:PH2
、PH3
.具体对照下图:
📘AT32F435 程序烧录的常用几种方式
-
- 通过SWD接口烧录,支持的烧录器有:DAP-LINK、J-LINK、以及AT32官方的AT-LINK。
-
- 通过USB DFU模式烧录,也就是USB接口(PA11、PA12引脚)。
-
- 通过串口烧录。(常见使用串口1:PA9、PA10引脚)
- 👉以及其他烧录方式:I2C,SPI、CAN,这里不做介绍,可以参考Bootloader ISP协议文档:
https://www.arterytek.com/cn/support/index.jsp?index=5
- ✨编程+烧录推荐使用DAP-LINK工具。AT-LINK需要购买, 自制也需要手上,必须要有一个AT-LINK才行,虽然官方开放了AT_Link资料,但是固件给的是加密的
.atcp
文件,只有通过AT-LINK
才能烧录,这一点很坑,自制还需要买一个才能烧录固件,那自制就没有必要了,毕竟这个东西多了,又不能当饭吃的。
- 🔬如果自制,补充一句有关固件加载和烧录:AT-LINK加载加密固件步骤和方式:使用
Artery_ICP_Programmer
工具
- 🌿Bootloader引脚描述参考《AT32F435/437系列 数据手册》:
https://www.arterytek.com/download/DS/DS_AT32F435_437_V2.12_CH.pdf
- 🎉个人使用串口1-3都进行了测试,通过
Artery ISP Programmer
工具,都可以进行连接。芯片版本是B1
USART1
PA9:USART1_TX
PA10:USART1_RX
------
USART2
PA2:USART2_TX
PA3:USART2_RX
----
USART3
PC10:USART3_TX
PC11:USART3_RX
或
PB10:USART3_TX(1)
PB11:USART3_RX(1)
- 🍭使用
Artery ISP Programmer
工具,通过串口连接时,最好将BOOT1(PB2引脚)=0拉低,BOOT0引脚拉高,然后按复位进行连接。✨如果BOOT1(PB2引脚)处于浮空或拉高的状态下,仅拉高BOOT0引脚,一次性连接成功率不高。✨
📄BOOT1(PB2)和BOOT0引脚电平
- 🌿当{BOOT1,BOOT0}=00/10 时,CODE 从主闪存存储器启动。
- 🌿当{BOOT1,BOOT0}=01 时,CODE 从启动程序存储器启动。
- 🌿当{BOOT1,BOOT0}=11 时,CODE 从片上 SRAM 启动。
📒程序烧录上位机使用
-
🔧串口和USB DFU模式以及I2C、SPI、CAN使用使用;
ArteryISPProgrammer
工具进行烧录。:https://www.arterytek.com/cn/product/AT32F435.jsp
-
🌿DFU模式:进入:
-
🔨SWD接口烧录,使用
ArteryICPProgrammer
工具进行烧录。支持OB-JLINK、AT-LINK烧录器。
- 🛠keil开发环境下,支持J-LINK、CMSIS-LINK烧录。
- 🌿J-LINK连接:
- 🌟对J-LINK的支持,需要提前导入AT32芯片数据数据到Keil安装的Segger目录。导入软件:
Segger_AT32MCU_AddOn_Win32-x86_64
:https://www.arterytek.com/cn/support/index.jsp?index=5
- 🧨导入位置:
- 🌿DAP-LINK不需要做任何配置,即可直接烧录。
⛳注意事项
- 🌿如果使用DAP-LINK下载报错:
Error: Flash Download failed - "Cortex-M4"
解决方法:对全片flash做擦除。
🌼点灯环节
- 🔖工程创建可以使用
AT32_Work_Bench
,具体可以参考前面的相关篇内容。
- 🌿基于
AT32_Work_Bench
配置的初始化工程,目前这个工具生成的代码宽度很有限,很多外设的功能函数没有。例如USB外设,就没有相对应的扩展驱动包。
📑GPIO位带操作实现方法
📄位带介绍
利用位带操作,可以使用普通的加载/存储操作来对单一比特进行读写访问。在 Cortex®-M4F 中提供了两个位带区:SRAM 最低 1M 字节空间和外设区间的最低 1M 字节空间。这两个区中的地址除了可以像普通存储器一样访问外,还可以通过它们各自的位带别名区来快捷访问这两个区中任意地址的任意比特位,位带别名区将位带区每个比特膨胀成一个 32 位的字。当你访问位带别名区的一个地址时,等同于直接访问位带区的一个比特位。
位带区:支持位带操作的地址区,分别是SRAM区的最低1MB范围和外设区的最低1MB范围。
位带别名:对别名地址的访问最终作用到位带区的访问上(注意:这其中有一个地址映射的过程)
- 🌿SRAM存储器
AT32F435/437 系列内置默认 384K 字节的片上 SRAM,起始地址为 0x2000_0000。它可以以字节、半字(16 位)或全字(32 位)访问。AT32F435/437 系列另外提供一个特别的模式能使片上 SRAM 在最低128K 字节到最高 512K 字节之间动态配置,使用者可透过设定扩充的系统选项 EOPB0 来使用此扩充模式。在 512K 字节扩充模式下,零等待延迟(zero wait state)的闪存容量限制为 128K 字节。在 128K 字节扩充模式下,零等待延时的闪存容量限制为 512K 字节。片上 SRAM 分为两块:SRAM1 和 SRAM2。SRAM1 大小固定为 64K 字节,可在 0x2000_0000 ~ 0x2000_FFFF 或0x1000_0000 ~ 0x1000_FFFF 两个地址空间对 SRAM1 进行访问。SRAM2 的大小为 64K~448K 字节,可在 0x2001_0000 ~ 2007_FFFF 地址空间对 SRAM2 进行访问。
-
🌿GPIO外设地址映射
-
🌿GPIO输入和输出偏移地址
-
🌿AT32F435的位带操作定义:
#include "at32f435_437.h"
#define ODR_OFFSET 0X14 //gpio output data register
#define IDR_OFFSET 0x10 //gpio input data register
//位带操作,实现51类似的GPIO控制功能
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+ODR_OFFSET) //0x40020014
#define GPIOB_ODR_Addr (GPIOB_BASE+ODR_OFFSET) //0x40020428
#define GPIOC_ODR_Addr (GPIOC_BASE+ODR_OFFSET) //0x4002083C
#define GPIOD_ODR_Addr (GPIOD_BASE+ODR_OFFSET) //0x40020C50
#define GPIOE_ODR_Addr (GPIOE_BASE+ODR_OFFSET) //0x40021064
#define GPIOF_ODR_Addr (GPIOF_BASE+ODR_OFFSET) //0x40021478
#define GPIOG_ODR_Addr (GPIOG_BASE+ODR_OFFSET) //0x4002188C
#define GPIOH_ODR_Addr (GPIOH_BASE+ODR_OFFSET) //0x400218A0
#define GPIOA_IDR_Addr (GPIOA_BASE+IDR_OFFSET) //0x40020010
#define GPIOB_IDR_Addr (GPIOB_BASE+IDR_OFFSET) //0x40020420
#define GPIOC_IDR_Addr (GPIOC_BASE+IDR_OFFSET) //0x40020830
#define GPIOD_IDR_Addr (GPIOD_BASE+IDR_OFFSET) //0x40020C40
#define GPIOE_IDR_Addr (GPIOE_BASE+IDR_OFFSET) //0x40021050
#define GPIOF_IDR_Addr (GPIOF_BASE+IDR_OFFSET) //0x40021460
#define GPIOG_IDR_Addr (GPIOG_BASE+IDR_OFFSET) //0x40021870
#define GPIOH_IDR_Addr (GPIOH_BASE+IDR_OFFSET) //0x40021880
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
#define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n) //输出
#define PHin(n) BIT_ADDR(GPIOH_IDR_Addr,n) //输入
- 🌿GPIO引脚按位取反操作
PHout(2) = !PHout(2) ;
PHout(3) = !PHout(3);
- 🌿GPIO引脚置位和复位操作:
PHout(2) = 1;
PHout(3) = 0 ;
- 🌿GPIO输入引脚位带操作读取:
if(PDin(2)==1){
while(PDin(2)==1);
}
📗串口printf重映射实现
#define PRINT_UART USART1
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
/* support printf function, usemicrolib is unnecessary */
#if (__ARMCC_VERSION > 6000000)
__asm(".global __use_no_semihosting\n\t");
void _sys_exit(int x)
{
x = x;
}
/* __use_no_semihosting was requested, but _ttywrch was */
void _ttywrch(int ch)
{
ch = ch;
}
FILE __stdout;
#else
#ifdef __CC_ARM
#pragma import(__use_no_semihosting)
struct __FILE {
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x = x;
}
/* __use_no_semihosting was requested, but _ttywrch was */
void _ttywrch(int ch)
{
ch = ch;
}
#endif
#endif
#if defined (__GNUC__) && !defined (__clang__)
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
/**
* @brief retargets the c library printf function to the usart.
* @param none
* @retval none
*/
PUTCHAR_PROTOTYPE {
while(usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET);
usart_data_transmit(PRINT_UART, (uint16_t)ch);
while(usart_flag_get(PRINT_UART, USART_TDC_FLAG) == RESET);
return ch;
}
#if (defined (__GNUC__) && !defined (__clang__)) || (defined (__ICCARM__))
#if defined (__GNUC__) && !defined (__clang__)
int _write(int fd, char *pbuffer, int size)
#elif defined ( __ICCARM__ )
#pragma module_name = "?__write"
int __write(int fd, char *pbuffer, int size)
#endif
{
for(int i = 0; i < size; i ++) {
while(usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET);
usart_data_transmit(PRINT_UART, (uint16_t)(*pbuffer++));
while(usart_flag_get(PRINT_UART, USART_TDC_FLAG) == RESET);
}
return size;
}
#endif
📚测试工程
链接:https://pan.baidu.com/s/1Q0b1t9ydOWakzxr2p0jTCw?pwd=471q
提取码:471q