cancel
Showing results for 
Search instead for 
Did you mean: 

How to swap little-endian to big-endian in TouchGFX?

KYama.1
Associate III

Hi Community,

I'm trying to connect STM32F412 with SPI LCD (ILI9341). And, I'm trying to run TouchGFX on this combination. The white and black color is correct. However, another colors are strange. I think that the endian is swapped. Might be, TouchGFX supports only little endian.

This ILI9341 device only support big-endian at using SPI port. If I use parallel port, it can choose both little-endian and big-endian. However, the target board supports only SPI.

So, I'd like to swap little-endian to big-endian at drawing. Where code do I need to modify?

Please give me your advice. Thank you.

Best regards,

Kotetsu

14 REPLIES 14

You can change order of bits in SPI, using the SPI_CR1.LSBFIRST bit, and MSB-first is the default setting.

Don't you by chance use SPI bytewise, rather than half-word-wise? That, combined with MSB-first, would indeed produce strange results, if you use RGB565 (i.e. the 16-bit format).

JW

Hi JW,

Thank you for your reply.

No, I use bytewise. Because, this LCD requires to send byte for command. Anyway, I see that RGB565 and bytewise will cause a problem. I'm going to try to change transfer bit width at transmitting data.

Best regards,

Kotetsu

Can you please let us know how did this solution work?

JW

Hi,

Please check my GitHub.

https://github.com/kotetsuy/TouchGFXDemo

Best regards,

Kotetsu

KYama.1
Associate III

Hi,

Unfortunately, the change SPI transfer wise doesn't solve my issue.

I use HAL_SPI_Transmit_DMA. And, I modified DMA parameter several pattern and modified SPI bit wise. However, I couldn't solve issue.

I made the software converter before transferring DMA.

The code is here;

static void ConvHL(uint8_t *s, int32_t l)

{

uint8_t v;

while (l > 0) {

v = *(s+1);

*(s+1) = *s;

*s = v;

s += 2;

l -= 2;

}

}

ConvHL(s, (int32_t)w*h*2);

HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)s, w * h * 2);

Also, I updated my GitHub.

Best regards,

Kotetsu

hi, chiming here just because i had a look to the pinout on the github page

BTW thanx a lot for the sharing! it's a neat little project you have here..

porting TouchGFX on a SPI LCD, how good are the raw performance for example frame rate?

anyway my comment was about the "wiring": i see both LCD & Touch do have a SPI interface so i was wondering if you were planning to share the bus between the two ICs LCD ad Touch (toggling accordingly the two ChipSelect bits) to reduce a bit the number of wires!

the Touch control is very light on the TouchGFX library, at least for the version 4.10.0 i'm using: currently every "frame refresh" (60Hz i think), the lib polls the device over the bus (my Touch ctrl is an I2C one, but i suppose the working model is the same for your SPI too..), so it's pretty heavy on the bus without a reason (as it mainly return empty as not touch is occurred..)

as touch events are pretty rare and slow too (human source indeed!), i just had to put a simple GPI read on the "TS_IRQ" wire (so really very easy, as i do not need to manage the IRQ mode of the GPI on the STM32 FW) to filter out the 99.99% of SPI bus transaction related to touch..

that's way the bus is practically always left to the DMA to write to LCD!

that IMHO would be a pretty little optimization to shrink a bit the "spaghetti connection" between the boards! :)

sorry again if this is slightly hijacking your quest :) , but can't help you for the "reordering" of the bytes during transaction (but i'd be a very amazed if there's no way to do it "the hard way"! maybe buried down in some pretty obscure register)

Hi,

Thank you for your reply.

Unfortunately, my board doesn't share the SPI pins for each LCD and Touch.

So, I need to connect 4 wires for each port.

The raw frame rate is 20fps at drawing all screen.

Anyway, I'm a success to run TouchGFX on SPI LCD and Touch.

Please check the following URL.

https://github.com/kotetsuy/TouchGFXDemo/tree/master/GUITestNoOS

Also, please check youTube.

https://youtu.be/tz8haqRtUfs

Enjoy !

Best regards,

Kotetsu

johnLocke
Associate II

Hi.

I've been trying to solve the same problem for a while. But I didn't succeed. The ConHL function in the ILI9341 library seems not to work. Also, as stated in the ILI9341 datasheet, the parameters at address 0xF6 have endian settings. Although I changed these parameters, I could not get any results.I am using 2.4 inch spi tft with STM32H750. The color format is rgb565.

I look forward to your help. Thank you.

Jack3
Senior II

ConvHL would work, but it would modify your frame buffer, and you have to convert it back afterwards, which is time consuming and inconvenient.

You should try to leave the byteswapping to the hardware.

The ByteSwap configuration on the ILI9341 display does not work in SPI mode, unfortunately, as stated in the datasheet.

And sometimes you just have to stick to a particular byte order. Say if you are using Chrom-Art (DMA2D) for instance. While just copying a rectangle just works fine, the BS (ByteSwap) bit for DMA2D (if available at all) doesn't do a great job when blending fonts (A4) onto the background (RGB565). (It probably needs an additional bit for that in the future).

Anyway, the next method may help you solve your problem, by just leaving the byte swapping to the hardware, using the next trick.

For this to happen, you can temporarily configure the SPI bus for 16-bit mode, so when you transfer your buffer, the bytes would be send swapped 2-by-2, automatically.

So let's say you function to transfer your buffer would look something like this, sending byte for byte (but the wrong order for the display):

void ILI9341_WriteData(uint8_t* buff, uint32_t buff_size)
{
  SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)buff) & ~(uint32_t)(__SCB_DCACHE_LINE_SIZE - 1U)), buff_size + __SCB_DCACHE_LINE_SIZE); /* Mem-to-Peri */
  HAL_GPIO_WritePin(ILI9341_DC_PORT, ILI9341_DC_PIN, GPIO_PIN_SET);
#if defined SW_CS_PIN
  HAL_GPIO_WritePin(ILI9341_CS_PORT, ILI9341_CS_PIN, GPIO_PIN_RESET);
#endif
  uint16_t buff_size_max = 65536 - 4;
  // Split data in smaller almost 64k chunks, because HAL can't send 64K at once.
  while (buff_size > 0)
  {
    uint16_t chunk_size = buff_size > buff_size_max ? buff_size_max : buff_size;
    HAL_SPI_Transmit(&ILI9341_SPI_PORT, buff, chunk_size, HAL_MAX_DELAY);
    buff += chunk_size;
    buff_size -= chunk_size;
  }
#if defined SW_CS_PIN
  HAL_GPIO_WritePin(ILI9341_CS_PORT, ILI9341_CS_PIN, GPIO_PIN_SET);
#endif
}

We could make a function like this, which also sends the data, but in the right byte order for the display:

void ILI9341_WriteData16(uint8_t* buff, uint32_t buff_size)
{
  SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)buff) & ~(uint32_t)(__SCB_DCACHE_LINE_SIZE - 1U)), buff_size + __SCB_DCACHE_LINE_SIZE); /* Mem-to-Peri */
  HAL_GPIO_WritePin(ILI9341_DC_PORT, ILI9341_DC_PIN, GPIO_PIN_SET);
#if defined SW_CS_PIN
  HAL_GPIO_WritePin(ILI9341_CS_PORT, ILI9341_CS_PIN, GPIO_PIN_RESET);
#endif
  // Set SPI to 16-bit
  ILI9341_SPI_PORT.Init.DataSize = SPI_DATASIZE_16BIT;
  HAL_SPI_Init(&ILI9341_SPI_PORT);
  // Split data in smaller, less than 64k chunks, because HAL can't send 64K at once
  buff_size /= 2;
  uint32_t buff_size_max = 65536 - 4;
  while (buff_size > 0)
  {
    uint16_t chunk_size = buff_size > buff_size_max ? buff_size_max : buff_size;
    HAL_SPI_Transmit(&ILI9341_SPI_PORT, buff, chunk_size, HAL_MAX_DELAY);
    buff += chunk_size * 2;
    buff_size -= chunk_size;
  }
#if defined SW_CS_PIN
  HAL_GPIO_WritePin(ILI9341_CS_PORT, ILI9341_CS_PIN, GPIO_PIN_SET);
#endif
  // Set SPI back to 8-bit
  ILI9341_SPI_PORT.Init.DataSize = SPI_DATASIZE_8BIT;
  HAL_SPI_Init(&ILI9341_SPI_PORT);
}

Note, ILI9341_SPI_PORT is a just definition in a header file for your display, i.e. ILI9341_conf.h, used to confgigure the display IO:

#define ILI9341_SPI_PORT     hspi4

In the code above, we only modify the DataSize of the SPI bus and leave the rest the same as when initally MX_SPI4_Init was called for example.

I have tried this for you, using an ILI9341 display, connected to a Nucleo-H7A3ZI-Q development board, and it works fine this way. You now do not have to loose time swapping bytes forth and back.

I added GPIO CS control too, in case you do it by software.

And never forget to set your window for the display.

You now can use DMA2D and nicely blend images.

Hope this helps.

0693W00000Hq9ruQAB.pngPhoto taken using my phone...