BRT Community

Please login or register.

Login with username, password and session length
Advanced search  

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

Author Topic: Using QUAD SPI (qspi)  (Read 355 times)

kumaichi

  • Newbie
  • *
  • Posts: 16
    • View Profile
Using QUAD SPI (qspi)
« on: September 04, 2024, 04:46:18 PM »

Hello,

I currently have Rudolphs library and the Riverdi_EVE library running via SPI.  All that is working just fine.  I'm using custom hardware with an STM32WB55REV6 on it and the QUADSPI bus is what's connected to the Riverdi display.  I tried using the QUADSPI in single mode but have failed miserably so thought I'd try using QUAD SPI instead.

Looking at the datasheet, 4.1 Quad SPI Host Interface, I believe I need to write 0x04 to the REG_SPI_WIDTH.  At which point in the initialization process, documented in the BRT_AN_033_BT81X-Series-Programming-Guide, section 2.4 Initialization Sequence during Boot Up?  Should REG_SPI_WIDTH be set after setting everything up or is it the first thing that should be set after the RST/PD sequence?

Any other things that might be helpful getting it up and running via QUAD SPI?

Any insight would be greatly appreciated.

Logged

BRT Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 770
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #1 on: September 06, 2024, 02:23:27 PM »

Hello,

Thank you for your question, below in code snippets I have included our standard initialization procedure from our BRT_AN_025 application note.

At the start of an application we would call the EVE_Init() function:

Code: [Select]
void EVE_Init(void)
{
uint8_t regGpio;
int i;

HAL_EVE_Init();

// ------------------------- Display settings ------------------------------

// LCD display parameters
// Active width of LCD display
HAL_MemWrite16(EVE_REG_HSIZE,   EVE_DISP_WIDTH);
// Total number of clocks per line
HAL_MemWrite16(EVE_REG_HCYCLE,  EVE_DISP_HCYCLE);
// Start of active line
HAL_MemWrite16(EVE_REG_HOFFSET, EVE_DISP_HOFFSET);
// Start of horizontal sync pulse
HAL_MemWrite16(EVE_REG_HSYNC0,  EVE_DISP_HSYNC0);
// End of horizontal sync pulse
HAL_MemWrite16(EVE_REG_HSYNC1,  EVE_DISP_HSYNC1);
// Active height of LCD display
HAL_MemWrite16(EVE_REG_VSIZE,   EVE_DISP_HEIGHT);
// Total number of lines per screen
HAL_MemWrite16(EVE_REG_VCYCLE,  EVE_DISP_VCYCLE);
// Start of active screen
HAL_MemWrite16(EVE_REG_VOFFSET, EVE_DISP_VOFFSET);
// Start of vertical sync pulse
HAL_MemWrite16(EVE_REG_VSYNC0,  EVE_DISP_VSYNC0);
// End of vertical sync pulse
HAL_MemWrite16(EVE_REG_VSYNC1,  EVE_DISP_VSYNC1);
// Define RGB output pins
HAL_MemWrite8(EVE_REG_SWIZZLE,  EVE_DISP_SWIZZLE);
// Define active edge of PCLK
HAL_MemWrite8(EVE_REG_PCLK_POL, EVE_DISP_PCLKPOL);
// Turn on or off CSpread
HAL_MemWrite8(EVE_REG_CSPREAD,  EVE_DISP_CSPREAD);
// Turn on or off Dither
HAL_MemWrite8(EVE_REG_DITHER,  1);
HAL_MemWrite8(EVE_REG_OUTBITS,  0x0);

// Write first display list
HAL_MemWrite32((EVE_RAM_DL + 0), EVE_ENC_CLEAR_COLOR_RGB(0,0,0));
HAL_MemWrite32((EVE_RAM_DL + 4), EVE_ENC_CLEAR(1,1,1));
HAL_MemWrite32((EVE_RAM_DL + 8), EVE_ENC_DISPLAY());
HAL_MemWrite8(EVE_REG_DLSWAP, EVE_DLSWAP_FRAME);

// Read the  GPIO register for a read/modify/write operation
regGpio = HAL_MemRead8(EVE_REG_GPIO);
// set bit 7 of  GPIO register (DISP) - others are inputs
regGpio = regGpio | 0x80;
// Enable the DISP signal to the LCD panel
HAL_MemWrite8(EVE_REG_GPIO, regGpio);

// Write the PCLK or PCLK_FREQ register
// If setting PCLK_FREQ then also set REG_PCLK to 1 to enable extsync mode
#if (defined EVE4_ENABLE) && (defined SET_PCLK_FREQ)
HAL_MemWrite16(EVE_REG_PCLK_FREQ,  EVE_DISP_PCLK_FREQ);
HAL_MemWrite8(EVE_REG_PCLK, 1);
# else
// Now start clocking data to the LCD panel
HAL_MemWrite8(EVE_REG_PCLK, EVE_DISP_PCLK);
#endif

HAL_MemWrite8(EVE_REG_PWM_DUTY, 127);

// ---------------------- Touch and Audio settings -------------------------
// Eliminate any false touches
HAL_MemWrite16(EVE_REG_TOUCH_RZTHRESH, 1200);

// turn recorded audio volume down
HAL_MemWrite8(EVE_REG_VOL_PB, EVE_VOL_ZERO);
// turn synthesizer volume down
HAL_MemWrite8(EVE_REG_VOL_SOUND, EVE_VOL_ZERO);
// set synthesizer to mute
HAL_MemWrite16(EVE_REG_SOUND, 0x6000);

// --------------------- Clear screen ready to start -----------------------
EVE_LIB_BeginCoProList();
EVE_CMD_DLSTART();
EVE_CLEAR_COLOR_RGB(0, 0, 0);
EVE_CLEAR(1,1,1);
EVE_DISPLAY();
EVE_CMD_SWAP();
EVE_LIB_EndCoProList();
EVE_LIB_AwaitCoProEmpty();


#if (defined EVE2_ENABLE || defined EVE3_ENABLE || defined EVE4_ENABLE)

// ---------------------- Reset all bitmap properties ------------------------
EVE_LIB_BeginCoProList();
EVE_CMD_DLSTART();
EVE_CLEAR_COLOR_RGB(0, 0, 0);
EVE_CLEAR(1,1,1);
for (i = 0; i < 16; i++)
{
EVE_BITMAP_HANDLE(i);
EVE_CMD_SETBITMAP(0,0,0,0);
}
EVE_DISPLAY();
EVE_CMD_SWAP();
EVE_LIB_EndCoProList();
EVE_LIB_AwaitCoProEmpty();

# else
   
    // ---------------------- Reset all bitmap properties ------------------------
EVE_LIB_BeginCoProList();
EVE_CMD_DLSTART();
EVE_CLEAR_COLOR_RGB(0, 0, 0);
EVE_CLEAR(1,1,1);
for (i = 0; i < 16; i++)
{
EVE_BITMAP_HANDLE(i);
//EVE_CMD_SETBITMAP(0,0,0,0);
        EVE_BITMAP_LAYOUT(0, 0, 0);
    EVE_BITMAP_SIZE(0, 0, 0, 0, 0);
}
EVE_DISPLAY();
EVE_CMD_SWAP();
EVE_LIB_EndCoProList();
EVE_LIB_AwaitCoProEmpty();
#endif
}

This immediately calls the HAL_EVE_Init() function:
Code: [Select]
void HAL_EVE_Init(void)
{
uint8_t val;

MCU_Init();

// Set Chip Select OFF
HAL_ChipSelect(0);

// Reset the display
MCU_Delay_20ms();
HAL_PowerDown(1);
MCU_Delay_20ms();
HAL_PowerDown(0);
MCU_Delay_20ms();

#if (defined EVE1_ENABLE)
// FT80x_selection - FT80x modules from BRT generally use external crystal
// You can also send the host command to set the PLL here if you want to change it from the default of 48MHz (FT80x) or 60MHz (FT81x)
// Clock selection and clock rate selection will put EVE to sleep and so must be before the Active command
// for example:
HAL_HostCmdWrite(0x44, 0x00); // 0x44 = HostCMD_CLKEXT
HAL_HostCmdWrite(0x62, 0x00); // 0x64 = HostCMD_CLK48M
#endif

#if defined (EVE3_ENABLE) || defined (EVE4_ENABLE)
// can optionally set to 72MHz system clock here
// In this case also adjust REG_FREQUENCY a few lines down from here in this file
HAL_HostCmdWrite(0x44, 0x00); // 0x44 = HostCMD_CLKEXT
HAL_HostCmdWrite(0x61, 0x46);
#endif

#if defined (EVE2_ENABLE) || defined (EVE3_ENABLE)|| defined (EVE4_ENABLE)
HAL_HostCmdWrite(0x68, 0x00); // Reset
#endif

// Set active
HAL_HostCmdWrite(0, 0x00);

// MCU_Delay_500ms(); // Optional delay can be commented so long as we check the REG_ID and REG_CPURESET

// Read REG_ID register (0x302000) until reads 0x7C
while ((val = HAL_MemRead8(EVE_REG_ID)) != 0x7C)
{
}

// Ensure CPUreset register reads 0 and so FT8xx is ready
while (HAL_MemRead8(EVE_REG_CPURESET) != 0x00)
{
}

#if defined (EVE3_ENABLE) || defined (EVE4_ENABLE)
HAL_MemWrite32(EVE_REG_FREQUENCY, 72000000);
#endif

// This function will not return unless an EVE device is present.
MCU_Setup();
}

Where MCU_Init() is called at the beginning to configure the MCU, and continues on to wait for EVE to boot. At the end of HAL_EVE_Init() we call MCU_Setup() which is where the REG_SPI_WIDTH register would be written to if requried:

Here are the MCU_Init() and MCU_Setup() calls for our FT9xx series MCUs which can enable QSPI transactions:

Code: [Select]
void MCU_Init(void)
{
// Initialize SPIM HW
sys_enable(sys_device_spi_master);

gpio_function(PIN_NUM_CLK, pad_spim_sck); /* GPIO27 to SPIM_CLK */
#if __FT900__
gpio_function(PIN_NUM_CS, pad_spim_ss0); /* GPIO28 as CS */
gpio_function(PIN_NUM_PD, pad_gpio43);
#else
gpio_function(PIN_NUM_CS, pad30_spim_ss0); /* GPIO30 as CS */
gpio_function(PIN_NUM_PD, pad_gpio15);
#endif

gpio_function(PIN_NUM_MOSI, pad_spim_mosi); /* GPIO29 to SPIM_MOSI */
gpio_function(PIN_NUM_MISO, pad_spim_miso); /* GPIO30 to SPIM_MISO */

gpio_dir(PIN_NUM_CLK, pad_dir_output);
gpio_dir(PIN_NUM_CS, pad_dir_output);
gpio_dir(PIN_NUM_MOSI, pad_dir_output);
gpio_dir(PIN_NUM_MISO, pad_dir_input);
gpio_dir(PIN_NUM_PD, pad_dir_output);
#if (SPI_ENABLE == ENABLE_SPI_QUAD)
/* Initialize IO2 and IO3 pad/pin for quad settings */
gpio_function(PIN_NUM_IO2, pad_spim_io2); /* GPIO31 to IO2 */
gpio_function(PIN_NUM_IO3, pad_spim_io3); /* GPIO32 to IO3 */
gpio_dir(PIN_NUM_IO2, pad_dir_output);
gpio_dir(PIN_NUM_IO3, pad_dir_output);
#endif
gpio_write(PIN_NUM_CS, 1);
gpio_write(PIN_NUM_PD, 1);

spi_init(SPIM, spi_dir_master, spi_mode_0, 8);
}

void MCU_Setup(void)
{
#if defined QUADSPI_ENABLE

#if (defined EVE2_ENABLE || defined EVE3_ENABLE || defined EVE4_ENABLE)
// Turn on EVE quad-SPI for FT81x devices.
MCU_CSlow();
MCU_SPIWrite24(MCU_htobe32((EVE_REG_SPI_WIDTH << 8) | (1 << 31)));
MCU_SPIWrite8(2);
MCU_CShigh();

// Turn on FT9xx quad-SPI.
spi_option(SPIM, spi_option_bus_width, 4);
#endif//(defined EVE2_ENABLE || defined EVE3_ENABLE || defined EVE4_ENABLE)
#endif// QUADSPI_ENABLE

// Turn off SPI buffering. Timing of chip select is critical.
spi_option(SPIM, spi_option_fifo, 0);
}

So to answer your question, you can write REG_SPI_WIDTH after the host commands have been sent to the device during the initialization sequence.

Note: when operating in QSPI mode EVE requires an extra cock cycle for data to be available during a read transaction, as such an extra dummy byte will be required during the transaction.

Best Regards,
BRT Community


« Last Edit: September 06, 2024, 02:25:13 PM by BRT Community »
Logged

kumaichi

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #2 on: September 06, 2024, 03:42:01 PM »

Thank you for your response.

Looking at the datasheet for REG_SPI_WIDTH Definition:
Bit 2: Extra dummy on SPI read transfer.  Writing 1 to enable one extra dummy byte on SPI read transfer.
Bit 1 - 0: SPI data bus width: 0b'10: 4 bit (Quad-SPI)

I would need to send: 00000110 (0x06)
Correct?

In the FT9xx code, it looks like '4' is being sent:
// Turn on FT9xx quad-SPI.
spi_option(SPIM, spi_option_bus_width, 4);

The reason I ask is because in the Programming Guide (page 12) for Quad SPI, it says when reading, you have to send:
WR/Address -> Address -> Address -> Dummy -> Data -> Data...

Trying to wrap my head around this, I set REG_SPI_WIDTH, TFT_write8(REG_SPI_WIDTH, 6);

This should switch into Quad SPI mode, correct?  I then immediately try to read the REG_SPI_WIDTH out to make sure I can successfully read something, kind of like initially reading the Chip_ID:

Code: [Select]
uint8_t TFT_read8(uint32_t const address)
{
QSPI_CommandTypeDef sCommand = {0};

// Set up the command structure
sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;   // Instruction sent over 1 line
sCommand.Instruction       = (uint8_t)(address >> 16U); //Get the first byte, should look like 0x30
sCommand.AddressMode       = QSPI_ADDRESS_1_LINE;       // Address sent over 1 line
sCommand.AddressSize       = QSPI_ADDRESS_16_BITS;      // Try using 16-bit address
sCommand.Address           = address & 0xFFFF;          // Mask off the first byte and keep the last two bytes
sCommand.DataMode          = QSPI_DATA_1_LINE;          // Data mode for receiving ID
sCommand.NbData            = 2;                         // Expecting 2 bytes (for ID)
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 receive the data
uint8_t retData[2] = {0};  // Array to hold the received ID
if (HAL_QSPI_Receive(&hqspi, retData, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
Error_Handler();

uint8_t data = retData[1];

    return data;
}

This however does not work, it either hangs waiting for a response or ends up in the Error_Handler().  I think I have what needs to be sent correct.  Referencing the Programming Guide:
4.1.3 Host Memory Read
For SPI memory read transactions, the host sends two zero bits, followed by the 22-bit address. This is
followed by a dummy byte. After the dummy byte, the BT817/8 responds to each host byte with read
data bytes.

Do you see anything obvious that I have wrong?

Kindest regards.
« Last Edit: September 09, 2024, 02:06:32 PM by kumaichi »
Logged

BRT Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 770
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #3 on: September 11, 2024, 04:09:26 PM »

Hello,

Thank you for the update.

Thank you for your response.

Looking at the datasheet for REG_SPI_WIDTH Definition:
Bit 2: Extra dummy on SPI read transfer.  Writing 1 to enable one extra dummy byte on SPI read transfer.
Bit 1 - 0: SPI data bus width: 0b'10: 4 bit (Quad-SPI)

I would need to send: 00000110 (0x06)
Correct?

In the FT9xx code, it looks like '4' is being sent:
// Turn on FT9xx quad-SPI.
spi_option(SPIM, spi_option_bus_width, 4);


Yes this is correct, to just enable Quad SPI mode on EVE you would write 2 (dec) to the REG_SPI_WIDTH register, to also enable the extra dummy byte you would write 6 (dec) to the register.

As for the spi_option() command, this is a FT9xx API command which is being used to configure the SPI mater interface on the MCU, you can find details of this command in Section 2.15.3.11 of the FT9xx API Programmers Manual. Essentially this is being used to set the interface to Quad SPI on the master.

I have attached a capture (Capture.PNG) of a REG_HSIZE write and subsequent read in QPSI mode for reference, were looking for the following values on the trace:
Code: [Select]
REG_HSIZE = 0x302034
Bin = 0011 0000 0010 0000 0011 0100
Bin (with write bit) = 1011 0000 0010 0000 0011 0100


Value = 800
Bin = 0000 0011 0010 0000
Bin (with endianness applied) = 0010 0000 0000 0011

Note: in this configuration I was using the FT9xx as the SPI master and we only need to utilise a single dummy byte during the read phase due to implementing a slow SCLK rate, for higher SCLK rates we would enable the extra dummy byte. The read and write addressing phases are send in 24 bit transactions with the 22 bit address appending the read (00) or write (10) bits.

Could you please clarify what the clock rate of your SPI master is?

The reason I ask is because in the Programming Guide (page 12) for Quad SPI, it says when reading, you have to send:
WR/Address -> Address -> Address -> Dummy -> Data -> Data...

Trying to wrap my head around this, I set REG_SPI_WIDTH, TFT_write8(REG_SPI_WIDTH, 6);

This should switch into Quad SPI mode, correct?  I then immediately try to read the REG_SPI_WIDTH out to make sure I can successfully read something, kind of like initially reading the Chip_ID:

Yes I believe your write should configure EVE into QPSI mode, do you then subsequently configure the SPI master interface into QSPI?

Code: [Select]
uint8_t TFT_read8(uint32_t const address)
{
QSPI_CommandTypeDef sCommand = {0};

// Set up the command structure
sCommand.InstructionMode   = QSPI_INSTRUCTION_1_LINE;   // Instruction sent over 1 line
sCommand.Instruction       = (uint8_t)(address >> 16U); //Get the first byte, should look like 0x30
sCommand.AddressMode       = QSPI_ADDRESS_1_LINE;       // Address sent over 1 line
sCommand.AddressSize       = QSPI_ADDRESS_16_BITS;      // Try using 16-bit address
sCommand.Address           = address & 0xFFFF;          // Mask off the first byte and keep the last two bytes
sCommand.DataMode          = QSPI_DATA_1_LINE;          // Data mode for receiving ID
sCommand.NbData            = 2;                         // Expecting 2 bytes (for ID)
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 receive the data
uint8_t retData[2] = {0};  // Array to hold the received ID
if (HAL_QSPI_Receive(&hqspi, retData, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
Error_Handler();

uint8_t data = retData[1];

    return data;
}

This however does not work, it either hangs waiting for a response or ends up in the Error_Handler().  I think I have what needs to be sent correct.  Referencing the Programming Guide:
4.1.3 Host Memory Read
For SPI memory read transactions, the host sends two zero bits, followed by the 22-bit address. This is
followed by a dummy byte. After the dummy byte, the BT817/8 responds to each host byte with read
data bytes.

Do you see anything obvious that I have wrong?

Have you configured the read function to use a dummy byte? I note the following line in your typedef for the address write:
Code: [Select]
sCommand.DummyCycles       = 0;                         // No dummy cycles
What is HAL_QSPI_Receive() function doing? (I'm looking to clarify where the dummy bytes are enacted on the master side)

Do you have a logic analyser to hand? it may be useful to scope the SPI traces during initialization so that you can observer the bus activity.
I can provide a SPI trance of the BRT_AN_025 code configuring EVE into QSPI if you believe this would be useful to you?

Best Regards,
BRT Community
Logged

kumaichi

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #4 on: September 13, 2024, 03:07:58 AM »

This is GREAT information, thank you! 

My SCK is VERY slow at this point, just trying to keep variables to a minimum while I try to get it working.  My QSPI clock is, 16Mhz and the prescaler is set at 250.

I've actually been using SPI traces to get my QSPI commands sorted so if you could share a working QSPI trace I could reference to try and match, I think that would be very helpful, thank you!

I will implement your suggestions and if I'm still having issues I will get a trace for analysis.

Again, thank you for your detailed explanation.

Kindest regards.
« Last Edit: September 13, 2024, 03:19:04 AM by kumaichi »
Logged

BRT Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 770
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #5 on: September 13, 2024, 10:55:32 AM »

Hello,

I have attached a Logic Analyser capture of the BRT_AN_025 code running on an FT9xx MCU for reference (BRT_AN_025 Quad Spi with delays.sal).

The SPI master clock is running at 200KHz, and some 20ms delays have been added into the code around the write to REG_SPI_WIDTH, as well as a 500ms delay before the main example loop to make the capture easier to read (see QSPI init (with delays).PNG).

Here are the code modifications:

HAL_EVE_Init(void)
Code: [Select]
void HAL_EVE_Init(void)
{
uint8_t val;

MCU_Init();

// Set Chip Select OFF
HAL_ChipSelect(0);

// Reset the display
MCU_Delay_20ms();
HAL_PowerDown(1);
MCU_Delay_20ms();
HAL_PowerDown(0);
MCU_Delay_20ms();

#if (defined EVE1_ENABLE)
// FT80x_selection - FT80x modules from BRT generally use external crystal
// You can also send the host command to set the PLL here if you want to change it from the default of 48MHz (FT80x) or 60MHz (FT81x)
// Clock selection and clock rate selection will put EVE to sleep and so must be before the Active command
// for example:
HAL_HostCmdWrite(0x44, 0x00); // 0x44 = HostCMD_CLKEXT
HAL_HostCmdWrite(0x62, 0x00); // 0x64 = HostCMD_CLK48M
#endif

#if defined (EVE3_ENABLE) || defined (EVE4_ENABLE)
// can optionally set to 72MHz system clock here
// In this case also adjust REG_FREQUENCY a few lines down from here in this file
HAL_HostCmdWrite(0x44, 0x00); // 0x44 = HostCMD_CLKEXT
HAL_HostCmdWrite(0x61, 0x46);
#endif

#if defined (EVE2_ENABLE) || defined (EVE3_ENABLE)|| defined (EVE4_ENABLE)
HAL_HostCmdWrite(0x68, 0x00); // Reset
#endif

// Set active
HAL_HostCmdWrite(0, 0x00);

// MCU_Delay_500ms(); // Optional delay can be commented so long as we check the REG_ID and REG_CPURESET

// Read REG_ID register (0x302000) until reads 0x7C
while ((val = HAL_MemRead8(EVE_REG_ID)) != 0x7C)
{
}

// Ensure CPUreset register reads 0 and so FT8xx is ready
while (HAL_MemRead8(EVE_REG_CPURESET) != 0x00)
{
}

#if defined (EVE3_ENABLE) || defined (EVE4_ENABLE)
HAL_MemWrite32(EVE_REG_FREQUENCY, 72000000);
#endif

MCU_Delay_20ms();
// This function will not return unless an EVE device is present.
MCU_Setup();


}

EVE_Init(void)
Code: [Select]
void EVE_Init(void)
{
uint8_t regGpio;
int i;

HAL_EVE_Init();
MCU_Delay_20ms();

// ------------------------- Display settings ------------------------------

// LCD display parameters
// Active width of LCD display
HAL_MemWrite16(EVE_REG_HSIZE,   EVE_DISP_WIDTH);
// Total number of clocks per line
HAL_MemWrite16(EVE_REG_HCYCLE,  EVE_DISP_HCYCLE);
// Start of active line
HAL_MemWrite16(EVE_REG_HOFFSET, EVE_DISP_HOFFSET);
// Start of horizontal sync pulse
HAL_MemWrite16(EVE_REG_HSYNC0,  EVE_DISP_HSYNC0);
// End of horizontal sync pulse
HAL_MemWrite16(EVE_REG_HSYNC1,  EVE_DISP_HSYNC1);
// Active height of LCD display
HAL_MemWrite16(EVE_REG_VSIZE,   EVE_DISP_HEIGHT);
// Total number of lines per screen
HAL_MemWrite16(EVE_REG_VCYCLE,  EVE_DISP_VCYCLE);
// Start of active screen
HAL_MemWrite16(EVE_REG_VOFFSET, EVE_DISP_VOFFSET);
// Start of vertical sync pulse
HAL_MemWrite16(EVE_REG_VSYNC0,  EVE_DISP_VSYNC0);
// End of vertical sync pulse
HAL_MemWrite16(EVE_REG_VSYNC1,  EVE_DISP_VSYNC1);
// Define RGB output pins
HAL_MemWrite8(EVE_REG_SWIZZLE,  EVE_DISP_SWIZZLE);
// Define active edge of PCLK
HAL_MemWrite8(EVE_REG_PCLK_POL, EVE_DISP_PCLKPOL);
// Turn on or off CSpread
HAL_MemWrite8(EVE_REG_CSPREAD,  EVE_DISP_CSPREAD);
// Turn on or off Dither
HAL_MemWrite8(EVE_REG_DITHER,  EVE_DISP_DITHER);

// Write first display list
HAL_MemWrite32((EVE_RAM_DL + 0), EVE_ENC_CLEAR_COLOR_RGB(0,0,0));
HAL_MemWrite32((EVE_RAM_DL + 4), EVE_ENC_CLEAR(1,1,1));
HAL_MemWrite32((EVE_RAM_DL + 8), EVE_ENC_DISPLAY());
HAL_MemWrite8(EVE_REG_DLSWAP, EVE_DLSWAP_FRAME);

// Read the  GPIO register for a read/modify/write operation
regGpio = HAL_MemRead8(EVE_REG_GPIO);
// set bit 7 of  GPIO register (DISP) - others are inputs
regGpio = regGpio | 0x80;
// Enable the DISP signal to the LCD panel
HAL_MemWrite8(EVE_REG_GPIO, regGpio);

// Write the PCLK or PCLK_FREQ register
// If setting PCLK_FREQ then also set REG_PCLK to 1 to enable extsync mode
#if (defined EVE4_ENABLE) && (defined SET_PCLK_FREQ)
HAL_MemWrite16(EVE_REG_PCLK_FREQ,  EVE_DISP_PCLK_FREQ);
HAL_MemWrite8(EVE_REG_PCLK, 1);
# else
// Now start clocking data to the LCD panel
HAL_MemWrite8(EVE_REG_PCLK, EVE_DISP_PCLK);
#endif

HAL_MemWrite8(EVE_REG_PWM_DUTY, 127);

// ---------------------- Touch and Audio settings -------------------------
// Eliminate any false touches
HAL_MemWrite16(EVE_REG_TOUCH_RZTHRESH, 1200);

// turn recorded audio volume down
HAL_MemWrite8(EVE_REG_VOL_PB, EVE_VOL_ZERO);
// turn synthesizer volume down
HAL_MemWrite8(EVE_REG_VOL_SOUND, EVE_VOL_ZERO);
// set synthesizer to mute
HAL_MemWrite16(EVE_REG_SOUND, 0x6000);

// --------------------- Clear screen ready to start -----------------------
EVE_LIB_BeginCoProList();
EVE_CMD_DLSTART();
EVE_CLEAR_COLOR_RGB(0, 0, 0);
EVE_CLEAR(1,1,1);
EVE_DISPLAY();
EVE_CMD_SWAP();
EVE_LIB_EndCoProList();
EVE_LIB_AwaitCoProEmpty();


#if (defined EVE2_ENABLE || defined EVE3_ENABLE || defined EVE4_ENABLE)

// ---------------------- Reset all bitmap properties ------------------------
EVE_LIB_BeginCoProList();
EVE_CMD_DLSTART();
EVE_CLEAR_COLOR_RGB(0, 0, 0);
EVE_CLEAR(1,1,1);
for (i = 0; i < 16; i++)
{
EVE_BITMAP_HANDLE(i);
EVE_CMD_SETBITMAP(0,0,0,0);
}
EVE_DISPLAY();
EVE_CMD_SWAP();
EVE_LIB_EndCoProList();
EVE_LIB_AwaitCoProEmpty();

# else
   
    // ---------------------- Reset all bitmap properties ------------------------
EVE_LIB_BeginCoProList();
EVE_CMD_DLSTART();
EVE_CLEAR_COLOR_RGB(0, 0, 0);
EVE_CLEAR(1,1,1);
for (i = 0; i < 16; i++)
{
EVE_BITMAP_HANDLE(i);
//EVE_CMD_SETBITMAP(0,0,0,0);
        EVE_BITMAP_LAYOUT(0, 0, 0);
    EVE_BITMAP_SIZE(0, 0, 0, 0, 0);
}
EVE_DISPLAY();
EVE_CMD_SWAP();
EVE_LIB_EndCoProList();
EVE_LIB_AwaitCoProEmpty();
#endif

}

 eve_display(void):
Code: [Select]
void eve_display(void)
{
uint32_t counter = 0;
uint8_t key;
int8_t i;
uint32_t units;
MCU_Delay_500ms();

do {
// Comment this line if the counter needs to increment continuously.
// Uncomment and it will increment by one each press.

Best Regards,
BRT Community 
Logged

kumaichi

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #6 on: September 13, 2024, 06:30:22 PM »

This is excellent, thank you! 

Increasing my clock speed, I think will yield better results in this case, maybe it's too slow.  Now I know what the communication should look like I will try and mimic and get something working.  I'll report back what my results are.

Thanks again.

Kindest regards
Logged

kumaichi

  • Newbie
  • *
  • Posts: 16
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #7 on: 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:

Code: [Select]
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
Logged

BRT Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 770
    • View Profile
Re: Using QUAD SPI (qspi)
« Reply #8 on: September 17, 2024, 10:15:23 AM »

Hello,

Thank you for the update, we are glad to hear you have managed to get up and running with QSPI.

Please let us know if you have any further questions.

Best Regards,
BRT Community
Logged