Description
I try to port LVGL9.3 to my AT32F403AVGT7 development board which has an 0.96’’ OLED display screen and the screen has a SSD1306 driver IC.
But i have not achieved success until now. I post two xxx.c files: lv_port_disp_template.c and ssd1306.c. I want to know whether this function(static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map)) is correct or not.
Code to reproduce
//lv_port_disp_template.c
#ifndef MY_DISP_HOR_RES
#define MY_DISP_HOR_RES 128
#endif
#ifndef MY_DISP_VER_RES
#define MY_DISP_VER_RES 64
#endif
void lv_port_disp_init(void)
{
/*-------------------------
* Initialize your display
* -----------------------*/
disp_init();
/*------------------------------------
* Create a display and set a flush_cb
* -----------------------------------*/
lv_display_t * disp = lv_display_create(MY_DISP_HOR_RES, MY_DISP_VER_RES);
lv_display_set_color_format(disp, LV_COLOR_FORMAT_I1);
lv_display_set_flush_cb(disp, disp_flush);
LV_ATTRIBUTE_MEM_ALIGN
static uint8_t buf_1[MY_DISP_HOR_RES * MY_DISP_VER_RES / 8 + 8];
lv_display_set_buffers(disp, buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_FULL);
}
/**********************
* STATIC FUNCTIONS
**********************/
/*Initialize your display and the required peripherals.*/
static void disp_init(void)
{
ssd1306_init();
}
static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t * px_map)
{
px_map += 8;
lv_draw_sw_i1_convert_to_vtiled(
px_map,
(MY_DISP_HOR_RES * MY_DISP_VER_RES) / 8,
MY_DISP_HOR_RES,
MY_DISP_VER_RES,
ssd1306_buffer,
sizeof(ssd1306_buffer),
false
);
ssd1306_flush();
lv_display_flush_ready(disp_drv);
}
//ssd1306.c
uint8_t ssd1306_buffer[SSD1306_WIDTH * SSD1306_HEIGHT / 8] = {0};
static void send_cmd(uint8_t code) {
// Function to send command to SSD1306
// This function should be implemented based on your specific hardware interface
i2c_start_generate(I2C1);
while(i2c_flag_get(I2C1,I2C_STARTF_FLAG)!= SET);
i2c_7bit_address_send(I2C1,SSD1306_IIC_ADDR,I2C_DIRECTION_TRANSMIT);
while(i2c_flag_get(I2C1,I2C_ADDR7F_FLAG)!= SET);
i2c_flag_clear(I2C1,I2C_ADDR7F_FLAG);
i2c_data_send(I2C1,0x00);
i2c_data_send(I2C1,code);
while(i2c_flag_get(I2C1,I2C_TDC_FLAG)!= SET);
i2c_stop_generate(I2C1);
}
static void send_data(uint8_t data) {
// Function to send data to SSD1306
// This function should be implemented based on your specific hardware interface
i2c_start_generate(I2C1);
while(i2c_flag_get(I2C1,I2C_STARTF_FLAG)!= SET);
i2c_7bit_address_send(I2C1,SSD1306_IIC_ADDR,I2C_DIRECTION_TRANSMIT);
while(i2c_flag_get(I2C1,I2C_ADDR7F_FLAG)!= SET);
i2c_flag_clear(I2C1,I2C_ADDR7F_FLAG);
i2c_data_send(I2C1,0x40);
i2c_data_send(I2C1,data);
while(i2c_flag_get(I2C1,I2C_TDC_FLAG)!= SET);
i2c_stop_generate(I2C1);
}
void ssd1306_flush(void) {
// Send the display buffer to the SSD1306
for (uint8_t page = 0; page < 8; page++) {
send_cmd(0xB0 + page); // Set page address
send_cmd(0x00); // Set lower column address
send_cmd(0x10); // Set higher column address
for (uint16_t col = 0; col < SSD1306_WIDTH; col++) {
send_data(ssd1306_buffer[col + (page * SSD1306_WIDTH)]);
}
}
}
void ssd1306_clear(void) {
// Clear the display buffer
for (uint16_t i = 0; i < sizeof(ssd1306_buffer); i++) {
ssd1306_buffer[i] = 0x00;
}
}
void ssd1306_draw_pixel(uint8_t x, uint8_t y, uint8_t color) {
if (x >= SSD1306_WIDTH || y >= SSD1306_HEIGHT) {
return; // Out of bounds
}
if (color) {
ssd1306_buffer[x + (y / 8) * SSD1306_WIDTH] |= (1 << (y % 8));
} else {
ssd1306_buffer[x + (y / 8) * SSD1306_WIDTH] &= ~(1 << (y % 8));
}
}
void ssd1306_init(void) {
// Initialize the SSD1306 display
send_cmd(0xAE); // Display off
send_cmd(0xD5); // Set display clock divide ratio/oscillator frequency
send_cmd(0x80); // Set divide ratio
send_cmd(0xA8); // Set multiplex ratio
send_cmd(0x3F); // 1/64 duty
send_cmd(0xD3); // Set display offset
send_cmd(0x00); // No offset
send_cmd(0x40); // Set start line to 0
send_cmd(0x8D); // Charge pump setting
send_cmd(0x14); // Enable charge pump
send_cmd(0x20); // Memory addressing mode
send_cmd(0x02); // Page addressing mode
send_cmd(0xA1); // Segment remap (column address 127 is mapped to SEG0)
send_cmd(0xC8); // COM output scan direction (remap mode)
send_cmd(0xDA); // Set COM pins hardware configuration
send_cmd(0x12);
send_cmd(0x81); // Contrast control
send_cmd(0xCF);
send_cmd(0xD9); // Pre-charge period
send_cmd(0xF1);
send_cmd(0xDB); // VCOMH deselect level
send_cmd(0x30);
send_cmd(0xA4); // Entire display ON (resume to RAM content display)
send_cmd(0xA6); // Normal display (not inverted)
send_cmd(0xAF); // Display ON
ssd1306_clear();
ssd1306_flush();
}