STM32 板上的 I/O 设备实现框架
STM32 开发板的功能概述
先决条件
要开始,您需要安装 STM32CubeIDE 和 STM32CubeProg,之后您需要获取一个 ST-LINK V2
设备和一个 STM32F411CEU6
开发板,通常被称为 Black Pill 开发板。
特性丰富度和性能比较
- Black pill > Blue/Red/Purple pill > Green pill > Arduino 板
基本 API 函数列表
GPIO_PIN_SET
和 GPIO_PIN_RESET
的名称来自 SR 触发器 (learnabout-electronics.org)
HAL_GPIO_WritePin()
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); HAL_GPIO_WritePin(GPIOE, LED1_Pin, GPIO_PIN_SET); // LED1 is turned on HAL_GPIO_WritePin(GPIOE, LED1_Pin, GPIO_PIN_RESET); // LED1 is turned off
HAL_GPIO_ReadPin()
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); GPIO_PinState LED1_PinState = HAL_GPIO_ReadPin(GPIOE, LED1_Pin); HAL_GPIO_WritePin(GPIOE, LED2_Pin, LED1_PinState); HAL_GPIO_WritePin(GPIOE, LED3_Pin, LED1_PinState);
HAL_Delay()
void HAL_Delay(uint32_t Delay); HAL_Delay(500); // Wait 500 ms
引导加载程序编程
在 STM32CubeIDE
中,创建一个新项目,将 STM32F411CEU6
作为商品编号
然后按顺序执行这些操作
- 下一篇
- 项目命名
- 结束
- 等待软件包下载
您现在看到的是所选的 MCU
为了能够关注正常或编程模式,LED 可以帮助实现这一点。
左键单击 PB10 引脚,选择 GPIO_Output ,然后在 System Core 选项卡中,选择该引脚并将其输出电平设置为高电平。
在电子板上,将 LED 物理连接到 B10 引脚并将其接地。
然后我们必须设置一个时钟设备(System Core 选项卡)
之后,我们可以在 Connectivity 和 Middleware 选项卡中设置 USB 功能
我们选择 自定义 HID 类
而不是 HID 类
,因为 自定义 HID 类
提供了读取 HID 数据包的可能性。
打开 Clock Configuration 选项卡,点击 Resolve Clock Issues,然后按 Ctrl-S 生成代码
单击锤子附近选择 Release 以生成 elf 格式的二进制文件。
抓住您的 STM32
板,并将其背面引脚连接到 ST-LINK V2
的相应引脚
3.3V
到3.3V
SWCLK
到SWCLK
GND
到GND
SWDIO
到SWDIO
完成后,将 ST-LINK V2
连接到 PC。
在 STM32CubeProgrammer
中,单击 Connect 按钮,然后单击 + 按钮访问 Open File。
选择在创建的 STM32CubeIDE
项目的 Release 文件夹中的 *.elf 文件,然后单击 Download 按钮,然后通过 USB-C 端口将 STM32 板插入 PC。
要查看新创建的设备出现在 Windows 上,您只需按板载的 NRST 按钮,您应该看到此,由于未设置 HID 报告描述符,因此出现错误。
固件编程
回到 STM32CubeIDE
,您需要修改一些数据来准备设备。
在 \USB_DEVICE\App\usbd_desc.c 中
使用这些新值更新这些定义
#define USBD_VID 0x0001
#define USBD_PID_FS 0x0001
#define USBD_LANGID_STRING 1033
#define USBD_MANUFACTURER_STRING "Manufacturer Name"
#define USBD_PRODUCT_STRING_FS "Product Name"
#define USBD_CONFIGURATION_STRING_FS "Configuration Name"
#define USBD_INTERFACE_STRING_FS "Interface Name"
在 \USB_DEVICE\App\usbd_custom_hid_if.c 中
将 CUSTOM_HID_ReportDesc_FS[]
替换为
enum HID_Helper { IN_REPORT_ID = 0x02, IN_REPORT_SIZE = 8, // Bit size of one HID packet IN_REPORT_COUNT = 2, // Number of HID packets OUT_REPORT_ID = 0x01, OUT_REPORT_SIZE = 8, // Bit size of one HID packet OUT_REPORT_COUNT = 2, // Number of HID packets }; // Set USBD_CUSTOM_HID_REPORT_DESC_SIZE to 33 __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END = { 0x06, 0x00, 0xFF, // USAGE_PAGE (Vendor Specific) 0x09, 0x01, // USAGE (1) 0xA1, 0xFF, // COLLECTION (Vendor Specific) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255 possibilities = 2 ^ 8 bits) 0x85, IN_REPORT_ID, // REPORT_ID (2) 0x75, IN_REPORT_SIZE, // 0x95, IN_REPORT_COUNT, // 0x09, 0x00, // USAGE (0) 0x81, 0x00, // INPUT (Data,Ary,Abs) 0x85, OUT_REPORT_ID, // REPORT_ID (1) 0x75, OUT_REPORT_SIZE, // 0x95, OUT_REPORT_COUNT, // 0x09, 0x00, // USAGE (0) 0x91, 0x00, // OUTPUT (Data,Ary,Abs) 0xC0 // END_COLLECTION };
要了解有关 HID 报告描述符的更多信息,您可以浏览 人机接口设备 (HID) 信息 | USB-IF
在 \Middlewares\ST\STM32_USB_Device_Library\Class\CustomHID\Src\usbd_customhid.c 中
在 USBD_CUSTOM_HID_SendReport()
之后添加以下代码
uint8_t USBD_CUSTOM_HID_SendReport(USBD_HandleTypeDef* pdev, uint8_t* report, uint16_t len) { // // ... // } extern USBD_HandleTypeDef hUsbDeviceFS; void HID_Send(uint8_t* Data, uint16_t Size) { USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, Data, Size); }
在 USBD_CUSTOM_HID_ReceivePacket()
之后添加以下代码
uint8_t USBD_CUSTOM_HID_ReceivePacket(USBD_HandleTypeDef *pdev) { // // ... // } // Set USBD_CUSTOMHID_OUTREPORT_BUF_SIZE to 3 void HID_Read(uint8_t* Data) { USBD_HandleTypeDef* pdev = &hUsbDeviceFS; USBD_CUSTOM_HID_HandleTypeDef* hhid; hhid = (USBD_CUSTOM_HID_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId]; memcpy(Data, hhid->Report_buf, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE); }
现在我们准备好开始编写固件(在该 IDE 中也称为 App)。
在 \Core\Src\main.c 中
将 main()
替换为
enum HID_Helper
{
RID_SIZE = 1, // Report ID is 1 byte size
IN_REPORT_COUNT = 2,
OUT_REPORT_COUNT = 2,
IN_REPORT_ID = 0x02,
OUT_REPORT_ID = 0x01,
};
uint8_t HostOutBuffer [RID_SIZE + OUT_REPORT_COUNT];
uint8_t HostInBuffer [RID_SIZE + IN_REPORT_COUNT ];
uint8_t DeviceOutBuffer[RID_SIZE + OUT_REPORT_COUNT];
uint8_t DeviceInBuffer [RID_SIZE + IN_REPORT_COUNT ];
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USB_DEVICE_Init();
while (1)
{
//
// Copy data sent by the PC
//
HID_Read(DeviceOutBuffer);
//
// Build IN buffer with the data
//
DeviceInBuffer[0] = IN_REPORT_ID;
DeviceInBuffer[1] = DeviceOutBuffer[1];
DeviceInBuffer[2] = DeviceOutBuffer[2];
//
// and send it back to PC for feedback purpose
//
HID_Send(DeviceInBuffer, RID_SIZE + IN_REPORT_COUNT);
HAL_Delay(500);
}
}
现在,我们拥有一个 STM32
板,该板能够获取可以从 PC(也称为主机设备)配置的数据,并且能够将此数据传输回主机设备。
最后,我们可以重建并将新的二进制文件上传到 STM32
板。
为了能够与此板交互,我们可以使用两种工具。
一个 USB 嗅探器,例如 Busdog 和一个 USB HID 通信工具
FS 代表 USB 规范的全速
LS = Low Speed = 1.5 Mbps FS = Full Speed = 12 Mbps HS = High Speed = 480 Mbps SS = SuperSpeed = 5 Gbps SS+ = SuperSpeed+ = 10 Gbps SS+ = SuperSpeed+ = 20 Gbps
历史
- 2021 年 7 月 16 日:初始版本