mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32L100 zu Fuß


Autor: Max G. (l0wside) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich versuche gerade, mich auf der Basis der Doku auf Registerebene durch 
den STM32L100 zu kämpfen. Vermutlich gibt es sinnvollere Methoden, seine 
Zeit zu verbringen; andererseits ist es mir ganz sympathisch, wenn ich 
weiß, was der Rechner denn nun macht, anstatt das alles wie ein 
schlechtes Schnitzel unter einem Haufen Soße (=CMSIS, StdPeriphLib) zu 
ersäufen. Auf dem MSP430 bin ich auch auf Registerebene zu Potte 
gekommen.

Nur den NVIC-Code habe ich geklaut, deswegen ist dort StdPeriphLib-Code 
drin.


Ich habe es geschafft, die LEDs auf dem Demoboard (PORT C) blinken zu 
lassen. Mäßig schöner Code:
#include <stm32l1xx.h>
#include <stdint.h>

int main() {
    RCC->AHBENR  |=  RCC_AHBENR_GPIOCEN;
    RCC->APB1ENR |=  RCC_APB1ENR_TIM2EN;
    GPIOC->MODER   |=   (0x55555555);   /* General purpose output mode*/
    GPIOC->OSPEEDR |=   (0x55555555);   /* 2 MHz Low speed            */
    static int i;



    TIM2->PSC = 40000; // Prescaler
    TIM2->ARR = 500;   // Timer overflow value
    TIM2->EGR = 0x01; // Update generation
    TIM2->DIER |= 0x01; // Enable timer interrupt
    TIM2->CR1 |= 0x01; // Timer enabled
    RCC->AHBENR  |=  RCC_AHBENR_GPIOAEN;

    NVIC_InitTypeDef nvicStructure;
    nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
    nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
    nvicStructure.NVIC_IRQChannelSubPriority = 1;
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicStructure);

    unsigned char n = 0;
  while (1) {
    GPIOC->BSRRL = 1 << 9; /* all on */
    GPIOA->ODR = 0xFFFFFFFF;
    for (i=0; i<100000; ++i);
    GPIOC->BSRRH = 1 <<9; /* all off */
    GPIOA->ODR = 0;
    for (i=0; i<100000; ++i);
  }
}

volatile uint16_t led_status = 0;

void TIM2_IRQHandler() {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
      led_status = !led_status;
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        if (led_status) {
          GPIOC->BSRRL = (1 << 8);
        } else {
          GPIOC->BSRRH = (1 << 8);
        }
    }
}

Die Hauptschleife beackert also PC9, der Interrupt PC8. Das funktioniert 
:)

Wenn ich nun versuche, den Code so zu erweitern, dass der USART1 auch 
noch etwas tun darf, klappt das nicht. Checkliste:
* Peripheral Clocks für USART und für Port A einschalten
* PA9 auf Alternate Function schalten, als Alternate Function #7 = 
USART1_TX nehmen
* Baudrate für USART1 setzen
* USART Enable und TX Enable setzen
* Wert ins USART Data Register schreiben

In Code gegossen (obiger Code erweitert):
#include <stm32l1xx.h>
#include <stdint.h>

int main() {
  RCC->AHBENR  |=  RCC_AHBENR_GPIOCEN;
  RCC->APB1ENR |=  RCC_APB1ENR_TIM2EN;
  GPIOC->MODER   |=   (0x55555555);   /* General purpose output mode*/
  GPIOC->OSPEEDR |=   (0x55555555);   /* 2 MHz Low speed            */
  static int i;



  TIM2->PSC = 40000; // Prescaler
  TIM2->ARR = 500;   // Timer overflow value
  TIM2->EGR = 0x01; // Update generation
  TIM2->DIER |= 0x01; // Enable timer interrupt
  TIM2->CR1 |= 0x01; // Timer enabled
  RCC->AHBENR  |=  RCC_AHBENR_GPIOAEN;
  RCC->APB2ENR |=  RCC_APB2ENR_USART1EN;
  GPIOA->MODER  |= (2UL << 18) | (2UL << 20);
  GPIOA->AFR[1] |= (7UL << 4) | (7UL << 8);
  GPIOA->OSPEEDR =   0xFFFFFFFF;
  USART1->BRR = 0x341;
  USART1->CR1 |= USART_CR1_UE + USART_CR1_TE;

    NVIC_InitTypeDef nvicStructure;
    nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
    nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
    nvicStructure.NVIC_IRQChannelSubPriority = 1;
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicStructure);

    unsigned char n = 0;
  while (1) {
    GPIOC->BSRRL = 1 << 9; /* all on */
    GPIOA->ODR = 0xFFFFFFFF;
    for (i=0; i<100000; ++i);
    GPIOC->BSRRH = 1 <<9; /* all off */
    GPIOA->ODR = 0;
    for (i=0; i<100000; ++i);
    while (!(USART1->SR & USART_SR_TXE));
    USART1->DR = n;
    n++;
  }
}

volatile uint16_t led_status = 0;

void TIM2_IRQHandler() {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
      led_status = !led_status;
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        if (led_status) {
          GPIOC->BSRRL = (1 << 8);
        } else {
          GPIOC->BSRRH = (1 << 8);
        }
    }
}

Leider tut sich exakt gar nichts, der LA sieht nur dröhnendes Schweigen 
an PA9. Die LEDs blinken beide, die Abfrage while (!(USART1->SR & 
USART_SR_TXE)) bleibt nicht hängen.

Jemand eine Idee, wo ich noch schrauben kann (außer die Soßenlösung 
CMSIS/StdPeriphLib)?

Max

: Bearbeitet durch User
Autor: Nop (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max G. schrieb:
> GPIOA->ODR = 0xFFFFFFFF;
...
> GPIOA->ODR = 0;

Was ist denn die Idee hierbei eigentlich?

Und sind die Defines alle richtig gesetzt? Das hatte ich mal, als ich 
STM32 per Hand gemacht hatte. Sind die Bits bei AF1 usw. wirklich die 
korrekten? Alles nochmal nachkontrollieren.

Hängt der UART wirklich an APB2?

Sonst nächster Schritt, erstmal den TX als GPIO schalten und toggeln. 
Das sollte ja funktionieren.

Autor: Mehmet K. (mkmk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max G. schrieb:
> Auf dem MSP430 bin ich auch auf Registerebene zu Potte gekommen.

Vermutlich nicht dasselbe wie ein STM32.
Ich mag es auch, wenn die Kontrolle soweit als möglich bei mir liegt. 
Aber ein Projekt gleich auf der Registerebene anzufangen finde ich keine 
so gute Idee. Und vorallem dann nicht, wenn man mit dem MCU Neuland 
betritt.
Ich an Deiner Stelle würde das Ganze mit der StdPeriphLib aufsetzen. 
Geht ja schnell. Und dann Schritt für Schritt diese Lib aussen vor 
lassen. Aber Du wirst sehen, dass manches von dieser Lib gar nicht mal 
so schlecht gehandhabt wird.

Autor: Max G. (l0wside) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gefühlt ist der Unterschied hauptsächlich, dass die Register zum einen 
32 Bit breit sind und die Doku zu jedem Config-Register entsprechend 
lang, und dass man für die Peripherie die Clocks aktivieren muss, was 
man auf dem MSP430 nicht muss.
Aber vermutlich hast du Recht, und ich sollte es erst mal mit der 
StdPeriphLib versuchen. Fahrradfahren ist auch einfacher, wenn man 
vorher ein Laufrad hatte :)

Danke für die sachlichen Beiträge!

Max

Autor: Max G. (l0wside) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag: mit Hilfe der StdPeriphLib funktioniert es jetzt. Fast: die 
Baudrate ist um den Faktor 2 daneben, aber das ist kein Desaster.

Wenn man mit dem Kopf schon durch die Wand will, sollte man vielleicht 
die Gipskartonwand statt der Betonwand nehmen...

Max

Autor: Nico W. (nico_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das damals mit dem MBED gemacht. Erstmal alles reingeladen und 
serial zum laufen bekommen und dann nach und nach den ganzen Ballast 
rausgelöscht.

https://github.com/Traumflug/Teacup_Firmware/commi...

Bei "STM32F411: get minimum to compile and upload" fängt der Spaß an. Is 
nen STM32F4 aber sollte ja analog beim deinem gehen.

Ob man dann mit der StdPeriphLib anfängt sollte auch keinen großen 
Unterschied machen. Mein kompletter Port von der Firmware für einen 
3D-Drucker ist dadurch ultra kompakt. Unter 20kB wenn ich mich recht 
erinnere.

Warum macht man das? Weil man viel lernt und es Spaß gemacht hat und es 
sau schnell ist.

: Bearbeitet durch User

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.