www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32: Über SPI ein TFT ansteuern (R61505U)


Autor: Lasse S. (cowz) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich habe hier ein TFT mit einem R61505U-Controller.

Dieser lässt sich über SPI ansteuern. Das klappt mit einem AVR auch ohne 
Probleme.

Nun möchte ich den AVR-Code (avr.c) auf einen STM32F103RB auf dem 
Olimex-H103 portieren.

Dabei funktioniert das Display nicht, bzw. es reagiert gar nicht erst.

Im Anhang findet ihr meinen AVR-Code (avr.c), unten die SPI-Funktionen 
für den STM.

Ich kann mir eigentlich nur vorstellen, dass der Fehler irgendwo in der 
SPI-Initialisierung oder den Funktionen spi_write und spi_wait liegt. 
Auch denkbar wären Compilersachen, die der AVR-GCC anders übersetzt als 
der CodeSourcery für meinen Cortex-M3.

Ich hoffe, ihr könnt mir helfen, bin mittlerweile etwas ratlos ;)

Gruß
Lasse

void DISPLAY_init(void) {

  SPI_InitTypeDef SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  // Clock enable
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

  // GPIO Init (SPI1)
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  // GPIO Init RST
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  LCD_RST_DISABLE();

  // GPIO Init CS
  GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  LCD_CS_DISABLE();


  // SPI Init
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8b
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // high
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 2 Edge
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //TODO: Geschwindkeiten testen
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // MSB
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPI1, &SPI_InitStructure);
  SPI_Cmd(SPI1, ENABLE);
}
void spi_write(uint8_t data) {
  SPI_I2S_SendData(SPI1, (uint16_t)data);
  spi_wait();
}
void spi_wait(void) {
  while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
}

Autor: STM32-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Habe den Quelltext und das Datenblatt des TFT-Controllers zwar nur 
"kurz" überflogen, aber hast du nicht vergessen beim Code für den Cortex 
die Chip Select Leitungen zu setzen bzw. rücksetzen in spi_write() ??

Habe zwar kein adäquates Beispiel mit einer Ansteuerung für ein TFT über 
SPI, aber mit einem OLED. Bei mir sieht der Code folgendermaßen aus, 
bitte mit der Beachtung, dass ich die alte Firmware Library des STM32 
verwende(Version 1.0):

Vermute bei dir ebenfalls den Fehler in spi_write() und vor allem in 
spi_wait()
static void
write_oled( uint32_t byte_packet )
{
  uint16_t spi_rx_dummy = 0;
  // Enable chip select
  _CS_CLR;
  // Do a dummy read
  spi_rx_dummy = SPI_ReceiveData(SPI1);
  // Loop while DR register is not empty
  while (SPI_GetFlagStatus( SPI1, SPI_FLAG_TXE  ) == 0);
  SPI_SendData(SPI1, (uint16_t) byte_packet);
  // Wait to receive one byte
  while(!SPI_GetFlagStatus( SPI1, SPI_FLAG_RXNE ) == 0);
  spi_rx_dummy = SPI_ReceiveData(SPI1);
}

MfG

Autor: Lasse S. (cowz) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

das mit CS ist nicht das Problem, dass funktioniert bei der AVR-Version 
auch ohne.

Unten nochmal die SPI-Funktionen auf dem AVR.

Eigentlich müsste das SPI auf dem STM doch genauso initialisiert sein, 
wie das auf dem AVR, oder?

Gruß
Lasse
void spi_init(void) {  
  
  // Set pinout
  PORTB |= (1<<SS);
  PORT_SPI |= (1<<MISO);
  PORT_SPI &= ~(1<<SCK);
  DDR_SPI |= (1<<SS) | (1<<SCK) | (1<<MOSI);
  
  // Set SPI  
  SPCR = (1<<SPE)    // SPI enable
     | (1<<MSTR);  // master mode

  // Fast Speed
  SPCR &= ~((1<< SPR1) | (1<<SPR0));
  SPSR |= (1<<SPI2X);
  // Slow Speed
  //SPCR |= (1<< SPR1) | (1<<SPR0);
  //SPSR &= ~(1<<SPI2X);
}

/* 
 * Sends byte over spi
 */
void spi_write(uint8_t data) {
  SPDR = data;
  
  while(!(SPSR & (1<<SPIF))) {
    asm volatile ("nop");
  }
}


void spi_wait(void) {
  while(!(SPSR & (1<<SPIF))) {
    asm volatile ("nop");
  }
}

Autor: STM32-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Klar, die Initialisierung auf dem AVR und dem Cortex sollte gleich sein. 
Ob das wirklich so ist, ist eine andere Frage...
Hast du CPOL und CPHA korrekt konfiguriert und überprüft? Werden 
überhaupt Daten gesendet(messen)? Ich weiß, dass ich damals auch 
Startschwierigkeiten damit hatte, deshalb würde ich dir empfehlen, die 
Register wirklich GENAU zu kontrollieren und sicherzustellen, ob alles 
richtig ist, gegebenfalls das Reference Manual nochmals genau lesen, vor 
allem zu CPOL, CPHA und NSS.
Eventuell könnte es Probleme mit der Geschwindigkeit geben. Du 
verwendest "nur" einen Prescaler von 2, ist das nicht etwas zu schnell, 
bei ich denke mal 72MHz MCU-Speed?

Schönen Abend noch...

Autor: Lasse S. (cowz) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Krass. Also erstmal: Danke schön! Ich stelle immer wieder fest, dass 
dieses Forum seeehr hilfreich ist!


Faszinierend: Ich hatte die gleiche Idee wie du... Nur habe ich es mit 
zwei Extremwerten ausprobiert, es funktioniert, sobald ich einen 
Prescaler von 16 einstelle!

Vielen Dank!

Gruß
Lasse

Autor: Lasse S. (cowz) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
(edit nicht mehr erlaubt)

Mich wundert jetzt nur noch, dass es nur funktioniert, wenn der 
Prescaler zwischen 4 und 16 liegt. Dass das ganze nicht mehr 
funktioniert, wenn das SPI zu schnell ist (Prescaler=2) kann ich ja 
verstehen. Aber warum funktioniert das bei Prescaler=32 nicht mehr?

Gruß
Lasse

PS: In der Praxis isses mir egal, weil ich mich darüber freue, dass es 
funktioniert, und je schneller desto besser. Aber in der Theorie 
interessiert es mich. Zumal es beim AVR mit maximaler und minimaler 
Frequenz funktioniert hat.

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.