瀏覽代碼

添加micropython扩展模块源码

liqiwen 3 年之前
父節點
當前提交
d4efc7bb61
共有 100 個文件被更改,包括 10394 次插入72 次删除
  1. 二進制
      project_0/.settings/.rtmenus
  2. 4 4
      project_0/.settings/projcfg.ini
  3. 28 1
      project_0/Kconfig
  4. 134 60
      project_0/README.md
  5. 138 0
      project_0/applications/board_config.h
  6. 54 0
      project_0/applications/board_config/board_config.c
  7. 2002 0
      project_0/applications/board_config/drv_gc0308.c
  8. 352 0
      project_0/applications/board_config/font.h
  9. 106 0
      project_0/applications/board_config/ili9341.c
  10. 113 0
      project_0/applications/board_config/ili9341.h
  11. 315 0
      project_0/applications/board_config/incbin.h
  12. 89 0
      project_0/applications/board_config/lcd.h
  13. 283 0
      project_0/applications/board_config/lcd_ili9341.c
  14. 10 7
      project_0/driver/Kconfig
  15. 68 0
      project_0/extmods/MicroPython_image_read_me.md
  16. 0 0
      project_0/extmods/README.md
  17. 17 0
      project_0/extmods/SConscript
  18. 40 0
      project_0/extmods/k210/__cmsis_gcc.h
  19. 877 0
      project_0/extmods/k210/bayer.c
  20. 40 0
      project_0/extmods/k210/common.h
  21. 279 0
      project_0/extmods/k210/draw.c
  22. 198 0
      project_0/extmods/k210/fmath.c
  23. 31 0
      project_0/extmods/k210/fmath.h
  24. 1077 0
      project_0/extmods/k210/font.c
  25. 20 0
      project_0/extmods/k210/font.h
  26. 187 0
      project_0/extmods/k210/imlib.c
  27. 698 0
      project_0/extmods/k210/imlib.h
  28. 154 0
      project_0/extmods/k210/imlib_config.h
  29. 47 0
      project_0/extmods/k210/imlib_exts.h
  30. 61 0
      project_0/extmods/k210/modk210.c
  31. 64 0
      project_0/extmods/k210/py_assert.h
  32. 230 0
      project_0/extmods/k210/py_camera.c
  33. 467 0
      project_0/extmods/k210/py_helper.c
  34. 63 0
      project_0/extmods/k210/py_helper.h
  35. 425 0
      project_0/extmods/k210/py_image.c
  36. 36 0
      project_0/extmods/k210/py_image.h
  37. 39 0
      project_0/extmods/k210/py_lcdctl.c
  38. 70 0
      project_0/extmods/k210/py_sha256.c
  39. 40 0
      project_0/extmods/k210/qstrdefscam.h
  40. 277 0
      project_0/extmods/k210/qstrdefsk210.h
  41. 211 0
      project_0/extmods/k210/qstrdefsk210.txt
  42. 413 0
      project_0/extmods/k210/rt_ai_img.c
  43. 128 0
      project_0/extmods/k210/rt_ai_img.h
  44. 14 0
      project_0/extmods/k210/rt_ai_img_utils.h
  45. 49 0
      project_0/extmods/k210/to_rgb565.c
  46. 127 0
      project_0/extmods/k210/yuv.c
  47. 14 0
      project_0/extmods/moddefsmisc.h
  48. 1 0
      project_0/extmods/qstrdefsmisc.h
  49. 二進制
      project_0/images/1-create_prj.png
  50. 二進制
      project_0/images/2-lab2-create.png
  51. 二進制
      project_0/images/20210731112127.png
  52. 二進制
      project_0/images/20210731112411.png
  53. 二進制
      project_0/images/20210731112623.png
  54. 二進制
      project_0/images/3-set_toolchian.png
  55. 二進制
      project_0/images/4-fresh.png
  56. 二進制
      project_0/images/5.png
  57. 二進制
      project_0/images/6.png
  58. 二進制
      project_0/images/SDK-Complete.png
  59. 二進制
      project_0/images/SDK-GCC.png
  60. 二進制
      project_0/images/SDK-K210-RT-DRACO.png
  61. 二進制
      project_0/images/Studio_icon.png
  62. 二進制
      project_0/images/Studio_menu.png
  63. 二進制
      project_0/images/com_ok.png
  64. 二進制
      project_0/images/com_open.png
  65. 二進制
      project_0/images/compile_ok.png
  66. 二進制
      project_0/images/config_window.png
  67. 0 0
      project_0/images/courgette.log
  68. 5 0
      project_0/images/debug.log
  69. 二進制
      project_0/images/download_com.png
  70. 二進制
      project_0/images/download_ok.png
  71. 二進制
      project_0/images/download_studio.png
  72. 二進制
      project_0/images/err_toolchain_path.png
  73. 二進制
      project_0/images/image-20210803120635990.png
  74. 二進制
      project_0/images/image-20210803120820601.png
  75. 二進制
      project_0/images/image-20210805172934786.png
  76. 二進制
      project_0/images/image-20210806152046809.png
  77. 二進制
      project_0/images/image-20210806154157722.png
  78. 二進制
      project_0/images/image-20210806154603636.png
  79. 二進制
      project_0/images/image-20210806154705231.png
  80. 二進制
      project_0/images/image-20210806154816110.png
  81. 二進制
      project_0/images/image-20210806160109511.png
  82. 二進制
      project_0/images/image-20210806160421936.png
  83. 二進制
      project_0/images/image-20210816105954821.png
  84. 二進制
      project_0/images/image-20210816110706258.png
  85. 二進制
      project_0/images/image-20210819110305551.png
  86. 二進制
      project_0/images/image-20210819110338344.png
  87. 二進制
      project_0/images/install-anyway.png
  88. 二進制
      project_0/images/module.png
  89. 二進制
      project_0/images/note_com.png
  90. 二進制
      project_0/images/note_download.png
  91. 二進制
      project_0/images/update-1.png
  92. 二進制
      project_0/images/update-2.png
  93. 二進制
      project_0/images/update-restart.png
  94. 二進制
      project_0/images/updating.png
  95. 二進制
      project_0/images/window_config_set.png
  96. 22 0
      project_0/moddefs.user.extmods.h
  97. 119 0
      project_0/mpy_rt_ai/Module_Design_Description.md
  98. 119 0
      project_0/mpy_rt_ai/README.md
  99. 14 0
      project_0/mpy_rt_ai/SConscript
  100. 25 0
      project_0/mpy_rt_ai/moddefs_rt_ai.h

二進制
project_0/.settings/.rtmenus


+ 4 - 4
project_0/.settings/projcfg.ini

@@ -1,5 +1,5 @@
 #RT-Thread Studio Project Configuration
-#Thu Nov 11 17:49:10 CST 2021
+#Wed May 25 18:36:58 CST 2022
 cfg_version=v3.0
 board_name=k210
 hardware_adapter=KFlash
@@ -7,9 +7,9 @@ tool_chain=gcc
 board_base_nano_proj=False
 project_type=rt-thread
 chip_name=k210
-selected_rtt_version=latest
 bsp_version=1.0.0
-is_use_scons_build=True
-output_project_path=E\:\\RTT\\K210\\Draco
+selected_rtt_version=latest
 project_base_bsp=true
+output_project_path=D\:\\project\\sdk-bsp-draco\\project_0
+is_use_scons_build=True
 project_name=Draco

+ 28 - 1
project_0/Kconfig

@@ -35,4 +35,31 @@ config __STACKSIZE__
 
 config RT_AI_USE_K210
 	bool "RT-AK use the k210-KPU backend"
-	default y
+	default y
+
+menu "mpy-extmods"
+config PRJ_USING_EXTMODS_MISC
+    bool "Enable MPY extmods"
+    select PKG_USING_MICROPYTHON
+    default y
+
+    if PRJ_USING_EXTMODS_MISC
+        menuconfig EXTMODS_MISC_USING_K210
+            bool "Enable K210 extmods"
+            default y
+
+            if EXTMODS_MISC_USING_K210
+                config EXTMODS_K210_LCDCTL
+                    bool "Enable LCD Control"
+                    default y
+                config EXTMODS_K210_DVP
+                    bool "Enable DVP Camera"
+                    select BSP_USING_CAMERA
+                    default y
+            endif
+
+        config PRJ_USING_RT_AK_EXMODS
+            bool "Enable RT-AK MPY module"
+            default y
+    endif
+endmenu

+ 134 - 60
project_0/README.md

@@ -1,4 +1,30 @@
 # Kendryte K210板级支持包说明
+## 前言
+本工程针对基于RT-Draco K210 嵌入式AI教育开发板专门定制。并进行持续更新。
+
+**开发板模块展示:**
+
+![module](/images/module.png)
+
+### 更新记录:
+
+#### 	1.0.0
+
+...
+
+#### 	1.0.1
+
+....
+
+#### 	1.0.2
+
+....
+
+#### 	1.0.3(当前版本)
+
+* 添加RT-AK MicroPython支持
+* 添加MicroPython K210拓展模块及Image模块, 包含摄像头的MicroPython对接.
+* **将文件夹`board_config`进行内置, 避免手动复制.** 此更新版本下用户无需再再复制baord_config文件夹.
 
 ## 1. 简介
 
@@ -20,76 +46,133 @@ Kendryte中文含义为勘智,而勘智取自勘物探智。这颗芯片主要
 
 芯片规格包括如下:
 
-| 硬件 | 描述 |
-| -- | -- |
-|芯片型号| K210 |
-|CPU| 双核RV64GC |
-|主频| 400MHz |
-|片内SRAM| 8MB |
-| 外设 | 内嵌AES与SHA256算法加速器 |
-| | DVP、JTAG、OTP、FPIOA、GPIO、UART、SPI、RTC、I²S、I²C、WDT、Timer与PWM |
+| 硬件     | 描述                                                         |
+| -------- | ------------------------------------------------------------ |
+| 芯片型号 | K210                                                         |
+| CPU      | 双核RV64GC                                                   |
+| 主频     | 400MHz                                                       |
+| 片内SRAM | 8MB(6M通用+2M AI)                                          |
+| 外设     | DVP、JTAG、OTP、FPIOA、GPIO、UART、SPI、RTC、I²S、I²C、WDT、Timer与PWM、内嵌AES与SHA256算法加速器 |
+
+
+## 2. Studio开发环境
+
+端侧部署分为工程准备、编译链接、系统烧录三步。工程准备基于 RT-AK 的 K210 插件,详见实验一。
+
+下载并安装 RT-Thread Studio完成后,下面实现一个简单的工程创建的流程:
+
+### Studio配置
+
+此章节为更新Studio到最新版本,并配置工程模板教程,若用户当前Studio环境中没有 `K210-RT-DRACO` sdk的模板工程,可参考此章节进行模板导入。若此前已经进行过导入,则可过此节直接进行工程创建。
+
+1. 打开桌面上的RT-Thread-Studio。
+
+   ![Studio_icon.png](images/Studio_icon.png)
+
+2. 若Studio弹框提示 `可用的更新`,一直点击下一步。
+
+   ![update-1](images/update-1.png)
+
+   直到勾选 `接收许可协议`,然后点击完成:
+
+   ![update-2](images/update-2.png)
+
+3. 若安装过程中提示如下图所示,点击 `install anyway`:
 
-## 2. 编译说明
+   ![install-anyway](images/install-anyway.png)
 
-编译 K210,需要有 RT-Thread 的代码,因为 K210 的 sdk 是以软件包方式,所以需要在 bsp/k210 下做软件包更新。注意,需要使用 latest 的 RT-Thread 源码和 Latest 的软件包,软件包在menuconfig中的配置路径如下:
+   可在右下角查看安装正在进行:
 
-```
-RT-Thread online packages ---> peripheral libraries and drivers ---> kendryte K210 SDK package for rt-thread
-```
+   ![updating](images/updating.png)
 
-最新的 k210 SDK 使用了 C++17 编写了部分代码,因此需要打开 C++ 组件,C++组件在menuconfig中的配置路径如下:
+4. 安装完成后提示 `Restart Now`点击进行重启:
 
-```
-RT-Thread Components --->  C++ features
-```
+   ![update-restart](images/update-restart.png)
 
-Windows下推荐使用[env工具][1],然后在console下进入bsp/k210目录中,运行:
+5. 点击Studio界面菜单栏下方的 `SDK Manager->勾选K210-RT-DRACO`:
 
-    cd bsp/k210
-    menuconfig # 在软件包中选择最新的 k210 SDK
-    pkgs --update
+   ![sdk-manager](images/SDK-K210-RT-DRACO.png)
 
-如果在Linux平台下,可以先执行
+   然后继续勾选编译器和调试器如下图:
 
-    scons --menuconfig
+   ![SDK-GCC](images/SDK-GCC.png)
 
-它会自动下载env相关脚本到~/.env目录,然后执行
+   最后点击 `安装资源包` 等待安装完成:
 
-    source ~/.env/env.sh
-    
-    cd bsp/k210
-    pkgs --update
-下载risc-v的工具链,[下载地址](https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases)  
-    
-更新完软件包后,在`rtconfig.py`中将risc-v工具链的本地路径加入文档。
-注:  
-1. 工具链建议使用上方提供的,`kendryte的官方工具链`会报浮点类型不兼容的错误,`risc-v工具链8.2.0之前的版本`会出现头文件不兼容的问题。
-2. 网上传需要开启C++ 17,认为k210的神经网络编译器nncase多数语法由C++ 17,故需要开启C++ 17。个人认为没有必要,nncase是在PC端独立使用的,
-作用是将神经网络模型转为kmodel格式,此格式文件为已经编译的二进制文件。([shentalon](13212105191@163.com)注)  
+   ![SDK-Complete](images/SDK-Complete.png)
 
-然后执行scons编译:  
+### 从模板创建工程
 
-    set RTT_EXEC_PATH=your_toolchains
-    scons
+1. 打开桌面上的RT-Thread-Studio。
 
-来编译这个板级支持包。如果编译正确无误,会产生rtthread.elf、rtthread.bin文件。其中rtthread.bin需要烧写到设备中进行运行。  
-注:如果初次使用编译报错,可能是使用的SDK过老,使用`menuconfig`命令,在→ RT-Thread online packages → peripheral libraries 
-and drivers → the kendryte-sdk package for rt-thread中将SDK改为latest版本即可。
-## 3. 烧写及执行
+   ![Studio_icon.png](images/Studio_icon.png)
 
-连接好串口,然后使用[K-Flash](https://kendryte.com/downloads/)工具进行烧写bin文件
+2. 打开Studio界面后,点击左上角 `文件->新建->RT-Thread项目`。
 
-![K-Flash](images/flash.png)
+   ![1-create_prj.png](images/1-create_prj.png)
 
-### 3.1 运行结果
+3. 在新建项目界面选择 `基于开发板` ,输入 `Project name`和要创建工程的位置路径,然后点击 `完成`。
 
-如果编译 & 烧写无误,当复位设备后,会在串口上看到RT-Thread的启动logo信息:
+   ![2-lab2-create.png](images/2-lab2-create.png)
 
-![terminal](images/k210.png)
+4. 每次创建完新的工程或添加新的代码文件或软件包后,进行刷新工程可将文件添加到工程目录中。操作如下所示,先右键点击项目,点击更新软件包,然后再次邮件点击项目,点击刷新:
 
-如果是K210-test_v0.2开发板,可以用如下命令来打开串口:
+   ![4-fresh.png](images/4-fresh.png)
 
-    python -m serial.tools.miniterm --rts 0 --dtr 0 COM9 115200
+5. 若代码中注释出现乱码现象,可以点击界面左上角 `窗口->首选项`。如下图所示:
+
+   ![5.png](images/config_window.png)
+
+   点击 `工作空间`,设置 `文本文件编码` ,编码设置为 `UTF-8`即可。
+
+   ![6.png](images/window_config_set.png)
+
+6. 工程创建完成,IDE界面基本功能按钮如下图:
+
+   ![image-20211105135453338](images/Studio_menu.png)
+
+## 3. 编译与下载
+
+
+   1. 参考4.2节中,界面展示的说明。点击上方编译图标进行编译:
+
+      ![compile_ok](images/compile_ok.png)
+
+   2. 点击下载,第一次下载通常会弹出端口选择框,进行选择即可:
+
+      ![download_com](images/download_com.png)
+
+      下载成功如下所示:
+
+      ![download_ok](images/download_ok.png)
+      
+      ***注意: 若点击下载时控制台已经开始下载时再次弹出串口选择框,则需要点击取消,或者可能出现串口占用。***
+      
+      ![note_com](images/note_com.png)
+      
+   3. 下载完成后打开串口,可查看交互信息:
+
+      ![com_open](images/com_open.png)
+
+   4. 串口打开成功,打印出RT-Thread LOGO和msh命令行:
+
+      ![com_ok](images/com_ok.png)
+      
+      ***注意: 若下载时出现 `请选择正确串口`,可能是由于串口被占用导致,需检查并关闭占用串口的窗口。***
+      
+      ![note_download](images/note_download.png)
+
+
+   **其它相关工具参考链接:**
+   交叉编译工具链,[下载地址 https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/tag/v8.3.0-1.2 ](https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/tag/v8.3.0-1.2)
+
+   或者: [https://github.com/kendryte/K210-Micropython-OpenMV/tree/master/toolchain](https://github.com/kendryte/K210-Micropython-OpenMV/tree/master/toolchain)
+
+   固件下载工具 [下载地址 https://github.com/kendryte/kendryte-flash-windows/releases/download/v0.4.1/K-Flash.zip](https://github.com/kendryte/kendryte-flash-windows/releases/download/v0.4.1/K-Flash.zip)
+
+   `K-Flash` 下载工具使用截图
+
+   ![K-Flash](images/flash.png)
 
 ## 4. 驱动支持情况及计划
 
@@ -99,20 +182,11 @@ and drivers → the kendryte-sdk package for rt-thread中将SDK改为latest版
 
 ## 5. 联系人信息
 
-维护人:[bernard](https://github.com/BernardXiong)
-
-## 6. 注意事项
+罗齐熙: 13632716562
 
-在进行系统menuconfig配置时,以下项是必选的
 
-| 配置项 | 强制配置值 |
-| -----  | --------- |
-| Alignment size for CPU architecture data access | 8 |
-| The stack size of idle thread | > 1024 |
-| the device name for console | "uarths" |
-| Set main thread stack size | 4096 |
 
-## 7. 参考
+## 6. 参考
 
 * 芯片[datasheet][2]
 

+ 138 - 0
project_0/applications/board_config.h

@@ -0,0 +1,138 @@
+#ifndef _BOARD_CONFIG_
+#define _BOARD_CONFIG_
+#include "fpioa.h"
+#include "gpiohs.h"
+#include "plic.h"
+#include "sysctl.h"
+#include "uarths.h"
+#include "dvp.h"
+#include <rtthread.h>
+
+/* ======> please config following this <====*/
+#define  CAMERA_USING_OV5640  0
+#define  CAMERA_USING_OV2640  0
+#define  CAMERA_USING_GC0308  1
+
+#ifndef BSP_USING_LCD
+#define  LCD_USING_NT35310    0
+#define  LCD_USING_ST7789     0
+#define  LCD_USING_ILI9341    1
+#endif
+
+#define  BOARD_KD233        0
+#define  BOARD_LICHEEDAN    0
+#define  BOARD_K61          0
+#define  YB_DKA01           0
+#define  EDU_KIT            1
+/* ====================================== */
+#if CAMERA_USING_OV5640
+#define CAMERA "ov5640"
+#elif CAMERA_USING_OV2640
+#define CAMERA "ov2640"
+#elif CAMERA_USING_GC0308
+#define CAMERA "gc0308"
+#endif
+
+#if CAMERA_USING_OV5640 && CAMERA_USING_OV2640 && CAMERA_USING_GC0308
+    #error "CAMERA_USING_XXX be selected >= 2"
+#endif
+#if LCD_USING_NT35310 && LCD_USING_ST7789
+    #error "LCD_USING_XXX be selected 2"
+#endif
+#if BOARD_KD233 && YB_DKA01
+    #error "BOARD be selected 2"
+#endif
+
+#if YB_DKA01 || BOARD_LICHEEDAN
+
+/* Camera */
+#define DVP_PIN_PCLK           (47)
+#define DVP_PIN_XCLK           (46)
+#define DVP_PIN_HSYNC          (45)
+#define DVP_PIN_PWDN           (44)
+#define DVP_PIN_VSYNC          (43)
+#define DVP_PIN_RST            (42)
+#define DVP_PIN_SCL            (41)
+#define DVP_PIN_SDA            (40)
+
+/* LCD */
+#define LCD_PIN_CS             (36)
+#define LCD_PIN_RST            (37)
+#define LCD_PIN_RS             (38)
+#define LCD_PIN_WR             (39)
+
+#define LCD_RST_GPIONUM        (3)
+#define LCD_RS_GPIONUM         (2)
+#define FUNC_LCD_CS             (FUNC_SPI0_SS3)
+#define FUNC_LCD_RST            (FUNC_GPIOHS0 + LCD_RST_GPIONUM)
+#define FUNC_LCD_RS             (FUNC_GPIOHS0 + LCD_RS_GPIONUM)
+#define FUNC_LCD_WR             (FUNC_SPI0_SCLK)
+
+#elif BOARD_KD233
+/* Camera */
+#define DVP_PIN_PCLK           (15)
+#define DVP_PIN_XCLK           (14)
+#define DVP_PIN_HSYNC          (17)
+#define DVP_PIN_PWDN           (13)
+#define DVP_PIN_VSYNC          (12)
+#define DVP_PIN_RST            (11)
+#define DVP_PIN_SCL            (10)
+#define DVP_PIN_SDA            (9)
+/* LCD */
+//pin
+#define LCD_PIN_CS             (6)
+// #define LCD_PIN_RST            (37)
+#define LCD_PIN_RS             (8)
+#define LCD_PIN_WR             (7)
+//func
+#define FUNC_LCD_CS             (FUNC_SPI0_SS3)
+// #define FUNC_LCD_RST            (FUNC_GPIOHS0 + LCD_RST_GPIONUM)
+#define FUNC_LCD_RS             (FUNC_GPIOHS0 + 2)
+#define FUNC_LCD_WR             (FUNC_SPI0_SCLK)
+
+#elif EDU_KIT
+/* Camera */
+#define DVP_PIN_PCLK           (8)
+#define DVP_PIN_XCLK           (9)
+#define DVP_PIN_HSYNC          (10)
+#define DVP_PIN_PWDN           (11)
+#define DVP_PIN_VSYNC          (12)
+#define DVP_PIN_RST            (13)
+#define DVP_PIN_SCL            (14)
+#define DVP_PIN_SDA            (15)
+#define DVP_PIN_SDA0           (0)
+/* LCD */
+//pin
+#define LCD_PIN_CS             (43)
+#define LCD_PIN_RST            (41)
+#define LCD_PIN_RS             (44)
+#define LCD_PIN_WR             (45)
+#define LCD_PIN_BACKLIGHT      (47)  
+#define LCD_BACKLIGHT_ACTIVE   (1)
+//func
+#define LCD_BACKLIGHT_GPIONUM  (10)
+#define LCD_RST_GPIONUM        (11)
+#define LCD_RS_GPIONUM         (12)
+#define FUNC_LCD_CS             (FUNC_SPI0_SS3)
+#define FUNC_LCD_RST            (FUNC_GPIOHS0 + LCD_RST_GPIONUM)
+#define FUNC_LCD_RS             (FUNC_GPIOHS0 + LCD_RS_GPIONUM)
+#define FUNC_LCD_WR             (FUNC_SPI0_SCLK)
+#define FUNC_LCD_BACKLIGHT      (FUNC_GPIOHS0 + LCD_BACKLIGHT_GPIONUM)
+
+#endif
+
+void io_mux_init(void);
+void io_set_power(void);
+void camera_init(void);
+
+static inline void __pixel_reversal(uint16_t *pix, int width, int height){ 
+    uint16_t tmp;               
+    for (int i = 0; i < (width*height);i += 2)  
+    { 
+        tmp = pix[i];           
+        pix[i] = pix[i + 1];            
+        pix[i + 1] = tmp;      
+    }               
+}
+
+#endif

+ 54 - 0
project_0/applications/board_config/board_config.c

@@ -0,0 +1,54 @@
+#include <board_config.h>
+
+void io_mux_init(void) {
+#if BOARD_LICHEEDAN || YB_DKA01
+    fpioa_set_function(LCD_PIN_RST, FUNC_LCD_RST);
+    // sysctl_set_spi0_dvp_data(1);
+#endif
+    /* Init DVP IO map and function settings */
+    fpioa_set_function(DVP_PIN_RST, FUNC_CMOS_RST);
+    fpioa_set_function(DVP_PIN_PWDN, FUNC_CMOS_PWDN);
+    fpioa_set_function(DVP_PIN_XCLK, FUNC_CMOS_XCLK);
+    fpioa_set_function(DVP_PIN_VSYNC, FUNC_CMOS_VSYNC);
+    fpioa_set_function(DVP_PIN_HSYNC, FUNC_CMOS_HREF);
+    fpioa_set_function(DVP_PIN_PCLK, FUNC_CMOS_PCLK);
+    fpioa_set_function(DVP_PIN_SCL, FUNC_SCCB_SCLK);
+    fpioa_set_function(DVP_PIN_SDA, FUNC_SCCB_SDA);
+#ifndef BSP_USING_LCD
+    /* Init SPI IO map and function settings */
+    fpioa_set_function(LCD_PIN_RS, FUNC_LCD_RS);
+    fpioa_set_function(LCD_PIN_CS, FUNC_LCD_CS);
+    fpioa_set_function(LCD_PIN_WR, FUNC_LCD_WR);
+    #ifdef LCD_PIN_BACKLIGHT
+    fpioa_set_function(LCD_PIN_BACKLIGHT, FUNC_LCD_BACKLIGHT);
+    gpiohs_set_drive_mode(LCD_BACKLIGHT_GPIONUM, GPIO_DM_OUTPUT);
+    gpiohs_set_pin(LCD_BACKLIGHT_GPIONUM, LCD_BACKLIGHT_ACTIVE);
+    #endif
+    // 使能SPI0和DVP
+    sysctl_set_spi0_dvp_data(1);
+#endif
+// #endif
+}
+
+void io_set_power(void) {
+#if BOARD_LICHEEDAN || YB_DKA01
+    /* Set dvp and spi pin to 1.8V */
+    sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
+#elif BOARD_KD233
+    /* Set dvp and spi pin to 1.8V */
+    sysctl_set_power_mode(SYSCTL_POWER_BANK0, SYSCTL_POWER_V18);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18);
+#elif EDU_KIT
+    /* Set dvp and spi pin to 1.8V */
+    sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V33);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V33);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK3, SYSCTL_POWER_V33);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK4, SYSCTL_POWER_V33);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK5, SYSCTL_POWER_V33);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V33);
+    sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V33);
+#endif
+}
+

+ 2002 - 0
project_0/applications/board_config/drv_gc0308.c

@@ -0,0 +1,2002 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "dvp.h"
+#include "fpioa.h"
+#include "i2c.h"
+#include "stdio.h"
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "syslog.h"
+#include "board_config.h"
+#include <stdint.h>
+#if CAMERA_USING_GC0308
+
+// #define DVP_PIN_SDA 15
+// #define DVP_PIN_SDA0 0
+// #define DVP_PIN_SCL 14
+
+#define LOGE(tag, format, ...) rt_kprintf("[LOGE]" tag format, ##__VA_ARGS__)
+#define LOGW(tag, format, ...) rt_kprintf("[LOGW]" tag format, ##__VA_ARGS__)
+#define LOGI(tag, format, ...) rt_kprintf("[LOGI]" tag format, ##__VA_ARGS__)
+#define LOGD(tag, format, ...) rt_kprintf("[LOGD]" tag format, ##__VA_ARGS__)
+#define LOGV(tag, format, ...) rt_kprintf("[LOGV]" tag format, ##__VA_ARGS__)
+#define TAG "GC0328"
+typedef enum
+{
+    AWB_MODE_OFF,
+    AWB_MODE_AUTO,
+    AWB_MODE_CLOUDY_DAYLIGHT,
+    AWB_MODE_DAYLIGHT,
+    AWB_MODE_INCANDESCENT,
+    AWB_MODE_TUNGSTEN,
+    AWB_MODE_FLUORESCENT
+} AWB_MODE_TYPE;
+
+typedef enum
+{
+    MEFFECT_OFF,
+    MEFFECT_SEPIA,
+    MEFFECT_NEGATIVE,
+    MEFFECT_SEPIAGREEN,
+    MEFFECT_SEPIABLUE,
+    MEFFECT_MONO,
+} MEFFECT_MODE_TYPE;
+
+typedef enum
+{
+    AE_FLICKER_MODE_50HZ,
+    AE_FLICKER_MODE_60HZ
+} AE_FLICKER_MODE_TYPE;
+
+typedef enum
+{
+    AE_EV_COMP_n13,
+    AE_EV_COMP_n10,
+    AE_EV_COMP_n07,
+    AE_EV_COMP_n03,
+    AE_EV_COMP_00,
+    AE_EV_COMP_03,
+    AE_EV_COMP_07,
+    AE_EV_COMP_10,
+    AE_EV_COMP_13
+} AE_EV_COMP_TYPE;
+
+typedef enum
+{
+    GammaLvl_01,
+    GammaLvl_02,
+    GammaLvl_03,
+    GammaLvl_04,
+    GammaLvl_05
+} GAMMALVL_TYPE;
+
+typedef enum
+{
+    cam_false,
+    cam_true
+} cam_bool_type;
+
+typedef enum
+{
+    NIR_CAM = 0,
+    RGB_CAM,
+    MAX_CAM
+} CAM_TYPE;
+
+struct measure_win
+{
+	int x1;
+	int y1;
+	int x2;
+	int y2;
+};
+void gc0308_gamma_select(uint8_t num, GAMMALVL_TYPE glvl);
+cam_bool_type gc0308_set_param_wb(uint8_t num, AWB_MODE_TYPE para);
+cam_bool_type gc0308_set_param_effect(uint8_t num, MEFFECT_MODE_TYPE para);
+cam_bool_type gc0308_set_param_banding(uint8_t num, AE_FLICKER_MODE_TYPE para);
+cam_bool_type gc0308_set_param_exposure(uint8_t num, AE_EV_COMP_TYPE para);
+void gc0308_set_test_patternmode(uint8_t num, cam_bool_type enable);
+void gc0308_write_more_registers(uint8_t num);
+void gc0308_read_all_reg_setting(uint8_t num);
+void gc0308_set_measure_win(CAM_TYPE type,int x1, int y1, int x2, int y2);
+
+int gc0308_init(void);
+void open_gc0308(CAM_TYPE type);
+
+void change_gc0308(CAM_TYPE type);
+void enable_gc0308_output(CAM_TYPE type);
+uint8_t gc0308_get_y_value(CAM_TYPE type);
+
+void dvp_face_set_win(int x1, int y1, int x2, int y2);
+void dvp_face_get_win(struct measure_win *win);
+
+#define SENSOR_OUTPUT_W		320
+#define SENSOR_OUTPUT_H		240
+
+#define SENSOR_EXP_WIN_W	200
+#define SENSOR_EXP_WIN_H	180
+#define SENSOR_EXP_WIN_W_OFFSET 	(-30)
+#define SENSOR_EXP_WIN_W_OFFSET2	(30)
+
+#define EXP_WIN_RECT_X1 (SENSOR_OUTPUT_W - SENSOR_EXP_WIN_W) / 2 + SENSOR_EXP_WIN_W_OFFSET  //90
+#define EXP_WIN_RECT_Y1 (SENSOR_OUTPUT_H - SENSOR_EXP_WIN_H) / 2 //30
+#define EXP_WIN_RECT_X2 (EXP_WIN_RECT_X1 + SENSOR_EXP_WIN_W + SENSOR_EXP_WIN_W_OFFSET2) //290
+#define EXP_WIN_RECT_Y2 (EXP_WIN_RECT_Y1 + SENSOR_EXP_WIN_H) //210
+
+#define ADD_SENSOR_EXPOSURE_WIN
+
+#define  READ_REG_TEST  (0)
+#if (READ_REG_TEST)
+void gc0308_reg_read_test_PAGE0(uint8_t num);
+void gc0308_reg_read_test_PAGE1(uint8_t num);
+#endif
+#define GC0308_ADDR                     0X42
+
+void gc0308_read_all_reg_setting(uint8_t num);
+
+
+static const uint8_t gc0308_config[][2] =
+{
+#if 0
+    {0xFE, 0x80},
+    {0xFE, 0x00},
+
+    {0x14, 0x12},
+    {0x1A, 0x2A},
+    {0x1C, 0x49},
+    {0x1D, 0x9A},
+    {0x1E, 0x61},
+    {0x1F, 0x15},
+    // {0x22, 0x46},  //crop window mode enable
+    {0x24, 0xA6},
+    {0x26, 0x3F},
+    {0x2E, 0x00},
+
+    {0xd2, 0x10},    // close AEC
+    {0x22, 0x55},    // close AWB
+    {0x5a, 0x56},
+    {0x5b, 0x40},
+    {0x5c, 0x4a},
+    {0x22, 0x57},   // Open AWB
+    {0x01, 0xfa},
+    {0x02, 0x70},
+    {0x0f, 0x01},
+
+    {0x03, 0x01},
+    {0x04, 0x2c},
+
+    {0xe2, 0x00},   //anti-flicker step [11:8]
+    {0xe3, 0x64},    //anti-flicker step [7:0]
+
+    {0xe4, 0x02},    //exp level 0  16.67fps
+    {0xe5, 0x58},
+    {0xe6, 0x03},    //exp level 1  12.5fps
+    {0xe7, 0x20},
+    {0xe8, 0x04},    //exp level 2  8.33fps
+    {0xe9, 0xb0},
+    {0xea, 0x09},    //exp level 3  4.00fps
+    {0xeb, 0xc4},
+    {0x05, 0x00},
+    {0x06, 0x00},
+    {0x07, 0x00},
+    {0x08, 0x00},
+    {0x09, 0x01},
+    {0x0a, 0xe8},
+    {0x0b, 0x02},
+    {0x0c, 0x88},
+    {0x0d, 0x02},
+    {0x0e, 0x02},
+    {0x10, 0x22},
+    {0x11, 0xfd},
+    {0x12, 0x2a},
+    {0x13, 0x00},
+    {0x14, 0x10},
+    {0x15, 0x0a},
+    {0x16, 0x05},
+    {0x17, 0x01},
+    {0x18, 0x44},
+    {0x19, 0x44},
+
+    {0x1a, 0x1e},
+    {0x1b, 0x00},
+    {0x1c, 0xc1},
+    {0x1d, 0x08},
+    {0x1e, 0x60},
+    {0x1f, 0x14},
+
+    {0xFE, 0x01},
+    {0x54, 0x22},
+    {0xFE, 0x00},
+    {0x25, 0x00},
+    {0x1f, 0x14}
+
+#else
+    /*****************************************************/
+    {0xfe, 0x80},
+    {0xFE, 0x01},
+    {0x54, 0x22},
+
+    {0xfe, 0x00},    // set page0
+
+    {0xd2, 0x10},    // close AEC
+    {0x22, 0x55},    // close AWB
+
+	{ 0x03, 0x01 },
+//	{ 0x04, 0x2c },
+	{ 0x04, 0xf4 },
+	{ 0x5a, 0x56 },
+	{ 0x5b, 0x40 },
+	{ 0x5c, 0x4a },
+
+    {0x22, 0x57},    // Open AWB
+
+    {0x01, 0xfa},
+    {0x02, 0x70},
+    {0x0f, 0x01},
+
+
+    {0xe2, 0x00},    //anti-flicker step [11:8]
+    {0xe3, 0x64},    //anti-flicker step [7:0]
+
+    {0xe4, 0x02},    //exp level 1  16.67fps
+    {0xe5, 0x58},
+    {0xe6, 0x03},    //exp level 2  12.5fps
+    {0xe7, 0x20},
+    {0xe8, 0x04},    //exp level 3  8.33fps
+    {0xe9, 0xb0},
+    {0xea, 0x09},    //exp level 4  4.00fps
+    {0xeb, 0xc4},
+
+    //{0xec , 0x20},
+
+    //  {0x05 , 0x00},              //默认值, 0x05-0x0c register not set(default value),window output is default to 648*488(640*480)
+    //  {0x06 , 0x00},
+    //  {0x07 , 0x00},
+    //  {0x08 , 0x00},
+    //  {0x09 , 0x01},
+    //  {0x0a , 0xe8},
+    //  {0x0b , 0x02},
+    //  {0x0c , 0x88},
+    //  {0x0d , 0x02},
+    {0x0e, 0x02},
+    //  {0x10 , 0x22},
+    {0x11, 0xfd},
+    {0x12, 0x2a},
+    //  {0x13 , 0x00},
+    /*{0x14 , 0x10}, */
+    //  {0x15 , 0x0a},
+    //  {0x16 , 0x05},
+    {0x17, 0x01},
+    //  {0x18 , 0x44},
+    //  {0x19 , 0x44},
+    {0x1a, 0x1e},
+    //  {0x1b , 0x00},
+    {0x1c, 0xc1},
+    {0x1d, 0x08},
+    {0x1e, 0x60},
+    {0x1f, 0x17},
+
+
+    //  {0x20 , 0xff},
+    {0x21, 0xf8},
+    {0x22, 0x57},
+    {0x24, 0xa6},
+    {0x25, 0x0f},  //default enable dvp data output,0x00 is disable @tration
+
+    //output sync_mode
+    {0x26, 0x02},    //0x03  20101016 zhj
+    //  {0x2f , 0x01},
+    {0x30, 0xf7},
+    {0x31, 0x50},
+    {0x32, 0x00},
+    {0x39, 0x04},
+    {0x3a, 0x18},
+    {0x3b, 0x20},
+    {0x3c, 0x00},
+    {0x3d, 0x00},
+    {0x3e, 0x00},
+    {0x3f, 0x00},
+    {0x50, 0x10},
+    {0x53, 0x82},
+    //  {0x54 , 0x80},
+    //  {0x55 , 0x80},
+    {0x56, 0x82},
+    //  {0x8b , 0x40},
+    //  {0x8c , 0x40},
+    //  {0x8d , 0x40},
+    {0x8e, 0x2e},
+    {0x8f, 0x2e},
+    {0x90, 0x2e},
+    {0x91, 0x3c},
+    {0x92, 0x50},
+    //  {0x5d , 0x12},
+    //  {0x5e , 0x1a},
+    //  {0x5f , 0x24},
+    //  {0x60 , 0x07},
+    {0x61, 0x15},
+    {0x62, 0x08},
+    {0x64, 0x03},
+    {0x66, 0xe8},
+    {0x67, 0x86},
+    {0x68, 0xa2},
+    {0x69, 0x18},
+    {0x6a, 0x0f},
+    {0x6b, 0x00},
+    {0x6c, 0x5f},
+    {0x6d, 0x8f},
+    {0x6e, 0x55},
+    {0x6f, 0x38},
+    {0x70, 0x15},
+    {0x71, 0x33},
+    {0x72, 0xdc},
+    //  {0x73 , 0x80},
+    {0x74, 0x02},
+    //  {0x75 , 0x3f},
+    {0x76, 0x02},
+    {0x77, 0x36},
+    //  {0x78 , 0x88},
+    {0x79, 0x81},
+    {0x7a, 0x81},
+    //  {0x7b , 0x22},
+    {0x7c, 0xff},
+    {0x93, 0x48},
+    {0x94, 0x00},
+    {0x95, 0x05},
+    {0x96, 0xe8},
+    {0x97, 0x40},
+    {0x98, 0xf0},
+    {0xb1, 0x38},
+    {0xb2, 0x38},
+    {0xbd, 0x38},
+    {0xbe, 0x36},
+    {0xd0, 0xc9},
+    {0xd1, 0x10},
+    //{0xd2 , 0x90},
+    {0xd3, 0x80},
+    //  {0xd5 , 0xf2},
+    {0xd6, 0x16},
+    {0xdb, 0x92},
+    {0xdc, 0xa5},
+    {0xdf, 0x23},
+    {0xd9, 0x00},
+    {0xda, 0x00},
+    {0xe0, 0x09},
+
+    {0xed, 0x04},
+    {0xee, 0xa0},
+    {0xef, 0x40},
+    //  {0x80 , 0x03},
+    //  {0x9F , 0x10},
+    //  {0xA0 , 0x20},
+    //  {0xA1 , 0x38},
+    //  {0xA2 , 0x4E},
+    //  {0xA3 , 0x63},
+    //  {0xA4 , 0x76},
+    //  {0xA5 , 0x87},
+    //  {0xA6 , 0xA2},
+    //  {0xA7 , 0xB8},
+    //  {0xA8 , 0xCA},
+    //  {0xA9 , 0xD8},
+    //  {0xAA , 0xE3},
+    //  {0xAB , 0xEB},
+    //  {0xAC , 0xF0},
+    //  {0xAD , 0xF8},
+    //  {0xAE , 0xFD},
+    //  {0xAF , 0xFF},
+    {0xc0, 0x00},
+    {0xc1, 0x10},
+    {0xc2, 0x1C},
+    {0xc3, 0x30},
+    {0xc4, 0x43},
+    {0xc5, 0x54},
+    {0xc6, 0x65},
+    {0xc7, 0x75},
+    {0xc8, 0x93},
+    {0xc9, 0xB0},
+    {0xca, 0xCB},
+    {0xcb, 0xE6},
+    {0xcc, 0xFF},
+    {0xf0, 0x02},
+    {0xf1, 0x01},
+    {0xf2, 0x01},
+    {0xf3, 0x30},
+    {0xf9, 0x9f},
+    {0xfa, 0x78},
+
+    //---------------------------------------------------------------
+    {0xfe, 0x01}, // set page1
+
+    //  {0x00 , 0xf5},
+    {0x02, 0x1a},
+    {0x0a, 0xa0},
+    //  {0x0b , 0x60},
+    {0x0c, 0x08},
+    {0x0e, 0x4c},
+    {0x0f, 0x39},
+    //  {0x11 , 0x3f},
+    {0x12, 0x72},
+    {0x13, 0x13},
+    /*  {0x14 , 0x42},
+        {0x15 , 0x43},
+        {0x16 , 0xc2},
+        {0x17 , 0xa8},
+        {0x18 , 0x18},
+        {0x19 , 0x40},
+        {0x1a , 0xd0},
+        {0x1b , 0xf5},
+        */
+    /*  {0x70 , 0x40},
+        {0x71 , 0x58},
+        {0x72 , 0x30},
+        {0x73 , 0x48},
+        {0x74 , 0x20},
+        {0x75 , 0x60},
+        {0x77 , 0x20},
+        {0x78 , 0x32},
+    */
+    /*  {0x30 , 0x03},
+        {0x31 , 0x40},
+        {0x32 , 0xe0},
+        {0x33 , 0xe0},
+        {0x34 , 0xe0},
+        {0x35 , 0xb0},
+        {0x36 , 0xc0},
+        {0x37 , 0xc0},
+        {0x38 , 0x04},
+        {0x39 , 0x09},
+        {0x3a , 0x12},
+        {0x3b , 0x1C},
+        {0x3c , 0x28},
+        {0x3d , 0x31},
+        {0x3e , 0x44},
+        {0x3f , 0x57},
+        */
+    /*  {0x40 , 0x6C},
+        {0x41 , 0x81},
+        {0x42 , 0x94},
+        {0x43 , 0xA7},
+        {0x44 , 0xB8},
+        {0x45 , 0xD6},
+        {0x46 , 0xEE},
+        {0x47 , 0x0d},
+        */
+    {0xfe, 0x00},  // set page0
+
+    //-----------Update the registers 2010/07/06-------------//
+    //Registers of Page0
+    {0xfe, 0x00},  // set page0
+    {0x10, 0x26},
+    {0x11, 0x0d},   // fd,modified by mormo 2010/07/06
+    {0x1a, 0x2a},   // 1e,modified by mormo 2010/07/06
+
+    {0x1c, 0x49},  // c1,modified by mormo 2010/07/06
+    {0x1d, 0x9a},  // 08,modified by mormo 2010/07/06
+    {0x1e, 0x61},  // 60,modified by mormo 2010/07/06
+
+    {0x3a, 0x20},
+
+    {0x50, 0x14},   // 10,modified by mormo 2010/07/06
+    {0x53, 0x80},
+    {0x56, 0x80},
+
+    {0x8b, 0x20},  //LSC
+    {0x8c, 0x20},
+    {0x8d, 0x20},
+    {0x8e, 0x14},
+    {0x8f, 0x10},
+    {0x90, 0x14},
+
+    {0x94, 0x02},
+    {0x95, 0x07},
+    {0x96, 0xe0},
+
+    {0xb1, 0x40},  // YCPT
+    {0xb2, 0x40},
+    {0xb3, 0x40},
+    {0xb6, 0xe0},
+
+    {0xd0, 0xcb},  // AECT  c9,modifed by mormo 2010/07/06
+    {0xd3, 0x48},  // 80,modified by mormor 2010/07/06
+
+    {0xf2, 0x02},
+    {0xf7, 0x12},
+    {0xf8, 0x0a},
+
+    //Registers of Page1
+    {0xfe, 0x01}, // set page1
+    {0x02, 0x20},
+    {0x04, 0x10},
+    {0x05, 0x08},
+    {0x06, 0x20},
+    {0x08, 0x0a},
+
+    {0x0e, 0x44},
+    {0x0f, 0x32},
+    {0x10, 0x41},
+    {0x11, 0x37},
+    {0x12, 0x22},
+    {0x13, 0x19},
+    {0x14, 0x44},
+    {0x15, 0x44},
+
+    {0x19, 0x50},
+    {0x1a, 0xd8},
+
+    {0x32, 0x10},
+
+    {0x35, 0x00},
+    {0x36, 0x80},
+    {0x37, 0x00},
+    //-----------Update the registers end---------//
+
+
+    {0xfe, 0x00},  // set page0
+    {0xd2, 0x90},  // open AEC
+
+
+    //-----------GAMMA Select(3)---------------//
+    /*  {0x9F , 0x10},
+        {0xA0 , 0x20},
+        {0xA1 , 0x38},
+        {0xA2 , 0x4E},
+        {0xA3 , 0x63},
+        {0xA4 , 0x76},
+        {0xA5 , 0x87},
+        {0xA6 , 0xA2},
+        {0xA7 , 0xB8},
+        {0xA8 , 0xCA},
+        {0xA9 , 0xD8},
+        {0xAA , 0xE3},
+        {0xAB , 0xEB},
+        {0xAC , 0xF0},
+        {0xAD , 0xF8},
+        {0xAE , 0xFD},
+        {0xAF , 0xFF},
+    */
+    /*GC0308_GAMMA_Select,
+    1:                                             //smallest gamma curve
+       {0x9F , 0x0B},
+       {0xA0 , 0x16},
+       {0xA1 , 0x29},
+       {0xA2 , 0x3C},
+       {0xA3 , 0x4F},
+       {0xA4 , 0x5F},
+       {0xA5 , 0x6F},
+       {0xA6 , 0x8A},
+       {0xA7 , 0x9F},
+       {0xA8 , 0xB4},
+       {0xA9 , 0xC6},
+       {0xAA , 0xD3},
+       {0xAB , 0xDD},
+       {0xAC , 0xE5},
+       {0xAD , 0xF1},
+       {0xAE , 0xFA},
+       {0xAF , 0xFF},
+
+    2:
+       {0x9F , 0x0E},
+       {0xA0 , 0x1C},
+       {0xA1 , 0x34},
+       {0xA2 , 0x48},
+       {0xA3 , 0x5A},
+       {0xA4 , 0x6B},
+       {0xA5 , 0x7B},
+       {0xA6 , 0x95},
+       {0xA7 , 0xAB},
+       {0xA8 , 0xBF},
+       {0xA9 , 0xCE},
+       {0xAA , 0xD9},
+       {0xAB , 0xE4},
+       {0xAC , 0xEC},
+       {0xAD , 0xF7},
+       {0xAE , 0xFD},
+       {0xAF , 0xFF},
+
+    3:
+       {0x9F , 0x10},
+       {0xA0 , 0x20},
+       {0xA1 , 0x38},
+       {0xA2 , 0x4E},
+       {0xA3 , 0x63},
+       {0xA4 , 0x76},
+       {0xA5 , 0x87},
+       {0xA6 , 0xA2},
+       {0xA7 , 0xB8},
+       {0xA8 , 0xCA},
+       {0xA9 , 0xD8},
+       {0xAA , 0xE3},
+       {0xAB , 0xEB},
+       {0xAC , 0xF0},
+       {0xAD , 0xF8},
+       {0xAE , 0xFD},
+       {0xAF , 0xFF},
+
+    4:
+       {0x9F , 0x14},
+       {0xA0 , 0x28},
+       {0xA1 , 0x44},
+       {0xA2 , 0x5D},
+       {0xA3 , 0x72},
+       {0xA4 , 0x86},
+       {0xA5 , 0x95},
+       {0xA6 , 0xB1},
+       {0xA7 , 0xC6},
+       {0xA8 , 0xD5},
+       {0xA9 , 0xE1},
+       {0xAA , 0xEA},
+       {0xAB , 0xF1},
+       {0xAC , 0xF5},
+       {0xAD , 0xFB},
+       {0xAE , 0xFE},
+       {0xAF , 0xFF},
+
+    5:                             //largest gamma curve
+       {0x9F , 0x15},
+       {0xA0 , 0x2A},
+       {0xA1 , 0x4A},
+       {0xA2 , 0x67},
+       {0xA3 , 0x79},
+       {0xA4 , 0x8C},
+       {0xA5 , 0x9A},
+       {0xA6 , 0xB3},
+       {0xA7 , 0xC5},
+       {0xA8 , 0xD5},
+       {0xA9 , 0xDF},
+       {0xAA , 0xE8},
+       {0xAB , 0xEE},
+       {0xAC , 0xF3},
+       {0xAD , 0xFA},
+       {0xAE , 0xFD},
+       {0xAF , 0xFF}, */
+    //-----------GAMMA Select End--------------//
+
+
+
+
+    //-------------H_V_Switch(4)---------------//
+    {0x14, 0x12},   //0x10
+
+    /*GC0308_H_V_Switch,
+
+    1:  // normal
+               {0x14 , 0x10},
+
+    2:  // IMAGE_H_MIRROR
+               {0x14 , 0x11},
+
+    3:  // IMAGE_V_MIRROR
+               {0x14 , 0x12},
+
+    4:  // IMAGE_HV_MIRROR
+               {0x14 , 0x13},
+    */
+    //-------------H_V_Select End--------------//
+    //add by traion for test
+    //{0xec,0x00}, //fixed fps(30fps) @tration
+
+#endif
+};
+
+void i2c_master_init(uint8_t num)
+{
+    if (num)                                            //1,GC0380  RGB
+    {
+        fpioa_set_function(DVP_PIN_SDA, FUNC_I2C1_SDA);
+        fpioa_set_function(DVP_PIN_SCL, FUNC_I2C1_SCLK);
+    }
+    #if 0
+    else
+    {
+        fpioa_set_function(DVP_PIN_SDA0, FUNC_I2C0_SDA);       //0,GC0328  NIR
+        fpioa_set_function(DVP_PIN_SCL, FUNC_I2C0_SCLK);
+    }
+    #endif
+    i2c_init(num, GC0308_ADDR >> 1, 7, 100000);
+
+}
+
+static void gc0308_wr_reg(uint8_t num, uint8_t reg, uint8_t data)
+{
+    uint8_t buf[2];
+
+    buf[0] = reg & 0xff;
+    buf[1] = data;
+	clear_csr(mie, MIP_MTIP);
+    i2c_send_data(num, buf, 2);
+	set_csr(mie, MIP_MTIP);
+}
+
+static uint8_t gc0308_rd_reg(uint8_t num, uint8_t reg)
+{
+    uint8_t reg_buf[1];
+    uint8_t data_buf;
+
+    reg_buf[0] = reg & 0xff;
+	clear_csr(mie, MIP_MTIP);
+    i2c_recv_data(num, reg_buf, 1, &data_buf, 1);
+	set_csr(mie, MIP_MTIP);
+    return data_buf;
+}
+
+#define GC0308_SET_PAGE0(n)     gc0308_wr_reg(n,0xfe,0x00)
+#define GC0308_SET_PAGE1(n)     gc0308_wr_reg(n,0xfe,0x01)
+
+#if 1
+void open_gc0308(CAM_TYPE type)
+{
+    #if 0
+	if (type == NIR_CAM)
+	{
+		i2c_master_init(1);
+		GC0308_SET_PAGE0(1);
+		gc0308_wr_reg(1, 0x25, 0x00); //disable visible light data output
+		i2c_master_init(0);
+		GC0308_SET_PAGE0(0);
+		gc0308_wr_reg(0, 0x25, 0x0F); //enable ir data output
+	}
+	else if (type == RGB_CAM)
+	{
+		i2c_master_init(0);
+		GC0308_SET_PAGE0(0);
+		gc0308_wr_reg(0, 0x25, 0x00); //disable ir data output
+		i2c_master_init(1);
+		GC0308_SET_PAGE0(1);
+		gc0308_wr_reg(1, 0x25, 0x0F); //enable visible light data output
+	}
+    #else
+    i2c_master_init(1);
+    GC0308_SET_PAGE0(1);
+    gc0308_wr_reg(1, 0x25, 0x0F); //enable visible light data output
+    #endif
+}
+#else
+void open_gc0308_0(void)
+{
+    usleep(1 * 1000);
+    i2c_master_init(1);
+    usleep(1 * 1000);
+    GC0308_SET_PAGE0(1);
+    gc0308_wr_reg(1, 0x25, 0x00);//disable visible light data output
+    usleep(1 * 1000);
+    i2c_master_init(0);
+    usleep(1 * 1000);
+    GC0308_SET_PAGE0(0);
+    gc0308_wr_reg(0, 0x25, 0x0F);//enable ir data output
+}
+
+void open_gc0308_1(void)
+{
+    usleep(1 * 1000);
+    i2c_master_init(0);
+    usleep(1 * 1000);
+    GC0308_SET_PAGE0(0);
+    gc0308_wr_reg(0, 0x25, 0x00); //disable ir data output
+    usleep(1 * 1000);
+    i2c_master_init(1);
+    usleep(1 * 1000);
+    GC0308_SET_PAGE0(1);
+    gc0308_wr_reg(1, 0x25, 0x0F); //enable visible light data output
+}
+#endif
+
+void change_gc0308(CAM_TYPE type)
+{
+	if (type == NIR_CAM)
+	{
+		i2c_master_init(1);
+		GC0308_SET_PAGE0(1);
+		gc0308_wr_reg(1, 0x25, 0x00); //disable visible light data output
+		i2c_master_init(0);
+		GC0308_SET_PAGE0(0);
+//		gc0308_wr_reg(0, 0x25, 0x0F); //enable ir data output
+
+	}
+	else if (type == RGB_CAM)
+	{
+		i2c_master_init(0);
+		GC0308_SET_PAGE0(0);
+		gc0308_wr_reg(0, 0x25, 0x00); //disable ir data output
+		i2c_master_init(1);
+		GC0308_SET_PAGE0(1);
+//		gc0308_wr_reg(1, 0x25, 0x0F); //enable visible light data output
+	}
+}
+
+void enable_gc0308_output(CAM_TYPE type)
+{
+	if (type == NIR_CAM)
+	{
+		gc0308_wr_reg(0, 0x25, 0x0F); //enable ir data output
+
+	}
+	else if (type == RGB_CAM)
+	{
+		gc0308_wr_reg(1, 0x25, 0x0F); //enable visible light data output
+	}
+}
+
+int gc0308_read_id(uint8_t num, uint8_t* id)
+{
+    *id = gc0308_rd_reg(num, 0x00);
+    return 0;
+}
+
+static void gc0308_AWB_enable(uint8_t num, uint8_t AWB_enable)
+{
+    uint16_t temp_AWB_reg = 0;
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    temp_AWB_reg = gc0308_rd_reg(num, 0x22);
+
+    if (AWB_enable == cam_true)
+    {
+        gc0308_wr_reg(num, 0x22, (temp_AWB_reg | 0x02));
+    }
+    else
+    {
+        gc0308_wr_reg(num, 0x22, (temp_AWB_reg & (~0x02)));
+    }
+}
+
+static void  gc0308_set_AE_mode(uint8_t num, cam_bool_type AE_enable)
+{
+    uint8_t temp_AE_reg = 0;
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    temp_AE_reg = gc0308_rd_reg(num, 0xd2);
+
+    if (AE_enable == cam_true)
+    {
+
+        gc0308_wr_reg(num, 0xd2, (temp_AE_reg | 0x80));
+    }
+    else
+    {
+        gc0308_wr_reg(num, 0xd2, (temp_AE_reg & (~0x80)));
+    }
+
+}
+
+
+/*************************************************************************
+ * FUNCTION
+ *  GC0308_NightMode
+ *
+ * DESCRIPTION
+ *  This function night mode of GC0308.
+ *
+ * PARAMETERS
+ *  bEnable: KAL_TRUE -> enable night mode, otherwise, disable night mode
+ *
+ * RETURNS
+ *  None
+ *
+ * GLOBALS AFFECTED
+ *
+ *************************************************************************/
+/*void gc0308_night_mode(bool enable)
+{
+    if (enable)
+    {
+
+        if(GC0308_MPEG4_encode_mode == KAL_TRUE)
+            GC0308_write_cmos_sensor(0xec, 0x00);
+        else
+            GC0308_write_cmos_sensor(0xec, 0x30);
+        GC0308_NIGHT_MODE = KAL_TRUE;
+    }
+    else
+    {
+        if(GC0308_MPEG4_encode_mode == KAL_TRUE)
+            GC0308_write_cmos_sensor(0xec, 0x00);
+        else
+            GC0308_write_cmos_sensor(0xec, 0x20);
+        GC0308_NIGHT_MODE = KAL_FALSE;
+    }
+}
+*/
+
+/*************************************************************************
+* FUNCTION
+*   gc0308_gamma_select
+*
+* DESCRIPTION
+*   This function is served for FAE to select the appropriate GAMMA curve.
+*
+* PARAMETERS
+*   num
+*   glvl
+*
+* RETURNS
+*   None
+*
+* GLOBALS AFFECTED
+*
+*
+*************************************************************************/
+void gc0308_gamma_select(uint8_t num, GAMMALVL_TYPE glvl)
+{
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    switch (glvl)
+    {
+        case GammaLvl_01:                            //smallest gamma curve
+            gc0308_wr_reg(num, 0x9F, 0x0B);
+            gc0308_wr_reg(num, 0xA0, 0x16);
+            gc0308_wr_reg(num, 0xA1, 0x29);
+            gc0308_wr_reg(num, 0xA2, 0x3C);
+            gc0308_wr_reg(num, 0xA3, 0x4F);
+            gc0308_wr_reg(num, 0xA4, 0x5F);
+            gc0308_wr_reg(num, 0xA5, 0x6F);
+            gc0308_wr_reg(num, 0xA6, 0x8A);
+            gc0308_wr_reg(num, 0xA7, 0x9F);
+            gc0308_wr_reg(num, 0xA8, 0xB4);
+            gc0308_wr_reg(num, 0xA9, 0xC6);
+            gc0308_wr_reg(num, 0xAA, 0xD3);
+            gc0308_wr_reg(num, 0xAB, 0xDD);
+            gc0308_wr_reg(num, 0xAC, 0xE5);
+            gc0308_wr_reg(num, 0xAD, 0xF1);
+            gc0308_wr_reg(num, 0xAE, 0xFA);
+            gc0308_wr_reg(num, 0xAF, 0xFF);
+            break;
+
+        case GammaLvl_02:
+            gc0308_wr_reg(num, 0x9F, 0x0E);
+            gc0308_wr_reg(num, 0xA0, 0x1C);
+            gc0308_wr_reg(num, 0xA1, 0x34);
+            gc0308_wr_reg(num, 0xA2, 0x48);
+            gc0308_wr_reg(num, 0xA3, 0x5A);
+            gc0308_wr_reg(num, 0xA4, 0x6B);
+            gc0308_wr_reg(num, 0xA5, 0x7B);
+            gc0308_wr_reg(num, 0xA6, 0x95);
+            gc0308_wr_reg(num, 0xA7, 0xAB);
+            gc0308_wr_reg(num, 0xA8, 0xBF);
+            gc0308_wr_reg(num, 0xA9, 0xCE);
+            gc0308_wr_reg(num, 0xAA, 0xD9);
+            gc0308_wr_reg(num, 0xAB, 0xE4);
+            gc0308_wr_reg(num, 0xAC, 0xEC);
+            gc0308_wr_reg(num, 0xAD, 0xF7);
+            gc0308_wr_reg(num, 0xAE, 0xFD);
+            gc0308_wr_reg(num, 0xAF, 0xFF);
+            break;
+
+        case GammaLvl_03:
+            gc0308_wr_reg(num, 0x9F, 0x10);
+            gc0308_wr_reg(num, 0xA0, 0x20);
+            gc0308_wr_reg(num, 0xA1, 0x38);
+            gc0308_wr_reg(num, 0xA2, 0x4E);
+            gc0308_wr_reg(num, 0xA3, 0x63);
+            gc0308_wr_reg(num, 0xA4, 0x76);
+            gc0308_wr_reg(num, 0xA5, 0x87);
+            gc0308_wr_reg(num, 0xA6, 0xA2);
+            gc0308_wr_reg(num, 0xA7, 0xB8);
+            gc0308_wr_reg(num, 0xA8, 0xCA);
+            gc0308_wr_reg(num, 0xA9, 0xD8);
+            gc0308_wr_reg(num, 0xAA, 0xE3);
+            gc0308_wr_reg(num, 0xAB, 0xEB);
+            gc0308_wr_reg(num, 0xAC, 0xF0);
+            gc0308_wr_reg(num, 0xAD, 0xF8);
+            gc0308_wr_reg(num, 0xAE, 0xFD);
+            gc0308_wr_reg(num, 0xAF, 0xFF);
+            break;
+
+        case GammaLvl_04:
+            gc0308_wr_reg(num, 0x9F, 0x14);
+            gc0308_wr_reg(num, 0xA0, 0x28);
+            gc0308_wr_reg(num, 0xA1, 0x44);
+            gc0308_wr_reg(num, 0xA2, 0x5D);
+            gc0308_wr_reg(num, 0xA3, 0x72);
+            gc0308_wr_reg(num, 0xA4, 0x86);
+            gc0308_wr_reg(num, 0xA5, 0x95);
+            gc0308_wr_reg(num, 0xA6, 0xB1);
+            gc0308_wr_reg(num, 0xA7, 0xC6);
+            gc0308_wr_reg(num, 0xA8, 0xD5);
+            gc0308_wr_reg(num, 0xA9, 0xE1);
+            gc0308_wr_reg(num, 0xAA, 0xEA);
+            gc0308_wr_reg(num, 0xAB, 0xF1);
+            gc0308_wr_reg(num, 0xAC, 0xF5);
+            gc0308_wr_reg(num, 0xAD, 0xFB);
+            gc0308_wr_reg(num, 0xAE, 0xFE);
+            gc0308_wr_reg(num, 0xAF, 0xFF);
+            break;
+
+        case GammaLvl_05:                               // largest gamma curve
+            gc0308_wr_reg(num, 0x9F, 0x15);
+            gc0308_wr_reg(num, 0xA0, 0x2A);
+            gc0308_wr_reg(num, 0xA1, 0x4A);
+            gc0308_wr_reg(num, 0xA2, 0x67);
+            gc0308_wr_reg(num, 0xA3, 0x79);
+            gc0308_wr_reg(num, 0xA4, 0x8C);
+            gc0308_wr_reg(num, 0xA5, 0x9A);
+            gc0308_wr_reg(num, 0xA6, 0xB3);
+            gc0308_wr_reg(num, 0xA7, 0xC5);
+            gc0308_wr_reg(num, 0xA8, 0xD5);
+            gc0308_wr_reg(num, 0xA9, 0xDF);
+            gc0308_wr_reg(num, 0xAA, 0xE8);
+            gc0308_wr_reg(num, 0xAB, 0xEE);
+            gc0308_wr_reg(num, 0xAC, 0xF3);
+            gc0308_wr_reg(num, 0xAD, 0xFA);
+            gc0308_wr_reg(num, 0xAE, 0xFD);
+            gc0308_wr_reg(num, 0xAF, 0xFF);
+            break;
+
+        default:
+            break;
+    }
+}
+
+///
+/// \brief 设置白平衡
+/// \param num
+/// \param para
+/// \return
+///
+cam_bool_type gc0308_set_param_wb(uint8_t num, AWB_MODE_TYPE para)
+{
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    switch (para)
+    {
+        case AWB_MODE_OFF:
+            gc0308_AWB_enable(num, false);
+            break;
+
+        case AWB_MODE_AUTO://for AWB can adjust back
+            gc0308_wr_reg(num, 0x5a, 0x56);
+            gc0308_wr_reg(num, 0x5b, 0x40);
+            gc0308_wr_reg(num, 0x5c, 0x4a);
+            gc0308_AWB_enable(num, true);
+            break;
+
+        case AWB_MODE_CLOUDY_DAYLIGHT://cloudy
+            gc0308_AWB_enable(num, false);
+            gc0308_wr_reg(num, 0x5a, 0x8c); //WB_manual_gain
+            gc0308_wr_reg(num, 0x5b, 0x50);
+            gc0308_wr_reg(num, 0x5c, 0x40);
+            break;
+
+        case AWB_MODE_DAYLIGHT://sunny
+            gc0308_AWB_enable(num, false);
+            gc0308_wr_reg(num, 0x5a, 0x74);
+            gc0308_wr_reg(num, 0x5b, 0x52);
+            gc0308_wr_reg(num, 0x5c, 0x40);
+            break;
+
+        case AWB_MODE_INCANDESCENT://office
+            gc0308_AWB_enable(num, false);
+            gc0308_wr_reg(num, 0x5a, 0x48);
+            gc0308_wr_reg(num, 0x5b, 0x40);
+            gc0308_wr_reg(num, 0x5c, 0x5c);
+            break;
+
+        case AWB_MODE_TUNGSTEN://home
+            gc0308_AWB_enable(num, false);
+            gc0308_wr_reg(num, 0x5a, 0x40);
+            gc0308_wr_reg(num, 0x5b, 0x54);
+            gc0308_wr_reg(num, 0x5c, 0x70);
+            break;
+
+        case AWB_MODE_FLUORESCENT:
+            gc0308_AWB_enable(num, false);
+            gc0308_wr_reg(num, 0x5a, 0x40);
+            gc0308_wr_reg(num, 0x5b, 0x54);
+            gc0308_wr_reg(num, 0x5c, 0x70);
+            break;
+
+        default:
+            return cam_false;
+    }
+
+    return cam_true;
+
+}/* GC0308_set_param_wb */
+
+cam_bool_type gc0308_set_param_effect(uint8_t num, MEFFECT_MODE_TYPE para)
+{
+    bool  ret = cam_true;
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    switch (para)
+    {
+        case MEFFECT_OFF:
+            gc0308_wr_reg(num, 0x23, 0x00);
+            gc0308_wr_reg(num, 0x2d, 0x0a);
+            gc0308_wr_reg(num, 0x20, 0xff);
+            gc0308_wr_reg(num, 0xd2, 0x90);
+            gc0308_wr_reg(num, 0x73, 0x00);
+            gc0308_wr_reg(num, 0x77, 0x54);
+
+            gc0308_wr_reg(num, 0xb3, 0x40);
+            gc0308_wr_reg(num, 0xb4, 0x80);
+            gc0308_wr_reg(num, 0xba, 0x00);
+            gc0308_wr_reg(num, 0xbb, 0x00);
+            break;
+
+        case MEFFECT_SEPIA:
+            gc0308_wr_reg(num, 0x23, 0x02);
+            gc0308_wr_reg(num, 0x2d, 0x0a); // 0x08
+            gc0308_wr_reg(num, 0x20, 0xff);
+            gc0308_wr_reg(num, 0xd2, 0x90);
+            gc0308_wr_reg(num, 0x73, 0x00);
+
+            gc0308_wr_reg(num, 0xb3, 0x40);
+            gc0308_wr_reg(num, 0xb4, 0x80);
+            gc0308_wr_reg(num, 0xba, 0xd0);
+            gc0308_wr_reg(num, 0xbb, 0x28);
+            break;
+
+        case MEFFECT_NEGATIVE:
+            gc0308_wr_reg(num, 0x23, 0x01);
+            gc0308_wr_reg(num, 0x2d, 0x0a);
+            gc0308_wr_reg(num, 0x20, 0xff);
+            gc0308_wr_reg(num, 0xd2, 0x90);
+            gc0308_wr_reg(num, 0x73, 0x00);
+
+            gc0308_wr_reg(num, 0xb3, 0x40);
+            gc0308_wr_reg(num, 0xb4, 0x80);
+            gc0308_wr_reg(num, 0xba, 0x00);
+            gc0308_wr_reg(num, 0xbb, 0x00);
+            break;
+
+        case MEFFECT_SEPIAGREEN:
+            gc0308_wr_reg(num, 0x23, 0x02);
+            gc0308_wr_reg(num, 0x2d, 0x0a);
+            gc0308_wr_reg(num, 0x20, 0xff);
+            gc0308_wr_reg(num, 0xd2, 0x90);
+            gc0308_wr_reg(num, 0x77, 0x88);
+
+            gc0308_wr_reg(num, 0xb3, 0x40);
+            gc0308_wr_reg(num, 0xb4, 0x80);
+            gc0308_wr_reg(num, 0xba, 0xc0);
+            gc0308_wr_reg(num, 0xbb, 0xc0);
+            break;
+
+        case MEFFECT_SEPIABLUE:
+            gc0308_wr_reg(num, 0x23, 0x02);
+            gc0308_wr_reg(num, 0x2d, 0x0a);
+            gc0308_wr_reg(num, 0x20, 0xff);
+            gc0308_wr_reg(num, 0xd2, 0x90);
+            gc0308_wr_reg(num, 0x73, 0x00);
+
+            gc0308_wr_reg(num, 0xb3, 0x40);
+            gc0308_wr_reg(num, 0xb4, 0x80);
+            gc0308_wr_reg(num, 0xba, 0x50);
+            gc0308_wr_reg(num, 0xbb, 0xe0);
+            break;
+
+        case MEFFECT_MONO:
+            gc0308_wr_reg(num, 0x23, 0x02);
+            gc0308_wr_reg(num, 0x2d, 0x0a);
+            gc0308_wr_reg(num, 0x20, 0xff);
+            gc0308_wr_reg(num, 0xd2, 0x90);
+            gc0308_wr_reg(num, 0x73, 0x00);
+
+            gc0308_wr_reg(num, 0xb3, 0x40);
+            gc0308_wr_reg(num, 0xb4, 0x80);
+            gc0308_wr_reg(num, 0xba, 0x00);
+            gc0308_wr_reg(num, 0xbb, 0x00);
+            break;
+
+        default:
+            ret = cam_false;
+            break;
+    }
+
+    return ret;
+
+}/* GC0308_set_param_effect */
+
+
+cam_bool_type gc0308_set_param_banding(uint8_t num, AE_FLICKER_MODE_TYPE para)
+{
+    bool  ret = cam_true;
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    switch (para)
+    {
+        case AE_FLICKER_MODE_50HZ:
+            gc0308_wr_reg(num, 0x01, 0x26);
+            gc0308_wr_reg(num, 0x02, 0x98);
+            gc0308_wr_reg(num, 0x0f, 0x03);
+
+            gc0308_wr_reg(num, 0xe2, 0x00);     //anti-flicker step [11:8]
+            gc0308_wr_reg(num, 0xe3, 0x50);     //anti-flicker step [7:0]
+
+            gc0308_wr_reg(num, 0xe4, 0x02);     //exp level 0  12.5fps
+            gc0308_wr_reg(num, 0xe5, 0x80);
+            gc0308_wr_reg(num, 0xe6, 0x03);     //exp level 1  10fps
+            gc0308_wr_reg(num, 0xe7, 0x20);
+            gc0308_wr_reg(num, 0xe8, 0x04);     //exp level 2  7.69fps
+            gc0308_wr_reg(num, 0xe9, 0x10);
+            gc0308_wr_reg(num, 0xea, 0x06);     //exp level 3  5.00fps
+            gc0308_wr_reg(num, 0xeb, 0x40);
+            break;
+
+        case AE_FLICKER_MODE_60HZ:
+            gc0308_wr_reg(num, 0x01, 0x97);
+            gc0308_wr_reg(num, 0x02, 0x84);
+            gc0308_wr_reg(num, 0x0f, 0x03);
+
+            gc0308_wr_reg(num, 0xe2, 0x00);     //anti-flicker step [11:8]
+            gc0308_wr_reg(num, 0xe3, 0x3e);   //anti-flicker step [7:0]
+
+            gc0308_wr_reg(num, 0xe4, 0x02);   //exp level 0  12.00fps
+            gc0308_wr_reg(num, 0xe5, 0x6c);
+            gc0308_wr_reg(num, 0xe6, 0x02);   //exp level 1  10.00fps
+            gc0308_wr_reg(num, 0xe7, 0xe8);
+            gc0308_wr_reg(num, 0xe8, 0x03);   //exp level 2  7.50fps
+            gc0308_wr_reg(num, 0xe9, 0xe0);
+            gc0308_wr_reg(num, 0xea, 0x05);   //exp level 3  5.00fps
+            gc0308_wr_reg(num, 0xeb, 0xd0);
+            break;
+
+        default:
+            ret = cam_false;
+            break;
+    }
+
+    return ret;
+}/* GC0308_set_param_banding */
+
+///
+/// \brief 设置曝光区域
+/// \param num
+/// \param para
+/// \return
+///
+cam_bool_type gc0308_set_param_exposure(uint8_t num, AE_EV_COMP_TYPE para)
+{
+	bool  ret = cam_true;
+//	usleep(1 * 1000);
+//	i2c_master_init(num);
+//	usleep(1 * 1000);
+
+	gc0308_wr_reg(num, 0xd2, 0x00);
+	switch (para)
+	{
+	case AE_EV_COMP_n13:
+		gc0308_wr_reg(num, 0xb5, 0xc0);
+		gc0308_wr_reg(0, 0xfb, 0x02);
+//		gc0308_wr_reg(num, 0xd3, 0x30);
+		gc0308_wr_reg(num, 0xd3, 0x20);
+		break;
+
+	case AE_EV_COMP_n10:
+		gc0308_wr_reg(num, 0xb5, 0xd0);
+		gc0308_wr_reg(0, 0xfb, 0x04);
+//		gc0308_wr_reg(num, 0xd3, 0x38);
+		gc0308_wr_reg(num, 0xd3, 0x25);
+		break;
+
+	case AE_EV_COMP_n07:
+		gc0308_wr_reg(num, 0xb5, 0xe0);
+		gc0308_wr_reg(0, 0xfb, 0x02);
+//		gc0308_wr_reg(num, 0xd3, 0x40);
+		gc0308_wr_reg(num, 0xd3, 0x28);
+		break;
+
+	case AE_EV_COMP_n03:
+		gc0308_wr_reg(num, 0xb5, 0xf0);
+//		gc0308_wr_reg(num, 0xd3, 0x48);
+		gc0308_wr_reg(num, 0xd3, 0x30);
+		break;
+
+	case AE_EV_COMP_00:
+		gc0308_wr_reg(num, 0xb5, 0x00);
+//		gc0308_wr_reg(num, 0xd3, 0x50);
+		gc0308_wr_reg(num, 0xd3, 0x38);
+		break;
+
+	case AE_EV_COMP_03:
+		gc0308_wr_reg(num, 0xb5, 0x10);
+		gc0308_wr_reg(num, 0xd3, 0x60);
+		break;
+
+	case AE_EV_COMP_07:
+		gc0308_wr_reg(num, 0xb5, 0x20);
+		gc0308_wr_reg(num, 0xd3, 0x70);
+		break;
+
+	case AE_EV_COMP_10:
+		gc0308_wr_reg(num, 0xb5, 0x30);
+		gc0308_wr_reg(num, 0xd3, 0x80);
+		break;
+
+	case AE_EV_COMP_13:
+		gc0308_wr_reg(num, 0xb5, 0x40);
+		gc0308_wr_reg(num, 0xd3, 0x90);
+		break;
+	default:
+		ret = cam_false;
+	}
+	gc0308_wr_reg(num, 0xd2, 0xc0);
+	return ret;
+} /* GC0308_set_param_exposure */
+
+
+void gc0308_set_test_patternmode(uint8_t num, cam_bool_type enable)
+{
+    LOGI(TAG, "test carama num:=%d", num);
+    LOGI(TAG, "test pattern enable:=%d", enable);
+
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    if (enable)
+    {
+        gc0308_wr_reg(num, 0xfe, 0x00);
+        gc0308_wr_reg(num, 0xfa, 0x32);
+        gc0308_wr_reg(num, 0x20, 0x08);
+        gc0308_wr_reg(num, 0x21, 0x00);
+        gc0308_wr_reg(num, 0x22, 0x00);
+        gc0308_wr_reg(num, 0xd2, 0x10);
+        gc0308_wr_reg(num, 0x15, 0x06);
+        gc0308_wr_reg(num, 0xf4, 0xc0);
+        gc0308_wr_reg(num, 0xf5, 0x40);
+        gc0308_wr_reg(num, 0x5a, 0x40);
+        gc0308_wr_reg(num, 0x5b, 0x40);
+        gc0308_wr_reg(num, 0x5c, 0x40);
+        gc0308_wr_reg(num, 0xb0, 0x40);
+        gc0308_wr_reg(num, 0xbd, 0x00);
+        gc0308_wr_reg(num, 0x51, 0x40);
+        gc0308_wr_reg(num, 0x52, 0x40);
+        gc0308_wr_reg(num, 0x03, 0x00);
+        gc0308_wr_reg(num, 0x04, 0x00);
+        gc0308_wr_reg(num, 0x2e, 0x01);
+    }
+    else
+    {
+        gc0308_wr_reg(num, 0xfe, 0x00);
+        gc0308_wr_reg(num, 0x2e, 0x00); //test pattern
+    }
+}
+
+/*************************************************************************
+* FUNCTION
+*   GC0308_Write_More_Registers
+*
+* DESCRIPTION
+*   This function is served for FAE to modify the necessary Init Regs. Do not modify the regs
+*     in init_GC0308() directly.
+*
+* PARAMETERS
+*   num
+*
+* RETURNS
+*   None
+*
+* GLOBALS AFFECTED
+*
+*************************************************************************/
+void gc0308_write_more_registers(uint8_t num)
+{
+    //  TODO: FAE Modify the Init Regs here!!!
+
+    //-----------Update the registers 2010/07/07-------------//
+
+    //Registers of Page0
+    usleep(1 * 1000);
+    i2c_master_init(num);
+    usleep(1 * 1000);
+
+    GC0308_SET_PAGE0(num);
+
+    gc0308_wr_reg(num, 0x10, 0x26);
+    gc0308_wr_reg(num, 0x11, 0x0d); // fd,modified by mormo 2010/07/06
+    gc0308_wr_reg(num, 0x1a, 0x2a); // 1e,modified by mormo 2010/07/06
+
+    gc0308_wr_reg(num, 0x1c, 0x49); // c1,modified by mormo 2010/07/06
+    gc0308_wr_reg(num, 0x1d, 0x9a); // 08,modified by mormo 2010/07/06
+    gc0308_wr_reg(num, 0x1e, 0x61); // 60,modified by mormo 2010/07/06
+
+    gc0308_wr_reg(num, 0x3a, 0x20);
+
+    gc0308_wr_reg(num, 0x50, 0x14); // 10,modified by mormo 2010/07/06
+    gc0308_wr_reg(num, 0x53, 0x80);
+    gc0308_wr_reg(num, 0x56, 0x80);
+
+    gc0308_wr_reg(num, 0x8b, 0x20); //LSC
+    gc0308_wr_reg(num, 0x8c, 0x20);
+    gc0308_wr_reg(num, 0x8d, 0x20);
+    gc0308_wr_reg(num, 0x8e, 0x14);
+    gc0308_wr_reg(num, 0x8f, 0x10);
+    gc0308_wr_reg(num, 0x90, 0x14);
+
+    gc0308_wr_reg(num, 0x94, 0x02);
+    gc0308_wr_reg(num, 0x95, 0x07);
+    gc0308_wr_reg(num, 0x96, 0xe0);
+
+    gc0308_wr_reg(num, 0xb1, 0x40); // YCPT
+    gc0308_wr_reg(num, 0xb2, 0x40);
+    gc0308_wr_reg(num, 0xb3, 0x40);
+    gc0308_wr_reg(num, 0xb6, 0xe0);
+
+    gc0308_wr_reg(num, 0xd0, 0xcb); // AECT  c9,modifed by mormo 2010/07/06
+    gc0308_wr_reg(num, 0xd3, 0x48); // 80,modified by mormor 2010/07/06
+
+    gc0308_wr_reg(num, 0xf2, 0x02);
+    gc0308_wr_reg(num, 0xf7, 0x12);
+    gc0308_wr_reg(num, 0xf8, 0x0a);
+
+    //Registers of Page1
+    GC0308_SET_PAGE1(num);
+
+    gc0308_wr_reg(num, 0x02, 0x20);
+    gc0308_wr_reg(num, 0x04, 0x10);
+    gc0308_wr_reg(num, 0x05, 0x08);
+    gc0308_wr_reg(num, 0x06, 0x20);
+    gc0308_wr_reg(num, 0x08, 0x0a);
+
+    gc0308_wr_reg(num, 0x0e, 0x44);
+    gc0308_wr_reg(num, 0x0f, 0x32);
+    gc0308_wr_reg(num, 0x10, 0x41);
+    gc0308_wr_reg(num, 0x11, 0x37);
+    gc0308_wr_reg(num, 0x12, 0x22);
+    gc0308_wr_reg(num, 0x13, 0x19);
+    gc0308_wr_reg(num, 0x14, 0x44);
+    gc0308_wr_reg(num, 0x15, 0x44);
+
+    gc0308_wr_reg(num, 0x19, 0x50);
+    gc0308_wr_reg(num, 0x1a, 0xd8);
+
+    gc0308_wr_reg(num, 0x32, 0x10);
+
+    gc0308_wr_reg(num, 0x35, 0x00);
+    gc0308_wr_reg(num, 0x36, 0x80);
+    gc0308_wr_reg(num, 0x37, 0x00);
+    //-----------Update the registers end---------//
+
+    GC0308_SET_PAGE0(num);
+    /*Customer can adjust GAMMA, MIRROR & UPSIDEDOWN here!*/
+
+    gc0308_gamma_select(num, 2);
+
+}
+
+uint8_t get_luma_average(CAM_TYPE _cam_type)
+{
+    uint8_t luma_value = 0;
+
+    GC0308_SET_PAGE0(_cam_type);
+    luma_value = gc0308_rd_reg(_cam_type, 0xd4);
+    GC0308_SET_PAGE0(_cam_type);
+
+    debug_log("_cam_type:%s, luma_value:%d", (_cam_type == NIR_CAM) ? "NIR_CAM" : "RGB_CAM", luma_value);
+
+    return luma_value;
+}
+
+void gc0308_set_measure_win(CAM_TYPE type, int x1, int y1, int x2, int y2)
+{
+	int cam_x1 = x1 * 2 / 4;
+	int cam_y1 = y1 * 2 / 4;
+	int cam_x2 = x2 * 2 / 4;
+	int cam_y2 = y2 * 2 / 4;
+//	LOG_I("x1:%d,y1:%d,x2:%d,y2:%d",cam_x1,cam_y1,cam_x2,cam_y2);
+	if (cam_x1 == 0 && cam_y1 == 0 && cam_x2 == 0 && cam_y2 == 0)
+	{
+		cam_x1 = EXP_WIN_RECT_X1 * 2 / 4;
+		cam_y1 = EXP_WIN_RECT_Y1 * 2 / 4;
+		cam_x2 = EXP_WIN_RECT_X2 * 2 / 4;
+		cam_y2 = EXP_WIN_RECT_Y2 * 2 / 4;
+	}
+	else if (cam_x1 == 0)
+	{
+		cam_x1 += 4;
+	}
+	else if (cam_y1 == 0)
+	{
+		cam_y1 += 4;
+	}
+	else if (cam_x2 == 0)
+	{
+		cam_x2 += 4;
+	}
+	else if (cam_y2 == 0)
+	{
+		cam_y2 += 4;
+	}
+
+	gc0308_wr_reg(type, 0xd2, 0x00);
+	gc0308_wr_reg(type, 0xf7, cam_x1);
+	gc0308_wr_reg(type, 0xf8, cam_y1);
+	gc0308_wr_reg(type, 0xf9, cam_x2);
+	gc0308_wr_reg(type, 0xfa, cam_y2);
+	gc0308_wr_reg(type, 0xd2, 0xc0);
+}
+
+static void gc0308_more_reg_set(CAM_TYPE type)
+{
+    /*
+    ADD_SENSOR_EXPOSURE_WIN在board_config.h中定义
+    不开启ADD_SENSOR_EXPOSURE_WIN时默认是全局曝光
+    */
+#ifdef ADD_SENSOR_EXPOSURE_WIN
+    /*
+        设置曝光窗口,坐标位置会在屏幕上显示
+        1、摄像头输出是抽样320X240的,曝光窗口是640X480来计算的,所以要先X2,
+           曝光窗口寄存器参数内部由X4的操作,所以要/4;
+        2、寄存器0xf7和0xf8最大为0x3f,所以要做是否超出3f的判断;
+    */
+    uint16_t x1, y1, x2, y2;
+
+    x1 = EXP_WIN_RECT_X1 * 2 / 4;
+    y1 = EXP_WIN_RECT_Y1 * 2 / 4;
+    x2 = EXP_WIN_RECT_X2 * 2 / 4;
+    y2 = EXP_WIN_RECT_Y2 * 2 / 4;
+
+    if (x1 > 0x3f)
+    {
+        x1 = 0x3f;    //the x1 max value is 3f
+    }
+
+    if (y1 > 0x3f)
+    {
+        y1 = 0x3f;    //the y1 max value is 3f
+    }
+
+#endif
+
+    if (NIR_CAM == type)
+    {
+        //debug_log("NIR_CAM gc0308_more_reg_set");
+
+        GC0308_SET_PAGE0(0);
+#if 0
+//		gc0308_wr_reg(0,0xb3, 0x38); //contrast
+		gc0308_wr_reg(0,0xd3, 0x28); //target-y value
+		gc0308_gamma_select(0,GammaLvl_01); //gamma
+
+#ifdef ADD_SENSOR_EXPOSURE_WIN //AEC window
+
+		gc0308_wr_reg(0,0xd2,0xc0); //开启AEC
+//		gc0308_wr_reg(0,0xd2,0x00);	//关闭AEC
+		//6灯的增益
+//		gc0308_wr_reg(0,0x50,0x0c);	//gain
+		//8灯的增益
+//		gc0308_wr_reg(0,0x50,0x08);	//gain
+
+		gc0308_wr_reg(0,0xd0,0xca);
+		gc0308_wr_reg(0,0xd1,0x10);
+		gc0308_wr_reg(0,0xf7,x1); //x0 max 3f=63 63*4 =252
+		gc0308_wr_reg(0,0xf8,y1); //y0 max 3f=63 1E=30 30*4=120
+		gc0308_wr_reg(0,0xf9,x2); //x1 max A0=160(640/4) 8C=140 140*4=560
+		gc0308_wr_reg(0,0xfa,y2); //y1 max 78=120(480/4) 5A=90 90*4=360
+#else
+		gc0308_wr_reg(0,0xd2,0xc0);
+		gc0308_wr_reg(0,0xd0,0xca);
+		gc0308_wr_reg(0,0xd1,0x10);
+		gc0308_wr_reg(0,0xf7,0x3F); //x0 max 3f=63 63*4 =252
+		gc0308_wr_reg(0,0xf8,0x1E); //y0 max 3f=63 1E=30 30*4=120
+		gc0308_wr_reg(0,0xf9,0x8C); //x1 max A0=160(640/4) 8C=140 140*4=560
+		gc0308_wr_reg(0,0xfa,0x5A); //y1 max 78=120(480/4) 5A=90 90*4=360
+#endif
+#endif
+//		gc0308_wr_reg(0, 0xb3, 0x50);           //contrast
+//		gc0308_wr_reg(0, 0xd3, 0x28);           //target-y value
+
+
+#ifdef ADD_SENSOR_EXPOSURE_WIN //AEC window
+
+		gc0308_wr_reg(0, 0xd2, 0x00);             //关闭AEC
+//		gc0308_wr_reg(0, 0xb3, 0x50);           //contrast
+
+//		gc0308_wr_reg(0,0x50,0x3f);				//gain
+
+		gc0308_wr_reg(0, 0xd3, 0x30);           //target-y value
+		gc0308_gamma_select(0, GammaLvl_01);    //gamma
+
+		gc0308_wr_reg(0, 0xd0, 0xca);
+		gc0308_wr_reg(0, 0xd1, 0x10);
+		gc0308_wr_reg(0, 0xf7, x1);             //x0 max 3f=63 63*4 =252
+		gc0308_wr_reg(0, 0xf8, y1);             //y0 max 3f=63 1E=30 30*4=120
+		gc0308_wr_reg(0, 0xf9, x2);             //x1 max A0=160(640/4) 8C=140 140*4=560
+		gc0308_wr_reg(0, 0xfa, y2);             //y1 max 78=120(480/4) 5A=90 90*4=360
+		gc0308_wr_reg(0, 0xfb, 0x05);
+		gc0308_wr_reg(0, 0xd2, 0xc0);           //开启AEC
+#else
+		gc0308_wr_reg(0, 0xd2, 0xc0);
+		gc0308_wr_reg(0, 0xd0, 0xca);
+		gc0308_wr_reg(0, 0xd1, 0x10);
+		gc0308_wr_reg(0, 0xf7, 0x3F); //x0 max 3f=63 63*4 =252
+		gc0308_wr_reg(0, 0xf8, 0x1E); //y0 max 3f=63 1E=30 30*4=120
+		gc0308_wr_reg(0, 0xf9, 0x8C); //x1 max A0=160(640/4) 8C=140 140*4=560
+		gc0308_wr_reg(0, 0xfa, 0x5A); //y1 max 78=120(480/4) 5A=90 90*4=360
+#endif
+
+#ifdef ENABLE_UYVY_OUTPUT
+        /*
+        UYVY 0xA0
+        VYUY 0xA1
+        YUYV 0xA2
+        YVYU 0xA3
+        RGB565 0xA6
+        ONLY Y 0xB1
+        */
+        gc0308_wr_reg(0, 0x24, 0xA0);
+#endif
+        //gc0308_set_test_patternmode(0,cam_true);
+
+        GC0308_SET_PAGE0(0);
+    }
+    else if (RGB_CAM == type)
+    {
+        //debug_log("RGB_CAM gc0308_more_reg_set");
+
+        GC0308_SET_PAGE0(1);
+
+		gc0308_wr_reg(1, 0xb3, 0x38); //contrast
+		gc0308_wr_reg(1, 0xd3, 0x45); //target-y value
+		gc0308_gamma_select(1, GammaLvl_05); //gamma GammaLvl_01
+
+
+#ifdef ADD_SENSOR_EXPOSURE_WIN //AEC window
+		gc0308_wr_reg(1, 0xd2, 0x00);             //关闭AEC
+		gc0308_wr_reg(1, 0xd2, 0xe0);
+		gc0308_wr_reg(1, 0xd0, 0xca);
+		gc0308_wr_reg(1, 0xd1, 0x10);
+		gc0308_wr_reg(1, 0xf7, x1); //x0 max 3f=63 63*4 =252
+		gc0308_wr_reg(1, 0xf8, y1); //y0 max 3f=63 1E=30 30*4=120
+		gc0308_wr_reg(1, 0xf9, x2); //x1 max A0=160(640/4) 8C=140 140*4=560
+		gc0308_wr_reg(1, 0xfa, y2); //y1 max 78=120(480/4) 5A=90 90*4=360
+		gc0308_wr_reg(1, 0xd2, 0xf0);            //开启AEC
+#else
+		gc0308_wr_reg(1, 0xd2, 0xc0);
+		gc0308_wr_reg(1, 0xd0, 0xca);
+		gc0308_wr_reg(1, 0xd1, 0x10);
+		gc0308_wr_reg(1, 0xf7, 0x3F); //x0 max 3f=63 63*4 =252
+		gc0308_wr_reg(1, 0xf8, 0x1E); //y0 max 3f=63 1E=30 30*4=120
+		gc0308_wr_reg(1, 0xf9, 0x8C); //x1 max A0=160(640/4) 8C=140 140*4=560
+		gc0308_wr_reg(1, 0xfa, 0x5A); //y1 max 78=120(480/4) 5A=90 90*4=360
+#endif
+
+#if 0 //AEC window
+		gc0308_wr_reg(1,0xd2,0xc0);
+		gc0308_wr_reg(1,0xd0,0xca);
+		gc0308_wr_reg(1,0xd1,0x10);
+		gc0308_wr_reg(1,0xf7,0x6e); //110
+		gc0308_wr_reg(1,0xf8,0x6e);
+		gc0308_wr_reg(1,0xf9,0x7E); //126
+		gc0308_wr_reg(1,0xfa,0x7E);
+		//gc0308_set_param_exposure(1, AE_EV_COMP_n10);
+#endif
+
+#ifdef ENABLE_UYVY_OUTPUT
+		/*
+		UYVY 0xA0
+		VYUY 0xA1
+		YUYV 0xA2
+		YVYU 0xA3
+		RGB565 0xA6
+		ONLY Y 0xB1
+		*/
+		gc0308_wr_reg(1, 0x24, 0xA0);
+#endif
+		//gc0308_set_test_patternmode(1,cam_true);
+
+		GC0308_SET_PAGE0(1);
+	}
+}
+
+int gc0308_init(void)
+{
+    uint8_t data;
+   	uint32_t i;
+	uint8_t num = 0;
+    #if 0
+    {
+
+        i2c_master_init(num);
+        gc0308_read_id(num, &data);
+        //debug_log("gc0308 0 ID : 0x%x", data);
+        LOGI(TAG, "gc0308 0 ID : 0x%x", data);
+
+		for (i = 0; gc0308_config[i][0]; i++)
+        {
+            gc0308_wr_reg(num, gc0308_config[i][0], gc0308_config[i][1]);
+            //data = gc0308_rd_reg(num, gc0308_config[i][0]);
+            //printf("0x%02x:0x%02x\n", gc0308_config[i][0], data);
+        }
+
+        /* set more nir-sensor reg */
+        gc0308_more_reg_set(NIR_CAM);
+        usleep(1 * 1000);
+    }
+    #endif
+    {
+        num = 1;
+        i2c_master_init(num);
+        gc0308_read_id(num, &data);
+        LOGI(TAG, "gc0308 1 ID : 0x%x", data);
+
+		for (i = 0; gc0308_config[i][0]; i++)
+        {
+            gc0308_wr_reg(num, gc0308_config[i][0], gc0308_config[i][1]);
+            //data = gc0308_rd_reg(num, gc0308_config[i][0]);
+            //printf("0x%02x:0x%02x\n", gc0308_config[i][0], data);
+        }
+
+        /* set more rgb-sensor reg */
+        gc0308_more_reg_set(RGB_CAM);
+        usleep(1 * 1000);
+    }
+
+#if (READ_REG_TEST)
+    gc0308_reg_read_test_PAGE0(0);
+    gc0308_reg_read_test_PAGE0(1);
+#endif
+
+	printf("sensor init ok\r\n");
+
+    return 0;
+}
+
+
+void gc0308_read_all_reg_setting(uint8_t num)
+{
+    uint8_t data;
+    uint32_t i;
+    i2c_master_init(num);
+    LOGI(TAG, "Carama Num:%d", num);
+    GC0308_SET_PAGE0(num);
+
+    for (i = 0; gc0308_config[i][0]; i++)
+    {
+        if (gc0308_config[i][0] == 0xfe && gc0308_config[i][1] == 0x00)
+        {
+            GC0308_SET_PAGE0(num);
+        }
+
+        if (gc0308_config[i][0] == 0xfe && gc0308_config[i][1] == 0x01)
+        {
+            GC0308_SET_PAGE1(num);
+        }
+
+        data = gc0308_rd_reg(num, gc0308_config[i][0]);
+        //LOGI(TAG,"0x%02x:0x%02x %s", gc0308_config[i][0], data, gc0308_config[i][1] == data ? "OK" : "FAILED");
+        LOGI(TAG, "0x%02x:0x%02x", gc0308_config[i][0], data);
+    }
+}
+
+uint8_t gc0308_get_y_value(CAM_TYPE type)
+{
+    return gc0308_rd_reg(type, 0xd4);
+}
+
+#if (READ_REG_TEST)
+static const uint8_t gc0308_reg_test[][2] =
+{
+    //is AEC enable?
+    {0xd2, 0xff},//
+    //windowing    default to 648*488
+    {0x05, 0xff},//0x00
+    {0x06, 0xff},//0x00
+    {0x07, 0xff},//0x00
+    {0x08, 0xff},//0x00
+    {0x09, 0xff},//0x01
+    {0x0a, 0xff},//0xe8
+    {0x0b, 0xff},//0x02
+    {0x0c, 0xff},//0x88
+    //crop window  default is 0x00(disable crop window mode)
+    {0x46, 0xff},//0x00
+    //AEC
+    {0x53, 0xff},//0x00
+    {0x54, 0xff},//0x00
+    {0x55, 0xff},//0x00
+    {0x56, 0xff},//0x00
+    {0x57, 0xff},//0x00
+    {0x58, 0xff},//0x00
+    {0x59, 0xff},//0x00
+    //GAIN
+    {0xee, 0xff},//0x00
+    {0xef, 0xff},//0x00
+    //exp level select
+    {0xec, 0xff},
+    //Target Y
+    {0xd3, 0xff},
+    //fixed fps
+    {0xec, 0xff},
+    //measure window
+    {0xf7, 0xff},
+    {0xf8, 0xff},
+    {0xf9, 0xff},
+    {0xfa, 0xff},
+    {0xb3, 0xff},
+};
+
+static const uint8_t gc0308_reg_test_PAGE1[][2] =
+{
+    //subsample
+    {0x53, 0xff},//0x00
+    {0x54, 0xff},//0x00
+    {0x55, 0xff},//0x00
+    {0x56, 0xff},//0x00
+    {0x57, 0xff},//0x00
+    {0x58, 0xff},//0x00
+    {0x59, 0xff},//0x00
+};
+
+void gc0308_reg_read_test_PAGE0(uint8_t num)
+{
+    uint8_t data;
+    i2c_master_init(num);
+    LOGD(TAG, "Carama Num:%d", num);
+
+    LOGD(TAG, "*******start read reg from PAGE0**********");
+    uint32_t reg_max = sizeof(gc0308_reg_test) / sizeof(gc0308_reg_test[0]);
+    LOGD(TAG, "reg_max:%d", reg_max);
+
+    for (int i = 0; i < reg_max; i++)
+    {
+        data = gc0308_rd_reg(num, gc0308_reg_test[i][0]);
+        LOGD(TAG, "{0x%02x,0x%02x}", gc0308_reg_test[i][0], data);
+    }
+
+    LOGD(TAG, "*******end read reg from PAGE0**********");
+}
+
+void gc0308_reg_read_test_PAGE1(uint8_t num)
+{
+    uint8_t data;
+    i2c_master_init(num);
+    LOGD(TAG, "Carama Num:%d", num);
+
+    LOGD(TAG, "*******start read reg from PAGE1**********");
+    uint32_t reg_max = sizeof(gc0308_reg_test_PAGE1) / sizeof(gc0308_reg_test_PAGE1[0]);
+    LOGD(TAG, "reg_max:%d", reg_max);
+    GC0308_SET_PAGE1(num);
+
+    for (int i = 0; i < reg_max; i++)
+    {
+        data = gc0308_rd_reg(num, gc0308_reg_test_PAGE1[i][0]);
+        LOGD(TAG, "{0x%02x,0x%02x}", gc0308_reg_test_PAGE1[i][0], data);
+    }
+
+    GC0308_SET_PAGE0(num);
+    LOGD(TAG, "*******end read reg from PAGE1**********");
+}
+#endif
+
+
+static struct rt_device _gc0308;
+static rt_size_t _read_size;
+static int dvp_irq_cb(void *ctx) {
+    /* 读取DVP中断状态,如果完成则刷新显示地址的数据,并清除中断标志,否则读取摄像头数据*/
+    if (dvp_get_interrupt(DVP_STS_FRAME_FINISH)) {
+        dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
+        dvp_clear_interrupt(DVP_STS_FRAME_FINISH);
+        if(((rt_device_t)ctx)->rx_indicate != NULL){
+            ((rt_device_t)ctx)->rx_indicate((rt_device_t)ctx, _read_size);
+        }
+    } else {
+        dvp_start_convert();
+        dvp_clear_interrupt(DVP_STS_FRAME_START);
+    }
+    return 0;
+}
+
+
+
+rt_err_t  drv_gc0308_init(rt_device_t dev){
+    
+    dvp_init(8);  /* DVP初始化,设置sccb的寄存器长度为8bit */
+    dvp_set_xclk_rate(24000000);  /* 设置输入时钟为24000000*/
+    dvp_enable_burst();  /* 使能突发传输模式 */
+    dvp_set_output_enable(0, 1);  /* 关闭AI输出模式,使能显示模式 */
+    dvp_set_output_enable(1, 1);
+    dvp_set_image_format(DVP_CFG_RGB_FORMAT);  /* 设置输出格式为RGB */
+    dvp_set_image_size(320, 240);  /* 设置输出像素大小为320*240 */
+    gc0308_init();  /* 摄像头初始化 */
+    return RT_EOK;
+}
+
+rt_err_t  drv_gc0308_open(rt_device_t dev, rt_uint16_t oflag){
+    open_gc0308(RGB_CAM);
+      /* 设置图像开始和结束中断状态,使能或禁用 */
+    dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
+    dvp_disable_auto();  /* 禁用自动接收图像模式 */
+
+    /* DVP 中断配置:中断优先级,中断回调,使能DVP中断 */
+    rt_kprintf("DVP interrupt config\n");
+    plic_set_priority(IRQN_DVP_INTERRUPT, 1);
+    plic_irq_register(IRQN_DVP_INTERRUPT, dvp_irq_cb, (void *)dev);
+    plic_irq_enable(IRQN_DVP_INTERRUPT);
+    return RT_EOK;
+}
+
+rt_err_t  drv_gc0308_close(rt_device_t dev){
+    
+    plic_irq_disable(IRQN_DVP_INTERRUPT);
+    return RT_EOK;
+}
+
+rt_size_t drv_gc0308_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size){
+    uint32_t dis_buf, ai_buf;
+    dis_buf = (uint32_t) buffer;
+    ai_buf = dis_buf + (320 * 240 * 2);
+    dvp_set_display_addr((uint32_t)buffer);
+    dvp_set_ai_addr((uint32_t)ai_buf, (uint32_t)(ai_buf + 320 * 240),
+                    (uint32_t)(ai_buf + 320 * 240 * 2));
+    _read_size = size;
+    dvp_clear_interrupt(DVP_STS_FRAME_START | DVP_STS_FRAME_FINISH);
+    dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 1);
+        
+    return RT_EOK;
+}
+
+rt_size_t drv_gc0308_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size){
+    /* no need */
+    return RT_EOK;
+}
+
+rt_err_t  drv_gc0308_control(rt_device_t dev, int cmd, void *args){
+    /* no need */
+    return RT_EOK;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops drv_gc0308_ops =
+{
+    drv_gc0308_init,
+    drv_gc0308_open,
+    drv_gc0308_close,
+    drv_gc0308_read,
+    drv_gc0308_write,
+    drv_gc0308_control
+};
+#endif
+
+
+int rt_hw_gc0308_init(void)
+{
+    rt_err_t ret = RT_EOK;
+
+    _gc0308.type        = RT_Device_Class_Sensor;
+    _gc0308.rx_indicate = RT_NULL;
+    _gc0308.tx_complete = RT_NULL;
+
+#ifdef RT_USING_DEVICE_OPS
+    _gc0308.ops        = &drv_gc0308_ops;
+#else
+    _gc0308.init    = drv_gc0308_init;
+    _gc0308.open    = drv_gc0308_open;
+    _gc0308.close   = drv_gc0308_close;
+    _gc0308.read    = drv_gc0308_read;
+    _gc0308.write   = drv_gc0308_write;
+    _gc0308.control = drv_gc0308_control;
+#endif
+    _gc0308.user_data = RT_NULL;
+
+    ret = rt_device_register(&_gc0308, "gc0308", RT_DEVICE_FLAG_INT_RX);
+    return ret;
+}
+INIT_DEVICE_EXPORT(rt_hw_gc0308_init);
+
+#endif //CAMERA_USING_GC0308

+ 352 - 0
project_0/applications/board_config/font.h

@@ -0,0 +1,352 @@
+#ifndef _FONT_H_
+#define _FONT_H_
+
+#include <stdint.h>
+
+static uint8_t const ascii0816[] =
+{
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD,
+    0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF,
+    0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE,
+    0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+    0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
+    0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD,
+    0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E,
+    0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30,
+    0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63,
+    0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8,
+    0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E,
+    0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+    0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB,
+    0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6,
+    0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
+    0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
+    0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C,
+    0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
+    0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C,
+    0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18,
+    0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C,
+    0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
+    0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E,
+    0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
+    0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE,
+    0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
+    0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18,
+    0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
+    0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+    0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00,
+    0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
+    0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE,
+    0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
+    0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0,
+    0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68,
+    0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
+    0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C,
+    0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60,
+    0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE,
+    0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66,
+    0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C,
+    0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C,
+    0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
+    0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38,
+    0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66,
+    0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30,
+    0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
+    0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60,
+    0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60,
+    0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06,
+    0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60,
+    0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6,
+    0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66,
+    0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60,
+    0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+    0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+    0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
+    0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6,
+    0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
+    0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00,
+    0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE,
+    0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C,
+    0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38,
+    0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06,
+    0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE,
+    0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
+    0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66,
+    0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6,
+    0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00,
+    0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36,
+    0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C,
+    0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+    0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
+    0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00,
+    0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+    0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C,
+    0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+    0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC,
+    0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0xD8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30,
+    0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC,
+    0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC,
+    0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+    0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
+    0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
+    0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xDC, 0x86, 0x0C,
+    0x18, 0x3E, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30,
+    0x66, 0xCE, 0x9E, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+    0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8, 0x6C, 0x36, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36,
+    0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
+    0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+    0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+    0x55, 0xAA, 0x55, 0xAA, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
+    0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
+    0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+    0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+    0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xC6, 0xC6, 0xCC,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0,
+    0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8,
+    0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66,
+    0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
+    0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66,
+    0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xDB, 0xDB, 0xF3, 0x7E, 0x60, 0xC0,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60,
+    0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C,
+    0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
+    0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
+    0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+    0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00,
+    0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
+    0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x0C,
+    0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00};
+
+#endif
+

+ 106 - 0
project_0/applications/board_config/ili9341.c

@@ -0,0 +1,106 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ili9341.h"
+#include "gpiohs.h"
+#include "spi.h"
+#include "unistd.h"
+#if LCD_USING_ILI9341
+static void  init_dcx(void)
+{   
+    gpiohs_set_drive_mode(DCX_GPIONUM, GPIO_DM_OUTPUT);
+    gpiohs_set_pin(DCX_GPIONUM, GPIO_PV_HIGH);
+}
+
+static void set_dcx_control(void)
+{
+    gpiohs_set_pin(DCX_GPIONUM, GPIO_PV_LOW);
+}
+
+static void set_dcx_data(void)
+{
+    gpiohs_set_pin(DCX_GPIONUM, GPIO_PV_HIGH);
+}
+
+#if BOARD_LICHEEDAN || EDU_KIT
+static void init_rst(void)
+{
+    gpiohs_set_drive_mode(RST_GPIONUM, GPIO_DM_OUTPUT);
+    gpiohs_set_pin(RST_GPIONUM, GPIO_PV_LOW);
+    usleep(100000);
+    gpiohs_set_pin(RST_GPIONUM, GPIO_PV_HIGH);
+    usleep(100000);
+}
+#endif
+
+void tft_hard_init(void)
+{
+    init_dcx();
+    spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
+#if BOARD_LICHEEDAN || EDU_KIT 
+    init_rst();
+    spi_set_clk_rate(SPI_CHANNEL, 20000000);
+#else
+    spi_set_clk_rate(SPI_CHANNEL, 25000000);
+#endif
+}
+
+void tft_write_command(uint8_t cmd)
+{
+    set_dcx_control();
+    spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
+    spi_init_non_standard(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/,
+                          SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT, (uint8_t *)(&cmd), 1,SPI_TRANS_CHAR);
+}
+
+void tft_write_byte(uint8_t *data_buf, uint32_t length)
+{
+    set_dcx_data();
+    spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
+    spi_init_non_standard(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/,
+                          SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT, data_buf, length, SPI_TRANS_CHAR);
+}
+
+void tft_write_half(uint16_t *data_buf, uint32_t length)
+{
+    set_dcx_data();
+    spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 16, 0);
+    spi_init_non_standard(SPI_CHANNEL, 16/*instrction length*/, 0/*address length*/, 0/*wait cycles*/,
+                          SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_SHORT);
+}
+
+void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag)
+{
+    set_dcx_data();
+    spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);
+
+    spi_init_non_standard(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/,
+                          SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_INT);
+}
+
+void tft_fill_data(uint32_t *data_buf, uint32_t length)
+{
+    set_dcx_data();
+    spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);
+    spi_init_non_standard(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/,
+                          SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
+    spi_fill_data_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT,data_buf, length);
+}
+
+#endif

+ 113 - 0
project_0/applications/board_config/ili9341.h

@@ -0,0 +1,113 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ILI9341_H_
+#define _ILI9341_H_
+#include <board_config.h>
+#include <stdint.h>
+#if LCD_USING_ILI9341
+/* clang-format off */
+#define NO_OPERATION            0x00
+#define SOFTWARE_RESET          0x01
+#define READ_STATUS             0x09
+#define READ_POWER_MODE         0x0A
+#define READ_MADCTL             0x0B
+#define READ_PIXEL_FORMAT       0x0C
+#define READ_IMAGE_FORMAT       0x0D
+#define READ_SIGNAL_MODE        0x0E
+#define READ_SELT_DIAG_RESULT   0x0F
+#define SLEEP_ON                0x10
+#define SLEEP_OFF               0x11
+#define PARTIAL_DISPALY_ON      0x12
+#define NORMAL_DISPALY_ON       0x13
+#define INVERSION_DISPALY_OFF   0x20
+#define INVERSION_DISPALY_ON    0x21
+#define GAMMA_SET               0x26
+#define DISPALY_OFF             0x28
+#define DISPALY_ON              0x29
+#define HORIZONTAL_ADDRESS_SET  0x2A
+#define VERTICAL_ADDRESS_SET    0x2B
+#define MEMORY_WRITE            0x2C
+#define COLOR_SET               0x2D
+#define MEMORY_READ             0x2E
+#define PARTIAL_AREA            0x30
+#define VERTICAL_SCROL_DEFINE   0x33
+#define TEAR_EFFECT_LINE_OFF    0x34
+#define TEAR_EFFECT_LINE_ON     0x35
+#define MEMORY_ACCESS_CTL       0x36
+#define VERTICAL_SCROL_S_ADD    0x37
+#define IDLE_MODE_OFF           0x38
+#define IDLE_MODE_ON            0x39
+#define PIXEL_FORMAT_SET        0x3A
+#define WRITE_MEMORY_CONTINUE   0x3C
+#define READ_MEMORY_CONTINUE    0x3E
+#define SET_TEAR_SCANLINE       0x44
+#define GET_SCANLINE            0x45
+#define WRITE_BRIGHTNESS        0x51
+#define READ_BRIGHTNESS         0x52
+#define WRITE_CTRL_DISPALY      0x53
+#define READ_CTRL_DISPALY       0x54
+#define WRITE_BRIGHTNESS_CTL    0x55
+#define READ_BRIGHTNESS_CTL     0x56
+#define WRITE_MIN_BRIGHTNESS    0x5E
+#define READ_MIN_BRIGHTNESS     0x5F
+#define READ_ID1                0xDA
+#define READ_ID2                0xDB
+#define READ_ID3                0xDC
+#define RGB_IF_SIGNAL_CTL       0xB0
+#define NORMAL_FRAME_CTL        0xB1
+#define IDLE_FRAME_CTL          0xB2
+#define PARTIAL_FRAME_CTL       0xB3
+#define INVERSION_CTL           0xB4
+#define BLANK_PORCH_CTL         0xB5
+#define DISPALY_FUNCTION_CTL    0xB6
+#define ENTRY_MODE_SET          0xB7
+#define BACKLIGHT_CTL1          0xB8
+#define BACKLIGHT_CTL2          0xB9
+#define BACKLIGHT_CTL3          0xBA
+#define BACKLIGHT_CTL4          0xBB
+#define BACKLIGHT_CTL5          0xBC
+#define BACKLIGHT_CTL7          0xBE
+#define BACKLIGHT_CTL8          0xBF
+#define POWER_CTL1              0xC0
+#define POWER_CTL2              0xC1
+#define VCOM_CTL1               0xC5
+#define VCOM_CTL2               0xC7
+#define NV_MEMORY_WRITE         0xD0
+#define NV_MEMORY_PROTECT_KEY   0xD1
+#define NV_MEMORY_STATUS_READ   0xD2
+#define READ_ID4                0xD3
+#define POSITIVE_GAMMA_CORRECT  0xE0
+#define NEGATIVE_GAMMA_CORRECT  0xE1
+#define DIGITAL_GAMMA_CTL1      0xE2
+#define DIGITAL_GAMMA_CTL2      0xE3
+#define INTERFACE_CTL           0xF6
+
+#define DCX_GPIONUM             LCD_RS_GPIONUM
+#define RST_GPIONUM             LCD_RST_GPIONUM
+
+#define SPI_CHANNEL             0
+#define SPI_SLAVE_SELECT        3
+/* clang-format on */
+
+void tft_hard_init(void);
+void tft_write_command(uint8_t cmd);
+void tft_write_byte(uint8_t *data_buf, uint32_t length);
+void tft_write_half(uint16_t *data_buf, uint32_t length);
+void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag);
+void tft_fill_data(uint32_t *data_buf, uint32_t length);
+#endif
+#endif
+

+ 315 - 0
project_0/applications/board_config/incbin.h

@@ -0,0 +1,315 @@
+/**
+ * @file incbin.h
+ * @author Dale Weiler
+ * @brief Utility for including binary files
+ *
+ * Facilities for including binary files into the current translation unit and
+ * making use from them externally in other translation units.
+ */
+#ifndef INCBIN_HDR
+#define INCBIN_HDR
+#include <limits.h>
+
+# define INCBIN_ALIGNMENT_INDEX 8
+
+/* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */
+#define INCBIN_ALIGN_SHIFT_0 1
+#define INCBIN_ALIGN_SHIFT_1 2
+#define INCBIN_ALIGN_SHIFT_2 4
+#define INCBIN_ALIGN_SHIFT_3 8
+#define INCBIN_ALIGN_SHIFT_4 16
+#define INCBIN_ALIGN_SHIFT_5 32
+#define INCBIN_ALIGN_SHIFT_6 64
+#define INCBIN_ALIGN_SHIFT_7 128
+#define INCBIN_ALIGN_SHIFT_8 256
+
+/* Actual alignment value */
+#define INCBIN_ALIGNMENT \
+    INCBIN_CONCATENATE( \
+        INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \
+        INCBIN_ALIGNMENT_INDEX)
+
+/* Stringize */
+#define INCBIN_STR(X) \
+    #X
+#define INCBIN_STRINGIZE(X) \
+    INCBIN_STR(X)
+/* Concatenate */
+#define INCBIN_CAT(X, Y) \
+    X ## Y
+#define INCBIN_CONCATENATE(X, Y) \
+    INCBIN_CAT(X, Y)
+/* Deferred macro expansion */
+#define INCBIN_EVAL(X) \
+    X
+#define INCBIN_INVOKE(N, ...) \
+    INCBIN_EVAL(N(__VA_ARGS__))
+
+/* Green Hills uses a different directive for including binary data */
+#if defined(__ghs__)
+#  define INCBIN_MACRO "\tINCBIN"
+#else
+#  define INCBIN_MACRO ".incbin"
+#endif
+
+#ifndef _MSC_VER
+#  define INCBIN_ALIGN \
+    __attribute__((aligned(INCBIN_ALIGNMENT)))
+#else
+#  define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT))
+#endif
+
+#if defined(__arm__) || /* GNU C and RealView */ \
+    defined(__arm) || /* Diab */ \
+    defined(_ARM) /* ImageCraft */
+#  define INCBIN_ARM
+#endif
+
+#ifdef __GNUC__
+/* Utilize .balign where supported */
+#  define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
+#  define INCBIN_ALIGN_BYTE ".balign 1\n"
+#elif defined(INCBIN_ARM)
+/*
+ * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is
+ * the shift count. This is the value passed to `.align'
+ */
+#  define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n"
+#  define INCBIN_ALIGN_BYTE ".align 0\n"
+#else
+/* We assume other inline assembler's treat `.align' as `.balign' */
+#  define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
+#  define INCBIN_ALIGN_BYTE ".align 1\n"
+#endif
+
+/* INCBIN_CONST is used by incbin.c generated files */
+#if defined(__cplusplus)
+#  define INCBIN_EXTERNAL extern "C"
+#  define INCBIN_CONST    extern const
+#else
+#  define INCBIN_EXTERNAL extern
+#  define INCBIN_CONST    const
+#endif
+
+#if defined(__APPLE__)
+/* The directives are different for Apple branded compilers */
+#  define INCBIN_SECTION         ".data\n"
+#  define INCBIN_GLOBAL(NAME)    ".globl " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
+#  define INCBIN_INT             ".long "
+#  define INCBIN_MANGLE          "_"
+#  define INCBIN_BYTE            ".byte "
+#  define INCBIN_TYPE(...)
+#else
+#  define INCBIN_SECTION         ".section .data\n"
+#  define INCBIN_GLOBAL(NAME)    ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
+#  define INCBIN_INT             ".int "
+#  if defined(__USER_LABEL_PREFIX__)
+#    define INCBIN_MANGLE        INCBIN_STRINGIZE(__USER_LABEL_PREFIX__)
+#  else
+#    define INCBIN_MANGLE        ""
+#  endif
+#  if defined(INCBIN_ARM)
+/* On arm assemblers, `@' is used as a line comment token */
+#    define INCBIN_TYPE(NAME)    ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n"
+#  elif defined(__MINGW32__) || defined(__MINGW64__)
+/* Mingw doesn't support this directive either */
+#    define INCBIN_TYPE(NAME)
+#  else
+/* It's safe to use `@' on other architectures */
+#    define INCBIN_TYPE(NAME)    ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n"
+#  endif
+#  define INCBIN_BYTE            ".byte "
+#endif
+
+/* List of style types used for symbol names */
+#define INCBIN_STYLE_CAMEL 0
+#define INCBIN_STYLE_SNAKE 1
+
+/**
+ * @brief Specify the prefix to use for symbol names.
+ *
+ * By default this is `g', producing symbols of the form:
+ * @code
+ * #include "incbin.h"
+ * INCBIN(Foo, "foo.txt");
+ *
+ * // Now you have the following symbols:
+ * // const unsigned char gFooData[];
+ * // const unsigned char gFooEnd;
+ * // const unsigned int gFooSize;
+ * @endcode
+ *
+ * If however you specify a prefix before including: e.g:
+ * @code
+ * #define INCBIN_PREFIX incbin
+ * #include "incbin.h"
+ * INCBIN(Foo, "foo.txt");
+ *
+ * // Now you have the following symbols instead:
+ * // const unsigned char incbinFooData[];
+ * // const unsigned char incbinFooEnd;
+ * // const unsigned int incbinFooSize;
+ * @endcode
+ */
+#if !defined(INCBIN_PREFIX)
+#  define INCBIN_PREFIX g
+#endif
+
+/**
+ * @brief Specify the style used for symbol names.
+ *
+ * Possible options are
+ * - INCBIN_STYLE_CAMEL "CamelCase"
+ * - INCBIN_STYLE_SNAKE "snake_case"
+ *
+ * Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form:
+ * @code
+ * #include "incbin.h"
+ * INCBIN(Foo, "foo.txt");
+ *
+ * // Now you have the following symbols:
+ * // const unsigned char <prefix>FooData[];
+ * // const unsigned char <prefix>FooEnd;
+ * // const unsigned int <prefix>FooSize;
+ * @endcode
+ *
+ * If however you specify a style before including: e.g:
+ * @code
+ * #define INCBIN_STYLE INCBIN_STYLE_SNAKE
+ * #include "incbin.h"
+ * INCBIN(foo, "foo.txt");
+ *
+ * // Now you have the following symbols:
+ * // const unsigned char <prefix>foo_data[];
+ * // const unsigned char <prefix>foo_end;
+ * // const unsigned int <prefix>foo_size;
+ * @endcode
+ */
+#if !defined(INCBIN_STYLE)
+#  define INCBIN_STYLE INCBIN_STYLE_CAMEL
+#endif
+
+/* Style lookup tables */
+#define INCBIN_STYLE_0_DATA Data
+#define INCBIN_STYLE_0_END End
+#define INCBIN_STYLE_0_SIZE Size
+#define INCBIN_STYLE_1_DATA _data
+#define INCBIN_STYLE_1_END _end
+#define INCBIN_STYLE_1_SIZE _size
+
+/* Style lookup: returning identifier */
+#define INCBIN_STYLE_IDENT(TYPE) \
+    INCBIN_CONCATENATE( \
+        INCBIN_STYLE_, \
+        INCBIN_CONCATENATE( \
+            INCBIN_EVAL(INCBIN_STYLE), \
+            INCBIN_CONCATENATE(_, TYPE)))
+
+/* Style lookup: returning string literal */
+#define INCBIN_STYLE_STRING(TYPE) \
+    INCBIN_STRINGIZE( \
+        INCBIN_STYLE_IDENT(TYPE)) \
+
+/* Generate the global labels by indirectly invoking the macro with our style
+ * type and concatenating the name against them. */
+#define INCBIN_GLOBAL_LABELS(NAME, TYPE) \
+    INCBIN_INVOKE( \
+        INCBIN_GLOBAL, \
+        INCBIN_CONCATENATE( \
+            NAME, \
+            INCBIN_INVOKE( \
+                INCBIN_STYLE_IDENT, \
+                TYPE))) \
+    INCBIN_INVOKE( \
+        INCBIN_TYPE, \
+        INCBIN_CONCATENATE( \
+            NAME, \
+            INCBIN_INVOKE( \
+                INCBIN_STYLE_IDENT, \
+                TYPE)))
+
+/**
+ * @brief Externally reference binary data included in another translation unit.
+ *
+ * Produces three external symbols that reference the binary data included in
+ * another translation unit.
+ *
+ * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
+ * "Data", as well as "End" and "Size" after. An example is provided below.
+ *
+ * @param NAME The name given for the binary data
+ *
+ * @code
+ * INCBIN_EXTERN(Foo);
+ *
+ * // Now you have the following symbols:
+ * // extern const unsigned char <prefix>FooData[];
+ * // extern const unsigned char <prefix>FooEnd;
+ * // extern const unsigned int <prefix>FooSize;
+ * @endcode
+ */
+#define INCBIN_EXTERN(NAME) \
+    INCBIN_EXTERNAL INCBIN_ALIGN unsigned char \
+        INCBIN_CONCATENATE( \
+            INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
+            INCBIN_STYLE_IDENT(DATA))[]; \
+    INCBIN_EXTERNAL INCBIN_ALIGN unsigned char * \
+    INCBIN_CONCATENATE( \
+        INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
+        INCBIN_STYLE_IDENT(END)); \
+    INCBIN_EXTERNAL unsigned int \
+        INCBIN_CONCATENATE( \
+            INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
+            INCBIN_STYLE_IDENT(SIZE))
+
+/**
+ * @brief Include a binary file into the current translation unit.
+ *
+ * Includes a binary file into the current translation unit, producing three symbols
+ * for objects that encode the data and size respectively.
+ *
+ * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
+ * "Data", as well as "End" and "Size" after. An example is provided below.
+ *
+ * @param NAME The name to associate with this binary data (as an identifier.)
+ * @param FILENAME The file to include (as a string literal.)
+ *
+ * @code
+ * INCBIN(Icon, "icon.png");
+ *
+ * // Now you have the following symbols:
+ * // const unsigned char <prefix>IconData[];
+ * // const unsigned char <prefix>IconEnd;
+ * // const unsigned int <prefix>IconSize;
+ * @endcode
+ *
+ * @warning This must be used in global scope
+ * @warning The identifiers may be different if INCBIN_STYLE is not default
+ *
+ * To externally reference the data included by this in another translation unit
+ * please @see INCBIN_EXTERN.
+ */
+#ifdef _MSC_VER
+#define INCBIN(NAME, FILENAME) \
+    INCBIN_EXTERN(NAME)
+#else
+#define INCBIN(NAME, FILENAME) \
+    __asm__(INCBIN_SECTION \
+            INCBIN_GLOBAL_LABELS(NAME, DATA) \
+            INCBIN_ALIGN_HOST \
+            INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \
+            INCBIN_MACRO " \"" FILENAME "\"\n" \
+            INCBIN_GLOBAL_LABELS(NAME, END) \
+            INCBIN_ALIGN_BYTE \
+            INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \
+                INCBIN_BYTE "1\n" \
+            INCBIN_GLOBAL_LABELS(NAME, SIZE) \
+            INCBIN_ALIGN_HOST \
+            INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \
+                INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \
+                           INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \
+    ); \
+    INCBIN_EXTERN(NAME)
+
+#endif
+#endif

+ 89 - 0
project_0/applications/board_config/lcd.h

@@ -0,0 +1,89 @@
+#ifndef _LCD_H_
+#define _LCD_H_
+
+#include <stdint.h>
+#include <board_config.h>
+#ifndef BSP_USING_LCD
+/* clang-format off */
+#define LCD_X_MAX   (240)
+#define LCD_Y_MAX   (320)
+
+#define BLACK       0x0000
+#define NAVY        0x000F
+#define DARKGREEN   0x03E0
+#define DARKCYAN    0x03EF
+#define MAROON      0x7800
+#define PURPLE      0x780F
+#define OLIVE       0x7BE0
+#define LIGHTGREY   0xC618
+#define DARKGREY    0x7BEF
+#define BLUE        0x001F
+#define GREEN       0x07E0
+#define CYAN        0x07FF
+#define RED         0xF800
+#define MAGENTA     0xF81F
+#define YELLOW      0xFFE0
+#define WHITE       0xFFFF
+#define ORANGE      0xFD20
+#define GREENYELLOW 0xAFE5
+#define PINK        0xF81F
+#define USER_COLOR  0xAA55
+/* clang-format on */
+
+/* LCD显示方向 */
+typedef enum _lcd_dir
+{
+    DIR_XY_RLUD = 0x00,
+    DIR_YX_RLUD = 0x20,
+    DIR_XY_LRUD = 0x40,
+    DIR_YX_LRUD = 0x60,
+    DIR_XY_RLDU = 0x80,
+    DIR_YX_RLDU = 0xA0,
+    DIR_XY_LRDU = 0xC0,
+    DIR_YX_LRDU = 0xE0,
+    DIR_XY_MASK = 0x20,
+    DIR_MASK = 0xE0,
+} lcd_dir_t;
+
+/* LCD结构体 */
+typedef struct _lcd_ctl
+{
+    uint8_t mode;
+    uint8_t dir;
+    uint16_t width;
+    uint16_t height;
+} lcd_ctl_t;
+
+void lcd_polling_enable(void);
+void lcd_interrupt_enable(void);
+void lcd_init(void);
+void lcd_clear(uint16_t color);
+void lcd_set_direction(lcd_dir_t dir);
+void lcd_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
+void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
+void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color);
+void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color);
+void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr);
+void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color);
+void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color);
+void lcd_draw_picture_half(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint16_t *ptr);
+#else //#ifndef BSP_USING_LCD
+/* 使用RTT自带LCD驱动,将LCD接口声明与上述一致 */
+#include <drv_lcd.h>
+#define __DO_WHILE0(_expr) do{ _expr }while(0)
+/* for mpy machine.lcd */
+// void lcd_display_on(void);
+// void lcd_display_off(void);
+// void lcd_clear(int color);
+// void lcd_set_direction(lcd_dir_t dir);
+void lcd_draw_circle(int x1, int y1, int r);
+void lcd_set_color(int back, int fore);
+#define lcd_draw_point( x,  y, color)  __DO_WHILE0( lcd_draw_point_color((x),  (y), (color)); )
+#define lcd_draw_string(x, y, str, color) __DO_WHILE0( lcd_set_color(0x0000, (color)); lcd_show_string((x), (y), 16, (str)); )
+#define lcd_draw_line( x1,  y1,  x2,  y2,  color) __DO_WHILE0( lcd_set_color(0x0000, (color)); lcd_draw_line( (x1),  (y1),  (x2),  (y2)); )
+#define lcd_draw_rectangle(x1 , y1 , x2, y2, width, color)  __DO_WHILE0( lcd_set_color(0x0000, (color));  lcd_draw_rectangle((x1), (y1) , (x2), (y2)); )
+#define lcd_draw_picture(x1, y1, width, height, ptr)  __DO_WHILE0( lcd_show_image((x1), (y1) , (height), (width), (ptr)); )
+#endif //BSP_USING_LCD
+#endif
+
+

+ 283 - 0
project_0/applications/board_config/lcd_ili9341.c

@@ -0,0 +1,283 @@
+/* Copyright 2018 Canaan Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <string.h>
+#include <unistd.h>
+#include "lcd.h"
+#if LCD_USING_ILI9341
+#include "ili9341.h"
+#include "font.h"
+
+
+static lcd_ctl_t lcd_ctl;
+
+void lcd_polling_enable(void)
+{
+    lcd_ctl.mode = 0;
+}
+
+void lcd_interrupt_enable(void)
+{
+    lcd_ctl.mode = 1;
+}
+
+void lcd_init(void)
+{
+    uint8_t data = 0;
+
+    tft_hard_init();
+    /*soft reset*/
+    tft_write_command(SOFTWARE_RESET);
+    usleep(100000);
+    /*exit sleep*/
+    tft_write_command(SLEEP_OFF);
+    usleep(100000);
+    /*pixel format*/
+    tft_write_command(PIXEL_FORMAT_SET);
+    data = 0x55;
+    tft_write_byte(&data, 1);
+    usleep(100000);
+    /* 打开显示反转 */
+    tft_write_command(INVERSION_DISPALY_ON);
+    
+    lcd_set_direction(DIR_YX_LRUD);
+    /*display on*/
+    tft_write_command(DISPALY_ON);
+    lcd_polling_enable();
+
+    /* 清空显示 */
+    lcd_clear(WHITE);
+}
+
+void lcd_set_direction(lcd_dir_t dir)
+{
+#if BOARD_LICHEEDAN
+   dir |= 0x08;
+#endif
+    lcd_ctl.dir = dir;
+    if (dir & DIR_XY_MASK)
+    {
+        lcd_ctl.width = LCD_Y_MAX - 1;
+        lcd_ctl.height = LCD_X_MAX - 1;
+    }
+    else
+    {
+        lcd_ctl.width = LCD_X_MAX - 1;
+        lcd_ctl.height = LCD_Y_MAX - 1;
+    }
+
+    tft_write_command(MEMORY_ACCESS_CTL);
+    tft_write_byte((uint8_t *)&dir, 1);
+}
+
+void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
+{
+    uint8_t data[4] = {0};
+
+    data[0] = (uint8_t)(x1 >> 8);
+    data[1] = (uint8_t)(x1);
+    data[2] = (uint8_t)(x2 >> 8);
+    data[3] = (uint8_t)(x2);
+    tft_write_command(HORIZONTAL_ADDRESS_SET);
+    tft_write_byte(data, 4);
+
+    data[0] = (uint8_t)(y1 >> 8);
+    data[1] = (uint8_t)(y1);
+    data[2] = (uint8_t)(y2 >> 8);
+    data[3] = (uint8_t)(y2);
+    tft_write_command(VERTICAL_ADDRESS_SET);
+    tft_write_byte(data, 4);
+
+    tft_write_command(MEMORY_WRITE);
+}
+
+void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
+{
+    lcd_set_area(x, y, x, y);
+    tft_write_half(&color, 1);
+}
+
+void lcd_draw_char(uint16_t x, uint16_t y, char c, uint16_t color)
+{
+    uint8_t i = 0;
+    uint8_t j = 0;
+    uint8_t data = 0;
+
+    for (i = 0; i < 16; i++)
+    {
+        data = ascii0816[c * 16 + i];
+        for (j = 0; j < 8; j++)
+        {
+            if (data & 0x80)
+                lcd_draw_point(x + j, y, color);
+            data <<= 1;
+        }
+        y++;
+    }
+}
+
+void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color)
+{
+    while (*str)
+    {
+        lcd_draw_char(x, y, *str, color);
+        str++;
+        x += 8;
+    }
+}
+
+void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color)
+{
+    uint8_t i = 0;
+    uint8_t j = 0;
+    uint8_t data = 0;
+    uint8_t *pdata = NULL;
+    uint16_t width = 0;
+    uint32_t *pixel = NULL;
+
+    width = 4 * strlen(str);
+    while (*str)
+    {
+        pdata = (uint8_t *)&ascii0816[(*str) * 16];
+        for (i = 0; i < 16; i++)
+        {
+            data = *pdata++;
+            pixel = ptr + i * width;
+            for (j = 0; j < 4; j++)
+            {
+                switch (data >> 6)
+                {
+                    case 0:
+                        *pixel = ((uint32_t)bg_color << 16) | bg_color;
+                        break;
+                    case 1:
+                        *pixel = ((uint32_t)bg_color << 16) | font_color;
+                        break;
+                    case 2:
+                        *pixel = ((uint32_t)font_color << 16) | bg_color;
+                        break;
+                    case 3:
+                        *pixel = ((uint32_t)font_color << 16) | font_color;
+                        break;
+                    default:
+                        *pixel = 0;
+                        break;
+                }
+                data <<= 2;
+                pixel++;
+            }
+        }
+        str++;
+        ptr += 4;
+    }
+}
+
+void lcd_clear(uint16_t color)
+{
+    uint32_t data = ((uint32_t)color << 16) | (uint32_t)color;
+
+    lcd_set_area(0, 0, lcd_ctl.width, lcd_ctl.height);
+    tft_fill_data(&data, LCD_X_MAX * LCD_Y_MAX / 2);
+}
+
+void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color)
+{
+    uint32_t data_buf[640] = {0};
+    uint32_t *p = data_buf;
+    uint32_t data = color;
+    uint32_t index = 0;
+
+    data = (data << 16) | data;
+    for (index = 0; index < 160 * width; index++)
+        *p++ = data;
+
+    lcd_set_area(x1, y1, x2, y1 + width - 1);
+    tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0);
+    lcd_set_area(x1, y2 - width + 1, x2, y2);
+    tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0);
+    lcd_set_area(x1, y1, x1 + width - 1, y2);
+    tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0);
+    lcd_set_area(x2 - width + 1, y1, x2, y2);
+    tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0);
+}
+
+void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr)
+{
+    lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1);
+    tft_write_word(ptr, width * height / 2, lcd_ctl.mode ? 2 : 0);
+}
+
+void lcd_draw_picture_half(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint16_t *ptr)
+{
+    lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1);
+    tft_write_half(ptr, width * height);
+}
+
+// https://blog.csdn.net/wllw7176/article/details/113847251
+void lcd_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
+{
+    uint16_t t;
+    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
+    int incx, incy, row, col;
+    uint32_t i = 0;
+ 
+    delta_x = x2 - x1;
+    delta_y = y2 - y1;
+    row = x1;
+    col = y1;
+ 
+    if(delta_x > 0)incx = 1;
+ 
+    else if(delta_x == 0)incx = 0;
+ 
+    else
+    {
+        incx = -1;
+        delta_x = -delta_x;
+    }
+ 
+    if(delta_y > 0)incy = 1;
+ 
+    else if(delta_y == 0)incy = 0;
+ 
+    else
+    {
+        incy = -1;
+        delta_y = -delta_y;
+    }
+ 
+    if(delta_x > delta_y)distance = delta_x;
+ 
+    else distance = delta_y;
+ 
+    for(t = 0; t <= distance + 1; t++)
+    {
+        lcd_draw_point(row, col, color);
+        xerr += delta_x ;
+        yerr += delta_y ;
+ 
+        if(xerr > distance)
+        {
+            xerr -= distance;
+            row += incx;
+        }
+ 
+        if(yerr > distance)
+        {
+            yerr -= distance;
+            col += incy;
+        }
+    }
+}
+#endif

+ 10 - 7
project_0/driver/Kconfig

@@ -174,28 +174,31 @@ menuconfig BSP_USING_CAMERA
 if BSP_USING_CAMERA
     config BSP_CAMERA_SCCB_SDA_PIN
         int "SCCB SDA pin number for camera"
-        default 9
+        default 15
+    config BSP_CAMERA_SCCB_SDA0_PIN
+        int "SCCB SDA0 pin number for gc03x8"
+        default 0
     config BSP_CAMERA_SCCB_SCLK_PIN
         int "SCCB SCLK pin number for camera"
-        default 10
+        default 14
     config BSP_CAMERA_CMOS_RST_PIN
         int "CMOS RST pin number for camera"
-        default 11
+        default 13
     config BSP_CAMERA_CMOS_VSYNC_PIN
         int "CMOS VSYNC pin number for camera"
         default 12
     config BSP_CAMERA_CMOS_PWDN_PIN
         int "CMOS PWDN pin number for camera"
-        default 13
+        default 11
     config BSP_CAMERA_CMOS_XCLK_PIN
         int "CMOS XCLK pin number for camera"
-        default 14
+        default 9
     config BSP_CAMERA_CMOS_PCLK_PIN
         int "CMOS PCLK pin number for camera"
-        default 15
+        default 8
     config BSP_CAMERA_CMOS_HREF_PIN
         int "CMOS HREF pin number for camera"
-        default 17
+        default 10
 endif
 
 menuconfig BSP_USING_RW007

+ 68 - 0
project_0/extmods/MicroPython_image_read_me.md

@@ -0,0 +1,68 @@
+# RT-AK MicroPython 图像处理模块
+
+## 1.简介
+
+该目录为针对[RT-AK](https://github.com/RT-Thread/RT-AK)的MicroPython图像处理模块Image Lib适配. 建议用户可先对C语言接口使用方法有所了解.
+
+## 2.RT-AK MicroPython函数使用说明
+
+### K210 图像处理模块
+
+K210 图像处理模块的所有python函数包含在extmods-k210文件夹中, 使用时应`import k210`. 在python环境下使用`dir(k210)`语句可查看模块所包含的函数名词.
+
+### cam_reset()
+
+该函数功能为初始化摄像头
+
+使用示例:cam.reset()
+
+### cam_set_framesize(height,weight)
+
+该函数功能为设定截取的一帧图像分辨率大小,Darco开发板配置摄像头分辨率为320x240
+
+使用示例:cam.set_framesize(320,240)
+
+### cam_snapshot()
+
+该函数功能为摄像头截取当前图像,截取图像为两张,分别为RGB565格式与RGB888格式,可将其分别显示
+
+使用示例:img1,img2=cam.snapshot()   //将截取的两张图像分别命名为img1、img2
+
+​         lcd.show_image(0,0,240,320,img1)   //显示img1 
+
+### crop(offset_height,offset_width,height,width)
+
+该函数功能为图像的裁剪,可适用于RGB565与RGB888格式,offset_height,offset_width分别表示裁剪的起始坐标的高与宽,height,width分别表示所需裁剪的大小的长与宽
+
+使用示例:new_img=img1.crop(0,0,160,160) // 将img1从(0,0)处开始裁剪160x160大小的图片并将裁剪的图片命名为new_img
+
+### resize(height,width)
+
+该函数的功能为图像的缩放,由于硬件固定了每一帧的分辨率为320x240,我们只需输入需要缩放的图像的高:height与宽:width,即可将图像缩放至指定大小
+
+使用示例:new_img=img1.resize(160,160) // 将img1缩放至160x160大小,并将裁剪的图片命名为 new_img
+
+### to_rgb565(name)
+
+由于LCD显示屏只能显示RGB565格式的图像,故如果直接显示img2(RGB888)则会花屏,故我们在对img2裁剪与缩放后,都需要将其转换为RGB565格式的图片进行显示,该函数就是用于实现图片格式转换为RGB565的功能
+
+ 使用示例: new_img=img2.crop(0,0,160,160)
+
+​           new_img1=new_img.to_rgb565() //将裁剪后的 new_img 转换为RGB565格式
+
+​           lcd.show_image(0,0,160,160,new_img1)
+
+
+
+### to_gray(name)
+
+#### ***!!!由于LCD显示屏只能显示RGB565格式的图像,如果只需要灰度图像对应的数组,不需要显示,则可直接使用。如需显示灰度图像,需在转换后用to_rgb565转换成RGB565格式图像再显示,否则会报错!!!
+
+该功能为了适配某些历程,可将RGB565、RGB888转换为grayscale格式
+
+ 使用示例:new_img=img1.to_gray() //将裁剪后的 new_img 转换为grayscale格式
+
+​          new_img_gray=new_img.to_rgb565()//为了显示,将grayscale格式转换为RGB565格式
+
+​          lcd.show_image(0,0,240,320,new_img_gray)
+

+ 0 - 0
project_0/extmods/README.md


+ 17 - 0
project_0/extmods/SConscript

@@ -0,0 +1,17 @@
+# RT-Thread building script for component
+
+from building import *
+
+cwd     = GetCurrentDir()
+src     = []
+CPPPATH = [cwd]
+
+if GetDepend('EXTMODS_MISC_USING_K210'):
+    src += Glob('k210/*.c')
+    CPPPATH += [cwd + '/k210']
+
+group = DefineGroup('extmods', src, depend = ['PRJ_USING_EXTMODS_MISC'], CPPPATH = CPPPATH)
+
+objs = [group]
+
+Return('objs')

+ 40 - 0
project_0/extmods/k210/__cmsis_gcc.h

@@ -0,0 +1,40 @@
+/**************************************************************************//**
+ * @file     cmsis_gcc.h
+ * @brief    CMSIS compiler GCC header file
+ * @version  V5.0.4
+ * @date     09. April 2018
+ ******************************************************************************/
+/*
+ * Copyright (c) 2009-2018 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ____CMSIS_GCC_H
+#define ____CMSIS_GCC_H
+
+#ifndef   __STATIC_INLINE
+  #define __STATIC_INLINE                        static inline
+#endif
+#ifndef   __STATIC_FORCEINLINE
+  #define __STATIC_FORCEINLINE                   __attribute__((always_inline)) static inline
+#endif
+
+__STATIC_FORCEINLINE uint32_t __UXTB_RORn(uint32_t op1, uint32_t rotate)
+{
+  return (op1 >> rotate) & 0xFF;
+}
+
+#endif //____CMSIS_GCC_H

+ 877 - 0
project_0/extmods/k210/bayer.c

@@ -0,0 +1,877 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Debayering Functions
+ */
+#include "imlib.h"
+
+void imlib_debayer_line(int x_start, int x_end, int y_row, void *dst_row_ptr, pixformat_t pixfmt, image_t *src)
+{
+    int src_w = src->w, w_limit = src_w - 1, w_limit_m_1 = w_limit - 1;
+    int src_h = src->h, h_limit = src_h - 1, h_limit_m_1 = h_limit - 1;
+
+    int y_row_odd = y_row & 1;
+    int y = (y_row / 2) * 2;
+    uint8_t *rowptr_grgr_0, *rowptr_bgbg_1, *rowptr_grgr_2, *rowptr_bgbg_3;
+
+    // keep row pointers in bounds
+    if (y == 0) {
+        rowptr_bgbg_1 = src->data;
+        rowptr_grgr_2 = rowptr_bgbg_1 + ((src_h >= 2) ? src_w : 0);
+        rowptr_bgbg_3 = rowptr_bgbg_1 + ((src_h >= 3) ? (src_w * 2) : 0);
+        rowptr_grgr_0 = rowptr_grgr_2;
+    } else if (y == h_limit_m_1) {
+        rowptr_grgr_0 = src->data + ((y - 1) * src_w);
+        rowptr_bgbg_1 = rowptr_grgr_0 + src_w;
+        rowptr_grgr_2 = rowptr_bgbg_1 + src_w;
+        rowptr_bgbg_3 = rowptr_bgbg_1;
+    } else if (y >= h_limit) {
+        rowptr_grgr_0 = src->data + ((y - 1) * src_w);
+        rowptr_bgbg_1 = rowptr_grgr_0 + src_w;
+        rowptr_grgr_2 = rowptr_grgr_0;
+        rowptr_bgbg_3 = rowptr_bgbg_1;
+    } else { // get 4 neighboring rows
+        rowptr_grgr_0 = src->data + ((y - 1) * src_w);
+        rowptr_bgbg_1 = rowptr_grgr_0 + src_w;
+        rowptr_grgr_2 = rowptr_bgbg_1 + src_w;
+        rowptr_bgbg_3 = rowptr_grgr_2 + src_w;
+    }
+
+    // If the image is an odd width this will go for the last loop and we drop the last column.
+    if (!y_row_odd) { // even
+        for (int x = x_start, i = 0; x < x_end; x += 2, i += 2) {
+            uint32_t row_grgr_0, row_bgbg_1, row_grgr_2;
+
+            // keep pixels in bounds
+            if (x == 0) {
+                if (src_w >= 4) {
+                    row_grgr_0 = *((uint32_t *) rowptr_grgr_0);
+                    row_bgbg_1 = *((uint32_t *) rowptr_bgbg_1);
+                    row_grgr_2 = *((uint32_t *) rowptr_grgr_2);
+                } else if (src_w >= 3) {
+                    row_grgr_0 = *((uint16_t *) rowptr_grgr_0) | (*(rowptr_grgr_0 + 2) << 16);
+                    row_bgbg_1 = *((uint16_t *) rowptr_bgbg_1) | (*(rowptr_bgbg_1 + 2) << 16);
+                    row_grgr_2 = *((uint16_t *) rowptr_grgr_2) | (*(rowptr_grgr_2 + 2) << 16);
+                } else if (src_w >= 2) {
+                    row_grgr_0 = *((uint16_t *) rowptr_grgr_0);
+                    row_grgr_0 = (row_grgr_0 << 16) | row_grgr_0;
+                    row_bgbg_1 = *((uint16_t *) rowptr_bgbg_1);
+                    row_bgbg_1 = (row_bgbg_1 << 16) | row_bgbg_1;
+                    row_grgr_2 = *((uint16_t *) rowptr_grgr_2);
+                    row_grgr_2 = (row_grgr_2 << 16) | row_grgr_2;
+                } else {
+                    row_grgr_0 = *(rowptr_grgr_0) * 0x01010101;
+                    row_bgbg_1 = *(rowptr_bgbg_1) * 0x01010101;
+                    row_grgr_2 = *(rowptr_grgr_2) * 0x01010101;
+                }
+                // The starting point needs to be offset by 1. The below patterns are actually
+                // rgrg, gbgb, rgrg, and gbgb. So, shift left and backfill the missing border pixel.
+                row_grgr_0 = (row_grgr_0 << 8) | __UXTB_RORn(row_grgr_0, 8);
+                row_bgbg_1 = (row_bgbg_1 << 8) | __UXTB_RORn(row_bgbg_1, 8);
+                row_grgr_2 = (row_grgr_2 << 8) | __UXTB_RORn(row_grgr_2, 8);
+            } else if (x == w_limit_m_1) {
+                row_grgr_0 = *((uint32_t *) (rowptr_grgr_0 + x - 2));
+                row_grgr_0 = (row_grgr_0 >> 8) | ((row_grgr_0 << 8) & 0xff000000);
+                row_bgbg_1 = *((uint32_t *) (rowptr_bgbg_1 + x - 2));
+                row_bgbg_1 = (row_bgbg_1 >> 8) | ((row_bgbg_1 << 8) & 0xff000000);
+                row_grgr_2 = *((uint32_t *) (rowptr_grgr_2 + x - 2));
+                row_grgr_2 = (row_grgr_2 >> 8) | ((row_grgr_2 << 8) & 0xff000000);
+            } else if (x >= w_limit) {
+                row_grgr_0 = *((uint16_t *) (rowptr_grgr_0 + x - 1));
+                row_grgr_0 = (row_grgr_0 << 16) | row_grgr_0;
+                row_bgbg_1 = *((uint16_t *) (rowptr_bgbg_1 + x - 1));
+                row_bgbg_1 = (row_bgbg_1 << 16) | row_bgbg_1;
+                row_grgr_2 = *((uint16_t *) (rowptr_grgr_2 + x - 1));
+                row_grgr_2 = (row_grgr_2 << 16) | row_grgr_2;
+            } else { // get 4 neighboring rows
+                row_grgr_0 = *((uint32_t *) (rowptr_grgr_0 + x - 1));
+                row_bgbg_1 = *((uint32_t *) (rowptr_bgbg_1 + x - 1));
+                row_grgr_2 = *((uint32_t *) (rowptr_grgr_2 + x - 1));
+            }
+
+            int r_pixels_0, g_pixels_0, b_pixels_0;
+
+            switch (src->pixfmt) {
+                case PIXFORMAT_BAYER_BGGR: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16(__UHADD8(row_02, __PKHTB(row_02, row_02, 16)));
+                    g_pixels_0 = __UXTB16(__UHADD8(row_1g, __PKHTB(row_1g, row_02, 8)));
+                    b_pixels_0 = __UXTB16_RORn(__UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16)), 8);
+                    #else
+
+                    int r0 = ((row_grgr_0 & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int r2 = (((row_grgr_0 >> 16) & 0xFF) + ((row_grgr_2 >> 16) & 0xFF)) >> 1;
+                    r_pixels_0 = (r2 << 16) | ((r0 + r2) >> 1);
+
+                    int g0 = (row_grgr_0 >> 8) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 8) & 0xFF;
+                    g_pixels_0 = (row_bgbg_1 & 0xFF0000) | ((((g0 + g2) >> 1) + g1) >> 1);
+
+                    int b1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    b_pixels_0 = (b1 << 16) | ((row_bgbg_1 >> 8) & 0xFF);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GBRG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16_RORn(__UHADD8(row_02, __PKHBT(row_02, row_02, 16)), 8);
+                    g_pixels_0 = __UXTB16_RORn(__UHADD8(row_1g, __PKHBT(row_1g, row_02, 8)), 8);
+                    b_pixels_0 = __UXTB16(__UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16)));
+                    #else
+
+                    int r0 = (((row_grgr_0 >> 8) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int r2 = (((row_grgr_0 >> 24) & 0xFF) + ((row_grgr_2 >> 24) & 0xFF)) >> 1;
+                    r_pixels_0 = r0 | (((r0 + r2) >> 1) << 16);
+
+                    int g0 = (row_grgr_0 >> 16) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 16) & 0xFF;
+                    g_pixels_0 = ((row_bgbg_1 >> 8) & 0xFF) | (((((g0 + g2) >> 1) + g1) >> 1) << 16);
+
+                    int b1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    b_pixels_0 = b1 | (row_bgbg_1 & 0xFF0000);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GRBG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16(__UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16)));
+                    g_pixels_0 = __UXTB16_RORn(__UHADD8(row_1g, __PKHBT(row_1g, row_02, 8)), 8);
+                    b_pixels_0 = __UXTB16_RORn(__UHADD8(row_02, __PKHBT(row_02, row_02, 16)), 8);
+                    #else
+
+                    int r1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    r_pixels_0 = r1 | (row_bgbg_1 & 0xFF0000);
+
+                    int g0 = (row_grgr_0 >> 16) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 16) & 0xFF;
+                    g_pixels_0 = ((row_bgbg_1 >> 8) & 0xFF) | (((((g0 + g2) >> 1) + g1) >> 1) << 16);
+
+                    int b0 = (((row_grgr_0 >> 8) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int b2 = (((row_grgr_0 >> 24) & 0xFF) + ((row_grgr_2 >> 24) & 0xFF)) >> 1;
+                    b_pixels_0 = b0 | (((b0 + b2) >> 1) << 16);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_RGGB: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16_RORn(__UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16)), 8);
+                    g_pixels_0 = __UXTB16(__UHADD8(row_1g, __PKHTB(row_1g, row_02, 8)));
+                    b_pixels_0 = __UXTB16(__UHADD8(row_02, __PKHTB(row_02, row_02, 16)));
+                    #else
+
+                    int r1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    r_pixels_0 = (r1 << 16) | ((row_bgbg_1 >> 8) & 0xFF);
+
+                    int g0 = (row_grgr_0 >> 8) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 8) & 0xFF;
+                    g_pixels_0 = (row_bgbg_1 & 0xFF0000) | ((((g0 + g2) >> 1) + g1) >> 1);
+
+                    int b0 = ((row_grgr_0 & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int b2 = (((row_grgr_0 >> 16) & 0xFF) + ((row_grgr_2 >> 16) & 0xFF)) >> 1;
+                    b_pixels_0 = (b2 << 16) | ((b0 + b2) >> 1);
+
+                    #endif
+                    break;
+                }
+                default: {
+                    r_pixels_0 = 0;
+                    g_pixels_0 = 0;
+                    b_pixels_0 = 0;
+                    break;
+                }
+            }
+
+            switch (pixfmt) {
+                case PIXFORMAT_BINARY: {
+                    uint32_t *dst_row_ptr_32 = (uint32_t *) dst_row_ptr;
+                    int y0 = ((r_pixels_0 * 38) + (g_pixels_0 * 75) + (b_pixels_0 * 15)) >> 7;
+                    IMAGE_PUT_BINARY_PIXEL_FAST(dst_row_ptr_32, i, (y0 >> 7));
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_BINARY_PIXEL_FAST(dst_row_ptr_32, i + 1, (y0 >> 23));
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_GRAYSCALE: {
+                    uint8_t *dst_row_ptr_8 = (uint8_t *) dst_row_ptr;
+                    int y0 = ((r_pixels_0 * 38) + (g_pixels_0 * 75) + (b_pixels_0 * 15)) >> 7;
+                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(dst_row_ptr_8, i, y0);
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_GRAYSCALE_PIXEL_FAST(dst_row_ptr_8, i + 1, y0 >> 16);
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_RGB565: {
+                    uint16_t *dst_row_ptr_16 = (uint16_t *) dst_row_ptr;
+                    int rgb565_0 = ((r_pixels_0 << 8) & 0xf800f800) |
+                                   ((g_pixels_0 << 3) & 0x07e007e0) |
+                                   ((b_pixels_0 >> 3) & 0x001f001f);
+
+                    if (x == w_limit) { // just put bottom
+                        IMAGE_PUT_RGB565_PIXEL_FAST(dst_row_ptr_16, i, rgb565_0);
+                    } else { // put both
+                        *((uint32_t *) (dst_row_ptr_16 + i)) = rgb565_0;
+                    }
+
+                    break;
+                }
+                default: {
+                    break;
+                }
+            }
+        }
+    } else { // odd
+        for (int x = x_start, i = 0; x < x_end; x += 2, i += 2) {
+            uint32_t row_bgbg_1, row_grgr_2, row_bgbg_3;
+
+            // keep pixels in bounds
+            if (x == 0) {
+                if (src_w >= 4) {
+                    row_bgbg_1 = *((uint32_t *) rowptr_bgbg_1);
+                    row_grgr_2 = *((uint32_t *) rowptr_grgr_2);
+                    row_bgbg_3 = *((uint32_t *) rowptr_bgbg_3);
+                } else if (src_w >= 3) {
+                    row_bgbg_1 = *((uint16_t *) rowptr_bgbg_1) | (*(rowptr_bgbg_1 + 2) << 16);
+                    row_grgr_2 = *((uint16_t *) rowptr_grgr_2) | (*(rowptr_grgr_2 + 2) << 16);
+                    row_bgbg_3 = *((uint16_t *) rowptr_bgbg_3) | (*(rowptr_bgbg_3 + 2) << 16);
+                } else if (src_w >= 2) {
+                    row_bgbg_1 = *((uint16_t *) rowptr_bgbg_1);
+                    row_bgbg_1 = (row_bgbg_1 << 16) | row_bgbg_1;
+                    row_grgr_2 = *((uint16_t *) rowptr_grgr_2);
+                    row_grgr_2 = (row_grgr_2 << 16) | row_grgr_2;
+                    row_bgbg_3 = *((uint16_t *) rowptr_bgbg_3);
+                    row_bgbg_3 = (row_bgbg_3 << 16) | row_bgbg_3;
+                } else {
+                    row_bgbg_1 = *(rowptr_bgbg_1) * 0x01010101;
+                    row_grgr_2 = *(rowptr_grgr_2) * 0x01010101;
+                    row_bgbg_3 = *(rowptr_bgbg_3) * 0x01010101;
+                }
+                // The starting point needs to be offset by 1. The below patterns are actually
+                // rgrg, gbgb, rgrg, and gbgb. So, shift left and backfill the missing border pixel.
+                row_bgbg_1 = (row_bgbg_1 << 8) | __UXTB_RORn(row_bgbg_1, 8);
+                row_grgr_2 = (row_grgr_2 << 8) | __UXTB_RORn(row_grgr_2, 8);
+                row_bgbg_3 = (row_bgbg_3 << 8) | __UXTB_RORn(row_bgbg_3, 8);
+            } else if (x == w_limit_m_1) {
+                row_bgbg_1 = *((uint32_t *) (rowptr_bgbg_1 + x - 2));
+                row_bgbg_1 = (row_bgbg_1 >> 8) | ((row_bgbg_1 << 8) & 0xff000000);
+                row_grgr_2 = *((uint32_t *) (rowptr_grgr_2 + x - 2));
+                row_grgr_2 = (row_grgr_2 >> 8) | ((row_grgr_2 << 8) & 0xff000000);
+                row_bgbg_3 = *((uint32_t *) (rowptr_bgbg_3 + x - 2));
+                row_bgbg_3 = (row_bgbg_3 >> 8) | ((row_bgbg_1 << 8) & 0xff000000);
+            } else if (x >= w_limit) {
+                row_bgbg_1 = *((uint16_t *) (rowptr_bgbg_1 + x - 1));
+                row_bgbg_1 = (row_bgbg_1 << 16) | row_bgbg_1;
+                row_grgr_2 = *((uint16_t *) (rowptr_grgr_2 + x - 1));
+                row_grgr_2 = (row_grgr_2 << 16) | row_grgr_2;
+                row_bgbg_3 = *((uint16_t *) (rowptr_bgbg_3 + x - 1));
+                row_bgbg_3 = (row_bgbg_3 << 16) | row_bgbg_3;
+            } else { // get 4 neighboring rows
+                row_bgbg_1 = *((uint32_t *) (rowptr_bgbg_1 + x - 1));
+                row_grgr_2 = *((uint32_t *) (rowptr_grgr_2 + x - 1));
+                row_bgbg_3 = *((uint32_t *) (rowptr_bgbg_3 + x - 1));
+            }
+
+            int r_pixels_1, g_pixels_1, b_pixels_1;
+
+            switch (src->pixfmt) {
+                case PIXFORMAT_BAYER_BGGR: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16(__UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16)));
+                    g_pixels_1 = __UXTB16_RORn(__UHADD8(row_2g, __PKHBT(row_2g, row_13, 8)), 8);
+                    b_pixels_1 = __UXTB16_RORn(__UHADD8(row_13, __PKHBT(row_13, row_13, 16)), 8);
+                    #else
+
+                    int r2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    r_pixels_1 = (row_grgr_2 & 0xFF0000) | r2;
+
+                    int g1 = (row_bgbg_1 >> 16) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 16) & 0xFF;
+                    g_pixels_1 = (((((g1 + g3) >> 1) + g2) >> 1) << 16) | ((row_grgr_2 >> 8) & 0xFF);
+
+                    int b1 = (((row_bgbg_1 >> 8) & 0xFF) + ((row_bgbg_3 >> 8) & 0xFF)) >> 1;
+                    int b3 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_3 >> 24) & 0xFF)) >> 1;
+                    b_pixels_1 = (((b1 + b3) >> 1) << 16) | b1;
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GBRG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16_RORn(__UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16)), 8);
+                    g_pixels_1 = __UXTB16(__UHADD8(row_2g, __PKHTB(row_2g, row_13, 8)));
+                    b_pixels_1 = __UXTB16(__UHADD8(row_13, __PKHTB(row_13, row_13, 16)));
+                    #else
+
+                    int r2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    r_pixels_1 = ((row_grgr_2 >> 8) & 0xFF) | (r2 << 16);
+
+                    int g1 = (row_bgbg_1 >> 8) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 8) & 0xFF;
+                    g_pixels_1 = ((((g1 + g3) >> 1) + g2) >> 1) | (row_grgr_2 & 0xFF0000);
+
+                    int b1 = ((row_bgbg_1 & 0xFF) + (row_bgbg_3 & 0xFF)) >> 1;
+                    int b3 = (((row_bgbg_1 >> 16) & 0xFF) + ((row_bgbg_3 >> 16) & 0xFF)) >> 1;
+                    b_pixels_1 = ((b1 + b3) >> 1) | (b3 << 16);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GRBG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16(__UHADD8(row_13, __PKHTB(row_13, row_13, 16)));
+                    g_pixels_1 = __UXTB16(__UHADD8(row_2g, __PKHTB(row_2g, row_13, 8)));
+                    b_pixels_1 = __UXTB16_RORn(__UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16)), 8);
+                    #else
+
+                    int r1 = ((row_bgbg_1 & 0xFF) + (row_bgbg_3 & 0xFF)) >> 1;
+                    int r3 = (((row_bgbg_1 >> 16) & 0xFF) + ((row_bgbg_3 >> 16) & 0xFF)) >> 1;
+                    r_pixels_1 = ((r1 + r3) >> 1) | (r3 << 16);
+
+                    int g1 = (row_bgbg_1 >> 8) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 8) & 0xFF;
+                    g_pixels_1 = ((((g1 + g3) >> 1) + g2) >> 1) | (row_grgr_2 & 0xFF0000);
+
+                    int b2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    b_pixels_1 = ((row_grgr_2 >> 8) & 0xFF) | (b2 << 16);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_RGGB: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16_RORn(__UHADD8(row_13, __PKHBT(row_13, row_13, 16)), 8);
+                    g_pixels_1 = __UXTB16_RORn(__UHADD8(row_2g, __PKHBT(row_2g, row_13, 8)), 8);
+                    b_pixels_1 = __UXTB16(__UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16)));
+                    #else
+
+                    int r1 = (((row_bgbg_1 >> 8) & 0xFF) + ((row_bgbg_3 >> 8) & 0xFF)) >> 1;
+                    int r3 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_3 >> 24) & 0xFF)) >> 1;
+                    r_pixels_1 = (((r1 + r3) >> 1) << 16) | r1;
+
+                    int g1 = (row_bgbg_1 >> 16) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 16) & 0xFF;
+                    g_pixels_1 = (((((g1 + g3) >> 1) + g2) >> 1) << 16) | ((row_grgr_2 >> 8) & 0xFF);
+
+                    int b2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    b_pixels_1 = (row_grgr_2 & 0xFF0000) | b2;
+
+                    #endif
+                    break;
+                }
+                default: {
+                    r_pixels_1 = 0;
+                    g_pixels_1 = 0;
+                    b_pixels_1 = 0;
+                    break;
+                }
+            }
+
+            switch (pixfmt) {
+                case PIXFORMAT_BINARY: {
+                    uint32_t *dst_row_ptr_32 = (uint32_t *) dst_row_ptr;
+                    int y1 = ((r_pixels_1 * 38) + (g_pixels_1 * 75) + (b_pixels_1 * 15)) >> 7;
+                    IMAGE_PUT_BINARY_PIXEL_FAST(dst_row_ptr_32, i, (y1 >> 7));
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_BINARY_PIXEL_FAST(dst_row_ptr_32, i + 1, (y1 >> 23));
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_GRAYSCALE: {
+                    uint8_t *dst_row_ptr_8 = (uint8_t *) dst_row_ptr;
+                    int y1 = ((r_pixels_1 * 38) + (g_pixels_1 * 75) + (b_pixels_1 * 15)) >> 7;
+                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(dst_row_ptr_8, i, y1);
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_GRAYSCALE_PIXEL_FAST(dst_row_ptr_8, i + 1, y1 >> 16);
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_RGB565: {
+                    uint16_t *dst_row_ptr_16 = (uint16_t *) dst_row_ptr;
+                    int rgb565_1 = ((r_pixels_1 << 8) & 0xf800f800) |
+                                   ((g_pixels_1 << 3) & 0x07e007e0) |
+                                   ((b_pixels_1 >> 3) & 0x001f001f);
+
+                    if (x == w_limit) { // just put bottom
+                        IMAGE_PUT_RGB565_PIXEL_FAST(dst_row_ptr_16, i, rgb565_1);
+                    } else { // put both
+                        *((uint32_t *) (dst_row_ptr_16 + i)) = rgb565_1;
+                    }
+
+                    break;
+                }
+                default: {
+                    break;
+                }
+            }
+        }
+    }
+}
+
+// Does no bounds checking on the destination. Destination must be mutable.
+void imlib_debayer_image(image_t *dst, image_t *src)
+{
+    int src_w = src->w, w_limit = src_w - 1, w_limit_m_1 = w_limit - 1;
+    int src_h = src->h, h_limit = src_h - 1, h_limit_m_1 = h_limit - 1;
+
+    // If the image is an odd height this will go for the last loop and we drop the last row.
+    for (int y = 0; y < src_h; y += 2) {
+        void *row_ptr_e = NULL, *row_ptr_o = NULL;
+
+        switch (dst->pixfmt) {
+            case PIXFORMAT_BINARY: {
+                row_ptr_e = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(dst, y);
+                row_ptr_o = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(dst, y + 1);
+                break;
+            }
+            case PIXFORMAT_GRAYSCALE: {
+                row_ptr_e = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(dst, y);
+                row_ptr_o = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(dst, y + 1);
+                break;
+            }
+            case PIXFORMAT_RGB565: {
+                row_ptr_e = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(dst, y);
+                row_ptr_o = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(dst, y + 1);
+                break;
+            }
+        }
+
+        uint8_t *rowptr_grgr_0, *rowptr_bgbg_1, *rowptr_grgr_2, *rowptr_bgbg_3;
+
+        // keep row pointers in bounds
+        if (y == 0) {
+            rowptr_bgbg_1 = src->data;
+            rowptr_grgr_2 = rowptr_bgbg_1 + ((src_h >= 2) ? src_w : 0);
+            rowptr_bgbg_3 = rowptr_bgbg_1 + ((src_h >= 3) ? (src_w * 2) : 0);
+            rowptr_grgr_0 = rowptr_grgr_2;
+        } else if (y == h_limit_m_1) {
+            rowptr_grgr_0 = src->data + ((y - 1) * src_w);
+            rowptr_bgbg_1 = rowptr_grgr_0 + src_w;
+            rowptr_grgr_2 = rowptr_bgbg_1 + src_w;
+            rowptr_bgbg_3 = rowptr_bgbg_1;
+        } else if (y >= h_limit) {
+            rowptr_grgr_0 = src->data + ((y - 1) * src_w);
+            rowptr_bgbg_1 = rowptr_grgr_0 + src_w;
+            rowptr_grgr_2 = rowptr_grgr_0;
+            rowptr_bgbg_3 = rowptr_bgbg_1;
+        } else { // get 4 neighboring rows
+            rowptr_grgr_0 = src->data + ((y - 1) * src_w);
+            rowptr_bgbg_1 = rowptr_grgr_0 + src_w;
+            rowptr_grgr_2 = rowptr_bgbg_1 + src_w;
+            rowptr_bgbg_3 = rowptr_grgr_2 + src_w;
+        }
+
+        // If the image is an odd width this will go for the last loop and we drop the last column.
+        for (int x = 0; x < src_w; x += 2) {
+            uint32_t row_grgr_0, row_bgbg_1, row_grgr_2, row_bgbg_3;
+
+            // keep pixels in bounds
+            if (x == 0) {
+                if (src_w >= 4) {
+                    row_grgr_0 = *((uint32_t *) rowptr_grgr_0);
+                    row_bgbg_1 = *((uint32_t *) rowptr_bgbg_1);
+                    row_grgr_2 = *((uint32_t *) rowptr_grgr_2);
+                    row_bgbg_3 = *((uint32_t *) rowptr_bgbg_3);
+                } else if (src_w >= 3) {
+                    row_grgr_0 = *((uint16_t *) rowptr_grgr_0) | (*(rowptr_grgr_0 + 2) << 16);
+                    row_bgbg_1 = *((uint16_t *) rowptr_bgbg_1) | (*(rowptr_bgbg_1 + 2) << 16);
+                    row_grgr_2 = *((uint16_t *) rowptr_grgr_2) | (*(rowptr_grgr_2 + 2) << 16);
+                    row_bgbg_3 = *((uint16_t *) rowptr_bgbg_3) | (*(rowptr_bgbg_3 + 2) << 16);
+                } else if (src_w >= 2) {
+                    row_grgr_0 = *((uint16_t *) rowptr_grgr_0);
+                    row_grgr_0 = (row_grgr_0 << 16) | row_grgr_0;
+                    row_bgbg_1 = *((uint16_t *) rowptr_bgbg_1);
+                    row_bgbg_1 = (row_bgbg_1 << 16) | row_bgbg_1;
+                    row_grgr_2 = *((uint16_t *) rowptr_grgr_2);
+                    row_grgr_2 = (row_grgr_2 << 16) | row_grgr_2;
+                    row_bgbg_3 = *((uint16_t *) rowptr_bgbg_3);
+                    row_bgbg_3 = (row_bgbg_3 << 16) | row_bgbg_3;
+                } else {
+                    row_grgr_0 = *(rowptr_grgr_0) * 0x01010101;
+                    row_bgbg_1 = *(rowptr_bgbg_1) * 0x01010101;
+                    row_grgr_2 = *(rowptr_grgr_2) * 0x01010101;
+                    row_bgbg_3 = *(rowptr_bgbg_3) * 0x01010101;
+                }
+                // The starting point needs to be offset by 1. The below patterns are actually
+                // rgrg, gbgb, rgrg, and gbgb. So, shift left and backfill the missing border pixel.
+                row_grgr_0 = (row_grgr_0 << 8) | __UXTB_RORn(row_grgr_0, 8);
+                row_bgbg_1 = (row_bgbg_1 << 8) | __UXTB_RORn(row_bgbg_1, 8);
+                row_grgr_2 = (row_grgr_2 << 8) | __UXTB_RORn(row_grgr_2, 8);
+                row_bgbg_3 = (row_bgbg_3 << 8) | __UXTB_RORn(row_bgbg_3, 8);
+            } else if (x == w_limit_m_1) {
+                row_grgr_0 = *((uint32_t *) (rowptr_grgr_0 + x - 2));
+                row_grgr_0 = (row_grgr_0 >> 8) | ((row_grgr_0 << 8) & 0xff000000);
+                row_bgbg_1 = *((uint32_t *) (rowptr_bgbg_1 + x - 2));
+                row_bgbg_1 = (row_bgbg_1 >> 8) | ((row_bgbg_1 << 8) & 0xff000000);
+                row_grgr_2 = *((uint32_t *) (rowptr_grgr_2 + x - 2));
+                row_grgr_2 = (row_grgr_2 >> 8) | ((row_grgr_2 << 8) & 0xff000000);
+                row_bgbg_3 = *((uint32_t *) (rowptr_bgbg_3 + x - 2));
+                row_bgbg_3 = (row_bgbg_3 >> 8) | ((row_bgbg_1 << 8) & 0xff000000);
+            } else if (x >= w_limit) {
+                row_grgr_0 = *((uint16_t *) (rowptr_grgr_0 + x - 1));
+                row_grgr_0 = (row_grgr_0 << 16) | row_grgr_0;
+                row_bgbg_1 = *((uint16_t *) (rowptr_bgbg_1 + x - 1));
+                row_bgbg_1 = (row_bgbg_1 << 16) | row_bgbg_1;
+                row_grgr_2 = *((uint16_t *) (rowptr_grgr_2 + x - 1));
+                row_grgr_2 = (row_grgr_2 << 16) | row_grgr_2;
+                row_bgbg_3 = *((uint16_t *) (rowptr_bgbg_3 + x - 1));
+                row_bgbg_3 = (row_bgbg_3 << 16) | row_bgbg_3;
+            } else { // get 4 neighboring rows
+                row_grgr_0 = *((uint32_t *) (rowptr_grgr_0 + x - 1));
+                row_bgbg_1 = *((uint32_t *) (rowptr_bgbg_1 + x - 1));
+                row_grgr_2 = *((uint32_t *) (rowptr_grgr_2 + x - 1));
+                row_bgbg_3 = *((uint32_t *) (rowptr_bgbg_3 + x - 1));
+            }
+
+            int r_pixels_0, g_pixels_0, b_pixels_0;
+
+            switch (src->pixfmt) {
+                case PIXFORMAT_BAYER_BGGR: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16(__UHADD8(row_02, __PKHTB(row_02, row_02, 16)));
+                    g_pixels_0 = __UXTB16(__UHADD8(row_1g, __PKHTB(row_1g, row_02, 8)));
+                    b_pixels_0 = __UXTB16_RORn(__UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16)), 8);
+                    #else
+
+                    int r0 = ((row_grgr_0 & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int r2 = (((row_grgr_0 >> 16) & 0xFF) + ((row_grgr_2 >> 16) & 0xFF)) >> 1;
+                    r_pixels_0 = (r2 << 16) | ((r0 + r2) >> 1);
+
+                    int g0 = (row_grgr_0 >> 8) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 8) & 0xFF;
+                    g_pixels_0 = (row_bgbg_1 & 0xFF0000) | ((((g0 + g2) >> 1) + g1) >> 1);
+
+                    int b1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    b_pixels_0 = (b1 << 16) | ((row_bgbg_1 >> 8) & 0xFF);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GBRG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16_RORn(__UHADD8(row_02, __PKHBT(row_02, row_02, 16)), 8);
+                    g_pixels_0 = __UXTB16_RORn(__UHADD8(row_1g, __PKHBT(row_1g, row_02, 8)), 8);
+                    b_pixels_0 = __UXTB16(__UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16)));
+                    #else
+
+                    int r0 = (((row_grgr_0 >> 8) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int r2 = (((row_grgr_0 >> 24) & 0xFF) + ((row_grgr_2 >> 24) & 0xFF)) >> 1;
+                    r_pixels_0 = r0 | (((r0 + r2) >> 1) << 16);
+
+                    int g0 = (row_grgr_0 >> 16) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 16) & 0xFF;
+                    g_pixels_0 = ((row_bgbg_1 >> 8) & 0xFF) | (((((g0 + g2) >> 1) + g1) >> 1) << 16);
+
+                    int b1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    b_pixels_0 = b1 | (row_bgbg_1 & 0xFF0000);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GRBG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16(__UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16)));
+                    g_pixels_0 = __UXTB16_RORn(__UHADD8(row_1g, __PKHBT(row_1g, row_02, 8)), 8);
+                    b_pixels_0 = __UXTB16_RORn(__UHADD8(row_02, __PKHBT(row_02, row_02, 16)), 8);
+                    #else
+
+                    int r1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    r_pixels_0 = r1 | (row_bgbg_1 & 0xFF0000);
+
+                    int g0 = (row_grgr_0 >> 16) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 16) & 0xFF;
+                    g_pixels_0 = ((row_bgbg_1 >> 8) & 0xFF) | (((((g0 + g2) >> 1) + g1) >> 1) << 16);
+
+                    int b0 = (((row_grgr_0 >> 8) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int b2 = (((row_grgr_0 >> 24) & 0xFF) + ((row_grgr_2 >> 24) & 0xFF)) >> 1;
+                    b_pixels_0 = b0 | (((b0 + b2) >> 1) << 16);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_RGGB: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_02 = __UHADD8(row_grgr_0, row_grgr_2);
+                    int row_1g = __UHADD8(row_bgbg_1, __PKHTB(row_bgbg_1, row_bgbg_1, 16));
+
+                    r_pixels_0 = __UXTB16_RORn(__UHADD8(row_bgbg_1, __PKHBT(row_bgbg_1, row_bgbg_1, 16)), 8);
+                    g_pixels_0 = __UXTB16(__UHADD8(row_1g, __PKHTB(row_1g, row_02, 8)));
+                    b_pixels_0 = __UXTB16(__UHADD8(row_02, __PKHTB(row_02, row_02, 16)));
+                    #else
+
+                    int r1 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_1 >> 8) & 0xFF)) >> 1;
+                    r_pixels_0 = (r1 << 16) | ((row_bgbg_1 >> 8) & 0xFF);
+
+                    int g0 = (row_grgr_0 >> 8) & 0xFF;
+                    int g1 = (((row_bgbg_1 >> 16) & 0xFF) + (row_bgbg_1 & 0xFF)) >> 1;
+                    int g2 = (row_grgr_2 >> 8) & 0xFF;
+                    g_pixels_0 = (row_bgbg_1 & 0xFF0000) | ((((g0 + g2) >> 1) + g1) >> 1);
+
+                    int b0 = ((row_grgr_0 & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int b2 = (((row_grgr_0 >> 16) & 0xFF) + ((row_grgr_2 >> 16) & 0xFF)) >> 1;
+                    b_pixels_0 = (b2 << 16) | ((b0 + b2) >> 1);
+
+                    #endif
+                    break;
+                }
+                default: {
+                    r_pixels_0 = 0;
+                    g_pixels_0 = 0;
+                    b_pixels_0 = 0;
+                    break;
+                }
+            }
+
+            switch (dst->pixfmt) {
+                case PIXFORMAT_BINARY: {
+                    uint32_t *row_ptr_e_32 = (uint32_t *) row_ptr_e;
+                    int y0 = ((r_pixels_0 * 38) + (g_pixels_0 * 75) + (b_pixels_0 * 15)) >> 7;
+                    IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_e_32, x, (y0 >> 7));
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_e_32, x + 1, (y0 >> 23));
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_GRAYSCALE: {
+                    uint8_t *row_ptr_e_8 = (uint8_t *) row_ptr_e;
+                    int y0 = ((r_pixels_0 * 38) + (g_pixels_0 * 75) + (b_pixels_0 * 15)) >> 7;
+                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_e_8, x, y0);
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_e_8, x + 1, y0 >> 16);
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_RGB565: {
+                    uint16_t *row_ptr_e_16 = (uint16_t *) row_ptr_e;
+                    int rgb565_0 = ((r_pixels_0 << 8) & 0xf800f800) |
+                                   ((g_pixels_0 << 3) & 0x07e007e0) |
+                                   ((b_pixels_0 >> 3) & 0x001f001f);
+
+                    if (x == w_limit) { // just put bottom
+                        IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_e_16, x, rgb565_0);
+                    } else { // put both
+                        *((uint32_t *) (row_ptr_e_16 + x)) = rgb565_0;
+                    }
+
+                    break;
+                }
+            }
+
+            if (y == h_limit) {
+                continue;
+            }
+
+            int r_pixels_1, g_pixels_1, b_pixels_1;
+
+            switch (src->pixfmt) {
+                case PIXFORMAT_BAYER_BGGR: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16(__UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16)));
+                    g_pixels_1 = __UXTB16_RORn(__UHADD8(row_2g, __PKHBT(row_2g, row_13, 8)), 8);
+                    b_pixels_1 = __UXTB16_RORn(__UHADD8(row_13, __PKHBT(row_13, row_13, 16)), 8);
+                    #else
+
+                    int r2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    r_pixels_1 = (row_grgr_2 & 0xFF0000) | r2;
+
+                    int g1 = (row_bgbg_1 >> 16) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 16) & 0xFF;
+                    g_pixels_1 = (((((g1 + g3) >> 1) + g2) >> 1) << 16) | ((row_grgr_2 >> 8) & 0xFF);
+
+                    int b1 = (((row_bgbg_1 >> 8) & 0xFF) + ((row_bgbg_3 >> 8) & 0xFF)) >> 1;
+                    int b3 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_3 >> 24) & 0xFF)) >> 1;
+                    b_pixels_1 = (((b1 + b3) >> 1) << 16) | b1;
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GBRG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16_RORn(__UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16)), 8);
+                    g_pixels_1 = __UXTB16(__UHADD8(row_2g, __PKHTB(row_2g, row_13, 8)));
+                    b_pixels_1 = __UXTB16(__UHADD8(row_13, __PKHTB(row_13, row_13, 16)));
+                    #else
+
+                    int r2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    r_pixels_1 = ((row_grgr_2 >> 8) & 0xFF) | (r2 << 16);
+
+                    int g1 = (row_bgbg_1 >> 8) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 8) & 0xFF;
+                    g_pixels_1 = ((((g1 + g3) >> 1) + g2) >> 1) | (row_grgr_2 & 0xFF0000);
+
+                    int b1 = ((row_bgbg_1 & 0xFF) + (row_bgbg_3 & 0xFF)) >> 1;
+                    int b3 = (((row_bgbg_1 >> 16) & 0xFF) + ((row_bgbg_3 >> 16) & 0xFF)) >> 1;
+                    b_pixels_1 = ((b1 + b3) >> 1) | (b3 << 16);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_GRBG: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16(__UHADD8(row_13, __PKHTB(row_13, row_13, 16)));
+                    g_pixels_1 = __UXTB16(__UHADD8(row_2g, __PKHTB(row_2g, row_13, 8)));
+                    b_pixels_1 = __UXTB16_RORn(__UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16)), 8);
+                    #else
+
+                    int r1 = ((row_bgbg_1 & 0xFF) + (row_bgbg_3 & 0xFF)) >> 1;
+                    int r3 = (((row_bgbg_1 >> 16) & 0xFF) + ((row_bgbg_3 >> 16) & 0xFF)) >> 1;
+                    r_pixels_1 = ((r1 + r3) >> 1) | (r3 << 16);
+
+                    int g1 = (row_bgbg_1 >> 8) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 8) & 0xFF;
+                    g_pixels_1 = ((((g1 + g3) >> 1) + g2) >> 1) | (row_grgr_2 & 0xFF0000);
+
+                    int b2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    b_pixels_1 = ((row_grgr_2 >> 8) & 0xFF) | (b2 << 16);
+
+                    #endif
+                    break;
+                }
+                case PIXFORMAT_BAYER_RGGB: {
+                    #if defined(ARM_MATH_DSP)
+                    int row_13 = __UHADD8(row_bgbg_1, row_bgbg_3);
+                    int row_2g = __UHADD8(row_grgr_2, __PKHBT(row_grgr_2, row_grgr_2, 16));
+
+                    r_pixels_1 = __UXTB16_RORn(__UHADD8(row_13, __PKHBT(row_13, row_13, 16)), 8);
+                    g_pixels_1 = __UXTB16_RORn(__UHADD8(row_2g, __PKHBT(row_2g, row_13, 8)), 8);
+                    b_pixels_1 = __UXTB16(__UHADD8(row_grgr_2, __PKHTB(row_grgr_2, row_grgr_2, 16)));
+                    #else
+
+                    int r1 = (((row_bgbg_1 >> 8) & 0xFF) + ((row_bgbg_3 >> 8) & 0xFF)) >> 1;
+                    int r3 = (((row_bgbg_1 >> 24) & 0xFF) + ((row_bgbg_3 >> 24) & 0xFF)) >> 1;
+                    r_pixels_1 = (((r1 + r3) >> 1) << 16) | r1;
+
+                    int g1 = (row_bgbg_1 >> 16) & 0xFF;
+                    int g2 = (((row_grgr_2 >> 24) & 0xFF) + ((row_grgr_2 >> 8) & 0xFF)) >> 1;
+                    int g3 = (row_bgbg_3 >> 16) & 0xFF;
+                    g_pixels_1 = (((((g1 + g3) >> 1) + g2) >> 1) << 16) | ((row_grgr_2 >> 8) & 0xFF);
+
+                    int b2 = (((row_grgr_2 >> 16) & 0xFF) + (row_grgr_2 & 0xFF)) >> 1;
+                    b_pixels_1 = (row_grgr_2 & 0xFF0000) | b2;
+
+                    #endif
+                    break;
+                }
+                default: {
+                    r_pixels_1 = 0;
+                    g_pixels_1 = 0;
+                    b_pixels_1 = 0;
+                    break;
+                }
+            }
+
+            switch (dst->pixfmt) {
+                case PIXFORMAT_BINARY: {
+                    uint32_t *row_ptr_o_32 = (uint32_t *) row_ptr_o;
+                    int y1 = ((r_pixels_1 * 38) + (g_pixels_1 * 75) + (b_pixels_1 * 15)) >> 7;
+                    IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_o_32, x, (y1 >> 7));
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_o_32, x + 1, (y1 >> 23));
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_GRAYSCALE: {
+                    uint8_t *row_ptr_o_8 = (uint8_t *) row_ptr_o;
+                    int y1 = ((r_pixels_1 * 38) + (g_pixels_1 * 75) + (b_pixels_1 * 15)) >> 7;
+                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_o_8, x, y1);
+
+                    if (x != w_limit) {
+                        IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_o_8, x + 1, y1 >> 16);
+                    }
+
+                    break;
+                }
+                case PIXFORMAT_RGB565: {
+                    uint16_t *row_ptr_o_16 = (uint16_t *) row_ptr_o;
+                    int rgb565_1 = ((r_pixels_1 << 8) & 0xf800f800) |
+                                   ((g_pixels_1 << 3) & 0x07e007e0) |
+                                   ((b_pixels_1 >> 3) & 0x001f001f);
+
+                    if (x == w_limit) { // just put bottom
+                        IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_o_16, x, rgb565_1);
+                    } else { // put both
+                        *((uint32_t *) (row_ptr_o_16 + x)) = rgb565_1;
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+}

+ 40 - 0
project_0/extmods/k210/common.h

@@ -0,0 +1,40 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Common macros.
+ */
+#ifndef __OMV_COMMON_H__
+
+#define OMV_ATTR_ALIGNED(x, a)   x __attribute__((aligned(a)))
+#define OMV_ATTR_SECTION(x, s)   x __attribute__((section(s)))
+#define OMV_ATTR_ALWAYS_INLINE  /* inline __attribute__((always_inline)) */
+#define OMV_ATTR_OPTIMIZE(o)    __attribute__((optimize(o)))
+
+// #define OMG_BREAK() __asm__ volatile ("BKPT")
+
+#ifdef OMV_DEBUG_PRINTF
+#define debug_printf(fmt, ...) \
+            do { printf("%s(): " fmt, __func__, ##__VA_ARGS__);} while (0)
+#else
+#define debug_printf(...)
+#endif
+
+#define OMV_MAX(a,b)                    \
+({                                      \
+    __typeof__ (a) _a = (a);            \
+    __typeof__ (b) _b = (b);            \
+    _a > _b ? _a : _b;                  \
+})
+
+#define OMV_MIN(a,b)                    \
+({                                      \
+    __typeof__ (a) _a = (a);            \
+    __typeof__ (b) _b = (b);            \
+    _a < _b ? _a : _b;                  \
+})
+#endif //__OMV_COMMON_H__

+ 279 - 0
project_0/extmods/k210/draw.c

@@ -0,0 +1,279 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Basic drawing functions.
+ */
+#include "font.h"
+#include "imlib.h"
+/* start openmv @file:draw.c @line:57 */
+// Set pixel (handles boundary check and image type check).
+void imlib_set_pixel(image_t *img, int x, int y, int p)
+{
+    if ((0 <= x) && (x < img->w) && (0 <= y) && (y < img->h)) {
+        switch (img->pixfmt) {
+            case PIXFORMAT_BINARY: {
+                IMAGE_PUT_BINARY_PIXEL(img, x, y, p);
+                break;
+            }
+            case PIXFORMAT_GRAYSCALE: {
+                IMAGE_PUT_GRAYSCALE_PIXEL(img, x, y, p);
+                break;
+            }
+            case PIXFORMAT_RGB565: {
+                IMAGE_PUT_RGB565_PIXEL(img, x, y, p);
+                break;
+            }
+            default: {
+                break;
+            }
+        }
+    }
+}
+
+// https://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles
+static void point_fill(image_t *img, int cx, int cy, int r0, int r1, int c)
+{
+    for (int y = r0; y <= r1; y++) {
+        for (int x = r0; x <= r1; x++) {
+            if (((x * x) + (y * y)) <= (r0 * r0)) {
+                imlib_set_pixel(img, cx + x, cy + y, c);
+            }
+        }
+    }
+}
+
+// https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C
+void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness)
+{
+    if (thickness > 0) {
+        int thickness0 = (thickness - 0) / 2;
+        int thickness1 = (thickness - 1) / 2;
+        int dx = abs(x1 - x0), sx = (x0 < x1) ? 1 : -1;
+        int dy = abs(y1 - y0), sy = (y0 < y1) ? 1 : -1;
+        int err = ((dx > dy) ? dx : -dy) / 2;
+
+        for (;;) {
+            point_fill(img, x0, y0, -thickness0, thickness1, c);
+            if ((x0 == x1) && (y0 == y1)) break;
+            int e2 = err;
+            if (e2 > -dx) { err -= dy; x0 += sx; }
+            if (e2 <  dy) { err += dx; y0 += sy; }
+        }
+    }
+}
+
+
+static void xLine(image_t *img, int x1, int x2, int y, int c)
+{
+    while (x1 <= x2) imlib_set_pixel(img, x1++, y, c);
+}
+
+static void yLine(image_t *img, int x, int y1, int y2, int c)
+{
+    while (y1 <= y2) imlib_set_pixel(img, x, y1++, c);
+}
+
+void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill)
+{
+    if (fill) {
+
+        for (int y = ry, yy = ry + rh; y < yy; y++) {
+            for (int x = rx, xx = rx + rw; x < xx; x++) {
+                imlib_set_pixel(img, x, y, c);
+            }
+        }
+
+    } else if (thickness > 0) {
+        int thickness0 = (thickness - 0) / 2;
+        int thickness1 = (thickness - 1) / 2;
+
+        for (int i = rx - thickness0, j = rx + rw + thickness1, k = ry + rh - 1; i < j; i++) {
+            yLine(img, i, ry - thickness0, ry + thickness1, c);
+            yLine(img, i, k - thickness0, k + thickness1, c);
+        }
+
+        for (int i = ry - thickness0, j = ry + rh + thickness1, k = rx + rw - 1; i < j; i++) {
+            xLine(img, rx - thickness0, rx + thickness1, i, c);
+            xLine(img, k - thickness0, k + thickness1, i, c);
+        }
+    }
+}
+
+// https://stackoverflow.com/questions/27755514/circle-with-thickness-drawing-algorithm
+void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill)
+{
+    if (fill) {
+        point_fill(img, cx, cy, -r, r, c);
+    } else if (thickness > 0) {
+        int thickness0 = (thickness - 0) / 2;
+        int thickness1 = (thickness - 1) / 2;
+
+        int xo = r + thickness0;
+        int xi = IM_MAX(r - thickness1, 0);
+        int xi_tmp = xi;
+        int y = 0;
+        int erro = 1 - xo;
+        int erri = 1 - xi;
+
+        while(xo >= y) {
+            xLine(img, cx + xi, cx + xo, cy + y,  c);
+            yLine(img, cx + y,  cy + xi, cy + xo, c);
+            xLine(img, cx - xo, cx - xi, cy + y,  c);
+            yLine(img, cx - y,  cy + xi, cy + xo, c);
+            xLine(img, cx - xo, cx - xi, cy - y,  c);
+            yLine(img, cx - y,  cy - xo, cy - xi, c);
+            xLine(img, cx + xi, cx + xo, cy - y,  c);
+            yLine(img, cx + y,  cy - xo, cy - xi, c);
+
+            y++;
+
+            if (erro < 0) {
+                erro += 2 * y + 1;
+            } else {
+                xo--;
+                erro += 2 * (y - xo + 1);
+            }
+
+            if (y > xi_tmp) {
+                xi = y;
+            } else {
+                if (erri < 0) {
+                    erri += 2 * y + 1;
+                } else {
+                    xi--;
+                    erri += 2 * (y - xi + 1);
+                }
+            }
+        }
+    }
+}
+
+/* origin openmv @file:draw.c @line:316 */
+// char rotation == 0, 90, 180, 360, etc.
+// string rotation == 0, 90, 180, 360, etc.
+void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space,
+                       int char_rotation, bool char_hmirror, bool char_vflip, int string_rotation, bool string_hmirror, bool string_vflip)
+{
+    char_rotation %= 360;
+    if (char_rotation < 0) char_rotation += 360;
+    char_rotation = (char_rotation / 90) * 90;
+
+    string_rotation %= 360;
+    if (string_rotation < 0) string_rotation += 360;
+    string_rotation = (string_rotation / 90) * 90;
+
+    bool char_swap_w_h = (char_rotation == 90) || (char_rotation == 270);
+    bool char_upsidedown = (char_rotation == 180) || (char_rotation == 270);
+
+    if (string_hmirror) x_off -= fast_floorf(font[0].w * scale) - 1;
+    if (string_vflip) y_off -= fast_floorf(font[0].h * scale) - 1;
+
+    int org_x_off = x_off;
+    int org_y_off = y_off;
+    const int anchor = x_off;
+
+    for(char ch, last = '\0'; (ch = *str); str++, last = ch) {
+
+        if ((last == '\r') && (ch == '\n')) { // handle "\r\n" strings
+            continue;
+        }
+
+        if ((ch == '\n') || (ch == '\r')) { // handle '\n' or '\r' strings
+            x_off = anchor;
+            y_off += (string_vflip ? -1 : +1) * (fast_floorf((char_swap_w_h ? font[0].w : font[0].h) * scale) + y_spacing); // newline height == space height
+            continue;
+        }
+
+        if ((ch < ' ') || (ch > '~')) { // handle unknown characters
+            continue;
+        }
+
+        const glyph_t *g = &font[ch - ' '];
+
+        if (!mono_space) {
+            // Find the first pixel set and offset to that.
+            bool exit = false;
+
+            if (!char_swap_w_h) {
+                for (int x = 0, xx = g->w; x < xx; x++) {
+                    for (int y = 0, yy = g->h; y < yy; y++) {
+                        if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] &
+                            (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) {
+                            x_off += (string_hmirror ? +1 : -1) * fast_floorf(x * scale);
+                            exit = true;
+                            break;
+                        }
+                    }
+
+                    if (exit) break;
+                }
+            } else {
+                for (int y = g->h - 1; y >= 0; y--) {
+                    for (int x = 0, xx = g->w; x < xx; x++) {
+                        if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] &
+                            (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) {
+                            x_off += (string_hmirror ? +1 : -1) * fast_floorf((g->h - 1 - y) * scale);
+                            exit = true;
+                            break;
+                        }
+                    }
+
+                    if (exit) break;
+                }
+            }
+        }
+
+        for (int y = 0, yy = fast_floorf(g->h * scale); y < yy; y++) {
+            for (int x = 0, xx = fast_floorf(g->w * scale); x < xx; x++) {
+                if (g->data[fast_floorf(y / scale)] & (1 << (g->w - 1 - fast_floorf(x / scale)))) {
+                    int16_t x_tmp = x_off + (char_hmirror ? (xx - x - 1) : x), y_tmp = y_off + (char_vflip ? (yy - y - 1) : y);
+                    point_rotate(x_tmp, y_tmp, IM_DEG2RAD(char_rotation), x_off + (xx / 2), y_off + (yy / 2), &x_tmp, &y_tmp);
+                    point_rotate(x_tmp, y_tmp, IM_DEG2RAD(string_rotation), org_x_off, org_y_off, &x_tmp, &y_tmp);
+                    imlib_set_pixel(img, x_tmp, y_tmp, c);
+                }
+            }
+        }
+
+        if (mono_space) {
+            x_off += (string_hmirror ? -1 : +1) * (fast_floorf((char_swap_w_h ? g->h : g->w) * scale) + x_spacing);
+        } else {
+            // Find the last pixel set and offset to that.
+            bool exit = false;
+
+            if (!char_swap_w_h) {
+                for (int x = g->w - 1; x >= 0; x--) {
+                    for (int y = g->h - 1; y >= 0; y--) {
+                        if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] &
+                            (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) {
+                            x_off += (string_hmirror ? -1 : +1) * (fast_floorf((x + 2) * scale) + x_spacing);
+                            exit = true;
+                            break;
+                        }
+                    }
+
+                    if (exit) break;
+                }
+            } else {
+                for (int y = 0, yy = g->h; y < yy; y++) {
+                    for (int x = g->w - 1; x >= 0; x--) {
+                        if (g->data[(char_upsidedown ^ char_vflip) ? (g->h - 1 - y) : y] &
+                            (1 << ((char_upsidedown ^ char_hmirror ^ string_hmirror) ? x : (g->w - 1 - x)))) {
+                            x_off += (string_hmirror ? -1 : +1) * (fast_floorf(((g->h - 1 - y) + 2) * scale) + x_spacing);
+                            exit = true;
+                            break;
+                        }
+                    }
+
+                    if (exit) break;
+                }
+            }
+
+            if (!exit) x_off += (string_hmirror ? -1 : +1) * fast_floorf(scale * 3); // space char
+        }
+    }
+}

+ 198 - 0
project_0/extmods/k210/fmath.c

@@ -0,0 +1,198 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Fast approximate math functions.
+ */
+#include "fmath.h"
+#include "common.h"
+
+#define M_PI    3.14159265f
+#define M_PI_2  1.57079632f
+#define M_PI_4  0.78539816f
+
+const float __atanf_lut[4] = {
+    -0.0443265554792128f,    //p7
+    -0.3258083974640975f,    //p3
+    +0.1555786518463281f,    //p5
+    +0.9997878412794807f     //p1
+};
+
+#include <math.h>
+float OMV_ATTR_ALWAYS_INLINE fast_sqrtf(float x)
+{
+    return sqrtf(x);
+}
+
+int OMV_ATTR_ALWAYS_INLINE fast_floorf(float x)
+{
+    return floorf(x);
+}
+
+int OMV_ATTR_ALWAYS_INLINE fast_ceilf(float x)
+{
+    return ceilf(x);
+}
+
+int OMV_ATTR_ALWAYS_INLINE fast_roundf(float x)
+{
+    return roundf(x);
+}
+
+float OMV_ATTR_ALWAYS_INLINE fast_fabsf(float x)
+{
+    return fabsf(x);
+}
+
+
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+typedef union{
+    uint32_t l;
+    struct {
+        uint32_t m : 20;
+        uint32_t e : 11;
+        uint32_t s : 1;
+    };
+}exp_t;
+
+float fast_expf(float x)
+{
+    exp_t e;
+    e.l = (uint32_t)(1512775 * x + 1072632447);
+    // IEEE binary32 format
+    e.e = (e.e -1023 + 127) &0xFF; // rebase
+
+    uint32_t packed = (e.s << 31) | (e.e << 23) | e.m <<3;
+    return *((float*)&packed);
+}
+#pragma GCC diagnostic pop
+
+/*
+ * From Hackers Delight:
+ * This is a very approximate but very fast version of acbrt. It is just eight
+ * integer instructions (shift rights and adds), plus instructions to load the constant.
+ * 1/3 is approximated as 1/4 + 1/16 + 1/64 + 1/256 + ... + 1/65536.
+ * The constant 0x2a511cd0 balances the relative error at +-0.0321.
+ */
+float fast_cbrtf(float x)
+{
+   union {int ix; float x;} v;
+   v.x = x;                // x can be viewed as int.
+   v.ix = v.ix/4 + v.ix/16; // Approximate divide by 3.
+   v.ix = v.ix + v.ix/16;
+   v.ix = v.ix + v.ix/256;
+   v.ix = 0x2a511cd0 + v.ix;  // Initial guess.
+   return v.x;
+}
+
+inline float fast_atanf(float xx)
+{
+    float x, y, z;
+    int sign;
+
+    x = xx;
+
+    /* make argument positive and save the sign */
+    if( xx < 0.0f )
+    {
+        sign = -1;
+        x = -xx;
+    }
+    else
+    {
+        sign = 1;
+        x = xx;
+    }
+    /* range reduction */
+    if( x > 2.414213562373095f )  /* tan 3pi/8 */
+    {
+        y = M_PI_2;
+        x = -( 1.0f/x );
+    }
+
+    else if( x > 0.4142135623730950f ) /* tan pi/8 */
+    {
+        y = M_PI_4;
+        x = (x-1.0f)/(x+1.0f);
+    }
+    else
+        y = 0.0f;
+
+    z = x * x;
+    y +=
+        ((( 8.05374449538e-2f  * z
+          - 1.38776856032E-1f) * z
+          + 1.99777106478E-1f) * z
+          - 3.33329491539E-1f) * z * x + x;
+
+    if( sign < 0 )
+        y = -y;
+
+    return( y );
+}
+
+float fast_atan2f(float y, float x)
+{
+  if(x > 0 && y >= 0)
+    return fast_atanf(y/x);
+
+  if(x < 0 && y >= 0)
+    return M_PI - fast_atanf(-y/x);
+
+  if(x < 0 && y < 0)
+    return M_PI + fast_atanf(y/x);
+
+  if(x > 0 && y < 0)
+    return 2*M_PI - fast_atanf(-y/x);
+
+  return (y == 0) ? 0 : ((y > 0) ? M_PI : -M_PI);
+}
+
+float fast_log2(float x)
+{
+  union { float f; uint32_t i; } vx = { x };
+  union { uint32_t i; float f; } mx = { (vx.i & 0x007FFFFF) | 0x3f000000 };
+  float y = vx.i;
+  y *= 1.1920928955078125e-7f;
+
+  return y - 124.22551499f - 1.498030302f * mx.f
+           - 1.72587999f / (0.3520887068f + mx.f);
+}
+
+float fast_log(float x)
+{
+  return 0.69314718f * fast_log2 (x);
+}
+
+float fast_powf(float a, float b)
+{
+    union { float d; int x; } u = { a };
+    u.x = (int)((b * (u.x - 1064866805)) + 1064866805);
+    return u.d;
+}
+
+void fast_get_min_max(float *data, size_t data_len, float *p_min, float *p_max)
+{
+    float min = FLT_MAX, max = -FLT_MAX;
+
+    for (size_t i = 0; i < data_len; i++) {
+        float temp = data[i];
+
+        if (temp < min) {
+            min = temp;
+        }
+
+        if (temp > max) {
+            max = temp;
+        }
+    }
+
+    *p_min = min;
+    *p_max = max;
+}

+ 31 - 0
project_0/extmods/k210/fmath.h

@@ -0,0 +1,31 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Fast approximate math functions.
+ */
+#ifndef __FMATH_H__
+#define __FMATH_H__
+#include <stdlib.h>
+#include <stdint.h>
+#include <float.h>
+float fast_sqrtf(float x);
+int fast_floorf(float x);
+int fast_ceilf(float x);
+int fast_roundf(float x);
+float fast_atanf(float x);
+float fast_atan2f(float y, float x);
+float fast_expf(float x);
+float fast_cbrtf(float d);
+float fast_fabsf(float d);
+float fast_log(float x);
+float fast_log2(float x);
+float fast_powf(float a, float b);
+void fast_get_min_max(float *data, size_t data_len, float *p_min, float *p_max);
+// extern const float cos_table[360];
+// extern const float sin_table[360];
+#endif // __FMATH_H__

+ 1077 - 0
project_0/extmods/k210/font.c

@@ -0,0 +1,1077 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Font data.
+ *
+ * Size: 8 Style: Normal
+ * Included characters:
+ *  !"#$%&'()*+,-./0123456789:;<=>?\x0040ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+ * Antialiasing: yes
+ * Type: monospaced
+ * Encoding: ASMO-708
+ * Unicode bom: no
+ *
+ * Preset name: Monochrome
+ * Data block size: 8 bit(s), uint8_t
+ * RLE compression enabled: no
+ * Conversion type: Monochrome, Diffuse Dither 128
+ * Bits per pixel: 1
+ *
+ * Preprocess:
+ *  main scan direction: top_to_bottom
+ *  line scan direction: forward
+ *  inverse: yes
+ */
+#include "font.h"
+const glyph_t font[95] = {
+  // character: ' '
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '!'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x10,
+  0x00,
+  0x00}},
+  // character: '"'
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x18,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '#'
+  {8, 10, {0x00,
+  0x00,
+  0x24,
+  0x7c,
+  0x24,
+  0x48,
+  0x7c,
+  0x48,
+  0x00,
+  0x00}},
+  // character: '$'
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x1c,
+  0x20,
+  0x18,
+  0x04,
+  0x38,
+  0x08,
+  0x00}},
+  // character: '%'
+  {8, 10, {0x00,
+  0x00,
+  0x24,
+  0x58,
+  0x28,
+  0x14,
+  0x1a,
+  0x24,
+  0x00,
+  0x00}},
+  // character: '&'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x28,
+  0x30,
+  0x34,
+  0x2c,
+  0x1c,
+  0x00,
+  0x00}},
+  // character: '''
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x10,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '('
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x08,
+  0x00}},
+  // character: ')'
+  {8, 10, {0x00,
+  0x00,
+  0x20,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x20,
+  0x00}},
+  // character: '*'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x38,
+  0x28,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '+'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x10,
+  0x10,
+  0x7c,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: ','
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x10,
+  0x20,
+  0x00}},
+  // character: '-'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x18,
+  0x00,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '.'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x10,
+  0x00,
+  0x00}},
+  // character: '/'
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x08,
+  0x10,
+  0x10,
+  0x10,
+  0x20,
+  0x20,
+  0x00}},
+  // character: '0'
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x24,
+  0x24,
+  0x24,
+  0x24,
+  0x18,
+  0x00,
+  0x00}},
+  // character: '1'
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x18,
+  0x08,
+  0x08,
+  0x08,
+  0x08,
+  0x00,
+  0x00}},
+  // character: '2'
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x24,
+  0x04,
+  0x08,
+  0x10,
+  0x3c,
+  0x00,
+  0x00}},
+  // character: '3'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x04,
+  0x18,
+  0x04,
+  0x04,
+  0x38,
+  0x00,
+  0x00}},
+  // character: '4'
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x18,
+  0x28,
+  0x3c,
+  0x08,
+  0x08,
+  0x00,
+  0x00}},
+  // character: '5'
+  {8, 10, {0x00,
+  0x00,
+  0x1c,
+  0x10,
+  0x18,
+  0x04,
+  0x04,
+  0x18,
+  0x00,
+  0x00}},
+  // character: '6'
+  {8, 10, {0x00,
+  0x00,
+  0x0c,
+  0x10,
+  0x38,
+  0x24,
+  0x24,
+  0x18,
+  0x00,
+  0x00}},
+  // character: '7'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x08,
+  0x08,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: '8'
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x24,
+  0x18,
+  0x24,
+  0x24,
+  0x18,
+  0x00,
+  0x00}},
+  // character: '9'
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x24,
+  0x24,
+  0x3c,
+  0x08,
+  0x30,
+  0x00,
+  0x00}},
+  // character: ':'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x10,
+  0x00,
+  0x00,
+  0x10,
+  0x00,
+  0x00}},
+  // character: ';'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x10,
+  0x00,
+  0x00,
+  0x10,
+  0x20,
+  0x00}},
+  // character: '<'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x38,
+  0x40,
+  0x38,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '='
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x3c,
+  0x00,
+  0x3c,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '>'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x30,
+  0x08,
+  0x30,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '?'
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x08,
+  0x08,
+  0x10,
+  0x00,
+  0x10,
+  0x00,
+  0x00}},
+  // character: '\x0040'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x44,
+  0x9a,
+  0xaa,
+  0xaa,
+  0xb4,
+  0x40,
+  0x38}},
+  // character: 'A'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x28,
+  0x28,
+  0x28,
+  0x7c,
+  0x44,
+  0x00,
+  0x00}},
+  // character: 'B'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x24,
+  0x38,
+  0x24,
+  0x24,
+  0x38,
+  0x00,
+  0x00}},
+  // character: 'C'
+  {8, 10, {0x00,
+  0x00,
+  0x1c,
+  0x20,
+  0x20,
+  0x20,
+  0x20,
+  0x1c,
+  0x00,
+  0x00}},
+  // character: 'D'
+  {8, 10, {0x00,
+  0x00,
+  0x78,
+  0x44,
+  0x44,
+  0x44,
+  0x44,
+  0x78,
+  0x00,
+  0x00}},
+  // character: 'E'
+  {8, 10, {0x00,
+  0x00,
+  0x3c,
+  0x20,
+  0x38,
+  0x20,
+  0x20,
+  0x3c,
+  0x00,
+  0x00}},
+  // character: 'F'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x20,
+  0x30,
+  0x20,
+  0x20,
+  0x20,
+  0x00,
+  0x00}},
+  // character: 'G'
+  {8, 10, {0x00,
+  0x00,
+  0x1c,
+  0x20,
+  0x20,
+  0x24,
+  0x24,
+  0x1c,
+  0x00,
+  0x00}},
+  // character: 'H'
+  {8, 10, {0x00,
+  0x00,
+  0x44,
+  0x44,
+  0x7c,
+  0x44,
+  0x44,
+  0x44,
+  0x00,
+  0x00}},
+  // character: 'I'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 'J'
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x08,
+  0x08,
+  0x08,
+  0x08,
+  0x30,
+  0x00,
+  0x00}},
+  // character: 'K'
+  {8, 10, {0x00,
+  0x00,
+  0x24,
+  0x28,
+  0x30,
+  0x30,
+  0x28,
+  0x24,
+  0x00,
+  0x00}},
+  // character: 'L'
+  {8, 10, {0x00,
+  0x00,
+  0x20,
+  0x20,
+  0x20,
+  0x20,
+  0x20,
+  0x38,
+  0x00,
+  0x00}},
+  // character: 'M'
+  {8, 10, {0x00,
+  0x00,
+  0x44,
+  0x6c,
+  0x6c,
+  0x54,
+  0x54,
+  0x44,
+  0x00,
+  0x00}},
+  // character: 'N'
+  {8, 10, {0x00,
+  0x00,
+  0x42,
+  0x62,
+  0x52,
+  0x4a,
+  0x46,
+  0x42,
+  0x00,
+  0x00}},
+  // character: 'O'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x44,
+  0x44,
+  0x44,
+  0x44,
+  0x38,
+  0x00,
+  0x00}},
+  // character: 'P'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x24,
+  0x24,
+  0x38,
+  0x20,
+  0x20,
+  0x00,
+  0x00}},
+  // character: 'Q'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x44,
+  0x44,
+  0x44,
+  0x44,
+  0x38,
+  0x10,
+  0x08}},
+  // character: 'R'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x24,
+  0x24,
+  0x38,
+  0x28,
+  0x24,
+  0x00,
+  0x00}},
+  // character: 'S'
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x20,
+  0x20,
+  0x18,
+  0x08,
+  0x30,
+  0x00,
+  0x00}},
+  // character: 'T'
+  {8, 10, {0x00,
+  0x00,
+  0x38,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 'U'
+  {8, 10, {0x00,
+  0x00,
+  0x44,
+  0x44,
+  0x44,
+  0x44,
+  0x44,
+  0x38,
+  0x00,
+  0x00}},
+  // character: 'V'
+  {8, 10, {0x00,
+  0x00,
+  0x44,
+  0x44,
+  0x28,
+  0x28,
+  0x28,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 'W'
+  {8, 10, {0x00,
+  0x00,
+  0x82,
+  0x92,
+  0xaa,
+  0xaa,
+  0xaa,
+  0x44,
+  0x00,
+  0x00}},
+  // character: 'X'
+  {8, 10, {0x00,
+  0x00,
+  0x44,
+  0x28,
+  0x10,
+  0x10,
+  0x28,
+  0x44,
+  0x00,
+  0x00}},
+  // character: 'Y'
+  {8, 10, {0x00,
+  0x00,
+  0x44,
+  0x28,
+  0x28,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 'Z'
+  {8, 10, {0x00,
+  0x00,
+  0x3c,
+  0x04,
+  0x08,
+  0x10,
+  0x20,
+  0x3c,
+  0x00,
+  0x00}},
+  // character: '['
+  {8, 10, {0x00,
+  0x00,
+  0x18,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x18,
+  0x00}},
+  // character: '\'
+  {8, 10, {0x00,
+  0x00,
+  0x20,
+  0x20,
+  0x10,
+  0x10,
+  0x10,
+  0x08,
+  0x08,
+  0x00}},
+  // character: ']'
+  {8, 10, {0x00,
+  0x00,
+  0x30,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x30,
+  0x00}},
+  // character: '^'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x28,
+  0x28,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00}},
+  // character: '_'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x78,
+  0x00}},
+  // character: '`'
+  {8, 10, {0x00,
+  0x10,
+  0x08,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00}},
+  // character: 'a'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x30,
+  0x08,
+  0x18,
+  0x38,
+  0x00,
+  0x00}},
+  // character: 'b'
+  {8, 10, {0x00,
+  0x00,
+  0x20,
+  0x20,
+  0x38,
+  0x24,
+  0x24,
+  0x38,
+  0x00,
+  0x00}},
+  // character: 'c'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x18,
+  0x20,
+  0x20,
+  0x18,
+  0x00,
+  0x00}},
+  // character: 'd'
+  {8, 10, {0x00,
+  0x00,
+  0x04,
+  0x04,
+  0x1c,
+  0x24,
+  0x24,
+  0x1c,
+  0x00,
+  0x00}},
+  // character: 'e'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x38,
+  0x38,
+  0x20,
+  0x18,
+  0x00,
+  0x00}},
+  // character: 'f'
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x10,
+  0x18,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 'g'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x1c,
+  0x24,
+  0x1c,
+  0x04,
+  0x38,
+  0x00}},
+  // character: 'h'
+  {8, 10, {0x00,
+  0x00,
+  0x20,
+  0x20,
+  0x38,
+  0x24,
+  0x24,
+  0x24,
+  0x00,
+  0x00}},
+  // character: 'i'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x00,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 'j'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x00,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x20,
+  0x00}},
+  // character: 'k'
+  {8, 10, {0x00,
+  0x00,
+  0x20,
+  0x20,
+  0x28,
+  0x30,
+  0x30,
+  0x28,
+  0x00,
+  0x00}},
+  // character: 'l'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x08,
+  0x00,
+  0x00}},
+  // character: 'm'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0xec,
+  0x92,
+  0x92,
+  0x92,
+  0x00,
+  0x00}},
+  // character: 'n'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x38,
+  0x24,
+  0x24,
+  0x24,
+  0x00,
+  0x00}},
+  // character: 'o'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x18,
+  0x24,
+  0x24,
+  0x18,
+  0x00,
+  0x00}},
+  // character: 'p'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x38,
+  0x24,
+  0x24,
+  0x38,
+  0x20,
+  0x00}},
+  // character: 'q'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x1c,
+  0x24,
+  0x24,
+  0x1c,
+  0x04,
+  0x00}},
+  // character: 'r'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x18,
+  0x10,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 's'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x18,
+  0x20,
+  0x18,
+  0x30,
+  0x00,
+  0x00}},
+  // character: 't'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x10,
+  0x18,
+  0x10,
+  0x10,
+  0x08,
+  0x00,
+  0x00}},
+  // character: 'u'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x24,
+  0x24,
+  0x24,
+  0x1c,
+  0x00,
+  0x00}},
+  // character: 'v'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x28,
+  0x28,
+  0x10,
+  0x10,
+  0x00,
+  0x00}},
+  // character: 'w'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x54,
+  0x54,
+  0x54,
+  0x28,
+  0x00,
+  0x00}},
+  // character: 'x'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x28,
+  0x10,
+  0x10,
+  0x28,
+  0x00,
+  0x00}},
+  // character: 'y'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x28,
+  0x28,
+  0x10,
+  0x10,
+  0x20,
+  0x00}},
+  // character: 'z'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x18,
+  0x08,
+  0x10,
+  0x18,
+  0x00,
+  0x00}},
+  // character: '{'
+  {8, 10, {0x00,
+  0x00,
+  0x08,
+  0x10,
+  0x10,
+  0x20,
+  0x10,
+  0x10,
+  0x08,
+  0x00}},
+  // character: '|'
+  {8, 10, {0x00,
+  0x00,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x10,
+  0x00}},
+  // character: '}'
+  {8, 10, {0x00,
+  0x00,
+  0x20,
+  0x10,
+  0x10,
+  0x08,
+  0x10,
+  0x10,
+  0x20,
+  0x00}},
+  // character: '~'
+  {8, 10, {0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x00,
+  0x28,
+  0x50,
+  0x00,
+  0x00,
+  0x00}}
+};

+ 20 - 0
project_0/extmods/k210/font.h

@@ -0,0 +1,20 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Font data.
+ */
+#ifndef __FONT_H__
+#define __FONT_H__
+#include <stdint.h>
+typedef struct {
+    int w;
+    int h;
+    uint8_t data[10];
+} glyph_t;
+extern const glyph_t font[95];
+#endif // __FONT_H__

+ 187 - 0
project_0/extmods/k210/imlib.c

@@ -0,0 +1,187 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Image library.
+ */
+#include <stdlib.h>
+#include "font.h"
+#include <imlib.h>
+#include "common.h"
+/* origin openmv @file:imlib.c @file:38 */
+/////////////////
+// Point Stuff //
+/////////////////
+
+void point_init(point_t *ptr, int x, int y)
+{
+    ptr->x = x;
+    ptr->y = y;
+}
+
+void point_copy(point_t *dst, point_t *src)
+{
+    memcpy(dst, src, sizeof(point_t));
+}
+
+bool point_equal_fast(point_t *ptr0, point_t *ptr1)
+{
+    return !memcmp(ptr0, ptr1, sizeof(point_t));
+}
+
+int point_quadrance(point_t *ptr0, point_t *ptr1)
+{
+    int delta_x = ptr0->x - ptr1->x;
+    int delta_y = ptr0->y - ptr1->y;
+    return (delta_x * delta_x) + (delta_y * delta_y);
+}
+
+void point_rotate(int x, int y, float r, int center_x, int center_y, int16_t *new_x, int16_t *new_y)
+{
+    x -= center_x;
+    y -= center_y;
+    *new_x = (x * cosf(r)) - (y * sinf(r)) + center_x;
+    *new_y = (x * sinf(r)) + (y * cosf(r)) + center_y;
+}
+
+void point_min_area_rectangle(point_t *corners, point_t *new_corners, int corners_len) // Corners need to be sorted!
+{
+    int i_min = 0;
+    int i_min_area = INT_MAX;
+    int i_x0 = 0, i_y0 = 0;
+    int i_x1 = 0, i_y1 = 0;
+    int i_x2 = 0, i_y2 = 0;
+    int i_x3 = 0, i_y3 = 0;
+    float i_r = 0;
+
+    // This algorithm aligns the 4 edges produced by the 4 corners to the x axis and then computes the
+    // min area rect for each alignment. The smallest rect is choosen and then re-rotated and returned.
+    for (int i = 0; i < corners_len; i++) {
+        int16_t x0 = corners[i].x, y0 = corners[i].y;
+        int x_diff = corners[(i+1)%corners_len].x - corners[i].x;
+        int y_diff = corners[(i+1)%corners_len].y - corners[i].y;
+        float r = -fast_atan2f(y_diff, x_diff);
+
+        int16_t x1[corners_len-1];
+        int16_t y1[corners_len-1];
+        for (int j = 0, jj = corners_len - 1; j < jj; j++) {
+            point_rotate(corners[(i+j+1)%corners_len].x, corners[(i+j+1)%corners_len].y, r, x0, y0, x1 + j, y1 + j);
+        }
+
+        int minx = x0;
+        int maxx = x0;
+        int miny = y0;
+        int maxy = y0;
+        for (int j = 0, jj = corners_len - 1; j < jj; j++) {
+            minx = IM_MIN(minx, x1[j]);
+            maxx = IM_MAX(maxx, x1[j]);
+            miny = IM_MIN(miny, y1[j]);
+            maxy = IM_MAX(maxy, y1[j]);
+        }
+
+        int area = (maxx - minx + 1) * (maxy - miny + 1);
+        if (area < i_min_area) {
+            i_min = i;
+            i_min_area = area;
+            i_x0 = minx, i_y0 = miny;
+            i_x1 = maxx, i_y1 = miny;
+            i_x2 = maxx, i_y2 = maxy;
+            i_x3 = minx, i_y3 = maxy;
+            i_r = r;
+        }
+    }
+
+    point_rotate(i_x0, i_y0, -i_r, corners[i_min].x, corners[i_min].y, &new_corners[0].x, &new_corners[0].y);
+    point_rotate(i_x1, i_y1, -i_r, corners[i_min].x, corners[i_min].y, &new_corners[1].x, &new_corners[1].y);
+    point_rotate(i_x2, i_y2, -i_r, corners[i_min].x, corners[i_min].y, &new_corners[2].x, &new_corners[2].y);
+    point_rotate(i_x3, i_y3, -i_r, corners[i_min].x, corners[i_min].y, &new_corners[3].x, &new_corners[3].y);
+}
+
+/* origin openmv @file:imlib.c @line:239 */
+/////////////////
+// Image Stuff //
+/////////////////
+void image_init(image_t *ptr, int w, int h, pixformat_t pixfmt, uint32_t size, void *pixels)
+{
+    ptr->w = w;
+    ptr->h = h;
+    ptr->pixfmt = pixfmt;
+    ptr->size   = size;
+    ptr->pixels = pixels;
+}
+
+void image_copy(image_t *dst, image_t *src)
+{
+    memcpy(dst, src, sizeof(image_t));
+}
+
+size_t image_size(image_t *ptr)
+{
+    switch (ptr->pixfmt) {
+        case PIXFORMAT_BINARY: {
+            return IMAGE_BINARY_LINE_LEN_BYTES(ptr) * ptr->h;
+        }
+        case PIXFORMAT_GRAYSCALE:
+        case PIXFORMAT_BAYER_ANY: { // re-use
+            return IMAGE_GRAYSCALE_LINE_LEN_BYTES(ptr) * ptr->h;
+        }
+        case PIXFORMAT_RGB565:
+        case PIXFORMAT_YUV_ANY: { // re-use
+            return IMAGE_RGB565_LINE_LEN_BYTES(ptr) * ptr->h;
+        }
+        case PIXFORMAT_JPEG: {
+            return ptr->size;
+        }
+        case PIXFORMAT_RGB888_CHW:
+        case PIXFORMAT_RGB888_HWC:
+        {
+            return IMAGE_RGB888_LINE_LEN_BYTES(ptr) * ptr->h;
+        }
+        default: {
+            return 0;
+        }
+    }
+}
+/* end openmv @file:imlib.c @line:278 */
+/* start openmv @file:imlib.c @line:448 */
+// https://en.wikipedia.org/wiki/Lab_color_space -> CIELAB-CIEXYZ conversions
+// https://en.wikipedia.org/wiki/SRGB -> Specification of the transformation
+uint16_t imlib_lab_to_rgb(uint8_t l, int8_t a, int8_t b)
+{
+    float x = ((l + 16) * 0.008621f) + (a * 0.002f);
+    float y = ((l + 16) * 0.008621f);
+    float z = ((l + 16) * 0.008621f) - (b * 0.005f);
+
+    x = ((x > 0.206897f) ? (x*x*x) : ((0.128419f * x) - 0.017713f)) * 095.047f;
+    y = ((y > 0.206897f) ? (y*y*y) : ((0.128419f * y) - 0.017713f)) * 100.000f;
+    z = ((z > 0.206897f) ? (z*z*z) : ((0.128419f * z) - 0.017713f)) * 108.883f;
+
+    float r_lin = ((x * +3.2406f) + (y * -1.5372f) + (z * -0.4986f)) / 100.0f;
+    float g_lin = ((x * -0.9689f) + (y * +1.8758f) + (z * +0.0415f)) / 100.0f;
+    float b_lin = ((x * +0.0557f) + (y * -0.2040f) + (z * +1.0570f)) / 100.0f;
+
+    r_lin = (r_lin>0.0031308f) ? ((1.055f*powf(r_lin, 0.416666f))-0.055f) : (r_lin*12.92f);
+    g_lin = (g_lin>0.0031308f) ? ((1.055f*powf(g_lin, 0.416666f))-0.055f) : (g_lin*12.92f);
+    b_lin = (b_lin>0.0031308f) ? ((1.055f*powf(b_lin, 0.416666f))-0.055f) : (b_lin*12.92f);
+
+    uint32_t red   = IM_MAX(IM_MIN(fast_floorf(r_lin * COLOR_R8_MAX), COLOR_R8_MAX), COLOR_R8_MIN);
+    uint32_t green = IM_MAX(IM_MIN(fast_floorf(g_lin * COLOR_G8_MAX), COLOR_G8_MAX), COLOR_G8_MIN);
+    uint32_t blue  = IM_MAX(IM_MIN(fast_floorf(b_lin * COLOR_B8_MAX), COLOR_B8_MAX), COLOR_B8_MIN);
+
+    return COLOR_R8_G8_B8_TO_RGB565(red, green, blue);
+}
+
+// https://en.wikipedia.org/wiki/YCbCr -> JPEG Conversion
+uint16_t imlib_yuv_to_rgb(uint8_t y, int8_t u, int8_t v)
+{
+    uint32_t r = IM_MAX(IM_MIN(y + ((91881 * v) >> 16), COLOR_R8_MAX), COLOR_R8_MIN);
+    uint32_t g = IM_MAX(IM_MIN(y - (((22554 * u) + (46802 * v)) >> 16), COLOR_G8_MAX), COLOR_G8_MIN);
+    uint32_t b = IM_MAX(IM_MIN(y + ((116130 * u) >> 16), COLOR_B8_MAX), COLOR_B8_MIN);
+
+    return COLOR_R8_G8_B8_TO_RGB565(r, g, b);
+}
+/* end openmv @file:imlib.c @line:484*/

+ 698 - 0
project_0/extmods/k210/imlib.h

@@ -0,0 +1,698 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2019 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2019 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Image processing library.
+ */
+#ifndef __IMLIB_H__
+#define __IMLIB_H__
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <math.h>
+#include "fmath.h"
+
+#include "__cmsis_gcc.h"
+#include <imlib_config.h>
+#include <imlib_exts.h>
+
+/* start openmv @file:imglib.h @line:32 */
+#ifndef M_PI
+#define M_PI    3.14159265f
+#define M_PI_2  1.57079632f
+#define M_PI_4  0.78539816f
+#endif
+
+#define IM_LOG2_2(x)    (((x) &                0x2ULL) ? ( 2                        ) :             1) // NO ({ ... }) !
+#define IM_LOG2_4(x)    (((x) &                0xCULL) ? ( 2 +  IM_LOG2_2((x) >>  2)) :  IM_LOG2_2(x)) // NO ({ ... }) !
+#define IM_LOG2_8(x)    (((x) &               0xF0ULL) ? ( 4 +  IM_LOG2_4((x) >>  4)) :  IM_LOG2_4(x)) // NO ({ ... }) !
+#define IM_LOG2_16(x)   (((x) &             0xFF00ULL) ? ( 8 +  IM_LOG2_8((x) >>  8)) :  IM_LOG2_8(x)) // NO ({ ... }) !
+#define IM_LOG2_32(x)   (((x) &         0xFFFF0000ULL) ? (16 + IM_LOG2_16((x) >> 16)) : IM_LOG2_16(x)) // NO ({ ... }) !
+#define IM_LOG2(x)      (((x) & 0xFFFFFFFF00000000ULL) ? (32 + IM_LOG2_32((x) >> 32)) : IM_LOG2_32(x)) // NO ({ ... }) !
+
+#define IM_MAX(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; })
+#define IM_MIN(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
+#define IM_DIV(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a / _b) : 0; })
+#define IM_MOD(a,b)     ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a % _b) : 0; })
+
+#define INT8_T_BITS     (sizeof(int8_t) * 8)
+#define INT8_T_MASK     (INT8_T_BITS - 1)
+#define INT8_T_SHIFT    IM_LOG2(INT8_T_MASK)
+
+#define INT16_T_BITS    (sizeof(int16_t) * 8)
+#define INT16_T_MASK    (INT16_T_BITS - 1)
+#define INT16_T_SHIFT   IM_LOG2(INT16_T_MASK)
+
+#define INT32_T_BITS    (sizeof(int32_t) * 8)
+#define INT32_T_MASK    (INT32_T_BITS - 1)
+#define INT32_T_SHIFT   IM_LOG2(INT32_T_MASK)
+
+#define INT64_T_BITS    (sizeof(int64_t) * 8)
+#define INT64_T_MASK    (INT64_T_BITS - 1)
+#define INT64_T_SHIFT   IM_LOG2(INT64_T_MASK)
+
+#define UINT8_T_BITS    (sizeof(uint8_t) * 8)
+#define UINT8_T_MASK    (UINT8_T_BITS - 1)
+#define UINT8_T_SHIFT   IM_LOG2(UINT8_T_MASK)
+
+#define UINT16_T_BITS   (sizeof(uint16_t) * 8)
+#define UINT16_T_MASK   (UINT16_T_BITS - 1)
+#define UINT16_T_SHIFT  IM_LOG2(UINT16_T_MASK)
+
+#define UINT32_T_BITS   (sizeof(uint32_t) * 8)
+#define UINT32_T_MASK   (UINT32_T_BITS - 1)
+#define UINT32_T_SHIFT  IM_LOG2(UINT32_T_MASK)
+
+#define UINT64_T_BITS   (sizeof(uint64_t) * 8)
+#define UINT64_T_MASK   (UINT64_T_BITS - 1)
+#define UINT64_T_SHIFT  IM_LOG2(UINT64_T_MASK)
+
+#define IM_DEG2RAD(x)   (((x)*M_PI)/180)
+#define IM_RAD2DEG(x)   (((x)*180)/M_PI)
+/* end openmv @file:imglib.h @line:83*/
+/////////////////
+// Point Stuff //
+/////////////////
+
+typedef struct point {
+    int16_t x;
+    int16_t y;
+} point_t;
+
+void point_init(point_t *ptr, int x, int y);
+void point_copy(point_t *dst, point_t *src);
+bool point_equal_fast(point_t *ptr0, point_t *ptr1);
+int point_quadrance(point_t *ptr0, point_t *ptr1);
+void point_rotate(int x, int y, float r, int center_x, int center_y, int16_t *new_x, int16_t *new_y);
+// void point_min_area_rectangle(point_t *corners, point_t *new_corners, int corners_len);
+
+/* start openmv @file:imlib.h @line:199 */
+#define COLOR_BINARY_MIN 0
+#define COLOR_BINARY_MAX 1
+#define COLOR_GRAYSCALE_BINARY_MIN 0x00
+#define COLOR_GRAYSCALE_BINARY_MAX 0xFF
+#define COLOR_RGB565_BINARY_MIN 0x0000
+#define COLOR_RGB565_BINARY_MAX 0xFFFF
+
+#define COLOR_GRAYSCALE_MIN 0
+#define COLOR_GRAYSCALE_MAX 255
+
+#define COLOR_R5_MIN 0
+#define COLOR_R5_MAX 31
+#define COLOR_G6_MIN 0
+#define COLOR_G6_MAX 63
+#define COLOR_B5_MIN 0
+#define COLOR_B5_MAX 31
+
+#define COLOR_R8_MIN 0
+#define COLOR_R8_MAX 255
+#define COLOR_G8_MIN 0
+#define COLOR_G8_MAX 255
+#define COLOR_B8_MIN 0
+#define COLOR_B8_MAX 255
+
+#define COLOR_L_MIN 0
+#define COLOR_L_MAX 100
+#define COLOR_A_MIN -128
+#define COLOR_A_MAX 127
+#define COLOR_B_MIN -128
+#define COLOR_B_MAX 127
+
+#define COLOR_Y_MIN 0
+#define COLOR_Y_MAX 255
+#define COLOR_U_MIN -128
+#define COLOR_U_MAX 127
+#define COLOR_V_MIN -128
+#define COLOR_V_MAX 127
+
+// RGB565 Stuff //
+
+#define COLOR_RGB565_TO_R5(pixel) (((pixel) >> 11) & 0x1F)
+#define COLOR_RGB565_TO_R8(pixel) \
+({ \
+    __typeof__ (pixel) __pixel = (pixel); \
+    __pixel = (__pixel >> 8) & 0xF8; \
+    __pixel | (__pixel >> 5); \
+})
+
+#define COLOR_RGB565_TO_G6(pixel) (((pixel) >> 5) & 0x3F)
+#define COLOR_RGB565_TO_G8(pixel) \
+({ \
+    __typeof__ (pixel) __pixel = (pixel); \
+    __pixel = (__pixel >> 3) & 0xFC; \
+    __pixel | (__pixel >> 6); \
+})
+
+#define COLOR_RGB565_TO_B5(pixel) ((pixel) & 0x1F)
+#define COLOR_RGB565_TO_B8(pixel) \
+({ \
+    __typeof__ (pixel) __pixel = (pixel); \
+    __pixel = (__pixel << 3) & 0xF8; \
+    __pixel | (__pixel >> 5); \
+})
+
+#define COLOR_R5_G6_B5_TO_RGB565(r5, g6, b5) (((r5) << 11) | ((g6) << 5) | (b5))
+#define COLOR_R8_G8_B8_TO_RGB565(r8, g8, b8) ((((r8) & 0xF8) << 8) | (((g8) & 0xFC) << 3) | ((b8) >> 3))
+
+#define COLOR_RGB888_TO_Y(r8, g8, b8) ((((r8) * 38) + ((g8) * 75) + ((b8) * 15)) >> 7) // 0.299R + 0.587G + 0.114B
+#define COLOR_RGB565_TO_Y(rgb565) \
+({ \
+    __typeof__ (rgb565) __rgb565 = (rgb565); \
+    int r = COLOR_RGB565_TO_R8(__rgb565); \
+    int g = COLOR_RGB565_TO_G8(__rgb565); \
+    int b = COLOR_RGB565_TO_B8(__rgb565); \
+    COLOR_RGB888_TO_Y(r, g, b); \
+})
+
+#define COLOR_Y_TO_RGB888(pixel) ((pixel) * 0x010101)
+#define COLOR_Y_TO_RGB565(pixel) \
+({ \
+    __typeof__ (pixel) __pixel = (pixel); \
+    int __rb_pixel = (__pixel >> 3) & 0x1F; \
+    (__rb_pixel * 0x0801) + ((__pixel << 3) & 0x7E0); \
+})
+
+#define COLOR_RGB888_TO_U(r8, g8, b8) ((((r8) * -21) - ((g8) * 43) + ((b8) * 64)) >> 7) // -0.168736R - 0.331264G + 0.5B
+#define COLOR_RGB565_TO_U(rgb565) \
+({ \
+    __typeof__ (rgb565) __rgb565 = (rgb565); \
+    int r = COLOR_RGB565_TO_R8(__rgb565); \
+    int g = COLOR_RGB565_TO_G8(__rgb565); \
+    int b = COLOR_RGB565_TO_B8(__rgb565); \
+    COLOR_RGB888_TO_U(r, g, b); \
+})
+
+#define COLOR_RGB888_TO_V(r8, g8, b8) ((((r8) * 64) - ((g8) * 54) - ((b8) * 10)) >> 7) // 0.5R - 0.418688G - 0.081312B
+#define COLOR_RGB565_TO_V(rgb565) \
+({ \
+    __typeof__ (rgb565) __rgb565 = (rgb565); \
+    int r = COLOR_RGB565_TO_R8(__rgb565); \
+    int g = COLOR_RGB565_TO_G8(__rgb565); \
+    int b = COLOR_RGB565_TO_B8(__rgb565); \
+    COLOR_RGB888_TO_V(r, g, b); \
+})
+
+extern const int8_t lab_table[196608/2];
+
+#ifdef IMLIB_ENABLE_LAB_LUT
+#define COLOR_RGB565_TO_L(pixel) lab_table[((pixel>>1) * 3) + 0]
+#define COLOR_RGB565_TO_A(pixel) lab_table[((pixel>>1) * 3) + 1]
+#define COLOR_RGB565_TO_B(pixel) lab_table[((pixel>>1) * 3) + 2]
+#else
+#define COLOR_RGB565_TO_L(pixel) imlib_rgb565_to_l(pixel)
+#define COLOR_RGB565_TO_A(pixel) imlib_rgb565_to_a(pixel)
+#define COLOR_RGB565_TO_B(pixel) imlib_rgb565_to_b(pixel)
+#endif
+
+#define COLOR_LAB_TO_RGB565(l, a, b) imlib_lab_to_rgb(l, a, b)
+#define COLOR_YUV_TO_RGB565(y, u, v) imlib_yuv_to_rgb((y) + 128, u, v)
+
+#define COLOR_BINARY_TO_GRAYSCALE(pixel) ((pixel) * COLOR_GRAYSCALE_MAX)
+#define COLOR_BINARY_TO_RGB565(pixel) COLOR_YUV_TO_RGB565(((pixel) ? 127 : -128), 0, 0)
+#define COLOR_RGB565_TO_BINARY(pixel) (COLOR_RGB565_TO_Y(pixel) > (((COLOR_Y_MAX - COLOR_Y_MIN) / 2) + COLOR_Y_MIN))
+#define COLOR_RGB565_TO_GRAYSCALE(pixel) COLOR_RGB565_TO_Y(pixel)
+#define COLOR_GRAYSCALE_TO_BINARY(pixel) ((pixel) > (((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN) / 2) + COLOR_GRAYSCALE_MIN))
+#define COLOR_GRAYSCALE_TO_RGB565(pixel) COLOR_YUV_TO_RGB565(((pixel) - 128), 0, 0)
+/* end openmv @file:imlib.h @line:324*/
+/* start openmv @file:imlib.h @line:335 */
+/////////////////
+// Image Stuff //
+/////////////////
+
+// Pixel format IDs.
+typedef enum {
+    PIXFORMAT_ID_BINARY     = 1,
+    PIXFORMAT_ID_GRAY       = 2,
+    PIXFORMAT_ID_RGB565     = 3,
+    PIXFORMAT_ID_BAYER      = 4,
+    PIXFORMAT_ID_YUV422     = 5,
+    PIXFORMAT_ID_JPEG       = 6,
+    /* Note: Update PIXFORMAT_IS_VALID when adding new formats */
+    PIXFORMAT_ID_RGB888     = 9,    // for rtak
+} pixformat_id_t;
+
+// Pixel sub-format IDs.
+typedef enum {
+    SUBFORMAT_ID_GRAY8      = 0,
+    SUBFORMAT_ID_GRAY16     = 1,
+    SUBFORMAT_ID_BGGR       = 0, // !!! Note: Make sure bayer sub-formats don't  !!!
+    SUBFORMAT_ID_GBRG       = 1, // !!! overflow the sensor.hw_flags.bayer field !!!
+    SUBFORMAT_ID_GRBG       = 2,
+    SUBFORMAT_ID_RGGB       = 3,
+    SUBFORMAT_ID_YUV422     = 0,
+    SUBFORMAT_ID_YVU422     = 1,
+    /* Note: Update PIXFORMAT_IS_VALID when adding new formats */
+    SUBFORMAT_ID_HWC        = 0,    // for rtak
+    SUBFORMAT_ID_CHW        = 1,    // for rtak
+} subformat_id_t;
+
+// Pixel format Byte Per Pixel.
+typedef enum {
+    PIXFORMAT_BPP_BINARY    = 0,
+    PIXFORMAT_BPP_GRAY8     = 1,
+    PIXFORMAT_BPP_GRAY16    = 2,
+    PIXFORMAT_BPP_RGB565    = 2,
+    PIXFORMAT_BPP_BAYER     = 1,
+    PIXFORMAT_BPP_YUV422    = 2,
+    /* Note: Update PIXFORMAT_IS_VALID when adding new formats */
+    PIXFORMAT_BPP_RGB888    = 3,    // for rtak
+} pixformat_bpp_t;
+
+// Pixel format flags.
+#define PIXFORMAT_FLAGS_Y       (1 << 28) // YUV format.
+#define PIXFORMAT_FLAGS_M       (1 << 27) // Mutable format.
+#define PIXFORMAT_FLAGS_C       (1 << 26) // Colored format.
+#define PIXFORMAT_FLAGS_J       (1 << 25) // Compressed format (JPEG/PNG).
+#define PIXFORMAT_FLAGS_R       (1 << 24) // RAW/Bayer format.
+#define PIXFORMAT_FLAGS_CY      (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_Y)
+#define PIXFORMAT_FLAGS_CM      (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_M)
+#define PIXFORMAT_FLAGS_CR      (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_R)
+#define PIXFORMAT_FLAGS_CJ      (PIXFORMAT_FLAGS_C | PIXFORMAT_FLAGS_J)
+#define IMLIB_IMAGE_MAX_SIZE(x) ((x) & 0xFFFFFFFF)
+
+// Each pixel format encodes flags, pixel format id and bpp as follows:
+// 31......29  28  27  26  25  24  23..........16  15...........8  7.............0
+// <RESERVED>  YF  MF  CF  JF  RF  <PIXFORMAT_ID>  <SUBFORMAT_ID>  <BYTES_PER_PIX>
+// NOTE: Bit 31-30 must Not be used for pixformat_t to be used as mp_int_t.
+typedef enum {
+    PIXFORMAT_INVALID    = (0),
+    PIXFORMAT_BINARY     = (PIXFORMAT_FLAGS_M  | (PIXFORMAT_ID_BINARY << 16) | (0                   << 8) | PIXFORMAT_BPP_BINARY ),
+    PIXFORMAT_GRAYSCALE  = (PIXFORMAT_FLAGS_M  | (PIXFORMAT_ID_GRAY   << 16) | (SUBFORMAT_ID_GRAY8  << 8) | PIXFORMAT_BPP_GRAY8  ),
+    PIXFORMAT_RGB565     = (PIXFORMAT_FLAGS_CM | (PIXFORMAT_ID_RGB565 << 16) | (0                   << 8) | PIXFORMAT_BPP_RGB565 ),
+    PIXFORMAT_BAYER      = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER  << 16) | (SUBFORMAT_ID_BGGR   << 8) | PIXFORMAT_BPP_BAYER  ),
+    PIXFORMAT_BAYER_BGGR = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER  << 16) | (SUBFORMAT_ID_BGGR   << 8) | PIXFORMAT_BPP_BAYER  ),
+    PIXFORMAT_BAYER_GBRG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER  << 16) | (SUBFORMAT_ID_GBRG   << 8) | PIXFORMAT_BPP_BAYER  ),
+    PIXFORMAT_BAYER_GRBG = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER  << 16) | (SUBFORMAT_ID_GRBG   << 8) | PIXFORMAT_BPP_BAYER  ),
+    PIXFORMAT_BAYER_RGGB = (PIXFORMAT_FLAGS_CR | (PIXFORMAT_ID_BAYER  << 16) | (SUBFORMAT_ID_RGGB   << 8) | PIXFORMAT_BPP_BAYER  ),
+    PIXFORMAT_YUV422     = (PIXFORMAT_FLAGS_CY | (PIXFORMAT_ID_YUV422 << 16) | (SUBFORMAT_ID_YUV422 << 8) | PIXFORMAT_BPP_YUV422 ),
+    PIXFORMAT_YVU422     = (PIXFORMAT_FLAGS_CY | (PIXFORMAT_ID_YUV422 << 16) | (SUBFORMAT_ID_YVU422 << 8) | PIXFORMAT_BPP_YUV422 ),
+    PIXFORMAT_JPEG       = (PIXFORMAT_FLAGS_CJ | (PIXFORMAT_ID_JPEG   << 16) | (0                   << 8) | 0                    ),
+    // for rtak
+    PIXFORMAT_RGB888_HWC = (PIXFORMAT_FLAGS_M  | (PIXFORMAT_ID_RGB888 << 16) | (SUBFORMAT_ID_HWC    << 8) | PIXFORMAT_BPP_RGB888 ),
+    PIXFORMAT_RGB888_CHW = (PIXFORMAT_FLAGS_M  | (PIXFORMAT_ID_RGB888 << 16) | (SUBFORMAT_ID_CHW    << 8) | PIXFORMAT_BPP_RGB888 ),
+    PIXFORMAT_LAST       = 0xFFFFFFFFU,
+} pixformat_t;
+
+#define PIXFORMAT_MUTABLE_ANY           \
+        PIXFORMAT_BINARY:               \
+        case PIXFORMAT_GRAYSCALE:       \
+        case PIXFORMAT_RGB565           \
+
+#define PIXFORMAT_BAYER_ANY             \
+        PIXFORMAT_BAYER_BGGR:           \
+        case PIXFORMAT_BAYER_GBRG:      \
+        case PIXFORMAT_BAYER_GRBG:      \
+        case PIXFORMAT_BAYER_RGGB       \
+
+#define PIXFORMAT_YUV_ANY               \
+        PIXFORMAT_YUV422:               \
+        case PIXFORMAT_YVU422           \
+
+#define IMLIB_PIXFORMAT_IS_VALID(x)     \
+    ((x == PIXFORMAT_BINARY)            \
+     || (x == PIXFORMAT_GRAYSCALE)      \
+     || (x == PIXFORMAT_RGB565)         \
+     || (x == PIXFORMAT_BAYER_BGGR)     \
+     || (x == PIXFORMAT_BAYER_GBRG)     \
+     || (x == PIXFORMAT_BAYER_GRBG)     \
+     || (x == PIXFORMAT_BAYER_RGGB)     \
+     || (x == PIXFORMAT_YUV422)         \
+     || (x == PIXFORMAT_YVU422)         \
+     || (x == PIXFORMAT_JPEG))          \
+
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#define PIXFORMAT_STRUCT            \
+struct {                            \
+  union {                           \
+    struct {                        \
+        uint32_t bpp            :8; \
+        uint32_t subfmt_id      :8; \
+        uint32_t pixfmt_id      :8; \
+        uint32_t is_bayer       :1; \
+        uint32_t is_compressed  :1; \
+        uint32_t is_color       :1; \
+        uint32_t is_mutable     :1; \
+        uint32_t is_yuv         :1; \
+        uint32_t /*reserved*/   :3; \
+    };                              \
+    uint32_t pixfmt;                \
+  };                                \
+  uint32_t size; /* for compressed images */ \
+}
+#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define PIXFORMAT_STRUCT            \
+struct {                            \
+  union {                           \
+    struct {                        \
+        uint32_t /*reserved*/   :3; \
+        uint32_t is_yuv         :1; \
+        uint32_t is_mutable     :1; \
+        uint32_t is_color       :1; \
+        uint32_t is_compressed  :1; \
+        uint32_t is_bayer       :1; \
+        uint32_t pixfmt_id      :8; \
+        uint32_t subfmt_id      :8; \
+        uint32_t bpp            :8; \
+    };                              \
+    uint32_t pixfmt;                \
+  };                                \
+  uint32_t size; /* for compressed images */ \
+}
+#else
+#error "Byte order is not defined."
+#endif
+
+typedef struct image {
+    uint32_t w;
+    uint32_t h;
+    PIXFORMAT_STRUCT;
+    union {
+        uint8_t *pixels;
+        uint8_t *data;
+    };
+} image_t;
+
+void image_init(image_t *ptr, int w, int h, pixformat_t pixfmt, uint32_t size, void *pixels);
+void image_copy(image_t *dst, image_t *src);
+size_t image_size(image_t *ptr);
+// bool image_get_mask_pixel(image_t *ptr, int x, int y);
+
+#define IMAGE_BINARY_LINE_LEN(image) (((image)->w + UINT32_T_MASK) >> UINT32_T_SHIFT)
+#define IMAGE_BINARY_LINE_LEN_BYTES(image) (IMAGE_BINARY_LINE_LEN(image) * sizeof(uint32_t))
+
+#define IMAGE_GRAYSCALE_LINE_LEN(image) ((image)->w)
+#define IMAGE_GRAYSCALE_LINE_LEN_BYTES(image) (IMAGE_GRAYSCALE_LINE_LEN(image) * sizeof(uint8_t))
+
+#define IMAGE_RGB565_LINE_LEN(image) ((image)->w)
+#define IMAGE_RGB565_LINE_LEN_BYTES(image) (IMAGE_RGB565_LINE_LEN(image) * sizeof(uint16_t))
+
+#define IMAGE_GET_BINARY_PIXEL(image, x, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    (((uint32_t *) _image->data)[(((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT)] >> (_x & UINT32_T_MASK)) & 1; \
+})
+
+#define IMAGE_PUT_BINARY_PIXEL(image, x, y, v) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (v) _v = (v); \
+    size_t _i = (((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT); \
+    size_t _j = _x & UINT32_T_MASK; \
+    ((uint32_t *) _image->data)[_i] = (((uint32_t *) _image->data)[_i] & (~(1 << _j))) | ((_v & 1) << _j); \
+})
+
+#define IMAGE_CLEAR_BINARY_PIXEL(image, x, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    ((uint32_t *) _image->data)[(((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT)] &= ~(1 << (_x & UINT32_T_MASK)); \
+})
+
+#define IMAGE_SET_BINARY_PIXEL(image, x, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    ((uint32_t *) _image->data)[(((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y) + (_x >> UINT32_T_SHIFT)] |= 1 << (_x & UINT32_T_MASK); \
+})
+
+#define IMAGE_GET_GRAYSCALE_PIXEL(image, x, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    ((uint8_t *) _image->data)[(_image->w * _y) + _x]; \
+})
+
+#define IMAGE_PUT_GRAYSCALE_PIXEL(image, x, y, v) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (v) _v = (v); \
+    ((uint8_t *) _image->data)[(_image->w * _y) + _x] = _v; \
+})
+
+#define IMAGE_GET_RGB565_PIXEL(image, x, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    ((uint16_t *) _image->data)[(_image->w * _y) + _x]; \
+})
+
+#define IMAGE_PUT_RGB565_PIXEL(image, x, y, v) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (v) _v = (v); \
+    ((uint16_t *) _image->data)[(_image->w * _y) + _x] = _v; \
+})
+
+#define IMAGE_GET_YUV_PIXEL(image, x, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    ((uint16_t *) _image->data)[(_image->w * _y) + _x]; \
+})
+
+#define IMAGE_PUT_YUV_PIXEL(image, x, y, v) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (v) _v = (v); \
+    ((uint16_t *) _image->data)[(_image->w * _y) + _x] = _v; \
+})
+
+#define IMAGE_GET_BAYER_PIXEL(image, x, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    ((uint8_t *) _image->data)[(_image->w * _y) + _x]; \
+})
+
+#define IMAGE_PUT_BAYER_PIXEL(image, x, y, v) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (v) _v = (v); \
+    ((uint8_t *) _image->data)[(_image->w * _y) + _x] = _v; \
+})
+
+// Fast Stuff //
+
+#define IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(image, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (y) _y = (y); \
+    ((uint32_t *) _image->data) + (((_image->w + UINT32_T_MASK) >> UINT32_T_SHIFT) * _y); \
+})
+
+#define IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    (_row_ptr[_x >> UINT32_T_SHIFT] >> (_x & UINT32_T_MASK)) & 1; \
+})
+
+#define IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr, x, v) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (v) _v = (v); \
+    size_t _i = _x >> UINT32_T_SHIFT; \
+    size_t _j = _x & UINT32_T_MASK; \
+    _row_ptr[_i] = (_row_ptr[_i] & (~(1 << _j))) | ((_v & 1) << _j); \
+})
+
+#define IMAGE_CLEAR_BINARY_PIXEL_FAST(row_ptr, x) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    _row_ptr[_x >> UINT32_T_SHIFT] &= ~(1 << (_x & UINT32_T_MASK)); \
+})
+
+#define IMAGE_SET_BINARY_PIXEL_FAST(row_ptr, x) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    _row_ptr[_x >> UINT32_T_SHIFT] |= 1 << (_x & UINT32_T_MASK); \
+})
+
+#define IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(image, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (y) _y = (y); \
+    ((uint8_t *) _image->data) + (_image->w * _y); \
+})
+
+#define IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    _row_ptr[_x]; \
+})
+
+#define IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr, x, v) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (v) _v = (v); \
+    _row_ptr[_x] = _v; \
+})
+
+#define IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(image, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (y) _y = (y); \
+    ((uint16_t *) _image->data) + (_image->w * _y); \
+})
+
+#define IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    _row_ptr[_x]; \
+})
+
+#define IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, v) \
+({ \
+    __typeof__ (row_ptr) _row_ptr = (row_ptr); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (v) _v = (v); \
+    _row_ptr[_x] = _v; \
+})
+
+#define IMAGE_COMPUTE_BAYER_PIXEL_ROW_PTR(image, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (y) _y = (y); \
+    ((uint8_t *) _image->data) + (_image->w * _y); \
+})
+
+#define IMAGE_COMPUTE_YUV_PIXEL_ROW_PTR(image, y) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (y) _y = (y); \
+    ((uint16_t *) _image->data) + (_image->w * _y); \
+})
+/* end openmv @file:imlib.h @line:698 */
+/* start openmv @file:imlib.h @line:709 */
+// Grayscale maxes
+#define IM_MAX_GS (255)
+
+#define IM_IS_BINARY(img)   ((img)->pixfmt == PIXFORMAT_BINARY)
+#define IM_IS_GS(img)       ((img)->pixfmt == PIXFORMAT_GRAYSCALE)
+#define IM_IS_RGB565(img)   ((img)->pixfmt == PIXFORMAT_RGB565)
+#define IM_IS_BAYER(img)    ((img)->is_bayer)
+#define IM_IS_JPEG(img)     ((img)->pixfmt == PIXFORMAT_JPEG)
+
+#define IM_X_INSIDE(img, x) \
+    ({ __typeof__ (img) _img = (img); \
+       __typeof__ (x) _x = (x); \
+       (0<=_x)&&(_x<_img->w); })
+
+#define IM_Y_INSIDE(img, y) \
+    ({ __typeof__ (img) _img = (img); \
+       __typeof__ (y) _y = (y); \
+       (0<=_y)&&(_y<_img->h); })
+
+#define IM_GET_GS_PIXEL(img, x, y) \
+    ({ __typeof__ (img) _img = (img); \
+       __typeof__ (x) _x = (x); \
+       __typeof__ (y) _y = (y); \
+       ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]; })
+
+#define IM_GET_RGB565_PIXEL(img, x, y) \
+    ({ __typeof__ (img) _img = (img); \
+       __typeof__ (x) _x = (x); \
+       __typeof__ (y) _y = (y); \
+       ((uint16_t*)_img->pixels)[(_y*_img->w)+_x]; })
+
+#define IM_SET_GS_PIXEL(img, x, y, p) \
+    ({ __typeof__ (img) _img = (img); \
+       __typeof__ (x) _x = (x); \
+       __typeof__ (y) _y = (y); \
+       __typeof__ (p) _p = (p); \
+       ((uint8_t*)_img->pixels)[(_y*_img->w)+_x]=_p; })
+
+#define IM_SET_RGB565_PIXEL(img, x, y, p) \
+    ({ __typeof__ (img) _img = (img); \
+       __typeof__ (x) _x = (x); \
+       __typeof__ (y) _y = (y); \
+       __typeof__ (p) _p = (p); \
+       ((uint16_t*)_img->pixels)[(_y*_img->w)+_x]=_p; })
+
+#define IM_EQUAL(img0, img1) \
+    ({ __typeof__ (img0) _img0 = (img0); \
+       __typeof__ (img1) _img1 = (img1); \
+       (_img0->w==_img1->w)&&(_img0->h==_img1->h)&&(_img0->pixfmt=_img1->pixfmt); })
+
+#define IM_TO_GS_PIXEL(img, x, y)    \
+    (img->bpp == 1 ? img->pixels[((y)*img->w)+(x)] : COLOR_RGB565_TO_Y(((uint16_t*)img->pixels)[((y)*img->w)+(x)]) )
+
+/* end openmv @file:imlib.h @line:960 */
+/* start openmv @file:imlib.h @line:1237 */
+void imlib_set_pixel(image_t *img, int x, int y, int p);
+void imlib_draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness);
+void imlib_draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill);
+void imlib_draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill);
+/**
+ * @brief draw string
+ * 
+ * @param img image_t
+ * @param x_off x
+ * @param y_off y
+ * @param str draw string
+ * @param c color
+ * @param scale string scale, eg: 1.0, 2.0....
+ * @param x_spacing 允许你在字符之间添加(如果是正数)或减去(如果是负数)x像素,设置字符间距。
+ * @param y_spacing 允许你在字符之间添加(如果是正数)或减去(如果是负数)y像素,设置行间距。
+ * @param mono_space 认为True,强制文本间距固定。对于大文本,这看起来很糟糕。设置False以获得非固定宽度的字符间距,看起来好多了。
+ * @param char_rotation 
+ * @param char_hmirror 如果为True,则水平镜像字符串中的所有字符。
+ * @param char_vflip 如果为True,则垂直翻转字符串中的所有字符。
+ * @param string_rotation 可以是0、90、180、270,来旋转字符串。
+ * @param string_hmirror 如果为True,则水平镜像字符串。
+ * @param string_hflip 如果为True,则垂直翻转字符串。
+ */
+void imlib_draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space,
+                       int char_rotation, bool char_hmirror, bool char_vflip, int string_rotation, bool string_hmirror, bool string_hflip);
+
+/**
+ * @brief 图像旋转校正
+ * 
+ * @param img image_t
+ * @param x_rotation 是围绕x轴在帧缓冲器中旋转图像的度数(这使图像上下旋转)。
+ * @param y_rotation 是帧缓冲区中围绕y轴旋转图像的度数(即左右旋转图像)。
+ * @param z_rotation 是围绕z轴在帧缓冲器中旋转图像的度数(即,使图像旋转到适当位置)。
+ * @param x_translation 是旋转后将图像移动到左侧或右侧的单位数。因为这个变换是应用在三维空间的,单位不是像素…
+ * @param y_translation 是旋转后将图像上移或下移的单位数。因为这个变换是应用在三维空间的,单位不是像素…
+ * @param zoom 是通过图像缩放的量。默认情况下1.0。
+ * @param fov 是在 3D 空间中旋转图像之前进行 2D->3D 投影时在内部使用的视场。 当这个值接近 0 时,图像被放置在远离视口的无穷远处。 当这个值接近 180 时,图像被放置在视口内。 通常,您不应更改此值,但可以修改它以更改 2D->3D 映射效果。
+ * @param corners 是四个 (x,y) 元组的列表,表示用于创建 4 点的四个角对应单应性, 将第一个角映射到 (0, 0),第二个角映射到 (image_width-1, 0), 第三个角映射到 (image_width-1, image_height-1),第四个角映射到 (0, image_height -1). 然后在重新映射图像后应用 3D 旋转。 此参数允许您使用 rotation_corr 来执行诸如鸟瞰图变换之类的操作。
+ */
+void imlib_rotation_corr(image_t *img, float x_rotation, float y_rotation, float z_rotation,
+                         float x_translation, float y_translation,
+                         float zoom, float fov, float *corners);
+
+
+#endif //__IMLIB_H__

+ 154 - 0
project_0/extmods/k210/imlib_config.h

@@ -0,0 +1,154 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Image library configuration.
+ */
+#ifndef __IMLIB_CONFIG_H__
+#define __IMLIB_CONFIG_H__
+
+// Enable Image I/O
+//#define IMLIB_ENABLE_IMAGE_IO
+
+// Enable Image File I/O
+// Not filesystem yet
+//#define IMLIB_ENABLE_IMAGE_FILE_IO
+
+// Enable LAB LUT
+//#define IMLIB_ENABLE_LAB_LUT
+
+// Enable YUV LUT
+//#define IMLIB_ENABLE_YUV_LUT
+
+// Enable mean pooling
+//#define IMLIB_ENABLE_MEAN_POOLING
+
+// Enable midpoint pooling
+//#define IMLIB_ENABLE_MIDPOINT_POOLING
+
+// Enable binary ops
+//#define IMLIB_ENABLE_BINARY_OPS
+
+// Enable math ops
+//#define IMLIB_ENABLE_MATH_OPS
+
+// Enable flood_fill()
+//#define IMLIB_ENABLE_FLOOD_FILL
+
+// Enable mean()
+//#define IMLIB_ENABLE_MEAN
+
+// Enable median()
+//#define IMLIB_ENABLE_MEDIAN
+
+// Enable mode()
+//#define IMLIB_ENABLE_MODE
+
+// Enable midpoint()
+//#define IMLIB_ENABLE_MIDPOINT
+
+// Enable morph()
+//#define IMLIB_ENABLE_MORPH
+
+// Enable Gaussian
+//#define IMLIB_ENABLE_GAUSSIAN
+
+// Enable Laplacian
+//#define IMLIB_ENABLE_LAPLACIAN
+
+// Enable bilateral()
+//#define IMLIB_ENABLE_BILATERAL
+
+// Enable cartoon()
+// #define IMLIB_ENABLE_CARTOON
+
+// Enable linpolar()
+//#define IMLIB_ENABLE_LINPOLAR
+
+// Enable logpolar()
+//#define IMLIB_ENABLE_LOGPOLAR
+
+// Enable lens_corr()
+//#define IMLIB_ENABLE_LENS_CORR
+
+// Enable rotation_corr()
+#define IMLIB_ENABLE_ROTATION_CORR
+
+// Enable phasecorrelate()
+//#if defined(IMLIB_ENABLE_ROTATION_CORR)
+//#define IMLIB_ENABLE_FIND_DISPLACEMENT
+//#endif
+
+// Enable get_similarity()
+//#define IMLIB_ENABLE_GET_SIMILARITY
+
+// Enable find_lines()
+//#define IMLIB_ENABLE_FIND_LINES
+
+// Enable find_line_segments()
+//#define IMLIB_ENABLE_FIND_LINE_SEGMENTS
+
+// Enable find_circles()
+//#define IMLIB_ENABLE_FIND_CIRCLES
+
+// Enable find_rects()
+//#define IMLIB_ENABLE_FIND_RECTS
+
+// Enable find_qrcodes() (14 KB)
+//#define IMLIB_ENABLE_QRCODES
+
+// Enable find_apriltags() (64 KB)
+//#define IMLIB_ENABLE_APRILTAGS
+
+// Enable fine find_apriltags() - (8-way connectivity versus 4-way connectivity)
+// #define IMLIB_ENABLE_FINE_APRILTAGS
+
+// Enable high res find_apriltags() - uses more RAM
+// #define IMLIB_ENABLE_HIGH_RES_APRILTAGS
+
+// Enable find_datamatrices() (26 KB)
+//#define IMLIB_ENABLE_DATAMATRICES
+
+// Enable find_barcodes() (42 KB)
+//#define IMLIB_ENABLE_BARCODES
+
+// Enable CMSIS NN
+// #if !defined(CUBEAI)
+// #define IMLIB_ENABLE_CNN
+// #endif
+
+// Enable Tensor Flow
+#if !defined(CUBEAI)
+//#define IMLIB_ENABLE_TF
+#endif
+
+// Enable FAST (20+ KBs).
+// #define IMLIB_ENABLE_FAST
+
+// Enable find_template()
+//#define IMLIB_FIND_TEMPLATE
+
+// Enable find_lbp()
+//#define IMLIB_ENABLE_FIND_LBP
+
+// Enable find_keypoints()
+//#define IMLIB_ENABLE_FIND_KEYPOINTS
+
+// Enable load, save and match descriptor
+//#define IMLIB_ENABLE_DESCRIPTOR
+
+// Enable find_hog()
+//#define IMLIB_ENABLE_HOG
+
+// Enable selective_search()
+//#define IMLIB_ENABLE_SELECTIVE_SEARCH
+
+// Enable STM32 DMA2D
+//#define IMLIB_ENABLE_DMA2D
+
+#define __BYTE_ORDER__  __ORDER_LITTLE_ENDIAN__
+#endif //__IMLIB_CONFIG_H__

+ 47 - 0
project_0/extmods/k210/imlib_exts.h

@@ -0,0 +1,47 @@
+#ifndef __IMLIB_EXTS_H
+#define __IMLIB_EXTS_H
+#include <stdbool.h>
+// for rt-ak
+#define IMAGE_RGB888_LINE_LEN(image) ((image)->w)
+#define IMAGE_RGB888_LINE_LEN_BYTES(image) (IMAGE_RGB888_LINE_LEN(image) * sizeof(uint8_t) * PIXFORMAT_BPP_RGB888)
+
+
+#define IMAGE_GET_RGB888_CHW_PIXEL(image, x, y, i) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (i) _i = (i); \
+    ((uint8_t *) _image->data)[(_i * _image->w * _image->h) + (_image->w * _y) + _x]; \
+})
+
+#define IMAGE_PUT_RGB888_CHW_PIXEL(image, x, y, i, v) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (v) _v = (v); \
+    __typeof__ (i) _i = (i); \
+    ((uint8_t *) _image->data)[(_i * _image->w * _image->h) + (_image->w * _y) + _x] = _v; \
+})
+
+#define IMAGE_GET_RGB888_HWC_PIXEL(image, x, y, i) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (i) _i = (i); \
+    ((uint8_t *) _image->data)[3 * (_image->w * _y + _x) + _i]; \
+})
+
+#define IMAGE_PUT_RGB888_HWC_PIXEL(image, x, y, i, v) \
+({ \
+    __typeof__ (image) _image = (image); \
+    __typeof__ (x) _x = (x); \
+    __typeof__ (y) _y = (y); \
+    __typeof__ (v) _v = (v); \
+    __typeof__ (i) _i = (i); \
+    ((uint8_t *) _image->data)[3 * (_image->w * _y + _x) + _i] = _v; \
+})
+
+#endif //__IMLIB_EXTS_H

+ 61 - 0
project_0/extmods/k210/modk210.c

@@ -0,0 +1,61 @@
+#include "py/runtime.h"
+
+#ifdef EXTMODS_K210_FFT
+extern const mp_obj_type_t k210_fft_type;
+#endif
+#ifdef EXTMODS_K210_I2S
+extern const mp_obj_type_t k210_i2s_type;
+#endif
+#ifdef EXTMODS_K210_FPIOA
+extern const mp_obj_type_t k210_fpioa_type;
+#endif
+#ifdef EXTMODS_K210_LCDCTL
+extern const mp_obj_type_t k210_lcdctl_type;
+#endif
+#ifdef EXTMODS_K210_KPU
+extern const mp_obj_type_t k210_kpu_type;
+#endif
+#ifdef EXTMODS_K210_DVP
+extern const mp_obj_type_t k210_cam_type;
+#endif
+
+#if (defined(EXTMODS_K210_DVP))
+extern const mp_obj_type_t py_image_type;
+#endif
+#ifdef EXTMODS_K210_SHA256
+extern const mp_obj_type_t k210_sha256_type;
+#endif
+
+STATIC const mp_rom_map_elem_t k210_module_globals_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_k210) },
+#ifdef EXTMODS_K210_FFT
+    { MP_ROM_QSTR(MP_QSTR_FFT),  MP_ROM_PTR(&k210_fft_type) },
+#endif
+#ifdef EXTMODS_K210_I2S
+    { MP_ROM_QSTR(MP_QSTR_I2S),  MP_ROM_PTR(&k210_i2s_type) },
+#endif
+#ifdef EXTMODS_K210_FPIOA
+    { MP_ROM_QSTR(MP_QSTR_FPIOA),  MP_ROM_PTR(&k210_fpioa_type) },
+#endif
+#ifdef EXTMODS_K210_LCDCTL
+    { MP_ROM_QSTR(MP_QSTR_lcdctl),  MP_ROM_PTR(&k210_lcdctl_type) },
+#endif
+#ifdef EXTMODS_K210_KPU
+    { MP_ROM_QSTR(MP_QSTR_KPU),  MP_ROM_PTR(&k210_kpu_type) },
+#endif
+#ifdef EXTMODS_K210_DVP
+    { MP_ROM_QSTR(MP_QSTR_camera),  MP_ROM_PTR(&k210_cam_type) },
+#endif
+#if (defined(EXTMODS_K210_DVP))
+    { MP_ROM_QSTR(MP_QSTR_Image),  MP_ROM_PTR(&py_image_type) },
+#endif
+#ifdef EXTMODS_K210_SHA256
+    { MP_ROM_QSTR(MP_QSTR_sha256),  MP_ROM_PTR(&k210_sha256_type) },
+#endif
+};
+STATIC MP_DEFINE_CONST_DICT (k210_module_globals, k210_module_globals_table);
+
+const mp_obj_module_t k210_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t*)&k210_module_globals,
+};

+ 64 - 0
project_0/extmods/k210/py_assert.h

@@ -0,0 +1,64 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * MP assertions.
+ */
+#ifndef __PY_ASSERT_H__
+#define __PY_ASSERT_H__
+#define PY_ASSERT_TRUE(cond)                            \
+    do {                                                \
+        if ((cond) == 0) {                              \
+            mp_raise_msg(&mp_type_OSError,              \
+                         MP_ERROR_TEXT(                 \
+                         "Operation not supported"));   \
+        }                                               \
+    } while(0)
+
+#define PY_ASSERT_TRUE_MSG(cond, msg)                   \
+    do {                                                \
+        if ((cond) == 0) {                              \
+            mp_raise_msg(&mp_type_OSError,              \
+                         MP_ERROR_TEXT(msg));           \
+        }                                               \
+    } while(0)
+
+#define PY_ASSERT_FALSE_MSG(cond, msg)                  \
+    do {                                                \
+        if ((cond) == 1) {                              \
+            mp_raise_msg(&mp_type_OSError,              \
+                         MP_ERROR_TEXT(msg));           \
+        }                                               \
+    } while(0)
+
+#define PY_ASSERT_TYPE(obj, type)                       \
+    do {                                                \
+        __typeof__ (obj) _a = (obj);                    \
+        __typeof__ (type) _b = (type);                  \
+        if (!MP_OBJ_IS_TYPE(_a, _b)) {                  \
+            mp_raise_msg_varg(&mp_type_TypeError,       \
+                        MP_ERROR_TEXT(                  \
+                        "Can't convert %s to %s"),      \
+                        mp_obj_get_type_str(_a),        \
+                        mp_obj_get_type_str(_b));       \
+        }                                               \
+    } while(0)
+/* IS_TYPE doesn't work for str objs */
+#define PY_ASSERT_STR(obj)                              \
+    do {                                                \
+        __typeof__ (obj) _a = (obj);                    \
+        if (!MP_OBJ_IS_STR(_a)) {                       \
+            mp_raise_msg_varg(                          \
+                        &mp_type_TypeError,             \
+                        MP_ERROR_TEXT(                  \
+                        "Can't convert %s to %s"),      \
+                        mp_obj_get_type_str(_a),        \
+                        str_type.name);                 \
+        }                                               \
+    } while(0)
+
+#endif // __PY_ASSERT_H__

+ 230 - 0
project_0/extmods/k210/py_camera.c

@@ -0,0 +1,230 @@
+#include <stdlib.h>
+
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/objarray.h"
+#include "py/binary.h"
+
+#ifdef EXTMODS_K210_DVP
+#include "py_image.h"
+
+
+typedef struct
+{
+    mp_obj_base_t base;
+    rt_dev_t sensor;
+    void *dis;
+    void *ai;
+    int w;
+    int h;
+}k210_cam_obj_t;
+
+volatile static uint32_t g_dvp_finish_flag;
+static rt_err_t camera_cb(rt_device_t dev, size_t size){
+    g_dvp_finish_flag = 1;
+    return RT_EOK;
+}
+
+static int k210sensor_reset(rt_dev_t *dev){
+    if(*dev){
+        rt_device_close(*dev);
+    }
+    *dev = rt_device_find("gc0308");
+    if(rt_device_init(*dev) != RT_EOK){
+        return -1;
+    }
+  
+    if(rt_device_open(*dev,RT_DEVICE_OFLAG_RDWR) != RT_EOK){
+        return -1;
+    }
+    rt_device_set_rx_indicate(*dev,camera_cb);
+
+    return 0;
+}
+
+static int k210sensor_read(rt_dev_t *dev, uint8_t *dis,  uint8_t *ai){
+    if(!(*dev)){
+        return -1;
+    }
+
+    g_dvp_finish_flag = 0;
+    rt_device_read(*dev,0,dis,0);
+
+    rt_tick_t start = rt_tick_get();
+    while (g_dvp_finish_flag == 0)
+    {
+        usleep(100);
+        if ((rt_tick_get() - start) > rt_tick_from_millisecond(1000)) //wait for 30ms
+            return -1;
+    }
+    return 0;
+}
+
+const mp_obj_type_t k210_cam_type;
+
+STATIC mp_obj_t k210_cam_reset(mp_obj_t self)
+{
+    k210_cam_obj_t *obj = (k210_cam_obj_t *)self;
+    if (k210sensor_reset(&obj->sensor) != 0)
+    {
+        mp_raise_OSError(-1);
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(k210_cam_reset_obj, k210_cam_reset);
+#if 0 
+STATIC mp_obj_t k210_cam_set_pixformat(mp_obj_t self, mp_obj_t pixformat)
+{
+    k210_cam_obj_t *obj = (k210_cam_obj_t *)self;
+
+    if (k210sensor_set_pixformat(&obj->sensor, mp_obj_get_int(pixformat)) != 0)
+    {
+        mp_raise_OSError(-1);
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(k210_cam_set_pixformat_obj, k210_cam_set_pixformat);
+#endif
+#if 1
+static mp_obj_t k210_cam_set_framesize(mp_obj_t self, mp_obj_t width, mp_obj_t height) 
+{
+    k210_cam_obj_t *obj = (k210_cam_obj_t *)self;
+    int w, h, ow, oh;
+
+    ow = obj->w;
+    oh = obj->h;
+    w = mp_obj_get_int(width);
+    h = mp_obj_get_int(height);
+    if ((w!=320) && (h!=240))
+    {
+        mp_raise_ValueError("invalid Width or Height, now only support 320x240");
+    }
+    obj->w = w;
+    obj->h = h;
+    // if (k210sensor_set_framesize(&obj->sensor, w, h) != 0)
+    // {
+    //     mp_raise_OSError(-1);
+    // }
+
+    if ((w * h) != (ow * oh))
+    {
+        char *ptr;
+
+        ptr = (char*)realloc(obj->dis, (w * h) * (2 + 3));
+        if (!ptr)
+        {
+            mp_raise_msg_varg(&mp_type_MemoryError, MP_ERROR_TEXT("no memory"));
+        }
+
+        obj->dis = ptr;
+        obj->ai = ptr + (w * h * 2);
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(k210_cam_set_framesize_obj, k210_cam_set_framesize);
+#endif
+
+static mp_obj_t k210_cam_snapshot(mp_obj_t self)
+{
+    k210_cam_obj_t *obj = (k210_cam_obj_t *)self;
+    mp_obj_t dis_data, ai_data;
+    rt_dev_t *s = &obj->sensor;
+    int ret;
+
+    if (!obj->dis)
+    {
+        mp_raise_ValueError("framebuffer not init");
+    }
+    
+    dis_data = py_image(320, 240, PIXFORMAT_RGB565, 320*240*2, obj->dis);
+    ai_data = py_image(320, 240, PIXFORMAT_RGB888_CHW, 320*240*3, obj->ai);
+    ret = k210sensor_read(s, obj->dis, obj->ai);
+    if (ret < 0) 
+    {
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, "Capture Failed: %d", ret));
+    }
+    mp_obj_list_t *ret_list = NULL;
+    ret_list = m_new(mp_obj_list_t, 1);
+    mp_obj_list_init(ret_list, 0);
+    mp_obj_list_append(ret_list, dis_data );
+    mp_obj_list_append(ret_list, ai_data );
+
+    return MP_OBJ_FROM_PTR(ret_list);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(k210_cam_snapshot_obj, k210_cam_snapshot);
+
+static mp_obj_t k210_cam_del(mp_obj_t self)
+{
+    k210_cam_obj_t *obj = (k210_cam_obj_t *)self;
+    if(!obj->sensor){
+        rt_device_close(obj->sensor);
+        obj->sensor = RT_NULL;
+    }
+    
+    if (obj->dis)
+    {
+        realloc(obj->dis, 0);
+        obj->dis = 0;
+        obj->ai = 0;
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(k210_cam_del_obj, k210_cam_del);
+
+STATIC mp_obj_t make_new()
+{
+	k210_cam_obj_t *self = m_new_obj_with_finaliser(k210_cam_obj_t);
+
+	self->base.type = &k210_cam_type;
+    self->sensor = RT_NULL;
+
+    return self;
+}
+#if 0
+static mp_obj_t k210_cam_switch(mp_obj_t self, mp_obj_t sel) 
+{
+    k210_cam_obj_t *obj = (k210_cam_obj_t *)self;
+    k210sensor_t *s = &obj->sensor;
+    if (mp_obj_get_type(sel) != &mp_type_int)
+        mp_raise_ValueError("Invalid Value");
+    
+    int select = mp_obj_get_int(sel);
+    if (select == 1)
+        k210sensor_switch(s, 1);
+    else if (select == 0)
+        k210sensor_switch(s, 0);
+    else
+        mp_raise_ValueError("Invalid Value");
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(k210_cam_switch_obj, k210_cam_switch);
+#endif
+
+STATIC const mp_rom_map_elem_t locals_dict_table[] = {
+    {MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&k210_cam_del_obj)},
+
+    {MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&k210_cam_reset_obj)},
+    // {MP_ROM_QSTR(MP_QSTR_set_pixformat), MP_ROM_PTR(&k210_cam_set_pixformat_obj)},
+    {MP_ROM_QSTR(MP_QSTR_set_framesize), MP_ROM_PTR(&k210_cam_set_framesize_obj)},
+    {MP_ROM_QSTR(MP_QSTR_snapshot), MP_ROM_PTR(&k210_cam_snapshot_obj)},
+    // {MP_ROM_QSTR(MP_QSTR_sw), MP_ROM_PTR(&k210_cam_switch_obj)},
+
+    // {MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(PIXFORMAT_RGB565)},   /* 2BPP/RGB565*/
+    // {MP_ROM_QSTR(MP_QSTR_YUV422), MP_ROM_INT(PIXFORMAT_YUV422)},   /* 2BPP/YUV422*/
+
+};
+STATIC MP_DEFINE_CONST_DICT(k210_cam_dict, locals_dict_table);
+
+const mp_obj_type_t k210_cam_type = {
+    .base = { &mp_type_type },
+    .make_new = make_new,
+    .name = MP_QSTR_camera,
+    .locals_dict = (mp_obj_t)&k210_cam_dict,
+};
+#endif

+ 467 - 0
project_0/extmods/k210/py_helper.c

@@ -0,0 +1,467 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Python helper functions.
+ */
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py_helper.h"
+#include "py_assert.h"
+
+extern void *py_image_cobj(mp_obj_t img_obj);
+
+mp_obj_t py_func_unavailable(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    PY_ASSERT_TRUE_MSG(false, "This function is unavailable on your OpenMV Cam.");
+    return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(py_func_unavailable_obj, 0, py_func_unavailable);
+
+image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg)
+{
+    image_t *arg_img = py_image_cobj(arg);
+    PY_ASSERT_TRUE_MSG(arg_img->is_mutable, "Image is not mutable!");
+    return arg_img;
+}
+
+image_t *py_helper_arg_to_image_not_compressed(const mp_obj_t arg)
+{
+    image_t *arg_img = py_image_cobj(arg);
+    PY_ASSERT_FALSE_MSG(arg_img->is_compressed, "Image is compressed!");
+    return arg_img;
+}
+
+image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg)
+{
+    image_t *arg_img = py_image_cobj(arg);
+    PY_ASSERT_TRUE_MSG(arg_img->pixfmt == PIXFORMAT_GRAYSCALE, "Image is not grayscale!");
+    return arg_img;
+}
+
+image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index,
+                                            mp_map_t *kw_args, mp_obj_t kw, image_t *default_val)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        default_val = py_helper_arg_to_image_mutable(kw_arg->value);
+    } else if (n_args > arg_index) {
+        default_val = py_helper_arg_to_image_mutable(args[arg_index]);
+    }
+
+    return default_val;
+}
+
+image_t *py_helper_keyword_to_image_mutable_mask(uint n_args, const mp_obj_t *args, uint arg_index,
+                                                 mp_map_t *kw_args)
+{
+    return py_helper_keyword_to_image_mutable(n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_mask), NULL);
+}
+
+image_t *py_helper_keyword_to_image_mutable_color_palette(uint n_args, const mp_obj_t *args, uint arg_index,
+                                                          mp_map_t *kw_args)
+{
+    return py_helper_keyword_to_image_mutable(n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_palette), NULL);
+}
+
+image_t *py_helper_keyword_to_image_mutable_alpha_palette(uint n_args, const mp_obj_t *args, uint arg_index,
+                                                          mp_map_t *kw_args)
+{
+    return py_helper_keyword_to_image_mutable(n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_alpha_palette), NULL);
+}
+
+// void py_helper_keyword_rectangle(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index,
+//                                  mp_map_t *kw_args, mp_obj_t kw, rectangle_t *r)
+// {
+//     mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+//     if (kw_arg) {
+//         mp_obj_t *arg_rectangle;
+//         mp_obj_get_array_fixed_n(kw_arg->value, 4, &arg_rectangle);
+//         r->x = mp_obj_get_int(arg_rectangle[0]);
+//         r->y = mp_obj_get_int(arg_rectangle[1]);
+//         r->w = mp_obj_get_int(arg_rectangle[2]);
+//         r->h = mp_obj_get_int(arg_rectangle[3]);
+//     } else if (n_args > arg_index) {
+//         mp_obj_t *arg_rectangle;
+//         mp_obj_get_array_fixed_n(args[arg_index], 4, &arg_rectangle);
+//         r->x = mp_obj_get_int(arg_rectangle[0]);
+//         r->y = mp_obj_get_int(arg_rectangle[1]);
+//         r->w = mp_obj_get_int(arg_rectangle[2]);
+//         r->h = mp_obj_get_int(arg_rectangle[3]);
+//     } else {
+//         r->x = 0;
+//         r->y = 0;
+//         r->w = img->w;
+//         r->h = img->h;
+//     }
+
+//     PY_ASSERT_TRUE_MSG((r->w >= 1) && (r->h >= 1), "Invalid ROI dimensions!");
+//     rectangle_t temp;
+//     temp.x = 0;
+//     temp.y = 0;
+//     temp.w = img->w;
+//     temp.h = img->h;
+
+//     PY_ASSERT_TRUE_MSG(rectangle_overlap(r, &temp), "ROI does not overlap on the image!");
+//     rectangle_intersected(r, &temp);
+// }
+
+// void py_helper_keyword_rectangle_roi(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index,
+//                                      mp_map_t *kw_args, rectangle_t *r)
+// {
+//     py_helper_keyword_rectangle(img, n_args, args, arg_index, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_roi), r);
+// }
+
+int py_helper_keyword_int(uint n_args, const mp_obj_t *args, uint arg_index,
+                          mp_map_t *kw_args, mp_obj_t kw, int default_val)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        default_val = mp_obj_get_int(kw_arg->value);
+    } else if (n_args > arg_index) {
+        default_val = mp_obj_get_int(args[arg_index]);
+    }
+
+    return default_val;
+}
+
+bool py_helper_keyword_int_maybe(uint n_args, const mp_obj_t *args, uint arg_index,
+                                 mp_map_t *kw_args, mp_obj_t kw, int* value)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        return mp_obj_get_int_maybe(kw_arg->value, value);
+    } else if (n_args > arg_index) {
+        return mp_obj_get_int_maybe(args[arg_index], value);
+    }
+
+    return false;
+}
+
+float py_helper_keyword_float(uint n_args, const mp_obj_t *args, uint arg_index,
+                              mp_map_t *kw_args, mp_obj_t kw, float default_val)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        default_val = mp_obj_get_float(kw_arg->value);
+    } else if (n_args > arg_index) {
+        default_val = mp_obj_get_float(args[arg_index]);
+    }
+
+    return default_val;
+}
+
+bool py_helper_keyword_float_maybe(uint n_args, const mp_obj_t *args, uint arg_index,
+                                   mp_map_t *kw_args, mp_obj_t kw, float *value)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        return mp_obj_get_float_maybe(kw_arg->value, value);
+    } else if (n_args > arg_index) {
+        return mp_obj_get_float_maybe(args[arg_index], value);
+    }
+
+    return false;
+}
+
+void py_helper_keyword_int_array(uint n_args, const mp_obj_t *args, uint arg_index,
+                                 mp_map_t *kw_args, mp_obj_t kw, int *x, int size)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        mp_obj_t *arg_array;
+        mp_obj_get_array_fixed_n(kw_arg->value, size, &arg_array);
+        for (int i = 0; i < size; i++) x[i] = mp_obj_get_int(arg_array[i]);
+    } else if (n_args > arg_index) {
+        mp_obj_t *arg_array;
+        mp_obj_get_array_fixed_n(args[arg_index], size, &arg_array);
+        for (int i = 0; i < size; i++) x[i] = mp_obj_get_int(arg_array[i]);
+    }
+}
+
+void py_helper_keyword_float_array(uint n_args, const mp_obj_t *args, uint arg_index,
+                                   mp_map_t *kw_args, mp_obj_t kw, float *x, int size)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        mp_obj_t *arg_array;
+        mp_obj_get_array_fixed_n(kw_arg->value, size, &arg_array);
+        for (int i = 0; i < size; i++) x[i] = mp_obj_get_float(arg_array[i]);
+    } else if (n_args > arg_index) {
+        mp_obj_t *arg_array;
+        mp_obj_get_array_fixed_n(args[arg_index], size, &arg_array);
+        for (int i = 0; i < size; i++) x[i] = mp_obj_get_float(arg_array[i]);
+    }
+}
+
+// float *py_helper_keyword_corner_array(uint n_args, const mp_obj_t *args, uint arg_index,
+//                                       mp_map_t *kw_args, mp_obj_t kw)
+// {
+//     mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+//     if (kw_arg) {
+//         mp_obj_t *arg_array;
+//         mp_obj_get_array_fixed_n(kw_arg->value, 4, &arg_array);
+//         float *corners = xalloc(sizeof(float) * 8);
+//         for (int i = 0; i < 4; i++) {
+//             mp_obj_t *arg_point;
+//             mp_obj_get_array_fixed_n(arg_array[i], 2, &arg_point);
+//             corners[(i*2)+0] = mp_obj_get_float(arg_point[0]);
+//             corners[(i*2)+1] = mp_obj_get_float(arg_point[1]);
+//         }
+//         return corners;
+//     } else if (n_args > arg_index) {
+//         mp_obj_t *arg_array;
+//         mp_obj_get_array_fixed_n(args[arg_index], 4, &arg_array);
+//         float *corners = xalloc(sizeof(float) * 8);
+//         for (int i = 0; i < 4; i++) {
+//             mp_obj_t *arg_point;
+//             mp_obj_get_array_fixed_n(arg_array[i], 2, &arg_point);
+//             corners[(i*2)+0] = mp_obj_get_float(arg_point[0]);
+//             corners[(i*2)+1] = mp_obj_get_float(arg_point[1]);
+//         }
+//         return corners;
+//     }
+
+//     return NULL;
+// }
+
+mp_obj_t *py_helper_keyword_iterable(uint n_args, const mp_obj_t *args,
+        uint arg_index, mp_map_t *kw_args, mp_obj_t kw, size_t *len)
+{
+    mp_obj_t itr = NULL;
+    mp_obj_t *items = NULL;
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        itr = kw_arg->value;
+    } else if (n_args > arg_index) {
+        itr = args[arg_index];
+    }
+
+    if (itr && (MP_OBJ_IS_TYPE(itr, &mp_type_tuple) ||
+                MP_OBJ_IS_TYPE(itr, &mp_type_list))) {
+        mp_obj_get_array(itr, len, &items);
+    }
+    return items;
+}
+
+uint py_helper_consume_array(uint n_args, const mp_obj_t *args, uint arg_index, size_t len, const mp_obj_t **items)
+{
+    if (MP_OBJ_IS_TYPE(args[arg_index], &mp_type_tuple) || MP_OBJ_IS_TYPE(args[arg_index], &mp_type_list)) {
+        mp_obj_get_array_fixed_n(args[arg_index], len, (mp_obj_t **) items);
+        return arg_index + 1;
+    } else {
+        PY_ASSERT_TRUE_MSG((n_args - arg_index) >= len, "Not enough positional arguments!");
+        *items = args + arg_index;
+        return arg_index + len;
+    }
+}
+
+int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index,
+                            mp_map_t *kw_args, int default_val)
+{
+    mp_map_elem_t *kw_arg = kw_args ? mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), MP_MAP_LOOKUP) : NULL;
+
+    if (kw_arg) {
+        if (mp_obj_is_integer(kw_arg->value)) {
+            default_val = mp_obj_get_int(kw_arg->value);
+        } else {
+            mp_obj_t *arg_color;
+            mp_obj_get_array_fixed_n(kw_arg->value, 3, &arg_color);
+            default_val = COLOR_R8_G8_B8_TO_RGB565(IM_MAX(IM_MIN(mp_obj_get_int(arg_color[0]), COLOR_R8_MAX), COLOR_R8_MIN),
+                                                   IM_MAX(IM_MIN(mp_obj_get_int(arg_color[1]), COLOR_G8_MAX), COLOR_G8_MIN),
+                                                   IM_MAX(IM_MIN(mp_obj_get_int(arg_color[2]), COLOR_B8_MAX), COLOR_B8_MIN));
+            switch (img->pixfmt) {
+                case PIXFORMAT_BINARY: {
+                    default_val = COLOR_RGB565_TO_BINARY(default_val);
+                    break;
+                }
+                case PIXFORMAT_GRAYSCALE: {
+                    default_val = COLOR_RGB565_TO_GRAYSCALE(default_val);
+                    break;
+                }
+                default: {
+                    break;
+                }
+            }
+        }
+    } else if (n_args > arg_index) {
+        if (mp_obj_is_integer(args[arg_index])) {
+            default_val = mp_obj_get_int(args[arg_index]);
+        } else {
+            mp_obj_t *arg_color;
+            mp_obj_get_array_fixed_n(args[arg_index], 3, &arg_color);
+            default_val = COLOR_R8_G8_B8_TO_RGB565(IM_MAX(IM_MIN(mp_obj_get_int(arg_color[0]), COLOR_R8_MAX), COLOR_R8_MIN),
+                                                   IM_MAX(IM_MIN(mp_obj_get_int(arg_color[1]), COLOR_G8_MAX), COLOR_G8_MIN),
+                                                   IM_MAX(IM_MIN(mp_obj_get_int(arg_color[2]), COLOR_B8_MAX), COLOR_B8_MIN));
+            switch (img->pixfmt) {
+                case PIXFORMAT_BINARY: {
+                    default_val = COLOR_RGB565_TO_BINARY(default_val);
+                    break;
+                }
+                case PIXFORMAT_GRAYSCALE: {
+                    default_val = COLOR_RGB565_TO_GRAYSCALE(default_val);
+                    break;
+                }
+                default: {
+                    break;
+                }
+            }
+        }
+    }
+
+    return default_val;
+}
+
+// void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds)
+// {
+//     mp_uint_t arg_thresholds_len;
+//     mp_obj_t *arg_thresholds;
+//     mp_obj_get_array(arg, &arg_thresholds_len, &arg_thresholds);
+//     if (!arg_thresholds_len) return;
+//     for(mp_uint_t i = 0; i < arg_thresholds_len; i++) {
+//         mp_uint_t arg_threshold_len;
+//         mp_obj_t *arg_threshold;
+//         mp_obj_get_array(arg_thresholds[i], &arg_threshold_len, &arg_threshold);
+//         if (arg_threshold_len) {
+//             color_thresholds_list_lnk_data_t lnk_data;
+//             lnk_data.LMin = (arg_threshold_len > 0) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[0]),
+//                         IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) :
+//                         IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN);
+//             lnk_data.LMax = (arg_threshold_len > 1) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[1]),
+//                         IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX)), IM_MIN(COLOR_L_MIN, COLOR_GRAYSCALE_MIN)) :
+//                         IM_MAX(COLOR_L_MAX, COLOR_GRAYSCALE_MAX);
+//             lnk_data.AMin = (arg_threshold_len > 2) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[2]), COLOR_A_MAX), COLOR_A_MIN) : COLOR_A_MIN;
+//             lnk_data.AMax = (arg_threshold_len > 3) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[3]), COLOR_A_MAX), COLOR_A_MIN) : COLOR_A_MAX;
+//             lnk_data.BMin = (arg_threshold_len > 4) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[4]), COLOR_B_MAX), COLOR_B_MIN) : COLOR_B_MIN;
+//             lnk_data.BMax = (arg_threshold_len > 5) ? IM_MAX(IM_MIN(mp_obj_get_int(arg_threshold[5]), COLOR_B_MAX), COLOR_B_MIN) : COLOR_B_MAX;
+//             color_thresholds_list_lnk_data_t lnk_data_tmp;
+//             memcpy(&lnk_data_tmp, &lnk_data, sizeof(color_thresholds_list_lnk_data_t));
+//             lnk_data.LMin = IM_MIN(lnk_data_tmp.LMin, lnk_data_tmp.LMax);
+//             lnk_data.LMax = IM_MAX(lnk_data_tmp.LMin, lnk_data_tmp.LMax);
+//             lnk_data.AMin = IM_MIN(lnk_data_tmp.AMin, lnk_data_tmp.AMax);
+//             lnk_data.AMax = IM_MAX(lnk_data_tmp.AMin, lnk_data_tmp.AMax);
+//             lnk_data.BMin = IM_MIN(lnk_data_tmp.BMin, lnk_data_tmp.BMax);
+//             lnk_data.BMax = IM_MAX(lnk_data_tmp.BMin, lnk_data_tmp.BMax);
+//             list_push_back(thresholds, &lnk_data);
+//         }
+//     }
+// }
+
+// void py_helper_keyword_thresholds(uint n_args, const mp_obj_t *args, uint arg_index,
+//                                   mp_map_t *kw_args, list_t *thresholds)
+// {
+//     mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_thresholds), MP_MAP_LOOKUP);
+
+//     if (kw_arg) {
+//         py_helper_arg_to_thresholds(kw_arg->value, thresholds);
+//     } else if (n_args > arg_index) {
+//         py_helper_arg_to_thresholds(args[arg_index], thresholds);
+//     }
+// }
+
+int py_helper_arg_to_ksize(const mp_obj_t arg)
+{
+    int ksize = mp_obj_get_int(arg);
+    PY_ASSERT_TRUE_MSG(ksize >= 0, "KernelSize must be >= 0!");
+    return ksize;
+}
+
+int py_helper_ksize_to_n(int ksize)
+{
+    return ((ksize * 2) + 1) * ((ksize * 2) + 1);
+}
+
+mp_obj_t py_helper_keyword_object(uint n_args, const mp_obj_t *args,
+        uint arg_index, mp_map_t *kw_args, mp_obj_t kw, mp_obj_t default_val)
+{
+    mp_map_elem_t *kw_arg = mp_map_lookup(kw_args, kw, MP_MAP_LOOKUP);
+
+    if (kw_arg) {
+        return kw_arg->value;
+    } else if (n_args > arg_index) {
+        return args[arg_index];
+    } else {
+        return default_val;
+    }
+}
+
+// const uint16_t *py_helper_keyword_color_palette(uint n_args, const mp_obj_t *args,
+//         uint arg_index, mp_map_t *kw_args, const uint16_t *default_color_palette)
+// {
+//     int palette;
+
+//     mp_map_elem_t *kw_arg =
+//         mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color_palette), MP_MAP_LOOKUP);
+
+//     if (kw_arg && (kw_arg->value == mp_const_none)) {
+//         default_color_palette = NULL;
+//     } else if ((n_args > arg_index) && (args[arg_index] == mp_const_none)) {
+//         default_color_palette = NULL;
+//     } else if (py_helper_keyword_int_maybe(n_args, args, arg_index, kw_args,
+//             MP_OBJ_NEW_QSTR(MP_QSTR_color_palette), &palette)) {
+//         if (palette == COLOR_PALETTE_RAINBOW) {
+//             default_color_palette = rainbow_table;
+//         } else if (palette == COLOR_PALETTE_IRONBOW) {
+//             default_color_palette = ironbow_table;
+//         } else {
+//             mp_raise_msg(&mp_type_ValueError,
+//                     MP_ERROR_TEXT("Invalid pre-defined color palette!"));
+//         }
+//     } else {
+//         image_t *arg_color_palette =
+//             py_helper_keyword_to_image_mutable_color_palette(n_args, args, arg_index, kw_args);
+
+//         if (arg_color_palette) {
+//             if (arg_color_palette->pixfmt != PIXFORMAT_RGB565) {
+//                 mp_raise_msg(&mp_type_ValueError,
+//                         MP_ERROR_TEXT("Color palette must be RGB565!"));
+//             }
+
+//             if ((arg_color_palette->w * arg_color_palette->h) != 256) {
+//                 mp_raise_msg(&mp_type_ValueError,
+//                         MP_ERROR_TEXT("Color palette must be 256 pixels!"));
+//             }
+
+//             default_color_palette = (uint16_t *) arg_color_palette->data;
+//         }
+//     }
+
+//     return default_color_palette;
+// }
+
+const uint8_t *py_helper_keyword_alpha_palette(uint n_args, const mp_obj_t *args,
+        uint arg_index, mp_map_t *kw_args, const uint8_t *default_alpha_palette)
+{
+    image_t *arg_alpha_palette =
+        py_helper_keyword_to_image_mutable_alpha_palette(n_args, args, 9, kw_args);
+
+    if (arg_alpha_palette) {
+        if (arg_alpha_palette->pixfmt != PIXFORMAT_GRAYSCALE) {
+            mp_raise_msg(&mp_type_ValueError,
+                    MP_ERROR_TEXT("Alpha palette must be GRAYSCALE!"));
+        }
+
+        if ((arg_alpha_palette->w * arg_alpha_palette->h) != 256) {
+            mp_raise_msg(&mp_type_ValueError,
+                    MP_ERROR_TEXT("Alpha palette must be 256 pixels!"));
+        }
+
+        default_alpha_palette = (uint8_t *) arg_alpha_palette->data;
+    }
+
+    return default_alpha_palette;
+}

+ 63 - 0
project_0/extmods/k210/py_helper.h

@@ -0,0 +1,63 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Python helper functions.
+ */
+#ifndef __PY_HELPER_H__
+#define __PY_HELPER_H__
+#include "imlib.h"
+extern const mp_obj_fun_builtin_var_t py_func_unavailable_obj;
+image_t *py_helper_arg_to_image_mutable(const mp_obj_t arg);
+image_t *py_helper_arg_to_image_not_compressed(const mp_obj_t arg);
+image_t *py_helper_arg_to_image_grayscale(const mp_obj_t arg);
+image_t *py_helper_keyword_to_image_mutable(uint n_args, const mp_obj_t *args, uint arg_index,
+                                            mp_map_t *kw_args, mp_obj_t kw, image_t *default_val);
+image_t *py_helper_keyword_to_image_mutable_mask(uint n_args, const mp_obj_t *args, uint arg_index,
+                                                 mp_map_t *kw_args);
+image_t *py_helper_keyword_to_image_mutable_color_palette(uint n_args, const mp_obj_t *args, uint arg_index,
+                                                          mp_map_t *kw_args);
+image_t *py_helper_keyword_to_image_mutable_alpha_palette(uint n_args, const mp_obj_t *args, uint arg_index,
+                                                          mp_map_t *kw_args);
+// void py_helper_keyword_rectangle(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index,
+//                                  mp_map_t *kw_args, mp_obj_t kw, rectangle_t *r);
+// void py_helper_keyword_rectangle_roi(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index,
+//                                      mp_map_t *kw_args, rectangle_t *r);
+int py_helper_keyword_int(uint n_args, const mp_obj_t *args, uint arg_index,
+                          mp_map_t *kw_args, mp_obj_t kw, int default_val);
+bool py_helper_keyword_int_maybe(uint n_args, const mp_obj_t *args, uint arg_index,
+                                 mp_map_t *kw_args, mp_obj_t kw, int* value);
+float py_helper_keyword_float(uint n_args, const mp_obj_t *args, uint arg_index,
+                              mp_map_t *kw_args, mp_obj_t kw, float default_val);
+bool py_helper_keyword_float_maybe(uint n_args, const mp_obj_t *args, uint arg_index,
+                                   mp_map_t *kw_args, mp_obj_t kw, float* value);
+void py_helper_keyword_int_array(uint n_args, const mp_obj_t *args, uint arg_index,
+                                 mp_map_t *kw_args, mp_obj_t kw, int *x, int size);
+void py_helper_keyword_float_array(uint n_args, const mp_obj_t *args, uint arg_index,
+                                   mp_map_t *kw_args, mp_obj_t kw, float *x, int size);
+float *py_helper_keyword_corner_array(uint n_args, const mp_obj_t *args, uint arg_index,
+                                      mp_map_t *kw_args, mp_obj_t kw);
+mp_obj_t *py_helper_keyword_iterable(uint n_args, const mp_obj_t *args, uint arg_index,
+                                        mp_map_t *kw_args, mp_obj_t kw, size_t *len);
+uint py_helper_consume_array(uint n_args, const mp_obj_t *args, uint arg_index, size_t len, const mp_obj_t **items);
+int py_helper_keyword_color(image_t *img, uint n_args, const mp_obj_t *args, uint arg_index,
+                            mp_map_t *kw_args, int default_val);
+// void py_helper_arg_to_thresholds(const mp_obj_t arg, list_t *thresholds);
+// void py_helper_keyword_thresholds(uint n_args, const mp_obj_t *args, uint arg_index,
+//                                   mp_map_t *kw_args, list_t *thresholds);
+int py_helper_arg_to_ksize(const mp_obj_t arg);
+int py_helper_ksize_to_n(int ksize);
+mp_obj_t py_helper_keyword_object(uint n_args, const mp_obj_t *args,
+        uint arg_index, mp_map_t *kw_args, mp_obj_t kw, mp_obj_t default_val);
+const uint16_t *py_helper_keyword_color_palette(uint n_args, const mp_obj_t *args,
+        uint arg_index, mp_map_t *kw_args, const uint16_t *default_color_palette);
+const uint8_t *py_helper_keyword_alpha_palette(uint n_args, const mp_obj_t *args,
+        uint arg_index, mp_map_t *kw_args, const uint8_t *default_alpha_palette);
+bool py_helper_is_equal_to_framebuffer(image_t *img);
+void py_helper_update_framebuffer(image_t *img);
+void py_helper_set_to_framebuffer(image_t *img);
+#endif // __PY_HELPER__

+ 425 - 0
project_0/extmods/k210/py_image.c

@@ -0,0 +1,425 @@
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/objarray.h"
+#include "py/binary.h"
+
+#if (defined(EXTMODS_K210_DVP))
+#include "py_image.h"
+#include "rt_ai_img.h"
+#include <drv_lcd.h>
+#include "imlib.h"
+#include "py_assert.h"
+typedef struct
+{
+    mp_obj_base_t base;
+    image_t _cobj;
+} py_image_obj_t;
+
+const mp_obj_type_t py_image_type;
+
+mp_obj_t py_image(int w, int h, pixformat_t pixfmt, uint32_t size, void *pixels)
+{
+    py_image_obj_t *o = m_new_obj(py_image_obj_t);
+    o->base.type = &py_image_type;
+    o->_cobj.w = w;
+    o->_cobj.h = h;
+    o->_cobj.size = size;
+    o->_cobj.pixfmt = pixfmt;
+    o->_cobj.pixels = pixels;
+    return o;
+}
+
+void *py_image_cobj(mp_obj_t img_obj)
+{
+    PY_ASSERT_TYPE(img_obj, &py_image_type);
+    return &((py_image_obj_t *)img_obj)->_cobj;
+}
+
+
+static mp_obj_t py_image_show(mp_obj_t self)
+{
+    image_t *p = py_image_cobj(self);
+
+    if (p->pixels)
+    {
+        lcd_show_image(0, 0, p->h, p->w, p->pixels);
+    }
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_show_obj, py_image_show);
+
+static mp_obj_t py_image_width(mp_obj_t img_obj)
+{
+    return mp_obj_new_int(((image_t *)py_image_cobj(img_obj))->w);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_width_obj, py_image_width);
+
+static mp_obj_t py_image_height(mp_obj_t img_obj)
+{
+    return mp_obj_new_int(((image_t *)py_image_cobj(img_obj))->h);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_height_obj, py_image_height);
+
+static mp_obj_t py_image_format(mp_obj_t img_obj)
+{
+    switch (((image_t *)py_image_cobj(img_obj))->bpp)
+    {
+    case PIXFORMAT_INVALID:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_INVALID", 18 - 1);
+    case PIXFORMAT_BINARY:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_BINARY", 17 - 1);
+    case PIXFORMAT_GRAYSCALE:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_GRAYSCALE", 20 - 1);
+    case PIXFORMAT_RGB565:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_RGB565", 17 - 1);
+    case PIXFORMAT_YUV422:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_YUV422", 17 - 1);
+    case PIXFORMAT_BAYER:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_BAYER", 16 - 1);
+    case PIXFORMAT_RGB888_HWC:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_RGB888_HWC", 21 - 1);
+    case PIXFORMAT_RGB888_CHW:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_RGB888_CHW", 21 - 1);
+    default:
+        return mp_obj_new_str_via_qstr("PIXFORMAT_JPEG", 15 - 1);
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format);
+
+static mp_obj_t py_image_size(mp_obj_t img_obj)
+{
+    return mp_obj_new_int(image_size((image_t *) py_image_cobj(img_obj)));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_size_obj, py_image_size);
+
+static mp_obj_t py_image_bytearray(mp_obj_t img_obj)
+{
+    image_t *arg_img = (image_t *) py_image_cobj(img_obj);
+    return mp_obj_new_bytearray_by_ref(image_size(arg_img), arg_img->data);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_bytearray_obj, py_image_bytearray);
+
+STATIC mp_obj_t py_image_get_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
+
+    const mp_obj_t *arg_vec;
+    uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
+    int arg_x = mp_obj_get_int(arg_vec[0]);
+    int arg_y = mp_obj_get_int(arg_vec[1]);
+
+    bool arg_rgbtuple = py_helper_keyword_int(n_args, args, offset, kw_args,
+            MP_OBJ_NEW_QSTR(MP_QSTR_rgbtuple), arg_img->pixfmt == PIXFORMAT_RGB565);
+
+    if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) {
+        return mp_const_none;
+    }
+
+    switch (arg_img->pixfmt) {
+        case PIXFORMAT_BINARY: {
+            if (arg_rgbtuple) {
+                int pixel = IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y);
+                mp_obj_t pixel_tuple[3];
+                pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_BINARY_TO_RGB565(pixel)));
+                pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_BINARY_TO_RGB565(pixel)));
+                pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_BINARY_TO_RGB565(pixel)));
+                return mp_obj_new_tuple(3, pixel_tuple);
+            } else {
+                return mp_obj_new_int(IMAGE_GET_BINARY_PIXEL(arg_img, arg_x, arg_y));
+            }
+        }
+        case PIXFORMAT_GRAYSCALE: {
+            if (arg_rgbtuple) {
+                int pixel = IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y);
+                mp_obj_t pixel_tuple[3];
+                pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
+                pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
+                pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(COLOR_GRAYSCALE_TO_RGB565(pixel)));
+                return mp_obj_new_tuple(3, pixel_tuple);
+            } else {
+                return mp_obj_new_int(IMAGE_GET_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y));
+            }
+        }
+        case PIXFORMAT_RGB565: {
+            if (arg_rgbtuple) {
+                int pixel = IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y);
+                mp_obj_t pixel_tuple[3];
+                pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(pixel));
+                pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(pixel));
+                pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(pixel));
+                return mp_obj_new_tuple(3, pixel_tuple);
+            } else {
+                return mp_obj_new_int(IMAGE_GET_RGB565_PIXEL(arg_img, arg_x, arg_y));
+            }
+        }
+        case PIXFORMAT_BAYER_ANY:
+            if (arg_rgbtuple) {
+                uint16_t pixel; imlib_debayer_line(arg_x, arg_x + 1, arg_y, &pixel, PIXFORMAT_RGB565, arg_img);
+                mp_obj_t pixel_tuple[3];
+                pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(pixel));
+                pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(pixel));
+                pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(pixel));
+                return mp_obj_new_tuple(3, pixel_tuple);
+            } else {
+                return mp_obj_new_int(IMAGE_GET_BAYER_PIXEL(arg_img, arg_x, arg_y));
+            }
+        case PIXFORMAT_YUV_ANY:
+            if (arg_rgbtuple) {
+                uint16_t pixel; imlib_deyuv_line(arg_x, arg_x + 1, arg_y, &pixel, PIXFORMAT_RGB565, arg_img);
+                mp_obj_t pixel_tuple[3];
+                pixel_tuple[0] = mp_obj_new_int(COLOR_RGB565_TO_R8(pixel));
+                pixel_tuple[1] = mp_obj_new_int(COLOR_RGB565_TO_G8(pixel));
+                pixel_tuple[2] = mp_obj_new_int(COLOR_RGB565_TO_B8(pixel));
+                return mp_obj_new_tuple(3, pixel_tuple);
+            } else {
+                return mp_obj_new_int(IMAGE_GET_YUV_PIXEL(arg_img, arg_x, arg_y));
+            }
+        default: return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_get_pixel_obj, 2, py_image_get_pixel);
+
+STATIC mp_obj_t py_image_set_pixel(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
+{
+    image_t *arg_img = py_helper_arg_to_image_not_compressed(args[0]);
+
+    const mp_obj_t *arg_vec;
+    uint offset = py_helper_consume_array(n_args, args, 1, 2, &arg_vec);
+    int arg_x = mp_obj_get_int(arg_vec[0]);
+    int arg_y = mp_obj_get_int(arg_vec[1]);
+
+    int arg_c =
+        py_helper_keyword_color(arg_img, n_args, args, offset, kw_args, -1); // White.
+
+    if ((!IM_X_INSIDE(arg_img, arg_x)) || (!IM_Y_INSIDE(arg_img, arg_y))) {
+        return args[0];
+    }
+
+    switch (arg_img->pixfmt) {
+        case PIXFORMAT_BINARY: {
+            IMAGE_PUT_BINARY_PIXEL(arg_img, arg_x, arg_y, arg_c);
+            return args[0];
+        }
+        case PIXFORMAT_GRAYSCALE:
+        case PIXFORMAT_BAYER_ANY: { // re-use
+            IMAGE_PUT_GRAYSCALE_PIXEL(arg_img, arg_x, arg_y, arg_c);
+            return args[0];
+        }
+        case PIXFORMAT_RGB565:
+        case PIXFORMAT_YUV_ANY: { // re-use
+            IMAGE_PUT_RGB565_PIXEL(arg_img, arg_x, arg_y, arg_c);
+            return args[0];
+        }
+        default: return args[0];
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_set_pixel_obj, 2, py_image_set_pixel);
+
+static mp_obj_t py_to_rgb565(mp_obj_t img_obj)
+{
+    image_t *ori = py_image_cobj(img_obj);
+    if(ori->pixfmt==PIXFORMAT_RGB565){return img_obj;}
+    if((ori->pixfmt==PIXFORMAT_GRAYSCALE)
+    || (ori->pixfmt==PIXFORMAT_RGB888_CHW)
+    || (ori->pixfmt==PIXFORMAT_RGB888_HWC))
+    {}else{ mp_raise_TypeError("now just support GRAYSCALER/GB888_CHW/RGB888_HWC");}
+
+    int size = ori->w * ori->h *2 ;
+    void *pix = m_malloc(size);
+    py_image_obj_t *img565_obj = py_image(ori->w, ori->h, PIXFORMAT_RGB565, size, pix);
+    image_t *res = py_image_cobj(img565_obj);
+    to_rgb565(ori, res);
+
+    return MP_OBJ_FROM_PTR(img565_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_to_rgb565_obj, py_to_rgb565);
+
+static mp_obj_t py_to_gray(mp_obj_t img_obj)
+{
+    image_t *ori = py_image_cobj(img_obj);
+    if(ori->pixfmt==PIXFORMAT_GRAYSCALE){return img_obj;}
+    if((ori->pixfmt==PIXFORMAT_RGB565)
+    || (ori->pixfmt==PIXFORMAT_RGB888_CHW)
+    || (ori->pixfmt==PIXFORMAT_RGB888_HWC))
+    {}else{ mp_raise_TypeError("now just support RGB565/GB888_CHW/RGB888_HWC");}
+
+    int size = ori->w * ori->h  ;
+    void *pix = m_malloc(size);
+    py_image_obj_t *img_gray_obj = py_image(ori->w, ori->h, PIXFORMAT_GRAYSCALE, size, pix);
+    image_t *res = py_image_cobj(img_gray_obj);
+    to_gray(ori, res);
+
+    return MP_OBJ_FROM_PTR(img_gray_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_to_gray_obj, py_to_gray);
+
+static mp_obj_t py_crop(size_t argc, const mp_obj_t *argv)
+{
+    enum{ARG_self_obj,
+        ARG_offset_height,
+        ARG_offset_width,
+        ARG_height,
+        ARG_width};
+
+    image_t *ori = py_image_cobj(argv[ARG_self_obj]);
+    if((ori->pixfmt==PIXFORMAT_RGB565)
+    || (ori->pixfmt==PIXFORMAT_GRAYSCALE)
+    || (ori->pixfmt==PIXFORMAT_RGB888_CHW)
+    || (ori->pixfmt==PIXFORMAT_RGB888_HWC))
+    {}else{ mp_raise_TypeError("now just support RGB565/GRAYSCALER/GB888_CHW/RGB888_HWC");}
+
+    int oh = mp_obj_get_int(argv[ARG_offset_height]);
+    int ow = mp_obj_get_int(argv[ARG_offset_width]);
+    int res_h = mp_obj_get_int(argv[ARG_height]);
+    int res_w = mp_obj_get_int(argv[ARG_width]);
+
+    int size = res_h * res_w * (ori->bpp) ;
+    void *pix = m_malloc(size);
+    py_image_obj_t *res_obj = py_image(res_w, res_h, ori->pixfmt, size, pix);
+    image_t *res = py_image_cobj(res_obj);
+    crop(ori, res, oh, ow);;
+    return MP_OBJ_FROM_PTR(res_obj);
+}
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_crop_obj, 5, 5, py_crop);
+
+static mp_obj_t py_resize(const mp_obj_t self, const mp_obj_t obj_w, const mp_obj_t obj_h)
+{
+    image_t *ori = py_image_cobj(self);
+    if((ori->pixfmt==PIXFORMAT_RGB565)
+    || (ori->pixfmt==PIXFORMAT_GRAYSCALE)
+    || (ori->pixfmt==PIXFORMAT_RGB888_CHW)
+    || (ori->pixfmt==PIXFORMAT_RGB888_HWC))
+    {}else{ mp_raise_TypeError("now just support RGB565/GRAYSCALER/GB888_CHW/RGB888_HWC");}
+
+    int res_w = mp_obj_get_int(obj_w);
+    int res_h = mp_obj_get_int(obj_h);
+
+    int size = res_w * res_h * (ori->bpp) ;
+    void *pix = m_malloc(size);
+    py_image_obj_t *res_obj = py_image(res_w, res_h, ori->pixfmt, size, pix);
+    image_t *res = py_image_cobj(res_obj);
+    resize_bilinera_interpolation(ori, res);
+    return MP_OBJ_FROM_PTR(res_obj);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(py_resize_obj, py_resize);
+
+STATIC mp_obj_t make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
+{
+    mp_arg_check_num(n_args, n_kw, 0, 4, true);
+    mp_obj_type_t *img_obj;
+    if (n_args == 0)
+    {
+        img_obj = py_image(0, 0, 0, 0, 0);
+    }
+    else if (n_args == 4)
+    {
+        mp_buffer_info_t bufinfo;
+        if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)){
+            int w = mp_obj_get_int(args[2]);
+            int h = mp_obj_get_int(args[3]);
+            int pixfmt = mp_obj_get_int(args[1]);
+
+            img_obj = py_image(w, h, (pixformat_t)pixfmt, bufinfo.len, bufinfo.buf);
+        }else{mp_raise_ValueError("get image fail!");}
+        
+    }
+    else
+    {
+        mp_raise_TypeError("use: (data, pixformat, w, h)");
+    }
+
+    return MP_OBJ_FROM_PTR(img_obj);
+}
+
+STATIC const mp_rom_map_elem_t locals_dict_table[] =
+    {
+        {MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&py_image_show_obj)},
+
+        /* Basic Methods */
+        {MP_ROM_QSTR(MP_QSTR_width),    MP_ROM_PTR(&py_image_width_obj)},
+        {MP_ROM_QSTR(MP_QSTR_height),   MP_ROM_PTR(&py_image_height_obj)},
+        {MP_ROM_QSTR(MP_QSTR_format),   MP_ROM_PTR(&py_image_format_obj)},
+        {MP_ROM_QSTR(MP_QSTR_size),        MP_ROM_PTR(&py_image_size_obj)},
+        {MP_ROM_QSTR(MP_QSTR_bytearray),   MP_ROM_PTR(&py_image_bytearray_obj)},
+        {MP_ROM_QSTR(MP_QSTR_get_pixel),   MP_ROM_PTR(&py_image_get_pixel_obj)},
+        {MP_ROM_QSTR(MP_QSTR_set_pixel),   MP_ROM_PTR(&py_image_set_pixel_obj)},
+        {MP_ROM_QSTR(MP_QSTR_to_rgb565),   MP_ROM_PTR(&py_to_rgb565_obj)},
+
+        {MP_ROM_QSTR(MP_QSTR_to_gray),   MP_ROM_PTR(&py_to_gray_obj)},
+
+        {MP_ROM_QSTR(MP_QSTR_resize),      MP_ROM_PTR(&py_resize_obj)},
+        {MP_ROM_QSTR(MP_QSTR_crop),        MP_ROM_PTR(&py_crop_obj)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_INVALID),    MP_ROM_INT(PIXFORMAT_INVALID)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_BINARY),     MP_ROM_INT(PIXFORMAT_BINARY)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_GRAYSCALE),  MP_ROM_INT(PIXFORMAT_GRAYSCALE)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_RGB565),     MP_ROM_INT(PIXFORMAT_RGB565)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_YUV422),     MP_ROM_INT(PIXFORMAT_YUV422)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_BAYER),      MP_ROM_INT(PIXFORMAT_BAYER)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_RGB888_HWC), MP_ROM_INT(PIXFORMAT_RGB888_HWC)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_RGB888_CHW), MP_ROM_INT(PIXFORMAT_RGB888_CHW)},
+        {MP_ROM_QSTR(MP_QSTR_PIXFORMAT_JPEG),       MP_ROM_INT(PIXFORMAT_JPEG)},
+};
+STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table);
+
+static void py_image_print(const mp_print_t *print, mp_obj_t self, mp_print_kind_t kind)
+{
+    image_t *image = py_image_cobj(self);
+    if (image->pixfmt == PIXFORMAT_JPEG
+            && image->pixels[0] == 0xFE
+            && image->pixels[image->size-1] == 0xFE) {
+        // print for ide.
+        print->print_strn(print->data, (const char *) image->pixels, image->size);
+    } else {
+        mp_printf(print, "{\"w\":%d, \"h\":%d, \"type\":\"%s\", \"size\":%d}",
+                image->w,
+                image->h,
+                (image->pixfmt == PIXFORMAT_BINARY)     ? "binary" :
+                (image->pixfmt == PIXFORMAT_GRAYSCALE)  ? "grayscale" :
+                (image->pixfmt == PIXFORMAT_RGB565)     ? "rgb565" :
+                (image->pixfmt == PIXFORMAT_BAYER_BGGR) ? "bayer_bggr" :
+                (image->pixfmt == PIXFORMAT_BAYER_GBRG) ? "bayer_gbrg" :
+                (image->pixfmt == PIXFORMAT_BAYER_GRBG) ? "bayer_grbg" :
+                (image->pixfmt == PIXFORMAT_BAYER_RGGB) ? "bayer_rggb" :
+                (image->pixfmt == PIXFORMAT_YUV422)     ? "yuv422" :
+                (image->pixfmt == PIXFORMAT_YVU422)     ? "yvu422" :
+                (image->pixfmt == PIXFORMAT_JPEG)       ? "jpeg" : 
+                (image->pixfmt == PIXFORMAT_RGB888_HWC) ? "rgb888_hwc" :
+                (image->pixfmt == PIXFORMAT_RGB888_CHW) ? "rgb888_chw" : "unknown",
+                image_size(image));
+    }
+}
+
+STATIC mp_int_t py_image_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags)
+{
+    py_image_obj_t *image_obj = (py_image_obj_t *)obj;
+    image_t *pic = py_image_cobj(image_obj);
+    switch (flags)
+    {
+    case MP_BUFFER_READ:
+        bufinfo->buf = pic->pixels;
+        bufinfo->len = pic->w * pic->h * (pic->bpp);
+        bufinfo->typecode = 'b';
+        break;
+    case MP_BUFFER_WRITE:
+        image_obj->_cobj.pixels = bufinfo->buf;
+        break;
+    case MP_BUFFER_RW:
+        /* code */
+        break;
+    default:
+        break;
+    }
+    return 0;
+}
+
+const mp_obj_type_t py_image_type =
+    {
+        {&mp_type_type},
+        .name = MP_QSTR_Image,
+        .print = py_image_print,
+        .make_new = make_new,
+        .locals_dict = (mp_obj_t)&locals_dict,
+        .buffer_p = {.get_buffer = py_image_get_buffer}};
+#endif

+ 36 - 0
project_0/extmods/k210/py_image.h

@@ -0,0 +1,36 @@
+#ifndef __PY_IMAGE_H
+#define __PY_IMAGE_H
+
+#include <stdint.h>
+#include "imlib.h"
+
+// typedef enum 
+// {
+//     PIXFORMAT_INVALID = 0,
+//     PIXFORMAT_BINARY,    // 1BPP/BINARY
+//     PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
+//     PIXFORMAT_RGB565,    // 2BPP/RGB565
+//     PIXFORMAT_YUV422,    // 2BPP/YUV422
+//     PIXFORMAT_BAYER,     // 1BPP/RAW
+//     PIXFORMAT_RGB888_HWC,
+//     PIXFORMAT_RGB888_CHW,
+//     PIXFORMAT_JPEG,      // JPEG/COMPRESSED
+// } pixformat_t;
+
+// typedef struct image 
+// {
+//     int w;
+//     int h;
+//     int bpp;
+//     union 
+//     {
+//         uint8_t *pixels;
+//         uint8_t *data;
+//     };
+//     void *ai;
+// } image_t;
+
+mp_obj_t py_image(int w, int h, pixformat_t pixfmt, uint32_t size, void *pixels);
+void *py_image_cobj(mp_obj_t img_obj);
+
+#endif

+ 39 - 0
project_0/extmods/k210/py_lcdctl.c

@@ -0,0 +1,39 @@
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/objarray.h"
+#include "py/binary.h"
+
+#ifdef EXTMODS_K210_LCDCTL
+#include <drv_lcd.h>
+
+static mp_obj_t py_lcdctl_set_direction(mp_obj_t dir_obj)
+{
+    int dir = mp_obj_get_int(dir_obj);
+
+    lcd_set_direction((lcd_dir_t)dir);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_lcdctl_set_direction_obj, py_lcdctl_set_direction);
+
+STATIC const mp_rom_map_elem_t lcdctl_locals_dict_table[] = {
+    {MP_ROM_QSTR(MP_QSTR_set_direction), MP_ROM_PTR(&py_lcdctl_set_direction_obj)},
+    {MP_ROM_QSTR(MP_QSTR_XY_RLUD), MP_ROM_INT(DIR_XY_RLUD)},
+    {MP_ROM_QSTR(MP_QSTR_YX_RLUD), MP_ROM_INT(DIR_YX_RLUD)},
+    {MP_ROM_QSTR(MP_QSTR_XY_LRUD), MP_ROM_INT(DIR_XY_LRUD)},
+    {MP_ROM_QSTR(MP_QSTR_YX_LRUD), MP_ROM_INT(DIR_YX_LRUD)},
+    {MP_ROM_QSTR(MP_QSTR_XY_RLDU), MP_ROM_INT(DIR_XY_RLDU)},
+    {MP_ROM_QSTR(MP_QSTR_YX_RLDU), MP_ROM_INT(DIR_YX_RLDU)},
+    {MP_ROM_QSTR(MP_QSTR_XY_LRDU), MP_ROM_INT(DIR_XY_LRDU)},
+    {MP_ROM_QSTR(MP_QSTR_YX_LRDU), MP_ROM_INT(DIR_YX_LRDU)},
+
+};
+STATIC MP_DEFINE_CONST_DICT(k210_lcdctl_dict, lcdctl_locals_dict_table);
+
+const mp_obj_type_t k210_lcdctl_type = {
+    {&mp_type_type},
+    .name = MP_QSTR_lcdctl,
+    .locals_dict = (mp_obj_dict_t *)&k210_lcdctl_dict,
+};
+#endif

+ 70 - 0
project_0/extmods/k210/py_sha256.c

@@ -0,0 +1,70 @@
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "py/objarray.h"
+#include "py/binary.h"
+
+#ifdef EXTMODS_K210_SHA256
+#include "sha256.h"
+
+typedef struct 
+{
+    mp_obj_base_t base;
+    sha256_context_t ctx;
+} k210_hash_obj_t;
+
+const mp_obj_type_t k210_sha256_type;
+
+STATIC mp_obj_t k210_sha256_update(mp_obj_t self_in, mp_obj_t arg) 
+{
+    k210_hash_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    mp_buffer_info_t bufinfo;
+
+    mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+    sha256_update(&self->ctx, bufinfo.buf, bufinfo.len);
+
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(k210_sha256_update_obj, k210_sha256_update);
+
+STATIC mp_obj_t k210_sha256_digest(mp_obj_t self_in) 
+{
+    k210_hash_obj_t *self = MP_OBJ_TO_PTR(self_in);
+    vstr_t vstr;
+
+    vstr_init_len(&vstr, SHA256_HASH_LEN);
+    sha256_final(&self->ctx, (byte*)vstr.buf);
+
+    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(k210_sha256_digest_obj, k210_sha256_digest);
+
+STATIC mp_obj_t make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) 
+{
+    mp_arg_check_num(n_args, n_kw, 1, 1, false);
+    mp_int_t len = mp_obj_get_int(args[0]);
+    k210_hash_obj_t *o = m_new_obj(k210_hash_obj_t);
+    o->base.type = &k210_sha256_type;
+
+    //mp_printf(&mp_plat_print, "input len %d\n", len);
+    sha256_init(&o->ctx, len);
+
+    return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC const mp_rom_map_elem_t locals_dict_table[] = 
+{
+    {MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&k210_sha256_update_obj)},
+    {MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&k210_sha256_digest_obj)},
+
+};
+STATIC MP_DEFINE_CONST_DICT(locals_dict, locals_dict_table);
+
+const mp_obj_type_t k210_sha256_type = 
+{
+    .base = { &mp_type_type },
+    .name = MP_QSTR_sha256,
+    .make_new = make_new,
+    .locals_dict = (void*)&locals_dict,
+};
+#endif

+ 40 - 0
project_0/extmods/k210/qstrdefscam.h

@@ -0,0 +1,40 @@
+#if (defined(EXTMODS_K210_DVP))
+QDEF(MP_QSTR_camera, (const byte*)"\xdc\x06" "camera")
+QDEF(MP_QSTR_set_pixformat, (const byte*)"\x3a\x0d" "set_pixformat")        
+QDEF(MP_QSTR_get_pixformat, (const byte*)"\x2e\x0d" "get_pixformat")        
+QDEF(MP_QSTR_set_framesize, (const byte*)"\x20\x0d" "set_framesize")        
+QDEF(MP_QSTR_get_framesize, (const byte*)"\x34\x0d" "get_framesize")        
+
+
+// Image
+QDEF(MP_QSTR_image, (const byte*)"\x42\x05" "image")
+QDEF(MP_QSTR_Image, (const byte*)"\x62\x05" "Image")
+QDEF(MP_QSTR_width, (const byte*)"\x23\x05" "width")
+QDEF(MP_QSTR_height, (const byte*)"\xfa\x06" "height")
+QDEF(MP_QSTR_resize, (const byte*)"\xb7\x06" "resize")
+QDEF(MP_QSTR_crop, (const byte*)"\x0b\x04" "crop")
+QDEF(MP_QSTR_PIXFORMAT_JPEG, (const byte*)"\xe0\x0e" "PIXFORMAT_JPEG")
+QDEF(MP_QSTR_PIXFORMAT_BINARY, (const byte*)"\x97\x10" "PIXFORMAT_BINARY")
+QDEF(MP_QSTR_PIXFORMAT_RGB888_HWC, (const byte*)"\xf4\x14" "PIXFORMAT_RGB888_HWC")
+QDEF(MP_QSTR_PIXFORMAT_YUV422, (const byte*)"\xd6\x10" "PIXFORMAT_YUV422")
+QDEF(MP_QSTR_PIXFORMAT_RGB888_CHW, (const byte*)"\x54\x14" "PIXFORMAT_RGB888_CHW")
+QDEF(MP_QSTR_PIXFORMAT_BAYER, (const byte*)"\x15\x0f" "PIXFORMAT_BAYER")
+QDEF(MP_QSTR_PIXFORMAT_INVALID, (const byte*)"\x89\x11" "PIXFORMAT_INVALID")
+QDEF(MP_QSTR_PIXFORMAT_GRAYSCALE, (const byte*)"\x4d\x13" "PIXFORMAT_GRAYSCALE")
+QDEF(MP_QSTR_PIXFORMAT_RGB565, (const byte*)"\x79\x10" "PIXFORMAT_RGB565")
+QDEF(MP_QSTR_mask, (const byte*)"\x91\x04" "mask")
+QDEF(MP_QSTR_color_palette, (const byte*)"\x1a\x0d" "color_palette")        
+QDEF(MP_QSTR_alpha_palette, (const byte*)"\x93\x0d" "alpha_palette")        
+QDEF(MP_QSTR_roi, (const byte*)"\xb1\x03" "roi")
+QDEF(MP_QSTR_color, (const byte*)"\xd8\x05" "color")
+QDEF(MP_QSTR_thresholds, (const byte*)"\x41\x0a" "thresholds")     
+QDEF(MP_QSTR_snapshot, (const byte*)"\x49\x08" "snapshot")
+// QDEF(MP_QSTR_sw, (const byte*)"\xe1\x02" "sw")
+QDEF(MP_QSTR_RGB565, (const byte*)"\x64\x06" "RGB565")
+QDEF(MP_QSTR_YUV422, (const byte*)"\x0b\x06" "YUV422")
+QDEF(MP_QSTR_set_pixel, (const byte*)"\xb0\x09" "set_pixel")
+QDEF(MP_QSTR_get_pixel, (const byte*)"\xa4\x09" "get_pixel")
+QDEF(MP_QSTR_rgbtuple, (const byte*)"\x6a\x08" "rgbtuple")
+QDEF(MP_QSTR_to_rgb565, (const byte*)"\x80\x09" "to_rgb565")
+QDEF(MP_QSTR_to_gray, (const byte*)"\x4c\x07" "to_gray")
+#endif

+ 277 - 0
project_0/extmods/k210/qstrdefsk210.h

@@ -0,0 +1,277 @@
+QDEF(MP_QSTR_k210, (const byte*)"\x9d\x04" "k210")
+QDEF(MP_QSTR_FFT, (const byte*)"\xf1\x03" "FFT")
+QDEF(MP_QSTR_run, (const byte*)"\x6c\x03" "run")
+//QDEF(MP_QSTR_input, (const byte*)"\x73\x05" "input")
+QDEF(MP_QSTR_shift, (const byte*)"\x85\x05" "shift")
+QDEF(MP_QSTR_direction, (const byte*)"\x20\x09" "direction")
+QDEF(MP_QSTR_DIR_BACKWARD, (const byte*)"\x0e\x0c" "DIR_BACKWARD")
+QDEF(MP_QSTR_DIR_FORWARD, (const byte*)"\x7e\x0b" "DIR_FORWARD")
+
+QDEF(MP_QSTR_I2S, (const byte*)"\x4d\x03" "I2S")
+QDEF(MP_QSTR_play, (const byte*)"\x21\x04" "play")
+QDEF(MP_QSTR_device, (const byte*)"\x3d\x06" "device")
+QDEF(MP_QSTR_workmode, (const byte*)"\x07\x08" "workmode")
+QDEF(MP_QSTR_sample_rate, (const byte*)"\x7e\x0b" "sample_rate")
+QDEF(MP_QSTR_bps, (const byte*)"\xc4\x03" "bps")
+QDEF(MP_QSTR_track_num, (const byte*)"\xc3\x09" "track_num")
+QDEF(MP_QSTR_set_param, (const byte*)"\x37\x09" "set_param")
+QDEF(MP_QSTR_TRANSMITTER, (const byte*)"\x2c\x0b" "TRANSMITTER")
+QDEF(MP_QSTR_RECEIVER, (const byte*)"\x3c\x08" "RECEIVER")
+QDEF(MP_QSTR_record, (const byte*)"\x28\x06" "record")
+
+QDEF(MP_QSTR_FPIOA, (const byte*)"\x94\x05" "FPIOA")
+QDEF(MP_QSTR_set_function, (const byte*)"\xba\x0c" "set_function")
+//QDEF(MP_QSTR_pin, (const byte*)"\xf2\x03" "pin")
+//QDEF(MP_QSTR_func, (const byte*)"\x1b\x04" "func")
+QDEF(MP_QSTR_set_sl, (const byte*)"\xe7\x06" "set_sl")
+QDEF(MP_QSTR_set_st, (const byte*)"\xff\x06" "set_st")
+QDEF(MP_QSTR_set_io_driving, (const byte*)"\x68\x0e" "set_io_driving")
+QDEF(MP_QSTR_get_io_by_function, (const byte*)"\x93\x12" "get_io_by_function")
+
+QDEF(MP_QSTR_JTAG_TCLK, (const byte*)"\xd2\x09" "JTAG_TCLK")
+QDEF(MP_QSTR_JTAG_TDI, (const byte*)"\x9b\x08" "JTAG_TDI")
+QDEF(MP_QSTR_JTAG_TMS, (const byte*)"\xa8\x08" "JTAG_TMS")
+QDEF(MP_QSTR_JTAG_TDO, (const byte*)"\x9d\x08" "JTAG_TDO")
+QDEF(MP_QSTR_SPI0_D0, (const byte*)"\x74\x07" "SPI0_D0")
+QDEF(MP_QSTR_SPI0_D1, (const byte*)"\x75\x07" "SPI0_D1")
+QDEF(MP_QSTR_SPI0_D2, (const byte*)"\x76\x07" "SPI0_D2")
+QDEF(MP_QSTR_SPI0_D3, (const byte*)"\x77\x07" "SPI0_D3")
+QDEF(MP_QSTR_SPI0_D4, (const byte*)"\x70\x07" "SPI0_D4")
+QDEF(MP_QSTR_SPI0_D5, (const byte*)"\x71\x07" "SPI0_D5")
+QDEF(MP_QSTR_SPI0_D6, (const byte*)"\x72\x07" "SPI0_D6")
+QDEF(MP_QSTR_SPI0_D7, (const byte*)"\x73\x07" "SPI0_D7")
+QDEF(MP_QSTR_SPI0_SS0, (const byte*)"\x50\x08" "SPI0_SS0")
+QDEF(MP_QSTR_SPI0_SS1, (const byte*)"\x51\x08" "SPI0_SS1")
+QDEF(MP_QSTR_SPI0_SS2, (const byte*)"\x52\x08" "SPI0_SS2")
+QDEF(MP_QSTR_SPI0_SS3, (const byte*)"\x53\x08" "SPI0_SS3")
+QDEF(MP_QSTR_SPI0_ARB, (const byte*)"\x51\x08" "SPI0_ARB")
+QDEF(MP_QSTR_SPI0_SCLK, (const byte*)"\xf7\x09" "SPI0_SCLK")
+QDEF(MP_QSTR_UARTHS_RX, (const byte*)"\xb9\x09" "UARTHS_RX")
+QDEF(MP_QSTR_UARTHS_TX, (const byte*)"\xff\x09" "UARTHS_TX")
+QDEF(MP_QSTR_CLK_SPI1, (const byte*)"\x25\x08" "CLK_SPI1")
+QDEF(MP_QSTR_CLK_I2C1, (const byte*)"\x17\x08" "CLK_I2C1")
+QDEF(MP_QSTR_GPIOHS0, (const byte*)"\xdf\x07" "GPIOHS0")
+QDEF(MP_QSTR_GPIOHS1, (const byte*)"\xde\x07" "GPIOHS1")
+QDEF(MP_QSTR_GPIOHS2, (const byte*)"\xdd\x07" "GPIOHS2")
+QDEF(MP_QSTR_GPIOHS3, (const byte*)"\xdc\x07" "GPIOHS3")
+QDEF(MP_QSTR_GPIOHS4, (const byte*)"\xdb\x07" "GPIOHS4")
+QDEF(MP_QSTR_GPIOHS5, (const byte*)"\xda\x07" "GPIOHS5")
+QDEF(MP_QSTR_GPIOHS6, (const byte*)"\xd9\x07" "GPIOHS6")
+QDEF(MP_QSTR_GPIOHS7, (const byte*)"\xd8\x07" "GPIOHS7")
+QDEF(MP_QSTR_GPIOHS8, (const byte*)"\xd7\x07" "GPIOHS8")
+QDEF(MP_QSTR_GPIOHS9, (const byte*)"\xd6\x07" "GPIOHS9")
+QDEF(MP_QSTR_GPIOHS10, (const byte*)"\xae\x08" "GPIOHS10")
+QDEF(MP_QSTR_GPIOHS11, (const byte*)"\xaf\x08" "GPIOHS11")
+QDEF(MP_QSTR_GPIOHS12, (const byte*)"\xac\x08" "GPIOHS12")
+QDEF(MP_QSTR_GPIOHS13, (const byte*)"\xad\x08" "GPIOHS13")
+QDEF(MP_QSTR_GPIOHS14, (const byte*)"\xaa\x08" "GPIOHS14")
+QDEF(MP_QSTR_GPIOHS15, (const byte*)"\xab\x08" "GPIOHS15")
+QDEF(MP_QSTR_GPIOHS16, (const byte*)"\xa8\x08" "GPIOHS16")
+QDEF(MP_QSTR_GPIOHS17, (const byte*)"\xa9\x08" "GPIOHS17")
+QDEF(MP_QSTR_GPIOHS18, (const byte*)"\xa6\x08" "GPIOHS18")
+QDEF(MP_QSTR_GPIOHS19, (const byte*)"\xa7\x08" "GPIOHS19")
+QDEF(MP_QSTR_GPIOHS20, (const byte*)"\x4d\x08" "GPIOHS20")
+QDEF(MP_QSTR_GPIOHS21, (const byte*)"\x4c\x08" "GPIOHS21")
+QDEF(MP_QSTR_GPIOHS22, (const byte*)"\x4f\x08" "GPIOHS22")
+QDEF(MP_QSTR_GPIOHS23, (const byte*)"\x4e\x08" "GPIOHS23")
+QDEF(MP_QSTR_GPIOHS24, (const byte*)"\x49\x08" "GPIOHS24")
+QDEF(MP_QSTR_GPIOHS25, (const byte*)"\x48\x08" "GPIOHS25")
+QDEF(MP_QSTR_GPIOHS26, (const byte*)"\x4b\x08" "GPIOHS26")
+QDEF(MP_QSTR_GPIOHS27, (const byte*)"\x4a\x08" "GPIOHS27")
+QDEF(MP_QSTR_GPIOHS28, (const byte*)"\x45\x08" "GPIOHS28")
+QDEF(MP_QSTR_GPIOHS29, (const byte*)"\x44\x08" "GPIOHS29")
+QDEF(MP_QSTR_GPIOHS30, (const byte*)"\x6c\x08" "GPIOHS30")
+QDEF(MP_QSTR_GPIOHS31, (const byte*)"\x6d\x08" "GPIOHS31")
+QDEF(MP_QSTR_GPIO0, (const byte*)"\xa4\x05" "GPIO0")
+QDEF(MP_QSTR_GPIO1, (const byte*)"\xa5\x05" "GPIO1")
+QDEF(MP_QSTR_GPIO2, (const byte*)"\xa6\x05" "GPIO2")
+QDEF(MP_QSTR_GPIO3, (const byte*)"\xa7\x05" "GPIO3")
+QDEF(MP_QSTR_GPIO4, (const byte*)"\xa0\x05" "GPIO4")
+QDEF(MP_QSTR_GPIO5, (const byte*)"\xa1\x05" "GPIO5")
+QDEF(MP_QSTR_GPIO6, (const byte*)"\xa2\x05" "GPIO6")
+QDEF(MP_QSTR_GPIO7, (const byte*)"\xa3\x05" "GPIO7")
+QDEF(MP_QSTR_UART1_RX, (const byte*)"\x33\x08" "UART1_RX")
+QDEF(MP_QSTR_UART1_TX, (const byte*)"\xf5\x08" "UART1_TX")
+QDEF(MP_QSTR_UART2_RX, (const byte*)"\x50\x08" "UART2_RX")
+QDEF(MP_QSTR_UART2_TX, (const byte*)"\x96\x08" "UART2_TX")
+QDEF(MP_QSTR_UART3_RX, (const byte*)"\xf1\x08" "UART3_RX")
+QDEF(MP_QSTR_UART3_TX, (const byte*)"\x37\x08" "UART3_TX")
+QDEF(MP_QSTR_SPI1_D0, (const byte*)"\xd5\x07" "SPI1_D0")
+QDEF(MP_QSTR_SPI1_D1, (const byte*)"\xd4\x07" "SPI1_D1")
+QDEF(MP_QSTR_SPI1_D2, (const byte*)"\xd7\x07" "SPI1_D2")
+QDEF(MP_QSTR_SPI1_D3, (const byte*)"\xd6\x07" "SPI1_D3")
+QDEF(MP_QSTR_SPI1_D4, (const byte*)"\xd1\x07" "SPI1_D4")
+QDEF(MP_QSTR_SPI1_D5, (const byte*)"\xd0\x07" "SPI1_D5")
+QDEF(MP_QSTR_SPI1_D6, (const byte*)"\xd3\x07" "SPI1_D6")
+QDEF(MP_QSTR_SPI1_D7, (const byte*)"\xd2\x07" "SPI1_D7")
+QDEF(MP_QSTR_SPI1_SS0, (const byte*)"\xd1\x08" "SPI1_SS0")
+QDEF(MP_QSTR_SPI1_SS1, (const byte*)"\xd0\x08" "SPI1_SS1")
+QDEF(MP_QSTR_SPI1_SS2, (const byte*)"\xd3\x08" "SPI1_SS2")
+QDEF(MP_QSTR_SPI1_SS3, (const byte*)"\xd2\x08" "SPI1_SS3")
+QDEF(MP_QSTR_SPI1_ARB, (const byte*)"\x10\x08" "SPI1_ARB")
+QDEF(MP_QSTR_SPI1_SCLK, (const byte*)"\x16\x09" "SPI1_SCLK")
+QDEF(MP_QSTR_SPI_SLAVE_D0, (const byte*)"\xd6\x0c" "SPI_SLAVE_D0")
+QDEF(MP_QSTR_SPI_SLAVE_SS, (const byte*)"\x02\x0c" "SPI_SLAVE_SS")
+QDEF(MP_QSTR_SPI_SLAVE_SCLK, (const byte*)"\x95\x0e" "SPI_SLAVE_SCLK")
+QDEF(MP_QSTR_I2S0_MCLK, (const byte*)"\xcb\x09" "I2S0_MCLK")
+QDEF(MP_QSTR_I2S0_SCLK, (const byte*)"\x95\x09" "I2S0_SCLK")
+QDEF(MP_QSTR_I2S0_WS, (const byte*)"\x86\x07" "I2S0_WS")
+QDEF(MP_QSTR_I2S0_IN_D0, (const byte*)"\xce\x0a" "I2S0_IN_D0")
+QDEF(MP_QSTR_I2S0_IN_D1, (const byte*)"\xcf\x0a" "I2S0_IN_D1")
+QDEF(MP_QSTR_I2S0_IN_D2, (const byte*)"\xcc\x0a" "I2S0_IN_D2")
+QDEF(MP_QSTR_I2S0_IN_D3, (const byte*)"\xcd\x0a" "I2S0_IN_D3")
+QDEF(MP_QSTR_I2S0_OUT_D0, (const byte*)"\x27\x0b" "I2S0_OUT_D0")
+QDEF(MP_QSTR_I2S0_OUT_D1, (const byte*)"\x26\x0b" "I2S0_OUT_D1")
+QDEF(MP_QSTR_I2S0_OUT_D2, (const byte*)"\x25\x0b" "I2S0_OUT_D2")
+QDEF(MP_QSTR_I2S0_OUT_D3, (const byte*)"\x24\x0b" "I2S0_OUT_D3")
+QDEF(MP_QSTR_I2S1_MCLK, (const byte*)"\x6a\x09" "I2S1_MCLK")
+QDEF(MP_QSTR_I2S1_SCLK, (const byte*)"\x34\x09" "I2S1_SCLK")
+QDEF(MP_QSTR_I2S1_WS, (const byte*)"\xe7\x07" "I2S1_WS")
+QDEF(MP_QSTR_I2S1_IN_D0, (const byte*)"\xcf\x0a" "I2S1_IN_D0")
+QDEF(MP_QSTR_I2S1_IN_D1, (const byte*)"\xce\x0a" "I2S1_IN_D1")
+QDEF(MP_QSTR_I2S1_IN_D2, (const byte*)"\xcd\x0a" "I2S1_IN_D2")
+QDEF(MP_QSTR_I2S1_IN_D3, (const byte*)"\xcc\x0a" "I2S1_IN_D3")
+QDEF(MP_QSTR_I2S1_OUT_D0, (const byte*)"\x46\x0b" "I2S1_OUT_D0")
+QDEF(MP_QSTR_I2S1_OUT_D1, (const byte*)"\x47\x0b" "I2S1_OUT_D1")
+QDEF(MP_QSTR_I2S1_OUT_D2, (const byte*)"\x44\x0b" "I2S1_OUT_D2")
+QDEF(MP_QSTR_I2S1_OUT_D3, (const byte*)"\x45\x0b" "I2S1_OUT_D3")
+QDEF(MP_QSTR_I2S2_MCLK, (const byte*)"\x89\x09" "I2S2_MCLK")
+QDEF(MP_QSTR_I2S2_SCLK, (const byte*)"\xd7\x09" "I2S2_SCLK")
+QDEF(MP_QSTR_I2S2_WS, (const byte*)"\xc4\x07" "I2S2_WS")
+QDEF(MP_QSTR_I2S2_IN_D0, (const byte*)"\xcc\x0a" "I2S2_IN_D0")
+QDEF(MP_QSTR_I2S2_IN_D1, (const byte*)"\xcd\x0a" "I2S2_IN_D1")
+QDEF(MP_QSTR_I2S2_IN_D2, (const byte*)"\xce\x0a" "I2S2_IN_D2")
+QDEF(MP_QSTR_I2S2_IN_D3, (const byte*)"\xcf\x0a" "I2S2_IN_D3")
+QDEF(MP_QSTR_I2S2_OUT_D0, (const byte*)"\xe5\x0b" "I2S2_OUT_D0")
+QDEF(MP_QSTR_I2S2_OUT_D1, (const byte*)"\xe4\x0b" "I2S2_OUT_D1")
+QDEF(MP_QSTR_I2S2_OUT_D2, (const byte*)"\xe7\x0b" "I2S2_OUT_D2")
+QDEF(MP_QSTR_I2S2_OUT_D3, (const byte*)"\xe6\x0b" "I2S2_OUT_D3")
+QDEF(MP_QSTR_I2C0_SCLK, (const byte*)"\x85\x09" "I2C0_SCLK")
+QDEF(MP_QSTR_I2C0_SDA, (const byte*)"\xe4\x08" "I2C0_SDA")
+QDEF(MP_QSTR_I2C1_SCLK, (const byte*)"\x24\x09" "I2C1_SCLK")
+QDEF(MP_QSTR_I2C1_SDA, (const byte*)"\xa5\x08" "I2C1_SDA")
+QDEF(MP_QSTR_I2C2_SCLK, (const byte*)"\xc7\x09" "I2C2_SCLK")
+QDEF(MP_QSTR_I2C2_SDA, (const byte*)"\x66\x08" "I2C2_SDA")
+QDEF(MP_QSTR_CMOS_XCLK, (const byte*)"\xb4\x09" "CMOS_XCLK")
+QDEF(MP_QSTR_CMOS_RST, (const byte*)"\x9d\x08" "CMOS_RST")
+QDEF(MP_QSTR_CMOS_PWDN, (const byte*)"\xa5\x09" "CMOS_PWDN")
+QDEF(MP_QSTR_CMOS_VSYNC, (const byte*)"\xd9\x0a" "CMOS_VSYNC")
+QDEF(MP_QSTR_CMOS_HREF, (const byte*)"\x11\x09" "CMOS_HREF")
+QDEF(MP_QSTR_CMOS_PCLK, (const byte*)"\xbc\x09" "CMOS_PCLK")
+QDEF(MP_QSTR_CMOS_D0, (const byte*)"\x1c\x07" "CMOS_D0")
+QDEF(MP_QSTR_CMOS_D1, (const byte*)"\x1d\x07" "CMOS_D1")
+QDEF(MP_QSTR_CMOS_D2, (const byte*)"\x1e\x07" "CMOS_D2")
+QDEF(MP_QSTR_CMOS_D3, (const byte*)"\x1f\x07" "CMOS_D3")
+QDEF(MP_QSTR_CMOS_D4, (const byte*)"\x18\x07" "CMOS_D4")
+QDEF(MP_QSTR_CMOS_D5, (const byte*)"\x19\x07" "CMOS_D5")
+QDEF(MP_QSTR_CMOS_D6, (const byte*)"\x1a\x07" "CMOS_D6")
+QDEF(MP_QSTR_CMOS_D7, (const byte*)"\x1b\x07" "CMOS_D7")
+QDEF(MP_QSTR_SCCB_SCLK, (const byte*)"\x3c\x09" "SCCB_SCLK")
+QDEF(MP_QSTR_SCCB_SDA, (const byte*)"\xbd\x08" "SCCB_SDA")
+QDEF(MP_QSTR_UART1_CTS, (const byte*)"\x9d\x09" "UART1_CTS")
+QDEF(MP_QSTR_UART1_DSR, (const byte*)"\xfc\x09" "UART1_DSR")
+QDEF(MP_QSTR_UART1_DCD, (const byte*)"\xfa\x09" "UART1_DCD")
+QDEF(MP_QSTR_UART1_RI, (const byte*)"\x22\x08" "UART1_RI")
+QDEF(MP_QSTR_UART1_SIR_IN, (const byte*)"\x29\x0c" "UART1_SIR_IN")
+QDEF(MP_QSTR_UART1_DTR, (const byte*)"\x5b\x09" "UART1_DTR")
+QDEF(MP_QSTR_UART1_RTS, (const byte*)"\x4c\x09" "UART1_RTS")
+QDEF(MP_QSTR_UART1_OUT2, (const byte*)"\xa5\x0a" "UART1_OUT2")
+QDEF(MP_QSTR_UART1_OUT1, (const byte*)"\xa6\x0a" "UART1_OUT1")
+QDEF(MP_QSTR_UART1_SIR_OUT, (const byte*)"\x20\x0d" "UART1_SIR_OUT")
+QDEF(MP_QSTR_UART1_BAUD, (const byte*)"\x4b\x0a" "UART1_BAUD")
+QDEF(MP_QSTR_UART1_RE, (const byte*)"\x2e\x08" "UART1_RE")
+QDEF(MP_QSTR_UART1_DE, (const byte*)"\xf8\x08" "UART1_DE")
+QDEF(MP_QSTR_UART1_RS485_EN, (const byte*)"\x95\x0e" "UART1_RS485_EN")
+QDEF(MP_QSTR_UART2_CTS, (const byte*)"\x5e\x09" "UART2_CTS")
+QDEF(MP_QSTR_UART2_DSR, (const byte*)"\x7f\x09" "UART2_DSR")
+QDEF(MP_QSTR_UART2_DCD, (const byte*)"\x79\x09" "UART2_DCD")
+QDEF(MP_QSTR_UART2_RI, (const byte*)"\x41\x08" "UART2_RI")
+QDEF(MP_QSTR_UART2_SIR_IN, (const byte*)"\x4a\x0c" "UART2_SIR_IN")
+QDEF(MP_QSTR_UART2_DTR, (const byte*)"\x98\x09" "UART2_DTR")
+QDEF(MP_QSTR_UART2_RTS, (const byte*)"\x8f\x09" "UART2_RTS")
+QDEF(MP_QSTR_UART2_OUT2, (const byte*)"\x06\x0a" "UART2_OUT2")
+QDEF(MP_QSTR_UART2_OUT1, (const byte*)"\x05\x0a" "UART2_OUT1")
+QDEF(MP_QSTR_UART2_SIR_OUT, (const byte*)"\x23\x0d" "UART2_SIR_OUT")
+QDEF(MP_QSTR_UART2_BAUD, (const byte*)"\xe8\x0a" "UART2_BAUD")
+QDEF(MP_QSTR_UART2_RE, (const byte*)"\x4d\x08" "UART2_RE")
+QDEF(MP_QSTR_UART2_DE, (const byte*)"\x9b\x08" "UART2_DE")
+QDEF(MP_QSTR_UART2_RS485_EN, (const byte*)"\xb6\x0e" "UART2_RS485_EN")
+QDEF(MP_QSTR_UART3_CTS, (const byte*)"\x1f\x09" "UART3_CTS")
+QDEF(MP_QSTR_UART3_DSR, (const byte*)"\xfe\x09" "UART3_DSR")
+QDEF(MP_QSTR_UART3_DCD, (const byte*)"\xf8\x09" "UART3_DCD")
+QDEF(MP_QSTR_UART3_RI, (const byte*)"\xe0\x08" "UART3_RI")
+QDEF(MP_QSTR_UART3_SIR_IN, (const byte*)"\x6b\x0c" "UART3_SIR_IN")
+QDEF(MP_QSTR_UART3_DTR, (const byte*)"\xd9\x09" "UART3_DTR")
+QDEF(MP_QSTR_UART3_RTS, (const byte*)"\xce\x09" "UART3_RTS")
+QDEF(MP_QSTR_UART3_OUT2, (const byte*)"\xe7\x0a" "UART3_OUT2")
+QDEF(MP_QSTR_UART3_OUT1, (const byte*)"\xe4\x0a" "UART3_OUT1")
+QDEF(MP_QSTR_UART3_SIR_OUT, (const byte*)"\x22\x0d" "UART3_SIR_OUT")
+QDEF(MP_QSTR_UART3_BAUD, (const byte*)"\x09\x0a" "UART3_BAUD")
+QDEF(MP_QSTR_UART3_RE, (const byte*)"\xec\x08" "UART3_RE")
+QDEF(MP_QSTR_UART3_DE, (const byte*)"\x3a\x08" "UART3_DE")
+QDEF(MP_QSTR_UART3_RS485_EN, (const byte*)"\xd7\x0e" "UART3_RS485_EN")
+QDEF(MP_QSTR_TIMER0_TOGGLE1, (const byte*)"\xee\x0e" "TIMER0_TOGGLE1")
+QDEF(MP_QSTR_TIMER0_TOGGLE2, (const byte*)"\xed\x0e" "TIMER0_TOGGLE2")
+QDEF(MP_QSTR_TIMER0_TOGGLE3, (const byte*)"\xec\x0e" "TIMER0_TOGGLE3")
+QDEF(MP_QSTR_TIMER0_TOGGLE4, (const byte*)"\xeb\x0e" "TIMER0_TOGGLE4")
+QDEF(MP_QSTR_TIMER1_TOGGLE1, (const byte*)"\xef\x0e" "TIMER1_TOGGLE1")
+QDEF(MP_QSTR_TIMER1_TOGGLE2, (const byte*)"\xec\x0e" "TIMER1_TOGGLE2")
+QDEF(MP_QSTR_TIMER1_TOGGLE3, (const byte*)"\xed\x0e" "TIMER1_TOGGLE3")
+QDEF(MP_QSTR_TIMER1_TOGGLE4, (const byte*)"\xea\x0e" "TIMER1_TOGGLE4")
+QDEF(MP_QSTR_TIMER2_TOGGLE1, (const byte*)"\x6c\x0e" "TIMER2_TOGGLE1")
+QDEF(MP_QSTR_TIMER2_TOGGLE2, (const byte*)"\x6f\x0e" "TIMER2_TOGGLE2")
+QDEF(MP_QSTR_TIMER2_TOGGLE3, (const byte*)"\x6e\x0e" "TIMER2_TOGGLE3")
+QDEF(MP_QSTR_TIMER2_TOGGLE4, (const byte*)"\x69\x0e" "TIMER2_TOGGLE4")
+QDEF(MP_QSTR_CLK_SPI2, (const byte*)"\x26\x08" "CLK_SPI2")
+QDEF(MP_QSTR_CLK_I2C2, (const byte*)"\x14\x08" "CLK_I2C2")
+QDEF(MP_QSTR_DRIVING_0, (const byte*)"\x63\x09" "DRIVING_0")
+QDEF(MP_QSTR_DRIVING_1, (const byte*)"\x62\x09" "DRIVING_1")
+QDEF(MP_QSTR_DRIVING_2, (const byte*)"\x61\x09" "DRIVING_2")
+QDEF(MP_QSTR_DRIVING_3, (const byte*)"\x60\x09" "DRIVING_3")
+QDEF(MP_QSTR_DRIVING_4, (const byte*)"\x67\x09" "DRIVING_4")
+QDEF(MP_QSTR_DRIVING_5, (const byte*)"\x66\x09" "DRIVING_5")
+QDEF(MP_QSTR_DRIVING_6, (const byte*)"\x65\x09" "DRIVING_6")
+QDEF(MP_QSTR_DRIVING_7, (const byte*)"\x64\x09" "DRIVING_7")
+QDEF(MP_QSTR_DRIVING_8, (const byte*)"\x6b\x09" "DRIVING_8")
+QDEF(MP_QSTR_DRIVING_9, (const byte*)"\x6a\x09" "DRIVING_9")
+QDEF(MP_QSTR_DRIVING_10, (const byte*)"\x92\x0a" "DRIVING_10")
+QDEF(MP_QSTR_DRIVING_11, (const byte*)"\x93\x0a" "DRIVING_11")
+QDEF(MP_QSTR_DRIVING_12, (const byte*)"\x90\x0a" "DRIVING_12")
+QDEF(MP_QSTR_DRIVING_13, (const byte*)"\x91\x0a" "DRIVING_13")
+QDEF(MP_QSTR_DRIVING_14, (const byte*)"\x96\x0a" "DRIVING_14")
+QDEF(MP_QSTR_DRIVING_15, (const byte*)"\x97\x0a" "DRIVING_15")
+
+QDEF(MP_QSTR_lcdctl, (const byte*)"\x95\x06" "lcdctl")
+QDEF(MP_QSTR_set_direction, (const byte*)"\x5d\x0d" "set_direction")
+QDEF(MP_QSTR_XY_LRUD, (const byte*)"\xf4\x07" "XY_LRUD")
+QDEF(MP_QSTR_YX_LRDU, (const byte*)"\x74\x07" "YX_LRDU")
+QDEF(MP_QSTR_XY_RLUD, (const byte*)"\xb4\x07" "XY_RLUD")
+QDEF(MP_QSTR_YX_RLUD, (const byte*)"\x14\x07" "YX_RLUD")
+QDEF(MP_QSTR_XY_LRDU, (const byte*)"\x94\x07" "XY_LRDU")
+QDEF(MP_QSTR_YX_LRUD, (const byte*)"\x54\x07" "YX_LRUD")
+QDEF(MP_QSTR_XY_RLDU, (const byte*)"\x54\x07" "XY_RLDU")
+QDEF(MP_QSTR_YX_RLDU, (const byte*)"\x34\x07" "YX_RLDU")
+
+
+QDEF(MP_QSTR_KPU, (const byte*)"\xeb\x03" "KPU")
+QDEF(MP_QSTR_load_kmodel, (const byte*)"\x78\x0b" "load_kmodel")
+QDEF(MP_QSTR_dma, (const byte*)"\x6d\x03" "dma")
+QDEF(MP_QSTR_get_output, (const byte*)"\xd3\x0a" "get_output")
+QDEF(MP_QSTR_regionlayer_init, (const byte*)"\x9b\x10" "regionlayer_init")
+QDEF(MP_QSTR_regionlayer, (const byte*)"\x1e\x0b" "regionlayer")
+QDEF(MP_QSTR_getlist, (const byte*)"\xd1\x07" "getlist")
+QDEF(MP_QSTR_in_h, (const byte*)"\xb5\x04" "in_h")
+QDEF(MP_QSTR_cls_num, (const byte*)"\xf0\x07" "cls_num")
+QDEF(MP_QSTR_variances, (const byte*)"\xb3\x09" "variances")
+QDEF(MP_QSTR_crood_num, (const byte*)"\x99\x09" "crood_num")
+QDEF(MP_QSTR_in_w, (const byte*)"\xaa\x04" "in_w")
+QDEF(MP_QSTR_landm_num, (const byte*)"\xc6\x09" "landm_num")
+QDEF(MP_QSTR_obj_thresh, (const byte*)"\x6d\x0a" "obj_thresh")
+QDEF(MP_QSTR_nms_thresh, (const byte*)"\xfa\x0a" "nms_thresh")
+QDEF(MP_QSTR_anchor_num, (const byte*)"\x55\x0a" "anchor_num")
+QDEF(MP_QSTR_max_num, (const byte*)"\x98\x07" "max_num")
+QDEF(MP_QSTR_anchor, (const byte*)"\xbc\x06" "anchor")
+#ifndef PKG_USING_OPENMV_CP
+QDEF(MP_QSTR_size, (const byte*)"\x20\x04" "size")
+#endif  //PKG_USING_OPENMV_CP
+#include "qstrdefscam.h"

+ 211 - 0
project_0/extmods/k210/qstrdefsk210.txt

@@ -0,0 +1,211 @@
+QCFG(BYTES_IN_LEN, 1)
+QCFG(BYTES_IN_HASH, 1)
+
+Q(FPIOA)
+Q(set_function)
+Q(JTAG_TCLK)
+Q(JTAG_TDI)
+Q(JTAG_TMS)
+Q(JTAG_TDO)
+Q(SPI0_D0)
+Q(SPI0_D1)
+Q(SPI0_D2)
+Q(SPI0_D3)
+Q(SPI0_D4)
+Q(SPI0_D5)
+Q(SPI0_D6)
+Q(SPI0_D7)
+Q(SPI0_SS0)
+Q(SPI0_SS1)
+Q(SPI0_SS2)
+Q(SPI0_SS3)
+Q(SPI0_ARB)
+Q(SPI0_SCLK)
+Q(UARTHS_RX)
+Q(UARTHS_TX)
+Q(RESV6)
+Q(RESV7)
+Q(CLK_SPI1)
+Q(CLK_I2C1)
+Q(GPIOHS0)
+Q(GPIOHS1)
+Q(GPIOHS2)
+Q(GPIOHS3)
+Q(GPIOHS4)
+Q(GPIOHS5)
+Q(GPIOHS6)
+Q(GPIOHS7)
+Q(GPIOHS8)
+Q(GPIOHS9)
+Q(GPIOHS10)
+Q(GPIOHS11)
+Q(GPIOHS12)
+Q(GPIOHS13)
+Q(GPIOHS14)
+Q(GPIOHS15)
+Q(GPIOHS16)
+Q(GPIOHS17)
+Q(GPIOHS18)
+Q(GPIOHS19)
+Q(GPIOHS20)
+Q(GPIOHS21)
+Q(GPIOHS22)
+Q(GPIOHS23)
+Q(GPIOHS24)
+Q(GPIOHS25)
+Q(GPIOHS26)
+Q(GPIOHS27)
+Q(GPIOHS28)
+Q(GPIOHS29)
+Q(GPIOHS30)
+Q(GPIOHS31)
+Q(GPIO0)
+Q(GPIO1)
+Q(GPIO2)
+Q(GPIO3)
+Q(GPIO4)
+Q(GPIO5)
+Q(GPIO6)
+Q(GPIO7)
+Q(UART1_RX)
+Q(UART1_TX)
+Q(UART2_RX)
+Q(UART2_TX)
+Q(UART3_RX)
+Q(UART3_TX)
+Q(SPI1_D0)
+Q(SPI1_D1)
+Q(SPI1_D2)
+Q(SPI1_D3)
+Q(SPI1_D4)
+Q(SPI1_D5)
+Q(SPI1_D6)
+Q(SPI1_D7)
+Q(SPI1_SS0)
+Q(SPI1_SS1)
+Q(SPI1_SS2)
+Q(SPI1_SS3)
+Q(SPI1_ARB)
+Q(SPI1_SCLK)
+Q(SPI_SLAVE_D0)
+Q(SPI_SLAVE_SS)
+Q(SPI_SLAVE_SCLK)
+Q(I2S0_MCLK)
+Q(I2S0_SCLK)
+Q(I2S0_WS)
+Q(I2S0_IN_D0)
+Q(I2S0_IN_D1)
+Q(I2S0_IN_D2)
+Q(I2S0_IN_D3)
+Q(I2S0_OUT_D0)
+Q(I2S0_OUT_D1)
+Q(I2S0_OUT_D2)
+Q(I2S0_OUT_D3)
+Q(I2S1_MCLK)
+Q(I2S1_SCLK)
+Q(I2S1_WS)
+Q(I2S1_IN_D0)
+Q(I2S1_IN_D1)
+Q(I2S1_IN_D2)
+Q(I2S1_IN_D3)
+Q(I2S1_OUT_D0)
+Q(I2S1_OUT_D1)
+Q(I2S1_OUT_D2)
+Q(I2S1_OUT_D3)
+Q(I2S2_MCLK)
+Q(I2S2_SCLK)
+Q(I2S2_WS)
+Q(I2S2_IN_D0)
+Q(I2S2_IN_D1)
+Q(I2S2_IN_D2)
+Q(I2S2_IN_D3)
+Q(I2S2_OUT_D0)
+Q(I2S2_OUT_D1)
+Q(I2S2_OUT_D2)
+Q(I2S2_OUT_D3)
+Q(RESV0)
+Q(RESV1)
+Q(RESV2)
+Q(RESV3)
+Q(RESV4)
+Q(RESV5)
+Q(I2C0_SCLK)
+Q(I2C0_SDA)
+Q(I2C1_SCLK)
+Q(I2C1_SDA)
+Q(I2C2_SCLK)
+Q(I2C2_SDA)
+Q(CMOS_XCLK)
+Q(CMOS_RST)
+Q(CMOS_PWDN)
+Q(CMOS_VSYNC)
+Q(CMOS_HREF)
+Q(CMOS_PCLK)
+Q(CMOS_D0)
+Q(CMOS_D1)
+Q(CMOS_D2)
+Q(CMOS_D3)
+Q(CMOS_D4)
+Q(CMOS_D5)
+Q(CMOS_D6)
+Q(CMOS_D7)
+Q(SCCB_SCLK)
+Q(SCCB_SDA)
+Q(UART1_CTS)
+Q(UART1_DSR)
+Q(UART1_DCD)
+Q(UART1_RI)
+Q(UART1_SIR_IN)
+Q(UART1_DTR)
+Q(UART1_RTS)
+Q(UART1_OUT2)
+Q(UART1_OUT1)
+Q(UART1_SIR_OUT)
+Q(UART1_BAUD)
+Q(UART1_RE)
+Q(UART1_DE)
+Q(UART1_RS485_EN)
+Q(UART2_CTS)
+Q(UART2_DSR)
+Q(UART2_DCD)
+Q(UART2_RI)
+Q(UART2_SIR_IN)
+Q(UART2_DTR)
+Q(UART2_RTS)
+Q(UART2_OUT2)
+Q(UART2_OUT1)
+Q(UART2_SIR_OUT)
+Q(UART2_BAUD)
+Q(UART2_RE)
+Q(UART2_DE)
+Q(UART2_RS485_EN)
+Q(UART3_CTS)
+Q(UART3_DSR)
+Q(UART3_DCD)
+Q(UART3_RI)
+Q(UART3_SIR_IN)
+Q(UART3_DTR)
+Q(UART3_RTS)
+Q(UART3_OUT2)
+Q(UART3_OUT1)
+Q(UART3_SIR_OUT)
+Q(UART3_BAUD)
+Q(UART3_RE)
+Q(UART3_DE)
+Q(UART3_RS485_EN)
+Q(TIMER0_TOGGLE1)
+Q(TIMER0_TOGGLE2)
+Q(TIMER0_TOGGLE3)
+Q(TIMER0_TOGGLE4)
+Q(TIMER1_TOGGLE1)
+Q(TIMER1_TOGGLE2)
+Q(TIMER1_TOGGLE3)
+Q(TIMER1_TOGGLE4)
+Q(TIMER2_TOGGLE1)
+Q(TIMER2_TOGGLE2)
+Q(TIMER2_TOGGLE3)
+Q(TIMER2_TOGGLE4)
+Q(CLK_SPI2)
+Q(CLK_I2C2)
+
+

+ 413 - 0
project_0/extmods/k210/rt_ai_img.c

@@ -0,0 +1,413 @@
+
+#include <rt_ai_img.h>
+#include <rtthread.h>
+#include <rt_ai_img_utils.h>
+
+
+static inline int is_in_array(int x, int y, int height, int width)
+{
+    if (x >= 0 && x < width && y >= 0 && y < height)
+        return 1;
+    else
+        return 0;
+}
+
+void bilinera_interpolation_grayscale(image_t *ori, image_t *res)
+{
+    uint32_t height = ori->h;
+    uint32_t width = ori->w;
+    uint32_t out_height = res->h;
+    uint32_t out_width = res->w;
+    // rescale factor
+    double h_times = (double)out_height / (double)height,
+           w_times = (double)out_width / (double)width;
+    int  x1, y1, x2, y2;
+    uint32_t f11, f12, f21, f22;
+    double x, y;
+
+    for (int i = 0; i < out_height; i++){
+        for (int j = 0; j < out_width; j++){
+            x = j / w_times;    // j:origin location at width axis. and x is new.
+            y = i / h_times;    // i:origin location at height axis. and y is new.
+          
+            x1 = (int)(x - 1);  // left x
+            x2 = (int)(x + 1);  // right x
+            y1 = (int)(y + 1);  // bottom y
+            y2 = (int)(y - 1);  // top y
+            /* 
+                f11 f12
+                f21 f22
+             */
+            //IMAGE_GET_GRAYSCALE_PIXEL(image, x, y)
+            f11 = is_in_array(x1, y1, height, width) ? IMAGE_GET_GRAYSCALE_PIXEL(ori, x1, y1) : 0;
+            f12 = is_in_array(x1, y2, height, width) ? IMAGE_GET_GRAYSCALE_PIXEL(ori, x1, y2) : 0;
+            f21 = is_in_array(x2, y1, height, width) ? IMAGE_GET_GRAYSCALE_PIXEL(ori, x2, y1) : 0;
+            f22 = is_in_array(x2, y2, height, width) ? IMAGE_GET_GRAYSCALE_PIXEL(ori, x2, y2) : 0;
+            uint8_t e = (uint8_t)(((f11 * (x2 - x) * (y2 - y)) +
+                            (f21 * (x - x1) * (y2 - y)) +
+                            (f12 * (x2 - x) * (y - y1)) +
+                            (f22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+            IMAGE_PUT_GRAYSCALE_PIXEL(res, j, i, e);
+        }
+    }
+}
+
+void bilinera_interpolation_rgb565(image_t *ori, image_t *res)
+{
+    uint32_t height = ori->h;
+    uint32_t width = ori->w;
+    uint32_t out_height = res->h;
+    uint32_t out_width = res->w;
+    // rescale factor
+    double h_times = (double)out_height / (double)height,
+           w_times = (double)out_width / (double)width;
+    int  x1, y1, x2, y2;
+    uint32_t f11, f12, f21, f22, e11, e12, e21, e22;
+    double x, y;
+
+    for (int i = 0; i < out_height; i++){
+        for (int j = 0; j < out_width; j++){
+            x = j / w_times;    // j:origin location at width axis. and x is new.
+            y = i / h_times;    // i:origin location at height axis. and y is new.
+          
+            x1 = (int)(x - 1);  // left x
+            x2 = (int)(x + 1);  // right x
+            y1 = (int)(y + 1);  // bottom y
+            y2 = (int)(y - 1);  // top y
+            /* 
+                f11 f12
+                f21 f22
+             */
+            f11 = is_in_array(x1, y1, height, width) ? IMAGE_GET_RGB565_PIXEL(ori, x1, y1) : 0;
+            f12 = is_in_array(x1, y2, height, width) ? IMAGE_GET_RGB565_PIXEL(ori, x1, y2) : 0;
+            f21 = is_in_array(x2, y1, height, width) ? IMAGE_GET_RGB565_PIXEL(ori, x2, y1) : 0;
+            f22 = is_in_array(x2, y2, height, width) ? IMAGE_GET_RGB565_PIXEL(ori, x2, y2) : 0;
+
+            e11 = COLOR_RGB565_TO_R8(f11);
+            e12 = COLOR_RGB565_TO_R8(f12);
+            e21 = COLOR_RGB565_TO_R8(f21);
+            e22 = COLOR_RGB565_TO_R8(f22);
+            uint8_t r = (uint8_t)(((e11 * (x2 - x) * (y2 - y)) +
+                                   (e21 * (x - x1) * (y2 - y)) +
+                                   (e12 * (x2 - x) * (y - y1)) +
+                                   (e22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+            
+            e11 = COLOR_RGB565_TO_G8(f11);
+            e12 = COLOR_RGB565_TO_G8(f12);
+            e21 = COLOR_RGB565_TO_G8(f21);
+            e22 = COLOR_RGB565_TO_G8(f22);
+            uint8_t g = (uint8_t)(((e11 * (x2 - x) * (y2 - y)) +
+                                   (e21 * (x - x1) * (y2 - y)) +
+                                   (e12 * (x2 - x) * (y - y1)) +
+                                   (e22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+
+            e11 = COLOR_RGB565_TO_B8(f11);
+            e12 = COLOR_RGB565_TO_B8(f12);
+            e21 = COLOR_RGB565_TO_B8(f21);
+            e22 = COLOR_RGB565_TO_B8(f22);
+            uint8_t b = (uint8_t)(((e11 * (x2 - x) * (y2 - y)) +
+                                   (e21 * (x - x1) * (y2 - y)) +
+                                   (e12 * (x2 - x) * (y - y1)) +
+                                   (e22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+            
+            IMAGE_PUT_RGB565_PIXEL(res, j, i, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
+        }
+    }
+}
+
+void bilinera_interpolation_rgb888_chw(image_t *ori, image_t *res)
+{
+    uint32_t height = ori->h;
+    uint32_t width = ori->w;
+    uint32_t out_height = res->h;
+    uint32_t out_width = res->w;
+
+    uint8_t* in_array = ori->data;
+    uint8_t* out_array = res->data;
+    // rescale factor
+    double h_times = (double)out_height / (double)height,
+           w_times = (double)out_width / (double)width;
+    int  x1, y1, x2, y2;
+    uint32_t f11, f12, f21, f22;
+    double x, y;
+    for(int rgb = 0; rgb < 3; rgb++){
+        in_array = ori->data + (height * width * rgb);
+        out_array = res->data + (out_height * out_width * rgb);
+        for (int i = 0; i < out_height; i++){
+            for (int j = 0; j < out_width; j++){
+                x = j / w_times;    // j:origin location at width axis. and x is new.
+                y = i / h_times;    // i:origin location at height axis. and y is new.
+            
+                x1 = (int)(x - 1);  // left x
+                x2 = (int)(x + 1);  // right x
+                y1 = (int)(y + 1);  // bottom y
+                y2 = (int)(y - 1);  // top y
+                f11 = is_in_array(x1, y1, height, width) ? in_array[y1*width+x1] : 0;
+                f12 = is_in_array(x1, y2, height, width) ? in_array[y2*width+x1] : 0;
+                f21 = is_in_array(x2, y1, height, width) ? in_array[y1*width+x2] : 0;
+                f22 = is_in_array(x2, y2, height, width) ? in_array[y2*width+x2] : 0;
+                out_array[i*out_width+j] = (uint8_t)(((f11 * (x2 - x) * (y2 - y)) +
+                                        (f21 * (x - x1) * (y2 - y)) +
+                                        (f12 * (x2 - x) * (y - y1)) +
+                                        (f22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+            }
+        }
+    }
+}
+
+void bilinera_interpolation_rgb888_hwc(image_t *ori, image_t *res)
+{
+    uint32_t height = ori->h;
+    uint32_t width = ori->w;
+    uint32_t out_height = res->h;
+    uint32_t out_width = res->w;
+
+    uint8_t* in_array = ori->data;
+    uint8_t* out_array = res->data;
+    // rescale factor
+    double h_times = (double)out_height / (double)height,
+           w_times = (double)out_width / (double)width;
+    int  x1, y1, x2, y2;
+    uint32_t f11, f12, f21, f22, e11, e12, e21, e22;
+    double x, y;
+
+    for (int i = 0; i < out_height; i++){
+        for (int j = 0; j < out_width; j++){
+            x = j / w_times;    // j:origin location at width axis. and x is new.
+            y = i / h_times;    // i:origin location at height axis. and y is new.
+        
+            x1 = (int)(x - 1);  // left x
+            x2 = (int)(x + 1);  // right x
+            y1 = (int)(y + 1);  // bottom y
+            y2 = (int)(y - 1);  // top y
+            // R
+            f11 = is_in_array(x1, y1, height, width) ? in_array[3*(y1*width+x1)+0] : 0;
+            f12 = is_in_array(x1, y2, height, width) ? in_array[3*(y2*width+x1)+0] : 0;
+            f21 = is_in_array(x2, y1, height, width) ? in_array[3*(y1*width+x2)+0] : 0;
+            f22 = is_in_array(x2, y2, height, width) ? in_array[3*(y2*width+x2)+0] : 0;
+            out_array[3*i*out_width+j+0] = (uint8_t)(((f11 * (x2 - x) * (y2 - y)) +
+                                    (f21 * (x - x1) * (y2 - y)) +
+                                    (f12 * (x2 - x) * (y - y1)) +
+                                    (f22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+            // G
+            f11 = is_in_array(x1, y1, height, width) ? in_array[3*(y1*width+x1)+1] : 0;
+            f12 = is_in_array(x1, y2, height, width) ? in_array[3*(y2*width+x1)+1] : 0;
+            f21 = is_in_array(x2, y1, height, width) ? in_array[3*(y1*width+x2)+1] : 0;
+            f22 = is_in_array(x2, y2, height, width) ? in_array[3*(y2*width+x2)+1] : 0;
+            out_array[3*(i*out_width+j)+1] = (uint8_t)(((f11 * (x2 - x) * (y2 - y)) +
+                                    (f21 * (x - x1) * (y2 - y)) +
+                                    (f12 * (x2 - x) * (y - y1)) +
+                                    (f22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+            // B
+            f11 = is_in_array(x1, y1, height, width) ? in_array[3*(y1*width+x1)+2] : 0;
+            f12 = is_in_array(x1, y2, height, width) ? in_array[3*(y2*width+x1)+2] : 0;
+            f21 = is_in_array(x2, y1, height, width) ? in_array[3*(y1*width+x2)+2] : 0;
+            f22 = is_in_array(x2, y2, height, width) ? in_array[3*(y2*width+x2)+2] : 0;
+            out_array[3*(i*out_width+j)+2] = (uint8_t)(((f11 * (x2 - x) * (y2 - y)) +
+                                    (f21 * (x - x1) * (y2 - y)) +
+                                    (f12 * (x2 - x) * (y - y1)) +
+                                    (f22 * (x - x1) * (y - y1))) / ((x2 - x1) * (y2 - y1)));
+        }
+    }
+}
+
+
+void resize_bilinera_interpolation(image_t *ori, image_t *res){
+    
+    switch (ori->pixfmt)
+    {
+    case PIXFORMAT_GRAYSCALE:
+        bilinera_interpolation_grayscale(ori, res);
+        break;
+    
+    case PIXFORMAT_RGB565:
+        bilinera_interpolation_rgb565(ori, res);
+        break;
+    
+    case PIXFORMAT_RGB888_CHW:
+        bilinera_interpolation_rgb888_chw(ori, res);
+        break;
+    
+    case PIXFORMAT_RGB888_HWC:
+        bilinera_interpolation_rgb888_hwc(ori, res);
+        break;
+    default:
+        IMG_LOG_ERR("can't resize the format current");
+        break;
+    }
+}
+
+
+void crop(image_t *ori, image_t *res, uint32_t offset_height, uint32_t offset_width){
+
+    IMG_ASSERT_RET((offset_height + res->h < ori->h), );
+    IMG_ASSERT_RET((offset_width + res->w < ori->w), );
+    switch (ori->pixfmt)
+    {
+    case PIXFORMAT_GRAYSCALE:
+        for(uint32_t ih = 0; ih < res->h; ih++){
+            for(uint32_t iw = 0; iw < res->w; iw++){
+                IMAGE_PUT_GRAYSCALE_PIXEL(res, iw, ih, IMAGE_GET_GRAYSCALE_PIXEL(ori, (iw+offset_width), (ih+offset_height)) );
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB565:
+        for(uint32_t ih = 0; ih < res->h; ih++){
+            for(uint32_t iw = 0; iw < res->w; iw++){
+                IMAGE_PUT_RGB565_PIXEL(res, iw, ih, IMAGE_GET_RGB565_PIXEL(ori, (iw+offset_width), (ih+offset_height)) );
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB888_CHW:
+        for(uint32_t ih = 0; ih < res->h; ih++){
+            for(uint32_t iw = 0; iw < res->w; iw++){
+                IMAGE_PUT_RGB888_CHW_PIXEL(res, iw, ih, 0, IMAGE_GET_RGB888_CHW_PIXEL(ori, (iw+offset_width), (ih+offset_height), 0));  // R
+                IMAGE_PUT_RGB888_CHW_PIXEL(res, iw, ih, 1, IMAGE_GET_RGB888_CHW_PIXEL(ori, (iw+offset_width), (ih+offset_height), 1));  // G
+                IMAGE_PUT_RGB888_CHW_PIXEL(res, iw, ih, 2, IMAGE_GET_RGB888_CHW_PIXEL(ori, (iw+offset_width), (ih+offset_height), 2));  // B
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB888_HWC:
+        for(uint32_t ih = 0; ih < res->h; ih++){
+            for(uint32_t iw = 0; iw < res->w; iw++){
+                IMAGE_PUT_RGB888_HWC_PIXEL(res, iw, ih, 0, IMAGE_GET_RGB888_HWC_PIXEL(ori, (iw+offset_width), (ih+offset_height), 0));  // R
+                IMAGE_PUT_RGB888_HWC_PIXEL(res, iw, ih, 1, IMAGE_GET_RGB888_HWC_PIXEL(ori, (iw+offset_width), (ih+offset_height), 1));  // G
+                IMAGE_PUT_RGB888_HWC_PIXEL(res, iw, ih, 2, IMAGE_GET_RGB888_HWC_PIXEL(ori, (iw+offset_width), (ih+offset_height), 2));  // B
+            }
+        }
+        break;
+    default:
+        IMG_LOG_ERR("can't crop the format current");
+        break;
+    }
+}
+
+void to_gray(image_t *ori, image_t *res){
+    switch (ori->pixfmt)
+    {
+    case PIXFORMAT_GRAYSCALE:
+        ;
+        break;
+    
+    case PIXFORMAT_RGB565:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint16_t pix = IMAGE_GET_RGB565_PIXEL(ori, iw, ih);
+                IMAGE_PUT_GRAYSCALE_PIXEL(res, iw, ih, COLOR_RGB565_TO_GRAYSCALE(pix));
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB888_CHW:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t r = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 0);
+                uint8_t g = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 1);
+                uint8_t b = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 2);
+                IMAGE_PUT_GRAYSCALE_PIXEL(res, iw, ih, COLOR_RGB888_TO_Y(r, g, b));
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB888_HWC:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t r = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 0);
+                uint8_t g = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 1);
+                uint8_t b = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 2);
+                IMAGE_PUT_GRAYSCALE_PIXEL(res, ih, iw, COLOR_RGB888_TO_Y(r, g, b));
+            }
+        }
+        break;
+    default:
+        IMG_LOG_ERR("can't gray the format current");
+        break;
+    }
+}
+
+void to_rgb565(image_t *ori, image_t *res){
+    switch (ori->pixfmt)
+    {
+    case PIXFORMAT_GRAYSCALE:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t pix = IMAGE_GET_GRAYSCALE_PIXEL(ori, iw, ih);
+                IMAGE_PUT_RGB565_PIXEL(res, iw, ih, COLOR_GRAYSCALE_TO_RGB565(pix));
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB565:
+        ;
+        break;
+    
+    case PIXFORMAT_RGB888_CHW:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t r = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 0);
+                uint8_t g = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 1);
+                uint8_t b = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 2);
+                IMAGE_PUT_RGB565_PIXEL(res, iw, ih, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB888_HWC:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t r = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 0);
+                uint8_t g = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 1);
+                uint8_t b = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 2);
+                IMAGE_PUT_RGB565_PIXEL(res, ih, iw, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
+            }
+        }
+        break;
+    default:
+        IMG_LOG_ERR("can't gray the format current");
+        break;
+    }
+}
+ 
+void set_pixel(image_t *img, int x, int y, int p)
+{
+    imlib_set_pixel(img, x,  y,  p);
+}
+
+
+void draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness)
+{
+    imlib_draw_line(img, x0,  y0,  x1,  y1,  c,  thickness);
+}
+
+
+void draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill)
+{
+    imlib_draw_rectangle(img, rx,  ry,  rw,  rh,  c,  thickness,  fill);
+}
+
+
+void draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill)
+{
+    imlib_draw_circle(img, cx,  cy,  r,  c,  thickness,  fill);
+}
+
+void draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space,
+                       int char_rotation, bool char_hmirror, bool char_vflip, int string_rotation, bool string_hmirror, bool string_hflip)
+{
+    imlib_draw_string(img,  x_off,  y_off, str,  c,  scale,  x_spacing,  y_spacing,  mono_space,
+                        char_rotation,  char_hmirror,  char_vflip,  string_rotation,  string_hmirror,  string_hflip);
+}
+
+
+void rotation_corr(image_t *img, float x_rotation, float y_rotation, float z_rotation,
+                         float x_translation, float y_translation,
+                         float zoom, float fov, float *corners)
+{
+    imlib_rotation_corr(img,  x_rotation,  y_rotation,  z_rotation,
+                          x_translation,  y_translation,
+                          zoom,  fov,  corners);
+}
+                         

+ 128 - 0
project_0/extmods/k210/rt_ai_img.h

@@ -0,0 +1,128 @@
+#ifndef __RT_AI_IMAGE__
+#define __RT_AI_IAMGE__
+
+#include <stdlib.h>
+#include <imlib.h>
+/**
+ * @brief bilinera interpolation resize. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_RGB888_CHW/PIXFORMAT_RGB888_HWC
+ * 
+ * @param ori origin image
+ * @param res result image
+ */
+void resize_bilinera_interpolation(image_t *ori, image_t *res);
+
+/**
+ * @brief crop ori img to res img by offset. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_RGB888_CHW/PIXFORMAT_RGB888_HWC
+ * @param ori origin image
+ * @param res result image
+ * @param offset_height height offset with start to crop
+ * @param offset_width width offset with start to crop
+ */
+void crop(image_t *ori, image_t *res, uint32_t offset_height, uint32_t offset_width);
+
+/**
+ * @brief covert ori img to grayscale to res. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_RGB888_CHW/PIXFORMAT_RGB888_HWC
+ * 
+ * @param ori origin image
+ * @param res result image
+ */
+void to_gray(image_t *ori, image_t *res);
+
+/**
+ * @brief covert to ori img to rgb565 to res. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_RGB888_CHW/PIXFORMAT_RGB888_HWC
+ * 
+ * @param ori origin image
+ * @param res result image
+ */
+void to_rgb565(image_t *ori, image_t *res);
+
+/**
+ * @brief Set the pixel object. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_BINARY
+ * 
+ * @param img the image be set
+ * @param x x
+ * @param y y
+ * @param p pixel
+ */
+void set_pixel(image_t *img, int x, int y, int p);
+
+/**
+ * @brief draw line. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_BINARY
+ * 
+ * @param img image_t.
+ * @param x0 start x.
+ * @param y0 start y.
+ * @param x1 end x.
+ * @param y1 end y.
+ * @param c color.
+ * @param thickness thickness.
+ */
+void draw_line(image_t *img, int x0, int y0, int x1, int y1, int c, int thickness);
+
+/**
+ * @brief draw rectangle. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_BINARY.
+ * 
+ * @param img image_t
+ * @param rx right-up x.
+ * @param ry right-up y.
+ * @param rw width.
+ * @param rh height.
+ * @param c color.
+ * @param thickness thickness. 
+ * @param fill fill the rectangle.
+ */
+void draw_rectangle(image_t *img, int rx, int ry, int rw, int rh, int c, int thickness, bool fill);
+
+/**
+ * @brief draw circle. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_BINARY.
+ * 
+ * @param img image_t.
+ * @param cx x of the centre of the circle.
+ * @param cy y of the centre of a circle
+ * @param r radius
+ * @param c color
+ * @param thickness thickness
+ * @param fill fill the circle.
+ */
+void draw_circle(image_t *img, int cx, int cy, int r, int c, int thickness, bool fill);
+
+/**
+ * @brief draw string. now support PIXFORMAT_GRAYSCALE/PIXFORMAT_RGB565/PIXFORMAT_BINARY.
+ * 
+ * @param img image_t
+ * @param x_off x
+ * @param y_off y
+ * @param str draw string
+ * @param c color
+ * @param scale string scale, eg: 1.0, 2.0....
+ * @param x_spacing 允许你在字符之间添加(如果是正数)或减去(如果是负数)x像素,设置字符间距。
+ * @param y_spacing 允许你在字符之间添加(如果是正数)或减去(如果是负数)y像素,设置行间距。
+ * @param mono_space 认为True,强制文本间距固定。对于大文本,这看起来很糟糕。设置False以获得非固定宽度的字符间距,看起来好多了。
+ * @param char_rotation 
+ * @param char_hmirror 如果为True,则水平镜像字符串中的所有字符。
+ * @param char_vflip 如果为True,则垂直翻转字符串中的所有字符。
+ * @param string_rotation 可以是0、90、180、270,来旋转字符串。
+ * @param string_hmirror 如果为True,则水平镜像字符串。
+ * @param string_hflip 如果为True,则垂直翻转字符串。
+ */
+void draw_string(image_t *img, int x_off, int y_off, const char *str, int c, float scale, int x_spacing, int y_spacing, bool mono_space,
+                       int char_rotation, bool char_hmirror, bool char_vflip, int string_rotation, bool string_hmirror, bool string_hflip);
+
+/**
+ * @brief 图像旋转校正
+ * 
+ * @param img image_t
+ * @param x_rotation 是围绕x轴在帧缓冲器中旋转图像的度数(这使图像上下旋转)。
+ * @param y_rotation 是帧缓冲区中围绕y轴旋转图像的度数(即左右旋转图像)。
+ * @param z_rotation 是围绕z轴在帧缓冲器中旋转图像的度数(即,使图像旋转到适当位置)。
+ * @param x_translation 是旋转后将图像移动到左侧或右侧的单位数。因为这个变换是应用在三维空间的,单位不是像素…
+ * @param y_translation 是旋转后将图像上移或下移的单位数。因为这个变换是应用在三维空间的,单位不是像素…
+ * @param zoom 是通过图像缩放的量。默认情况下1.0。
+ * @param fov 是在 3D 空间中旋转图像之前进行 2D->3D 投影时在内部使用的视场。 当这个值接近 0 时,图像被放置在远离视口的无穷远处。 当这个值接近 180 时,图像被放置在视口内。 通常,您不应更改此值,但可以修改它以更改 2D->3D 映射效果。
+ * @param corners 是四个 (x,y) 元组的列表,表示用于创建 4 点的四个角对应单应性, 将第一个角映射到 (0, 0),第二个角映射到 (image_width-1, 0), 第三个角映射到 (image_width-1, image_height-1),第四个角映射到 (0, image_height -1). 然后在重新映射图像后应用 3D 旋转。 此参数允许您使用 rotation_corr 来执行诸如鸟瞰图变换之类的操作。
+ */
+void rotation_corr(image_t *img, float x_rotation, float y_rotation, float z_rotation,
+                         float x_translation, float y_translation,
+                         float zoom, float fov, float *corners);
+
+#endif //__RT_AI_IMAGE__

+ 14 - 0
project_0/extmods/k210/rt_ai_img_utils.h

@@ -0,0 +1,14 @@
+#ifndef __RT_AI_IMG_UTILS_H
+#define __RT_AI_IMG_UTILS_H
+#include <rtthread.h>
+#ifndef IMG_LOG_TAG
+#define IMG_LOG_TAG ""
+#endif
+
+#define img_log(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__)
+#define IMG_LOG(fmt, ...) img_log( IMG_LOG_TAG fmt "\n", ##__VA_ARGS__)
+#define IMG_LOG_ERR(fmt, ...) img_log("[IMG_ERR]" fmt "\n", ##__VA_ARGS__)
+
+#define RET_NONE /* void return */
+#define IMG_ASSERT_RET(_expr, _ret) if(!(_expr)){ IMG_LOG_ERR("%s,%d:%s",__FILE__,__LINE__, #_expr); return _ret; }
+#endif //__RT_AI_IMG_UTILS_H

+ 49 - 0
project_0/extmods/k210/to_rgb565.c

@@ -0,0 +1,49 @@
+#if 0
+#include <rtthread.h>
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "imlib.h"
+
+void to_rgb565(image_t *ori, image_t *res){
+    switch (ori->pixfmt)
+    {
+    case PIXFORMAT_GRAYSCALE:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t pix = IMAGE_GET_GRAYSCALE_PIXEL(ori, iw, ih);
+                IMAGE_PUT_RGB565_PIXEL(res, iw, ih, COLOR_GRAYSCALE_TO_RGB565(pix));
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB565:
+        ;
+        break;
+    
+    case PIXFORMAT_RGB888_CHW:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t r = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 0);
+                uint8_t g = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 1);
+                uint8_t b = IMAGE_GET_RGB888_CHW_PIXEL(ori, iw, ih, 2);
+                IMAGE_PUT_RGB565_PIXEL(res, iw, ih, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
+            }
+        }
+        break;
+    
+    case PIXFORMAT_RGB888_HWC:
+        for(uint32_t ih = 0; ih < ori->h; ih++){
+            for(uint32_t iw = 0; iw < ori->w; iw++){
+                uint8_t r = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 0);
+                uint8_t g = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 1);
+                uint8_t b = IMAGE_GET_RGB888_HWC_PIXEL(ori, iw, ih, 2);
+                IMAGE_PUT_RGB565_PIXEL(res, ih, iw, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
+            }
+        }
+        break;
+    default:
+        mp_raise_TypeError("can't gray the format current");
+        break;
+    }
+}
+#endif // #if 0

+ 127 - 0
project_0/extmods/k210/yuv.c

@@ -0,0 +1,127 @@
+/*
+ * This file is part of the OpenMV project.
+ *
+ * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
+ * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
+ *
+ * This work is licensed under the MIT license, see the file LICENSE for details.
+ *
+ * Deyuv Functions
+ */
+#include "imlib.h"
+
+void imlib_deyuv_line(int x_start, int x_end, int y_row, void *dst_row_ptr, pixformat_t pixfmt, image_t *src)
+{
+    int shift = (src->pixfmt == PIXFORMAT_YUV422) ? 16 : 0;
+    int src_w = src->w, w_limit = src_w - 1;
+
+    uint16_t *rowptr_yuv = ((uint16_t *) src->data) + (y_row * src_w);
+
+    // If the image is an odd width this will go for the last loop and we drop the last column.
+    for (int x = x_start; x < x_end; x += 2) {
+        int32_t row_yuv; // signed
+
+        // keep pixels in bounds
+        if (x >= w_limit) {
+            if (src_w >= 2) {
+                uint32_t temp = *((uint32_t *) (rowptr_yuv + x - 1));
+                row_yuv = ((temp & 0xff00) << 16) | (temp & 0xff0000) | (temp >> 16);
+            } else {
+                row_yuv = *((uint16_t *) (rowptr_yuv + x));
+                row_yuv = ((row_yuv & 0xff) << 16) | 0x80000000;
+            }
+        } else {
+            row_yuv = *((uint32_t *) (rowptr_yuv + x));
+        }
+
+        int y0 = row_yuv & 0xff, y1 = (row_yuv >> 16) & 0xff;
+
+        switch (pixfmt) {
+            case PIXFORMAT_BINARY: {
+                uint32_t *row_ptr_32 = (uint32_t *) dst_row_ptr;
+                IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_32, x, (y0 >> 7));
+
+                if (x != w_limit) {
+                    IMAGE_PUT_BINARY_PIXEL_FAST(row_ptr_32, x + 1, (y1 >> 7));
+                }
+
+                break;
+            }
+            case PIXFORMAT_GRAYSCALE: {
+                uint8_t *row_ptr_8 = (uint8_t *) dst_row_ptr;
+                IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_8, x, y0);
+
+                if (x != w_limit) {
+                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(row_ptr_8, x + 1, y1);
+                }
+
+                break;
+            }
+            case PIXFORMAT_RGB565: {
+                uint16_t *row_ptr_16 = (uint16_t *) dst_row_ptr;
+
+                // R = Y + (1.40200 * U)
+                // G = Y - (0.34414 * V) - (0.71414 * U)
+                // B = Y + (1.77200 * V)
+
+                // R = Y + ((179 * U) >> 7)
+                // G = Y - (((44 * V) - (91 * U)) >> 7)
+                // B = Y + ((227 * V) >> 7)
+
+                row_yuv ^= 0x80008000;
+
+                int u = (row_yuv << shift) >> 24; // signed bit extraction
+                int v = (row_yuv << (16 - shift)) >> 24; // signed bit extraction
+
+                int ry = (179 * u) >> 7;
+                int gy = ((44 * v) + (91 * u)) >> 7;
+                int by = (227 * v) >> 7;
+
+                int r0 = y0 + ry, g0 = y0 - gy, b0 = y0 + by;
+                r0 = IM_MIN(IM_MAX(r0, COLOR_R8_MIN), COLOR_R8_MAX);
+                g0 = IM_MIN(IM_MAX(g0, COLOR_G8_MIN), COLOR_G8_MAX);
+                b0 = IM_MIN(IM_MAX(b0, COLOR_B8_MIN), COLOR_B8_MAX);
+                int rgb565_0 = COLOR_R8_G8_B8_TO_RGB565(r0, g0, b0);
+                IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_16, x, rgb565_0);
+
+                if (x != w_limit) {
+                    int r1 = y1 + ry, g1 = y1 - gy, b1 = y1 + by;
+                    r1 = IM_MIN(IM_MAX(r1, COLOR_R8_MIN), COLOR_R8_MAX);
+                    g1 = IM_MIN(IM_MAX(g1, COLOR_G8_MIN), COLOR_G8_MAX);
+                    b1 = IM_MIN(IM_MAX(b1, COLOR_B8_MIN), COLOR_B8_MAX);
+                    int rgb565_1 = COLOR_R8_G8_B8_TO_RGB565(r1, g1, b1);
+                    IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_16, x + 1, rgb565_1);
+                }
+
+                break;
+            }
+            default: {
+                break;
+            }
+        }
+    }
+}
+
+void imlib_deyuv_image(image_t *dst, image_t *src)
+{
+    for (int y = 0, src_w = src->w, src_h = src->h; y < src_h; y++) {
+        void *row_ptr = NULL;
+
+        switch (dst->pixfmt) {
+            case PIXFORMAT_BINARY: {
+                row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(dst, y);
+                break;
+            }
+            case PIXFORMAT_GRAYSCALE: {
+                row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(dst, y);
+                break;
+            }
+            case PIXFORMAT_RGB565: {
+                row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(dst, y);
+                break;
+            }
+        }
+
+        imlib_deyuv_line(0, src_w, y, row_ptr, dst->pixfmt, src);
+    }
+}

+ 14 - 0
project_0/extmods/moddefsmisc.h

@@ -0,0 +1,14 @@
+#ifndef __MODDEFSMISC_H
+#define __MODDEFSMISC_H
+
+#ifdef EXTMODS_MISC_USING_K210
+extern const struct _mp_obj_module_t k210_module;
+#define MPY_MODDEFS_K210 {MP_ROM_QSTR(MP_QSTR_k210), MP_ROM_PTR(&k210_module) },
+#else
+#define MPY_MODDEFS_K210
+#endif
+
+#define MPY_MODDEFS_MISC \
+    MPY_MODDEFS_K210 \
+
+#endif

+ 1 - 0
project_0/extmods/qstrdefsmisc.h

@@ -0,0 +1 @@
+#include "k210/qstrdefsk210.h"

二進制
project_0/images/1-create_prj.png


二進制
project_0/images/2-lab2-create.png


二進制
project_0/images/20210731112127.png


二進制
project_0/images/20210731112411.png


二進制
project_0/images/20210731112623.png


二進制
project_0/images/3-set_toolchian.png


二進制
project_0/images/4-fresh.png


二進制
project_0/images/5.png


二進制
project_0/images/6.png


二進制
project_0/images/SDK-Complete.png


二進制
project_0/images/SDK-GCC.png


二進制
project_0/images/SDK-K210-RT-DRACO.png


二進制
project_0/images/Studio_icon.png


二進制
project_0/images/Studio_menu.png


二進制
project_0/images/com_ok.png


二進制
project_0/images/com_open.png


二進制
project_0/images/compile_ok.png


二進制
project_0/images/config_window.png


+ 0 - 0
project_0/images/courgette.log


+ 5 - 0
project_0/images/debug.log

@@ -0,0 +1,5 @@
+[1105/171802.755:INFO:crash_reporting.cc(219)] Crash reporting enabled for process: browser
+[1105/171802.934:INFO:gpu_process_host.cc(941)] [XWEB_LOG_GPU]  GPU process laucnched multi-process mode SUCCESS!!! gpu-process-pid:20364 gpu-process-sandbox:1
+[1105/171802.977:INFO:crash_reporting.cc(219)] Crash reporting enabled for process: gpu-process
+[1105/171803.097:INFO:crash_reporting.cc(219)] Crash reporting enabled for process: utility
+[1105/172002.986:INFO:crash_reporting.cc(219)] Crash reporting enabled for process: gpu-process

二進制
project_0/images/download_com.png


二進制
project_0/images/download_ok.png


二進制
project_0/images/download_studio.png


二進制
project_0/images/err_toolchain_path.png


二進制
project_0/images/image-20210803120635990.png


二進制
project_0/images/image-20210803120820601.png


二進制
project_0/images/image-20210805172934786.png


二進制
project_0/images/image-20210806152046809.png


二進制
project_0/images/image-20210806154157722.png


二進制
project_0/images/image-20210806154603636.png


二進制
project_0/images/image-20210806154705231.png


二進制
project_0/images/image-20210806154816110.png


二進制
project_0/images/image-20210806160109511.png


二進制
project_0/images/image-20210806160421936.png


二進制
project_0/images/image-20210816105954821.png


二進制
project_0/images/image-20210816110706258.png


二進制
project_0/images/image-20210819110305551.png


二進制
project_0/images/image-20210819110338344.png


二進制
project_0/images/install-anyway.png


二進制
project_0/images/module.png


二進制
project_0/images/note_com.png


二進制
project_0/images/note_download.png


二進制
project_0/images/update-1.png


二進制
project_0/images/update-2.png


二進制
project_0/images/update-restart.png


二進制
project_0/images/updating.png


二進制
project_0/images/window_config_set.png


+ 22 - 0
project_0/moddefs.user.extmods.h

@@ -0,0 +1,22 @@
+#ifndef _MODDEFS_USER_EXTMODS
+#define _MODDEFS_USER_EXTMODS
+
+#ifdef PRJ_USING_EXTMODS_MISC
+#include "moddefsmisc.h"
+#else
+#define MPY_MODDEFS_MISC
+#endif
+
+#ifdef PRJ_USING_RT_AK_EXMODS
+#include "moddefs_rt_ai.h"
+#else
+#define MICROPY_RT_AI_MODULES
+#endif
+#define MICROPY_USER_MODULES \
+    MICROPY_RT_AI_MODULES\
+    MPY_MODDEFS_MISC\
+
+#define MICROPY_REGISTERED_MODULES \
+    {MP_ROM_QSTR(MP_QSTR_uarray), MP_ROM_PTR(&mp_module_uarray)},\
+
+#endif

+ 119 - 0
project_0/mpy_rt_ai/Module_Design_Description.md

@@ -0,0 +1,119 @@
+# 模块设计说明
+
+## 1.简介
+
+该文档用于简要说明RT-AK MicroPython扩展模块的设计及实现.
+
+关于MicroPython添加自定义模块及相关接口说明请参考[micropython-usermod](https://micropython-usermod.readthedocs.io/en/latest/usermods_01.html)
+
+## 2.C-->MicroPython开发基础
+
+### Python相关概念
+
+熟悉python的小伙伴会知道, python是面向对象的. 了解的更深一点的人或许知道, 与C语言不同, python中的变量本质上是个引用, 类似C语言的指针. 而指针可以理解为是一种若类型的变量, 其指向一个内存地址. 因此在python中,类型属于对象,对象有不同类型的区分,变量是没有类型的, 对象是在内存中的一个实体, 而变量是对其的一个引用(指针). 带着这个概念, 来理解用C开发Pyhthon模块会更加清晰.
+
+一个基础的python函数其底层C函数的基本形式如下:
+
+```c
+mp_obj_t some_function(mp_obj_t some_variable, ...) {
+    // some_variable is converted to fundamental C types (bytes, ints, floats, pointers, structures, etc.)
+    ...
+}
+
+// 其中 typedef (void *) mp_obj_t 
+```
+
+某个类型的变量被传递给函数,函数将结果作为类型的对象返回。基本上,该变量只不过是一个8字节(地址位宽)的内存段,所有具体对象都需要进一步通过该变量进行进步解析获得。对于Python对象到C层面的解析, 有一系列宏可做判断.
+
+如果我们想知道该变量是否是一个整数,我们可以检查布尔值
+
+```c
+MP_OBJ_IS_SMALL_INT(some_variable)
+```
+
+存储在其中的整数值可以通过调用下面宏获得:
+
+```c
+int value_of_some_variable = MP_OBJ_SMALL_INT_VALUE(some_variable);
+```
+
+在C层面, 想要返回一个整数给python, 同样需要C-->Python的编码:
+
+```c
+return mp_obj_new_int(value_of_some_variable);
+```
+
+更泛型的类型可以用宏处理,宏将对象作为第一个参数,并将指向该类型的指针作为第二个参数。现在,如果你想知道,是否是一个元组,你可以应用宏:
+
+```c
+mp_obj_is_type(some_variable, &mp_type_tuple);
+```
+
+判断变量所指的对象:
+
+```c
+mp_obj_is_type(myobject, &my_type);
+```
+
+还有关于用C添加MicroPython模块以及对象的相关方法参考[micropython-usermod](https://micropython-usermod.readthedocs.io/en/latest/usermods_01.html)
+
+## 3.源文件及代码介绍
+
+源文件列表:
+
+| 源文件 | 说明 |
+| ------ | ---- |
+| rt_ai_mpython.c/.h | 该文件为`rt_ak`模块及相关函数主要适配代码 |
+| moddefs_rt_ai.h | 该头文件为模块声明文件, 该头文件被`moddefs.user.extmods.h`包含, 用于导入MicroPython |
+| qstrdefs_rt_ai.h | 标识字符串, 如python中所输入的如变量名、函数名等用字符串进行标识 |
+
+### rt_ak Module
+
+C层面使用键值对的方式来描述python变量. 键为python层显示的变量名, 值为变量的值. 
+
+```c
+STATIC const mp_rom_map_elem_t rt_ak_module_globals_table[] = {
+        // 键 对应python层面rt_ak.__name__(变量)            值(字符串)
+        { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_RT_AK) },
+        // 键 rt_ak.model(变量)                    值(对象)
+        { MP_OBJ_NEW_QSTR(MP_QSTR_model), MP_ROM_PTR(&py_model_type)},
+        // 键 对应rt_ak.ai_find()                      值(C函数实现)
+        { MP_OBJ_NEW_QSTR(MP_QSTR_ai_find), MP_ROM_PTR(&py_rt_ai_find_obj) },
+        { MP_OBJ_NEW_QSTR(MP_QSTR_ai_init), MP_ROM_PTR(&py_rt_ai_init_obj) },
+        { MP_OBJ_NEW_QSTR(MP_QSTR_ai_run), MP_ROM_PTR(&py_rt_ai_run_obj) },
+        { MP_OBJ_NEW_QSTR(MP_QSTR_ai_output), MP_ROM_PTR(&py_rt_ai_output_obj) },
+};
+    // 理解为rt_ak_module_globals 注册到rt_ak_module_globals_table
+STATIC MP_DEFINE_CONST_DICT(rt_ak_module_globals, rt_ak_module_globals_table);
+// 定义一个模块
+const mp_obj_module_t rt_ak_module = {
+    .base = { &mp_type_module },
+    .globals = (mp_obj_dict_t*)&rt_ak_module_globals,
+};
+```
+
+关于MP_QSTR_xxx,  MicroPython使用字符串池的方式来保存RAM和ROM内容。这避免了必须存储相同字符串的重复副本。这主要适用于代码中的标识符,因为像函数或变量名这样的东西很可能出现在代码中的多个位置。在MicroPython中,嵌入字符串称为QSTR(唯一字符串)。例如在python中输入函数, 并且使用关键字参数时如`add(a=1, b=2)`其中`add` `a` `b`都是作为字符串输入到python解析器中, 在C层面中使用`MP_QSTR_add` `MP_QSTR_a` `MP_QSTR_a`来进行匹配函数名和变量名, 使用字符串标识的方式避免了在C层面多处使用`"xxxx"`的文字池.
+
+QSTR值(类型为QSTR)是QSTR池的索引。qstr存储它们的长度和内容的哈希值,以便在重复数据删除过程中进行快速比较。所有与字符串相关的字节码操作都使用QSTR参数. 例如在MicroPython C代码中,任何应该被嵌入到最终固件中的字符串都被写成MP_QSTR_Foo。在编译时,它将求值为qstr值,该值指向qstr池中“Foo”的索引.
+
+QSTR值可使用工程跟目录下的genqstr.py来进行生成.
+
+### Model
+
+```c
+// 类型对应的C实现
+typedef struct
+{
+    mp_obj_base_t base; //每个python对应的c类型的具体实现需要包含该成员, 该成员指向const mp_obj_type_t py_model_type;
+    rt_ai_t handle;
+    void *buf;
+} py_model_obj_t;
+// 类型标识
+const mp_obj_type_t py_model_type =
+{
+    {&mp_type_type},
+    .name = MP_QSTR_model,
+    // .make_new = make_new,
+    .locals_dict = (mp_obj_t)&locals_dict
+};
+```

+ 119 - 0
project_0/mpy_rt_ai/README.md

@@ -0,0 +1,119 @@
+# RT-AK MicroPython扩展模块
+
+## 1.简介
+
+该目录为针对[RT-AK](https://github.com/RT-Thread/RT-AK)的MicroPython适配. 建议用户可先对C语言接口使用方法有所了解.
+
+- RT-AK MicroPython的代码实现说明: [Module_Design_Description](Module_Design_Description.md)
+
+## 2.编译配置说明
+
+该文件夹加入具有RT-AK C库的工程目录中, 参考文件夹下的`Sconscript`脚本, `SConscript`脚本部分展示如下:
+
+```python
+if GetDepend('PRJ_USING_RT_AK_EXMODS'):
+    CPPPATH = [cwd]
+    src = Glob('*.c')
+
+group = DefineGroup('RT-AK-LIB', src, depend = ['PRJ_USING_RT_AK_EXMODS'], CPPPATH = CPPPATH)
+```
+
+代码加入编译需要开启`PRJ_USING_RT_AK_EXMODS`宏.
+
+具体配置方法示例:
+在Kconfig中加入`PRJ_USING_RT_AK_EXMODS`, 配置语句如下(以K210平台为例):
+
+```python
+menu "mpy-extmods"
+config PRJ_USING_EXTMODS_MISC
+    bool "Enable MPY extmods"
+    select PKG_USING_MICROPYTHON
+    default y
+
+    if PRJ_USING_EXTMODS_MISC
+        menuconfig EXTMODS_MISC_USING_K210
+            bool "Enable K210 extmods"
+            default y
+
+            if EXTMODS_MISC_USING_K210
+                config EXTMODS_K210_LCDCTL
+                    bool "Enable LCD Control"
+                    default y
+                config EXTMODS_K210_DVP
+                    bool "Enable DVP Camera"
+                    default n
+            endif
+
+        config PRJ_USING_RT_AK_EXMODS
+            bool "Enable RT-AK MPY module"
+            default y
+    endif
+endmenu
+```
+
+## 3.RT-AK MicroPython函数使用说明
+
+### rt_ak模块
+
+RT-AK的所有python函数包含在`rt_ak`模块中, 使用时应`import rt_ak`. 在python环境下使用`dir(rt_ak)`语句可查看模块所包含的函数名词.
+
+#### Model对象
+
+神经网络模型对象, 保存注册到RT-AK中的模型信息, 以及运行环境等.
+
+#### ai_find(name)
+
+该函数通过一个字符串类型的名字, 用于查找一个已注册到RT-AK中的模型. 若查找成功将返回一个`Model`对象实例, 否则返回`None`
+
+使用示例:
+
+```python
+model=rt_ak.ai_find("cifar10_mb")
+```
+
+该方法对应RT-AK C接口`rt_ai_find()`
+
+#### ai_init(model, size=0)
+
+该函数初始化一个模型对象. `model`参数必须传入, `size`为运行时需要的内存, 在K210上指示模型输入的buffer大小. 可选参数. 无返回值
+
+使用示例:
+
+```python
+model=rt_ak.ai_find("cifar10_mb")
+rt_ak.ai_init(model)
+```
+
+该函数对应RT-AK C接口`rt_ai_init()`.
+
+#### ai_run(model, input)
+
+该函数执行模型一次前向推理, 参数`model`为要进行推理的模型, `input`为模型的输入数据, 无返回值.
+
+使用示例:
+
+```python
+model=rt_ak.ai_find("cifar10_mb")
+rt_ak.ai_init(model)
+rt_ak.ai_run(model,img_888_chw)
+```
+
+该函数对于RT-AK C接口`rt_ai_run()`.
+
+#### ai_output(model, index=0)
+
+该函数返回最近一次执行模型推理的输出结果. 参数`model`为模型, `index`为要获取的输出索引. 返回值为结果的`list`对象.
+
+使用示例:
+
+```python
+model=rt_ak.ai_find("cifar10_mb")
+rt_ak.ai_init(model)
+rt_ak.ai_run(model,img_888_chw)
+predicts=rt_ak.ai_output(model,0)
+predicts
+
+# out[]: [0.0, 0.9, 0.0, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0]
+```
+
+该函数对于RT-AK C接口`rt_ai_output()`.

+ 14 - 0
project_0/mpy_rt_ai/SConscript

@@ -0,0 +1,14 @@
+import rtconfig
+from building import *
+import os
+cwd     = GetCurrentDir()
+CPPPATH = []
+src = []
+
+if GetDepend('PRJ_USING_RT_AK_EXMODS'):
+    CPPPATH = [cwd]
+    src = Glob('*.c')
+
+group = DefineGroup('RT-AK-LIB', src, depend = ['PRJ_USING_RT_AK_EXMODS'], CPPPATH = CPPPATH)
+
+Return('group')

+ 25 - 0
project_0/mpy_rt_ai/moddefs_rt_ai.h

@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-02-28     liqiwen       the first version
+ */
+#ifndef RT_AI_LIB_MPYTHON_MODDEFS_RT_AI_H_
+#define RT_AI_LIB_MPYTHON_MODDEFS_RT_AI_H_
+
+#ifdef MICROPYTHON_USING_USEREXTMODS
+
+extern const struct _mp_obj_module_t rt_ak_module;
+#define MICROPY_RT_AI_MODULES \
+            {MP_ROM_QSTR(MP_QSTR_rt_ak), MP_ROM_PTR(&rt_ak_module) }, \
+
+#else
+
+#define MICROPY_RT_AI_MODULES
+
+#endif
+
+#endif /* RT_AI_LIB_MPYTHON_MODDEFS_RT_AI_H_ */

Some files were not shown because too many files changed in this diff