找回密码
 立即注册
查看: 1648|回复: 5

Ai8051U电调(移植AM32固件)

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:316
  • 最近打卡:2025-04-14 12:35:14
已绑定手机

14

主题

41

回帖

563

积分

高级会员

积分
563
发表于 2024-12-22 13:41:18 | 显示全部楼层 |阅读模式

单片机请购买24年10月之后生产的(最下方丝印前四位数>=2442)

介绍

AM32 固件原为 ARM 处理器设计,现成功移植到强大的 Ai8051U,用于控制无刷电机 (BLDC)。该固件旨在安全、快速、平滑、快速启动和线性油门。它适用于多种车辆类型和飞行控制器。

AM32具有以下特点:

  1. 可通过 betaflight 直通、单线串行或 arduino 升级固件
  2. 伺服 PWM、Dshot(300, 600) 电机协议支持
  3. 双向控制
  4. KISS 标准 ESC 遥测
  5. 可变 PWM 频率
  6. 正弦启动模式,旨在让更大的电机加速

主控及外设配置

使用AI8051U作为主控芯片,AI8051U具有充足的外设资源和优异的性能表现。

MCU

mcu.png

MCU引脚图

mcu_pins.png

使用 PWMA 输出 3 组互补 PWM 来驱动 MOSFEET,使用 PWMB 捕获外部油门信号,使用 ADC 对电压和电流进行采样,用于低电压保护和过流保护。使用内部 OPA 和 BEMF 估计转子位置。TMR0 和 TMR1 用于计算换向时间,TMR2 用于串口,TMR3 和 TMR11 用于延迟功能(实际上,只需要一个),TMR4 用于完成一些周期性任务。

引脚选择

PINS.png

AH AL BH BL CH CL : PWMA 输出

INPUT: PWMB 外部输入触发

A_BEMF: A相反电动势
B_BEMF: B相反电动势
C_BEMF: C相反电动势

CC_BEMF: 反电动势中电

CMP_OUT:比较器输出

ADC_V: 电压检测口
ADC_I: 电流检测口

为了统一 OPA 的中断入口,将 OPA 的输出到 P41 中,使用 P41 的引脚中断进行过零比较处理

P30 和 P31 用于通过 STC-LINK1、UART 或内部 USB 下载 bootloader

初始化(板子仅供参考)

烧录Bootloader

  1. 对于空芯片,BootLoader 需要通过 STC-LINK1、UART 或内部 USB 进行烧录,如下图所示进行连

connect.jpg

  1. 使用 AIapp-ISP 打开 Bootloader(upload 附件:AM32_Bootloader_AI8051U.zip) 工程,编译后直接下载。

    download.png

  2. 使用单线串口(可以将 USB 转串口芯片的 RX 和 TX 连接在一起,比如 CH340,然后连接到板子上)连接到 ESC,并使用工具配置和更新固件。我用 CH340 来表现,接线如下图所示。

config.jpg

config3.jpg

如果 Bootloader 烧录正确,打开 Esc_Config_Tool_1_82_WIN.exe(upload 附件:Esc_Config_Tool_1_82_WIN.zip) 配置工具并打开 ESC 电源。按照下图中的步骤进行单击。首次连接时,将显示 No EEprom!

first.png

直接点击下面的 发送默认设置 以烧写默认值。烧录成功后,重新开机。再次连接并单击 M1。将显示我们刚刚烧录的默认参数。

then.png

  1. 刷写固件和配置固件可以使用 Keil C251 进行编译,编译后的固件位于 Objects 文件夹中。

    hex.png使用文本编辑器打开 HEX 文件(我更喜欢使用 VScode),为了更好的支持 HEX 文件编辑,需要安装 Hex Editor 或 Intel HEX 格式插件,该插件可以在扩展市场中找到。安装后,打开 HEX 文件。

    Plug_in.png

    在这个 HEX 文件中,请注意第一行。
    :03000000023E5865
    0000H 的值更改为 1000H,将 65H 的值更改为 55H
    :03100000023E5855
    请注意,0000H 的值是程序的起始地址,65H 的值是校验和。1000H 的值是烧录 bootloader 后程序的起始地址。55H 的值是新的校验和。烧录 bootloader 后程序的起始地址是 0x1000H,因此 0000H 的值更改为 1000H。校验和的计算方法是将行中除起始冒号和校验和本身之外的所有数据相加,然后取总和最后一个字节的二进制补码。65H 的值更改为 55H,一般来讲,上面这个改动导致的校验位变化可以直接在校验位上面减去10H。具体计算方法可以在网上找到。如果 VScode 配合插件使用,可以直接点击地址值进行修改,插件可能会自动计算新的校验和。

    Hexline.png

    Hex_change.png

回到工具的 FLASH 界面,我们点击 Load Firmware,选择我们刚刚修改的固件,会弹出 FLash Firmware 按钮。单击以开始更新程序。

updata.png

更新完成后,重新上电并重新连接 ESC 以配置 ESC。

para.png

测试

我移植的版本是 V2.16,支持 dshot300、dshot600、PWM 等信号。(但出于某种原因,我只实现了 PWM,不能使用 dshot)。

2 喜欢他/她就送朵鲜花吧,赠人玫瑰,手有余香!
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:316
  • 最近打卡:2025-04-14 12:35:14
已绑定手机

14

主题

41

回帖

563

积分

高级会员

积分
563
发表于 2024-12-22 14:10:03 | 显示全部楼层

Bootloader 程序

upload 附件:AM32_Bootloader_AI8051U.zip

AM32程序

PCB文件在docs文件夹下,使用KiCAD和LCEDA进行设计(附件已更新,请注意LCEDA绘制的PCB需要在两个程序中修改一下输入引脚的 #define)

upload 附件:AM32_AI8051U.zip

Esc_Config_Tool_1_82_WIN

upload 附件:Esc_Config_Tool_1_82_WIN.zip

测试视频

新PCB测试

Github

https://github.com/Icey7122/AM32_AI8051U

回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:54
  • 最近打卡:2025-05-01 09:07:55

717

主题

1万

回帖

1万

积分

管理员

积分
15655
发表于 2024-12-22 14:47:09 | 显示全部楼层
DSHOT 等后续的集成 单总线 的芯片出来
Ai8051U暂时无 单总线


截图202412221446171464.jpg



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:316
  • 最近打卡:2025-04-14 12:35:14
已绑定手机

14

主题

41

回帖

563

积分

高级会员

积分
563
发表于 2024-12-22 16:35:41 | 显示全部楼层
神*** 发表于 2024-12-22 14:47
DSHOT 等后续的集成 单总线 的芯片出来
Ai8051U暂时无 单总线

问一下,后续芯片在高速PWM时还是得异步读写吗?

点评

如果外设用的时钟频率和CPU不一致,那就是异步; 如果外设用的时钟频率和CPU是一致,那就是不需要异步  详情 回复 发表于 2024-12-22 17:18
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:54
  • 最近打卡:2025-05-01 09:07:55

717

主题

1万

回帖

1万

积分

管理员

积分
15655
发表于 2024-12-22 17:18:35 | 显示全部楼层
Qinlu*** 发表于 2024-12-22 16:35
问一下,后续芯片在高速PWM时还是得异步读写吗?

如果外设用的时钟频率和CPU不一致,那就是异步;

如果外设用的时钟频率和CPU是一致,那就是不需要异步


回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:458
  • 最近打卡:2025-05-01 07:48:22
已绑定手机
已实名认证

110

主题

2218

回帖

5450

积分

版主

积分
5450
发表于 2025-4-17 13:29:50 | 显示全部楼层

部分程序快速预览:

/*
  引导程序用于AM32电调固件

  基于 https://github.com/AlkaMotors/AT32F421_AM32_Bootloader
 */
#include "main.h"  // 包含主头文件
#include <stdio.h>  // 标准输入输出库

#include "version.h"  // 包含版本信息头文件

/* 包含的头文件 --------------------------------------------------*/
#include "nstdbool.h"  // 包含布尔类型定义头文件
#include <stdio.h>  // 标准输入输出库
#include <stdlib.h>  // 标准库,包含内存分配等函数

#include "eeprom.h"  // 包含EEPROM操作相关头文件


#define USE_P21  // 定义使用P21引脚作为通信引脚

// 禁用应用程序头部检查
// #define DISABLE_APP_HEADER_CHECKS 

// 直接跳转到应用程序并忽略EEPROM
//#define USE_ADC_INPUT    
//#define UPDATE_EEPROM_ENABLE

// 使用逻辑分析仪在输入引脚上检查MCU的时钟配置
//#define BOOTLOADER_TEST_CLOCK

// 启用后,每10ms输出一次字符串"HELLO_WORLD"
// #define BOOTLOADER_TEST_STRING

// 如果没有应用固件,则禁用跳转
//#define DISABLE_JUMP

// 可选地启用串行位敲统计
//#define SERIAL_STATS

/*
  启用软件复位检查以跳转。
  通常在软件复位时我们希望保持在引导程序中,
  如果信号引脚浮动,但禁用此功能对CAN测试有用。
*/
#define CHECK_SOFTWARE_RESET 1

/*
  在跳转前启用EEPROM配置检查。
  禁用此功能对CAN开发有用。
*/
#define CHECK_EEPROM_BEFORE_JUMP 1

/*
  是否应在EEPROM中更新引导程序版本?
 */
#define UPDATE_EEPROM_ENABLE 1

#include <string.h>  // 包含字符串处理函数头文件

#ifndef MCU_FLASH_START  // 如果未定义MCU_FLASH_START
#define MCU_FLASH_START 0xFF0000  // 定义MCU_FLASH_START为0xFF0000
#endif

#ifndef FIRMWARE_RELATIVE_START  // 如果未定义FIRMWARE_RELATIVE_START
#define FIRMWARE_RELATIVE_START 0x1000  // 定义FIRMWARE_RELATIVE_START为0x1000
#endif

// 根据USE_Pxx宏定义选择不同的GPIO引脚和端口
#ifdef USE_P01
#define input_pin        P01  // 定义输入引脚为P01
#define input_port       P0  // 定义输入端口为P0
#define mode_set_pin     GPIO_ModePin_1  // 定义模式设置引脚为GPIO_ModePin_1
#define PIN_NUMBER       1  // 定义引脚编号为1
#define PORT_LETTER      0  // 定义端口字母为0

#elif defined(USE_P11)
#define input_pin        P11  // 定义输入引脚为P11
#define input_port       P1  // 定义输入端口为P1
#define mode_set_pin     GPIO_ModePin_1  // 定义模式设置引脚为GPIO_ModePin_1
#define PIN_NUMBER       1  // 定义引脚编号为1
#define PORT_LETTER      1  // 定义端口字母为1

#elif defined(USE_P21)
#define input_pin        P21  // 定义输入引脚为P21
#define input_port       P2  // 定义输入端口为P2
#define mode_set_pin     GPIO_ModePin_1  // 定义模式设置引脚为GPIO_ModePin_1
#define PIN_NUMBER       1  // 定义引脚编号为1
#define PORT_LETTER      2  // 定义端口字母为2

#elif defined(USE_P50)
#define input_pin        P50  // 定义输入引脚为P50
#define input_port       P5  // 定义输入端口为P5
#define mode_set_pin     GPIO_ModePin_0  // 定义模式设置引脚为GPIO_ModePin_0
#define PIN_NUMBER       0  // 定义引脚编号为0
#define PORT_LETTER      5  // 定义端口字母为5

#else
#error "未定义引导程序通信引脚"  // 如果没有定义任何USE_Pxx宏,则报错
#endif
// 定义一个静态变量用于存储无效命令的计数
static uint16_t invalid_command;

#include "blutil.h"  // 包含引导程序实用工具头文件

#ifndef BOARD_FLASH_SIZE  // 如果未定义BOARD_FLASH_SIZE
#error "必须定义BOARD_FLASH_SIZE"  // 报错提示需要定义FLASH大小
#endif

// 定义PIN_CODE为端口字母左移4位加上引脚编号
#define PIN_CODE (PORT_LETTER << 4 | PIN_NUMBER)

/*
  目前只支持32k、64k或128k闪存
 */
#if BOARD_FLASH_SIZE == 32  // 如果FLASH大小为32k
#define EEPROM_START_ADD (uint32_t)(MCU_FLASH_START+0x7c00)  // 定义EEPROM起始地址
#define FLASH_SIZE_CODE 0x1f  // 定义FLASH大小代码
#define ADDRESS_SHIFT 0  // 地址偏移量为0

#elif BOARD_FLASH_SIZE == 64  // 如果FLASH大小为64k
#define EEPROM_START_ADD (uint32_t)(MCU_FLASH_START+0xF800)  // 定义EEPROM起始地址
#define FLASH_SIZE_CODE 0x35  // 定义FLASH大小代码
#define ADDRESS_SHIFT 0  // 地址偏移量为0

#elif BOARD_FLASH_SIZE == 128  // 如果FLASH大小为128k
#define EEPROM_START_ADD (uint32_t)(MCU_FLASH_START+0x1f800)  // 定义EEPROM起始地址
#define FLASH_SIZE_CODE 0x2B  // 定义FLASH大小代码
#define ADDRESS_SHIFT 2  // 地址偏移量为2,客户端传来的地址需左移2位后使用
#else
#error "不支持的BOARD_FLASH_SIZE"  // 报错提示不支持的FLASH大小
#endif

/*
  devinfo结构体告诉配置客户端我们的引脚代码、FLASH大小和设备类型。
  主固件也可以使用它来确认我们有正确的EEPROM地址和引脚代码。
  我们有两个32位的魔数值,以便主固件可以确认引导程序支持此功能。
 */
#define DEVINFO_MAGIC1 0x5925e3da  // 定义第一个魔数值
#define DEVINFO_MAGIC2 0x4eb863d9  // 定义第二个魔数值

// 定义devinfo结构体并将其放置在特定地址
static const struct {
    uint32_t magic1;  // 第一个魔数值
    uint32_t magic2;  // 第二个魔数值
    const uint8_t deviceInfo[9];  // 设备信息数组
} devinfo _at_ (MCU_FLASH_START + FIRMWARE_RELATIVE_START - 32) = {
        {DEVINFO_MAGIC1},  // 初始化第一个魔数值
        {DEVINFO_MAGIC2},  // 初始化第二个魔数值
        {'4','7','1',PIN_CODE,FLASH_SIZE_CODE,0x06,0x06,0x01,0x30}  // 初始化设备信息数组
};

// 定义函数指针类型
typedef void (*pFunction)(void);

// 定义应用程序地址
#define APPLICATION_ADDRESS     (uint32_t)(MCU_FLASH_START + FIRMWARE_RELATIVE_START)

// 定义各种命令码
#define CMD_RUN             0x00  // 运行命令
#define CMD_PROG_FLASH      0x01  // 编程FLASH命令
#define CMD_ERASE_FLASH     0x02  // 擦除FLASH命令
#define CMD_READ_FLASH_SIL  0x03  // 读取FLASH命令(SIL)
#define CMD_VERIFY_FLASH    0x03  // 验证FLASH命令(重复定义)
#define CMD_VERIFY_FLASH_ARM 0x04  // 验证FLASH命令(ARM)
#define CMD_READ_EEPROM     0x04  // 读取EEPROM命令(重复定义)
#define CMD_PROG_EEPROM     0x05  // 编程EEPROM命令
#define CMD_READ_SRAM       0x06  // 读取SRAM命令
#define CMD_READ_FLASH_ATM  0x07  // 读取FLASH命令(ATM)
#define CMD_KEEP_ALIVE      0xFD  // 保持连接命令
#define CMD_SET_ADDRESS     0xFF  // 设置地址命令
#define CMD_SET_BUFFER      0xFE  // 设置缓冲区命令

// 定义一些静态变量用于接收和处理数据
static uint16_t low_pin_count;  // 低电平计数器
static char receiveByte;  // 接收到的字节
static int count;  // 计数器
static char messagereceived;  // 标记是否接收到消息
static uint16_t address_expected_increment;  // 地址预期增量
static int cmd;  // 命令码
static char eeprom_req;  // EEPROM请求标志
static int received;  // 接收标志

// 定义接收缓冲区和负载缓冲区
static uint8_t xdata rxBuffer[258];  // 接收缓冲区
static uint8_t xdata payLoadBuffer[256];  // 负载缓冲区
static char rxbyte;  // 接收到的字节
static uint32_t address;  // 地址

// 定义一个联合体用于CRC计算
typedef union {
    uint8_t bytes[2];  // 字节数组
    uint16_t word;  // 16位整数
} uint8_16_u;

// 定义一些静态变量用于CRC计算和缓冲区管理
static uint16_t len;  // 数据长度
static uint8_t calculated_crc_low_byte;  // 计算出的CRC低字节
static uint8_t calculated_crc_high_byte;  // 计算出的CRC高字节
static uint16_t payload_buffer_size;  // 负载缓冲区大小
static char incoming_payload_no_command;  // 标记是否有无命令的有效负载

/* 用户代码开始 */
// 声明一些函数用于发送字符串、接收缓冲区和串行写入字符
static void sendString(const uint8_t dat[], int len);
static void receiveBuffer();
static void serialwriteChar(uint8_t dat);
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 10:58 , Processed in 0.118614 second(s), 90 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表