If I understood right, color map array is divided by splitting x, y coordinates.
setting the displays up so one is on top in a vertical arrangement is going to be far easier to do because you can simply split the buffer instead of having to iterate over it and moving bytes into 2 new buffersβ¦
The buffers are single dimension arrays so think of the data as being all on a single line.
as an example
say you have 3 rows of 10 pixels in each row. each pixel contains 2 bytes of color data.
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
The data is not arranged in the above kind of a fashion and instead is arranged like this
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
when you have the displays side by side as say you need to have 5 pixels written to the left display and 5 pixels written to the right display view it like this.
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
the | is where the data needs to be split to send to the right and to the left.
Now when you look at it like this
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
You cannot simply βcutβ the buffer. You have to separate the data into 2 new buffers in order to do it.
where as if they are arranged vertically and say you have to write 15 pixels to the top display and 15 pixels to the bottom display.
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
255, 255, 255, 255, 255, 255, 255, 255, 255, 255| 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
you literally split the buffer, no need to iterate over it. It becomes a simple math problem. The area that is being updated gets passed to the flush callback by LVGL. This is an lv_area_t structure and that structure contains the upper left corner and the lower right corner of the area being changed.
if (area.y1 < top_display_height) {
if (area.y2 < top_display_height) {
// send entire buffer to top display
} else {
// buffer needs to be split
uint16_t top_display_pixel_count = (area.x2 - area.x1 + 1) * (top_display_height - area.y1 + 1);
uint16_t bottom_display_pixel_count = (area.x2 - area.x1 + 1) * (area.y2 - top_display_height + 1);
uint16_t top_display_buf_size = top_display_pixel_count * sizeof(lv_color_t);
uint16_t bottom_display_buf_size = bottom_display_pixel_count * sizeof(lv_color_t);
// set the top display to be written to using
// area.x1, area.y1
// area.x2, top_display_height
// and the bottom display using
// area.x1, 0
// area.x2, area.y2 - top_display_height
// when writing the data there is normally a function you call to do that.
// pass the following to the function for the top display
// top_display_buf_size, buf
// and for the bottom display
// bottom_display_buf_size, buf + top_display_buf_size
}
} else {
// send entire buffer to bottom display
}
the above is pseudo code and is not working. It is for example only.
Another try to explain
d1 is left display pixel data
d2 is right display pixel data
a00 to a27 is display/pixel data generated by lvgl (color_map).
So a00 to a02 belongs to the left display
and a03 to a06 belongs to the right display (just for one display line)...
d1 d1 d1 d1 d1 d1 d1 d1 d2 d2 d2 d2 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 d1 d1 d1 d2 d2 d2 d2 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 d1 d1 d1 d2 d2 d2 d2 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 a00 a01 a02 a03 a04 a05 a06 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 a07 a08 a09 a10 a11 a12 a13 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 a14 a15 a16 a17 a18 a19 a20 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 a21 a22 a23 a24 a25 a26 a27 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 d1 d1 d1 d2 d2 d2 d2 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 d1 d1 d1 d2 d2 d2 d2 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 d1 d1 d1 d2 d2 d2 d2 d2 d2 d2 d2 d2
d1 d1 d1 d1 d1 d1 d1 d1 d2 d2 d2 d2 d2 d2 d2 d2 d2
What Marian_M wantβs to say, splitting would be easier in the following case.
d1 is top display pixel data
d2 is bottom display pixel data
a00 to a27 is display/pixel data generated by lvgl (color_map array)
a00 to a06 belongs to the top display
and a07 to a27 belongs to the bottom display (only one split necessary).
d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1
d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1
d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1
d1 d1 d1 d1 d1 a00 a01 a02 a03 a04 a05 a06 d1 d1 d1 d1 d1
d2 d2 d2 d2 d2 a07 a08 a09 a10 a11 a12 a13 d2 d2 d2 d2 d2
d2 d2 d2 d2 d2 a14 a15 a16 a17 a18 a19 a20 d2 d2 d2 d2 d2
d2 d2 d2 d2 d2 a21 a22 a23 a24 a25 a26 a27 d2 d2 d2 d2 d2
d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2
d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2
d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2
d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2 d2
Here is a flush function written in Python. This is for writing to a single display.
def flush(self, disp_drv, area, color_p):
# ============ tells display where to write the buffer to ================
# Column addresses
self.send_cmd(0x2A)
self.word_trans_data[0] = (area.x1 >> 8) & 0xFF
self.word_trans_data[1] = area.x1 & 0xFF
self.word_trans_data[2] = (area.x2 >> 8) & 0xFF
self.word_trans_data[3] = area.x2 & 0xFF
self.send_trans_word()
# Page addresses
self.send_cmd(0x2B)
self.word_trans_data[0] = (area.y1 >> 8) & 0xFF
self.word_trans_data[1] = area.y1 & 0xFF
self.word_trans_data[2] = (area.y2 >> 8) & 0xFF
self.word_trans_data[3] = area.y2 & 0xFF
self.send_trans_word()
# ==========================================
# ======== writing the data to the display ============
self.send_cmd(0x2C)
size = (area.x2 - area.x1 + 1) * (area.y2 - area.y1 + 1)
# gets a pointer to the buffer
data_view = color_p.__dereference__(size * lv.color_t.__SIZE__)
self.send_data_dma(data_view)
# ===========================================
and adapted to write to 2 displays arranged vertically
def flush(self, disp_drv, area, color_p):
# lets say the displays are 128 x 128 in size
display_width = 128
display_height = 128
x1 = area.x1
y1 = area.y1
x2 = area.x2
y2 = area.y2
if y2 <= display_height:
# all data is going to fit on the top display so write
# the entire buffer to the top display
# ============ tells display where to write the buffer to ================
# Column addresses
self.send_cmd_top(0x2A)
self.word_trans_data_top[0] = (x1 >> 8) & 0xFF
self.word_trans_data_top[1] = x1 & 0xFF
self.word_trans_data_top[2] = (x2 >> 8) & 0xFF
self.word_trans_data_top[3] = x2 & 0xFF
self.send_trans_word_top()
# Page addresses
self.send_cmd_top(0x2B)
self.word_trans_data_top[0] = (y1 >> 8) & 0xFF
self.word_trans_data_top[1] = y1 & 0xFF
self.word_trans_data_top[2] = (y2 >> 8) & 0xFF
self.word_trans_data_top[3] = y2 & 0xFF
self.send_trans_word_top()
# ==========================================
# ======== writing the data to the display ============
self.send_cmd_top(0x2C)
size = (x2 - x1 + 1) * (y2 - y1 + 1)
# gets a pointer to the buffer
data_view = color_p.__dereference__(size * lv.color_t.__SIZE__)
self.send_data_dma_top(data_view)
# ===========================================
elif y2 > display_height:
# all data is going to go to the bottom display
# we have to modify the y1 and y2 to reposition where the data
# is going to be written to on the display
y1 -= display_height
y2 -= display_height
# ============ tells display where to write the buffer to ================
# Column addresses
self.send_cmd_bottom(0x2A)
self.word_trans_data_bottom[0] = (x1 >> 8) & 0xFF
self.word_trans_data_bottom[1] = x1 & 0xFF
self.word_trans_data_bottom[2] = (x2 >> 8) & 0xFF
self.word_trans_data_bottom[3] = x2 & 0xFF
self.send_trans_word_bottom()
# Page addresses
self.send_cmd_bottom(0x2B)
self.word_trans_data_bottom[0] = (y1 >> 8) & 0xFF
self.word_trans_data_bottom[1] = y1 & 0xFF
self.word_trans_data_bottom[2] = (y2 >> 8) & 0xFF
self.word_trans_data_bottom[3] = y2 & 0xFF
self.send_trans_word_bottom()
# ==========================================
# ======== writing the data to the display ============
self.send_cmd_bottom(0x2C)
size = (x2 - x1 + 1) * (y2 - y1 + 1)
# gets a pointer to the buffer
data_view = color_p.__dereference__(size * lv.color_t.__SIZE__)
self.send_data_dma_bottom(data_view)
# ===========================================
else:
# we have to split the data. so lets start off with modifying the heights.
y3 = 0
y4 = y2 - display_height
y2 = display_height
# top display writing of the data
# ============ tells display where to write the buffer to ================
# Column addresses
self.send_cmd_top(0x2A)
self.word_trans_data_top[0] = (x1 >> 8) & 0xFF
self.word_trans_data_top[1] = x1 & 0xFF
self.word_trans_data_top[2] = (x2 >> 8) & 0xFF
self.word_trans_data_top[3] = x2 & 0xFF
self.send_trans_word_top()
# Page addresses
self.send_cmd_top(0x2B)
self.word_trans_data_top[0] = (y1 >> 8) & 0xFF
self.word_trans_data_top[1] = y1 & 0xFF
self.word_trans_data_top[2] = (y2 >> 8) & 0xFF
self.word_trans_data_top[3] = y2 & 0xFF
self.send_trans_word_top()
# ==========================================
# ======== writing the data to the display ============
self.send_cmd_top(0x2C)
top_size = (x2 - x1 + 1) * (y2 - y1 + 1)
# gets a pointer to the buffer
data_view = color_p.__dereference__(top_size * lv.color_t.__SIZE__)
self.send_data_dma_top(data_view)
# ===========================================
# and now the botom display
# ============ tells display where to write the buffer to ================
# Column addresses
self.send_cmd_bottom(0x2A)
self.word_trans_data_bottom[0] = (x1 >> 8) & 0xFF
self.word_trans_data_bottom[1] = x1 & 0xFF
self.word_trans_data_bottom[2] = (x2 >> 8) & 0xFF
self.word_trans_data_bottom[3] = x2 & 0xFF
self.send_trans_word_bottom()
# Page addresses
self.send_cmd_bottom(0x2B)
self.word_trans_data_bottom[0] = (y3 >> 8) & 0xFF
self.word_trans_data_bottom[1] = y3 & 0xFF
self.word_trans_data_bottom[2] = (y4 >> 8) & 0xFF
self.word_trans_data_bottom[3] = y4 & 0xFF
self.send_trans_word_bottom()
# ==========================================
# ======== writing the data to the display ============
self.send_cmd_bottom(0x2C)
# we make a pointer of the entire buffer and then split it
# where we need it to be split
total_size = (x2 - x1 + 1) * (area.y2 - area.y1 + 1)
# gets a pointer to the buffer
data_view = color_p.__dereference__(total_size * lv.color_t.__SIZE__)
# we use the top size as the mechanism to cut the buffer
self.send_data_dma_bottom(data_view[top_size * lv.color_t.__SIZE__:])
# ===========================================
@robekras is example is a great visual. I am going to toss in some ascii art to beautify it.
DISPLAY 1 DISPLAY 2
βββββββββββββββββββββββ¦ββββββββββββββββββββββ
β 0 0 0 0 0 0 0 0 0 0 β 0 0 0 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 1 1 1 β 1 1 1 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 1 1 1 β 1 1 1 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 1 1 1 β 1 1 1 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 0 0 0 β 0 0 0 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 0 0 0 β 0 0 0 0 0 0 0 0 0 0 β
βββββββββββββββββββββββ©ββββββββββββββββββββββ
The 1βs are the pixels being written to
The data is going to look like this
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
every 2 items in the array represent a single pixel of the display. How do you sort that data stream into 2 streams, one that gets written to DISPLAY 1 and the other to DISPLAY 2?
[]'s are DISPLAY 1 and {}'s are DISPLAY 2
[255, 255, 255, 255, 255, 255], {255, 255, 255, 255, 255, 255}, [255, 255, 255, 255, 255, 255], {255, 255, 255, 255, 255, 255}, [255, 255, 255, 255, 255, 255], {255, 255, 255, 255, 255, 255}
Now if they are arranged vertically
DISPLAY 1
βββββββββββββββββββββββ
β 0 0 0 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 0 0 0 β
β 0 0 0 1 1 1 0 0 0 0 β
β 0 0 0 1 1 1 0 0 0 0 β
β 0 0 0 1 1 1 0 0 0 0 β
β ββββββββββββββββββββββ£
β 0 0 0 1 1 1 0 0 0 0 β
β 0 0 0 1 1 1 0 0 0 0 β
β 0 0 0 1 1 1 0 0 0 0 β
β 0 0 0 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 0 0 0 β
β 0 0 0 0 0 0 0 0 0 0 β
βββββββββββββββββββββββ
DISPLAY 2
The 1βs are the pixels being written to
same data format as the first example
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
but when we separate the data watch what happens
[]'s are DISPLAY 1 and {}'s are DISPLAY 2
[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
which one is easier to sort out?
Now to make things a bit more interesting the shape of the data being written is not a constant. All that matters is the data being written fits into the buffer so the visual representation of the data could change.
If the buffer is able to hold the data for say 12 pixels the buffer is going to have a length of 24 because there are 2 bytes for each pixel. the buffer could represent data being written that is 2 pixels wide by 6 pixels high, or it could be 6 pixels wide by 2 pixels high. so long as the data being written fits into the buffer it doesnβt matter the βshapeβ the data visually represents.
I think this is about the best that can be done to explain what needs to be done. itβs hard to visualize 2 dimensional display data being stored in a single dimension array. If the data was stored in a 2 dimension array it would be easier but there would need to be additional work done to send that data to the display which would slow things down.