ESP32S3 PSRAM Mhz
-
- Posts: 26
- Joined: Wed Feb 08, 2023 6:17 pm
ESP32S3 PSRAM Mhz
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.
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.
-
- Posts: 9772
- Joined: Thu Nov 26, 2015 4:08 am
Re: ESP32S3 PSRAM Mhz
How are you testing those numbers?
-
- Posts: 26
- Joined: Wed Feb 08, 2023 6:17 pm
Re: ESP32S3 PSRAM Mhz
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?
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?
-
- Posts: 9772
- Joined: Thu Nov 26, 2015 4:08 am
Re: ESP32S3 PSRAM Mhz
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?
-
- Posts: 26
- Joined: Wed Feb 08, 2023 6:17 pm
Re: ESP32S3 PSRAM Mhz
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:
source:
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.
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);
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();
}
}
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.
-
- Posts: 9772
- Joined: Thu Nov 26, 2015 4:08 am
Re: ESP32S3 PSRAM Mhz
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.
-
- Posts: 26
- Joined: Wed Feb 08, 2023 6:17 pm
Re: ESP32S3 PSRAM Mhz
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
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!
Code: Select all
EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t)
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!
-
- Posts: 9772
- Joined: Thu Nov 26, 2015 4:08 am
Re: ESP32S3 PSRAM Mhz
Something with LVGL draw buffers... I'm afraid I don't know LVGL good enough to know the details.MasterExploder wrote: ↑Wed Apr 12, 2023 7:38 amcould you please explain me?Code: Select all
EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t)
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.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?
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.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.
-
- Posts: 26
- Joined: Wed Feb 08, 2023 6:17 pm
Re: ESP32S3 PSRAM Mhz
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!!
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!!
-
- Posts: 26
- Joined: Wed Feb 08, 2023 6:17 pm
Re: ESP32S3 PSRAM Mhz
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: MichaelS and 77 guests