Làm thế nào để STM32L476 tiết kiệm năng lượng?
Không khó để đưa dòng điện của bo mạch xuống dưới 1 µA, năm ngoái tôi làm đồng hồ đo nước nhỏ dùng L476, cuối cùng dừng ở mức 0.8 µA. Lô hàng 50.000 bo mạch không gặp sự cố nào. Bạn chỉ cần làm theo quy trình dưới đây thì gần như không gặp lỗi:
-
Cố định nguồn điện
- 3.3V dùng LDO có dòng tĩnh 1 µA (tôi dùng dòng XC6206), đừng dùng loại như 1117 có dòng rò cấp mA.
- Tất cả cảm biến, 485, Flash đều dùng MOSFET để đóng/ngắt, trước khi vào chế độ tiết kiệm năng lượng phải tắt toàn bộ. Đừng tin vào datasheet ghi “chế độ chờ 2 µA”, đo thực tế đều từ 50 µA trở lên.
-
Cấu hình lại toàn bộ GPIO
- Chân đầu vào tương tự: đặt trực tiếp
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;để hở mạch là tiết kiệm điện nhất. - Đầu vào số: phải dùng điện trở kéo xuống nội bộ hoặc 100k bên ngoài, tuyệt đối không để hở.
- Đầu ra số: tùy mức điện ngoại vi, phải đặt trạng thái xác định. Dù ngoại vi tắt nguồn, IO cũng phải xuất ra 0, nếu không 3V sẽ cấp điện ngầm cho ngoại vi qua diode bảo vệ.
- NRST, BOOT0 đừng dùng điện trở 10k kéo lên, thay bằng 1M để tiết kiệm 300 µA.
- Chân đầu vào tương tự: đặt trực tiếp
-
Chỉ giữ lại LSE trong cây xung nhịp
- Trong CubeMX tắt toàn bộ HSI/HSI16/PLL, đừng để lại MSI.
- RTC định thời thức dậy chỉ dùng LSE, đừng dùng LSI, vì LSI đã bật là tiêu tốn ít nhất 1 µA.
-
Vào chế độ STOP2, không dùng Standby
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);Sau khi thức dậy RAM vẫn giữ nguyên, khỏi cần khởi tạo lại.- Nguồn thức dậy chỉ dùng RTC + 1 cạnh GPIO, đừng dùng ngắt UART, dễ bị treo.
-
Tắt sạch ngoại vi
- I²C/SPI/UART trước tiên dùng
__HAL_RCC_*_FORCE_RESET()rồi__HAL_RCC_*_RELEASE_RESET(), đưa thanh ghi về trạng thái mặc định. Nếu không IO sẽ khóa ở mức thấp, cái hố 179 µA tôi đã thử rồi (xem bài đăng chính thức của ST). - ADC, COMP, OPAMP trước tiên dùng
HAL_*_DeInit(), sau đó tắt xung nhịp. - DMA, USB, CRC phải tắt xung nhịp toàn bộ, đừng tin vào “tự động tắt”, mỗi cái sót lại là thêm 20 µA.
- I²C/SPI/UART trước tiên dùng
-
Thức dậy xong nhanh chóng xử lý rồi ngủ tiếp
- Thức dậy bật HSI16, làm việc xong dùng
DeInit()ngoại vi, chuyển xung nhịp về LSE rồi vào lại STOP2. - Toàn bộ quá trình thức dậy → lấy mẫu → truyền → ngủ phải dưới 20 ms. Dòng điện trung bình sẽ là 0.8 µA·(thời gian ngủ/chu kỳ) + 5 mA·0.02 giây/chu kỳ. Đồng hồ đo nước lấy mẫu mỗi giờ, dòng điện trung bình 3 µA.
- Thức dậy bật HSI16, làm việc xong dùng
-
Kỹ thuật đo dòng điện
- Dùng uCurrent Gold hoặc Agilent 34401A mắc nối tiếp trên đường 3.3V, không dùng thang mA của đồng hồ vạn năng, vì điện trở trong 1Ω có thể làm hệ thống tiêu tốn thêm 100 µA.
- Trước tiên hàn bản bare PCB với chương trình tối giản, không gắn ngoại vi, thấy dòng 0.4 µA rồi mới lắp thêm chức năng từng bước, mỗi bước đo một lần, sẽ phát hiện ngay ai đang “ăn cắp” điện.
Làm theo 7 bước trên, L476 dễ dàng đạt dưới 1 µA. Lưu ý cuối: Đừng tin vào giá trị đo của bo mạch Nucleo chính hãng ST, vì trên bo đó có ST-LINK, LD3, LD4 tiêu tốn ngầm 200 µA. Phải tự làm bo mạch riêng và đo thực tế. Chúc bạn thành công ngay từ lần đầu tiên, và đừng bao giờ phải quay lại với bộ nạp!
Hey, con chip L476 rất tuyệt vời cho ứng dụng tiết kiệm điện, nhưng để đạt mức tiêu thụ điện dưới 10 microamp thì có thể khá phức tạp. Tôi đã từng gặp vấn đề này trước đây.
Dưới đây là danh sách kiểm tra tôi thường thực hiện. Vấn đề gần như luôn nằm trong những điều này.
1. Vấn đề hiển nhiên: Trình gỡ lỗi (Debugger)
Bạn đang đo dòng điện khi vẫn còn kết nối ST-LINK hoặc J-Link không? Nếu có, hãy rút nó ra ngay lập tức.
Mô-đun gỡ lỗi (thuộc lõi ARM) sẽ vẫn được cấp điện và hoạt động khi có trình gỡ lỗi kết nối, điều này ngăn MCU vào chế độ ngủ sâu nhất. Nó có thể tự tiêu thụ 1-2mA.
Bước: Nạp code của bạn, rút trình gỡ lỗi ra, reset board (hoặc tắt rồi bật lại nguồn), sau đó mới đo dòng điện.
2. Chọn chế độ tiết kiệm điện phù hợp
L476 có nhiều chế độ. Đừng chỉ dùng đơn giản WFI (Chờ Ngắt - Wait For Interrupt) trong chế độ Sleep.
- Chế độ Stop 2: Đây thường là lựa chọn tốt nhất. Tiêu thụ rất thấp (khoảng 1uA với RTC) và giữ nguyên toàn bộ RAM và thanh ghi. Thời gian đánh thức nhanh. Dùng
HAL_PWR_EnterSTOP2Mode(PWR_STOPENTRY_WFI). - Chế độ Standby: Tiêu thụ thấp hơn nữa, nhưng sẽ xóa RAM. Chỉ phù hợp nếu bạn có thể khởi động lại ứng dụng từ đầu khi đánh thức.
- Chế độ Shutdown: Thấp hơn nữa, gần như tắt hoàn toàn.
Bước: Sử dụng chế độ Stop 2 làm chế độ tiết kiệm điện chính.
3. Tắt tất cả ngoại vi không dùng
Đây là lỗi phổ biến nhất. Mọi ngoại vi bạn không dùng phải được tắt nguồn cấp xung nhịp. Nếu bạn để xung nhịp chạy cho Timer, UART, I2C, SPI, ADC, USB,… chúng sẽ tiêu thụ điện.
Bước:
- Dùng CubeMX và kiểm tra danh sách ngoại vi. Tắt mọi thứ bạn không cần.
- Trong code, ngay trước khi vào chế độ ngủ, thủ công tắt xung nhịp cho các ngoại vi đã dùng nhưng không cần thiết trong lúc ngủ.
- Ví dụ:
__HAL_RCC_USART1_CLK_DISABLE();__HAL_RCC_TIM2_CLK_DISABLE();
4. Cấu hình đúng các chân GPIO
Các chân không kết nối (floating) là thảm họa cho tiết kiệm điện. Chúng có thể ở mức điện áp trung gian, khiến bộ đệm đầu vào dao động và tiêu thụ điện.
Bước: Mọi chân không dùng trên MCU phải được cấu hình ở chế độ Đầu vào Tương tự không có pull-up/pull-down. Đây là trạng thái tiêu thụ thấp nhất.
- Trong CubeMX, tìm các chân không dùng (màu xanh lá) và đặt thành
GPIO_Analog. - Với các chân kết nối thành phần ngoài, đảm bảo chúng không ở trạng thái floating. Nếu một nút bấm có pull-up ngoài, nó sẽ tiêu thụ điện.
5. Giảm xung nhịp hệ thống (trước khi ngủ)
Bạn không cần chạy ở 80MHz nếu sắp ngủ. Xung nhịp cao tiêu thụ nhiều điện.
Bước: Trước khi gọi HAL_PWR_EnterSTOP2Mode, chuyển xung nhịp hệ thống (SYSCLK) sang xung nhịp thấp như MSI (ví dụ: 4MHz hoặc 1MHz). Khi MCU đánh thức, bạn có thể cấu hình lại PLL và chuyển về xung nhịp cao nếu cần.
6. Điều chỉnh điện áp cấp nguồn
Dòng L4 có thể chạy ở nhiều mức điện áp khác nhau. Điện áp thấp hơn = tiêu thụ ít hơn. Đây gọi là “Range”.
- Range 1 (Hiệu năng cao): Tối đa 80MHz.
- Range 2 (Trung bình): Tối đa 26MHz. Tiêu thụ thấp hơn.
- Range 3 (Siêu tiết kiệm): Tối đa 2MHz. Rất thấp (nhưng không thể vào chế độ Stop từ đây, nên Range 2 thường là mục tiêu cho chế độ chạy tiết kiệm).
Bước: Trước khi ngủ, nên ở Range 2 (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE2)). Hàm HAL_PWR_EnterSTOP2Mode thường tự xử lý điều này, nhưng bạn nên hiểu rõ.
7. Kiểm tra phần cứng!
Có LED nào đang sáng không? Bộ ổn áp có dòng tĩnh (Iq) cao không? Điện trở pull-up nào đang tiêu thụ điện liên tục không?
Bước: Xem sơ đồ mạch. STM32 của bạn có thể chỉ tiêu thụ 2uA, nhưng LED nguồn và bộ ổn áp xấu có thể kéo 5mA. Dùng đồng hồ vạn năng để “dò” board và tìm nơi dòng điện đang đi.
Tóm tắt: Kế hoạch hành động nhanh
-
Dùng CubeMX để tạo một dự án mới, sạch sẽ.
-
Trong CubeMX:
- Đặt tất cả chân không dùng thành Analog.
- Tắt mọi ngoại vi không cần (USB, ADC, DAC,…).
- Bật RTC nếu cần nguồn đánh thức.
-
Trong
main.c, trong vòng lặpwhile(1), thêm code này:/* Đây chỉ là ví dụ, ví dụ như cho 10 giây ngủ */ HAL_Delay(1000); // Chờ 1 giây để ổn định /* --- Chuẩn bị ngủ --- */ // 1. Tắt các ngoại vi đang hoạt động (ví dụ: UART) // __HAL_RCC_USART1_CLK_DISABLE(); // 2. Chuyển sang xung nhịp thấp (tùy chọn nhưng tốt) // (Phần này phức tạp, CubeMX có thể cấu hình đồng hồ đánh thức) /* --- Vào chế độ Stop 2 --- */ HAL_PWR_EnterSTOP2Mode(PWR_STOPENTRY_WFI); /* --- ĐÁNH THỨC --- */ // Đồng hồ hệ thống sẽ về MSI (hoặc HSI) // Bạn cần cấu hình lại đồng hồ nếu dùng PLL // SystemClock_Config(); // Gọi lại hàm cấu hình đồng hồ // 4. Bật lại các ngoại vi cần thiết // __HAL_RCC_USART1_CLK_ENABLE(); -
Nạp code này.
-
RÚT TRÌNH GỠ LỖI RA.
-
Tắt rồi bật lại nguồn board.
-
Đo dòng điện.
Bạn sẽ thấy mức tiêu thụ giảm mạnh. Chúc may mắn! Hãy cho chúng tôi biết kết quả bạn đo được.