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);
    }
}

17.07.2017

System.Runtime.InteropServices.Marshal w TinyCLR OS

Bardzo przydatną klasą w TinyCLR OS jest System.Runtime.InteropServices.Marshal. Dzięki metodom z tej klasy uzyskamy dostęp do komórek pamięci. Między innymi rejestry procesora to też komórki pamięci, więc będziemy mogli bezpośrednio je zapisywać lub odczytywać.

Adresy rejestrów zaczynają się od wartości 0x4000 0000. W jednym z wcześniejszych wpisów na temat interop był pobierany unikatowy identyfikator procesora. Ten identyfikator przechowywany jest właśnie w jednym z rejestrów i składa się z trzech 32-bitowych komórek. Rejestr zaczyna się od adresu 0x1FFF 7A10. Jak więc uzyskać unikatowy identyfikator? Nic prostszego!

public static string GetDeviceGuid()
{
    var uidAddr = new IntPtr(0x1FFF7A10);
    int uid0 = Marshal.ReadInt32(uidAddr, 0);
    int uid1 = Marshal.ReadInt32(uidAddr, 0x04);
    int uid2 = Marshal.ReadInt32(uidAddr, 0x08);

    string result = uid0.ToString("X8")
                    + "-" + (uid1 >> 16).ToString("X4")
                    + "-" + (uid1 & 0xFFFF).ToString("X4")
                    + "-" + "0000"
                    + "-" + uid2.ToString("X8") + "0000";

    return result;
}

10.07.2017

TinyCLR OS od GHI Electronics

Od jakiegoś czasu na stronie GHI Electronics pojawiały się wzmianki o tym, że pracują nad nowym rozwiązaniem w stylu .NET Micro Framework. Nazwali to TinyCLR OS. Natomiast kilka dni temu pojawiła się informacja o wypuszczeniu wersji Preview 5 oraz o udostępnieniu kodu, który pozwala wygenerować TinyCLR OS na dowolną płytkę z procesorem STMF4. Żart? Nie!

To działa!

Bez problemu wygenerowałem dla poczciwej płytki STM32F4Discovery TinyCLR OS!. Bez problemu zrobiłem projekt w Visual Studio 2017 i bez problemu uruchomiłem prosty program z mrugającą diodą! Wszystko się debuguje, restartuje, przerywa itp. Bez najmniejszego problemu. Przygotowanie portu zajęło mi 15 minut, a kompilacja 5 sekund! TinyCLR OS będzie sukcesywnie rozwijany i uzupełniany o nowe biblioteki i peryferia.

Poniżej kilka przydatnych linków:
Przy rozpoczynaniu pracy trzeba się trzymać dokumentacji. Aha. Trzeba pamiętać o wgraniu sterownika USB, bo w dokumentacji nie ma o tym wzmianki.

TinyCLR OS Library trzeba podłączyć jako repozytorium lokalne NuGeta np.w ten sposób: How to Install a local sources NuGet package or a Prerelease package in Visual Studio