Nasz mikrokontroler ma wbudowany system zabezpieczający przed zawieszeniem systemu. Nazywa się to watchdog. Właściwie to ma dwie takie funkcje: IWDG - independent watchdog i WWDG - window watchdog. Znacznie prostszy w użyciu i adekwatny do nieprzewidywalnego czasu działania NET MF jest IWDG. Spróbujemy zatem zaimplementować obsługę takiego watchdoga. W watchdogu chodzi o to, aby cyklicznie co jakiś czas poinformować go, że nasz program działa poprawnie. W przypadku, gdy watchdog nie dostanie takiego sygnału to mikrokontroler samoczynnie się zrestartuje. Nasza implementacja będzie bardzo zbliżona do tej na stronie stm32f4-discovery.com: Library 20- Independent watchdog timer on STM32F4.
A więc do dzieła. Do naszego projektu STM32F4Helper dodajemy nowy plik: Watchdog.cs. Statyczna klasa Watchdog będzie miała dwie funkcje: Start i Reset. Nasz mikrokontroler ma jeszcze jedną dodatkowa informację, która może być bardzo użyteczna: ostatni reset wykonał watchdog. Tą informację zwrócimy przez statyczną właściwość: LastReset. Tak więc cały "kadłubek" klasy wygląda tak:
namespace STM32F4Helper { public static class Watchdog { public static bool LastReset { get { throw new NotImplementedException(); } } public static void Start(TimeSpan period) { throw new NotImplementedException(); } public static void Reset() { throw new NotImplementedException(); } } }
No dobra uzupełniamy funkcje. Aha. W dokumentacji zobaczymy, że do poprawnego działania watchdoga musimy odpowiednio ustawić rejestry prescallera (IWDG_PR) i licznika (IWDG_RLR). Te wartości obliczymy po stronie kodu zarządzanego na podstawie parametru period metody Start. Jeśli nie popełniłem żadnego błędu to cała klasa powinna wyglądać tak:
namespace STM32F4Helper { public static class Watchdog { public static bool LastReset { get { return LastResetIwdg(); } } public static void Start(TimeSpan period) { SetTimings(period); StartIwdg(); } public static void Reset() { ResetIwdg(); } private static void SetTimings(TimeSpan period) { const int kHzLsi = 32000; long usPeriod = (period.Ticks * 1000) / TimeSpan.TicksPerMillisecond; int[] dividers = { 4, 8, 16, 32, 64, 128, 256 }; for (int i = 0; i < dividers.Length; i++) { int usMin = (dividers[i] * 1000 * 1000) / kHzLsi; if (usPeriod >= usMin) { long counter = usPeriod / usMin - 1; if (counter < 0 || counter > 0xFFF) continue; SetupIwdg(i, (int)counter); return; } } throw new InvalidOperationException("Invalid period (0.125..32768 ms)."); } [MethodImpl(MethodImplOptions.InternalCall)] private static extern void SetupIwdg(int divider, int counter); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void StartIwdg(); [MethodImpl(MethodImplOptions.InternalCall)] private static extern void ResetIwdg(); [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool LastResetIwdg(); } }
Teraz standardowo generujemy pliki po stronie native. I uzupełniamy funkcje w pliku *_Watchdog.cpp. Oczywiście zmiany z innych plików (dotNetMF.proj, *_Native.cpp, *_Native.h) musimy odpowiednio przenieść do już istniejącej biblioteki. Funkcje po stronie native będą wyglądały tak:
#include "STM32F4Helper_Native.h" #include "STM32F4Helper_Native_STM32F4Helper_Watchdog.h" using namespace STM32F4Helper; void Watchdog::SetupIwdg( INT32 param0, INT32 param1, HRESULT &hr ) { IWDG->KR = 0x5555; IWDG->PR = param0; IWDG->RLR = param1; RCC->CSR |= RCC_CSR_RMVF; } void Watchdog::StartIwdg( HRESULT &hr ) { IWDG->KR = 0xCCCC; IWDG->KR = 0xAAAA; } void Watchdog::ResetIwdg( HRESULT &hr ) { IWDG->KR = 0xAAAA; } INT8 Watchdog::LastResetIwdg( HRESULT &hr ) { INT8 retVal = 0; if (RCC->CSR & RCC_CSR_WDGRSTF) retVal = 1; return retVal; }
I już. Zostaje tylko skompilowanie solucji, wgranie przez MFDeploy obrazów hex i przetestowanie. Na przykład takim programem. Diody informują po restarcie jaki był powód: czerwona - watchdog, zielona - zasilanie. Naciśnięcie przycisku wymusza blokadę programu, tak aby zadziałał watchdog.
public class Program { public static void Main() { OutputPort redLed = new OutputPort(Stm32F4Discovery.LedPins.Red, false); OutputPort greenLed = new OutputPort(Stm32F4Discovery.LedPins.Green, false); OutputPort blueLed = new OutputPort(Stm32F4Discovery.LedPins.Blue, false); InputPort button = new InputPort(Stm32F4Discovery.ButtonPins.User, false, Port.ResistorMode.PullDown); OutputPort led = STM32F4Helper.Watchdog.LastReset ? redLed : greenLed; led.Write(true); Thread.Sleep(1000); led.Write(false); STM32F4Helper.Watchdog.Start(new TimeSpan(0, 0, 0, 5, 0)); for (;;) { STM32F4Helper.Watchdog.Reset(); Thread.Sleep(500); blueLed.Write(!blueLed.Read()); if (button.Read()) { while (button.Read()) { } while (true) { blueLed.Write(!blueLed.Read()); Thread.Sleep(100); if (button.Read()) { while (button.Read()) { } blueLed.Write(false); break; } } } } } }
Is Watchdog native methods integrated in your compilation on github?
OdpowiedzUsuńNo. Hex images on github does not contains IWDG functions.
OdpowiedzUsuń