- 12V Akku mit 280 Ah bauen         
Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 21

Thema: EA DOMG-163 an SPI - Ich krieg die Krise

  1. #1
    Erfahrener Benutzer Roboter Genie Avatar von White_Fox
    Registriert seit
    04.10.2011
    Beiträge
    1.473

    EA DOMG-163 an SPI - Ich krieg die Krise

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo

    Ich will oben genanntes LCD mit einem STM32 über SPI ansteuern, allerdings will das Ganze nicht wie ich.
    Datenblatt:
    http://cdn-reichelt.de/documents/dat...500/dog-me.pdf

    Das LCD wird mit 3,3V versorgt, die Beschaltung erfolgte nach Datenblatt. Die Initialisierung ebenso. Die SPI wird mit 2MHz getaktet, das macht mit dem verwendeten Taktteiler irgendwas knapp unter 8kHz.

    Init:
    void SPI2_IntHandler(DMA_HandleTypeDef *hdma_spi2_tx){
    HAL_Delay(1);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
    }

    void testLCD(){
    unsigned short pl; //pl - Pufferlänge
    unsigned long to; //to - Time Out
    char t=0;

    //Chip-Select-Pin
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET);

    //RS_Pin
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET);
    //Init-Befehle für LCD
    char lcdpuffer[] = {0b00111001, 0b00010101, 0b01010101, 0b01101110, 0b01110010, 0b00001111, 0b00000001, 0b00000110};
    pl = 8;
    to = 50;
    char s[]= "Test OK";

    //Init senden
    HAL_SPI_Transmit(&hspi2, lcdpuffer, pl, to);
    HAL_Delay(100);
    printf("LCD initialisiert\n");

    //RS_Pin
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET);
    //String in s an LCD senden
    pl = 6;
    HAL_SPI_Transmit(&hspi2, s, pl, to);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
    SPI-Init:
    /* SPI2 init function */
    static void MX_SPI2_Init(void)
    {

    hspi2.Instance = SPI2;
    hspi2.Init.Mode = SPI_MODE_MASTER;
    hspi2.Init.Direction = SPI_DIRECTION_2LINES;
    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
    hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi2.Init.NSS = SPI_NSS_SOFT;
    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi2.Init.CRCPolynomial = 10;
    if (HAL_SPI_Init(&hspi2) != HAL_OK)
    {
    Error_Handler();
    }

    }
    Hat irgendjemand eine Ahnung, warum das Scheißteil nicht kooperieren will? Die SPI jedenfalls scheint auszugeben was sie soll...sagt zumindest das Oszilloskop von einem Freund.

    PS: Langsam glaube ich an Voodoo...
    Während ich das hier schreibe und zwischendurch mal rumprobiere, habe ich die Spannung versehentlich kurz kurzgeschlossen. Ist Mist (das Netzteil liefert kontinuierlich 40A, wenn es muß), aber das LCD hat endlich mal das angezeigt was es anzeigen soll.
    Auch heute Nachmittag waren einmal kurz etwas Blödsinn drauf...

    Hat irgendjemand ne Ahnung was da los sein könnte?

    Ach...und nach Neustart funktioniert es wieder nicht.
    Geändert von White_Fox (24.10.2016 um 17:49 Uhr)

  2. #2
    Erfahrener Benutzer Roboter Genie Avatar von BMS
    Registriert seit
    21.06.2006
    Ort
    TT,KA
    Alter
    33
    Beiträge
    1.192
    Hallo White_Fox,
    habe schon mal ein ähnliches Display vom gleichen Hersteller verwendet (DOGM132), erfahrungsgemäß sind die Datenblätter eher knapp.

    Was z.B. nicht genannt wird, ob/wie lange eine Startup-Zeit eingehalten werden muss. Am einfachsten könnte man vor der Initialisierung eine Pause programmieren.
    Auch nicht spezifiziert wird, wie beim SPI die CPOL / CPHA einzustellen ist, eventuell muss man hier probieren.
    Ich kenne die HAL-Funktionen jetzt nicht näher, aber vermutlich wird zwischen dem Senden der einzelnen Intiilisierungs-Bytes keine Pause eingelegt?
    Eventuell bringt eine Pause zwischen den Befehlen etwas. Zumindest der Clear Display Befehl braucht ~1ms.
    Die Initialisierungs-Sequenz habe ich jetzt nicht überprüft. Das Datenblatt zeigt nur 8bit Initialisierungen an. Das könnte man sicherheitshalber auch nochmal mit dem Datenblatt vergleichen.

    Habe selber auch schon an einigen Displays rumprobiert, die Pausen zu programmieren hilft meist.
    Sind alle Pins richtig angeschlossen und an jedem Ausgang auch mal nachgemessen oder eine LED blinken lassen?
    Liegt der PSB-Anschluss auf GND?
    Sind Reset, VIN, VDD an 3,3V?
    Ist die Chip-Select-Leitung in Ordnung? Hat das Display einen Abblockkondensator bekommen? Ist die Betriebsspannung im Rahmen?

    Viele Grüße,
    Bernhard
    Geändert von BMS (24.10.2016 um 18:49 Uhr)
    "Im Leben geht es nicht darum, gute Karten zu haben, sondern auch mit einem schlechten Blatt gut zu spielen." R.L. Stevenson

  3. #3
    Erfahrener Benutzer Roboter Genie Avatar von White_Fox
    Registriert seit
    04.10.2011
    Beiträge
    1.473
    Hallo BMS

    Nun, das LCD hat 2s bevor die SPI Daten rausschiebt. 10ms zwischen den Befehlen hab ich schon ausprobiert. Initialisiert wird auch mit acht Bit. Taktpolarität und -phase sind im Datenblatt vom Controller...die passen soweit.

    Das LCD hat auch seinen eigenen Abblockkondensator...das sollte hinhauen. Die Betriebsspannung liegt bei stabilen 3,3V.

    und wie gesagt...aus irgendeinem mir unerfindlichen Grund hat es einmal kurz funktioniert.

  4. #4
    Erfahrener Benutzer Roboter Genie Avatar von White_Fox
    Registriert seit
    04.10.2011
    Beiträge
    1.473
    Jetzt gehts rund...

    Mit folgendem Code hab ich meinen STM32 gefüttert:

    void testLCD(){
    unsigned short pl; //pl - Pufferlänge
    unsigned long to; //to - Time Out
    char t=0;

    //Chip-Select-Pin
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET);

    //RS_Pin
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET);
    //Init-Befehle für LCD
    char lcdpuffer[] = {0b00001111, 0b00111001, 0b00010101, 0b01010101, 0b01101110, 0b01110010, 0b00111000, 0b00001111, 0b00000001, 0b00000110};
    pl = 9;
    to = 50;
    char s[]= "Test OK";

    //Init senden
    HAL_SPI_Transmit(&hspi2, lcdpuffer, pl, to);
    HAL_Delay(100);
    //printf("LCD initialisiert\n");

    HAL_Delay(10);
    //RS_Pin
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET);

    //Text senden
    HAL_SPI_Transmit(&hspi2, s, 7, 10);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
    Am Ende der Text-Übertragung habe ich mal den RS-Pin getoggelt. Und es hat funktioniert!

    Einmal Ein- und Ausschalten, und es funktioniert nicht mehr. Und ich krieg es auch nicht mehr hin daß es wieder funktioniert. Was ist das bloß für ein Mist...

  5. #5
    Erfahrener Benutzer Roboter Genie Avatar von BMS
    Registriert seit
    21.06.2006
    Ort
    TT,KA
    Alter
    33
    Beiträge
    1.192
    Wenn ich das richtig sehe, wird hier der RS-Pin getoggelt.
    Code:
    void SPI2_IntHandler(DMA_HandleTypeDef *hdma_spi2_tx){
      HAL_Delay(1);
      HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
      HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
    }
    Frage: Wozu?

    Ist diese Interrupt-Routine während der Initialisierung aktiv? Besser nicht...

    Grüße, Bernhard
    "Im Leben geht es nicht darum, gute Karten zu haben, sondern auch mit einem schlechten Blatt gut zu spielen." R.L. Stevenson

  6. #6
    Erfahrener Benutzer Roboter Genie Avatar von White_Fox
    Registriert seit
    04.10.2011
    Beiträge
    1.473
    Hallo BMS

    Errstmal: leider ist dieser Interrupt nicht aktiv. ich hab da mal im Debug-Modus einen Haltepunkt reingesetzt, jedoch kam der NIE zum Auslösen. Anscheinend stelle ich mich beim Thema Interrupt noch zu doof an.

    Den RS-Pin zu toggeln war ein Hinweis, den ich auf mikrocontroller.net gefunden habe. Da fragte auch wer, der sein LCD (gleicher Typ9 zwar initialisieren konnte, aber keine Zeichen dargestellt bekam. Wie gesagt, weil die aber nie angesprungen wird hab ich mich darum nicht mehr gekümmert die wieder rauszunehmen. Werd ich trotzdem gleich mal machen...

  7. #7
    Erfahrener Benutzer Roboter Genie Avatar von White_Fox
    Registriert seit
    04.10.2011
    Beiträge
    1.473
    So...es reicht. Ich werde jetzt erstmal von dem HAL-Kram wegkommen und das Ganze selber per Registereintrag machen.

    Ich meld mich wieder, wenns klappt...oder nicht...

  8. #8
    Erfahrener Benutzer Roboter Genie Avatar von White_Fox
    Registriert seit
    04.10.2011
    Beiträge
    1.473
    Also...ich hab in der letzten Woche das Ganze mal ohne den HAL-Kram nochmal gemacht. Um keine Verwirrung aufkommen zu lassen, der Code enthält neben der SPI-LCD-Sache noch Inits für ein paar LEDs und Taster und zukünftige Sachen...die sind aber nicht weiter wichtig bzw. funktionieren.

    Das LCD sagt wieder nichts...ich hab aber gestern mal wieder (zufällig) ein paar wirre Zeichen auf dem LCD gehabt. War nicht reproduzierbar. Langsam glaube ich aber eine Gemeinsamkeit zwischen diesem "zufälligen" Funktionieren zu erkennen. Ich hatte wohl immer ein Oszilloskop an MOSI, oder an Clk oder an beiden Pins. Ich kann allerdings nicht vorstellen, daß das Oszi vllt einen dringend notwendigen Pulldown-Widerstand geliefert hat. Immerhin hab ich die Pins des STM32 als Push-Pull-Stufen konfiguriert.

    Drei Fragen:
    1.: Kann irgendjemand aus dem Code herauslesen, ob ich etwas falsch gemacht habe?
    Datenblatt LCD: http://www.reichelt.de/index.html?AC...252Fdog-me.pdf
    Datenblatt LCD-Controller: http://www.lcd-module.de/eng/pdf/zubehoer/st7036.pd
    Die SPI-Konfiguration ist auf Seite 47 dargestellt.

    Die Registerbeschreibung für den STM32 sind hier:
    http://www.st.com/content/ccc/resour...DM00135183.pdf
    Die Beschreibung der SPI-Schnittstelle fängt ab S. 848 an, die Controllregister werden auf S. 888 beschrieben.

    Ich habe, um die Timings zu verlängern, mal vor jeder Datenübertragung (SndBfhlLCD() und SndDtnLCD()) einen Haltepunkt gesetzt und das Programm im Debug-Modus laufen lassen. >Kein Erfolg.

    2.: Sieht die Taktkonfiguration OK aus? Ich benutze keinen Quarz, mit wieviel die CPU befeuert wird ist erstmal nicht so wichtig. Daher hab ich die PLL in Ruhe gelassen. Den Bus, an dem die SPI2 hängt, will ich niedriger takten damit ich sicherheitshalber eine niedrige SPI-Frequenz generieren kann. Bei meiner aktuellen Einstellung sollte der SPI-Clock bei <10kHz liegen. Ich kann mir schwer vorstellen daß das für das LCD zu rasch ist.

    3.: Irgendwas mache ich bei der Interupt-Konfiguration noch falsch. Gibt es irgendwo sowas wie "Interrupts global aktivieren" (sei-Befehl bei den AVRs), den ich übersehen habe? Der SPI-Interrupt wird nie angesprungen.


    Ich hoffe, irgendwer hat da eine Lösung für...
    Ach ja, anbei noch der Code:
    Code:
    /*********************************************************************
    *               SEGGER MICROCONTROLLER GmbH & Co. KG                 *
    *       Solutions for real time microcontroller applications         *
    **********************************************************************
    *                                                                    *
    *       (c) 2014 - 2016  SEGGER Microcontroller GmbH & Co. KG        *
    *                                                                    *
    *       www.segger.com     Support: support@segger.com               *
    *                                                                    *
    **********************************************************************
    
    -------------------------- END-OF-HEADER -----------------------------
    
    File    : main.c
    Purpose : Generic application start
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <stm32f446xx.h>
    
    //Takteinstellungen konfigurieren
    void TaktInit(){
      //APB1: Tim6, SPI2, USART3
      //AHB1: PortE, PortB, PortC
      //APB2: Tim1
    
      //SysClk 16MHz (interner Oszillator) - Takt für APB1 auf 2MHz setzen
    
      RCC->CFGR |= RCC_CFGR_HPRE_DIV1;      //AHB-Prescaler /1 => 16NHz
      RCC->CFGR |= RCC_CFGR_PPRE1_DIV8;     //Takt für APB1 = AHB/8
    }
    
    //Nested Vector Interrupt Controller konfigurieren
    void NVICInit(){
      NVIC_EnableIRQ(SPI2_IRQn);
    }
    
    //Pins, die als einfache Standard-EAs (Taster/LEDs) verwendet werden,konfigurieren
    void EAInit(){
      //Pins für LEDs initialisieren
      RCC->AHB1ENR |= RCC_AHB1ENR_GPIOEEN;      //Takt für PortE aktivieren
      //PE0
      GPIOE->MODER |= GPIO_MODER_MODER0_0;
      GPIOE->MODER &= ~GPIO_MODER_MODER0_1;     //PE0 -> Ausgang MODER ->01
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_0;       //PE0 als Push-Pull-Stufe
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR0; //PE0 High-Speed
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR0_0;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR0_1;     //Pull-up/-down-Widerstände abschalten
      GPIOE->BSRR|= GPIO_BSRR_BS_0;             //LED abschalten
      //PE1
      GPIOE->MODER |= GPIO_MODER_MODER1_0;
      GPIOE->MODER &= ~GPIO_MODER_MODER1_1;     //PE1 -> Ausgang MODER ->01
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_1;       //PE1 als Push-Pull-Stufe
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR1; //PE1 High-Speed
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR1_0;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR1_1;     //Pull-up/-down-Widerstände abschalten
      GPIOE->BSRR|= GPIO_BSRR_BS_1;             //LED abschalten
      //PE2
      GPIOE->MODER |= GPIO_MODER_MODER2_0;
      GPIOE->MODER &= ~GPIO_MODER_MODER2_1;     //PE2 -> Ausgang MODER ->01
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_2;       //PE2 als Push-Pull-Stufe
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR2; //PE2 High-Speed
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR2_0;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR2_1;     //Pull-up/-down-Widerstände abschalten
      GPIOE->BSRR|= GPIO_BSRR_BS_2;             //LED abschalten
      //PE3
      GPIOE->MODER |= GPIO_MODER_MODER3_0;
      GPIOE->MODER &= ~GPIO_MODER_MODER3_1;     //PE3 -> Ausgang MODER ->01
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_3;       //PE3 als Push-Pull-Stufe
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR3; //PE3 High-Speed
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR3_0;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR3_1;     //Pull-up/-down-Widerstände abschalten
      GPIOE->BSRR|= GPIO_BSRR_BS_3;             //LED abschalten
      //PE4
      GPIOE->MODER |= GPIO_MODER_MODER4_0;
      GPIOE->MODER &= ~GPIO_MODER_MODER4_1;     //PE4 -> Ausgang MODER ->01
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_4;       //PE4 als Push-Pull-Stufe
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR4; //PE4 High-Speed
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR4_0;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR4_1;     //Pull-up/-down-Widerstände abschalten
      GPIOE->BSRR|= GPIO_BSRR_BS_4;             //LED abschalten
      //PE5
      GPIOE->MODER |= GPIO_MODER_MODER5_0;
      GPIOE->MODER &= ~GPIO_MODER_MODER5_1;     //PE5 -> Ausgang MODER ->01
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_5;       //PE5 als Push-Pull-Stufe
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5; //PE5 High-Speed
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR5_0;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR5_1;     //Pull-up/-down-Widerstände abschalten
      GPIOE->BSRR|= GPIO_BSRR_BS_5;             //LED abschalten
      //PE6
      GPIOE->MODER |= GPIO_MODER_MODER6_0;
      GPIOE->MODER &= ~GPIO_MODER_MODER6_1;     //PE6 -> Ausgang MODER ->01
      GPIOE->OTYPER &= ~GPIO_OTYPER_OT_6;       //PE6 als Push-Pull-Stufe
      GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6; //PE6 High-Speed
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR6_0;
      GPIOE->PUPDR &= ~GPIO_PUPDR_PUPDR6_1;     //Pull-up/-down-Widerstände abschalten
      GPIOE->BSRR|= GPIO_BSRR_BS_6;             //LED abschalten
    
      //Pins für Taster initialisieren
      //PB5
      GPIOB->MODER &= ~GPIO_MODER_MODER5_0;
      GPIOB->MODER &= ~GPIO_MODER_MODER5_1;     //PB5 -> Eingang MODER ->00
      GPIOB->OTYPER &= ~GPIO_OTYPER_OT_5;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR5_0;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR5_1;
      GPIOB->PUPDR |= GPIO_PUPDR_PUPDR5_0;
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR5_1;     //Pull-up-Widerstände einschalten PUPDR ->0
      //PB6
      GPIOB->MODER &= ~GPIO_MODER_MODER6_0;
      GPIOB->MODER &= ~GPIO_MODER_MODER6_1;     //PB6 -> Eingang MODER ->00
      GPIOB->OTYPER &= ~GPIO_OTYPER_OT_6;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR6_0;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR6_1;
      GPIOB->PUPDR |= GPIO_PUPDR_PUPDR6_0;
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR6_1;     //Pull-up-Widerstände einschalten PUPDR ->01
      //PB7
      GPIOB->MODER &= ~GPIO_MODER_MODER7_0;
      GPIOB->MODER &= ~GPIO_MODER_MODER7_1;     //PB7 -> Eingang MODER ->00
      GPIOB->OTYPER &= ~GPIO_OTYPER_OT_7;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR7_0;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR7_1;
      GPIOB->PUPDR |= GPIO_PUPDR_PUPDR7_0;
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR7_1;     //Pull-up-Widerstände einschalten PUPDR ->01
      //PB12
      GPIOB->MODER &= ~GPIO_MODER_MODER12_0;
      GPIOB->MODER &= ~GPIO_MODER_MODER12_1;     //PB12 -> Eingang MODER ->00
      GPIOB->OTYPER &= ~GPIO_OTYPER_OT_12;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR12_0;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR12_1;
      GPIOB->PUPDR |= GPIO_PUPDR_PUPDR12_0;
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR12_1;     //Pull-up-Widerstände einschalten PUPDR ->01
      //PB13
      GPIOB->MODER &= ~GPIO_MODER_MODER13_0;
      GPIOB->MODER &= ~GPIO_MODER_MODER13_1;     //PB13 -> Eingang MODER ->00
      GPIOB->OTYPER &= ~GPIO_OTYPER_OT_13;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR13_0;
      GPIOB->OSPEEDR &= ~GPIO_OSPEEDER_OSPEEDR13_1;
      GPIOB->PUPDR |= GPIO_PUPDR_PUPDR13_0;
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR13_1;     //Pull-up-Widerstände einschalten PUPDR ->01
    }
    
    //SPI2 konfigurieren, es wird nur ein LCD damit bedient.
    void SPIInit(){
      //Taktversorgung aktivieren
      RCC->AHB1ENR |= RCC_APB1ENR_SPI2EN;       //Takt für SPI2 aktivieren
      RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;      //Takt für PortB aktivieren
      RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;      //Takt für PortC aktivieren
    
      //Pins konfigurieren
      //PB10 -> SPI2-Clock
      GPIOB->MODER &= ~GPIO_MODER_MODER10_0;
      GPIOB->MODER |= GPIO_MODER_MODER10_1;         //PB10 -> Alternate Function MODER ->10
      GPIOB->OTYPER &= ~GPIO_OTYPER_OT_10;          //PB10 als Push-Pull-Stufe
      GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10_0;
      GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10_1;  //PB10 High-Speed
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR10_0;
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR10_1;        //Pull-up/-down-Widerstände abschalten
      GPIOB->AFR[1] |= (0b0101<<8);                 //SPI2 AF5
    
      //PB15 -> SPI2-MoSi
      GPIOB->MODER &= ~GPIO_MODER_MODER15_0;
      GPIOB->MODER |= GPIO_MODER_MODER15_1;         //PB15 -> Alternate Function MODER ->10
      GPIOB->OTYPER &= ~GPIO_OTYPER_OT_15;          //PB15 als Push-Pull-Stufe
      GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15_0;  
      GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15_1;  //PB15 High-Speed
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR15_0;
      GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR15_1;        //Pull-up/-down-Widerstände abschalten
      GPIOB->AFR[1] |= (0b0101<<28);                 //SPI2 AF5
    
      //PC3 -> SPI2-Select LCD
      GPIOC->MODER |= GPIO_MODER_MODER3_0;
      GPIOC->MODER &= ~GPIO_MODER_MODER3_1;         //PC3 als Ausgang MODER ->01
      GPIOC->OTYPER &= ~GPIO_OTYPER_OT_3;           //PC3 als Push-Pull-Stufe
      GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR3_0;
      GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR3_1;   //PC3 High-Speed
      GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR3_0;
      GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR3_1;         //Pull-up/-down-Widerstände abschalten
    
      //PC2 -> SPI2-R/S
      GPIOC->MODER |= GPIO_MODER_MODER2_0;
      GPIOC->MODER |= GPIO_MODER_MODER2_1;          //PC2 als Ausgang MODER ->01
      GPIOC->OTYPER &= ~GPIO_OTYPER_OT_3;           //PC2 als Push-Pull-Stufe
      GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR2_0;
      GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR2_1;   //PC2 als High-Speed
      GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR2_0;
      GPIOC->PUPDR &= ~GPIO_PUPDR_PUPDR2_1;         //Pull-up/-down-Widerstände abschalten
    
      //SPI konfigurieren
      SPI2->CR1 |= SPI_CR1_BIDIMODE;                //Bidirektionaler Modus
      SPI2->CR1 |= SPI_CR1_BIDIOE;                  //Nur senden
      SPI2->CR1 &= SPI_CR1_CRCEN;                   //CRC-Berechnung abschalten
      SPI2->CR1 &= ~SPI_CR1_CRCNEXT;                //Keine CRC-Phase
      SPI2->CR1 &= ~SPI_CR1_DFF;                    //8-Bit Frameformat
      SPI2->CR1 &= ~SPI_CR1_RXONLY;                 //Receive-Only-Modus abschalten
      SPI2->CR1 &= ~SPI_CR1_SSM;                    //Software Slave Management abschalten
      //SPI2->CR1 &= ~SPI_CR1_SSI;                    //NSS-Pin
      SPI2->CR1 &= ~SPI_CR1_LSBFIRST;               //MSB zuerst übertragen
      SPI2->CR1 |= SPI_CR1_SPE;                     //SPI aktivieren
      SPI2->CR1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0; //Taktteiler 256 -> 2MHz/256 -> 7,8kHz
      SPI2->CR1 |= SPI_CR1_MSTR;                    //Master configuration
      SPI2->CR1 |= SPI_CR1_CPOL;                    //Takt=1 im Leerlauf
      SPI2->CR1 &= ~SPI_CR1_CPHA;                   //Clockphase, first clock transistion is first data capture edge
    
      SPI2->CR2 |= SPI_CR2_TXEIE;                   //Tx-buffer empty interupt aktivieren
      SPI2->CR2 &= ~SPI_CR2_RXNEIE;                 //Rx-buffer not empty interrupt deaktivieren
      SPI2->CR2 &= ~SPI_CR2_ERRIE;                  //Error Interrupt deaktivieren
      SPI2->CR2 &= ~SPI_CR2_FRF;                    //Motorola-Modus (Sandard)
      SPI2->CR2 &= ~SPI_CR2_SSOE;                   //SS Output deaktivieren
      SPI2->CR2 &= ~SPI_CR2_TXDMAEN;                //TXE DMA-Request deaktivieren
      SPI2->CR2 &= ~SPI_CR2_RXDMAEN;                //RXNE DMA Request deaktivieren
    }
    
    void LCDInit(){
      SndBfhlLCD(0b00111001);
      SndBfhlLCD(0b00010101);
      SndBfhlLCD(0b01010101);
      SndBfhlLCD(0b01101110);
    
      SndBfhlLCD(0b01110010);
      SndBfhlLCD(0b00111000);
      SndBfhlLCD(0b00001111);
      SndBfhlLCD(0b00000001);
      SndBfhlLCD(0b00000110);
      printf("Init-Befehle an LCD gesendet\n");
    }
    
    //Sendet ein Byte ans LCD
    void SndLCD(char Byte){
      while (SPI2->SR & SPI_SR_TXE){              //Warten bis Transmitpuffer frei ist
      }
      SPI2->DR = Byte;                              //Byte ins Transmitregister schreiben
    }
    
    //Sendet ein Befehlbyte ans LCD
    void SndBfhlLCD(char byte){
      while (SPI2->SR & SPI_SR_TXE){              //Warten bis Transmitpuffer frei ist
      }
      GPIOC->BSRR |= GPIO_BSRR_BR_2;              //RS-Pin zurücksetzen
      SPI2->DR = byte;                            //Byte senden
      while(SPI2->SR & SPI_SR_TXE){                     //Warten bis Übertragung abgeschlossen ist
      }
      //RS NICHT toggeln
    }
    
    //Sendet ein Datenbyte ans LCD
    void SndDtnlLCD(char byte){
      while (SPI2->SR & SPI_SR_TXE){              //Warten bis Transmitpuffer frei ist
      }
      GPIOC->BSRR |= GPIO_BSRR_BS_2;              //RS-Pin setzen
      SPI2->DR = byte;                            //Byte senden
      while(SPI2->SR & SPI_SR_TXE){               //Warten bis Übertragung abgeschlossen ist
      }
      GPIOC->BSRR |= GPIO_BSRR_BS_2;              //RS toggeln
      GPIOC->BSRR |= GPIO_BSRR_BR_2;
    }
    
    //SPI2 Interrupt
    void SPI2_IRQHandler (void){
      GPIOE->BSRR |= GPIO_BSRR_BR_4;              //LED an E4 einschalten
      printf("SPI2 Interrupt Event\n");
    }
    
    void main(void){
      TaktInit();
      NVICInit();
      EAInit();
    
      GPIOE->BSRR |= GPIO_BSRR_BR_5;              //LED an E5 einschalten
    
      SPIInit();
      LCDInit();
    
      SndDtnlLCD('T');
      SndDtnlLCD('e');
      SndDtnlLCD('s');
      SndDtnlLCD('t');
      SndDtnlLCD(' ');
      SndDtnlLCD('O');
      SndDtnlLCD('K');
    
      GPIOE->BSRR |= GPIO_BSRR_BR_1;              //LED an E1 einschalten
    }
    Geändert von White_Fox (06.11.2016 um 16:48 Uhr) Grund: Code aktualisiert

  9. #9
    Erfahrener Benutzer Roboter Genie Avatar von White_Fox
    Registriert seit
    04.10.2011
    Beiträge
    1.473
    Hat niemand eine Idee? Schade.

    Ich hab den Code heute um folgende While-Schleife in der main ergänzt:
    while(1){
    printf("Klack\n");
    LCDInit();
    SndDtnlLCD('T');
    SndDtnlLCD('e');
    SndDtnlLCD('s');
    SndDtnlLCD('t');
    SndDtnlLCD(' ');
    SndDtnlLCD('O');
    SndDtnlLCD('K');
    }
    Ziel war, mit einem Oszilloskop zu prüfen ob die SPI wenigstens überhaupt muckt. Aber da kommt nichts...absolut nichts. Jetzt frag ich mich doch, warum? Ich hab mal den Code durchgesehen den mir die Cube generiert hat. Das Einzige, was ich nicht gemacht habe, war, den Power-Controller zu konfigurieren (PWR). Die Cube schreibt noch irgendwas in die VOS-Bits. Aber das ist für die SPI doch auch gar nicht notwendig, wenn ich das Datenblatt richtig verstehe...und GPIOs funktionieren ja auch.

  10. #10
    Benutzer Stammmitglied
    Registriert seit
    19.05.2015
    Beiträge
    69
    Hallo,

    mir fallen einige Dinge bei der ganzen Sache auf. Leider bin ich schon eine Weile aus der STM32 Programmierung heraus, so dass das was ich hier schreibe eher als Hinweise denn als Lösungen zu verstehen sind.

    Zuerst der SPI-Takt, damit liegst du meiner Meinung nach ziemlich daneben. Im Datenblatt des Controlers vom LCD ist hinten ein Diagramm und eine Tabelle zu finden, in der steht, dass die CLK-Zyklen mindesten 200ns lang sein müssen. Wenn ich mich nicht verrechne, dann sind das 5MHz und da würde ich auch den SPI-Bus-Takt so nahe wie möglich heranbringen. Da du eh mit dem internen Clock-Mechanismus des STM arbeitest und der 16MHz abgibt, würde ich den APB1-Bustakt auf 16MHz stehen lassen und im SPI2->CR1 Register mit dem Vorteiler 4MHz einstellen.

    Im Verhältnis zu dem, was der STM an Datenmenge ans SPI anlegen kann und wie schnell der LCD-Controller das verarbeiten kann, besteht 'ne gewisse Diskrepanz. Wenn du dir mal die Initialisierungssequenz vom LCD-Controler ansiehst, dann sind da mehrere Wartezeiten angegben. Von ca. 27uS nach Commando-Bytes (entspricht ca. 13 Bytes die du bei 4MHz losschicken könntest), über 40ms nach dem Reset, bis hin zu einem besonderem Befehl, der 200ms zur Verarbeitung braucht, bevor der Controler überhaupt das nächste Commando oder Datenbyte verabeiten könnte.
    Diese Zeiten müssen eingehalten werden und so schließt es sich aus, dass du Interruptgetrieben ein Byte nach dem anderen übertragen könntest.

    Daher würde ich das SPI2->CR2 Register mit den Interrupts einfach mal in Ruhe lassen (auskommentieren), dann ein Byte nach dem anderem übertragen und dazwischen SPI abschalten und die Wartezeiten einhalten.

    Ein klarer Fehler liegt bei dir in der Verwendung des SPE-Bits im CR1 Register vor.
    Du schaltest das Ding an und konfigurierst noch weiter z.B. MSTR, CPOL, CPHA und das gesamte CR2 Register. Zumindestens bei den Bits steht im Prog-Manual drin, dass man diese Bits nicht bei laufender Peripherie setzen darf. Auch beim Teiler für den SPI-Takt steht das dabei und ziemlich sicher ist das der Grund, dass du nichts am Oszi sehen konntest.
    Also alles konfigurieren ohne das SPE Bit. Das wird erst in der Übertragungfunktion gesetzt, die für ein Commando Byte im Pseudo-Code so lautet:
    Code:
    RS Leitung setzen
    CS Leitung setzen
    SPE Bit setzen (einschalten)
    TXE Bit pollen bis DR frei ist
    DR beschreiben
    TXE Bit pollen bis DR frei ist
    BSY Bit pollen bis es 0 ist (Übertragung vollständig)
    SPE zurück setzen (ausschalten)
    Wichtig ist vor dem Ausschalten das Busy-Bit zu kontrollieren, da das Datum im DR Register in ein internes Shift-Register kopiert wird. Das setzt das TXE Bit, bedeutet aber noch nicht das die Übertragung komplett ist. Die ist erst vollständig, wenn das Busy-Bit zu 0 wird!

    Gruss botty

Seite 1 von 3 123 LetzteLetzte

Ähnliche Themen

  1. noch ne seltsame Rechenfunktion - ich krieg die Krise!
    Von dl1akp im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 17.08.2008, 21:44
  2. wie, krieg ich die hex auf dem board
    Von Sp666dy im Forum AVR Hardwarethemen
    Antworten: 2
    Letzter Beitrag: 25.02.2008, 08:34
  3. Menü - ich krieg die Krise!!!
    Von dl1akp im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 3
    Letzter Beitrag: 18.11.2007, 15:41
  4. Wo krieg ich BASCOM Basic her?
    Von zwerg1 im Forum AVR Hardwarethemen
    Antworten: 23
    Letzter Beitrag: 13.02.2007, 23:34
  5. [ERLEDIGT] Wo krieg ich Baupläne her
    Von Aramis im Forum Elektronik
    Antworten: 5
    Letzter Beitrag: 05.09.2004, 11:16

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiFePO4 Speicher Test