diff options
| author | Your Name <you@example.com> | 2026-05-19 02:00:31 +0530 |
|---|---|---|
| committer | Your Name <you@example.com> | 2026-05-19 02:00:31 +0530 |
| commit | 9f7dd94029c8dc12117494548f5f32221a729307 (patch) | |
| tree | 0db4cf1f0e2cb5ad64cf9c7eb93085598a4722a2 | |
| parent | 58a0b5fd115d9687a1292e5e82e6b9fa8454b930 (diff) | |
Fix display rotation: use stride=480 for correct framebuffer addressing
The framebuffer was using s_width as row stride, but s_width changes
after rotation (320→480). This caused buffer overflows and black screen
in landscape mode. Now uses fixed stride=480 with 480*480*2 allocation.
| -rw-r--r-- | components/axs15231b/axs15231b.c | 66 |
1 files changed, 35 insertions, 31 deletions
diff --git a/components/axs15231b/axs15231b.c b/components/axs15231b/axs15231b.c index 77708dd..ac05ba7 100644 --- a/components/axs15231b/axs15231b.c +++ b/components/axs15231b/axs15231b.c | |||
| @@ -38,6 +38,7 @@ static uint16_t *s_fb = NULL; | |||
| 38 | static int s_width = AXS15231B_WIDTH; | 38 | static int s_width = AXS15231B_WIDTH; |
| 39 | static int s_height = AXS15231B_HEIGHT; | 39 | static int s_height = AXS15231B_HEIGHT; |
| 40 | static int s_rotation = 0; | 40 | static int s_rotation = 0; |
| 41 | static int s_stride = 480; | ||
| 41 | static uint8_t *s_swap_buf = NULL; | 42 | static uint8_t *s_swap_buf = NULL; |
| 42 | #define SWAP_BUF_PIXELS 2048 | 43 | #define SWAP_BUF_PIXELS 2048 |
| 43 | 44 | ||
| @@ -242,7 +243,7 @@ esp_err_t axs15231b_init(void) { | |||
| 242 | 243 | ||
| 243 | cs_init(); | 244 | cs_init(); |
| 244 | 245 | ||
| 245 | size_t fb_size = (size_t)s_width * s_height * 2; | 246 | size_t fb_size = (size_t)480 * 480 * 2; |
| 246 | s_fb = heap_caps_malloc(fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); | 247 | s_fb = heap_caps_malloc(fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); |
| 247 | if (!s_fb) { | 248 | if (!s_fb) { |
| 248 | ESP_LOGE(TAG, "Failed to allocate framebuffer (%zu bytes)", fb_size); | 249 | ESP_LOGE(TAG, "Failed to allocate framebuffer (%zu bytes)", fb_size); |
| @@ -297,9 +298,10 @@ void axs15231b_set_backlight(bool on) { | |||
| 297 | } | 298 | } |
| 298 | 299 | ||
| 299 | void axs15231b_fill_screen(uint16_t color) { | 300 | void axs15231b_fill_screen(uint16_t color) { |
| 300 | uint32_t pixels = (uint32_t)s_width * s_height; | 301 | for (int row = 0; row < s_height; row++) { |
| 301 | for (uint32_t i = 0; i < pixels; i++) { | 302 | for (int col = 0; col < s_width; col++) { |
| 302 | s_fb[i] = color; | 303 | s_fb[row * s_stride + col] = color; |
| 304 | } | ||
| 303 | } | 305 | } |
| 304 | } | 306 | } |
| 305 | 307 | ||
| @@ -307,7 +309,7 @@ void axs15231b_fill_rect(int x, int y, int w, int h, uint16_t color) { | |||
| 307 | if (x < 0 || y < 0 || x + w > s_width || y + h > s_height) return; | 309 | if (x < 0 || y < 0 || x + w > s_width || y + h > s_height) return; |
| 308 | for (int row = y; row < y + h; row++) { | 310 | for (int row = y; row < y + h; row++) { |
| 309 | for (int col = x; col < x + w; col++) { | 311 | for (int col = x; col < x + w; col++) { |
| 310 | s_fb[row * s_width + col] = color; | 312 | s_fb[row * s_stride + col] = color; |
| 311 | } | 313 | } |
| 312 | } | 314 | } |
| 313 | } | 315 | } |
| @@ -319,36 +321,38 @@ void axs15231b_flush(void) { | |||
| 319 | qspi_write_cmd_d16d16(RASET, 0, s_height - 1); | 321 | qspi_write_cmd_d16d16(RASET, 0, s_height - 1); |
| 320 | qspi_write_command(RAMWR); | 322 | qspi_write_command(RAMWR); |
| 321 | 323 | ||
| 322 | int total_pixels = s_width * s_height; | ||
| 323 | int pixel_offset = 0; | ||
| 324 | bool first = true; | 324 | bool first = true; |
| 325 | 325 | ||
| 326 | cs_low(); | 326 | cs_low(); |
| 327 | while (pixel_offset < total_pixels) { | 327 | for (int row = 0; row < s_height; row++) { |
| 328 | int remaining = total_pixels - pixel_offset; | 328 | int chunk_remaining = s_width; |
| 329 | int chunk_pixels = remaining < SWAP_BUF_PIXELS ? remaining : SWAP_BUF_PIXELS; | 329 | int col_offset = 0; |
| 330 | int chunk_bytes = chunk_pixels * 2; | 330 | while (chunk_remaining > 0) { |
| 331 | 331 | int chunk_pixels = chunk_remaining < SWAP_BUF_PIXELS ? chunk_remaining : SWAP_BUF_PIXELS; | |
| 332 | uint8_t *src = (uint8_t *)(s_fb + pixel_offset); | 332 | int chunk_bytes = chunk_pixels * 2; |
| 333 | for (int i = 0; i < chunk_bytes; i += 2) { | 333 | |
| 334 | s_swap_buf[i] = src[i + 1]; | 334 | uint8_t *src = (uint8_t *)(s_fb + row * s_stride + col_offset); |
| 335 | s_swap_buf[i + 1] = src[i]; | 335 | for (int i = 0; i < chunk_bytes; i += 2) { |
| 336 | } | 336 | s_swap_buf[i] = src[i + 1]; |
| 337 | 337 | s_swap_buf[i + 1] = src[i]; | |
| 338 | spi_transaction_ext_t t = {0}; | 338 | } |
| 339 | if (first) { | 339 | |
| 340 | t.base.flags = SPI_TRANS_MODE_QIO; | 340 | spi_transaction_ext_t t = {0}; |
| 341 | t.base.cmd = QSPI_CMD_DATA_WRITE; | 341 | if (first) { |
| 342 | t.base.addr = QSPI_DATA_ADDR; | 342 | t.base.flags = SPI_TRANS_MODE_QIO; |
| 343 | first = false; | 343 | t.base.cmd = QSPI_CMD_DATA_WRITE; |
| 344 | } else { | 344 | t.base.addr = QSPI_DATA_ADDR; |
| 345 | t.base.flags = SPI_TRANS_MODE_QIO | SPI_TRANS_VARIABLE_CMD | | 345 | first = false; |
| 346 | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY; | 346 | } else { |
| 347 | t.base.flags = SPI_TRANS_MODE_QIO | SPI_TRANS_VARIABLE_CMD | | ||
| 348 | SPI_TRANS_VARIABLE_ADDR | SPI_TRANS_VARIABLE_DUMMY; | ||
| 349 | } | ||
| 350 | t.base.tx_buffer = s_swap_buf; | ||
| 351 | t.base.length = chunk_pixels * 16; | ||
| 352 | spi_device_polling_transmit(s_spi, (spi_transaction_t *)&t); | ||
| 353 | col_offset += chunk_pixels; | ||
| 354 | chunk_remaining -= chunk_pixels; | ||
| 347 | } | 355 | } |
| 348 | t.base.tx_buffer = s_swap_buf; | ||
| 349 | t.base.length = chunk_pixels * 16; | ||
| 350 | spi_device_polling_transmit(s_spi, (spi_transaction_t *)&t); | ||
| 351 | pixel_offset += chunk_pixels; | ||
| 352 | } | 356 | } |
| 353 | cs_high(); | 357 | cs_high(); |
| 354 | } | 358 | } |