Merge pull request #1004 from kwagyeman/kwabena/add_hdmi_cec_support

Add hdmi cec support
This commit is contained in:
Ibrahim Abd Elkader 2020-11-27 16:06:52 +02:00 committed by GitHub
commit be59d895d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 709 additions and 19 deletions

View File

@ -312,6 +312,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/py/, \
py_image.o \ py_image.o \
py_time.o \ py_time.o \
py_lcd.o \ py_lcd.o \
py_lcd_cec.o \
py_lcd_touch.o \ py_lcd_touch.o \
py_tv.o \ py_tv.o \
py_fir.o \ py_fir.o \

View File

@ -97,6 +97,7 @@ SRCS += $(addprefix py/, \
py_image.c \ py_image.c \
py_time.c \ py_time.c \
py_lcd.c \ py_lcd.c \
py_lcd_cec.c \
py_lcd_touch.c \ py_lcd_touch.c \
py_tv.c \ py_tv.c \
py_fir.c \ py_fir.c \

View File

@ -579,6 +579,10 @@
#define OMV_TOUCH_SDA_PIN (pin_J14) #define OMV_TOUCH_SDA_PIN (pin_J14)
#define OMV_TOUCH_INT_PIN (pin_J6) #define OMV_TOUCH_INT_PIN (pin_J6)
// HDMI CEC I/O
#define OMV_CEC_PRESENT
#define OMV_CEC_PIN (pin_H2)
// Enable additional GPIO banks for DRAM... // Enable additional GPIO banks for DRAM...
#define OMV_ENABLE_GPIO_BANK_F #define OMV_ENABLE_GPIO_BANK_F
#define OMV_ENABLE_GPIO_BANK_G #define OMV_ENABLE_GPIO_BANK_G

View File

@ -11,6 +11,7 @@
#include STM32_HAL_H #include STM32_HAL_H
#include "extint.h" #include "extint.h"
#include "spi.h" #include "spi.h"
#include "py_lcd_cec.h"
#include "py_lcd_touch.h" #include "py_lcd_touch.h"
#include "py_helper.h" #include "py_helper.h"
#include "extmod/machine_i2c.h" #include "extmod/machine_i2c.h"
@ -1251,7 +1252,12 @@ STATIC mp_obj_t py_lcd_deinit()
if ((lcd_type == LCD_DISPLAY) || (lcd_type == LCD_DISPLAY_WITH_HDMI)) ltdc_set_backlight(0); // back to default state if ((lcd_type == LCD_DISPLAY) || (lcd_type == LCD_DISPLAY_WITH_HDMI)) ltdc_set_backlight(0); // back to default state
#endif // OMV_LCD_BL_PIN #endif // OMV_LCD_BL_PIN
#ifdef OMV_DVI_PRESENT #ifdef OMV_DVI_PRESENT
if ((lcd_type == LCD_DISPLAY_WITH_HDMI) || (lcd_type == LCD_DISPLAY_ONLY_HDMI)) ltdc_dvi_deinit(); if ((lcd_type == LCD_DISPLAY_WITH_HDMI) || (lcd_type == LCD_DISPLAY_ONLY_HDMI)) {
ltdc_dvi_deinit();
#ifdef OMV_CEC_PRESENT
lcd_cec_deinit();
#endif
}
#endif // OMV_DVI_PRESENT #endif // OMV_DVI_PRESENT
#ifdef OMV_TOUCH_PRESENT #ifdef OMV_TOUCH_PRESENT
if ((lcd_type == LCD_DISPLAY) || (lcd_type == LCD_DISPLAY_WITH_HDMI)) lcd_touch_deinit(); if ((lcd_type == LCD_DISPLAY) || (lcd_type == LCD_DISPLAY_WITH_HDMI)) lcd_touch_deinit();
@ -1318,7 +1324,12 @@ STATIC mp_obj_t py_lcd_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args
if ((type == LCD_DISPLAY) || (type == LCD_DISPLAY_WITH_HDMI)) ltdc_set_backlight(255); // to on state if ((type == LCD_DISPLAY) || (type == LCD_DISPLAY_WITH_HDMI)) ltdc_set_backlight(255); // to on state
#endif // OMV_LCD_BL_PIN #endif // OMV_LCD_BL_PIN
#ifdef OMV_DVI_PRESENT #ifdef OMV_DVI_PRESENT
if ((type == LCD_DISPLAY_WITH_HDMI) || (type == LCD_DISPLAY_ONLY_HDMI)) ltdc_dvi_init(); if ((type == LCD_DISPLAY_WITH_HDMI) || (type == LCD_DISPLAY_ONLY_HDMI)) {
ltdc_dvi_init();
#ifdef OMV_CEC_PRESENT
lcd_cec_init();
#endif
}
#endif // OMV_DVI_PRESENT #endif // OMV_DVI_PRESENT
#ifdef OMV_TOUCH_PRESENT #ifdef OMV_TOUCH_PRESENT
if ((type == LCD_DISPLAY) || (type == LCD_DISPLAY_WITH_HDMI)) lcd_touch_init(); if ((type == LCD_DISPLAY) || (type == LCD_DISPLAY_WITH_HDMI)) lcd_touch_init();
@ -1425,34 +1436,62 @@ STATIC mp_obj_t py_lcd_get_backlight()
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_get_backlight_obj, py_lcd_get_backlight); STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_get_backlight_obj, py_lcd_get_backlight);
#ifdef OMV_DVI_PRESENT
STATIC mp_obj_t py_lcd_get_display_connected() STATIC mp_obj_t py_lcd_get_display_connected()
{ {
#ifdef OMV_DVI_PRESENT
return ltdc_dvi_get_display_connected(); return ltdc_dvi_get_display_connected();
#else
return mp_const_false;
#endif
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_get_display_connected_obj, py_lcd_get_display_connected); STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_get_display_connected_obj, py_lcd_get_display_connected);
STATIC mp_obj_t py_lcd_get_display_id_data()
{
#if defined(OMV_DVI_PRESENT) && defined(OMV_DDC_PRESENT)
return ltdc_dvi_get_display_id_data();
#else
return mp_const_empty_bytes;
#endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_get_display_id_data_obj, py_lcd_get_display_id_data);
STATIC mp_obj_t py_lcd_register_hotplug_cb(mp_obj_t cb) STATIC mp_obj_t py_lcd_register_hotplug_cb(mp_obj_t cb)
{ {
#ifdef OMV_DVI_PRESENT
ltdc_dvi_register_hotplug_cb(cb); ltdc_dvi_register_hotplug_cb(cb);
#endif
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcd_register_hotplug_cb_obj, py_lcd_register_hotplug_cb); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcd_register_hotplug_cb_obj, py_lcd_register_hotplug_cb);
#endif
#if defined(OMV_DVI_PRESENT) && defined(OMV_DDC_PRESENT)
STATIC mp_obj_t py_lcd_get_display_id_data()
{
return ltdc_dvi_get_display_id_data();
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_get_display_id_data_obj, py_lcd_get_display_id_data);
#endif
#if defined(OMV_DVI_PRESENT) && defined(OMV_CEC_PRESENT)
STATIC mp_obj_t py_lcd_send_frame(mp_obj_t dst_addr, mp_obj_t src_addr, mp_obj_t bytes)
{
lcd_cec_send_frame(dst_addr, src_addr, bytes);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_lcd_send_frame_obj, py_lcd_send_frame);
STATIC mp_obj_t py_lcd_receive_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
return lcd_cec_receive_frame(n_args, args, kw_args);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_lcd_receive_frame_obj, 1, py_lcd_receive_frame);
STATIC mp_obj_t py_lcd_register_cec_receive_cb(mp_obj_t cb, mp_obj_t dst_addr)
{
lcd_cec_register_cec_receive_cb(cb, dst_addr);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_lcd_register_cec_receive_cb_obj, py_lcd_register_cec_receive_cb);
STATIC mp_obj_t py_lcd_received_frame_src_addr()
{
return lcd_cec_received_frame_src_addr();
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_received_frame_src_addr_obj, py_lcd_received_frame_src_addr);
STATIC mp_obj_t py_lcd_received_frame_bytes()
{
return lcd_cec_received_frame_bytes();
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_received_frame_bytes_obj, py_lcd_received_frame_bytes);
#endif
#ifdef OMV_TOUCH_PRESENT #ifdef OMV_TOUCH_PRESENT
STATIC mp_obj_t py_lcd_update_touch_points() STATIC mp_obj_t py_lcd_update_touch_points()
@ -1464,6 +1503,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(py_lcd_update_touch_points_obj, py_lcd_update_t
STATIC mp_obj_t py_lcd_register_touch_cb(mp_obj_t cb) STATIC mp_obj_t py_lcd_register_touch_cb(mp_obj_t cb)
{ {
lcd_touch_register_touch_cb(cb); lcd_touch_register_touch_cb(cb);
return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcd_register_touch_cb_obj, py_lcd_register_touch_cb); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcd_register_touch_cb_obj, py_lcd_register_touch_cb);
@ -1503,6 +1543,7 @@ STATIC mp_obj_t py_lcd_get_point_y_position(mp_obj_t index)
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcd_get_point_y_position_obj, py_lcd_get_point_y_position); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcd_get_point_y_position_obj, py_lcd_get_point_y_position);
#endif #endif
STATIC mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) STATIC mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{ {
image_t *arg_img = py_helper_arg_to_image_mutable(args[0]); image_t *arg_img = py_helper_arg_to_image_mutable(args[0]);
@ -1703,9 +1744,31 @@ STATIC const mp_rom_map_elem_t globals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&py_lcd_refresh_obj) }, { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&py_lcd_refresh_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_backlight), MP_ROM_PTR(&py_lcd_get_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_get_backlight), MP_ROM_PTR(&py_lcd_get_backlight_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&py_lcd_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&py_lcd_set_backlight_obj) },
#ifdef OMV_DVI_PRESENT
{ MP_ROM_QSTR(MP_QSTR_get_display_connected), MP_ROM_PTR(&py_lcd_get_display_connected_obj) }, { MP_ROM_QSTR(MP_QSTR_get_display_connected), MP_ROM_PTR(&py_lcd_get_display_connected_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_display_id_data), MP_ROM_PTR(&py_lcd_get_display_id_data_obj) },
{ MP_ROM_QSTR(MP_QSTR_register_hotplug_cb), MP_ROM_PTR(&py_lcd_register_hotplug_cb_obj) }, { MP_ROM_QSTR(MP_QSTR_register_hotplug_cb), MP_ROM_PTR(&py_lcd_register_hotplug_cb_obj) },
#else
{ MP_ROM_QSTR(MP_QSTR_get_display_connected), MP_ROM_PTR(&py_func_unavailable_obj) },
{ MP_ROM_QSTR(MP_QSTR_register_hotplug_cb), MP_ROM_PTR(&py_func_unavailable_obj) },
#endif
#if defined(OMV_DVI_PRESENT) && defined(OMV_DDC_PRESENT)
{ MP_ROM_QSTR(MP_QSTR_get_display_id_data), MP_ROM_PTR(&py_lcd_get_display_id_data_obj) },
#else
{ MP_ROM_QSTR(MP_QSTR_get_display_id_data), MP_ROM_PTR(&py_func_unavailable_obj) },
#endif
#if defined(OMV_DVI_PRESENT) && defined(OMV_CEC_PRESENT)
{ MP_ROM_QSTR(MP_QSTR_send_frame), MP_ROM_PTR(&py_lcd_send_frame_obj) },
{ MP_ROM_QSTR(MP_QSTR_receive_frame), MP_ROM_PTR(&py_lcd_receive_frame_obj) },
{ MP_ROM_QSTR(MP_QSTR_register_receive_cb), MP_ROM_PTR(&py_lcd_register_cec_receive_cb_obj) },
{ MP_ROM_QSTR(MP_QSTR_received_frame_src_addr), MP_ROM_PTR(&py_lcd_received_frame_src_addr_obj) },
{ MP_ROM_QSTR(MP_QSTR_received_frame_bytes), MP_ROM_PTR(&py_lcd_received_frame_bytes_obj) },
#else
{ MP_ROM_QSTR(MP_QSTR_send_frame), MP_ROM_PTR(&py_func_unavailable_obj) },
{ MP_ROM_QSTR(MP_QSTR_receive_frame), MP_ROM_PTR(&py_func_unavailable_obj) },
{ MP_ROM_QSTR(MP_QSTR_register_receive_cb), MP_ROM_PTR(&py_func_unavailable_obj) },
{ MP_ROM_QSTR(MP_QSTR_received_frame_src_addr), MP_ROM_PTR(&py_func_unavailable_obj) },
{ MP_ROM_QSTR(MP_QSTR_received_frame_bytes), MP_ROM_PTR(&py_func_unavailable_obj) },
#endif
#ifdef OMV_TOUCH_PRESENT #ifdef OMV_TOUCH_PRESENT
{ MP_ROM_QSTR(MP_QSTR_update_touch_points), MP_ROM_PTR(&py_lcd_update_touch_points_obj) }, { MP_ROM_QSTR(MP_QSTR_update_touch_points), MP_ROM_PTR(&py_lcd_update_touch_points_obj) },
{ MP_ROM_QSTR(MP_QSTR_register_touch_cb), MP_ROM_PTR(&py_lcd_register_touch_cb_obj) }, { MP_ROM_QSTR(MP_QSTR_register_touch_cb), MP_ROM_PTR(&py_lcd_register_touch_cb_obj) },

596
src/omv/py/py_lcd_cec.c Normal file
View File

@ -0,0 +1,596 @@
/*
* This file is part of the OpenMV project.
*
* Copyright (c) 2013-2020 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2020 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* LCD Python module.
*/
#include "extint.h"
#include "objarray.h"
#include "py_helper.h"
#include "py_lcd_cec.h"
#include "omv_boardconfig.h"
#ifdef OMV_CEC_PRESENT
static mp_obj_t lcd_cec_user_cb = NULL;
static volatile uint8_t lcd_cec_src_addr = 0;
static volatile mp_obj_t lcd_cec_dst_addr = NULL;
static volatile mp_obj_t lcd_cec_bytes = NULL;
////////////////////////////////////////////////////////////////////////////////
// stsw-stm32086 - https://www.st.com/en/embedded-software/stsw-stm32086.html
////////////////////////////////////////////////////////////////////////////////
/* Start bit timings */
#define Sbit_Nom_LD 37 /* Start Bit Nominal Low duration: 37 x 100µs = 3.7ms */
#define Sbit_Nom_HD 8 /* Start Bit Nominal High Duration: 8 x 100µs = 0.8ms */
#define Sbit_Min_LD 35 /* Start Bit Minimum Low duration: 35 x 100µs = 3.5ms */
#define Sbit_Max_LD 39 /* Start Bit Maximum Low duration: 39 x 100µs = 3.9ms */
#define Sbit_Min_TD 43 /* Start Bit Minimum Total duration: 43 x 100µs = 4.3ms */
#define Sbit_Max_TD 47 /* Start Bit Maximum Total duration: 47 x 100µs = 4.7ms */
/* Data bit logical "0" timings */
#define Dbit0_Nom_LD 15 /* Data Bit "0" Nominal Low duration: 15 x 100µs = 1.5ms */
#define Dbit0_Nom_HD 9 /* Data Bit "0" Nominal High Duration: 9 x 100µs = 0.9ms */
#define Dbit0_Min_LD 13 /* Data Bit "0" Minimum Low duration: 13 x 100µs = 1.3ms */
#define Dbit0_Max_LD 17 /* Data Bit "0" Maximum Low duration: 17 x 100µs = 1.7ms */
/* Data bit logical "1" timings */
#define Dbit1_Nom_LD 6 /* Data Bit (logical "1") Nominal Low duration: 0.6ms */
#define Dbit1_Nom_HD 18 /* Data Bit (logical "1") Nominal High Duration: 1.8ms */
#define Dbit1_Min_LD 4 /* Data Bit "1" Minimum Low duration: 0.4ms */
#define Dbit1_Max_LD 8 /* Data Bit "1" Maximum Low duration: 0.8ms */
/* Data bit duration */
#define DbitX_Min_TD 20 /* Data Bit Minimum Total duration: 2ms */
#define DbitX_Max_TD 27 /* Data Bit Maximum Total duration: 2.7ms */
/* Header or Data block definition */
#define DataBlock 0
#define HeaderBlock 1
/* Masks */
#define ReceiveFrameStatusMask 0x00010000
#define FrameSendToMeMask 0x00020000
#define InitiatorAddressMask 0x000000FF
static uint8_t cec_byte;
static uint8_t cec_bit;
static uint8_t cec_eom;
static uint32_t cec_counter;
static uint8_t cec_last_byte;
static void CEC_Wait100us(uint32_t nTime)
{
mp_hal_delay_us(nTime * 100);
}
static void CEC_SendStartBit()
{
/* Start Low Period */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_RESET);
/* Wait 3.7ms*/
CEC_Wait100us(Sbit_Nom_LD);
/* Start High Period */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_SET);
/* Wait 0.8ms for a total of 3.7 + 0.8 = 4.5ms */
CEC_Wait100us(Sbit_Nom_HD);
}
static uint8_t CEC_ReceiveStartBit()
{
/* Initialize cec_counter */
cec_counter = 0;
/* Go to high impedance: CEC bus state = VDD */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_SET);
/* Wait for rising edge of the start bit */
while (!HAL_GPIO_ReadPin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask))
{
/* Wait 100us */
CEC_Wait100us(1);
/* Increment cec_counter that contains the duration of low level duration */
cec_counter++;
/* If too long low level for start bit */
if (cec_counter > Sbit_Max_LD)
{
/* Exit: it's an error: 0 */
return 0;
}
}
/* If too short duration of low level for start bit */
if (cec_counter < Sbit_Min_LD)
{
/* Exit: it's an error: 0 */
return 0;
}
/* Wait for falling edge of the start bit (end of start bit) */
while (HAL_GPIO_ReadPin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask))
{
/* Wait 100us */
CEC_Wait100us(1);
/* Increment cec_counter that contains the duration of high level duration */
cec_counter++;
/* If too long total duration for start bit */
if (cec_counter > Sbit_Max_TD)
{
/* Exit: it's an error: 0 */
return 0;
}
}
/* If too short total duration for start bit */
if (cec_counter < Sbit_Min_TD)
{
/* Exit: it's an error: 0 */
return 0;
}
/* Exit: start bit received correctly */
return 1;
}
static void CEC_SendDataBit(uint8_t bit)
{
/* Start Low Period: the duration depends on the Logical Level "0" or "1" */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_RESET);
/* Wait 0.6 ms if Logical Level is "1" and 1.5ms if Logical Level is "0" */
CEC_Wait100us(bit ? Dbit1_Nom_LD : Dbit0_Nom_LD);
/* Start High Period: the duration depends on the Logical Level "0" or "1" */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_SET);
/* Wait 1.8 ms if Logical Level is "1" and 0.9 ms if Logical Level is "0" */
CEC_Wait100us(bit ? Dbit1_Nom_HD : Dbit0_Nom_HD);
}
static uint8_t CEC_ReceiveDataBit()
{
uint8_t bit = 0xFF;
/* Initialize cec_counter */
cec_counter = 0;
/* Wait for rising edge of the data bit */
while (!HAL_GPIO_ReadPin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask))
{
/* Wait 100us */
CEC_Wait100us(1);
/* Increment cec_counter that contains the duration of low level duration */
cec_counter++;
if (cec_counter > Dbit0_Max_LD)
{
/* Exit: it's an error: 0xFF */
return 0xFF;
}
}
/* If the measured duration of the low level is greater than the minimum low duration
of "logical 0" i.e > 1.3 ms */
if (cec_counter > Dbit0_Min_LD)
{
/* The received bit is "logical 0" */
bit = 0;
}
else
{
/* If the measured duration of the low level is greater than the maximum low duration
of "logical 1" i.e > 0.8 ms */
if (cec_counter > Dbit1_Max_LD)
{
/* Exit: it's an error: 0xFF */
return 0xFF;
}
/* If the measured duration of the low level is greater than the minimum low duration
of "logical 1" i.e > 0.4 ms */
if (cec_counter > Dbit1_Min_LD)
{
/* The received bit is "logical 1" */
bit = 1;
}
else
{
/* Exit: it's an error: 0xFF */
return 0xFF;
}
}
/* Wait for falling edge of the data bit */
while (HAL_GPIO_ReadPin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask))
{
/* Wait 100us */
CEC_Wait100us(1);
/* Increment cec_counter that contains the duration of high level duration */
cec_counter++;
/* If too long total duration for the data bit is detected */
if (cec_counter > DbitX_Max_TD)
{
/* Exit: it's an error: 0xFF */
return 0xFF;
}
}
/* If too short total duration for the data bit is detected */
if (cec_counter < DbitX_Min_TD)
{
/* Exit: it's an error: 0xFF */
return 0xFF;
}
/* The data bit is received correctly. Return its value */
return bit;
}
static void CEC_SendAckBit()
{
mp_uint_t start = mp_hal_ticks_ms();
/* Wait for falling edge: end of EOM bit sent by the initiator */
while (HAL_GPIO_ReadPin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask)) {
if ((mp_hal_ticks_ms() - start) > 10) nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Ack timeout!"));
}
/* Send ACK bit */
CEC_SendDataBit(0);
/* Force the bus to 0: for ACK bit delimiting */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_RESET);
/* Wait 100us to allow the initiator to detect the end of ACK bit */
CEC_Wait100us(1);
/* Go to high impedance: CEC bus state = VDD */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_SET);
}
static uint8_t CEC_ReceiveAckBit()
{
uint8_t AckValue = 0xFF;
/* Get the ACK bit */
AckValue = CEC_ReceiveDataBit();
/* If the byte has been acknowledged by the Follower (ACK = 0) */
if (AckValue != 0xFF)
{
mp_uint_t start = mp_hal_ticks_ms();
/* Wait for falling edge of ACK bit (the end of ACK bit)*/
while (HAL_GPIO_ReadPin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask)) {
if ((mp_hal_ticks_ms() - start) > 10) nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Ack timeout!"));
}
}
return AckValue;
}
static bool CEC_SendByte(uint8_t byte)
{
/* Send the data byte: bit by bit (MSB first) */
for (cec_bit = 0; cec_bit <= 7; cec_bit++)
{
CEC_SendDataBit(byte & 0x80);
byte <<= 1;
}
/* Send EOM bit after sending the data byte */
CEC_SendDataBit(cec_last_byte);
/* Force the bus to 0: for EOM bit delimiting */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_RESET);
/* Wait 100us to allow the follower to detect the end of EOM bit */
CEC_Wait100us(1);
/* Go to high impedance: CEC bus state = VDD */
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_SET);
/* If the byte is acknowledged by the receiver */
if (CEC_ReceiveAckBit() == 0)
{
/* Exit: the data byte has been received by the follower */
return true;
}
else /* The data byte is not acknowledged by the follower */
{
/* Exit: the data byte has not been received by the follower */
return false;
}
}
static uint8_t CEC_ReceiveByte(uint8_t HeaderDataIndicator)
{
uint8_t TempReceiveBit = 0;
bool ReceiveByteStatus = true;
/* Initialize cec_counter */
cec_byte = 0;
for (cec_bit = 0; cec_bit <= 7; cec_bit++)
{
/* Shift the data byte */
cec_byte <<= 1;
/* Receive the data bit */
TempReceiveBit = CEC_ReceiveDataBit();
/* If the received bit was received incorrectly */
if (TempReceiveBit == 0xFF) /* If the received bit is wrong */
{
/* Store the error status */
ReceiveByteStatus = false;
}
/* Build the data byte (MSB first) */
cec_byte |= TempReceiveBit;
}
/* Read EOM bit */
cec_eom = CEC_ReceiveDataBit();
/* If the EOM bit was received incorrectly */
if (cec_eom == 0xFF) /* If the received bit is wrong */
{
/* Store the error status */
ReceiveByteStatus = false;
}
/* If the byte to send is a "Data" block */
if (HeaderDataIndicator == DataBlock)
{
/* If the bits has been received correctly, acknowledge the data byte */
if (ReceiveByteStatus != false)
{
/* Send the Ack bit */
CEC_SendAckBit();
/* Byte received correctly: return 1 */
return 1;
}
else /* Otherwise do not acknowledge the received byte */
{
/* Byte received incorrectly: return 0 */
return 0;
}
}
else /* If the byte is a "Header" block */
{
/* If the bits has been received correctly and do not acknowledge the byte */
if (ReceiveByteStatus != false)
{
/* Byte received correctly: return 1 */
return 1;
}
else /* If the bits has been received incorrectly and do not acknowledge the byte */
{
/* Byte received incorrectly: return 0 */
return 0;
}
}
}
static bool CEC_SendFrame(uint8_t InitiatorAddress, uint8_t FollowerAddress, uint8_t MessageLength, uint8_t *Message)
{
uint8_t i = 0;
uint8_t HeaderBlockValueToSend = 0;
cec_last_byte = 0;
/* Build the Header block to send */
HeaderBlockValueToSend = (((InitiatorAddress & 0xF) << 4) | (FollowerAddress & 0xF));
/* Disable EXTI global interrupt to avoid the EXTI to enter EXTI interrupt
while transmitting a frame */
if (lcd_cec_user_cb) extint_disable(OMV_CEC_PIN->pin);
/* Send start bit */
CEC_SendStartBit();
/* Send initiator and follower addresses. If the Header block is not
transmitted successfully then exit and return error */
if (CEC_SendByte(HeaderBlockValueToSend) == false)
{
if (lcd_cec_user_cb) extint_enable(OMV_CEC_PIN->pin);
/* Exit and return send failed */
return false;
}
/* Send data bytes */
for (i = 0; i < MessageLength; i++)
{
if (i == (MessageLength - 1))
{
cec_last_byte = 1;
}
/* Send data byte and check if the follower sent the ACK bit = 0 */
if (CEC_SendByte(Message[i]) == false)
{
if (lcd_cec_user_cb) extint_enable(OMV_CEC_PIN->pin);
/* Exit and return send failed */
return false;
}
}
if (lcd_cec_user_cb) extint_enable(OMV_CEC_PIN->pin);
/* Exit and return send succeeded */
return true;
}
static uint32_t CEC_ReceiveFrame(uint8_t* Message, uint8_t FollLogAdd)
{
uint32_t i = 0;
uint32_t InitiatorAddress = 0;
uint32_t ReceiveStatus = 1;
uint32_t FrameSendToMe = 0;
cec_byte = 0;
cec_eom = 0;
/* If the start bit has been received successfully */
if (CEC_ReceiveStartBit())
{
/* Get the first byte and check if the byte has been received correctly */
if (CEC_ReceiveByte(HeaderBlock))
{
/* Get the initiator address */
InitiatorAddress = cec_byte >> 4;
/* If the frame was sent to me */
if ((cec_byte & 0x0F) == FollLogAdd)
{
CEC_SendAckBit(); /* Send Acknowledge bit = 0 */
FrameSendToMe = 1;
/* Continue to read the data byte since the frame is not completed */
while (!cec_eom)
{
/* Check if the byte has been received correctly */
if (CEC_ReceiveByte(DataBlock))
{
/* Build the frame */
Message[i] = cec_byte;
i++;
}
else /* If the byte has not been received correctly */
{
/* Set receive status bit (Error) */
ReceiveStatus = 0;
}
}
}
}
}
else /* If the start bit has not been received successfully */
{
/* Set receive status bit (Error) */
ReceiveStatus = 0;
}
/* Return the different receive infos: Receive status, number of data byte received,
Frame send to me or not and the initiator address */
return ((((InitiatorAddress) | (i << 8)) | (ReceiveStatus << 16)) | (FrameSendToMe << 17));
}
////////////////////////////////////////////////////////////////////////////////
static bool lcd_cec_receive_frame_int(mp_obj_t dst_addr, bool assertOnError)
{
mp_obj_array_t *bytes = (mp_obj_array_t *) lcd_cec_bytes;
uint32_t result = CEC_ReceiveFrame(bytes->items, mp_obj_get_int(dst_addr));
bool receiveFrameStatus = result & ReceiveFrameStatusMask;
bool frameSendToMe = result & FrameSendToMeMask;
if (assertOnError && (!receiveFrameStatus)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Receive Failed!"));
}
if (receiveFrameStatus && frameSendToMe) {
lcd_cec_src_addr = result & InitiatorAddressMask;
bytes->len = (result >> 8) & 0xFF;
return true;
}
return false;
}
void lcd_cec_send_frame(mp_obj_t dst_addr, mp_obj_t src_addr, mp_obj_t bytes)
{
size_t len;
uint8_t *data = (uint8_t *) mp_obj_str_get_data(bytes, &len);
if (!CEC_SendFrame(mp_obj_get_int(src_addr), mp_obj_get_int(dst_addr), len, data)) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Send Failed!"));
}
}
mp_obj_t lcd_cec_received_frame_src_addr()
{
return mp_obj_new_int(lcd_cec_src_addr);
}
mp_obj_t lcd_cec_received_frame_bytes()
{
return lcd_cec_bytes;
}
mp_obj_t lcd_cec_receive_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
{
if (n_args > 0) {
int timeout = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_timeout), 1000);
mp_uint_t start = mp_hal_ticks_ms();
while (HAL_GPIO_ReadPin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask)) {
if ((mp_hal_ticks_ms() - start) > timeout) nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Receive timeout!"));
}
return mp_obj_new_bool(lcd_cec_receive_frame_int(args[0], true));
}
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Expected destination address!"));
}
STATIC mp_obj_t lcd_cec_extint_callback(mp_obj_t line)
{
if (lcd_cec_user_cb && lcd_cec_receive_frame_int(lcd_cec_dst_addr, false)) mp_call_function_0(lcd_cec_user_cb);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lcd_cec_extint_callback_obj, lcd_cec_extint_callback);
void lcd_cec_deinit()
{
extint_disable(OMV_CEC_PIN->pin);
lcd_cec_user_cb = NULL;
lcd_cec_src_addr = 0;
lcd_cec_dst_addr = NULL;
lcd_cec_bytes = NULL;
HAL_GPIO_DeInit(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask);
}
void lcd_cec_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Pin = OMV_CEC_PIN->pin_mask;
HAL_GPIO_Init(OMV_CEC_PIN->gpio, &GPIO_InitStructure);
HAL_GPIO_WritePin(OMV_CEC_PIN->gpio, OMV_CEC_PIN->pin_mask, GPIO_PIN_SET);
HAL_Delay(1);
lcd_cec_bytes = mp_obj_new_bytearray_by_ref(0, m_new(byte, 16));
extint_register((mp_obj_t) OMV_CEC_PIN, GPIO_MODE_IT_FALLING, GPIO_PULLUP, (mp_obj_t) &lcd_cec_extint_callback_obj, true);
}
void lcd_cec_register_cec_receive_cb(mp_obj_t cb, mp_obj_t dst_addr)
{
extint_disable(OMV_CEC_PIN->pin);
lcd_cec_user_cb = cb;
lcd_cec_dst_addr = dst_addr;
if (cb != mp_const_none) extint_enable(OMV_CEC_PIN->pin);
}
#endif // OMV_CEC_PRESENT

20
src/omv/py/py_lcd_cec.h Normal file
View File

@ -0,0 +1,20 @@
/*
* This file is part of the OpenMV project.
*
* Copyright (c) 2013-2020 Ibrahim Abdelkader <iabdalkader@openmv.io>
* Copyright (c) 2013-2020 Kwabena W. Agyeman <kwagyeman@openmv.io>
*
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* LCD Python module.
*/
#ifndef __PY_LCD_CEC_H__
#define __PY_LCD_CEC_H__
void lcd_cec_init();
void lcd_cec_deinit();
void lcd_cec_send_frame(mp_obj_t dst_addr, mp_obj_t src_addr, mp_obj_t bytes);
mp_obj_t lcd_cec_receive_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args);
void lcd_cec_register_cec_receive_cb(mp_obj_t cb, mp_obj_t dst_addr);
mp_obj_t lcd_cec_received_frame_src_addr();
mp_obj_t lcd_cec_received_frame_bytes();
#endif // __PY_LCD_CEC_H__

View File

@ -1198,6 +1198,11 @@ Q(set_backlight)
Q(get_backlight) Q(get_backlight)
Q(get_display_connected) Q(get_display_connected)
Q(get_display_id_data) Q(get_display_id_data)
Q(send_frame)
Q(receive_frame)
Q(register_receive_cb)
Q(received_frame_src_addr)
Q(received_frame_bytes)
Q(register_hotplug_cb) Q(register_hotplug_cb)
Q(update_touch_points) Q(update_touch_points)
Q(register_touch_cb) Q(register_touch_cb)