News:

Welcome to the Bridgetek Community!

Please read our Welcome Note

Technical Support enquires
please contact the team
@ Bridgetek Support

Please refer to our website for detailed information on all our products - Bridgetek - Bridging Technology

Main Menu
Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - kumaichi

#1
Hello,

I've just ran into the strangest issue and I'm not exactly sure where to even start.  I have two projects, they both use QSPI to write to the BT817, not sure that matters but want to give as much information as possible.  One project uses FreeRTOS and the other one doesn't.  When the FreeRTOS version runs through the initialization,  I try to set the REG_PWM_DUTY to 25 and it crashes everything, the QSPI command returns successfully but then it crashes the debugger.  I've never ran into anything like this.  Has anyone experienced this before?  It's only on the setting of, REG_PWM_DUTY which calls TFT_qspi_write8(...), other commands call the same method with no issues.  Below is my initialization code as well as my write 8 method.

The non-freeRTOS project runs fine all day long using the exact same code.  Only difference is it uses a timer to update the display running off the main thread.

Any insight would be greatly appreciated.

Kindest regards.

Initialization:
void TFT_qspi_init()
{
tft_active = 0;

HAL_GPIO_WritePin(MCU_DISP_RST_GPIO_Port, MCU_DISP_RST_Pin, GPIO_PIN_RESET);
HAL_Delay(40); /* minimum time for power-down is 5ms */
HAL_GPIO_WritePin(MCU_DISP_RST_GPIO_Port, MCU_DISP_RST_Pin, GPIO_PIN_SET);
HAL_Delay(40); /* minimum time to allow from rising PD_N to first access is 20ms */

//Explicitly put SPI in single mode
TFT_write8(REG_SPI_WIDTH, 0x00);
//External Crystal
TFT_sendCmd(CMD_CLKEXT, 0x00);
HAL_Delay(100);
/* set clock to 72 MHz */
TFT_sendCmd(CMD_CLKSEL, 0x46);
//Reset the device
TFT_sendCmd(EVE_RST_PULSE, 0x00);
/* give EVE time to power up */
HAL_Delay(40);
/* start EVE */
TFT_sendCmd(CMD_ACTIVE, 0x00);
HAL_Delay(300);
/* tell EVE that we changed the frequency to 72MHz */
TFT_write32(REG_FREQUENCY, 72000000);
/* read the frequency to verify */
if (TFT_read32(REG_FREQUENCY) != 72000000)
Error_Handler();

TFT_write8(REG_TRIM, 25);

/* read the ID */
while (TFT_readId(REG_ID) != 0x7c)
{
};

/* read REG_CPURESET to confirm 0 is returned */
uint8_t engine_status;

/* Read REG_CPURESET to check if engines are ready.
Bit 0 for coprocessor engine,
Bit 1 for touch engine,
Bit 2 for audio engine.
*/
engine_status = TFT_read8(REG_CPURESET);
while (engine_status != 0x00)
{
engine_status = TFT_read8(REG_CPURESET);
HAL_Delay(100);
}

TFT_write16(REG_PWM_HZ, 4000);
TFT_write8(REG_PWM_DUTY, 0);

/* switch to QSPI */
TFT_write8(REG_SPI_WIDTH, 0x02);
while (TFT_qspi_read8(REG_SPI_WIDTH) != 0x02)
{
TFT_write8(REG_SPI_WIDTH, 0x02);
};

/* Check if everything is okay */
if (TFT_qspi_read16(REG_CMD_READ) == 0xFFF)
{
uint8_t Offset = 0;
uint8_t ErrChar;
uint8_t result[128 + 1]; // Buffer to hold the full string (including null terminator)
int result_index = 0;
do
{
// Get the error character and display it
ErrChar = TFT_qspi_read8(EVE_RAM_ERR_REPORT + Offset);
// Only append valid characters (non-null)
if (ErrChar != 0 && result_index < 128)
{
result[result_index++] = ErrChar;
}

Offset++;
}
while ((ErrChar != 0) && (Offset < 128)); // when the last stuffed character was null, we are done

// Null-terminate the string
result[result_index] = '\0';

// Now the full string is in 'result', which you can use or print
printf("Captured string: %s\n", result);
sprintf((char*) message, "Captured string: %s\r\n", result);
CDC_Transmit_FS((uint8_t*) message, strlen((char*) message));
}

TFT_qspi_write16(REG_HSIZE, DispWidth); /*   800 */
TFT_qspi_write16(REG_VSIZE, DispHeight); /*   480 */
TFT_qspi_write16(REG_HCYCLE, DispHCycle); /*   816 */
TFT_qspi_write16(REG_HOFFSET, DispHOffset); /*     8 */
TFT_qspi_write16(REG_HSYNC0, DispHSync0); /*     0 */
TFT_qspi_write16(REG_HSYNC1, DispHSync1); /*     4 */
TFT_qspi_write16(REG_VCYCLE, DispVCycle); /*   496 */
TFT_qspi_write16(REG_VOFFSET, DispVOffset); /*     8 */
TFT_qspi_write16(REG_VSYNC0, DispVSync0); /*     0 */
TFT_qspi_write16(REG_VSYNC1, DispVSync1); /*     4 */
TFT_qspi_write8(REG_SWIZZLE, DispSwizzle); /*     0 */
TFT_qspi_write8(REG_PCLK_POL, DispPCLKPol); /*     1 */
TFT_qspi_write16(REG_CSPREAD, DispCSpread); /*     0 */
TFT_qspi_write16(REG_DITHER, DispDither); /*     0 */
TFT_qspi_write16(REG_PCLK_FREQ, DispPLCLKFREQ); /* 0xD14 */
TFT_qspi_write8(REG_PCLK_2X, DispPCLK2x); /*     0 */

/* disable Audio for now */
TFT_qspi_write8(REG_VOL_PB, 0U); /* turn recorded audio volume down, reset-default is 0xff */
TFT_qspi_write8(REG_VOL_SOUND, 0U); /* turn synthesizer volume down, reset-default is 0xff */
TFT_qspi_write16(REG_SOUND, EVE_MUTE); /* set synthesizer to mute */

uint32_t initCommands[] =
{
CMD_DLSTART,
DL_CLEAR_COLOR_RGB | WHITE,
DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG, /* clear the screen - this and the previous prevent artifacts between lists, Attributes are the color, stencil and tag buffers */
DL_DISPLAY,
CMD_SWAP // display, in this case nothing
};

TFT_qspi_cmd_burst(initCommands,
sizeof(initCommands) / sizeof(initCommands[0]));

//while (TFT_busy() != E_OK){};
TFT_qspi_WaitCmdfifo_empty();

if (TFT_qspi_read16(REG_CMD_READ) == 0xFFF)
{
uint8_t Offset = 0;
uint8_t ErrChar;
uint8_t result[128 + 1]; // Buffer to hold the full string (including null terminator)
int result_index = 0;
do
{
// Get the error character and display it
ErrChar = TFT_qspi_read8(EVE_RAM_ERR_REPORT + Offset);
// Only append valid characters (non-null)
if (ErrChar != 0 && result_index < 128)
{
result[result_index++] = ErrChar;
}

Offset++;
}
while ((ErrChar != 0) && (Offset < 128)); // when the last stuffed character was null, we are done

// Null-terminate the string
result[result_index] = '\0';

// Now the full string is in 'result', which you can use or print
printf("Captured string: %s\n", result);
sprintf((char*) message, "Captured string: %s\r\n", result);
CDC_Transmit_FS((uint8_t*) message, strlen((char*) message));
}

TFT_qspi_cmd_setrotate(0);

TFT_qspi_write16(REG_GPIOX_DIR, 0xFFFF);
TFT_qspi_write16(REG_GPIOX, 0xFFFF);

/* after this display is visible on the LCD */
TFT_qspi_write8(REG_PCLK, DispPCLK);

//while (TFT_busy() != E_OK){};
TFT_qspi_WaitCmdfifo_empty();

/* If the status of the flash is 0 (INIT) Attach it */
while (EVE_FLASH_STATUS_DETACHED == TFT_qspi_read8(REG_FLASH_STATUS))
{
TFT_qspi_dl_cmd(CMD_FLASHATTACH);
}

/* Initialize the onboard flash and put in FAST mode
* Need to check the return value and not proceed if
* there is an error so we can read in the Fonts
*/
if (TFT_init_flash() == E_OK)
{
/* Read the image from the flash */
uint32_t flashCommands[] =
{
CMD_FLASHREAD, (uint32_t) MEM_FONT34, (uint32_t) 198592, (uint32_t) 280 + 40,
CMD_FLASHREAD, (uint32_t) CAR_IMAGE_HORIZONTAL, (uint32_t) 198912, (uint32_t) 92000 + 32
};

TFT_qspi_cmd_burst(flashCommands, sizeof(flashCommands) / sizeof(flashCommands[0]));

while (TFT_busy() != E_OK)
{
};

TFT_qspi_WaitCmdfifo_empty();
}

TFT_qspi_dl_cmd(CMD_DLSTART);
TFT_qspi_dl_cmd(DL_CLEAR_COLOR_RGB | WHITE);
TFT_qspi_dl_cmd(DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG);
TFT_qspi_dl_cmd(DL_BEGIN);

TFT_qspi_dl_cmd(COLOR_RGB(120, 6, 6));

TFT_qspi_cmd_setfont2(13, MEM_FONT34, 0); /* assign bitmap handle to a custom font */
TFT_qspi_cmd_text((DispWidth / 2), (DispHeight / 5) - 15, 13, EVE_OPT_CENTERX, "Please wait...");

TFT_qspi_dl_cmd(COLOR_RGB(20, 20, 130));

TFT_qspi_cmd_spinner(DispWidth / 2, DispHeight / 2, 0, 0);

//TFT_qspi_write8(REG_PWM_DUTY, 25);

HAL_Delay(2000);

TFT_qspi_cmd_stop();

TFT_qspi_WaitCmdfifo_empty();

/* set the precision of VERTEX2F coordinates */
#if defined (IPS_70) || (IPS_101)
      /* VERTEX2F range: -2048 to 2047 */
      //TFT_qspi_dl_cmd(VERTEX_FORMAT(3));
      pixel_precision = 8;
#else
/* use default VERTEX_FORMAT(3) with VERTEX2F range: -1024 to 1023 */
pixel_precision = 16;
#endif

tft_active = 1;
}

Write 8 Method:
void TFT_qspi_write8(uint32_t const address, uint32_t const data)
{
QSPI_CommandTypeDef sCommand = {0};

// Set up the command structure
sCommand.InstructionMode   = QSPI_INSTRUCTION_4_LINES;    // Instruction sent over 1 line
sCommand.Instruction       = (uint8_t) (address >> 16U) | 0X80; //Get the first byte, should look like 0x30
sCommand.AddressMode       = QSPI_ADDRESS_4_LINES;        // Address sent over 1 line
sCommand.AddressSize       = QSPI_ADDRESS_16_BITS;        // 16-bit address
sCommand.Address           = address & 0xFFFF;            // Mask off the first byte and keep the last two bytes
sCommand.DataMode          = QSPI_DATA_4_LINES;            // Data mode for receiving ID
sCommand.NbData            = 2;                          // Sending 2 bytes
sCommand.DummyCycles       = 0;                          // No dummy cycles
sCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      // Disable DDR mode
sCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;    // Send instruction every command

// Send the command (instruction and address)
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
Error_Handler();

// Now write the data
uint8_t localData[2] = {(uint8_t) data & 0xFF,
(uint8_t) (data >> 8) & 0xFF};
if (HAL_QSPI_Transmit(&hqspi, localData, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
Error_Handler();

return;
}

FreeRTOS Task:
void StartDisplayTask(void *argument)
{
  /* USER CODE BEGIN StartDisplayTask */
  /* Infinite loop */
(void)argument;
const TickType_t period = pdMS_TO_TICKS(16); // ~60 Hz
TickType_t last = xTaskGetTickCount();
bool initialized = false;

for (;;)
{
if(!initialized)
{
initialized = true;

TFT_qspi_init();
}

//TFT_touch(); - Called from another task
TFT_display();

vTaskDelayUntil(&last, period);
}
  /* USER CODE END StartDisplayTask */
}
#2
Discussion - EVE / Re: Not able to display font degree
August 27, 2025, 04:48:05 PM
Hello, thank you for your response.

Well don't I feel like an idiot :(.  I tried using the Windows Anton font to make sure it wasn't something with the font I changed and that's when I saw it.  I'm setting the font to, 13 but I then use a system font, 31.

TFT_qspi_dl_cmd(COLOR_RGB(0, 25, 0));
TFT_qspi_cmd_setfont2(13, MEM_FONT_ANTON_34, 0);

char buf[32];
snprintf(buf, sizeof buf, "%.1f Psi", pressure);
TFT_qspi_cmd_text(75, 60, 13, EVE_OPT_CENTERY, buf);

When I set the correct font to use, 13, the whole display crashes.  I'll have to verify that my set font code is correct cause it doesn't seem to be working, ugh.

Apologies for wasting your time.

Kindest regards.
#3
Discussion - EVE / Not able to display font degree
August 26, 2025, 02:48:40 PM
Hello,

I modified a font, Reglo-Bold, adding a "degree" symbol but I'm unable to actually display it.  For some reason, depending on how I try to display it, it'll show up as a '0'.  I'm confident the symbol is there and in the correct position.  I viewed the images created by EVE Asset Builder v2.10.2 and it's there.

FontFolio Screenshot
You cannot view this attachment.

EVE Asset Builder Preview Last Screenshot
You cannot view this attachment.

EVE Asset Builder Font Index HTML Screenshot
You cannot view this attachment.

I've tried a bunch of different ways to display it:

snprintf(buf, sizeof buf, "%d " "\u00B0" "   F", temperature);
TFT_qspi_cmd_text(75, 120, 31, EVE_OPT_CENTERY, buf);

I'm not really sure what I'm doing wrong or maybe something like this isn't possible?

Any insight would be greatly appreciated.

Kindest regards.

#4
Thank you, Rudolph!  I did a quick test setting the REG_PCLK_2X to 1 and didn't resolve the issue.  I was thinking that using QSPI would have been able to read from the flash fast enough but apparently, I was mistaken :(.  I'm discovering there isn't anything easy about this, LOL.  I will go through your suggestions and see if I can figure it out.  I'm sure I'll have lots of questions.

Thanks again for your help and patience.

Kindest regards.
#5
Hi Rudolph,

I switched all the fonts to use ROM font 31 and everything displayed correctly.  Is there any way to change settings so that I can use custom fonts or are ROM fonts the only option?

Thank you for your response, extremely helpful.

Kindest regards.
#6
Hello,

Thank you for your response.

That's strange, I pulled the settings from the Riverdi's module.h file.  Could you please share the settings you have so I can try it?

Kindest regards.
#7
Hello,

Thank you for your response.

The two Riverdi displays I'm using are:
    RVT50HQBNWC00-B
    RVT70HSBNWC00-B

One thing to note is that when I have the IPS-70 settings, the 5" display will display the data, it's just partially off the screen (image attached).

The display settings are:
#if defined (IPS_50)
  #define DispWidth      800L
  #define DispHeight     480L
  #define DispHCycle     816L
  #define DispHOffset    8L
  #define DispHSync0     0L
  #define DispHSync1     4L
  #define DispVCycle     496L
  #define DispVOffset    8L
  #define DispVSync0     0L
  #define DispVSync1     4L
  #define DispPCLK       1
  #define DispSwizzle    0
  #define DispPCLKPol    1
  #define DispCSpread    0
  #define DispDither     0
  #define DispPLCLKFREQ  0xD14
  #define DispPCLK2x    0
#elif defined (IPS_70)
  #define DispWidth      1024L
  #define DispHeight     600L
  #define DispHCycle     1344L
  #define DispHOffset    160L
  #define DispHSync0     0L
  #define DispHSync1     70L
  #define DispVCycle     635L
  #define DispVOffset    23L
  #define DispVSync0     0L
  #define DispVSync1     10L
  #define DispPCLK       1
  #define DispSwizzle    0
  #define DispPCLKPol    1
  #define DispCSpread    0
  #define DispDither     0
  #define DispPLCLKFREQ  0xD12
  #define DispPCLK2x    0
#endif

The fonts are custom and are stored in the Flash, I have attached the .bin file I'm using on both displays, don't know if this will help or not, just including it.  This is the memory map for the attached file:

Generating flash image...
Generate flash success!
Flash image file       :  Reglo-Bold_200_34_Icons_ASTC Font.bin
Flash map file         :  Reglo-Bold_200_34_Icons_ASTC Font.map
Flash description file :  Reglo-Bold_200_34_Icons_ASTC Font.edf

Flash map:
bt817.blob                                      : 0      : 4096 
EDF Block                                       : 4096   : 448   
Reglo-Bold_200_ASTC.glyph                       : 4544   : 209920
Reglo-Bold_200_ASTC.xfont                       : 214464 : 176   
Reglo-Bold_200_ASTC.xfont.pad                   : 214640 : 16   
Reglo-Bold_34_ASTC.glyph                        : 214656 : 116480
Reglo-Bold_34_ASTC.xfont                        : 331136 : 176   
Reglo-Bold_34_ASTC.xfont.pad                    : 331312 : 16   
Tambourine Outline_34_ASTC.glyph                : 331328 : 200640
Tambourine Outline_34_ASTC.xfont                : 531968 : 176   
Tambourine Outline_34_ASTC.xfont.pad            : 532144 : 16   
Tambourine_34_ASTC.glyph                        : 532160 : 200640
Tambourine_34_ASTC.xfont                        : 732800 : 176   
Tambourine_34_ASTC.xfont.pad                    : 732976 : 16   
Airbag_300x400_COMPRESSED_RGBA_ASTC_4x4_KHR.raw : 732992 : 120000
Tire_300x400_COMPRESSED_RGBA_ASTC_4x4_KHR.raw   : 852992 : 120000

If there is anything else I can help with, please let me know.

Kindest regards.
#8
Hello,

I have my QSPI working perfect for my Riverdi 5" display, using the IPS-50 settings.  I switched over to my Riverdi 7" display, using the IPS-70 settings and I only get the DL-size text multiple times down the display.  I've attached photos of the 5" display and the 7" display.  I have flashed the same .bin file to both displays.

Is there anything special to consider when using the same code for both displays besides switching the IPS-X0 settings?

The DL sizes are different because after a few seconds my display connects to the Bluetooth module and updates the data on the screen, so the size isn't the issue.

Kindest regards.
#9
This is my first time using QSPI which was partly the cause of my confusion.  I couldn't figure out if it was something with my custom hardware or my firmware that was causing me so much trouble.  I'm using a STM32WB55REV for my two custom boards, one is the sender, and one is the receiver, the receiver is the one connected to a Riverdi display with the BT817Q.

Quote from: Rudolph on January 09, 2025, 05:37:08 PM
I do not see in your code to which address the command is written to.

numberCommand.Instruction = 0xB0; // Get the first byte, should 0xB0 (0x10) to write

And the rest?

If I understand correctly, the QSPI is broken into Command and Address (excuse the variable names, I've been copy/pasting and have to come back to refactor everything, just trying to get something working initially):


numberCommand.Instruction = 0xB0; // Get the first byte, should 0xB0 (0x10) to write
numberCommand.Address     = 0x2578;


Those two lines are equivalent to these lines in your library:


spi_transmit((uint8_t) 0xB0U); /* high-byte of REG_CMDB_WRITE + MEM_WRITE */
spi_transmit((uint8_t) 0x25U); /* middle-byte of REG_CMDB_WRITE */
spi_transmit((uint8_t) 0x78U); /* low-byte of REG_CMDB_WRITE */


Then it sets up the EVE command and the value:


uint8_t cmdArray[8] = {
(uint8_t)(CMD_SETROTATE & 0x000000ff),
(uint8_t)(CMD_SETROTATE >> 8),
(uint8_t)(CMD_SETROTATE >> 16),
(uint8_t)(CMD_SETROTATE >> 24),
/* Rotation */
(uint8_t)(rotation & 0x000000ff),
(uint8_t)(rotation >> 8),
(uint8_t)(rotation >> 16),
(uint8_t)(rotation >> 24)
};



Quote from: Rudolph on January 09, 2025, 05:37:08 PM
CS likely is hardware controlled?

Correct, the CS is completely out of my hands which is making it difficult to create the same kind of flow of your library where you setup the _burst commands because I haven't figured out how to keep the CS line pulled low while transmitting the rest of the EVE commands. 

Quote from: Rudolph on January 09, 2025, 05:37:08 PM
What does this look like on the logic analyzer? The whole sequence for this function and perhaps some bits and pieces before and after.

I've captured waveforms with my Digilent AD 3 and Waveforms software, but they don't really have a QSPI decoder, so I had no idea what I was looking at.  As per the suggestion from BRT, I connected an oscilloscope to the QSPI lines and they didn't look well-formed which is what prompted me to change the skew rate, again suggested by BRT.  This has seemed to resolve the issue for me.

Kindest regards.
#10
Hello,

Thank you for your response and patience.

I was trying to rotate the entire screen, my function was incorrectly named, thank you for pointing that out.  It has since been fixed.

This has been very frustrating to pinpoint the issue, and your suggestions have been very helpful.  Reading your responses, I started changing the slew rate.  The original setting in STM32CubeMX was set to "Very High".  I switched them all to "High" and haven't encountered any blank screens since.  I'm really hoping this was the issue.  I'll report back if I'm still encountering issues.

Again, thank you for your assistance and patience helping me work through interacting with the BT817Q via QSPI, it is greatly appreciated.

Kindest regards.
#11
Hello,

Thank you for your response.  After more research, I think the issue is in the set rotate command, nothing to do with reading from the flash.  I went through and put this line of code after pretty much everything, so I could see how much space was available:


uint16_t space;
space = TFT_qspi_read16(REG_CMDB_SPACE);


The rotate command always returns 4084 when the display doesn't work because it gets into the infinite loop, checking if REG_CMD_READ == REG_CMD_WRITE or if I use the TFT_Busy, it always returns EVE_FIFO_HALF_EMPTY.

Is there a reason why rotating the screen would have the REG_CMD_SPACE equal to 4084?  Every other call to TFT_qspi_read16(REG_CMDB_SPACE) always returns 4092. 


space = TFT_qspi_read16(REG_CMDB_SPACE); //Always 4092
TFT_qspi_cmd_rotate(1);
space = TFT_qspi_read16(REG_CMDB_SPACE); //When it fails, always 4084



void TFT_qspi_cmd_rotate(uint32_t rotation)
{
QSPI_CommandTypeDef numberCommand = {0};

// Set up the command structure
numberCommand.InstructionMode   = QSPI_INSTRUCTION_4_LINES;    // Instruction sent over 1 line
numberCommand.Instruction       = 0xB0; //Get the first byte, should 0xB0 (0x10) to write
numberCommand.AddressMode       = QSPI_ADDRESS_4_LINES;        // Address sent over 1 line
numberCommand.AddressSize       = QSPI_ADDRESS_16_BITS;        // Try using 16-bit address
numberCommand.Address           = 0x2578;            // Mask off the first byte and keep the last two bytes
numberCommand.DataMode          = QSPI_DATA_4_LINES;            // Data mode for receiving ID
numberCommand.NbData    = 8;                          // Expecting to receive 4 bytes
numberCommand.DummyCycles       = 0;                          // No dummy cycles
numberCommand.DdrMode           = QSPI_DDR_MODE_DISABLE;      // Disable DDR mode
numberCommand.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;    // Send instruction every command

uint8_t cmdArray[8] = {
(uint8_t)(CMD_SETROTATE & 0x000000ff),
(uint8_t)(CMD_SETROTATE >> 8),
(uint8_t)(CMD_SETROTATE >> 16),
(uint8_t)(CMD_SETROTATE >> 24),
/* Rotation */
(uint8_t)(rotation & 0x000000ff),
(uint8_t)(rotation >> 8),
(uint8_t)(rotation >> 16),
(uint8_t)(rotation >> 24)
};

if (HAL_QSPI_Command(&hqspi, &numberCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
Error_Handler();

if (HAL_QSPI_Transmit(&hqspi, cmdArray, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
Error_Handler();

return;
}


Any suggestions would be greatly appreciated.

Kindest regards.
#12
Hello,

Thank you for your response and suggestions.

It's definitely an issue with the flash, might be a timing issue because when I have the logic analyzer connected, it seems to work more consistently.  Not exactly sure why that is.  If I debug stepping through the code, it also works more consistently.  However, when it fails while debugging, it's always in the TFT_init_flash(), which makes sense because it's a hard fault at that point.

I update the flash code to be like this:


/* If the status of the flash is 0 (INIT) Attach it */
while (EVE_FLASH_STATUS_DETACHED == TFT_qspi_read8(REG_FLASH_STATUS))
{
    uint32_t flashAttachCommand[] = {CMD_FLASHATTACH};
    TFT_qspi_display(flashAttachCommand, 1);
}

if(TFT_init_flash() != E_OK)
Error_Handler();


My TFT_init_flash() method is borrowed from the EVE library or Rudolph's library, with the addition of the QSPI methods I created:


uint8_t TFT_init_flash()
{
    uint8_t timeout = 0U;
    uint8_t status;
    uint8_t ret_val = E_NOT_OK;

    status = TFT_qspi_read8(REG_FLASH_STATUS); /* should be 0x02 - FLASH_STATUS_BASIC, power-up is done and the attached flash is detected */

     /* we are somehow still in init, give it a litte more time, this should never happen */
    while (EVE_FLASH_STATUS_INIT == status)
    {
        status = TFT_qspi_read8(REG_FLASH_STATUS);
        DELAY_MS(1U);
        timeout++;
        if (timeout > 100U) /* 100ms and still in init, lets call quits now and exit with an error */
        {
            ret_val = EVE_FAIL_FLASH_STATUS_INIT;
            break;
        }
    }

/* no flash was found during init, no flash present or the detection failed, give it another try */
if (EVE_FLASH_STATUS_DETACHED == status) {
TFT_qspi_write32(REG_CMDB_WRITE, CMD_FLASHATTACH);
//EVE_execute_cmd();
status = TFT_qspi_read8(REG_FLASH_STATUS);
if (status != 2U) /* still not in FLASH_STATUS_BASIC, time to give up */
{
ret_val = EVE_FAIL_FLASH_STATUS_DETACHED;
}
}

    /* flash detected and ready for action, move it up to FLASH_STATUS_FULL */
    if (EVE_FLASH_STATUS_BASIC == status)
    {
        uint32_t result;

        //result = EVE_cmd_flashfast();
        uint16_t cmdoffset;

        TFT_qspi_cmd(REG_CMDB_WRITE, CMD_FLASHFAST, 0);
        status = TFT_qspi_read8(REG_FLASH_STATUS);

        //while (TFT_busy() != E_OK){};
        //TFT_qspi_WaitCmdfifo_empty();

        cmdoffset = TFT_qspi_read16(REG_CMD_READ);
    cmdoffset = TFT_qspi_read16(REG_CMD_WRITE); /* read the coprocessor write pointer */
    cmdoffset -= 4U;
    cmdoffset &= 0x0fffU;
    result = TFT_qspi_read32(EVE_RAM_CMD + cmdoffset);

        switch (result)
        {
            case 0x0000UL:
                ret_val = E_OK;
            break;

            case 0xE001UL:
                ret_val = EVE_FAIL_FLASHFAST_NOT_SUPPORTED;
            break;

            case 0xE002UL:
                ret_val = EVE_FAIL_FLASHFAST_NO_HEADER_DETECTED;
            break;

            case 0xE003UL:
                ret_val = EVE_FAIL_FLASHFAST_SECTOR0_FAILED;
            break;

            case 0xE004UL:
                ret_val = EVE_FAIL_FLASHFAST_BLOB_MISMATCH;
            break;

            case 0xE005UL:
                ret_val = EVE_FAIL_FLASHFAST_SPEED_TEST;
            break;

            default: /* we have an unknown error, so just return failure */
                ret_val = E_NOT_OK;
            break;
        }
    }

    if (EVE_FLASH_STATUS_FULL == status) /* we are already there, why has this function been called? */
    {
        ret_val = E_OK;
    }

    return (ret_val);
}


I'm certain the flash is the reason why it's failing because I was just stopping all processing.  However, with the above changes, it's more consistently working, maybe 1 out of 5 I still get just the backlight when turning it on/off.  Is the above code the best way to manage initializing the flash?  Any optimizations I can make?

I also have a Riverdi IPS_70 that I tried, using the IPS_70 settings and it turns on/off every time, but custom fonts don't work even though I flashed the same .bin file I'm using on the Riverdi IPS_50.  None of this is making any sense at all :(.

Thanks again for your assistance.

Kindest regards.
#13
Hello,

Thanks for your response.

I haven't tried using SPI thus far, I'll have to dig out a board and give it a try.  While trying to debug this situation the only thing I've found so far is that sometimes the flash initialization fails:


if(TFT_init_flash() != E_OK)
Error_Handler();


To check for possible co-processor errors, I added this code placing a breakpoint at the bottom:


if(TFT_qspi_read16(REG_CMD_READ) == 0xFFF){
uint8_t Offset = 0;
uint8_t ErrChar;
uint8_t result[128 + 1]; // Buffer to hold the full string (including null terminator)
int result_index = 0;
do
{
// Get the error character and display it
ErrChar = TFT_qspi_read8(EVE_RAM_ERR_REPORT + Offset);
// Only append valid characters (non-null)
if (ErrChar != 0 && result_index < 128) {
result[result_index++] = ErrChar;
}

Offset++;
}while ( (ErrChar != 0) && (Offset < 128) ); // when the last stuffed character was null, we are done

// Null-terminate the string
result[result_index] = '\0';

// Now the full string is in 'result', which you can use or print
printf("Captured string: %s\n", result); //Line with breakpoint
}


It never hits the breakpoint, even when the screen just has the backlight, no graphics at all.

Thanks for the link to the latest programmer's guide, I was using an older version and didn't initially see the EVE_RAM_ERR_REPORT, this has since come in quite handy while trying to get custom fonts working via QSPI.

If I can do anything to help facilitate a solution, please let me know.

Kindest regards.
#14
I'm stuck in an extremely painful situation where sometimes everything displays correctly when my device powers up and other times, actually most of the time, only the backlight seems to work.  I'm using Rudolph's library as well as the EVE library as a reference and can't seem to figure out what I'm missing.  I'm using qspi which I don't think is an issue because sometimes it works fine.

I have attached my init method, can anyone possibly see what could cause it to display intermittently?

Kindest regards.


void TFT_qspi_init()
{
    HAL_GPIO_WritePin(MCU_DISP_RST_GPIO_Port, MCU_DISP_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(21); /* minimum time for power-down is 5ms */
    HAL_GPIO_WritePin(MCU_DISP_RST_GPIO_Port, MCU_DISP_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(21); /* minimum time to allow from rising PD_N to first access is 20ms */

    //Reset the device
    TFT_sendCmd(EVE_RST_PULSE, 0x00);
    HAL_Delay(21);

    //External Crystal
    TFT_sendCmd(CMD_CLKEXT, 0x00);
    HAL_Delay(100);
    /* set clock to 72 MHz */
    TFT_sendCmd(CMD_CLKSEL, 0x46);
    /* start EVE */
    TFT_sendCmd(CMD_ACTIVE, 0x00);
    /* give EVE time to power up */
    HAL_Delay(40);

    /* read the ID */
    uint8_t regId = TFT_readId(REG_ID);
    while(regId != 0x7c)
    regId = TFT_readId(REG_ID);

    /* ensure CPUreset register reads 0 signaling it's ready */
    uint8_t cpuState = TFT_read8(REG_CPURESET);
    while ( cpuState != 0x00)
cpuState = TFT_read8(REG_CPURESET);

    /* switch to QSPI */
    TFT_write8(REG_SPI_WIDTH, 0x02);
    if(TFT_qspi_read8(REG_SPI_WIDTH) != 0x02)
        Error_Handler();

    /* tell EVE that we changed the frequency to 72MHz */
    TFT_qspi_write32(REG_FREQUENCY, 72000000);
    /* read the frequency to verify */
    if(TFT_qspi_read32(REG_FREQUENCY) != 72000000)
    Error_Handler();

    TFT_qspi_write8(REG_TRIM, 25);
    TFT_qspi_write16(REG_HSIZE, DispWidth); /*   800 */
    TFT_qspi_write16(REG_VSIZE, DispHeight); /*   480 */
    TFT_qspi_write16(REG_HCYCLE, DispHCycle); /*   816 */
    TFT_qspi_write16(REG_HOFFSET, DispHOffset); /*     8 */
    TFT_qspi_write16(REG_HSYNC0, DispHSync0); /*     0 */
    TFT_qspi_write16(REG_HSYNC1, DispHSync1); /*     4 */
    TFT_qspi_write16(REG_VCYCLE, DispVCycle); /*   496 */
    TFT_qspi_write16(REG_VOFFSET, DispVOffset); /*     8 */
    TFT_qspi_write16(REG_VSYNC0, DispVSync0); /*     0 */
    TFT_qspi_write16(REG_VSYNC1, DispVSync1); /*     4 */
    TFT_qspi_write8(REG_PCLK, DispPCLK); /*     1 */
    TFT_qspi_write8(REG_SWIZZLE, DispSwizzle); /*     0 */
    TFT_qspi_write8(REG_PCLK_POL, DispPCLKPol); /*     1 */
    TFT_qspi_write16(REG_CSPREAD, DispCSpread); /*     0 */
    TFT_qspi_write16(REG_DITHER, DispDither); /*     0 */
    TFT_qspi_write16(REG_PCLK_FREQ, DispPLCLKFREQ); /* 0xD14 */
    TFT_qspi_write8(REG_PCLK_2X, DispPCLK2x); /*     0 */

    TFT_qspi_write16(REG_PWM_HZ, 4000);
    TFT_qspi_write8(REG_PWM_DUTY, 128);

    TFT_qspi_write16(REG_GPIOX_DIR, 0xFFFF);
    TFT_qspi_write16(REG_GPIOX, 0xFFFF);

    /* turn off back light */
    TFT_qspi_write8(REG_PWM_DUTY, 0);

    while(TFT_busy()){};

    TFT_qspi_cmd(REG_CMDB_WRITE, CMD_SETROTATE, 1);

    /* If the status of the flash is 0 (INIT) Attach it */
    if (TFT_qspi_read8(REG_FLASH_STATUS) == 0x00) {
        uint32_t flashAttachCommand[] = {CMD_FLASHATTACH};

TFT_qspi_display(flashAttachCommand, 1);
    }

    /* Initialize the onboard flash and put in FAST mode
* Need to check the return value and not proceed if
* there is an error.
    */
    if(TFT_init_flash() != E_OK)
Error_Handler();

    /* turn on backlight pwm to 25% for any other module */
    TFT_qspi_write8(REG_PWM_DUTY, 0x25);
    uint32_t commands[] = {
CMD_DLSTART, /* start the display list */
DL_CLEAR_COLOR_RGB | 0x00000000, /* set the default clear color to white */
DL_CLEAR | CLR_COL | CLR_STN | CLR_TAG, /* clear the screen - this and the previous prevent artifacts between lists, Attributes are the color, stencil and tag buffers */
DL_BEGIN | EVE_BITMAPS,
COLOR_RGB(255, 255, 255),
VERTEX2II(DispWidth / 2 , (DispHeight / 2) - 31, 31, 'T'), // ASCII T in font 31
VERTEX2II((DispWidth / 2 ) + 26, (DispHeight / 2) - 31, 31, 'E'), // ASCII E in font 31
VERTEX2II((DispWidth / 2 ) + 50, (DispHeight / 2) - 31, 31, 'X'), // ASCII X in font 31
VERTEX2II((DispWidth / 2 ) + 76, (DispHeight / 2) - 31, 31, 'T'),
DL_END,
COLOR_RGB(160, 22, 22), // change color to red
POINT_SIZE(520), // set point size to 20 pixels in radius
DL_BEGIN | EVE_POINTS, // start drawing points
VERTEX2II((DispWidth / 2 ) - 40, (DispHeight / 2) - 10, 0, 0), // red point
DL_END,
DL_DISPLAY,
CMD_SWAP// display the image
};

TFT_qspi_display(commands, sizeof(commands) / sizeof(commands[0]));

/* turn on backlight pwm to 25% for any other module */
TFT_qspi_write8(REG_PWM_DUTY, 0x25);

HAL_Delay(2000);
}
#15
Discussion - EVE / Re: Using QUAD SPI (qspi)
September 16, 2024, 09:09:18 PM
WOW, I can't believe it, I actually got it to work, very cool!  I set the prescaler to be 80, which brings the clock up to roughly 200khz.  My code looks like this now:


HAL_GPIO_WritePin(QSPI1_RST_GPIO_Port, QSPI1_RST_Pin, GPIO_PIN_RESET);
HAL_Delay(21); /* minimum time for power-down is 5ms */
HAL_GPIO_WritePin(QSPI1_RST_GPIO_Port, QSPI1_RST_Pin, GPIO_PIN_SET);
HAL_Delay(21); /* minimum time to allow from rising PD_N to first access is 20ms */

//External Crystal
TFT_sendCmd(CMD_CLKEXT, 0x00);
HAL_Delay(100);
/* set clock to 72 MHz */
TFT_sendCmd(CMD_CLKSEL, 0x46);
/* start EVE */
TFT_sendCmd(CMD_ACTIVE, 0x00);
/* give EVE time to power up */
HAL_Delay(40);

/* read the ID */
uint8_t regId = TFT_readId(REG_ID);
while(regId != 0x7c)
    regId = TFT_readId(REG_ID);

/* ensure CPUreset register reads 0 signaling it's ready */
uint8_t cpuState = TFT_read8(REG_CPURESET);
while ( cpuState != 0x00)
    cpuState = TFT_read8(REG_CPURESET);

/* switch to QSPI */
TFT_write8(REG_SPI_WIDTH, 0x02);
if(TFT_qspi_read8(REG_SPI_WIDTH) != 0x02)
    Error_Handler();

/* tell EVE that we changed the frequency to 72MHz */
TFT_qspi_write32(REG_FREQUENCY, 72000000);
/* read the frequency to verify */
if(TFT_qspi_read32(REG_FREQUENCY) != 72000000)
    Error_Handler();

/* turn off back light */
TFT_qspi_write8(REG_PWM_DUTY, 0);
/* active display width */
TFT_qspi_write16(REG_HSIZE, 800);
/* verify the value was set */
if(TFT_qspi_read16(REG_HSIZE) != 800)
    Error_Handler();


I've attached my capture.  I'm currently using WaveForms which I don't care for much but it's what I have right now.  The capture is pretty close to what you posted for the REG_HSIZE.

I have a lot of code yet to write to get something to show up on the display, but this is a HUGE start.

Thanks so much for your assistance.

Kindest regards