Các bác ơi, có ai từng làm giao tiếp PMBus bằng thư viện HAL của STM32 chưa, một con 32 làm master, một con làm slave.

Tôi dùng CubeMX để cấu hình SMBus, thêm gói X_CUBE_SMBUS, tôi thấy trong thư mục Middlewares có stm32_PMBUS_stack và stm32_SMBUS_stack, nhưng không biết bước tiếp theo phải làm gì, tôi không biết cách sử dụng.

Đừng cố gặm mã nguồn cấp thấp trong Middleware, dễ hoa mắt lắm. Cách làm của ST đều giống nhau hết, bạn đã tải gói X_CUBE_SMBUS về rồi thì cứ vào thẳng thư mục cài đặt của gói này (thường nằm trong STM32Cube\Repository) để tìm thư mục Projects. Bên trong chắc chắn sẽ có sẵn các Example tương ứng với một số board phát triển (như NUCLEO hoặc EVAL). Tìm project liên quan đến PMBus, mở thẳng main.cstm32_xx_it.c của nó ra mà xem. Tập trung vào hai thứ: một là hàm xử lý Stack Process được gọi trong vòng lặp chính; hai là hàm Callback được viết như thế nào sau khi slave nhận được Command. Copy mã tầng ứng dụng của nó qua sửa sơ lại là chạy được ngay.

Ông đừng nóng, tài liệu của gói này đúng là viết hơi lộn xộn, lúc xưa tôi xài lần đầu cũng điên đầu thật lâu đó.

Trạng thái của ông lúc này là: đã config xong tầng hardware (CubeMX), nhưng tầng protocol (stack) thì chưa biết ghép vào business code kiểu gì.

Để tôi system lại luồng chính theo ý hiểu của tôi cho, ông cứ làm theo:

Bước 1: Kiểm tra xem ông đã gen ra cấu trúc project chuẩn chưa Khi add X-CUBE-SMBUS trong Software Packs của CubeMX, cửa sổ Mode có hai checkbox: SMBus stackPMBus extension, ông phải tick cả hai vào. Sau khi generate code, project của ông phải có:

  • Middlewares/ST/STM32_SMBus_Stack/ —— Đây là core protocol stack
  • Drivers/BSP/ —— Board support (nếu ông có chọn)

Bước 2: Hiểu cách hoạt động của stack Cái stack này không phải để ông gọi HAL_I2C_xxx đâu, nó wrap thêm một tầng state machine. Code của ông sẽ chủ yếu đánh nhau với 3 hàm sau:

  • STACK_SMBUS_Init() —— Khởi tạo, bind I2C handle
  • STACK_SMBUS_HostCommand() —— Dành cho Host, dùng để initiate một lần giao tiếp
  • STACK_SMBUS_ExecuteCommand() —— Dành cho Slave, callback khi nhận được lệnh

Bước 3: Code Slave thế nào Đối với Slave, quan trọng nhất là CMD_Table, đây là một mảng dùng để báo cho stack biết: „Khi nhận được command code 0x01 thì tôi đọc thanh ghi nào; nhận 0x02 thì tôi ghi thanh ghi nào".

const tSMBUS_CMD_Table MyCmdTable[] = {
    {0x01, MyReadHandler, MyWriteHandler, 1},  // Mã lệnh, callback đọc, callback ghi, độ dài dữ liệu
    {0x02, MyReadHandler2, NULL, 2},
};

Sau đó trong STACK_SMBUS_ExecuteCommand(), ông cứ dựa vào stackhandle.CurrentCommand để dispatch.

Bước 4: Code Host thế nào Host đơn giản hơn nhiều, construct xong command struct rồi gọi STACK_SMBUS_HostCommand(&stackhandle, &cmd) là xong. Lưu ý là hàm này non-blocking nhé, kết quả thì xem stackhandle.State trong interrupt callback.

Lưu ý особо quan trọng:

  • Example chính thức nằm trong thư mục Projects, ông tìm cái khớp với board của mình nhất, ví dụ NUCLEO-G431RB hoặc board Discovery của F072.
  • Chắc chắn phải đọc AN4502, đây là Application Note chính thức, dù khá dày nhưng Chương 8 „Configuration" và Chương 9 „Project example" là cứu cánh đó.
  • Khi nối dây giữa 2 con 32 thì SDA và SCL đều phải kéo lên (pull-up), dù board có sẵn pull-up bên trong thì bên ngoài cứ add thêm con trở 4.7k sẽ ổn định hơn, vì PMBus nhạy với signal integrity hơn I2C.

Có vấn đề gì thì cứ paste cái log lỗi cụ thể lên, anh em sẽ giúp ông fix.

Có lẽ bạn đang nhìn các thư mục từ sai góc độ rồi. stm32_SMBUS_stack là lớp giao tiếp cấp thấp, trong khi stm32_PMBUS_stack nằm ở lớp trên để xử lý lệnh PMBus.
Những việc bạn cần làm tiếp theo thường là: kích hoạt ngoại vi HAL SMBus, thêm các tệp mã nguồn middleware vào dự án, khởi tạo stack trong main(), và triển khai các hàm callback mà thư viện yêu cầu. Nếu không có các callback, stack sẽ không có nơi nào để gửi các frame đã nhận.

Cảm ơn các cao nhân đã trả lời, mình đi thử trước nhé.

Kết quả thử ra sao?

Mình đẩy phần này cho đồng đội làm rồi, không đủ sức :sweat_smile: