Artykuły

20.07.2017

Watchdog IWDG w TinyCLR OS

Dzięki klasie Marshal można pisać bardziej zaawansowane funkcje. Na przykład implementacja watchdoga IWDG może wyglądać tak: 
public class WatchDog
{
    public static bool LastReboot
    {
        get
        {
            var rccAddr = new IntPtr(0x40023800);
            int rccCsrValue = Marshal.ReadInt32(rccAddr, 0x74);
            return IsIwdgRstf(rccCsrValue);
        }
    }

    public static void Start(TimeSpan period)
    {
        ResetLastReboot();
        SetTimings(period);
        WriteIwdgKr(0xCCCC);
    }

    public static void Reset()
    {
        WriteIwdgKr(0xAAAA);
    }

    private static void ResetLastReboot()
    {
        var rccAddr = new IntPtr(0x40023800);
        int rccCsrValue = Marshal.ReadInt32(rccAddr, 0x74);

        if (IsIwdgRstf(rccCsrValue))
        {
            const int rmvfMask = 0x01000000;
            rccCsrValue = rccCsrValue | rmvfMask;
            Marshal.WriteInt32(rccAddr, 0x74, rccCsrValue);
        }
    }

    private static void WriteIwdgKr(int value)
    {
        Marshal.WriteInt32(new IntPtr(0x40003000), value);
    }

    private static bool IsIwdgRstf(int rccCsrValue)
    {
        const int iwdgRstfMask = 0x20000000;
        return (rccCsrValue & iwdgRstfMask) > 0;
    }

    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)
            {
                int counter = (int)(usPeriod / usMin - 1);
                if (counter < 0 || counter > 0xFFF)
                    continue;

                SetIwdgPrAndRlr(i, counter);
                return;
            }
        }

        throw new InvalidOperationException("Invalid period (0.125..32768 ms).");
    }

    private static void SetIwdgPrAndRlr(int prValue, int rlrValue)
    {
        var iwdgKrAddr = new IntPtr(0x40003000);
        Marshal.WriteInt32(iwdgKrAddr, 0x5555);
        Marshal.WriteInt32(iwdgKrAddr, 0x04, prValue);
        Marshal.WriteInt32(iwdgKrAddr, 0x08, rlrValue);
    }
}

Brak komentarzy:

Prześlij komentarz