美文网首页
STM32F1 F4 USB 工程更新

STM32F1 F4 USB 工程更新

作者: 小鱼儿他老汉 | 来源:发表于2019-06-24 22:02 被阅读0次

    现状

    • 基于STM32CubeMX的F103/F40X的USB堆栈测试完毕;
    • 基于Mbed OS的F103/F40X的USB堆栈测试完毕;
    • 主要测试USB CDC设备;
    • 基于USB ACM/CDC实现nRF24L01及类似“小无线”系统集成;
    • 基于USB ACM/CDC开发了VT100 cmdline
    • 基于USB ACM/CDC和cmdline实现SPI NOR Flash的读写;
    • 基于USB ACM/CDC开发HCI定制协议;
    • 基于Linux udev的USB设备插入拔出时间的检测;

    计划

    • 开发其他TLV类型二进制协议和基于字符串的JSON RPC等协议;
    • 实现xmodem传输;
    • 实现I2C设备扫描与访问;
    • 更新现有的LoRaPHY/Aloha/LoRaWAN USB Dongle;
    • 支持C8T6/RCT6等多种核心板,以应对更加复杂的堆栈;
    • 支持USB ECM,以直接支持6LowPAN等物联网设备;
    • 集成Arduino STM32的Bootloader实现固件升级。

    开源设计与板级产品

    • 大部分设计都是开源设计;
    • 或有根据客户要求定制进行设计;

    代码设计过程

    以下内容针对Mbed C++和STM32F103/F407

    今天完成的主要是在USB通道上实现VT100 cmdline,可以通过TeraTerm终端来配置管理设备,或者通过专门的cmd/GUI上位机程序实现自动化配置。最早基于C和串口,在Mbed Serial类上移植也很容易。但是在USB信道上实现cmdline很花费了一些时间,且有了反复。主要原因是USB对象初始化的特殊性,以及Mbed C++与基于标准库或HAL库的原始设计的差异所造成的。

    基于标准库或者HAL库的模板一般是:

    • 将所需硬件资源(串口、GPIO)声明为main的全局变量
    • 将USB声明为 extern 全局变量
    • 在主函数中配置时钟,初始化这些硬件资源
    • 展开应用逻辑

    发现STM32 CubeMX的USB实例是usb_device.c中的全局变量。 这和一般的硬件资源如GPIO/ADC/PWM/CAN/UART都有所不同。

    // Private in main.c
    CAN_HandleTypeDef hcan;
    RTC_HandleTypeDef hrtc;
    UART_HandleTypeDef huart1;
    
    int main(void){
      HAL_Init();
      SystemClock_Config();  // RCC init before any other resources
      MX_GPIO_Init();
      MX_CAN_Init();
      MX_USART1_UART_Init();
      MX_RTC_Init();
      MX_USB_DEVICE_Init();  // USB init here
      while(1){
        ...
      }
    }
    

    main.c

    USBD_HandleTypeDef hUsbDeviceFS;
    
    void MX_USB_DEVICE_Init(void)
    {
      USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);
      USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);
      USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);
      USBD_Start(&hUsbDeviceFS);
    }
    
    

    usb_device.c

    extern USBD_HandleTypeDef hUsbDeviceFS;
    

    usb_device.h

    而基于Mbed C++有些特殊。

    DigitalOut myled(DBG_LED);  // See main.h for hardware issue
    cmdline cmdhandler;
    // You can put USBSerial/USBTerminal here, but will not be enumerated in F103
    //USBSerial usbSerial(0x1f00, 0x2012, 0x0001,  false); 
    USBTerminal *term;
    
    int main(){
      confSysClock();  // RCC init first
      Serial    uart(PA_9, PA_10, 115200);
      //USBSerial usbSerial(0x1f00, 0x2012, 0x0001,  false); 
      USBTerminal usbSerial(0x1f00, 0x2012, 0x0001,  false);
      term = &usbSerial;  
    }
    

    main.cpp

    USB对于时钟是非常敏感的,所以必须在系统时钟配置正确后才能够产生USB对象。

    在Mbed C++中,在调用main函数之前,进行时钟配置和对象实例化。RCC时钟配置隐藏在Mbed Library中,如果对象在Main函数之外,视为公有对象,也在main函数之前进行实例化。

    如果将USB对象作为公有对象,F407工作正常,而F103工作不正常,表现在枚举失败。换而言之,在F407代码中,可以将USBSerial/USBTerminal在main函数之外声明,且工作正常。但是F103代码中,同样的代码,编译通过,但是枚举失败。

    所以第三方开发者打了一个补丁,在main函数中增加了一个confSysClock()。有兴趣的话,可以查看RCC寄存器的数值。

    由于时钟是main函数中调用的,间接造成USB对象(USBSerial及其子类USBTerminal)是main函数中的对象,其他模块和函数无法访问。

    解决方法是在main.cpp中预留一个USB对象指针,让其他函数和其他模块可以访问到USB对象。代价是USB对象的所有方法必须采用“->”来访问。这也就导致了基于Serial对象和USB对象的代码存在两套,这实在违背了OOP的原则。

    由此看来,基于Serial对象,基于F103的USBSerial,基于F407的USBSerial的通道,居然出现了两套(确切地说是2.5套)代码。这种情况可能同样会影响到其他协议,包括HCI/SIP/TLV/JSON等。

    对于ARM来说,USB不是IoT的一部分。他们的IoT/Connectivity主要包括的是Cellular Modem/WiFi/BLE/LoRaWAN/BLE/TLS/MQTT等。

    要合并代码,还需要开发者自己动手。要么统一为指针类型;要么期待Mbed底层得到修改。然而这些代码都是基于Mbed 2,而Mbed 5并没有对USB堆栈进行维护。需要开发者自己Backport。代码在此:ARM Mbed OS STM32F103的系统时钟配置代码

    相关文章

      网友评论

          本文标题:STM32F1 F4 USB 工程更新

          本文链接:https://www.haomeiwen.com/subject/pwuaqctx.html