STM32 SysTick-Timer – Führt das Alarmereignis nicht aus

Ich versuche, einen Interrupt zu schreiben, um die Grundzeit in Ticks auf einem STM32F407VGT (Discovery Board) zu messen.

Mein Interrupt scheint einmal zu laufen (obwohl ich nicht sicher sein kann), aber dann stürzt es ab / blockiert den Prozessor vollständig. Alle UART-Ausgaben werden gestoppt ...

Der Code ist im Wesentlichen derselbe wie in „The Definitive Guide to the ARM Cortex-M3, 2nd ed“. (Joseph Yiu, Newnes.) Könnte die Tatsache, dass der STM32F4xx ein ARM Cortex-M4 ist, ein Problem sein? Wenn ja, wie behebe ich das? Ich habe anfangs versucht, TMR2 mit ähnlichen Problemen zu verwenden, was mich denken lässt, dass es etwas ist, das mir fehlt. Ich habe auch versucht, SysTickConfig zu verwenden, mit den gleichen Problemen.

uint32_t ticks;

void SysTickAlarm(void)
{
    SysTick->CTRL = 0;
    SCB->ICSR = SCB->ICSR & 0xFDFFFFFF;
    ticks++;
    return;
}

/*
 * Initialise system timer
 */
void tick_init(void)
{
    ticks = 0;
    *((volatile unsigned int*)(SCB->VTOR + (15 << 2))) = (unsigned int) SysTickAlarm;

    SysTick->CTRL = 0;                  // Disable SysTick
    SysTick->LOAD = TICK_DELAY;         // Delay for 10 ms
    SysTick->VAL = 0;                   // Clear current value to 0
    SysTick->CTRL = 0x7;                // Enable SysTick+exception and use processor clock
}

/*
 * get_ticks: Get the number of ticks since processor initialisation.
 */
uint32_t get_ticks()
{
    return ticks;
}

printf("ticks=%d\n", get_ticks());main() ruft tick_init() auf und beginnt dann in einer Schleife auszuspucken . Aber es stoppt ziemlich schnell, ich bekomme ungefähr 10 Zeilen, bevor es abstürzt.

Ich bin sehr neu bei ARM-Prozessoren, also ist es wahrscheinlich etwas sehr Einfaches, aber ich kann es nicht sehen.

Haben Sie eine Toolchain mit Debug? Ich würde auch empfehlen, die Standard-Peripheriebibliothek von ST für Ihr Gerät zu verwenden, da dies die Konfiguration des Geräts viel einfacher macht, als Dinge in Register zu stecken.
Ich muss mal schauen, ob ich einen Debugger zur Verfügung habe. Ich arbeite in einem Praktikum und wir dürfen die Peripheriebibliothek von ST nicht verwenden, weil sie mit vielen Dingen nicht kompatibel ist. (Das habe ich mir nicht ausgesucht.)
Ist Ihr SysTickAlarm() tatsächlich ein Systick-Handler? Überprüfen Sie Ihre Vektortabelle noch einmal.
Ich glaube *((volatile unsigned int*)(SCB->VTOR + (15 << 2))) = (unsigned int) SysTickAlarm;dafür ist der da, bin mir aber nicht sicher.
Wo ist dein Code, ist er im RAM? Hast du den RAM auf die Adresse 0x0 neu gemappt? Standardmäßig versucht diese Art der Zuweisung, Flash zu modifizieren, was nicht erlaubt ist. Wenn sich Ihr Code im RAM befindet, Sie RAM jedoch nicht auf Adresse 0x0 neu zugeordnet haben, müssen Sie den Offset der Vektortabelle festlegen, bevor Sie irgendetwas mit Interrupts tun. Bitte posten Sie ein vollständiges Minimalbeispiel mit Linker-Skript (vorzugsweise auch minimal, aber funktionierend) und Startcode.
Der Code ist soweit ich weiß im Flash. Ich muss prüfen, ob es in Ordnung ist, die Linker-Skripte zu veröffentlichen, da sie wahrscheinlich Firmeneigentum sind ...

Antworten (1)

Sie haben sich selbst ein ziemliches Problem geschaffen, indem Sie die Standard-Peripheriebibliothek (SPL) aufgegeben haben. Dieser Mikrocontroller ist schwer genug, damit zu lernen, geschweige denn ohne. Die Bibliothek mag schrecklich gestaltet sein, aber sie hat den Vorteil, dass sie tatsächlich funktioniert. Ich schlage vor, dass Sie zuerst ein einfaches Testprogramm mit SPL zum Laufen bringen und dann seine Funktionalität schrittweise neu implementieren, wenn Sie es wirklich nicht verwenden können (ich sehe jedoch noch keinen technischen Grund dafür).

Um einen Interrupt in einem Cortex-M3/M4 zu verwenden, benötigen Sie Folgendes:

  • ein Stapel. Der Kern speichert automatisch mehrere Register auf dem Stack, wenn ein Interrupt ausgelöst wird. Der anfängliche Stapelzeigerwert wird als erstes von Adresse 0x0 gelesen, wenn der Kern hochfährt. Dieser Wert sollte normalerweise dem Ende von RAM + 1 entsprechen.
  • korrekter Vektortabellen-Offset im SCB->VTORRegister. Standardmäßig ist es 0, was (wiederum standardmäßig) der Beginn des Flashs ist. Wenn Ihre Kombination aus Startcode und Linker-Skript die Vektortabelle korrekt einrichtet, großartig. Das macht die SPL. Sie scheinen es nicht zu tun (es sei denn, es steht in dem Code, den Sie nicht gepostet haben). Sehen Sie sich an, wie es in der Standard-Peripheriebibliothek ( startup_stm32f4xx.sund dem entsprechenden Linker-Skript für eine gcc-basierte Toolchain) gemacht wird.
  • ein Handler. du hast das.
  • Adresse dieses Handlers + 1 muss an der richtigen Position in der Vektortabelle stehen. Die Art und Weise, wie Sie einem Ort in der (angenommenen) Vektortabelle einen Wert zuweisen, wird standardmäßig nicht funktionieren, da es sich um Flash handelt. Ich denke, Sie haben Ihren RAM neu zugeordnet, um bei Adresse 0 zu beginnen, aber Ihre Frage enthält nichts, was darauf hindeuten würde.
  • Der Interrupt muss im NVIC aktiviert und seine Priorität festgelegt werden. Das sehe ich in deinem Code überhaupt nicht. Dies verwendet NVIC->ISER[x]und NVIC->IPR[x]registriert. Siehe Implementierung von NVIC_Init()in SPL und PM00214 , Abschnitt 4.3.
  • Schließlich muss das Peripheriegerät konfiguriert werden, um tatsächliche Unterbrechungsanforderungen zu erzeugen. Scheint, als würdest du das tun.

Wenn Sie alles überprüft haben und es immer noch nicht zum Laufen bringen können, ist es am besten, ein vollständiges (aber minimales) Projekt zur Analyse zu veröffentlichen.

Ich habe die SPL eher als Hindernis denn als Hilfe empfunden, vielleicht weil ich nicht die richtige Dokumentation dafür gefunden habe. Anhand des STM-Datenblatts und der mitgelieferten Header kann ich wissen, dass der E / A-Port B0 auf normale E / A eingestellt werden kann, indem Bit 0 gesetzt und Bit 1 von GPIOB_MODER gelöscht wird, und der C-Code dafür ist (mithilfe rmw_mask32(&GPIOB->MODER, 3, 1);von meiner rmw_mask32Routine auszuführen GPIOB->MODER = (GPIOB->MODER & ~3) | 1, aber LDREX/STREX zu verwenden, um Interrupt-sicher zu sein). Gibt es eine nette, leicht durchsuchbare Dokumentation, die sagt, wie man die SPL für einen solchen Zweck verwendet?
Es ist nicht meine Entscheidung, die SPL nicht zu verwenden. Mein Arbeitgeber verlangt es. Ich habe das Problem mit meiner ursprünglichen Timer-Lösung herausgefunden - ich hatte die Uhr nicht richtig eingestellt - jetzt funktioniert das gut.