Skip to content

Commit

Permalink
feat(Examples): Speedup TFT update for MAX78002 CameraIF (#672)
Browse files Browse the repository at this point in the history
  • Loading branch information
vicloginov authored Jul 25, 2023
1 parent 9a649af commit d88c7ee
Show file tree
Hide file tree
Showing 13 changed files with 167 additions and 61 deletions.
2 changes: 2 additions & 0 deletions Examples/MAX78002/CameraIF/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This example supports the following cameras:
* OV7962 (Default)
* HM0360 (MONO), for color use the CameraIF_Debayer example
* OV5640
* OV5642
* HM01B0

To change the camera drivers set the `CAMERA` build configuration variable in [project.mk](project.mk)
Expand All @@ -35,6 +36,7 @@ To change the camera drivers set the `CAMERA` build configuration variable in [p
Additionally, ensure JP38 (DVP CAM PWR) is connected properly.
- OV7692: Connect JP38 to "ON"
- OV5640: Connect JP38 to "ON"
- OV5642: Connect JP38 to "ON"
- HM0360: Connect JP38 to "OFF"

Consult your camera module's power-down logic and the MAX78002EVKIT schematic for other camera modules.
Expand Down
28 changes: 15 additions & 13 deletions Examples/MAX78002/CameraIF/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#include "mipi_camera.h"
#include "utils.h"
#include "dma.h"

#ifdef TFT_ADAFRUIT
#include "adafruit_3315_tft.h"
#endif
Expand Down Expand Up @@ -111,13 +112,19 @@ void process_img(void)
// to an image file
utils_send_img_to_pc(raw, imgLen, w, h, camera_get_pixel_format());
#else
#ifdef TFT_NEWHAVEN
MXC_TFT_Stream(X_START, Y_START, IMAGE_XRES, IMAGE_YRES);
// Stream captured image to TFT display
TFT_SPI_Transmit(raw, IMAGE_XRES * IMAGE_YRES * 2);
#else //#ifdef TFT_NEWHAVEN
#ifndef CAMERA_MONO
// Send the image to TFT
MXC_TFT_ShowImageCameraRGB565(X_START, Y_START, raw, w, h);
MXC_TFT_WriteBufferRGB565(X_START, Y_START, raw, w, h);
#else
MXC_TFT_ShowImageCameraMono(X_START, Y_START, raw, w, h);
#endif // #ifndef CAMERA_MONO
#endif // ##ifndef ENABLE_TFT
#endif //#ifdef TFT_NEWHAVEN
#endif // #ifndef ENABLE_TFT
}

// *****************************************************************************
Expand Down Expand Up @@ -182,21 +189,19 @@ int main(void)
printf("Init TFT\n");
/* Initialize TFT display */
#ifdef TFT_ADAFRUIT
/* Initialize touch screen */
if (MXC_TS_Init(MXC_SPI0, -1, NULL, NULL) != E_NO_ERROR) {
printf("Touch screen initialization failed\n");
if (MXC_TFT_Init(MXC_SPI0, 1, NULL, NULL) != E_NO_ERROR) {
printf("TFT initialization failed\n");
return E_ABORT;
}
#else
/* Initialize TFT display */
if (MXC_TFT_Init(NULL, NULL) != E_NO_ERROR) {
printf("Touch screen initialization failed\n");
printf("TFT initialization failed\n");
return E_ABORT;
}
// Set 0 rotation to match camera orientation
MXC_TFT_SetRotation(ROTATE_0);
#endif
MXC_TFT_SetBackGroundColor(0);
MXC_TFT_SetRotation(ROTATE_90);
MXC_TFT_SetBackGroundColor(4);
#endif

// Setup the camera image dimensions, pixel format and data acquiring details.
Expand Down Expand Up @@ -228,10 +233,7 @@ int main(void)

while (1) {
// Check if image is acquired.
#ifndef STREAM_ENABLE
if (camera_is_image_rcv())
#endif
{
if (camera_is_image_rcv()) {
// Process the image, send it through the UART console.
process_img();

Expand Down
25 changes: 17 additions & 8 deletions Examples/MAX78002/CameraIF/pc_utility/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
## Description

Python scripts can be used to grab images and convert it to .png on PC side
Python scripts can be used to grab images and convert them to `.png` on PC side.
Existing codes was tested and work as expected, tested with python 3.7
You may need to install png and serial and opencv python library on your machine.

To grab camera output run: python grab_image.py <your_comport> <baudrate>
default baudrate is 921600, if you would like to change it do not forget
to update the board side too.
To grab camera output run:

```bash
python grab_image.py <your_comport> <baudrate>
```

The default baudrate is 921600 but if you would like to change it, do not forget to update the board side too.


## Software
Expand All @@ -21,11 +25,16 @@ Universal instructions on building, flashing, and debugging this project can be

## Requirements

These requirements are needed to run the scripts
pySerial
opencv-python
Pillow
These requirements are needed to run the scripts:

- pySerial
- opencv-python
- Pillow

A `requirements.txt` can be found in this directory. Use `pip install -r requirements.txt` to install all dependencies.

## Example Usage

```bash
sudo python3 grab_image.py COM42 921600
```
5 changes: 1 addition & 4 deletions Examples/MAX78002/CameraIF/pc_utility/grab_image.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import serial
import time
from datetime import datetime
import os
import sys
import string
import comManager
import imgConverter
import cv2
Expand Down Expand Up @@ -83,7 +80,7 @@ def print_sep_line( ch ):
#image_file.write(hex_string)
#image_file.close()

image = cv2.imread("image-out.png")
image = cv2.imread("image.png")
cv2.imshow(" ", image)
cv2.waitKey(1)
#exit(0)
14 changes: 4 additions & 10 deletions Examples/MAX78002/CameraIF/pc_utility/imgConverter.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import time
import os
import sys
import string
import sys
import zlib
import struct
from PIL import Image, ImageTk
from PIL import Image

def swap32(i):
return struct.unpack("<I", struct.pack(">I", i))[0]
Expand Down Expand Up @@ -199,7 +193,7 @@ def convert(bytesequence, outputfile, xres, yres, pixelformat):
imagepixels = blackAndWhite_to_rgb(bytesequence)
elif (pixelformat == "BAYER"): #Black and white raw
imagepixels = blackAndWhite_to_rgb(bytesequence)

offset = 0
for i in range(yres):
line = []
Expand All @@ -210,7 +204,7 @@ def convert(bytesequence, outputfile, xres, yres, pixelformat):

print("Output image to file xres {}, yres {}".format(xres,yres), flush=True)

g_pil_image = generate_img("image-out.png", (0, 0, 0), (xres, yres))
g_pil_image = generate_img(outputfile, (0, 0, 0), (xres, yres))
x = 0
y = 0
for i in range(int(len(imagepixels) / 3)):
Expand All @@ -224,6 +218,6 @@ def convert(bytesequence, outputfile, xres, yres, pixelformat):
y = y + 1
if y > (yres - 1):
break
g_pil_image.save("image-out.png")
g_pil_image.save(outputfile)


4 changes: 4 additions & 0 deletions Examples/MAX78002/CameraIF/pc_utility/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
numpy==1.22.4
opencv-python==4.5.5.64
Pillow==9.3.0
pyserial==3.5
6 changes: 3 additions & 3 deletions Examples/MAX78002/CameraIF/project.mk
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
# connected camera. These are some common values.
# For a full list of options for the 'CAMERA' variable,
# see the documentation.
#CAMERA=OV7692
CAMERA=OV5640
CAMERA=OV7692
#CAMERA=OV5640
#CAMERA=OV5642
#CAMERA=HM0360_MONO
#CAMERA=HM01B0
Expand All @@ -27,7 +27,7 @@ endif

# Uncomment to use legacy Adafruit 3315 TFT drivers (TFT = ADAFRUIT)
# Otherwise, default drivers (TFT = NEWHAVEN) will be used for NewHaven NHD-2.4
# TFT = ADAFRUIT
#TFT = ADAFRUIT

# Set a higher optimization level. The increased performance
# is required for the CameraIF DMA code to work within the
Expand Down
47 changes: 29 additions & 18 deletions Libraries/Boards/MAX78002/EvKit_V1/Source/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ void mxc_assert(const char *expr, const char *file, int line)
}

/******************************************************************************/
/**
/**
* NOTE: This weak definition is included to support Push Button interrupts in
* case the user does not define this interrupt handler in their application.
**/
Expand Down Expand Up @@ -186,38 +186,49 @@ void TFT_SPI_Write(uint8_t data, bool cmd)

void TFT_SPI_Transmit(void *src, int count)
{
int tx_count;
uint8_t *buf = (uint8_t *)src;

// TFT and TS share the same SPI bus, and TS will set a lower SPI freq
// So explicity set the TFT speed again before transmitting
MXC_SPI_SetFrequency(TFT_SPI, TFT_SPI_FREQ);

// Software controlled Slave Select
MXC_GPIO_OutClr(TFT_SS_PORT, TFT_SS_PIN);
while (count > 0) {
if (count > 65000)
tx_count = 65000;
else
tx_count = count;

MXC_GPIO_OutSet(TFT_DC_PORT, TFT_DC_PIN);
count -= tx_count;

TFT_SPI->dma = MXC_F_SPI_DMA_TX_FIFO_EN;
// Software controlled Slave Select
MXC_GPIO_OutClr(TFT_SS_PORT, TFT_SS_PIN);

TFT_SPI->ctrl1 = count << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS;
MXC_GPIO_OutSet(TFT_DC_PORT, TFT_DC_PIN);

while (count--) {
while ((TFT_SPI->dma & MXC_F_SPI_DMA_TX_LVL) ==
(MXC_SPI_FIFO_DEPTH << MXC_F_SPI_DMA_TX_LVL_POS)) {}
TFT_SPI->dma = MXC_F_SPI_DMA_TX_FIFO_EN;

*TFT_SPI->fifo8 = *buf++;
// SPI TX byte count is 16-bit value
TFT_SPI->ctrl1 = tx_count << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS;

if (!(TFT_SPI->ctrl0 & MXC_F_SPI_CTRL0_START))
TFT_SPI->ctrl0 |= MXC_F_SPI_CTRL0_START;
}
while (tx_count--) {
while ((TFT_SPI->dma & MXC_F_SPI_DMA_TX_LVL) ==
(MXC_SPI_FIFO_DEPTH << MXC_F_SPI_DMA_TX_LVL_POS)) {}

// MAX78002 Evaluation Kit is designed for firmware control of device select.
// Wait here until done as caller will negate select on return, possibly before FIFO is empty.
while (!(TFT_SPI->intfl & MXC_F_SPI_INTFL_MST_DONE)) {}
*TFT_SPI->fifo8 = *buf++;

TFT_SPI->intfl = TFT_SPI->intfl;
if (!(TFT_SPI->ctrl0 & MXC_F_SPI_CTRL0_START))
TFT_SPI->ctrl0 |= MXC_F_SPI_CTRL0_START;
}

MXC_GPIO_OutSet(TFT_SS_PORT, TFT_SS_PIN);
// MAX78002 Evaluation Kit is designed for firmware control of device select.
// Wait here until done as caller will negate select on return, possibly before FIFO is empty.
while (!(TFT_SPI->intfl & MXC_F_SPI_INTFL_MST_DONE)) {}

TFT_SPI->intfl = TFT_SPI->intfl;

MXC_GPIO_OutSet(TFT_SS_PORT, TFT_SS_PIN);
}
}

void TS_SPI_Init(void)
Expand Down
5 changes: 5 additions & 0 deletions Libraries/Boards/MAX78002/EvKit_V1/board.mk
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ PROJ_CFLAGS+=-DCAMERA_OV5640
else ifeq "$(CAMERA)" "HM01B0"
SRCS += hm01b0.c
PROJ_CFLAGS+=-DCAMERA_HM01B0
PROJ_CFLAGS+=-DCAMERA_MONO
else ifeq "$(CAMERA)" "HM0360_MONO"
SRCS += hm0360_mono.c
PROJ_CFLAGS+=-DCAMERA_HM0360_MONO
Expand All @@ -94,6 +95,10 @@ PROJ_CFLAGS+=-DCAMERA_OV5642
else ifeq "$(CAMERA)" "OV7692"
SRCS += ov7692.c
PROJ_CFLAGS+=-DCAMERA_OV7692
else ifeq "$(CAMERA)" "PAG7920"
SRCS += pag7920.c
PROJ_CFLAGS+=-DCAMERA_PAG7920
PROJ_CFLAGS+=-DCAMERA_MONO
else ifeq "$(CAMERA)" ""
SRCS += ov7692.c
PROJ_CFLAGS+=-DCAMERA_OV7692
Expand Down
33 changes: 32 additions & 1 deletion Libraries/MiscDrivers/Display/adafruit_3315_tft.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
The SPI interface is shared by the TFT and touchscreen controllers.
The touchscreen events generate an external interrupt. The TFT driver
disables interrupts to prevent the touchscreen driver from accessing the
disables interrupts to prevent the touchscreen driver from accessing the
SPI bus during TFT activity. Firmware control of the TFT Data/Command signal
and the use of GPIO as device delect signals bars a interrupt SPI interface.
Expand Down Expand Up @@ -621,6 +621,28 @@ void MXC_TFT_ShowImageCameraRGB565(int x0, int y0, uint8_t *image, int width, in
__enable_irq();
}

/* This function writes an image data line by line, required by most UI libraries like LVGL */
void MXC_TFT_WriteBufferRGB565(int x0, int y0, uint8_t *image, int width, int height)
{
__disable_irq();

if (tft_rotation == ROTATE_0 || tft_rotation == ROTATE_180) {
window(x0, y0, height, width);
} else {
window(x0, y0, width, height);
}

write_command(MEM_WRITE); // send pixel

for (unsigned int y = 0; y < width * height; y += width) { //height
spi_transmit_data_buf(&image[y * 2], width * 2); //width
}

window_max();

__enable_irq();
}

void MXC_TFT_PrintPalette(void)
{
area_t area = { 10, 10, 2, 25 };
Expand Down Expand Up @@ -861,3 +883,12 @@ void MXC_TFT_WriteReg(unsigned char command, unsigned char data)

__enable_irq();
}

void MXC_TFT_Stream(int x0, int y0, int width, int height)
{
if (tft_rotation == ROTATE_0 || tft_rotation == ROTATE_180)
window(x0, y0, height, width);
else
window(x0, y0, width, height);
write_command(MEM_WRITE); // send pixel
}
Loading

0 comments on commit d88c7ee

Please sign in to comment.