Saya sedang mencari untuk mengembangkan perangkat lunak bertenaga baterai menggunakan pengontrol EFM Gekko (http://energymicro.com/) dan ingin pengontrol tertidur setiap kali tidak ada yang berguna untuk dilakukan. Instruksi WFI (Wait For Interrupt) digunakan untuk tujuan ini; itu akan membuat prosesor tidur sampai terjadi gangguan.
Jika tidur diaktifkan dengan menyimpan sesuatu di suatu tempat, seseorang dapat menggunakan operasi load-eksklusif / toko-eksklusif untuk melakukan sesuatu seperti:
// dont_sleep akan dimuat dengan 2 setiap kali sesuatu terjadi itu // harus memaksa loop utama untuk berputar setidaknya sekali. Jika ada interupsi // Terjadi yang menyebabkannya diatur ulang ke 2 selama pernyataan berikut, // perilaku akan seolah-olah interupsi terjadi setelahnya. store_exclusive (load_exclusive (dont_sleep) >> 1); while (! dont_sleep) { // Jika interupsi terjadi antara pernyataan berikutnya dan store_exclusive, jangan tidur load_exclusive (SLEEP_TRIGGER); if (! dont_sleep) store_exclusive (SLEEP_TRIGGER); }
Jika terjadi interupsi antara operasi load_exclusive dan store_exclusive, efeknya akan melewatkan store_exclusive, sehingga menyebabkan sistem untuk menjalankan loop sekali lagi (untuk melihat apakah interupsi telah mengatur dont_sleep). Sayangnya, Gekko menggunakan instruksi WFI daripada alamat tulis untuk memicu mode tidur; menulis kode suka
if (! dont_sleep) WFI ();
akan menjalankan risiko bahwa interupsi dapat terjadi antara 'jika' dan 'wfi' dan mengatur dont_sleep, tetapi wfi akan tetap melanjutkan dan mengeksekusi. Apa pola terbaik untuk mencegah itu? Atur PRIMASK ke 1 untuk mencegah interupsi mengganggu prosesor sesaat sebelum menjalankan WFI, dan menghapusnya segera setelah itu? Atau ada trik yang lebih baik?
EDIT
Saya bertanya-tanya tentang bit Event. Secara umum, ini dimaksudkan untuk dukungan multi-prosesor, tetapi bertanya-tanya apakah sesuatu seperti yang berikut ini bisa berfungsi:
if (dont_sleep) SEV (); / * Akan membuat mengikuti bendera acara WFE yang jelas tetapi tidak tidur * / WFE ();
Setiap interupsi yang diset jangan_sleep juga harus menjalankan instruksi SEV, jadi jika interupsi terjadi setelah tes "jika", WFE akan menghapus flag event tetapi tidak pergi tidur. Apakah itu terdengar seperti paradigma yang baik?
Jawaban:
Saya tidak sepenuhnya memahami
dont_sleep
hal itu, tetapi satu hal yang dapat Anda coba adalah melakukan "pekerjaan utama" pada penangan PendSV, atur ke prioritas terendah. Kemudian, cukup jadwalkan PendSV dari penangan lain setiap kali Anda perlu melakukan sesuatu. Lihat di sini cara melakukannya (ini untuk M1 tetapi M3 tidak terlalu berbeda).Hal lain yang bisa Anda gunakan (mungkin bersama dengan pendekatan sebelumnya) adalah fitur Sleep-on-exit. Jika Anda mengaktifkannya, prosesor akan tidur setelah keluar dari penangan ISR terakhir, tanpa Anda harus memanggil WFI. Lihat beberapa contoh di sini .
sumber
Letakkan di bagian kritis. ISR tidak akan berjalan, jadi Anda tidak menjalankan risiko dont_sleep berubah sebelum WFI, tetapi mereka tetap membangunkan prosesor dan ISR akan dijalankan segera setelah bagian kritis berakhir.
Lingkungan pengembangan Anda mungkin memiliki fungsi bagian kritis, tetapi kira-kira seperti ini:
EnterCriticalSection adalah:
ExitCriticalSection adalah:
sumber
Ide Anda baik-baik saja, inilah yang diterapkan oleh Linux. Lihat di sini .
Kutipan yang berguna dari utas diskusi yang disebutkan di atas untuk mengklarifikasi mengapa WFI bekerja meskipun interupsi dinonaktifkan:
sumber
Berasumsi bahwa:
Maka solusinya adalah dengan menggunakan PRIMASK untuk memblokir interupsi antara validasi flag dan WFI:
sumber
Bagaimana dengan mode Tidur Saat Keluar? Ini secara otomatis masuk ke mode tidur kapan pun pawang IRQ keluar, sehingga sebenarnya tidak ada "mode normal" yang berjalan setelah itu dikonfigurasi. IRQ terjadi, ia bangun dan menjalankan handler, dan kembali tidur. Tidak perlu WFI.
sumber