0
\$\begingroup\$

I am trying to use this display with an STM32F0 using SPI. I begin by setting up the peripherals using the following

RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;

GPIOB->MODER |= (0x2 << (2*12)) + (0x2 << (2*13)) + (0x2 << (2*15)) +
                (0x1 << (2*11)) + (0x1 << (2*10));

SPI2->CR1 |= SPI_CR1_BIDIMODE + SPI_CR1_BIDIOE + SPI_CR1_MSTR + SPI_CR1_BR;
SPI2->CR2 |= SPI_CR2_SSOE + SPI_CR2_NSSP;
SPI2->CR1 |= SPI_CR1_SPE;

In other words, I enable the clock to the peripherals, enable alternate funtions for the SPI NSS, MOSI, and SCK pins, as well as for the manually controlled D/CX and RST pins. I enable bidirectional mode and enable the SPI. I then initialize the LCD using commands adapted from Crystalfontz' Arduino example code (which I will not post to save space). However, once the initialization is done, the screen displays the following.

enter image description here

Clearly, this is not what I want. I attempt to fill the screen using the following functions.

void SPI_sendCommand(uint8_t command) {
    CLR_RS;
    while (!(SPI2->SR & SPI_SR_TXE));
    SPI2->DR = command;
    while (!(SPI2->SR & SPI_SR_TXE));
}

void SPI_sendData(uint8_t data) {
    SET_RS;
    while (!(SPI2->SR & SPI_SR_TXE));
    SPI2->DR = data;
    while (!(SPI2->SR & SPI_SR_TXE));
}
void setDisplayWindow(int x0, int y0, int x1, int y1) {
    SPI_sendCommand(ST7789_CASET);   // Column Address Set
    SPI_sendData(x0>>8); // X address start:
    SPI_sendData(x0);        // 0 <= XS <= X
    SPI_sendData(x1>>8); // X address end:
    SPI_sendData(x1);        // S <= XE <= X

    SPI_sendCommand(ST7789_RASET); //Row address set
    SPI_sendData(y0>>8); // Y address start:
    SPI_sendData(y0);        // 0 <= YS <= Y
    SPI_sendData(y1>>8); // Y address start:
    SPI_sendData(y1);        // S <= YE <= Y

    SPI_sendCommand(ST7789_RAMWR); //write data
}
void fillLCD(uint8_t R, uint8_t G, uint8_t B) {
    setDisplayWindow(0, 0, 239, 239);
    SET_RS;
    for (h = 0; h < 240; h++) {
        for (w = 0; w < 240; w++) {
            while (!(SPI2->SR & SPI_SR_TXE));
            SPI2->DR = R;
            while (!(SPI2->SR & SPI_SR_TXE));
            SPI2->DR = G;
            while (!(SPI2->SR & SPI_SR_TXE));
            SPI2->DR = B;
            while (!(SPI2->SR & SPI_SR_TXE));
        }
      }
    CLR_RS;
}

where CLR_RS and SET_RS clear and set the D/CX pin, respectively. These functions do not do their job, but are almost identical to the ones in the example code. My pins are set up as follows.

1  - GND                2  - Vcc (3.3 V)
3  - Open               4  - Open
5  - GND                6  - Vcc
7  - Vcc                8  - GND
9  - PB13 (SCL)         10 - PB15 (MOSI)
11 - Open               12 - PB11 (D/CX)
13 - PB12 (NSS)         14 - GND
15 - PB10 (RST)         16 - GND
17 - Open               18 - GND

I believe the issue may be with how I write data bytes to the SPI, as commands that don't take parameters, like putting the display in sleep mode, work, while commands that take parameters, like changing the brightness, do not work. Does anyone have any idea how I can get just a solid color to display on this?

\$\endgroup\$
  • 1
    \$\begingroup\$ This seems a bit mixed up, in the you are defining an SCL pin (which is I2C) and MOSI which is SPI. Another issue is that your code does not seem to manipulate the NSS pin at all, if that is being done automatically there's no indication it is being done over transactions and not individual words which could be related to why data arguments don't seem to be getting through... \$\endgroup\$ – Chris Stratton Apr 19 at 20:51
  • \$\begingroup\$ @ChrisStratton Instead of SCL I meant SCK, the SPI clock. NSS is being strobed automatically (what the SPI2-CR2 statement does), but you may have a point with the the transactions vs. words. \$\endgroup\$ – Chris Loonam Apr 19 at 20:56
  • 1
    \$\begingroup\$ Using automatic NSS control probably requires you to ensure that the TX buffer register is always full throughout the transaction. I'm not sure your while(busy) loops do that, possibly resulting in NSS being released between each byte. Try driving NSS manually and see if those start to work. \$\endgroup\$ – brhans Apr 20 at 3:25
  • \$\begingroup\$ @Chris: can you edit your title to make clear what the question is about. You don't "display color TFT Display", you display something on a TFT display. Also your question shows a photo of what you're getting but, unless I've missed it, you haven't stated what you expected to get. Are you expecting some text or a picture of Bo Diddley? \$\endgroup\$ – Transistor Apr 22 at 20:22
  • \$\begingroup\$ @Transistor I was trying to display a solid color on the TFT, but was running into the issue stated. However, I have now resolved that problem. \$\endgroup\$ – Chris Loonam Apr 22 at 20:46
2
\$\begingroup\$

After getting this working on an MSP430 using nearly identical code, and staring hard at the oscilloscope, I realized that the SPI peripheral of the STM32 was performing 'data packing' on my bytes, resulting in 16 cycles per transfer rather than 8. I resolved the issue by using this method of setting SPI2->DR.

*((uint8_t *)&SPI2->DR) = (uint8_t)data;
\$\endgroup\$
1
\$\begingroup\$

first of all you disable the CS before the transmition is over. while (!(SPI2->SR & SPI_SR_TXE)); will not work. You need to wait for TC flag before disabling the CS.

This is one of the most common mistakes

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.