ESP32S3 PSRAM Mhz

MasterExploder
Posts: 26
Joined: Wed Feb 08, 2023 6:17 pm

ESP32S3 PSRAM Mhz

Postby MasterExploder » Fri Apr 07, 2023 6:21 am

Hi everyone, i would like to ask for anyone has tried to put octal mode PSRAM with 80 MHz.
I have and esp32-s3-wroom1-n16-r8, with 80MHz and DDR PSRAM in octal mode i should be albe to go at 160MB/s but i tried to measure it and i found out that for me is like 40MB/s or so, maybe is it something that i am doing wrong with other configurations? Maybe a GDMA configuration?
Help would be appreciated to understand these numbers, thank you for your time.

ESP_Sprite
Posts: 9757
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32S3 PSRAM Mhz

Postby ESP_Sprite » Sat Apr 08, 2023 3:04 am

How are you testing those numbers?

MasterExploder
Posts: 26
Joined: Wed Feb 08, 2023 6:17 pm

Re: ESP32S3 PSRAM Mhz

Postby MasterExploder » Sun Apr 09, 2023 6:10 am

I simply try to write 1MB of Memory in PSRam and set a PIN to 1, then when i finish i set the PIN to 0 and i measure the time with the oscilloscope.
I allocate memory in PSRam with heap_caps_malloc so i am sure that i am accessing PSRam, the problem in this case is that i am not sure if the GDMA is been used or not to access that memory.
What is the correct method and configurations to get the max speed in read and write using external memory?

ESP_Sprite
Posts: 9757
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32S3 PSRAM Mhz

Postby ESP_Sprite » Mon Apr 10, 2023 1:05 am

Simply writing data does not use DMA, it goes via the cache. This also means your number will be halved, as the cache will read the memory when accessed, even if you fully overwrite it in your code. That still does not account for the other 50% you're lacking, can you post your specific code perhaps?

MasterExploder
Posts: 26
Joined: Wed Feb 08, 2023 6:17 pm

Re: ESP32S3 PSRAM Mhz

Postby MasterExploder » Tue Apr 11, 2023 4:06 pm

Yes sure, actually, i was asking this question because i'm trying to work with an LCD screen with 565 RGB and i have some problems with the screen, so i did some tests with the memory to see if i understood well.
I thought: if i'm working with SPRAM at 80Mhz with 8 channels, it means 80MB/s, also, i read that the SPRAM in my esp32-s3-wroom1-n16r8 is DDR, so it should be 160MB/s.
I will paste here lcd.h and lcd.c.

header:

Code: Select all

#pragma once


#include "lvgl.h"
#include "utils.h"
#include "esp_timer.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_rgb.h"
#include "esp_lcd_touch.h"
#include "esp_lcd_touch_gt911.h"
#include "esp_lvgl_port.h"


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define SETTE_POLLICI 0
#define DIECI_POLLICI 1

#define SELECTED_TFT DIECI_POLLICI

#if SELECTED_TFT == SETTE_POLLICI

#define EXAMPLE_LCD_PIXEL_CLOCK_HZ     (10 * 1000 * 1000)
#define EXAMPLE_LCD_H_RES              800
#define EXAMPLE_LCD_V_RES              480
#define HSYNC_BACK_PORCH 43
#define HSYNC_FRONT_PORCH 8
#define HSYNC_PULSE_WIDTH 4
#define VSYNC_BACK_PORCH 12
#define VSYNC_FRONT_PORCH 37
#define VSYNC_PULSE_WIDTH 37
#define MS_BETWEEN_FRAMES 32

#elif SELECTED_TFT == DIECI_POLLICI

#define EXAMPLE_LCD_PIXEL_CLOCK_HZ     (16 * 1000 * 1000)
#define EXAMPLE_LCD_H_RES              1024
#define EXAMPLE_LCD_V_RES              600
#define HSYNC_BACK_PORCH 160
#define HSYNC_FRONT_PORCH 16
#define HSYNC_PULSE_WIDTH 1
#define VSYNC_BACK_PORCH 23
#define VSYNC_FRONT_PORCH 12
#define VSYNC_PULSE_WIDTH 1
#define MS_BETWEEN_FRAMES 38 // lo schermo può andare a 60 fps a livello teorico

#endif


#define EXAMPLE_PIN_NUM_HSYNC          6
#define EXAMPLE_PIN_NUM_VSYNC          7
#define EXAMPLE_PIN_NUM_DE             15
#define EXAMPLE_PIN_NUM_PCLK           21

#define EXAMPLE_PIN_NUM_DATA0          42 // B3
#define EXAMPLE_PIN_NUM_DATA1          44 // B4
#define EXAMPLE_PIN_NUM_DATA2          43 // B5
#define EXAMPLE_PIN_NUM_DATA3          2 // B6
#define EXAMPLE_PIN_NUM_DATA4          1 // B7

#define CONFIG_EXAMPLE_DOUBLE_FB          0
#define CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM          0

#define EXAMPLE_PIN_NUM_DATA5          14 // G2
#define EXAMPLE_PIN_NUM_DATA6          46 // G3
#define EXAMPLE_PIN_NUM_DATA7          38 // G4
#define EXAMPLE_PIN_NUM_DATA8          39 // G5
#define EXAMPLE_PIN_NUM_DATA9          40 // G6
#define EXAMPLE_PIN_NUM_DATA10         41 // G7

#define EXAMPLE_PIN_NUM_DATA11         47  // R3
#define EXAMPLE_PIN_NUM_DATA12         48  // R4
#define EXAMPLE_PIN_NUM_DATA13         45 // R5
#define EXAMPLE_PIN_NUM_DATA14         0 // R6
#define EXAMPLE_PIN_NUM_DATA15         17 // R7

#define EXAMPLE_PIN_NUM_DISP_EN        -1

// The pixel number in horizontal and vertical



#define EXAMPLE_LVGL_TICK_PERIOD_MS    2

void increase_lvgl_tick(void *arg);
void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map);
bool example_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *event_data, void *user_data);

void lcd_init();

void lvgl_task(void *pvParameters);
source:

Code: Select all

#include "lcd.h"
#include "i2c.h"


static const char *TAG = "LCD SCREEN";

#include "driver/gpio.h"
#include "utils.h"

// we use two semaphores to sync the VSYNC event and the LVGL task, to avoid potential tearing effect
#if CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM
SemaphoreHandle_t sem_vsync_end;
SemaphoreHandle_t sem_gui_ready;
#endif


bool example_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *event_data, void *user_data)
{
	BaseType_t high_task_awoken = pdFALSE;
#if CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM
	if (xSemaphoreTakeFromISR(sem_gui_ready, &high_task_awoken) == pdTRUE) {
		xSemaphoreGiveFromISR(sem_vsync_end, &high_task_awoken);
	}
#endif
	return high_task_awoken == pdTRUE;
}

void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map)
{
	
	esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
	int offsetx1 = area->x1;
	int offsetx2 = area->x2;
	int offsety1 = area->y1;
	int offsety2 = area->y2;
#if CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM
	xSemaphoreGive(sem_gui_ready);
	xSemaphoreTake(sem_vsync_end, portMAX_DELAY);
#endif
	// pass the draw buffer to the driver
	esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
	lv_disp_flush_ready(drv);
}

void increase_lvgl_tick(void *arg)
{
	/* Tell LVGL how many milliseconds has elapsed */
	lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS);
}




void lcd_init()
{
	
	static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
	static lv_disp_drv_t disp_drv; // contains callback functions

#if CONFIG_EXAMPLE_AVOID_TEAR_EFFECT_WITH_SEM
	ESP_LOGI(TAG, "Create semaphores");
	sem_vsync_end = xSemaphoreCreateBinary();
	assert(sem_vsync_end);
	sem_gui_ready = xSemaphoreCreateBinary();
	assert(sem_gui_ready);
#endif

	ESP_LOGI(TAG, "Install RGB LCD panel driver");
	esp_lcd_panel_handle_t panel_handle = NULL;
	esp_lcd_rgb_panel_config_t panel_config = {
		.data_width = 16,
		.clk_src = LCD_CLK_SRC_PLL240M,
		.disp_gpio_num = EXAMPLE_PIN_NUM_DISP_EN,
		.pclk_gpio_num = EXAMPLE_PIN_NUM_PCLK,
		.vsync_gpio_num = EXAMPLE_PIN_NUM_VSYNC,
		.hsync_gpio_num = EXAMPLE_PIN_NUM_HSYNC,
		.de_gpio_num = EXAMPLE_PIN_NUM_DE,
		.data_gpio_nums = {
		EXAMPLE_PIN_NUM_DATA0,
		EXAMPLE_PIN_NUM_DATA1,
		EXAMPLE_PIN_NUM_DATA2,
		EXAMPLE_PIN_NUM_DATA3,
		EXAMPLE_PIN_NUM_DATA4,
		EXAMPLE_PIN_NUM_DATA5,
		EXAMPLE_PIN_NUM_DATA6,
		EXAMPLE_PIN_NUM_DATA7,
		EXAMPLE_PIN_NUM_DATA8,
		EXAMPLE_PIN_NUM_DATA9,
		EXAMPLE_PIN_NUM_DATA10,
		EXAMPLE_PIN_NUM_DATA11,
		EXAMPLE_PIN_NUM_DATA12,
		EXAMPLE_PIN_NUM_DATA13,
		EXAMPLE_PIN_NUM_DATA14,
		EXAMPLE_PIN_NUM_DATA15,
	},
		.timings = {
		.pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
		.h_res = EXAMPLE_LCD_H_RES,
		.v_res = EXAMPLE_LCD_V_RES,
		// The following parameters should refer to LCD spec
		.hsync_back_porch = HSYNC_BACK_PORCH,
		.hsync_front_porch = HSYNC_FRONT_PORCH,
		.hsync_pulse_width = HSYNC_PULSE_WIDTH,
			
		.vsync_back_porch = VSYNC_BACK_PORCH,
		.vsync_front_porch = VSYNC_FRONT_PORCH,
		.vsync_pulse_width = VSYNC_PULSE_WIDTH,	
	},

		.flags.fb_in_psram = true,
#if CONFIG_EXAMPLE_DOUBLE_FB
		.flags.double_fb = true,
#else
		.flags.double_fb = false,
#endif 
		
	};
	ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(&panel_config, &panel_handle));

	ESP_LOGI(TAG, "Register event callbacks");
	esp_lcd_rgb_panel_event_callbacks_t cbs = {
		.on_vsync = example_on_vsync_event,
	};
	ESP_ERROR_CHECK(esp_lcd_rgb_panel_register_event_callbacks(panel_handle, &cbs, &disp_drv));

	ESP_LOGI(TAG, "Initialize RGB LCD panel");
	ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
	ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));


	
	// LIVELLO LVGL IN POI, DUNQUE CONFIGURO IL TOUCH
	ESP_LOGI(TAG, "Initialize LVGL library");
	lv_init();
	void *buf1 = NULL;
	void *buf2 = NULL;

	ESP_LOGI(TAG, "Allocate separate LVGL draw buffers from PSRAM");
	
	/*
	
	*/
	
#if CONFIG_EXAMPLE_DOUBLE_FB
	ESP_LOGI(TAG, "Use frame buffers as LVGL draw buffers");
	ESP_ERROR_CHECK(esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 2, &buf1, &buf2));
	// initialize LVGL draw buffers
	lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES);
#else
	gpio_set_level(GPIO_NUM_8, 1);
	buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), MALLOC_CAP_SPIRAM);
	assert(buf1);
	gpio_set_level(GPIO_NUM_8, 0);
	buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), MALLOC_CAP_SPIRAM);
	assert(buf2);
	// initialize LVGL draw buffers
	lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 100);
#endif
	
	
	ESP_LOGI(TAG, "Register display driver to LVGL");
	lv_disp_drv_init(&disp_drv);
	disp_drv.hor_res = EXAMPLE_LCD_H_RES;
	disp_drv.ver_res = EXAMPLE_LCD_V_RES;
	disp_drv.flush_cb = example_lvgl_flush_cb;
	disp_drv.draw_buf = &disp_buf;
	disp_drv.user_data = panel_handle;
#if CONFIG_EXAMPLE_DOUBLE_FB
	disp_drv.full_refresh = true; // the full_refresh mode can maintain the synchronization between the two frame buffers
#else
	disp_drv.full_refresh = false; 
#endif
	lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
	
	
	esp_lcd_touch_handle_t tp;

	/* Initialize touch */
	const esp_lcd_touch_config_t tp_cfg = {
		.x_max = EXAMPLE_LCD_H_RES,
		.y_max = EXAMPLE_LCD_V_RES,
		.rst_gpio_num = -1,
		.int_gpio_num = -1,
		.levels = {
		.reset = 0,
		.interrupt = 0,
	},
		.flags = {
		.swap_xy = 0,
		.mirror_x = 0,
		.mirror_y = 0,
	},
	};
	esp_lcd_panel_io_handle_t tp_io_handle = NULL;
	const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
	ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_NUM_0, &tp_io_config, &tp_io_handle));
	ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
	assert(tp);

	/* Add touch input (for selected screen) */
	const lvgl_port_touch_cfg_t touch_cfg = {
		.disp = disp,
		.handle = tp,
	};
	
	lvgl_port_add_touch(&touch_cfg);
	

	ESP_LOGI(TAG, "Install LVGL tick timer");
	// Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
	const esp_timer_create_args_t lvgl_tick_timer_args = {
		.callback = &increase_lvgl_tick,
		.name = "lvgl_tick"
	};
	esp_timer_handle_t lvgl_tick_timer = NULL;
	ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
	ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

	//ESP_LOGI(TAG, "Display LVGL Scatter Chart");
}


void lvgl_task(void *pvParameters) {
	for (;;) {
		// raise the task priority of LVGL and/or reduce the handler period can improve the performance
		vTaskDelay(pdMS_TO_TICKS(MS_BETWEEN_FRAMES));
		// The task running lv_timer_handler should have lower priority than that running `lv_tick_inc`
		lv_timer_handler();
	}
}
As you can see, i allocate the memory i need with heap_caps_malloc, when i'm not using double frame buffer, with this configuration, i can go at high fps and the screen movements seems smooth (even with 1024x600), as long as you change only a fer pixels at a time.

When i need to change the whole screen or i have large widgets where is needed to change a lot of pixels, the problems start to arise.
I doubt that i'm not using correctly the GDMA, or maybe LVGL is not using the GDMA when it accesses the memory.

A help to understand the whole mechanism would be really appreciated! Thank you for your time and your patience.

ESP_Sprite
Posts: 9757
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32S3 PSRAM Mhz

Postby ESP_Sprite » Wed Apr 12, 2023 12:41 am

The issue is that the PSRAM memory bandwidth arbiter is not very smart, and writing data from the CPU can impact the bandwidth to the PSRAM chip. You could try to set bounce_buffer_size_px in panel_config to e.g. EXAMPLE_LCD_H_RES*8. That does the main reading from PSRAM using the CPU, working around this issue.

MasterExploder
Posts: 26
Joined: Wed Feb 08, 2023 6:17 pm

Re: ESP32S3 PSRAM Mhz

Postby MasterExploder » Wed Apr 12, 2023 7:38 am

Thank you for your reply, i will test it in moments, i also read that only certain areas of external memery are accessible with GDMA, ()also, i don't understand why in the example code the memory allocated is

Code: Select all

EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t)
could you please explain me?

I read in the Technical reference manual that the GDMA can be set in burst mode (page 350 of esp32s3 TRM), but i don't see in the sdkconfig any option regarding this, maybe i have to do it "manually"? if so, what is the correct method to setup and use the GDMA?

p.s. using the bounce buffers seems so improve the performace, i also can set much more MHz on the "pclk_hz" field, but if i'm not wrong, i'm not using at all GDMA, because it needs to be configured, so maybe there is no need to allocate such memory in internal RAM.

Thank you for your help!

ESP_Sprite
Posts: 9757
Joined: Thu Nov 26, 2015 4:08 am

Re: ESP32S3 PSRAM Mhz

Postby ESP_Sprite » Thu Apr 13, 2023 2:25 am

MasterExploder wrote:
Wed Apr 12, 2023 7:38 am

Code: Select all

EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t)
could you please explain me?
Something with LVGL draw buffers... I'm afraid I don't know LVGL good enough to know the details.
I read in the Technical reference manual that the GDMA can be set in burst mode (page 350 of esp32s3 TRM), but i don't see in the sdkconfig any option regarding this, maybe i have to do it "manually"? if so, what is the correct method to setup and use the GDMA?
Browsing the GDMA driver, it seems burst mode is enabled automagically if sram_trans_align and psram_trans_align are set high enough. I think for psram a value of 64 enables this for sure, but I'm not 100% on the details.
p.s. using the bounce buffers seems so improve the performace, i also can set much more MHz on the "pclk_hz" field, but if i'm not wrong, i'm not using at all GDMA, because it needs to be configured, so maybe there is no need to allocate such memory in internal RAM.
What the bounce buffer does is allocate a buffer in internal RAM where the data is copied by the CPU from PSRAM, working around the psram arbiter quirks. GDMA is then used to DMA it to the LCD. In general, the ESP-LCD driver uses GDMA 'under the hood', so you don't need to set it up yourself.

MasterExploder
Posts: 26
Joined: Wed Feb 08, 2023 6:17 pm

Re: ESP32S3 PSRAM Mhz

Postby MasterExploder » Thu Apr 13, 2023 5:34 am

Interesting, much thanks, very appreciated.

One last thing: would It be useful do use bounce buffer in concomitance with double buffer in PSRam in your opinion? The FPS seems to remain the same but i don't understand why since it should be a little faster.

Thank you again for your help!!

MasterExploder
Posts: 26
Joined: Wed Feb 08, 2023 6:17 pm

Re: ESP32S3 PSRAM Mhz

Postby MasterExploder » Thu Apr 13, 2023 6:03 am

Also, is there any way to clock the psram to 120Mhz with the v5.0 ? i see that they added the possibility to do so in the 5.1 but if i try to work on master branch i have build problems. Maybe it is sufficient to change a bit in a register, without change the version of idf.

Who is online

Users browsing this forum: Google [Bot] and 289 guests