ports/stm32: Enable DSI display support.

This commit is contained in:
iabdalkader 2023-09-29 20:57:52 +02:00
parent 6c63368297
commit 55dfec4f06
6 changed files with 363 additions and 70 deletions

View File

@ -376,6 +376,15 @@ void SystemClock_Config(void)
PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PLL2;
#endif
#if defined(DSI)
PeriphClkInitStruct.PeriphClockSelection |= RCC_PERIPHCLK_DSI;
#if defined(OMV_OSC_DSI_CLKSOURCE)
PeriphClkInitStruct.DsiClockSelection = OMV_OSC_DSI_CLKSOURCE;
#else
PeriphClkInitStruct.DsiClockSelection = RCC_DSICLKSOURCE_PHY;
#endif // defined(OMV_OSC_DSI_CLKSOURCE)
#endif // defined(DSI)
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
// Initialization Error
__fatal_error("HAL_RCCEx_PeriphCLKConfig");

View File

@ -11,6 +11,7 @@ stm32h7xx_hal_adc.c\
stm32h7xx_hal_adc_ex.c\
stm32h7xx_hal_dac.c\
stm32h7xx_hal_dac_ex.c\
stm32h7xx_hal_dsi.c\
stm32h7xx_hal.c\
stm32h7xx_hal_cortex.c\
stm32h7xx_hal_crc.c\

View File

@ -185,6 +185,72 @@ STATIC mp_obj_t py_display_write(uint n_args, const mp_obj_t *args, mp_map_t *kw
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_write_obj, 2, py_display_write);
#ifdef OMV_DSI_DISPLAY_CONTROLLER
STATIC mp_obj_t py_display_dsi_write(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_cmd, ARG_args, ARG_dcs };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_cmd, MP_ARG_INT | MP_ARG_REQUIRED },
{ MP_QSTR_args, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_dcs, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_bool = false } },
};
// Parse args.
py_display_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
py_display_p_t *display_p = (py_display_p_t *) MP_OBJ_TYPE_GET_SLOT(self->base.type, protocol);
if (display_p->dsi_write == NULL) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected a DSI display controller"));
} else if (args[ARG_args].u_obj == mp_const_none) {
display_p->dsi_write(self, args[ARG_cmd].u_int, NULL, 0, args[ARG_dcs].u_bool);
} else if (mp_obj_is_int(args[ARG_args].u_obj)) {
uint8_t arg = mp_obj_get_int(args[ARG_args].u_obj);
display_p->dsi_write(self, args[ARG_cmd].u_int, &arg, 1, args[ARG_dcs].u_bool);
} else {
mp_buffer_info_t rbuf;
mp_get_buffer_raise(args[ARG_args].u_obj, &rbuf, MP_BUFFER_READ);
display_p->dsi_write(self, args[ARG_cmd].u_int, rbuf.buf, rbuf.len, args[ARG_dcs].u_bool);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_dsi_write_obj, 1, py_display_dsi_write);
STATIC mp_obj_t py_display_dsi_read(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_cmd, ARG_len, ARG_args, ARG_dcs };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_cmd, MP_ARG_INT | MP_ARG_REQUIRED },
{ MP_QSTR_len, MP_ARG_INT | MP_ARG_REQUIRED },
{ MP_QSTR_args, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
{ MP_QSTR_dcs, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_bool = false } },
};
// Parse args.
py_display_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
py_display_p_t *display_p = (py_display_p_t *) MP_OBJ_TYPE_GET_SLOT(self->base.type, protocol);
mp_obj_array_t *wbuf = MP_OBJ_TO_PTR(mp_obj_new_bytearray_by_ref(args[ARG_len].u_int,
m_new(byte, args[ARG_len].u_int)));
if (display_p->dsi_read == NULL) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Expected a DSI display controller"));
} else if (args[ARG_args].u_obj == mp_const_none) {
display_p->dsi_read(self, args[ARG_cmd].u_int, NULL, 0, wbuf->items, wbuf->len, args[ARG_dcs].u_bool);
} else if (mp_obj_is_int(args[ARG_args].u_obj)) {
uint8_t arg = mp_obj_get_int(args[ARG_args].u_obj);
display_p->dsi_read(self, args[ARG_cmd].u_int, &arg, 1, wbuf->items, wbuf->len, args[ARG_dcs].u_bool);
} else {
mp_buffer_info_t rbuf;
mp_get_buffer_raise(args[ARG_args].u_obj, &rbuf, MP_BUFFER_READ);
display_p->dsi_read(self, args[ARG_cmd].u_int, rbuf.buf, rbuf.len,
wbuf->items, wbuf->len, args[ARG_dcs].u_bool);
}
return MP_OBJ_FROM_PTR(wbuf);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_display_dsi_read_obj, 1, py_display_dsi_read);
#endif
STATIC const mp_rom_map_elem_t py_display_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_display) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&py_display_deinit_obj) },
@ -198,6 +264,10 @@ STATIC const mp_rom_map_elem_t py_display_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&py_display_clear_obj) },
{ MP_ROM_QSTR(MP_QSTR_backlight), MP_ROM_PTR(&py_display_backlight_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&py_display_write_obj) },
#ifdef OMV_DSI_DISPLAY_CONTROLLER
{ MP_ROM_QSTR(MP_QSTR_dsi_write), MP_ROM_PTR(&py_display_dsi_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_dsi_read), MP_ROM_PTR(&py_display_dsi_read_obj) },
#endif
};
MP_DEFINE_CONST_DICT(py_display_locals_dict, py_display_locals_dict_table);
@ -242,5 +312,9 @@ const mp_obj_module_t display_module = {
.globals = (mp_obj_t) &globals_dict,
};
MP_REGISTER_MODULE(MP_QSTR_display, display_module);
#ifdef MP_REGISTER_EXTENSIBLE_MODULE
MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_display, display_module);
#else
MP_REGISTER_MODULE(MP_QSTR_udisplay, display_module);
#endif
#endif // MICROPY_PY_DISPLAY

View File

@ -41,6 +41,7 @@ typedef enum {
typedef struct _py_display_obj_t {
mp_obj_base_t base;
uint32_t vcid;
uint32_t width;
uint32_t height;
uint32_t framesize;
@ -49,6 +50,7 @@ typedef struct _py_display_obj_t {
bool bgr;
bool byte_swap;
bool display_on;
mp_obj_t controller;
#if defined(OMV_SPI_DISPLAY_CONTROLLER)
omv_spi_t spi_bus;
bool spi_tx_running;
@ -68,6 +70,11 @@ typedef struct _py_display_p_t {
float x_scale, float y_scale, rectangle_t *roi, int rgb_channel, int alpha,
const uint16_t *color_palette, const uint8_t *alpha_palette, image_hint_t hint);
void (*set_backlight) (py_display_obj_t *self, uint32_t intensity);
#ifdef OMV_DSI_DISPLAY_CONTROLLER
// To be implemented by MIPI DSI controllers.
int (*dsi_write) (py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, bool dcs);
int (*dsi_read) (py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, uint8_t *buf, size_t len, bool dcs);
#endif
} py_display_p_t;
extern const mp_obj_type_t py_spi_display_type;

View File

@ -6,11 +6,13 @@
*
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* LTDC display Python module.
* LTDC/DSI display Python module.
*/
#include "omv_boardconfig.h"
#if MICROPY_PY_DISPLAY && defined(OMV_RGB_DISPLAY_CONTROLLER)
#if MICROPY_PY_DISPLAY && \
(defined(OMV_RGB_DISPLAY_CONTROLLER) || \
defined(OMV_DSI_DISPLAY_CONTROLLER))
#include "py/obj.h"
#include "py/runtime.h"
@ -21,11 +23,15 @@
#include "omv_gpio.h"
#include "py_display.h"
#if defined(OMV_RGB_DISPLAY_BL_PIN)
#if defined(OMV_DSI_DISPLAY_BL_PIN)
#define OMV_DISPLAY_BL_PIN OMV_DSI_DISPLAY_BL_PIN
#elif defined(OMV_RGB_DISPLAY_BL_PIN)
#define OMV_DISPLAY_BL_PIN OMV_RGB_DISPLAY_BL_PIN
#endif
#if defined(OMV_RGB_DISPLAY_DISP_PIN)
#if defined(OMV_DSI_DISPLAY_DISP_PIN)
#define OMV_DISPLAY_DISP_PIN OMV_DSI_DISPLAY_DISP_PIN
#elif defined(OMV_RGB_DISPLAY_DISP_PIN)
#define OMV_DISPLAY_DISP_PIN OMV_RGB_DISPLAY_DISP_PIN
#endif
@ -46,6 +52,9 @@ typedef struct display_mode {
typedef struct _display_state {
py_display_obj_t *self;
LTDC_HandleTypeDef hltdc;
#ifdef OMV_DSI_DISPLAY_CONTROLLER
DSI_HandleTypeDef hdsi;
#endif
#ifdef OMV_DISPLAY_BL_TIM
TIM_HandleTypeDef htim;
#endif
@ -151,6 +160,12 @@ void LTDC_IRQHandler() {
HAL_LTDC_IRQHandler(&display.hltdc);
}
#ifdef OMV_DSI_DISPLAY_CONTROLLER
void DSI_IRQHandler(void) {
HAL_DSI_IRQHandler(&display.hdsi);
}
#endif
static void pll_config(int framesize, int refresh) {
uint32_t pixel_clock = (display_modes[framesize].pixel_clock * refresh) / 60;
@ -209,6 +224,97 @@ static void pll_config(int framesize, int refresh) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unable to initialize LTDC PLL!"));
}
#ifdef OMV_DSI_DISPLAY_CONTROLLER
static void dsi_init(py_display_obj_t *self) {
const display_mode_t *dm = &display_modes[self->framesize];
DSI_PLLInitTypeDef dsi_pllinit;
dsi_pllinit.PLLNDIV = 125;
dsi_pllinit.PLLIDF = DSI_PLL_IN_DIV4;
dsi_pllinit.PLLODF = DSI_PLL_OUT_DIV1;
uint32_t LANE_BYTE_CLOCK = 62500;
display.hdsi.Instance = DSI;
display.hdsi.Init.NumberOfLanes = DSI_TWO_DATA_LANES;
display.hdsi.Init.TXEscapeCkdiv = 3;
display.hdsi.Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE;
HAL_DSI_Init(&display.hdsi, &dsi_pllinit);
#if OMV_DSI_DISPLAY_TE_ENABLE
DSI_CmdCfgTypeDef dsi_cmd;
dsi_cmd.VirtualChannelID = self->vcid;
dsi_cmd.HSPolarity = DSI_HSYNC_ACTIVE_LOW;
dsi_cmd.VSPolarity = DSI_VSYNC_ACTIVE_LOW;
dsi_cmd.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
dsi_cmd.ColorCoding = DSI_RGB565;
dsi_cmd.CommandSize = 0xFFFFU;
dsi_cmd.TearingEffectSource = DSI_TE_DSILINK;
dsi_cmd.TearingEffectPolarity = DSI_TE_RISING_EDGE;
dsi_cmd.VSyncPol = DSI_VSYNC_FALLING;
dsi_cmd.AutomaticRefresh = DSI_AR_DISABLE;
dsi_cmd.TEAcknowledgeRequest = DSI_TE_ACKNOWLEDGE_ENABLE;
HAL_DSI_ConfigAdaptedCommandMode(&display.hdsi, &dsi_cmd);
#endif
// Configure DSI PHY HS2LP and LP2HS timings
DSI_PHY_TimerTypeDef dsi_phyinit;
dsi_phyinit.ClockLaneHS2LPTime = 35;
dsi_phyinit.ClockLaneLP2HSTime = 35;
dsi_phyinit.DataLaneHS2LPTime = 35;
dsi_phyinit.DataLaneLP2HSTime = 35;
dsi_phyinit.DataLaneMaxReadTime = 0;
dsi_phyinit.StopWaitTime = 10;
HAL_DSI_ConfigPhyTimer(&display.hdsi, &dsi_phyinit);
HAL_DSI_ConfigFlowControl(&display.hdsi, DSI_FLOW_CONTROL_BTA);
HAL_DSI_SetLowPowerRXFilter(&display.hdsi, 10000);
HAL_DSI_ConfigErrorMonitor(&display.hdsi, HAL_DSI_ERROR_NONE);
// Timing parameters for Video modes
DSI_VidCfgTypeDef dsi_vidcfg = { 0 };
dsi_vidcfg.VirtualChannelID = self->vcid;
dsi_vidcfg.ColorCoding = DSI_RGB565;
dsi_vidcfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE;
dsi_vidcfg.VSPolarity = DSI_VSYNC_ACTIVE_LOW;
dsi_vidcfg.HSPolarity = DSI_HSYNC_ACTIVE_LOW;
dsi_vidcfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
dsi_vidcfg.Mode = DSI_VID_MODE_BURST;
dsi_vidcfg.NullPacketSize = 0xFFF;
dsi_vidcfg.NumberOfChunks = 0;
dsi_vidcfg.PacketSize = self->width;
dsi_vidcfg.HorizontalSyncActive = dm->hsync_len * LANE_BYTE_CLOCK / dm->pixel_clock;
dsi_vidcfg.HorizontalBackPorch = dm->hback_porch * LANE_BYTE_CLOCK / dm->pixel_clock;
dsi_vidcfg.HorizontalLine = (self->width + dm->hsync_len + dm->hback_porch + dm->hfront_porch)
* LANE_BYTE_CLOCK / dm->pixel_clock;
dsi_vidcfg.VerticalSyncActive = dm->vsync_len;
dsi_vidcfg.VerticalBackPorch = dm->vback_porch;
dsi_vidcfg.VerticalFrontPorch = dm->vfront_porch;
dsi_vidcfg.VerticalActive = self->height;
// Enable/disable sending LP command while streaming
dsi_vidcfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE;
// Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions
dsi_vidcfg.LPLargestPacketSize = 0;
// Largest packet size possible to transmit in LP mode in HFP region during VACT period
dsi_vidcfg.LPVACTLargestPacketSize = 0;
// Specify for each region, if the going in LP mode is allowed while streaming
dsi_vidcfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;
dsi_vidcfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE;
dsi_vidcfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;
dsi_vidcfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;
dsi_vidcfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;
dsi_vidcfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE;
// Configure DSI Video mode timings with settings set above
HAL_DSI_ConfigVideoMode(&display.hdsi, &dsi_vidcfg);
HAL_DSI_Start(&display.hdsi);
HAL_DSI_Refresh(&display.hdsi);
HAL_DSI_PatternGeneratorStop(&display.hdsi);
HAL_NVIC_SetPriority(DSI_IRQn, IRQ_PRI_LTDC, 0);
HAL_NVIC_EnableIRQ(DSI_IRQn);
}
#endif
static void ltdc_init(py_display_obj_t *self) {
const display_mode_t *dm = &display_modes[self->framesize];
uint32_t fb_size = self->width * self->height * sizeof(uint16_t);
@ -412,7 +518,50 @@ static void display_set_backlight(py_display_obj_t *self, uint32_t intensity) {
}
#endif // OMV_DISPLAY_BL_PIN
#ifdef OMV_DSI_DISPLAY_CONTROLLER
int display_dsi_write(py_display_obj_t *self, uint8_t cmd, uint8_t *args, size_t n_args, bool dcs) {
HAL_StatusTypeDef status = HAL_ERROR;
if (n_args == 0) {
status = HAL_DSI_ShortWrite(&display.hdsi, self->vcid, (dcs == true) ?
DSI_DCS_SHORT_PKT_WRITE_P0 : DSI_GEN_SHORT_PKT_WRITE_P1, cmd, 0x00);
} else if (n_args == 1) {
status = HAL_DSI_ShortWrite(&display.hdsi, self->vcid, (dcs == true) ?
DSI_DCS_SHORT_PKT_WRITE_P1 : DSI_GEN_SHORT_PKT_WRITE_P2, cmd, args[0]);
} else {
status = HAL_DSI_LongWrite(&display.hdsi, self->vcid, (dcs == true) ?
DSI_DCS_LONG_PKT_WRITE : DSI_GEN_LONG_PKT_WRITE, n_args, cmd, args);
}
if (status != HAL_OK) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("DSI write command failed"));
}
return 0;
}
int display_dsi_read(py_display_obj_t *self, uint8_t cmd, uint8_t *args,
size_t n_args, uint8_t *buf, size_t len, bool dcs) {
HAL_StatusTypeDef status = HAL_ERROR;
uint8_t params[] = { cmd, (args == NULL) ? 0 : args[0] };
if (n_args == 0) {
// For generic commands, the HAL expects cmd in ParametersTable[0U]
status = HAL_DSI_Read(&display.hdsi, self->vcid, buf, len, (dcs == true) ?
DSI_DCS_SHORT_PKT_READ : DSI_GEN_SHORT_PKT_READ_P1, cmd, params);
} else if (n_args == 1) {
status = HAL_DSI_Read(&display.hdsi, self->vcid,
buf, len, DSI_GEN_SHORT_PKT_READ_P2, 0, params);
}
if (status != HAL_OK) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("DSI read command failed"));
}
return 0;
}
#endif
static void display_deinit(py_display_obj_t *self) {
#ifdef OMV_DSI_DISPLAY_CONTROLLER
HAL_DSI_DeInit(&display.hdsi);
HAL_NVIC_DisableIRQ(DSI_IRQn);
#endif
HAL_LTDC_DeInit(&display.hltdc);
HAL_NVIC_DisableIRQ(LTDC_IRQn);
@ -435,13 +584,15 @@ static void display_deinit(py_display_obj_t *self) {
}
mp_obj_t display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
enum { ARG_framesize, ARG_refresh, ARG_display_on, ARG_triple_buffer, ARG_portrait };
enum { ARG_framesize, ARG_refresh, ARG_display_on, ARG_triple_buffer, ARG_portrait, ARG_channel, ARG_controller };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_framesize, MP_ARG_INT, {.u_int = DISPLAY_RESOLUTION_FWVGA } },
{ MP_QSTR_refresh, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60 } },
{ MP_QSTR_display_on, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
{ MP_QSTR_triple_buffer, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} },
{ MP_QSTR_portrait, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_channel, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0 } },
{ MP_QSTR_controller, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_rom_obj = MP_ROM_NONE} },
};
// Parse args.
@ -456,7 +607,12 @@ mp_obj_t display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
}
py_display_obj_t *self = (py_display_obj_t *) m_new_obj_with_finaliser(py_display_obj_t);
#ifdef OMV_DSI_DISPLAY_CONTROLLER
self->base.type = &py_dsi_display_type;
#else
self->base.type = &py_rgb_display_type;
#endif
self->vcid = args[ARG_channel].u_int;
self->refresh = args[ARG_refresh].u_int;
self->display_on = args[ARG_display_on].u_bool;
self->bgr = false;
@ -471,6 +627,7 @@ mp_obj_t display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
self->width = display_modes[self->framesize].hactive;
self->height = display_modes[self->framesize].vactive;
}
self->controller = args[ARG_controller].u_obj;
// Store state to access it from IRQ handlers or callbacks
display.self = self;
@ -481,6 +638,21 @@ mp_obj_t display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
// Init LTDC controller
ltdc_init(self);
#ifdef OMV_DSI_DISPLAY_CONTROLLER
// Init DSI controller
dsi_init(self);
// Init the display controller.
if (self->controller != mp_const_none) {
mp_obj_t dest[3];
mp_load_method_maybe(self->controller, MP_QSTR_init, dest);
if (dest[0] != MP_OBJ_NULL) {
dest[2] = MP_OBJ_FROM_PTR(self);
mp_call_method_n_kw(1, 0, dest);
}
}
#endif
#ifdef OMV_DISPLAY_BL_PIN
if (self->display_on) {
display_set_backlight(self, 255); // to on state
@ -497,8 +669,13 @@ STATIC const py_display_p_t py_display_p = {
#ifdef OMV_DISPLAY_BL_PIN
.set_backlight = display_set_backlight,
#endif
#ifdef OMV_DSI_DISPLAY_CONTROLLER
.dsi_write = display_dsi_write,
.dsi_read = display_dsi_read,
#endif
};
#ifdef OMV_RGB_DISPLAY_CONTROLLER
MP_DEFINE_CONST_OBJ_TYPE(
py_rgb_display_type,
MP_QSTR_RGBDisplay,
@ -507,4 +684,17 @@ MP_DEFINE_CONST_OBJ_TYPE(
protocol, &py_display_p,
locals_dict, &py_display_locals_dict
);
#endif
#ifdef OMV_DSI_DISPLAY_CONTROLLER
MP_DEFINE_CONST_OBJ_TYPE(
py_dsi_display_type,
MP_QSTR_DSIDisplay,
MP_TYPE_FLAG_NONE,
make_new, display_make_new,
protocol, &py_display_p,
locals_dict, &py_display_locals_dict
);
#endif
#endif // MICROPY_PY_DISPLAY

View File

@ -601,7 +601,19 @@ void HAL_JPEG_MspDeInit(JPEG_HandleTypeDef *hjpeg) {
}
#endif
#if defined(OMV_RGB_DISPLAY_CONTROLLER)
#if defined(OMV_DSI_DISPLAY_CONTROLLER)
void HAL_DSI_MspInit(DSI_HandleTypeDef *hdsi) {
__HAL_RCC_DSI_CLK_ENABLE();
}
void HAL_DSI_MspDeInit(DSI_HandleTypeDef *hdsi) {
__HAL_RCC_DSI_FORCE_RESET();
__HAL_RCC_DSI_RELEASE_RESET();
__HAL_RCC_DSI_CLK_DISABLE();
}
#endif
#if defined(OMV_RGB_DISPLAY_CONTROLLER) || defined(OMV_DSI_DISPLAY_CONTROLLER)
void HAL_LTDC_MspInit(LTDC_HandleTypeDef *hltdc) {
#if defined(OMV_RGB_DISPLAY_R0_PIN)
const omv_gpio_t ltdc_pins[] = {