STM32F072 CAN and USB

1 通用描述
1.1 STM8
MOSTek 6502 -> ST7 -> STM8
STM8型号单片机分为STM8A、STM8L、STM8S三个系列。
STM8A:汽车级应用
STM8L:超低功耗MCU
STM8S:标准系列

1.2 STM32
- F1系列用的最多,最大工作频率72MHz
- STM32固件库(函数)使用手册
STM32F107:2010,DWC2 FS OTG
STM32MP157C-DK2:MPU
STM32U5:U means ULP

1.3 ST开发板种类
ST官方出的有NUCLEO板、Discovery板以及评估板,配置从低到高,价格也是从低到高。
NUCLEO:一般只将MCU引脚引出,还有一个串口(通过STLINK USB虚拟),价格也就几十到100RMB左右。
Discovery板:一般比NUCLEO板多USB(MCU带USB),音频解码,耳机插孔。价格也就100多点。
评估板:功能是最全的,一般外设都有引出,功能最全,价格最高,几百到1000+RMB。

1.4 STM32 GPIO Alternate function mapping
GPIO复用功能要查找的是datasheet。TRM中是详细的寄存器描述,但不包括GPIO复用功能的描述。

2 开发环境搭建
2.1 STM32CubeMX_V4.27.0
www.st.com/stm32cubemx

STM32CubeMX可以生成Atollic公司的TrueSTUDIO项目文件。

2.2 IAR8.30.1
IAR embedded Workbench 8.30
https://m.baidu.com/ala/c/m.3322.cc/mip/40168.html

3 CAN
3.1 CAN分类
PT CAN:PowerTrain CAN,动力总成
CH CAN:Chassis CAN,底盘控制CAN总线
Body CAN:车身控制总线,BMW Body Domain Controller or Basis Central Platform
Info CAN:娱乐系统总线
Diag CAN:诊断控制总线

3.2 CAN速率
同时支持速率500 Kbps和2 Mbps;BMS充电器CAN默认通信传输速率为250 kbit/s。
CAN:payload的长度是固定的8个字节
CAN FD:payload的长度不是8个字节的都是FD;CAN FD包头和payload用不同的速度传输,速率切换从BRS位(bit rate switching)开始一直到CRC(包括CRC)结束

3.3 STM32F072
3.3.1 bxCAN pinout
PB8: CAN Rx
PB9: CAN Tx
STM32F072 Discovery board, without CAN Transceiver MCP2551.

3.3.2 bxCAN Rx filter
bxCAN: Basic Extended CAN
3个发送邮箱,每个发送邮箱包括4个寄存器:
CAN_TIxR[31:21]存放11bits ID
CAN_TDTxR[3:0]存放数据长度DLC
CAN_TDLxR和CAN_TDHxR存放8个字节的payload
2个接收邮箱,每个接收邮箱包括4个寄存器:
CAN_RIxR[31:21]存放11bits ID
CAN_RDTxR[3:0]存放数据长度DLC
CAN_RDLxR和CAN_RDHxR存放8个字节的payload

ID寄存器32bit CAN_FxR1,Mask寄存器32bit CAN_FxR2。CAN接收过滤类似于Marvell 88Q5050交换机的ACL过滤机制,包含数据寄存器,和对应的mask寄存器。mask寄存器某位为1表示接收到的CAN ID对应的位必须与数据寄存器对应的位相同,mask寄存器某位为0表示不关心接收到的CAN ID对应的位,这种内存的类型称为TCAM。
Mask Data Meaning
0        x        Don't care. The data bit can be a one or a zero.
1        0        Hit on 0.
1        1        Hit on 1.

3.4 STM32F072 CANable
3.4.1 PCAN USB
深圳嘉立创打样
STM32F042/072, SRAM 1024 bytes, last 256 bytes are exclusively shared with CAN peripheral.
STM32F405/407 for PCAN USB Pro.

STM32F072
PA8: OTG_FS_SOF, Synopsys DWC OTG
PA11: USB FS DM
PA12: USB FS DP
PA13: SWDIO
PA14: SWCLK
PB8: CAN0_Rx
PB9: CAN0_Tx
PB14: USB HS DM. Waveshare USB3300 PHY Module from TB.
PB15: USB HS DP. Waveshare USB3300 PHY Module from TB.
BOOT0-PF11
一旦开启了USB电源,即USB_CNTR.PDWN位清零,PA11和PA12将不再作为其它功能使用,仅供USB使用,自动作为DM和DP,不需要手工配置IO MUX。

3.4.2 CANable
CANable is based on STM32Cube.
下载ARM官方的arm-none-eabi-gcc编译器。
GNU Arm Embedded Toolchain
gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 

github上搜索CANable。
https://github.com/moonglow/pcan_cantact
make canable
find -name *.bin

3.4.3 Standard PCAN
The STM32F072 has up to 16 mono-directional or 8 bidirectional endpoints.
USB SRAM(0x4000_6000)偏移地址0到ENDP0_RXADDR之间的buffer用来存储端点的参数,每个端点参数有4个寄存器,每个寄存器占用2个字节,分别表示双向EP的接收packet和发送packet的位置和大小。Refer to Src/usbd_conf.c USBD_LL_Init().
Both USB and bxCAN do not support DMA.
Linux: drivers/net/can/usb/peak_usb/pcan_usb.c
CANable: Src/pcan_usb.c
4 endpoints: two for command IN/OUT, another two for message IN/OUT.
CMDOUT / MSGOUT: device_data_out()
CMDIN: pcan_usb_send_command_buffer()
MSGIN: pcan_flush_data()
CMDIN / CMDOUT: 1-byte func +
    1-byte number (GET or SET) +
    14-byte param
MSGOUT: 1-byte prefix +
    1-byte rec_count +
    1-byte status +
    4 or 2-byte ID +
    (DLC = status & 0xf)-byte data + 
    extra_byte (if SRR = 1)

每一个Full-speed USB_EP_MSGIN MPS(Max Packet Size)可以包含多个PCAN消息(Aggregation mode),并且第一个PCAN消息的时间戳是2个字节,从第二个开始的PCAN消息时间戳都是1个字节。下一个Full-speed MPS报文重复该模式。
MSGIN: 1-byte prefix +
    1-byte rec_count +
    1-byte status +
    4 or 2-byte ID +
    2 or 1-byte timestamp +
    (DLC = status & 0xf)-byte data +
    extra_byte (if SRR = 1)
status: bit7 = timestamp, bit6 = internal, bit5 = ext_ID, bit4 = RTR (Remote Transmission Request)
29-bit ID = 4-byte ID >>= 3
11-bit ID = 2-byte ID >>= 5
SRR = ID.bit0, Substitute Remote Request

3.4.4 Debug
1) Windows PCAN-View
When PCAN-View starts, it will send the below five commands.
05: PCAN_USB_CMD_CFG
01: PCAN_USB_CMD_BITRATE
03: PCAN_USB_SET_SILENT_MODE
0b: PCAN_USB_CMD_LED
03: PCAN_USB_CMD_BUS

2)status packet
03 02 01, CAN bus active, then call pcan_timesync_event() sends the timestamp frame 02 02 42 04 01 b1 28 40 01 00 to PC periodically for about 1 second.
2-byte header: 02 02
1-byte status: 42
1-byte function: 04, PCAN_USB_REC_TS
1-byte number: 01
2-byte timestamp: b1 28
1-byte status: 40
1-byte function: 01, PCAN_USB_REC_ERROR
1-byte number: 00

3) CANable patch
MSGIN: 14 x Max_Packet_Size = 14 x 64-byte, the first PCAN packet in each 64-byte has two bytes timestamp.
Add a variable msg_count to pcan_rx_can_frame(), append the 4-byte to status packet.
The first 5-byte of status packet: 02 02 42 04  01
The third 3-byte of PCAN packet: 02 01 08

Change CANable VID from 0x0483 (STMicroelectronics) to 0x0C72, otherwise Windows PCAN_USB.inf cannot recognize CANable because of driver signature issue.
Windows PCAN-View sends PCAN_USB_CMD_BITRATE to CANable twice, the second command will cause STM32F072 bxCAN does not work, after apply the below patch, the issue will be gone.
case PCAN_USB_CMD_BITRATE:
  if (pcan_device.bus_active)
    pcan_can_set_bus_active(0);
  pcan_device.can.btr0 = cmd->param[1];
  pcan_device.can.btr1 = cmd->param[0];
  pcan_set_bitrate( cmd->param );
  if (pcan_device.bus_active)
    pcan_can_set_bus_active(
      pcan_device.bus_active);

4) Bit timing
STM32F072 CANbps = APB1_clock / BRP / (tseg1 + tseg2 + 1)
PCAN-View发送给CANable下位机的有关时序的4个参数中sjw、tseg1和tseg2是三个数组的索引,索引到三个值后分别减去1,再写入CAN_BTR寄存器,而brp的数值做特殊处理后,再减去1写入CAN_BTR寄存器。
从函数SystemClock_Config中找出APB1 bxCAN的时钟信息,APB1的时钟是48 MHz。

500 kBit/s
APB1: 48 MHz
tseg1 = c -> CAN_BS1_13TQ -> 13
tseg2 = 1 -> CAN_BS2_2TQ -> 2
brp = 0 -> 1 x 6 -> 6
sjw = 0 -> CAN_SJW_1TQ -> 1

4 USB
4.1 USB SRAM
USB SRAM base: 0x4000_6000
STM32F072/042是2014年发布的产品。STM32F072/042上对STM32F103的USBD做了改进,0x400空间里面塞下了1024B的SRAM,而且最后面的256B可以分给CAN专用,前面768B给USBD,完美解决了STM32F103的USBD和CAN不能同时使用的问题。除此之外,STM32F072/042还增加了LPM、DP上拉电阻;尤其是DP上拉电阻,节省一个电阻和一个IO,是非常好的改进。

4.2 Flash and SRAM Base Address
STM32F042/072 bootROM supports USB DFU. The built-in USB IP is legacy, not DWC.
On-chip Flash base address: 0x0800_0000, 1 Kbyte page
On-chip RAM base address: 0x2000_0000, SRAM data bus is 36 bits because 4 bits are available for parity check (1 bit per byte) in order to increase memory robustness.

4.3 DFU Tool
Refer to AN2606 to get what STM32 devices support DFU bootloader.
Use Zadig to replace DFU driver with WinUSB.
https://zadig.akeo.ie/
https://dfu-util.sourceforge.net/
dfu-util -d 0483:df11 -a 0 -s 0x08000000 -D xx.bin

There is a web to implement USB DFU based on the draft WebUSB specification (based on WinUSB, Javascript API, Chrome 61, in 2018).

4.4 VCP
STM32F0x2xx USB FS device library: UM1717
1)添加CDC ACM的3个端点时,顺序排在PCAN的4个端点之后,中间不能有端点不用,否则Windows 10 CDC ACM不工作。
2)CAN_MSGIN和VCP_DATIN双方会互抢带宽,所以VCP发送到PC的日志要尽可能少。
3)VCP的setup bRequest只要实现0x20(SET)和0x21(GET)。

typedef struct usb_interface_assoc_descriptor {
  uint8_t bLength;
  uint8_t bDescriptorType;
  uint8_t bFirstInterface;
  uint8_t bInterfaceCount;
  uint8_t bFunctionClass;
  uint8_t bFunctionSubClass;
  uint8_t bFunctionProtocol;
  uint8_t iFunction;
} USB_INTERFACE_ASSOC_DESCRIPTOR;

typedef struct usb_cdc_header_desc {
  uint8_t bLength;
  uint8_t bDescriptorType;
  uint8_t bDescriptorSubType;
  uint16_t bcdCDC;
} USB_CDC_HEADER_DESC;
typedef struct usb_cdc_call_mgmt_descriptor {
  uint8_t bLength;
  uint8_t bDescriptorType;
  uint8_t bDescriptorSubType;
  uint8_t bmCapabilities;
  uint8_t bDataInterface;
} USB_CDC_CALL_MGMT_DESCRIPTOR;
typedef struct usb_cdc_acm_descriptor {
  uint8_t bLength;
  uint8_t bDescriptorType;
  uint8_t bDescriptorSubType;
  uint8_t bmCapabilities;
} USB_CDC_ACM_DESCRIPTOR;
typedef struct usb_cdc_union_desc {
  uint8_t bLength;
  uint8_t bDescriptorType;
  uint8_t bDescriptorSubType;
  uint8_t bMasterInterface0;
  uint8_t bSlaveInterface0;
} USB_CDC_UNION_DESC;

static struct usb_cdc_line_coding line_code = {
  .dwDTERate = 9600,
  .bCharFormat = 0, /* stop bits-1 */
  .bParityType = 0, /* none */
  .bDataBits = 8, /* nb. of bits 8 */
};

include <stdarg.h>
void usb_printf(const char *fmt, ...)
{
  USBD_HandleTypeDef *pdev = &hUsbDeviceFS;
  va_list args;
  uint32_t len;
  char buf[APP_TX_DATA_SIZE];

  if (pdev->dev_state !=
      USBD_STATE_CONFIGURED)
    return;


  va_start(args, fmt);
  len = vsnprintf(buf,
        (APP_TX_DATA_SIZE - 1),
        fmt, args);
  va_end(args);
  buf[len] = '\0';

  if (pdev->ep_in[VCP_USB_EP_DATIN & 0xFU].total_length)
    return;
  pdev->ep_in[VCP_USB_EP_DATIN & 0xFU].total_length =
    (len + 1);
  USBD_LL_Transmit(pdev,
    VCP_USB_EP_DATIN,
    (uint8_t *)buf,
    (len + 1));
}
Download Davidozzoo / STM32-USB-VCP from github.

4.5 socketCAN
sudo ip link set can0 type can bitrate 500000 restart-ms 100
sudo ip link set up can0
sudo apt install can-utils
candump can0
CAN identifier: 456h
CAN data: 00h FFh AAh 55h 01h 02h 03h 04h (8 bytes)
cansend can0 456#00FFAA5501020304

5 STM32软件实施USB PD协议
USB PD通讯使用的是双相标记码(Bi-phase Mark Code,BMC,300KHz,bit rate 600kbps),此码是一种单线通信编码,数据1的传输需要有一次高/低电平之间的切换过程,数据0的传输则是固定的高电平或低电平。

TX:SPI1从模式MISO当作TX,SPI1 CLK通过配置TIM14产生,工作在600KHz(对应BMC 600kbps),ARR = 72Mhz / 600kbps,PSC = 0,72MHz频率输入,每计数12个(= 72MHz / 600kbps)触发产生一个SPI1从clk时钟。
SPI传输数据过程中总是先发送或接收高字节数据,每个时钟周期接收器或发送器左移一位数据。对于小于16位的数据,在发送前必须左对齐,如果接收的数据小于16位,则采用软件将无效的数据位屏蔽。

RX:TIM1 CH1输入捕获模式并用DMA接收数据。
输入捕获模式下:当捕获单元捕获到外来有效信号边沿事件(通过TIM1 CH1 Capture Compare Enable Register = 0xB设置上升沿和下降沿捕获,STM32库使用宏TIM_ICPolarity_BothEdge = 0x000A配置双边沿触发捕获),将此刻计数器的值锁存到CCR(Capture Compare Register,16bit)影子寄存器并自动将CCR影子寄存器的值拷贝进CCR预装寄存器,以供用户读取。DMA传输方式就是将CCR预装寄存器中的计数值传输到内存中。CCR寄存器中的计数值与上一次的计数值相减 x 计数频率的倒数 = 高电平或者低电平信号宽度。
输入捕获采样的频率就是定时器经过预分配器(PSC)之后的频率,譬如STM32F1 TIM1 CH1的计数器频率等于2.4MHz = 72MHz/(Prescaler + 1),那么计数器计数每增加4个就表示BMC(bit rate 600kbps)的一个bit。解码时,如果连续2次计数间隔之差都小于6,那么这2次计数间隔对应的4b5b bit是1,如果1次计数间隔之差大于6,说明这次4b5b bit是0。

https://github.com/alterapraxisptyltd/chromium-ec/blob/master/chip/stm32

MISO (DAT0): mi s əu
MOSI (CMD): m əu si

6 General Abbreviations
AIRC:Application Interrupt and Reset Register
ARR: Automatic Reload Register
BKP: BackUp
BSP:Board Support Package
CCER: Capture/Compare Enable Register,用来判断当前是下降沿捕获中断还是上升沿捕获中断,同时也能随时改变上升沿捕获还是下降沿捕获
CCR: Capture/Compare Register,表示当前中断发生时的CNT寄存器的值,也就是用来判断时间的;PWM输出时作为占空比寄存器,函数是TIM_SetCompare1(...)
CNT: Counter Register,用来计数的,每个定时器时钟周期自动+1,在需要的时间将其清零,便于计时
CmBacktrace:Cortex Microcontroller Backtrace,是一款针对ARM Cortex-M系列MCU的错误代码自动追踪、定位、错误原因自动分析的开源库
CubeMX:Microcontroller GUI
eCC-USB:eCos Centric USB
GHS:Green Hills Software,提供GHS hypervisor(类似于QNX hypervisor)、仪表专用RTOS、MCU开发IDE
IAR:后两个字母取之于创始人名字Anders Rundgren的首字母,瑞典语Ingenjörsfirman Anders Rundgren,意为Anders Rundgren工程公司
IAR icf:ILINK Configuration File
MDATA:More DATA,USB ep双缓冲(ep_kind配置使能)切换机制对应到DATA0和DATA1
MSP:MCU Specific Package
NVIC:Nested Vectors Interrupts Controller
NVIC IPR:Interrupt Priority Registers
OC:Output Compare(输出比较),用于输出PWM信号;寄存器CNT与CCR比较,大于输出1,小于输出0
PMA:Packet Buffer Memory Area
PSC:PreSCaler register,预分频寄存器
RCC:Reset and Clock Control
RCR:Repetition Counter Register,重复次数寄存器
SHPRx:System Handler Priority Registers
SR: Status Register,用来判断是不是输入捕获中断
ST AMG:Analog and MEMS Group,模拟和MEMS部门(现在改成了Analog, MEMS and Sensors Group)
STM32H7:High-perf Cortex-M7
STM32WB:WB表示集成了Wireless Bluetooth模块
STM32WL:WL表示集成了Wireless LoRa模块
PendSV:Pendable 服务是一个中断请求,如果没有其他中断需要响应时,系统将强制执行上下文切换
SVCall:SuperVisor Call由SVC指令触发,FreeRTOS用它来启动任务调度
USB BH reset:Bigger Hammer or Brad Hosler,表示warm reset;you may be confused why the USB 3.0 spec calls the same type of reset "warm reset" in some places and "BH reset" in other places. "BH" reset is supposed to stand for "Big Hammer" reset, but it also stands for "Brad Hosler". Brad died shortly after the USB 3.0 bus specification was started, and they decided to name the reset after him. The suggestion was made shortly before the spec was finalized, so the wording is a bit inconsistent.

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Version: 2.15.0 (2020-09-28) Keil.STM32F4xx_DFP.2.15.0.pack Download Updated Pack to STM32Cube_FW_F4 Firmware Package version V1.25.1 using HAL Drivers V1.7.9. STM32CubeMX integration (Version 6.0.1): Added support for Timebase Source TIMx (FrameworkCubeMX_gpdsc.ftl). Removed non-existent include path. CMSIS Flash Algorithm: Corrected STM32F42xxx_43xxx_OPT Algorithm. CMSIS SVD: Updated STM32F42*.svd, STM32F43*.svd files. CMSIS-Driver: I2C: Corrected 2 byte reception in master mode. MCI: Replaced empty delay loops with _NOP(). SPI: Corrected PowerControl function (to return error if Initialize was not called, to abort active transfer if power off was requested). Updated GetDataCount function to give accurate count in DMA mode. Corrected Control function (abort in DMA mode, software controlled slave select in slave mode, TI Frame Format selection, ignore bus speed for slave mode). Corrected Uninitialize function (to power off the peripheral if it is powered). Corrected SPI3_SCK pin configuration. Corrected DMA MemDataAlignment configuration. USART: Corrected DMA MemDataAlignment configuration. USBD_HS/USBH_HS: OTG_HS ULPI clock disabled in low power if internal PHY is used to enable proper operation of OTG_HS port in FS mode during CPU sleep. CAN/EMAC/USBD/USBH: Removed macros already provided by cmsis_compiler.h. Updated Boards Examples: Migrated CubeMX projects to V6.0.1 and updated config files. Changed variant selection to "MDK-Plus" where possible. Updated all USB Host/Device examples with user templates from MDK-Middleware v7.11.1. Terminating app_main thread with osThreadExit() to avoid endless loop Updated MS Windows UBS driver files.
Updated Pack to STM32Cube_FW_F4 Firmware Package version V1.25.1 using HAL Drivers V1.7.9. STM32CubeMX integration (Version 6.0.1): Added support for Timebase Source TIMx (FrameworkCubeMX_gpdsc.ftl). Removed non-existent include path. CMSIS Flash Algorithm: Corrected STM32F42xxx_43xxx_OPT Algorithm. CMSIS SVD: Updated STM32F42*.svd, STM32F43*.svd files. CMSIS-Driver: I2C: Corrected 2 byte reception in master mode. MCI: Replaced empty delay loops with _NOP(). SPI: Corrected PowerControl function (to return error if Initialize was not called, to abort active transfer if power off was requested). Updated GetDataCount function to give accurate count in DMA mode. Corrected Control function (abort in DMA mode, software controlled slave select in slave mode, TI Frame Format selection, ignore bus speed for slave mode). Corrected Uninitialize function (to power off the peripheral if it is powered). Corrected SPI3_SCK pin configuration. Corrected DMA MemDataAlignment configuration. USART: Corrected DMA MemDataAlignment configuration. USBD_HS/USBH_HS: OTG_HS ULPI clock disabled in low power if internal PHY is used to enable proper operation of OTG_HS port in FS mode during CPU sleep. CAN/EMAC/USBD/USBH: Removed macros already provided by cmsis_compiler.h. Updated Boards Examples: Migrated CubeMX projects to V6.0.1 and updated config files. Changed variant selection to "MDK-Plus" where possible. Updated all USB Host/Device examples with user templates from MDK-Middleware v7.11.1. Terminating app_main thread with osThreadExit() to avoid endless loop Updated MS Windows UBS driver files.
Version: 2.12.0 (2019-07-17) Keil.STM32F7xx_DFP.2.12.0.pack Download Updated Pack to include subset of STM32Cube_FW_F7 Firmware Package version V1.15.0 using HAL Drivers V1.2.7 Added support for Low Level (LL) drivers. Corrected RTE_Device.h file (I2C3_SDA) Corrected condition for selecting HAL RCC MX_Device_h.ftl: Updated parsing of USART virtual mode Updated generation of macros: Added handling for '(' and ')' symbols Corrected launching STM32CubeMX via "play" button for existing projects overwrites with a new STM32CubeMX project file instead of loading existing. Updated Board Examples: graphics examples use Segger emWin version 5.50.0. examples enable Event Recorder in debug targets Updated LCDConf.c (ready for GUI_USE_ARGD = 1) CMSIS-Driver: CAN: Corrected SetBitrate function to leave Silent and Loopback mode as they were. Corrected SetMode function to clear Silent and Loopback mode when NORMAL mode is activated. Corrected MessageSend function to only access required data for sending. EMAC: Corrected __MEMORY_AT(x) define to be compliant with Arm Compiler 6. Corrected: ETH DMA initialization moved to enable of MAC transmitter or receiver solving netInitialize/netUnnitialize/netInitialize sequence. I2C: Corrected transfers for data sizes greater than 255 (Complete Reload handling). Corrected I2C_SlaveReceive functionality. Corrected code alignment. MCI: Added data cache handling. USART: Added check for valid pointer to USART_PIN prior to use. Corrected POWER_OFF sequence. DMA is DeInitialized after it is aborted. USB Device: Updated USBD_EndpointConfigure function to check that maximum packet size requested fits into configured FIFO (compile time configured). I/O output speed is configurable SPI: Updated SPI_TRANSFER_INFO structure - tx_buf type changed from uint8_t * to const uint8_t *. Added check for valid pointer to SPI_PIN prior to use.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值