Bài 16: Lập trình STM32 USB CDC truyền nhận dữ liệu qua cổng COM ảo

stm32 usb cdc

Giao thức USB nói chung và STM32 USB CDC nói riêng là một giao thức khá khó lập trình. Nhưng ST đã hỗ trợ lập trình viên rất nhiều bằng cách tạo ra các gói Middleware USB có sẵn. Việc của chúng ta là học cách sử dụng API của các Middleware đó.

Bài 16 trong Serie Học lập trình STM32 từ A tới Z

Giao thức usb là gì?

USB (Universal Serial Bus) là một chuẩn kết nối nối tiếp đa dụng trong máy tính, dùng để kết nối các ngoại vi với máy tính theo quy chuẩn Plug and Play (cắm và chạy). Với tính năng cắm nóng thiết bị (không phải khởi động lại hệ thống), việc kết nối trở nên đơn giản hơn rất nhiều.
Giao thức USB được phát hành vào năm 1996, hiện đang được duy trì bởi tổ chức USB-IF (theo Wikipedia).

Đã có bốn thế hệ USB, gồm: USB 1.x, USB 2.0, USB 3.x và USB4.

Giao thức USB rất thông dụng

Một số kiến thức cơ bản về giao thức usb

Kiến trúc hệ thống USB

Một hệ thống USB được mô tả bởi 3 định nghĩa:

  • USB Host: chỉ có 1 Host duy nhất trong hệ thống (thông thường là máy tính cá nhân hoặc máy tính nhúng). Host điều khiển mọi luồng dữ liệu và cách thức giao tiếp trong hệ thống.
  • USB Device: một hệ thống có thể có nhiều Device, đóng nhiều vai trò như: thiết bị tương tác với người dùng (HID), lớp giao tiếp (CDC), lưu trữ dữ liệu (MSC), mở rộng cổng kết nối (HUB)…
  • USB Interconnect: kiểu kết nối để các thiết bị USB có thể giao tiếp được với Host.

Kiến trúc bus: về mặt vật lý, bus USB có dạng hình sao nhiều tầng, với Host là trung tâm. Mỗi nhánh là 1 kết nối giữa Host với Hub, Host với Device hoặc Hub với Device. Với 7 bit địa chỉ, một Host có thể quản lý tối đa 127 thiết bị.

kiến trúc của hệ thống USB
hệ thống USB

Cấu trúc điều khiển truyền nhận

Để tất cả các thiết bị trong cùng hệ thống hiểu nhau, chúng phải tuân thủ quy tắc điều khiển truyền nhận (Control Transfer).

control transfer

Một gói Control Transfer được chia thành 3 Transaction:

  • Setup Transaction: thiết lập
  • Data Transaction: dữ liệu
  • Status Transaction: trạng thái

Mỗi Transaction lại chia thành các gói tin:

  • SETUP hoặc IN/OUT (Token): gói thông báo, cho biết dữ liệu phía sau dùng để làm gì, được xác định bởi mã Token tương ứng
  • DATA: gói chứa dữ liệu truyền của transaction
  • ACK (Handshake): gói bắt tay, thông báo dữ liệu truyền thành công hay thất bại

Mỗi gói tin (Packet) lại bao gồm các trường riêng, trong đó có 3 trường (field) bắt buộc trong mọi gói tin là:

  • SYNC: trường đồng bộ, thông báo thời điểm bắt đầu gói
  • PID (Packet Identifier): trường định danh gói tin, cho biết gói tin này dùng làm gì, hướng dữ liệu của gói. Nếu là gói bắt tay, nó cho biết đã truyền nhận thành công hay chưa
  • EOP (End of Packet): trường kết thúc, cho biết gói tin đã kết thúc
  • Các trường còn lại tùy thuộc vào kiểu gói tin

Các kiểu truyền nhận trong USB

Chuẩn USB định nghĩa 4 kiểu transfer (cũng có thể gọi là 4 kiểu endpoint), bao gồm:

  1. Control transfer
  2. Interrupt transfer
  3. Bulk transfer
  4. Isochronous transfer

Tài liệu về giao thức USB

Nói về USB thì cần rất nhiều tài liệu mới có thể hiểu hết được, nhưng để hiểu ở mức cơ bản thì bạn có thể đọc cuốn USB in a Nutshell. Cuốn này khá cô đọng và không quá dài như các tài liệu khác.

Link: https://drive.google.com/open?id=1wEQKyJVl3d0I6MbVtHehQ1Ciqf878DOC

Hoặc tham khảo các tài liệu khác tại vidieukhien.org: http://vidieukhien.org/mot-so-tai-lieu-co-ban-ve-usb.html

Giao thức Usb cdc trên stm32

USB CDC là gì?

USB CDC (Communications Device Class) hiểu đơn giản là lớp thiết bị giao tiếp qua USB. Nghe có vẻ hơi khó hiểu, nhưng bạn có thể hiểu rằng nó được dùng để các thiết bị trao đổi dữ liệu với nhau, chứ không tương tác trực tiếp với con người như lớp HID (chuột, bàn phím).

Các thiết bị thuộc lớp này cũng được triển khai trong các hệ thống nhúng như điện thoại di động, để điện thoại có thể được dùng làm modem, fax hoặc cổng mạng. Với STM32, CDC được dùng nhiều nhất ở dạng cổng COM ảo (Virtual COM Port): máy tính nhìn thấy STM32 như một cổng COM, dùng y hệt UART nhưng không cần mạch chuyển đổi USB to UART.

STM32 USB CDC

STM32F103C8T6 chỉ hỗ trợ USB kiểu Device, nên ta sẽ sử dụng KIT Blue Pill như một thiết bị để truyền nhận dữ liệu với máy tính. Cách thức giao tiếp đã được chuẩn hóa trong thư viện USB của CubeMX, vậy nên trong bài này chúng ta sẽ không đi sâu vào phần đó nữa, mà tập trung vào việc sử dụng dữ liệu truyền nhận được.

Lập trình stm32 usb cdc

Thiết lập STM32 Usb CDC trên Cube MX

Mở CubeMX lên, trong tab SYS chọn Debug Serial Wire.

STM32 USB CDC 1

Tab RCC chúng ta chọn nguồn dao động là thạch anh ngoài HSE.

STM32 USB CDC 2

 

Trong Connectivity chọn USB và tick vào Device (FS), tức là USB Device Full Speed.

STM32 USB CDC 3

Phần Middleware chọn USB_DEVICE, Class chọn Communication Device Class (Virtual Port Com). Chỉnh sửa kích thước Buffer truyền và nhận, ở đây mình sử dụng 64 byte.

STM32 USB CDC 4

Chuyển qua tab Clock Configuration, chọn tần số cho bộ USB là 48MHz (bắt buộc). Tần số hệ thống có thể chọn cao hơn, ở đây mình chọn 48MHz.

STM32 USB CDC 5

Đặt tên, chọn IDE sau đó Gen code.

STM32 USB CDC 6

Lập trình STM32 Usb CDC với Keil C

Mở Project vừa tạo, chọn file usbd_cdc_if.c. Thêm code vào hàm CDC_Receive_FS như hình.

STM32 USB CDC 7

Giải thích code:

Khi có một gói tin truyền đến, thư viện sẽ gọi hàm CDC_Receive_FS, bên trong đó lệnh USBD_CDC_ReceivePacket(&hUsbDeviceFS); sẵn sàng nhận gói tiếp theo.

Dữ liệu nhận được sẽ được lưu tại biến UserRxBufferFS.

Sau đó chúng ta gửi dữ liệu trả lại với độ dài lấy từ hàm strlen((const char*)UserRxBufferFS) – 1. Tại sao lại trừ 1? Vì khi gửi từ Terminal, cuối chuỗi thường có thêm kí tự xuống dòng (Enter), mình bỏ kí tự này đi để chuỗi gửi lại gọn hơn.

Sau khi gửi xong, chúng ta xóa UserRxBufferFS để chuẩn bị nhận gói tiếp theo.

Lưu ý: Hàm CDC_Receive_FS có sẵn tham số *Len là số byte thực sự nhận được. Dùng *Len sẽ an toàn hơn strlen(), vì nếu dữ liệu nhận về là dạng nhị phân có byte 0x00, hoặc buffer chưa được xóa sạch, strlen() sẽ tính sai độ dài.

Cài đặt Driver STM32 Usb CDC

Khi nạp xong cho Blue Pill, chúng ta cắm dây micro USB vào KIT và kết nối với máy tính. Nếu máy tính chưa có driver cho thiết bị, nó sẽ báo như hình.

Programming STM32F103 Board Blue Pill using USB Port

Để sử dụng được Virtual COM Port chúng ta cần cài Driver để máy tính biết cần giao tiếp với thiết bị nào, cũng giống như khi bạn cài driver cho mạch USB to COM dùng PL2303 hoặc CH340 vậy.

Nhấn vào link để tải về: https://www.st.com/en/development-tools/stsw-stm32102.html

STM32 USB CDC 8

Tải bản phù hợp với máy tính của bạn rồi cài đặt. Sau khi cài xong, mở Device Manager xem đã nhận chưa, hiển thị giống hình là đã cài đúng. Với Windows 10 trở lên, driver CDC đã có sẵn nên thường cắm vào là nhận luôn.

STM32 USB CDC 9

Lưu ý: Nhiều KIT Blue Pill hàn sai điện trở kéo lên chân D+ (R10 là 10kΩ hoặc 4.7kΩ thay vì 1.5kΩ chuẩn), nên một số máy tính không nhận thiết bị hoặc báo “Unknown USB Device”. Gặp lỗi này các bạn thay R10 bằng 1.5kΩ, hoặc hàn thêm 1 con 1.8kΩ nối giữa PA12 và 3.3V là được.

Gửi dữ liệu lên STM32 USB CDC với Hercules Terminal

Sau khi đã cài đặt xong, chúng ta mở phần mềm Hercules Terminal, chọn cổng COM tương ứng. Nếu bạn chưa có phần mềm có thể tham khảo bài viết: Hướng dẫn sử dụng Hercules Terminal

STM32 USB CDC 10

Gửi dữ liệu bất kì xuống, mạch sẽ phản hồi lại đúng dữ liệu đó. Với cổng COM ảo, baud rate chọn bao nhiêu cũng được vì dữ liệu thực chất đi qua USB.

Kết

STM32 USB CDC được sử dụng rất nhiều trong việc truyền nhận giữa các thiết bị nhúng với nhau hoặc với máy tính, vì tính tiện dụng, hiệu quả và tốc độ nó mang lại.

Nếu bạn thấy bài viết này có ích hãy chia sẻ với bạn bè mình và cùng vào nhóm những Anh Em Nghiện Lập trình nhé!!!

5/5 - (1 bình chọn)

1 những suy nghĩ trên “Bài 16: Lập trình STM32 USB CDC truyền nhận dữ liệu qua cổng COM ảo”

  1. Vu Duy nói:

    anh cho em hỏi với. Giờ em đang dùng con camera OV 7670 thu hình ảnh về rồi qua STM32 rồi từ STM32F103c8
    qua cổng USB cho về máy tính liệu có được không ạ

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *