diff --git a/src/Makefile b/src/Makefile index ac4292d16..db7928d66 100755 --- a/src/Makefile +++ b/src/Makefile @@ -161,6 +161,7 @@ OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/py/, \ py_image.o \ py_time.o \ mlx90620.o \ + py_lcd.o \ py_gif.o \ py_mjpeg.o \ ) diff --git a/src/omv/Makefile b/src/omv/Makefile index 209ed65c3..9c3f68b6f 100644 --- a/src/omv/Makefile +++ b/src/omv/Makefile @@ -64,6 +64,7 @@ SRCS += $(addprefix py/, \ py_image.c \ py_time.c \ mlx90620.c \ + py_lcd.c \ py_gif.c \ py_mjpeg.c \ ) diff --git a/src/omv/main.c b/src/omv/main.c index b186a1527..422484d91 100644 --- a/src/omv/main.c +++ b/src/omv/main.c @@ -59,6 +59,7 @@ #include "py_sensor.h" #include "py_image.h" #include "mlx90620.h" +#include "py_lcd.h" int errno; extern char _fatfs_buf; @@ -271,7 +272,7 @@ static void make_flash_fs() int main(void) { FRESULT f_res; - int sensor_init_ret; + int sensor_init_ret = 0; bool first_soft_reset = true; // Stack limit should be less than real stack size, so we @@ -316,6 +317,7 @@ soft_reset: pyb_usb_init0(); sensor_init0(); fb_alloc_init0(); + py_lcd_init0(); #if MICROPY_HW_ENABLE_RTC if (first_soft_reset) { diff --git a/src/omv/py/py_lcd.c b/src/omv/py/py_lcd.c new file mode 100644 index 000000000..87b6e9f8f --- /dev/null +++ b/src/omv/py/py_lcd.c @@ -0,0 +1,400 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2013/2014 Ibrahim Abdelkader + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * LCD Python module. + * + */ +#include +#include +#include +#include +#include "imlib.h" +#include "fb_alloc.h" +#include "ff_wrapper.h" +#include "py_assert.h" +#include "py_helper.h" +#include "py_image.h" + +#define RST_PORT GPIOD +#define RST_PIN GPIO_PIN_12 +#define RST_PIN_WRITE(bit) HAL_GPIO_WritePin(RST_PORT, RST_PIN, bit); + +#define RS_PORT GPIOD +#define RS_PIN GPIO_PIN_13 +#define RS_PIN_WRITE(bit) HAL_GPIO_WritePin(RS_PORT, RS_PIN, bit); + +#define CS_PORT GPIOB +#define CS_PIN GPIO_PIN_12 +#define CS_PIN_WRITE(bit) HAL_GPIO_WritePin(CS_PORT, CS_PIN, bit); + +#define LED_PORT GPIOA +#define LED_PIN GPIO_PIN_5 +#define LED_PIN_WRITE(bit) HAL_GPIO_WritePin(LED_PORT, LED_PIN, bit); + +extern mp_obj_t pyb_spi_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t pyb_spi_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); +extern mp_obj_t pyb_spi_deinit(mp_obj_t self_in); + +static mp_obj_t spi_port = NULL; +static int width = 0; +static int height = 0; +static enum { LCD_NONE, LCD_SHIELD } type = LCD_NONE; +static bool backlight_init = false; + +// Send out 8-bit data using the SPI object. +static void lcd_write_command_byte(uint8_t data_byte) +{ + mp_map_t arg_map; + arg_map.all_keys_are_qstrs = true; + arg_map.is_fixed = true; + arg_map.is_ordered = true; + arg_map.used = 0; + arg_map.alloc = 0; + arg_map.table = NULL; + + CS_PIN_WRITE(false); + RS_PIN_WRITE(false); // command + pyb_spi_send( + 2, (mp_obj_t []) { + spi_port, + mp_obj_new_int(data_byte) + }, + &arg_map + ); + CS_PIN_WRITE(true); +} + +// Send out 8-bit data using the SPI object. +static void lcd_write_data_byte(uint8_t data_byte) +{ + mp_map_t arg_map; + arg_map.all_keys_are_qstrs = true; + arg_map.is_fixed = true; + arg_map.is_ordered = true; + arg_map.used = 0; + arg_map.alloc = 0; + arg_map.table = NULL; + + CS_PIN_WRITE(false); + RS_PIN_WRITE(true); // data + pyb_spi_send( + 2, (mp_obj_t []) { + spi_port, + mp_obj_new_int(data_byte) + }, + &arg_map + ); + CS_PIN_WRITE(true); +} + +// Send out 8-bit data using the SPI object. +static void lcd_write_command(uint8_t data_byte, uint32_t len, uint8_t *dat) +{ + lcd_write_command_byte(data_byte); + for (uint32_t i=0; i width) { + int adjust = rect.w - width; + rect.w -= adjust; + rect.x += adjust / 2; + } else if (rect.w < width) { + int adjust = width - rect.w; + l_pad = adjust / 2; + r_pad = (adjust + 1) / 2; + } + + // Fit Y. + int t_pad = 0, b_pad = 0; + if (rect.h > height) { + int adjust = rect.h - height; + rect.h -= adjust; + rect.y += adjust / 2; + } else if (rect.h < height) { + int adjust = height - rect.h; + t_pad = adjust / 2; + b_pad = (adjust + 1) / 2; + } + + switch (type) { + case LCD_NONE: + return mp_const_none; + case LCD_SHIELD: + lcd_write_command_byte(0x2C); + uint8_t *zero = fb_alloc0(width*2); + uint16_t *line = fb_alloc(width*2); + for (int i=0; ipixels) + + ((rect.y + i) * arg_img->w) + rect.x)); + } + if (r_pad) { + lcd_write_data(r_pad*2, zero); // r_pad < width + } + } + for (int i=0; i + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * LCD Python module. + * + */ +#ifndef __PY_LCD_H__ +#define __PY_LCD_H__ +void py_lcd_init0(); +#endif // __PY_LCD_H__ diff --git a/usr/examples/Example1-LCD-Shield-Demo.py b/usr/examples/Example1-LCD-Shield-Demo.py new file mode 100644 index 000000000..6cd2ea4a4 --- /dev/null +++ b/usr/examples/Example1-LCD-Shield-Demo.py @@ -0,0 +1,15 @@ +# Example 1 - LCD Shield Demo +# +# Note: To run this example you will need a LCD Shield for your OpenMV Cam. +# +# The LCD Shield allows you to view your OpenMV Cam's frame buffer on the go. + +import sensor, image, lcd + +sensor.reset() # Initialize the camera sensor. +sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE +sensor.set_framesize(sensor.QQVGA2) # Special 128x160 framesize for LCD Shield. +lcd.init() # Initialize the lcd screen. + +while(True): + lcd.display(sensor.snapshot()) # Take a picture and display the image.