From 0853c2d60762aa149b3fe129b6e6dab81ddb6bd4 Mon Sep 17 00:00:00 2001 From: SEEKFREE_BUDING <2289331269@qq.com> Date: Fri, 2 Feb 2024 10:56:07 +0800 Subject: [PATCH] =?UTF-8?q?V3.2.8=20=20=20=20=20=20=20=20=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=87=8C=E7=9E=B3=E6=97=A0MCU=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E9=A9=B1=E5=8A=A8=20=20=20=20=20=20=20=20=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?SBUS=E9=81=A5=E6=8E=A7=E5=99=A8=E5=BA=95=E5=B1=82=E9=A9=B1?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../E01_gpio_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../E02_uart_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + Example/E02_uart_demo/user/cpu0_main.c | 2 +- .../E03_adc_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../E04_pwm_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../E05_pit_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../E06_exit_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../E08_eeprom_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../E09_timer_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../E15_fft_demo/libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + .../libraries/doc/version.txt | 3 + .../libraries/zf_common/zf_common_headfile.h | 1 + .../libraries/zf_device/zf_device_config.a | Bin 39956 -> 98860 bytes .../libraries/zf_device/zf_device_config.h | 6 + .../libraries/zf_device/zf_device_scc8660.c | 369 ++++++++++-------- .../libraries/zf_device/zf_device_scc8660.h | 37 +- .../libraries/zf_device/zf_device_type.h | 1 + .../zf_device/zf_device_uart_receiver.c | 134 +++++++ .../zf_device/zf_device_uart_receiver.h | 72 ++++ .../libraries/zf_driver/zf_driver_uart.c | 49 +++ .../libraries/zf_driver/zf_driver_uart.h | 1 + 177 files changed, 7857 insertions(+), 2913 deletions(-) create mode 100644 Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.h create mode 100644 Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.c create mode 100644 Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.h diff --git a/Example/E01_gpio_demo/libraries/doc/version.txt b/Example/E01_gpio_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E01_gpio_demo/libraries/doc/version.txt +++ b/Example/E01_gpio_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E01_gpio_demo/libraries/zf_common/zf_common_headfile.h b/Example/E01_gpio_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E01_gpio_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E01_gpio_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E01_gpio_demo/libraries/zf_device/zf_device_config.a b/Example/E01_gpio_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E01_gpio_demo/libraries/zf_device/zf_device_config.h b/Example/E01_gpio_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E01_gpio_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E01_gpio_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E01_gpio_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E01_gpio_demo/libraries/zf_device/zf_device_type.h b/Example/E01_gpio_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E01_gpio_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E01_gpio_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E01_gpio_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E01_gpio_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E02_uart_demo/libraries/doc/version.txt b/Example/E02_uart_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E02_uart_demo/libraries/doc/version.txt +++ b/Example/E02_uart_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E02_uart_demo/libraries/zf_common/zf_common_headfile.h b/Example/E02_uart_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E02_uart_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E02_uart_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E02_uart_demo/libraries/zf_device/zf_device_config.a b/Example/E02_uart_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E02_uart_demo/libraries/zf_device/zf_device_config.h b/Example/E02_uart_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E02_uart_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E02_uart_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E02_uart_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E02_uart_demo/libraries/zf_device/zf_device_type.h b/Example/E02_uart_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E02_uart_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E02_uart_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E02_uart_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E02_uart_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E02_uart_demo/user/cpu0_main.c b/Example/E02_uart_demo/user/cpu0_main.c index ae07ee4..d93d56d 100644 --- a/Example/E02_uart_demo/user/cpu0_main.c +++ b/Example/E02_uart_demo/user/cpu0_main.c @@ -80,7 +80,7 @@ uint8 fifo_get_data[64]; uint8 get_data = 0; // 接收数据变量 uint32 fifo_data_count = 0; // fifo 数据个数 -fifo_obj_struct uart_data_fifo; +fifo_struct uart_data_fifo; int core0_main(void) { diff --git a/Example/E03_adc_demo/libraries/doc/version.txt b/Example/E03_adc_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E03_adc_demo/libraries/doc/version.txt +++ b/Example/E03_adc_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E03_adc_demo/libraries/zf_common/zf_common_headfile.h b/Example/E03_adc_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E03_adc_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E03_adc_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E03_adc_demo/libraries/zf_device/zf_device_config.a b/Example/E03_adc_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E03_adc_demo/libraries/zf_device/zf_device_config.h b/Example/E03_adc_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E03_adc_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E03_adc_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E03_adc_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E03_adc_demo/libraries/zf_device/zf_device_type.h b/Example/E03_adc_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E03_adc_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E03_adc_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E03_adc_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E03_adc_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E04_pwm_demo/libraries/doc/version.txt b/Example/E04_pwm_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E04_pwm_demo/libraries/doc/version.txt +++ b/Example/E04_pwm_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E04_pwm_demo/libraries/zf_common/zf_common_headfile.h b/Example/E04_pwm_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E04_pwm_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E04_pwm_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E04_pwm_demo/libraries/zf_device/zf_device_config.a b/Example/E04_pwm_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E04_pwm_demo/libraries/zf_device/zf_device_config.h b/Example/E04_pwm_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E04_pwm_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E04_pwm_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E04_pwm_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E04_pwm_demo/libraries/zf_device/zf_device_type.h b/Example/E04_pwm_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E04_pwm_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E04_pwm_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E04_pwm_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E04_pwm_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E05_pit_demo/libraries/doc/version.txt b/Example/E05_pit_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E05_pit_demo/libraries/doc/version.txt +++ b/Example/E05_pit_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E05_pit_demo/libraries/zf_common/zf_common_headfile.h b/Example/E05_pit_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E05_pit_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E05_pit_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E05_pit_demo/libraries/zf_device/zf_device_config.a b/Example/E05_pit_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 zcmeFa3w#vS`Tsw&mt=DxS;9p`)a4RHgx%p%KsJTR29zSjB}PgqCE*eTi)4Z|-c56B7E~@=XeNN?Zke&*)*185 zZ=0EVDv|cQTW+PKt7pi<&6zj9Qkgw}(99&kXLWgU1*9Ae9weoT?8S4+XICzoH>*;_ z=neU@v$K7&N(7jw!@mQP%}tHc6jWBYgARGsx)7!GC*lRQk3}> z#*t^J;vt})@_f=+5$KDLFFf#t2fpyY7asV+17CRH3lDtZfiFDpg$KUyz!x4!>j7K& zYDLliI7U%ctr{J?g&2A4SMv4Y`Ew0TiP`8(MsG8U4Ek^hJCAJpQd2LW56N@|rWY_W zc23FWlSiBuE2~y{+BP09Qk57TB;s&dOJWzo`j+<-_BXbCkg&hGv}!)u1(Oq{b?f{Nxw9n9DU`t`x@jrxP%J?Onr2mRWh_m&(e z>fjetbNAuda~q!7?1)5r6xoXY`?cJh+C*O3_PP$=K03bxw-LjeS!edTZn)mlxT>GN zw5VS~Wv(rS^AXpLxXuZVLi?4=l+kTD5!7zD+|w9!C6u;3uERT%W81^2##Sv$O7+Yh zmp^h5#fJGK(nsVtB0D8wWK!`FnGNX@dATPh8Gq~0whce7Im5mxf9+S1Xw6fR5mVTI zPbvHJ?{B;~$p_8ck`0fPy%$&=4cITwK7L)BY8$RpwfXhSm2jIQLZ6A&mDRS}70%C0 zq~6|IDE2e=KXWmYMr+IR>~>w3uiDnfrBdbz#8{EXS-!ol4Q=f$x9p5xc_VXlTUH{6 zWoOR#dL|t?l*6{7f<&H;5aBkbLLpBUWwh(ks!6o+v*oY3J%8*AGw(h3x&oK8AEw6I zV<>Ao{AKcoa`?+hIcOVAUZNbdjc!YygG-ei>3x4a)s=h0>VK8rDRyN;>>v6(@)WhF zB%fcO2P;tjDMY&M8@ zrVO)b=6Zd&EvOi=w)z`YJ=%qPe6+Le5#zIu?JvgXP}?t!&oQ?9jL$L|L)jV1k8#C} z&Q8^MjP>hXjr0Bp*^QT&c8u)UrG_m-Wu1w;j^+3p6+NMxXm)XG{uZK@A;FDz8%J)t z?ys_$@p#B?P)%F2>(LtxB4~#=UNGY@Mzu8&e=Juw%jRz&%P5_{ku0Np{y14i3H>d( zi8$KJ=x!Cf~2*=yY8&bJ?0rbtTG2IZJq?1#>3a9nV2pj((H#W^3j-8qdY# z{41AiIsfVmdN#wb3k7JdNt^a zL0sYS1L&JUe-!lXpzj3z1+wiI(Hp&9rax)7vRzAW^g2p^QvU$# z(_m-N*C&$CW1B07UIRcML$>tQII^V=Cxbo}^!cDyfxZOvDClcJuLpe-=vzSF0s1b` z_k-R7`Wv9X1^S1ee++uAt-ZW%vSoQap!We?W4+My+fdepJ&|nb|EbLMGMVYj2zxH; zf}hX2uvfA!m^G{m`$5n*fWC=!?o9OB!n&}x1HTjaeXNVLUSM6=hk<_;_@k_gIFGR| z>{FmC_I5p+Y{}<=-UD%yMGdN0!t(^wbw&8&+&FJN8R zHNf8v{BqVsoGV!u_Jg2r0DT+iJ3xsN35%jH~H-o+h z^!=c>fKJP_M0q~|-9;Ni(hs?0OFwi6{W8$|fZh*uooqRljsrUg_7t!yz@9_4tkavx zmTjp9n8nNpA1+}=*vo)f3w8t8TflB4Tb6e#*|NONpzi_w1+rzij)46(*dKs>8tjbB z_O!CemT47`E#vG1wioOXU^H%Fmu#6<8`(0gkAQK}y&VDBbd#=nnQ=3x}sG7r}PQwny}#w!cClG&8lD}-GKTKVvPLiqY~+;xDx zQyDL>t{3F`)2woe(yzH;?PKPUuRgL|4zgvrvRM~>B#(7r8*3tQT`<-}!tMw041joy zHIWEwtcip@68KTTmys>o^AupF0dq6xy!MfKUPQJG8v&*km=(a(gUzeKc8|2jBRze1 z2<*3CPy6j>V88wP_FcjMsQvc#ZwSga)9yQ!#rTFKI@H`dkjH+V*7#kFwL0y*@TWYJ zmNfSr8q7WWXtuG#oi^U+?4-E*;1TZ|;j!4$zp_2$q_bs7M>R=Do%zUil?>?@Ia_tF zN6Bw&h{@yTZo^%3BhPGdM55h`oc@^0QJ(einb)$nuazNFO4}m+A_;#aMTyyHUna}g zg-B4Xq_yQs&D_WH`CC3iresi>$=;zpkz8u3 zk>oZ=A*_C2zZWLOOn$fcioKr9kk^x$l>SJ2qvl?4!fz2$lFL9lss4CovX5FxYqj{T zjX6slE3|(aN!BP2#>gmBq+L=yBRTdK+JO~&kCO7YrfShKekCs{WV9^V1JT(jZIgPV z-1SYw-9W7~rXtmTO0r1pha3e`YVBqi=7AEl&KktXIg`7J@B z_0q1r#YgUx)IAhaLvs03ycS7mr!i72bw>T!5|6(zC0v{+PjYJhIMsH{GK#dMw24-t zDw4hAZ%b)i3Vn0aW{Jy9-`^zXmA~If8QWc{J)z2F^Jx zs=-pCUJQ$aJVSaQGeH>UVBPCji- zj@#doLbVbVv($fE3Z+n)t#P?iJmVqC8dpmS)k;*vlCQQDN+Hi!<8r6?&qI_oE-i)9 z)6_*UrQfCN!Rbd3OTMVaD?8* zswg9xQ{?dLj>h&GuAk=9=C`(T#Gtru6>|v@_w?)JIe%P^CPg`@`Qyp+AIP6MD~r>; zNAh|izGq+19z&yS%MdGRG&fGZR#J=eD-BLc*^Fbfd9TdeWQtp%61OL)>n)Th)oa%e ziX@oPer2Gt#C|xtC~=S0GSWJmcUrV`Z7aGM*?d#iI<^&c0A0@^o$l9YDY6}INDd)l zZ@*80V$WAb)BOv6j@|C3xF{ymThwP#?y93+lQQ3?7S*15n%O$FulDmPp<{41-CVx` z&!>cLlr15VYib+*R(oDE{ccs`|6EpRrS-&^r~O6W+3_MT+6mKfb1VfA}M`<)TX z(xuUe=Tp*%r=-zBX;}Tb!LUV2h(vnXrQfq9aDakzt>c$uo*PeMTf4L(2 zRdfv3%Btr4Ny$p$sLUU<&IsD?rCD})%FYA%kHVUxZ|d2WPd!U3%1;T)Ys*M-+5Eh= zY_weSt4LEUErjN^DXTl0*-EWwa-zJ_AMdTYTtACXXl9VoJ5!XZl-U*SaSE$9*ihefw#}l~QtAbI}|wxh?Uk%j%)VG#by>t*ic)r1;Ew{_(LM7XLM! ztv&f0c@<{XP7&X;XY>rw3Y+rZTXp?ez3!nak7B9o)Lx;dp@P=FLw({)Nuv?vD&hMd zTYV2b$n3|hynkS6VQs8g{H)NZV67vaTd`%v<4M`I`Iqhf_#>27@+cTf8O<6}n8uVG z#(BRaH@RK4aCt4`R%=SgwlpCX-tSEgnKJ6qwVm#GOiq!n?iH3Xfv)A2{j4gYEcHdP z7bdj;8ksD9q0xx$@JmjQ#~^EZJO))IUore{(lkq3^^m4pW+EDC9?STub9|PT6eKNT zX>k=CU$W0=%||{;zVh;D56H&5;bzzgl6{k@N4b0Zt;pj zb);Fm;wH_ypX}lKwe&2Fw3x+HI)}B4TtU*TBUc4!){(1^N{qu=w1$*j z#73g5Gx9iT*72r=vZvNyte%Q+Sc|7@3y4jCauMi zXAfx=mON{$S+2Y~$7ktTLDFPJYc zveZnBQb_JK4MeqCs76j9x$IP?q!kx^ZyQg}J$-MRv@VIxwj9@3L-1V{w9Aq_L#Mkc zlEd+xDi($As7Q$`o+d8(4%!luR(=+R*L^8@p!$j=m!Im`+Ey#L)mU<0m2!oOrGztD zswG@wO1Kt^z0K0cxlLNy8h^8vGD5qlOtUPq6JBd zSV~rrCTtaH)^RzOCTs&~9!q?UX~NR}fM2nURTZpR!d9ixBBVtu<%p%x8aS+lYh=!{ z!fc`ZS+1BVS6=?^E2*#e>ANq>6^Ot2N@n<*uL?^J-10k_#Jt=1<}10}*1k(CU~Am8 z+ePpqviHAQJl zQ7S0zR_O${Zt-MvIZwnB2Ggjm%kc8fVVZn_5V-%=e;0WjnWR zkiUvS_ZMHG7%vCCyM)cpUrOB#dJoV&pd0rci?GIh$HL}&jb%I|fDeFv4d@eD?@Mp= zDy2V{u=)8*sZR%e4(NP8vgG;sOUd*7$WmVddKC2Kpsxg-pTCsxtOtDq=o>+A1br*$ zyFhOSeLw5MS1qgy`(?7_@1Pt3rWKf@z#M0rZ?LAm@;6d0aF3YY+!B%rV5xE zU={;oJXb2pZah~i>}9~LfOujM&pKe%1M?s-4+FCqm`8!x2FxC|h0osv{%zpfm|1H2 z^8;W$0>)-*XEMl6)HT_Ox(22jFg<|j2h0FqG+>H=(U}o_b__GZu47&Jb~)?9=I2vo zS=Irw9vFUBRWcia*$hk*>msdftP49%whX(Q8IkT@W`unJm_xwu^Q@A26PUMwc^8FS5S(o+By0F)fEz@1cjNsQZBW!*yR)*ck zx(M4ywhX(K8NqL7M%c~3>;YyUF#PPSjEA3{mGQg^%-g`c3rrg@r+`uD!YSi%kS+6* zN489>02qEAS27-8_!(RoPd{Mz8C)692w;kUxdxc=!0GOek=7|-kqzZuW$3VS{< zRS=Ky{H|akz|;b>jBJ?}Kff#UTo23xz-$C&Gcb<=vjdo2z%&E%0x$=FIRs2AFmD3G z&-ltbe*nx!z?=fcLC>eka=G}qRpFCder{FR{Oqq}x&w0=F#UiT0E`CANMMX-f<^qs zGr_{1089|#;b($nex?I66PP)`Q~|@!1j};W4on1?T40s|vj&)Tz^n)6VPG}^vjv## z!0ZGj4$OXFT7WqSOe-*N0`oR7{LHbeuaAH^1&kx3opF&Z{bM|rEbAQ@;~8b48_y^U zyFV~qh-Wa_vc5(E69DEKV1mGu0mIKR%Xlh)nGMWbV5)&x1PnjZEaRyIW;rk`fmsjC zgTQP6#(36Q%v&0PF`ji6{@Dfb7|%Tm-FWU<*e$>ugm_*iTju#qVEB1xSzqr0^C2)F z19KV}S7v*?=aMbsag#06>JH3h!1Myfcz#-xeK0V?fYHg8?Qje*j~2Fwm%_5iaF7=Aum z#`7{TM}TPs<|r`7fH@A#DPR;=yAK^?%e35N%d+$H+|tk8fbjs+2bg}q3zSz)U7v=4UD}{EWEFv+<0$h-W@9RlwXywu~nNOf4`gfms6#KSwUp+5pT( zU^WBO1Pnh@E`7KI7=ET)=7*mtm&|@(UIyj}Fs;BG1?Ctq$ALKwjE$cozrtKYW$<(4 z!p`Go$Au3Ifawa%Wx(_ThM!rN@fgpni+F|s!_TivW(?Uft#QCi0A?~UQ-PTd%v@mR z15*XeoxntZsRd>QFfm}(0`nj+8-UpeOd~K`f!PksZeaETvmcm4z#InVRbY++a}1c{ zz?=rgmJRhzwyX;`*|IJ=1JezdKEU(?W&kk5fEfwQC}73|GZC0lV5R|60nBV*s(`5h z=5}CefmsI33Sia&vmTfSf!Peqqrfx)vlEy&FuQ?i0p=huF9Y)iFmC~K6qpZz`52hf zz_{o?_{ciVC0q7)H`%h@djR7BrVlV)Ucy2r$cmSqaP*c!127wbX#{2~Fx!FI4a{C(_5*VWn8U!l3d~VpjsbHVm{Y(g zv`H=N)IqkaQ#aYN-a7-+4VYfQ^aZ9rFvEZu3Ct*9#sM<{m>@9IfT;jxHZTi-sRm{d zFi~LYfLRXAT43sdc>tJAz-$4g5ttpo>;k44m=}OK0L&p^T7h{Jn74uX0GN+}IR#8c zhxR(nCR^5f9@(Fuj234~&8mCOix9qS^_^{fl~VX|fXn}K;0m>t0E0;U<5eZaf`%mHAI0Mp8h$lIID2>V^u zMc&$27xu?w%X}*IqcoCnkS!TE*^=oDOgCWqurAW-$GWhGkuAfHWJaVriWy;#XI=0U zSr_&+vSru`U}gie0Q73mqoCJ;z8>@kL2m+m8|eE%Zvnj(^fy62#kwe$lHXp&T(V_Z z++<6pGcX=t`T)}p7>#w|pP{S^TPIt_KZY5RhjGjZJIK1=%UBoobh2gGnal`&4l}}D zz`Ee8Sr_&avSrvPGlH*UM%XJ^7yKI5h5Z28GHe4gf`6D9VLu8?6ENF=X$EEwF#CWx zz`98H5bMHzgKU|Hx0n&>9%V+@$5|KrhpY=*p)XTqSO?iMtcz?Jwg8x}z;p+uFEIUq z@d7gfm?B_wU?u<)1f~p_>A=hcW)3jbz$^l0F)+2jECXf*F!jJZ089fgn^+hA+`_uB zx05Y>yOSAF7jb5Uy_a>t?`K`uhsc&;4>Ke9SD6v^TdWKIDC@%hkZc+DV`c<@ni*kd zbZifsO|}f%nQR%h8#99M!Hlr`0@EKDFEAs483jxLnDMNOJWpg@*i*@td6>?ONOvYP z!oHbx!7pH4*te4{!`{h^;3LckdpR&Gfms90gTQP6W+O0-z-$F(J21O}*$d2mU=9NF zGB8Jgc?+1Mz#IeSLts7z<}@&_f_DGpk}dt?CR_TaJ2004(+e0cFoS^^2222$Yk(OK z%w%Au0y7<$n}JyXOf@izfms4f6quF3tN~^nFdKl`2+U?+nt<5`%no371G5*H{lL5o z%n@K(fjJ7yF<_1Za~c?1r}jF{AY0aH0ok%&bOok6FnxjP4~!R>5x^7yqXRPmm>@7^ zz*GP;8<@GkQ~^`NjO^pg2s_HU=+||u3ws6G@*a=1z|;ftATwf5Yy&VGfoTM0D=^!E ziL);9vzv8czd*K({{S;0Z-_N%N5{tecJ{Vv%uEdBI-BJ2muh_I(v7d-t0L?Uc9 z*)nV%*)rV%W<=QTtc$Rhu`cX>WXrGvm=V0jjIfJ<(SaEQOc0ndV5R^w8<@Gk%m?On zVD1Da0?Z0v)&R2(m4a~d1 zv;p%G>!Myxu`X;^m-c+-k}d1VO}4C~ZmbKw2kXM_OSUXye`Z9TdYKXS2w;kU(SaEc z%tT;Hfte1>Okm~!Qw_`_U={;Y2h4I{Rsypgmm}X%1FeCi7j~QVf zU|sm?5bMG|LbhyUZvyi+Fvpk?ZR|KO9|B|R+RnJhmTBdZEz>GsMzrV4fawKHKW0Q) z1Ax(hDFQ|ZW(+VBfhh%MGB7iNnFGwtz|;V9J1}t0E0cIaCF935Gm{);$1DIpL90%q@U~Ke%FJzuG$d-A|CR^sY zGcetN=>be%VEO~&1!e>=MZoC5j0a{SFr~mu1EvC)*}yCSrW%+w$R~m`%WJ0cIO8JAl~*%syaV0OkNNuLAQ1FmD0V2FwS*d<2Z6TYK4EWXpQb zC0o{eH(+`I;{m20FavVbIxm;`5pFb9Eo8JHu$yba8|z_bB#3K-?$_BwTtE$h@xw(Ren zf$0WJA7J_cGXR(oz!U+a12X}bATVXXQ~)y@n7P2z0CPJqcLK8vm=(apfO!Cz24Efr zhW_zj!arM?5o7yyW`y0$x){&*urBNtvZZei0`oF3Zvyi+Fz*8M5iqBKQM$LMl}olv z%T2b-PiJ5}!1Mv8A236K839ZYFynxk089{=X~0wfGaHyHU}}K59hh2RmI1Q@n0jCy z0Hy($ExS12YkrQedV7GZUCOz*GaX2$;pd)B&>`n3ce+2j)RwHURS| zFipU01Ev|6J;3Y(<`6K4fq4~}qre;k<~T5?fw9qpK(f9v$d+S50ok%ny909>F#UiT z0E`Aq5imM1V}J<)QwGcwU}gg|7nu3L+z!m0z(jyq0Za^-wZJq0^Dr=*fY}Pnc3^e_ zvlp2Cz_b8!1ejJ}-UOx%m=A#Y2pGqu?e*m%Th?hV*|JW%0n-B*4=@9O(SR8Wj1J5g zV8#Jc3e03+rUEkun45uF0L)@wmH-n4W+gCdfLRC324FS$OM zz`P2~8^F8;%yD2o1mS3o#v4(>$E#CmjTlY7%wn`ff)u&0GMll84t{4 zV5R~y9hjSeSpZBmFn0nI0j3t17%*#rsR!m^U^W4>1(@x?>;xtb%zj{6fH??ED==>Y z^ENOa0P_(rr+{%?-d?AEQA9554rnF7o-U@Cx_ z4@?y>HNZrGsRd>kFl&LS2j&4_HUYB*m_}f>1G5vDI57Kwc>$OMz#IXl6__`HX#?g1 zU_JuI;c2f^7um8-bIF!<+7+1Yz+47QKVSv`qXAO{j1J5gV1mGu0W$@dnZV2e=4N0P z0kasGCBQ5LW(6=YVAcckATS$%c@&r?V739%49p&2_5pJcn3sV$0?b>$90leWFdqYR z8W>y8_BzcYTh5UR$d>iq6_{SY^aZ9rFvEZu3Ct*9#sf1Em{MS-12YqtIlxo{vj~{Q zz|;Y=9GI2BtOw>nU^W2rC@@XHYy+klm_5Mk1LhDghkQlFh_wo2F!6_P6K1>4RuO(qE5+9 z)G09Cf$0TIUtszJGYpuKz>ETBJTMc1DFtR4FcrYe2Br#_8enb*rWTlGz^nkK9+(G! zX#i#mFpa=$1!fm8&A{vd<^V8lu%yeL80^YG4)t69uLYnB~B%17no3JS*HbL%R21}OfO*i0@ELu z!N3dyW+X6UfEfqO1YjluGZmQWz{~|^J}_0l+zCtsm|9>~0<#8~b--)@W+O10foTF} z8!$V7*$vEIVDokLGS*HbL%f8$dnC`&z0j3`?1ArL@%t&BH z0W%($iNKTsGYyyuU}gie0GMiE76B6hrWTlGz^nmg9Wd*G*$B*LU>*f#2Qa&UX$EFL zFfG6w1f~_3H-UK@m=A#Y2$)mAxcax(X)f8aFT2T>_1*&*4={az(SR8W%m`p~V8#G5 z4wy1vrT{Yyn7P2r2c`;`JAsJ+Qwz*WVAcS$4wwdD9tLI;FipU017-&>&A{vdW*;zz zfH@4ztH2xu<`^)?fjJF~?W*=V%^+LWX#v@Zz6?xvVEO{n9~dt%BY_zOOaPb(z?lCF z+%|5tlK7w5V{f5d7CILHn`ps8`hU`GiSzQm@toy9@kG=9cOu&f5vTcI2jX_!qO_za z^xL8qrj37D)bd-6{L7+^mfvcu;@|YN{F-uvH0yuBh_!1)iT|{h`0q>qlK(bj{lC=w zUjWIw$-lnZVErxE_Ft70wMF$K$At{CWgDW$+!AewZlO=yYeKi@CGIt$ZJ9(^nj$8` z4j|her8jyFr9T<}2(o4TqsW$RGyu#szyyIQ17->^Gl7`{%+0{m0CPJqcLGxf%yM8> z0#gsn1Hd!@vjvz&V73Ai2WB@gdx1F!%*((W0p@LB-UX%&m{Y*;Z%WF#;NO&#b&*T9 ztgmjs@NY^=rWZ3yDKdKX1*ShR{F{=J;op>$Y0@G7#E>`43n_54rxzggB1<)0Zpc+8M~rQ3@Ve)W(o+Z|0& z6AX_Z()WXz5xyS=%t&B(%#h4%VCDj|fEh6+Ee2)@FtyBxw3Y$00+@3d12#iEk3u|6 z5YH}Pnt|B^ObakP9!MYZcp&}L3e20p@Yo=k4}kdy7#C=_c>Q(` z`^YGVN&bcQCCSGe2mNZ;+uOzoAemPq=k8rlew2zf_ z%5_;Cm5z!{8K@q-!>_)w*rANR8=zk0_(hT>Qb56LU_?J`sPfO=(qrtG=YZqMiw#QQuT* zPQI^vtehFW&pv;|T-33 zx=Q`Nx<*~C{z>_-*9JnU_2N4>hNq&fy<#P&ca&shiXWb(3?ex>bEa zX;Drozf#Y9@|dEGP_)0FICbK;YJ*aKM$ykGO5~ROca-p%<`Z*IKK|ZK`QON&ksryQ za`GD|@5--Js`Ky8-}7ELfBs3z`k5C`+>^gN|BStD^!JpNN{oCv@Wj3o&#Ru}pS4H- zlj75Y_1-_^1qauAKej7cTUeof-a>zB#I@lQU%hvSy{GqLMfDz2l%`CdO19Eu_o+d9 zX}vddzv}%H9be&ddY3CsQhxoc-TOa^-qaR$3D)6LXiWGYrQW;sG1c3RXt&QvX@2!N zexLg5dhg%1)_cpE>b*B@tM^{i#3RUUl-^&7bWr+>pWyI+CFP*vcr=G%w5Z|Tq-&K@Y%=?~A_5MMG_2qHcJLudUq!dtC8g*kfiuLlmtbz63r5%h|Ns;9@ z={t#zd9&=Q_fAC}q`J(UT>HG4x22k)lRCp^_ugydtbS+xc4t%ml-|C~SXP;$4fk~^ zb`&4kHD=e59Rt)EO8(^W`MJIq18cWG8|bJxy*Hm6@U-vANRz8qz4y5%dJdeS^`^YB z%{iWWqT9gN!$FPfB)>E>7z|Wt9m)cMCDAuRk)}Yv>FY_fo6bM?gneKIg*a&BA|uv~ z%D70$Da$Nv4U_MleLdvru4^uX_YnV!C(M#Msq`ZZ?~q3*{GCd-f$R(WW|h1%HjnMm z5&H(!r+96|ej`t#&@ULd`>tZfp;A35O?`+z@x0ypd!=KUn!U63uDYJy->9v6r_$Ye zRNwSuX`p1+4FN}XFz|Y~ZBVg(JXH9!%Vo=Mq5N(7UB=EALvMs!*^xlKcZw1FF@@{D zC)IMq`+?fMPcQm>S9J$JA^v^)*MgsfRPEbk9Rq>9Q@*%Y4YZY;;}ee7>s9`R=Kt-N zC-~pt55pOQ^Sv`poX(0r?(kit`KaX%q~i}m{~c;A-|ID*YqWgt!|(0Niaeg->p-5a z{e{ifRU1gHw2s~@5;S@EWY*67?bK(e{BA9W+S_tv-Oe9x*PEPV&pr8|VP}%PL@ADO z-5s&p2XKupQ9cQ^m2amMTf?7Fuf8H!@AdD!lHPy1SEctG_rD&xiauL^^GQh2TFW`a zcJIQVs(np(ce~fTqQ~iT{ClzB$?#j@--maH9}hnij)kM)JE%s!^aS^mA2!;(tCURd zYQ^b&Oc}l7$JzOB?&%S;~ucuY-wu=yQ%k%qFmWDRdW!{rJ0Sv`d0HS*m`~ z!M{Ctsx<2)q(d9nAs9)2Aa#YkL!C3)lu1dS{++dJic}YYXY!HmHzll*h-MV9XV1 z%Av7x--)(SF;^jdI%&?-I-2dTpNNGX3Oyd$9r}IftN7J=_-Lfcr@viU z8^V!r z_P$IbsjBs-a|e|%)UU2>QnZ28n(kDt8ff?a{e;oSVx8&ysS`iq{uaw4`z!AimW_Am zF&BA{dx2ZC`-0>H8kcFj{Dm==-Kk^`bb9BV9B7R7+(N&r^rm=Q2lW(VLWD|e*7+Tw z)kbM6CS?~6TlPWtov<=^Q0ZW;6ZyT%^Vx+%Y7c}<=zkRsq*j05vj;*~(B~h1-M_H0 zE*^d<{EONvgYSi?KkV&a_~`P@%Z@L&D)?;ZrO*fDfo*$R7bs1GeM8Fbs(UZ=T-c#$ z+6Up5a8vlt+OI;B^|8hMT=vd+TU|S&x;xuf*4Mc@Jf`1IDC8gGt|y0RH)I(xh3>lO zT77<(rqHgeTXSN8v4Kf>gLm5QeJHe~&Wz2WtqvXXy%TDfzTIo5UVX{Vir|lT=5B8b z>rL;3uOgp?m114>?p4(89eu;6^d`$)+z=kIR4s0y)?M$N{kxV>X5^tzN9u`>g;csy zs$N>tY_e<5_ZnZQQuv~Kzf|fhtM~4H;n`3dmG{2iIR>hlX;I2F-q~r4u?=q1?1Qx6 za+k~XysI@FX?j2WO1O}6u#ZMb8WrejyN||+(e}78j?%nVD|Ynu9wu!~le@4jq>!%C zv5i`JPx{oGR2n(X3iRm#6tB)2wIzv()2D^%FIc!|yfm zx{%gyO(?qJkx-~~Uf$JZulO!*=t8ZGNB5;_Huc1%sE-%(NnE0j2dD#TIdTBWg!&bw5QfB+H%0J_@Ux%=_o9 zDy67wV(S}a_eG+5q{*faTrs+I9i44{{K~vV6!JH;tGu+|*wV+Th3D`4W?6*#>_d8W zI7&SCTKL zyHxu?oxF9IdX@KXbt;`xR$o=V4&yz~bnVWhHb@`T2?7uk|Yl{IP+q6*L+j2rZ@dKC3LF zUo3EUAZvh);v4BRpcw572br7mA(pfXSrxwR&-2rC_?JE@X%>DJPm1WO{ zBD&I4GG$(HjPJ&2Pu#O2zk_$3x?3OSE1vwly#BtN(ueZ0$#bjJ&PGqUuFRG{FX+@N z%eqkSUa5X{+RFTq#(A!(>&v3~PHkSWvP|>cQrbletQZ?`XjcuWE%{byV1?qnyQGWO zXTaFN%6t#a!&a(~<@KOmzEbTzFfZ>S-$VIb=;-@uCmPRd;w5FxlyYUz5y{aqqB()@ zM2htSx}L63)qt5sZM39z*NR%buDI`&YXiGh{yu#1LnV3+5w-fSi@$m06<3Z8)CQWv zsxSWdrIg3D>W>;!U*z#l^w*8FuD$|Y)z?rvsfn)%x$`~L*ZHctg!($aXAbljNA`iH z+8kn^@2s^^e^IEV{61v!b)mlWzP)(0Q_J+-6#R1JD)N*w;GnkQ4A=%Jnxbt8)i1Bp zBR_Q-<3-#U8!`&J7rqf%6kVrJE}4|~iSMb9Mx&WZvov*3u}g3A1dnSr*C%0BqqUoN zzp^ye8n%;f_S1NIBdyvl{iVC`6B-#?jggT@WzOM#nt`@bJjx{Jly}1Y3-2urO}#hR zsW?M_TGud zw`Dhn;)$a`HubxUio4z0_4RHo-5v^GQP`E@`A+?J z;k$cTamZ1;BHy8P_0=v@ypCdrlh5S)qRR%+8S}{HyURGo9FJT7rP7GFnrA2vsl~?Z zgp~>XdefO}8ZvxKYrkJQE*jN)()mDO8uf3dcQcKnHtj|V^D}i#$Q*+y_xXxu)5iNY zgzhO_t=wHYDbGgNgc1tT9154N&a-Jnl-s3r1?F+^ajmD}(ZS@c$F%~(4ul#LHpSQP zE}EyD{!O!pncMwClyU);C=jxHf39+z1-??Ux2UW0ZCWmsXS143W3Qe3^ZhBVdyDms zB?`?}A5ss7R+TCxBkxtb?h<#&3~H%%Z-d&gyUk}S>`B%;A%)u8>QXnA;l9bGf$M0E z`2DhF(H~5X1a1iEfk53|WpQsa)yPjul}V-gwR(4&Rs2v{wX3@BlW>l9=QEE4-LBVm zR4x1Hndbv9h37wY>ZxC4$HJF{b4ub(e+fSk-bigS=I!xBruTpnr@8zOOI7c0l_=Hg zQ~PtY;iN`Gu~7FyrRjU&&c2OL7e2l1NnYn4Y|QojsOcR_ae>(X&*VU!YV0CyF#nv2uom%aS*&O@tX-!Za`eEt+nO5)3_-${B|3{_q zCdbod`Y)awtG^z$X&Jsa)ur8c|Fi;aZOPpw_Gdy*MIQI~GD3aTuAv3?v4ME(O79EG z{iU6WQM^AWt}Fht&mF!9T^H*@3-dGSx=FG6%4k$B&>RCgYBu_#cbe-T2rEr| z^*lu@vtO%j@^?@Av=6imP-*7eNUi(6-@O=WFh1W1{g{06f)dq(f!qNBn#1)buSlwa zR_{zJURrfhUENiuQvX}4_vx0Q+>m#@?Qg#A-k+5!-U_;ocGy|JlUDe&D*Sor4MnB8 zu3x7_yY_uj-CnG_T|eBey5e4%A-YQH3U!D6@~#0ny*ic!?2+s8KBQQF9CQc&tJLXz zN#WIRC;bP3Vrnn--bbFO_ulh6)%!pIzBSnW&2V*Ha>e?uei52 zg)sLkCe!ZLSDtfgyb|Z}uqVwrd4~Fu(sjFS==j{8-hn5We@U_L>`6N)yo;jC9WZ0I z^D?b%dFB}+t|#TLqqfwg((ci>NB4eOrCk(OZ$3%)#nN~?l~U#XD_*(qZpm{`@LcAg zu@7J`jL@2dcS`=*Kh^uqldheSEqPDTh(NRDXh!^DMeFF(e`fdTt2_9VpXShY?C~i! zU+kg2ojkqGH97qnE79A%zYKPBxppqw*5RT(PfybT< zk__M1^_S~+W^9jaD$dUHMQCO+FgPwh%lAx!!}m-q!}mnlKAKt3Y-hj|r2|Wk58?Ur zC!zO-Q!8<`l|M82$+8xGH(hc6{{AzivB28EeRO4hHkiLGgXTQz0>283+qF>ZKAN_Ysh_pZ&| z3%?s}qn)n7g2Jy=QM#bcKSiaY84<%)itqa`E0 z^+b?!L_T<;ID?=Si9@<)3d_%EXGBjKn?mOr& zwC1k&4&OI8bZh7?Jy6^`TtIcA7fzzQ4Byu|N;Oo9D@YN^WMC=1}LHD@l9qC(o{WGt?4# z%h#E%c%c)f+HK%(Cp!lJGSowzR9ss8oc_!3n-uQy+&4o#?@>w|gMU{xHSe#!E@fHN z8hTMYx1IbX6r8@@>kjfB6pb3;Nj|k{oX^%o`w6khzCV(ZARA&&mzdHcIsMwo>{m*1MFA&l~9*8Kr(i*W|nNbsAmky^rPc z&MWV=@_3Qr<_VQQ&0Gz>CP+lX8C_%#BvlKIB2#8@uDAPU)Nbf>pFuy_&9iuMeI{T=VW< zPJSfxbJyz7b*|SY?+*3O`s$7!>|BxaVkjr;`O?>?PY(Qol-^IT&HhVh?o;o$o_=!H zu1`Xxfj`p-R1%1lzZkT83*YZV^U(Wu-oMrL^!6v~cOK4mZM(N?oOa-5+RX9L+;1PG zxg5NU%j4}K%IhC!OyoU#I~|Rq^-hF#=eK+R9PBw%4MeqPjr}zG9+B3y<7uak&Xl$J z@6um({e?WDXm@GB!0y3U&<@jDB}mu!mqyp>-;Ms+r3daJ_D`jXrU&kW#BmNY-PSGj`sYiRW8No^)~V5axm`JJ^M zS>`Bl?XDlV*3vHJZ72V`EEpJ1GmP!tAgvEe>i$A|w0{mC2*+tJgKJsQ$2oYuciHBb zLY=k8LVxZRr*;0Dp$T~fG`Dz%<}P*ldaNT|w|kStv-6hFC!t2V?&!hy!r6sIb?=0W zhx9UPhjwzbBU#r@X%4N;dS}YbPaSb>ee$uV|7YrbuAWbS_{?oNlXkrqdWY(xEWq^< zFAoM!1P5sy1D}NN&~oS+Y>V_Bq6X}=;})^=HL-W;8?+S7%+_f`K?fa1@cnoauHimMx+r5|2o@!&bigsFi5@DXH z_udk(_kJ_}{{`#4W1jyjyJBgmY@sMp$LEz^@a%dGv^N7Iv z!%voe5*(v%$PNU)Hz>gI$G!C=tH!-0y%-!@Qal1DNno@icsC! zX&>hOGKa=#tM|^#``A}P<^3eY<8fp8v*Q)zmai$wZ7UU}^~{+wFVWv$=-`P{;}q3RmXyahFi&FOUP zCW-FWaJ-ll44BOJ$mWL@+++lFWM--zv%0w!&YE9dHE)4(f&x3}SxVQ!*)vdZxMs|r zU9D`Q)2gkv%Qd@l{*3QPI@>jG-mG$pLV3mv?ly(lGo;X2ab#0@+B3kJc4THP{LaFf z%3H|y6kGW%3l;U!i&c7M*UY=6k`At2#7@ZJRI?U_=G2s%>CBp0ep~gtn#%I(%A4j< z1mu^?%y0=PH1lQ>gWsm`*^(+>FoR>gta=NpvuD)Ipo3K^$8M&Pn+U#e7Nt>LIb${? zarwnY={b7|&Pe9+w8>mv?dHa6R7(fdv49Tp%BgwHuB@t|46AAtDb9$_k!GA3t>oN8 z$C;`+Y%G;}y*XW#$Yl9BT4W9_b=9*KrP@ZqM#ykifd-|yqo6M zET~+#P-fUHssPNQiUYH#;=pBQboRVOGGI1jT|l|6dAH2CsnRTt(DGc|63VG>-!dcN zCAaIA84GTmF~9t_nKHTp(=Q@aXDa5bStEuG)2vQ--EIrh$l|=mXjmC_s**FqLB6L~ z2L189+5CE#{^(k5ywr}W-Bswi#MLQ3a!szAFk2tR?#js@MgMfb?kAJlQNHpOy3jaP zH7B2qjGl^*&SrK}N9OzUug=e*16Kz^ztSlue?%5_7%xR?o*R~bMegX_BDx(b+ew5e zawIu@jYxCb(XVuBhdXpphEc3}U6aDlLX3w_dYnM9si(5CxhZomRh9JPD3>skn#Jc~ zwB@`~Rw=Wxg;UQ-RPd}>GZpm_m0ZG?5H54#C$)5L0 zCG{5&w~=AP8IP%#$T;ZJ=mWw#Mjz13lROO4j)3v{FSh$r^Q6xggw5xF&-TUiMlafT zG3;s7)agzh#r7>l;d>|FXPd(EmFT35p~#j!wy9n|OZZu`S{(5H`ozNANr< z_7nVf>GNvPzby26VuC{7O?H{ke?p&?Lg#qq37z_i!vDXX^TRs-|9Z~PAo^ShI^ToL z`c1@a0DYs-`HHbq=adCe5is@jR(hbvR^4N4^ zhA}#QS?T7cP6ES*+Z;AJss*Y}RZRb3IWf+-Z6r8zC?fW6#!$-{Wkb$+k0;KanTnG# zM*%mgs?(EYQ|xxtIgmb8=Vg54P@PWkc}13s)I#H&p-~8*&>VEendMOIpm7{l4z;f) zg{8D8tke=5sSDHS;XIzZG!CyGgRcHkq5C)Y@;Z>Hg(fyRMu9$af2bl?N7){FU*qA{YQfLS6# z-7|?}K*pFSK%@33Kt~DmF{;9EM4M%#H-S&7&T`|#Y{RZL-fuGAJ912v6b9tjRp)sH z9AHG2XS|;^pph2k7Sp(xuJ25a0Qz6 z!UT0N4$9T!H%@Zv;v>_;)kffN8sJ^30Yp`vJ2=;wM{CWGkp^**@!p-|qdMqd91S#c z<`!aaBSQ1k5cAY^LNXhT$2b~hynn@b_Zsm`G~O$WEKE0YaD!nlH1s;vK)-DqaHmk6 zZhGfz^fF*hUv+-jO!2FR)LRz3W7beQ*VBl>Xp+=4KRp|hjTGh@(cEE#n`6XpW@)Jk z*|=O}qeIp(N`(8O>I@mdx&G|Vbe_K3bSgQV`(3?xBpiNrPhTv{WB8h?5PfZSDH5-2 zFD5mPPcPEK$^+aW0Cf3UZW=1zXT+$g!(YepGWH_1?njAEEoYW80m z!OSjU4z*{4`x`FlO7Gmy`Wn#;GBnM2zf#1KWwbBza@L7yYL!F8r`a!i7<^YAAF1t` zF)^V!&G9!B~-MI3|LkLaA)wT*LhbhQz)JSs{$N+z#2&iM^zasS|S(rLO# z%_PhwDtYrLmqSzYGbxu;gfV)iHO7WNpYGZx9|z}(<_aOCzXG! z5nzhp6C)YY%uFU{M`qPbCjF6FM2xW;CoQhPs`E?c<=d==u||@{rJwvVT;!XgpbW^Q z&BVqemB~EEL$;mn2;ym*J@eB;m>DuEoU$@jv_ms)I7hiKy_d^%MY%}ZhRo#05F!$% z8pjgLsxmcM(dN+%(FkgcqJPII)(X`)xZOBdZ4SXP^MkH=d@-47yg#Ix*OaX$|D<_t zzj?IXJbKX#*J6IWWQspBj|z=gWUkD@Uu$UA9HV2*c44@V9P(v@ce3lrksLiWX|7XR z?p{rkZMjaOjqfu&`Q{g|mE_AohGc9s*Z=%3`Dwo`wD8vIN@LTFb~btC|08?amH&L+ zu;Q};>4wAtp9N#RJJ>vBtapc+wz1wFV%oUgHP*Pa4&(Dj=+7n=&#l7VK%Z~2Jzr7y zlw9xfdd^tylFl!FhEIm&^(NaK_A^`0Ddu`k;YHnfZU;G?iRIgRYG}QT9@3Y4IyJ%( z#)xQ6=7t#!GHCQ@p48LeD=(@2j6fp|*j#;?N#7FI)%mW%L)p zxIWkYg|^s5FWH{Hmk^+++wG#k(*}XLm$lt~opc8D8l%tfL%sAe`pgK^Hu}tP)5bpY zJW0HF!RHUK-NR%K2|JrUc~8VfKM=w0{%^Jg|Blc(+P?{%`_kWqP9L<-*&Zi-!(znG zaen4~X(~l}zI~}zqAxv3O+D8fw2ci69>P=Gr0@;4NiK_g8EsN9AAauIq}-EF*|w#7 ziMfQIzHPh0VcoV};kZURCec34ZChh&bCpB%UfST2oOyb#qW*;cHL&?IHQJ_q*wHDW z!G7u^ASZ9YZiF+l=FY1!_E~@G=#q%V*k_$nO`EXgx6PYfL+Nfxe|B!Ad7=6loL)F< z#(cWQQJ~H3s>m{Z*hZSR(Fco6+vtOS)5boSvQK-d$^4N%Y-CTqO6=2qTTup3yOP(f zXXw0f-6DM)=_&iPr1Q(zrxkG;`?MlXxlhacmc~9U@%PyjdT!cGcRz*YeN~xpnqNHD#bG&bpAaF=D$X9()T)vc$N$OLDKIRI*%bg7CJYQCqaK&=zRWV z(2odx7JV9fvy@Mc=eW>!ll_^EITTU){n%Nw3xB?YQ2Paa6?F zrzd~XMPr1K-j|K^JR-f}hW2SkyaU9k>js%^teA|Qc+$=#w7Hr*d+7cmexET@yO=L* zH1+z2o4~yF!iBoT2xc?pi*$H}oH&j$vRh&l_6kv0sj+jC zoW^4DZp?ML7`?@Hn)im;iM^Pmu5+RK6&w%6FLT9B!djwq8kc;s;h8IFO3nT=V=#9j zxkGa<&#sjj-cIKJ2`xjWVeWdEIhrc!it?4nL%Q>r$8_hCsPM4Pp)c!%wxX}Ke-2P>qr}GtQ z{~#}>ug(%SrOwmEmmD^o?>{vS$X}vOrf3&ZAIbSUKi{WI_gv%qPv_E=EuBW?fci*R zzi0R91%^#&fB%B~T}T?|^+5`Eu4Vh*;Qlw#_^kbRf$^PF z`@6t2QtJGR_|jj0FVHXal`qa;++xjOe%ofu@onO(5_2w(@APddrGBS5ujlVpX?9Na z*4vmZw;%D?eYPWW3{RfbC&qP4JL@R&X5LC-ehD2kzm&VlnB31d68<(}=2ya;nQ_LM zuNr3z2U;RcH#sxDLZh(qD>N>^RdO#qU_@ws`82^u>MF6i!81luiTUvaBl#PR_qj&+ zGBNAVg<1dEsE%1gQCwJVw_Na<6~$SQ_mYe>U7{OO7tR|M#r#6SXJ`dRKEz!f=GT*- z6=p6xM~Os@+eE%AZZe^-InOJv=G_5iUPp0h+)X2a8fIEAc&$a&3O?S?sol{;eB<#87`CPfP6hgH#&lCIl9U(F&VIp8cQH+; zoom_Bg-xejNPOwSrb~k~@WJ`DgR{iDo(5dDDeWr=4rM>B5qh(x=mL=UTt#5jG{=v!wA4e0BCd z^UuY1-u(^gEs+<{{$1^!^J3$*Dfv11fl9iU-*`q$Jkx;B+BRQKoG?v!a`}@yv>d z2%lLoo)r_%f*8-KTyFAzq7NI{kCMM%XS+&K=F%tsI37Pc@)~^_&x(=GuhaC$Jim-* z#Y9-+ITaCqSAK?r_*!EA_0MpOrYBd<_Zg1-#DiqN$ritQ#D#-@PjHDhcV zW7@{pRASmVHoZuad`|6Uwml|uMA&Zfbt~J|^naJ>Q$A1k8rjD4bfoj^6#dDt#&h5v z`ZuZ+mj7h@o!KUyv-htbo0d{)|NPkWu^gK$O*umhIP}98)W7J;pWGjfTcKbM!$X&~ zck-CSzgl6ZuWyapz3A42E3>+#iS2xQce);Gj*rQsz*#sdjpWRHr-tQku({OOyR(F5 z4%F$M1*W#ZFYMdgF67JT+aB}i^Y?r@_U-oP(>L%BWu`s|Y&@U7A!mqL*u?Yc8*;9b zN@D&Y`m%U1*yzjSOvvcV*P1r=<>yI~ea)D2^fVdc`E;_o(xLHu`a(tF$KF$(PbZz9 zAvNY4V*c@WI<}F{FJsOj;xwL57jb@OeOdn2Lj@&vzFoI>Vp{PNdNR)JmBw|4dgG^E zcSL!xZL*)_%V?W|;b(?FU)LS^^P=X@7}L)}&lVS*XlKDX`D_z7%i zp6krta!uDn*Qv#_?1>g>{O-XZMXgsm$#aG@n5B!QWPBR!cA_a6?KWuIM!UVc{)+KCsh`riDVp?8YSQNI1Ubf{fq!zY{kBBD z^_`E*Ur0w2F_~}#IykK}d_Mti=&w6Q&>{C>v&?e6M>tSYX2zY*8Bf(FNr1rqg%gW$@HGk^pQm;f5lLM0&leppsiY~j0S=TaER$>xTA+@!& zvgK}Bt|j~Xb@#ci-+BEWm)iX!?5R1g&*}c1)7|Hu+xO$$d3T({{1QbKWbPmKzC@2Z z7x-7!BR_kvDE&KS)RR626HodCEVjpzpI=S0{&H@|nvkQCg#12E-=m3U^URMw%rnkk z$gZs(^C>EiuRN3U(vm!TDSpA}^6aIPr^@t8^K6l8vg>BElWm@T)5#U{>>P)&c?LPj zv%WHUhI*3CGjD72%-jBn<=M-)Tr8hwe*6{l%wu>C|EHd3SPC%6p5-g?S_1qeyL**M zOBdciVlu-c?QaHUPIQxS>(gQy81pw^t|cQ;zUJjkaP~Ik4fp^RZ&%d&-vAGP&ikvQ zs`zVw`@qLXsN^)fXGM?v%)iOpZMS$)oR%;G#c_HCI%CE+Uc5hZ=q=!n zk35nSgrZgHJ0psgC6`MbrEz){Rm>&6gN6%n)ddcdX8pGN+kW7WvpA`BY3+z`VZwCm z+SKLZ5atw@7FnCP99K?6 z=FXHcji;jEfjeVb@M%dL5K#jL$~EAg00g;LkPBq~9HP{>2C}$9mHl1PjOnCEk|tj4 z*MrduzlGtiDQ67tCs-0x7TOexT09-a!4rw{CvOE`tX^atES`s8&Ie~qQ_V@Zp#g^I zy(XQnsWRp{FlPTL(s(lF7YPKdIIdWf`I0&}<|WO5I5CNr44-jxO*h_(L3Ox+&B36) z9v>J0-r%NY$V;5T41j0G4LHVMfFr4e`I*nHRrBSDV;eYQ{6$hBc3Tj;r)*dox1$&a zpJ+Db9?zMbUd0yL1#wTI<)>an%c~Ig7h2wf_&yjdEIzbi%SR|a2Ybh#K^$Rc*2p*H zQ1mTXhQy>cPH+;&j`RWHN(7lFe`#nq7X}vH;>ji*BkzY^D@P z)#mwFXKeR7FJFl&`F-zYf&5q?zZ%HD3S@gf&HK3oStEYB0-4_oO8wJ;`~bG0)XQYx z+VB=(WdCNli8Hi%uewkeNd$cgJvaQR0lwxD2EF)A>5*qW8>v;f#=bi%>O z80yhB&3b5LF~^Ec{C0DUb=Jt@0xKr#qRo45Fi?sVcR6lN7Z})MVm!6(@n1v>1NQ0bhFxt&Pl<|c-ZnO zG8`ouQ8=+=U0#jETLZ=x*@EJ)owy6dPn`G$ihWLe8wK9NPVBExeCWjgLh*?cKSOcZ z7c4-JhB}83+fHobcTkbsV+=WS1dlP~%po#{oH<0saDkoWjdVkjI5Kd~wwZx*w#^Kj zvu$SJoNY;3tw8YjN;WLNx1-?ZL}$)_p@$u){;5OlM6nUyaAeF)gQs9CgORwb*=%bY zS!}an)21_w*$M`h#SSYrviMsoHhqZGvV&ms&f-6;*mM@Y`#cAXS{9S7*d${LN}I#> z{MYZBUcLz!{suB>8(8Fhfy@&Tsh=OnO9Pqjv=hv)1DUU5lX}?*>?>FYxbsC0y+pAo zmK`-{b4y|)i|JrQwjafvR%~R!-4nI=^kid@bBbO2ylmG#FPDxnaS%3*hLk>P_%ZM{y95oK_y~cY#&&i&h{Ze*x_O$Gn?AYwN* z%|``5eI6mTlvuKh+Vky(_3ge*>i;iaL!BFJsB7q-k(;x!r?(?F zWlDWR!==-w;q|QO^IFUcC#2zca8p&(g21uItFvwqJTF zAYHfD@6J>CmJ^ws`VYyXO#6-x(ZLGA4C@9VGa?OEQFpEV7!jYJ_*g}|T(e0L7+ z2Hyr=21eSOr@+sGNnCdL^%8z!-*AoR688l7c`%7f2fu^A6wEbsCU`6O1u%(A!60}D zd=D9%&YV8T*~!*TAHS;Kkr2;G4lM;Ag;l!K4ep ztzbs81Kb7P1%4Au!t!YD1AmVSXfpVI@Pkx9wcrilA5a0+fj5FTQ2|{HehBC@F6KJs*-5z^r!`;`8X(oYQs1pLKHU!e4rN`FM@FDU(8rGKpSQ>wxN9X@h_(&s9@ zUFr8K{n0=_0r7mhNFQrHDbl}aCZ15}{{-wQi;DDf%!5UG&g?GI$D2PC={4r85uv{c z=ISDSqPeR`ztB8gq+ev-DbgpK&x`b0GvUP0f1R0Mq+e_Xi}ZT)qawY*yi=r4G5=kp zPc|2z5tFmub_8rQ;OWAiT``eWLGG)J9 z+4m{?Zz=nJWuI5}gUWtL+25h;?^5=6EBkwt{c2^uM%k}b_UlypeX9L?s{MY|{-A2# zpxS?++Bd59O{)DN)&4`({;+D_qS_x(?T?y^i}uIIl>UU$w<>*`(zh%9DW&gF`c9<} zEBzUz?=rkOD|CYSiPE1{`twSELFq3l{bx#lN$D>u{S~FZru4l^f74u5H2$~DwShhw z6T406>%7kE&uX06J)zp4@j8oY9IxK+`ZlYdV}9@TldYaJpL(6wh}Ae#t3C-0AZK4= z@GPVyUguTgOpM<=ka#^;jWe%Suk$>m8fRLAUN<>oPQ#hc175!m?Wf_)=Q}7vqQ2Hw z@X#-^VAw8)WVVYe?bPq}3fo1NcG{m1w2Lh5)Yk;MPf9t!{3>;By#+D-Bgb`>zC1C@w}4^1TQlg8pF1xniG$(@o0d0ZuFkXc2$OB%~` z7kxr6ab5CNeOr*i1h{i~z1ZRJuv+Sq66oZQ;h*55fOT5r#aPLca@Be8QpwBEjU5$!uTP2GyV ze5V=c>&mzEVDy+tTZ`L4u?c&4Y*3AMcTC!3pVnzRa0g76x42h^E+0saOFCae`^cgn zHYX`1(Jtw;y?q8AByQ1tgm}H6hixj$!=|L~=$0$lK&Gz0v$yqFm%$V^dM!+0qN9{% zXgY#vY}ij^3#K(qB3#KJ+$8>Caa6Tc47b=E%bdi9bJ7`;c6=(E(weC_L>DI6D~c8- zn+lcTdUaxs#uq5*Az4SQ_sZC0F)cq5iEGM%C-B(7%dM8tJ=8_NoJq<4>)_!k>*jBl zU0G^_D!1MS6|(3CRd(eKbie%C8oLHB?eAN8yQv$vV|l(6DV=W}ScY#g>hQ*6xaUfb z$JlMlK)09V(%`7&&A3+?UVn{Pk}*qBr>RNdx))~5WBxia#C`=hxwc~cj;k}~qpYiw zYZP8XUjp1|f#JTZGA0L|W0CGzYTTg!C$~Xkxa_=wKYuxG{c3-c0-Q`I=5Jnr!*ndg zaNPk8w*$)J)(1FV_mg7&b_BSQ4i?4j3vi<<;0^`2Q!3!H*lszrb9#BTVvsSjfIZ4Dmvb0XGi{et9n}^!MBZ_u!+r6n`TD3jOT?j^n1koCi~%t^Dl=j`!z; z#NSNiuLfVNZe8H~jrU;s<9BlSOY-3LC*yJXvBJF#9Pj%HNx$1s7tUkoNBGVYli)ls zR7>plH_G3Rr`&x*4@tHM-`^hk+x@gL{9cg$CVDXajllp=oy_CGAG_ZG@sPyd>A;2l zwgXoK5dB@~!Sr`Ea9P&-{ew-iKT;MSLlN8<0z3(BryrmA+lPLojZidOdQai@m%&wG zzh7 z&HjJHwuBL?%~Ws9?eU)ScM!N|d^-#A_eX`>^iKspAubu85By%>M#@GA{OR!>cn8l1 zpfiq-&rOhu#^-&k{%1UC>YD9m$@o0(x4=Cm2UH*hcMu(faasTC!g|29mc)MfPX^Y; z``Zj$mbUIr&^`CSxbS%pQY%gUn%LjqKxq&|&mqWzKpnwxm$K~VSx#v|F zmn#E*Nj_J(%Eu0-i_5JKLi*Klng9DjTzGsX#p2QoT$;Gt9{9V)xr^q@D&Rhq zK>;VCj?2&=@C*zZ8JGEiKOL9Re@wR@^#iw*58HT>esx?vz%%NM1N*(+V`FhS1YDZ9 z82o^!_`@OA5_O#~qkubG28DJJbzCNo%h>0eIKCUKH@Dq%T;2t)&9}1vJr`>A0-I;A9?)yx&+{)&rL&E?WbC&4E81mto-en=e8l>bUH~5B}@`h;iZbTqKT9 z$L02O)5YZ%zn3{BP83Ua7>k8(f<5C0M zpGz=;@#(nKPr!Wvv@>721AjU$`+>XGx3dt}Ixb`Je=S21oQ}(8;A9@lJU$ket-z(p zm)(IsUK5e%PsinT;E)OliKydpXky0f0g7?y^Jx0haoI5`V{Y~BEX1FVOZLKy`E~@S zh8MriY84mpMnO0IPF1vyI+%?-znTL+c?!U~~=QbIaL648cW!^>U z_M=CDlXaBtq+cDEkARc7@cCL&EH0k`mnJS}OfLB2v$~{MTynsriA%1w5Enj&ONzy1 z7jSa?BSz+{^CeT4E-uZ$NnBRbAt)A?4&c(nWmVvBjdK@`%X;8&DUguNL+48~9(Jt< ziutnEqhoPd4_t70p2S7(zs~}3)9+T$=grXeji{ z=SE1e`MwWantn6*-|M%W8~a%<&ijFrIB)RySiheEm!{tdQ`7bP5pdG)#tQxBrlsrm zYT*7M#eB!$A9gx^>EIqqw~$#pq>NnT}v!(T$50mpTN`!CNENbFbpJ7Y%txUc;^ z2%N<43F|HH@8`hnj+~EcfBCNz&R@1x@HZMa`qIpI9&j?>Z59083S6UaXHhPG&jDA1 zcE)czfuLCY-Um+3n~5psZ^o>GKimqm6!W(PxHR+K44llD*A1kYzhU6^*jD#ZZhXC$ z7sj{K<756d0{3`|?OQ)PV~-n*-*5$g&jA-ZztZ_KZBAi)a$hVqzGmRkY~SI)->zVM zXJaRl7_s^QaMOG{3u#MmJ{BY9y6iWJ!QU$2zU13kl$-CCz~74%{Ow9PzCD3I`5&xU{N7LL?@-|Hr3&LSSESp% zqk)s{`*H<;lYmPTzbgWNuT=22B<1*e1Anho@V7Rlzs-Tay%qcor}X#pz~7sJzl*UG ko#gZ^i+6$hII<4Sb^Gr<-qdVq#Q6b|lk1S==xE6Q1G z|7U&F^r=(7I(6#QsngXp(;ty|1({3vPI2I|I#@{vr8A3 zm6Tc%6(i*L`$MKl1PnIm*k;+PI*QCS;=&8Ym`!H-qZ6*URFWi^&P);;&e}?hy<5%s z!I3NoVhF2iS8KNU@$*Lu{Aht6E%2iSezd@k7WmNuKU(1bZwt7JiZQ_T>&Jz)FXw|A z9he6ymj$%5`M_QHbob&UOD1}@N%yzW8yIVTs}+oeW?h2WlzC8;Et-0%_LzORLS_%t z-}?2z=EuHZwbWAdBNJUp9L9Pg3%Xhkrn=T7txnxa(%zmi{6BM>0-8_r`_?r3eS4Ze zyS6~9YQ7?`{J2lA^?joI^o_nxB0{@$Q+Kp#U#z=&O{m(lW=oB4-A}b|*1TNf0q>eM zp_QIV-}?RQu6^>$Nna%U*Il>cy)U<{D|+%PU(pu%$&D3ZeQZxEZ?B=fhW1*!_QTBf3Gw#Ouko!H8LMin`n=#} zvV|V-H6N4@ejW{YnGZ9$BSa(G_{x@tR<^pDbHXGYJxe=|jb>r?`j&&|ZV7BmA01e@ zi7d5czXKH{)WNHAw@I2F0II3F7md2Qr|VIE9pw6$Uq`xr%dg{I_tCZB^XdYi!<>G( zdbXfxCUdpkoSz#5z3nWMt_59tHm7~9jq+!Sx!aiLYdI*Bgj_bF`LXr6$C&17;pJ4f zmb=hpwhV&aB$>48)~c`Oh_D;2|G--py;Kp)txeWUjdM4F;yUMU1I4w@Z3JcN-IRMQ zSsTqP%^P!@+Df^p-P&|-PHxkkfiHA#Zj`@D%nf#H)4eIKb*)Y7O*XB!#kHQqdc27=RC? zi;!iDj)8Vl@IzXQEa-cPo=aTDet|6bkJ;#LHhLG)7XJ4{_r?cO6SCk>lc2-7#AWPy z(6U8Wffn+siSBD+4%+CiKqs7I^1lWxTl5XMafr4RHhQUzuC~!@ZS?&%dW((zjg5ZR zM*rSMziFdCvC&`JXy$Iy&2OW7+vq_yTCve%Y_x8p!#4VQ8-0U~UTmYQZS+PP{qHvV zaU1=Njc&BjFWTsLZS*HL`b!&~fSa-=hi>D(BQ)0@+Pn*{b?wHcB zEv7u|Hp^^VSWQ>1X-UQB4J|Px7qg1K`$=pdTf|r@OMQiH&yOkWzz-oe6_NG`81Y1r zt$mXFF}B)bd7B;|<87){zh?Kd$-eHaJ9Dut>GfN4rFWKk*tlC?DnH~|;XCB{$6t~! zmDqW#A8?x>KbbX;WjGUcgHD009Oh-8VG$ew?O|KJpCvF)gKIlmk=VX(v$O-Pb|crt zDe(e{D=X(DQ?$qEN{q+{cU! zU;InV_`g($8m?3RloHOVQ@(aHwK>YL&W|BWF?q|WP@VFuJ6-9=Bn2Dr`oxd~n$^2Q zQrI1-Qxad4ls}_XnH&&xbJXX=zb^%OyFMt`3J=|TTXcT)S$!Fio|ev<^L)MH|Zdb>M? z)w@E};&#;E&RA`&a@-{;f3n(!QmE~%sJj)MG_-vk7#F0To8rr=QKf{HdFum(8KJ~lUjb7`hkE6C^4{Gy ze&4ws5qVA|z@v6=zhh$fAvxAe_= zKN?nPP6Cm{a9Cfcb}P{JJE}i0V)eT24W$E}iuyx4-B~ly;&rY?LTz7+aWP9ONQ^W^ zVY>tG8*+b5l{r2L{8Ky4k$N%uG2A+^2-@Gq`eucAJ&V&@A$Hm-Rq!3eFz+Ri8 zqV*rRcDFNAhJ<-y^@D(KIqFv4VBHHOe?!gkmFdd!Qj^vra#*X@w(gGT`TM5o9)DPW zKiZs~r+r~$?v-Vi{}}Y!`f@_UE5-+g?2qYnN+Fm28Ke16$1KN`FQxv22IBe;DK&fw z_!I7*hEExidQ(AnT~GNY)Tl^$bCDUJ?9uw?(nx;)`G33Qg5keLzltX01eD^I?|hBh zJ)u5o2%ejT@>j-Rji#a_iix>Y4JeNs-{*^MPY88`rE8vYg?g)5@Y0p|oEb;M!Y6$V zfn8WL7=Nmo1b4HbqZi zRi78GQ*w_C#pf@NNcg<^#rKV2xHdh1%3x|!5w+N*RE8z>r>l>(N8er=weVci-hFxo2IUY4rncV`kk#CI8C%xX18|z2GYsg{=mbDNK4Lk>;bPJ+o zKOSE}spMNd5G4+^B*Q1u)Krgq+u+P}ekZtcC&k9km`j}*%|yGIkl^K!|L?3Rn8d>OuKeokd9rH@@dJTJ^Apt7~ zE2}m`c@vRTQqM=->ufyM)n)Ze&4M@G#)f6Nm2X@48msMz`fpl(M(eFM1@xrjnFW{2 zTCEK0(JDw)-JvjSfVhl!`4o?3w=sW~S1CK0#bZ5r=a!YVh97E3-qjq{>OYMRgUzBW zPm`1*OzPh~G`cVYRBGO)=$K_v-Z6N0oih97V@6_Zv(X(Z@o7WCol;W1VQi~gJv#96 zObPABuDKxMEvQot|KWhqjPc(0vL{PYO$t3D-nkKDTsh6EJ6jE}m1X&;+!T$~pNPH_ z&4dOoAW9-C;BNZ@;>0+2Bafrl*Q$A*4CQU`?x|1BY&ID963Q-kc{;9Iy@bedM0&?) zGLGSnbKlF7+Qj?s&Skv=?k?q6nC9u~@T<`eqV9E#(LGV7dZ%AlFeUHN=>70lvZz;W zi3T$_7`cTP&&ZvIUC)aLu;L?HIR5~mYieel^4;_FS=G4GP>0-ORIhu~Fd}6s7Z$t| z>bI#Eyo{pzGRcpXxJ>d6(MM6ql|r$f?vH7zq>+p%M$(MCQ*w=;7P^4HPnuwyf7h$g zqtPBAmpTp_ZcRxEH5yY3Tx?2#o|39w6G6np-QJxQ)^$BieHB(S`-(|v=<9jrig}fo z)Lq>$glUP75aF2(A5 zsw{*OBvcy9v=6j0Pxrw4T5t8cp+_}WXt}XGFfer4v>t&p_2$qdj4n;B46zLq(e9M` zZFQ;Tp^`9D`siML-taUvDN_!FRToz0a><>g!CK3uVaf_=I_lVlVVNGFU1}e_&u|xZ zDMBmieOb-5YPB{Rcvnhds3@YTv$Q;I1LlHccvX^;rj8okTkVy(%r>HaTfo6s9*|;2 zHMinQDPc&uvQkPy#91X375rq#2CRWayD6h#V@_OZEKNg*DZyy@(+z zbZQWL6^^jl(iS{m-B>m*4x`>3hTui3Y*Mq8OTc<4rb-`#IS`)$tGl7Ohup3A## z=y^jY=r#Jms1$14el~R6DE(}c6pC%{f!r6o-k~&2((ZwuR5jjXqy~am>vUJW18bc= z6SIQ6vR~rsYpbIThMtsEB3~c4<;}o~+de!(XT_`BYR= z@$9C&$d=VMMcuH?i-?z3k&&V@Y4{>`piPj&rg#fKjh>&mCSpuq z6Yi0hplz3W>qmPhXeV4f^wN};kXP%e4j<~#<;_g3RU*%9U%hSZGc}K3ulZZV#CxKZ zsz<$A)3vpIPRKV(wXUhVCRhJ@-%Zg8eqTWikE#zFw-y}JAC7(zor&mrld)*}&4stj zSj6M&)5a_#tUn#yu2NhLyij8Vhu&n|V?2rx-;h!Xn;gRmcqO_6l7{Wl zjF)sj)?J^xzH55F-}hMG&C&BRdqd7GjdvE*LMCEcZMV?vk$Z4A2)s~l)TSha?hN-- zbz_RrQ%}=rSDB5vs>VEn?f_Md)kdl(KOzOZ%2C{RJZgGqijiNqF2$n`2(4J1XL$0~ z1w3l+P|a$lc=9}6stJUuS7)QfEXkqeypC`bw|*@lB5t4^%4R8#?@oww#gGitT)HVC zw5;Z?$i(VuEgki`J_GC9t2~Z4>Qb*pn_o%y7-kHH_5r54)XPI#j8*t8g&u0nZDp4L5|VYj+jdfiwbVfh!WVM=O# zYJM?1)vaujy7za5T$$;hJ~bHpZ9^m#W4LcxM4yaj#JdVsSKm7=rcc#1U0=Dppiw!9 z8F@IurbM*MwEoytJiylPt5|s|nxx*g|Iu)&{NA$*SO4e!qxx&n@;%?|`JKNudR8cu++Nd@9XR`V`qdh~9?akc# z%x-$le|=kW=w}5FPD@gg@I3H(zEeM{uZ&jK{BqhM`ND`dToEmSw1bWB z!)sshlk_+6Oi*Dw5c#(mbxOiZ8Ib?8NMpTcZ-MsI?g`raQJ0z!YQ$W+Ll4eKQ#aA1SHT*D>ooVUTd?|bg!Q*k8`L*}O-;GV_0P~QX@7>2Z>b zU1U)PxalazaOyotNBvJ1#%lk(?+UqS_ca4!crJC1JS2Z{ zkzaOQ&{%u9f8xMKB?B$Y^NMLW-I{bLRi!6!iihdgb*K}5iAxjLco5vFzzX}@xZv<=-t z?3YQnk8Lk>g=#ks?h(u|pUGcLVLDK4>d#5$*EPVS}k94*_6?g8O z%n9yO(XV(U8T~@<-~PNIVOMNxo%Y?{?yFS0 z;d$?>XKQq~zHGY-yAz`&0ncbRpWHj`UOa{0d~#1grgE?)5i)dj$B4K6SFrOy=WDNz zdsog!T{9j3#P!YR~R}zr{qmorswt0a@R6#vgcSr7YH&ua;JHD2{P*YmyKlV4+Zxt?lxdiOQ{QloqR<{go|sd-ZV$Y^PFaQ4S|=B`sl zzmQ`rGL~z4UPd$xbE0KVfi9z8=xGGK3yn;pEOCpGZ6v84{XzXs{c1fYs{QJaaT6lY zG3^j`1lopP@Pi&9_DJ_o&0gFiU%1-XSx}Hy%}$J)kayJe6>Ks3g$s;FjJ$lDQsqBl zTwwI!cglM;y_)46V(xqz)kZBZ?+Vvp34QDIuwTV#rmG^Mu-Ip+7}#iRs$18ipH8opNvTTLpg#Z`SJeR%@43zwIBd-P!v? zHWj{+ul?K=!8K3oRd9LAMWKtTv5s(0UJ=j`UF(#mlj-D@&RQv6Fg1qr);~vH!@2KO zHI?c+k>&bX>Wz8^PEP*BMnjWyoGvY`>4O-n@^zk;m5x|S=g5cxCzG=Jz}i!i-v}pH zSKu7-b)1dedQwCG=DFZPJgZ)ayWaabvw%Bz__xy@HJ*?+7?b7qrX4mid{;huZ^OEz zSBxaz(a8JPPt%_QCu8qM|HsC>J)g>ZcbDutWkmE35rOjc+M-v&ZYA?X59~u9YPr)U%E!*>6uY;$+>6vl%>DVt=xR zok!<2h(77?ndGcQ<)%PSb%4)|5|{0}SKf$I%9~IAwIHltjvdA>C5-38{FNW$jP}Fm ztI|Is{wA${tZ)bp_-T5)& zl(7x>9W8u3>dzdz^3!PEh=F`|aFV0G>$|M*ps~^SY2gif-j#RketPfUrr#&0@BM23 z%}G=C9XCG3d=%(3AB{!fa7#E_?XI7S-l`_y9_)%`jF5CUPTXQ{x+i8tKESCF?Qx$; zc?IY1{WEV}c`Pc8NaMW`ht+oreP~F)Pf?#+nW3bAAvZL_zaQO6G4PnO%}CniR?fni z>bB@YoV2C`Vb;_s^Be1w>l*(fT&Ijb`Z+!?J#-wOQ=hv4pR@67Kqra8!HtG1J57IL zL=v7Nv5(MCj6NAT6&|l`@$34X**@j^lm9IEP=?p*86zg+IVVXQp)S{x^rq-5(7SNw zD@F`+>&7|Ei2{#GeM@U*rFz5dww1mQAIVA+*($Fzk2T6;2>7!j_)eUXE76;f z;AXDpTHk>LNlIS_zFFmw6eV=pdrBp&AaCmANk6$PIIS?N$}r0D;#6>sQ4!3$Ix?v+ zIKFgoX}Pg*e(8d$;MA%`v&)R&kOjtqtP*4X{L+e&vf}cg7X|Z!C@#c1RTX&Hm{GQ1 zPSMRq#f_Bk<#+g;>yw)ESX!ywP-8@Jq8Fqb#A z#_VFj=*c{OjHgWjQreT~tGuPMs&qcy5red%`ISr>&<`(nNq%~94TZ}VlM#}rS6`(u zr>e;8r({;q%@t);rSv9S83e#CXPfQfAY;}IV1{o(d%r*xEhr|bXIDH)+}Xud#VD+o zNV?faa=bacY6t1Xvu$0R(~pmy)QjVIH|KQN%{djRltl~wpMJZKY zSWU;u+mtHcqvi5s9068sHBQX0oN~S)NyNJ2^d9{R%JgI_XzF?UYLN?$-oEF zBgn2noMcjW$t`EfXURPRu}hOv0Yi;jP6}KSzzWU<2^$C4Bm`lvBqariNJwWP)F$?j zE(+uZE(|20Aa?_FQjes-7$2NTfl#whcS*&Jmz2z6 z(jyW~LgAIh98aG3{PWfFh@^-r&#Xmr=1{Xs1qY6R=|f0ZSTqYRC_N_O+eb4c%r9P2 zL|!ia(#GUab182%dna^)saiRcer3ZFlNJM*nU+wNU@i!TUjw!EWUdI}SxyLv6{S^+ zDi*+di>nYro|JmVC78i$!J_$0!f{!gU4mePS8EZhrQg_ObA`Dfwn=9RFs|JH2b&D; z|3gfg!h`EPlm0c)1L2yu{=uTD{tcr0-~$Qg5u85aVGO@;VXmtg+m7oAqS2Nj^ht}q zAM@lzCO*EqVm_jQr<6i8bReq)Eeu73K^Ep?TraTkFSPh|z+7SR4}%U{{NeDOVjI5H z;*Z6ZqCDw9@|RltCAhA&@$a_y_;n8ZcN>3;#h(uOyDUE0q`~6<74*wC{%aP07WjX$ z_|)&;Ej~@bHx{4n9^~_6lL)TuW6{+KJQ`ih`le!0*uq4r878_*X_AI%_1NM{stXKn zl5{mL2_xHL2j{aanL@$$iXPtdMCOHRX!xikc>`{IixTvCnAOWxtUn+)E%uhn`u zFPS{5Cy7)ic?AxAgJ;L}C4F4P!!_E5L@yn49qmaL$;{xRYhM~cb&$d>0i9{=lDC&H zfwwr@($M6dZE-s)i56+p0`k&H*J~`Dhe_TZXe)V>Elma|@@}&DrU58x5lFp?~L6 zP3xra7S2A0TMC=C6FKHAlIp==Os8-sfOIdFyytQc>1UaVxPZHFgOl;may`g5d}LLy zD@YDt)e;wb9Us>H62Ap1ye)^Rsda+Wn_zhxSjXbM+)ELZDX$vcfZlsWC^Tch;$Cfmc# zLum>JQvm^BD2)^4^L)uLrEqx8g&Xyt!DA}Y=n88Lr7QRY=z6OJk!TH@4dxxUmz7Nz zNbW%x7%-j6=zai|ZnKVWbxmrG414aTr!bUr~`|`1 zGN&=qDvfJbXCi5SX`E)b6+Cn7c3!4!?CyDzH{act8ks;c0WtH=$jq<|(v7Pylt&*} zp^#*l25GOjP}P**amiF1BKndD%)iFxPXvb1mVW3)$Tp>o=Q`+??vu!OxrGut22QYm z=1pq?xdh~(y9t&nnNlZkslqApcAm+*xS7pu4Ix`;p%)Bh& z!Z(;H?f*n_^6lmLW*lH@B4iD)(Zh+hw#P1X`on!(>EJKpNOkTGpIXYx z=FY=2Y@J)j=y~D~C!&B29COjjFi4LeCZ@@v z!?=D#^fbokxj^jKX>ZE+>)=zu@7UsP@m$GiYWpwSn=;zBLSO^(_uY(o z68A+5Lk|4IjI-v^ERMQon}2!?uVr=P%TWxIdAKL8kwyxR2cF1)yFxJ99FhBBj>+eK zXf+}~b6Kuz_rqhvw@zVRw`h7@_f4V;85@i1$3$Dc`ZtS@D)yDdC*S+p;^V^Trs_h! zbPMd7ztIUmC(r+kp8wem$luq~y2U+hHMWWw6kewyIAX_zJs%DnX#<(d8F@S~Vy8eG z23tI|Y-9I9>vd+RgRvrU0w2V;m+fE7a9_1#4FFEqobMHSnG(+V!TK;i`nS38edbwR zM{azdlxL0>2Rnk`Cz#nxdO+&Yj+H~KeuBlX+`mVeEbiZ9Oq%;Q1w`%x<2XTFe=mLBoeS$1}{U1bwPxE!0Xsd0DMF(;9V9o@d?uUe@9T0sskUE|7_yPNl)4ctm#>kj|&vD9e(!6M0P23_<1cBwhiM`@e`&F@|hS@b;+ z#^?P;6Vra)fw#UJw13ezF4^S+`Z?tP?V;T?)oFhZTKX!1`%2tQrky65Hn7`iKUie5 zEs(_5O1X*o9(FqNgRztNRYci>GV!wrCf&v#t=jq1<)_=}fMqB8wG26ii#F&;U9l7Q zrXSA2i(3gl7^7driC+WVel`u*G8B)=6o`=Q{&W~+@+bP?5MOt^(f6>^?;zlZvFe1K z78lJbFJ5pXlVVabnM1gex#oUCtoAnAhcek{HO9&9#Xa!!tBd>UZ7!! z=OTNfAn|P~+Uuwji4{Nds`P4NK^$ znyhJ?Tw;sS5dC{gs%?^mP&DL8V%JdkHm!1v#e~djgdC89E85a|KE-s2UE33vz9t#O z#T0X`XaE3-G0ha`3NdY{*+kYLpJ5eIwZsZB8mosw;!pyYdUzGl6XbWe^al#0S>0y% zftaqb$gtK#TxOf3K#8kRZ62ykt*;kVxKjV(`&RN*u_ice)e|jzob&sDfh72Jr7V1$ zR;!T1X_RTL5G~|zz9mQSNe0nE&iSB)ZsS3JOA8!{(^gxeNhY-=TC|-ATHra2GKEQ^ zg$|r=$q{_n!U#EYP!>8Yv(dk>(VIYvzBr9Cg#n^PUqpXv^(FY!7tx}xM?ecXoJN^! zK(vs<`Ia2PCpkn5IXgiMoj;d1X}3u9Lcoih10;&ybvv9a=s-~@JS}oLgrDM98RO2=7ne> zhx08tf=_aY7IOXuTIlv4Hkq6TmUJUp$mD!Wrr?uIqJ_-kHaVO|J?TcYki+?w9Kk0! zL<>1?L{i~1oVM^plN`bmE%1ppJf~4lK0~zVm-8(-f=_aY7IIY3!Y0?-Xc6H7=W?-^ zB9fB5iguy)Etnbm`*R#SmntpV-iYihv8zo`dwHauUEb-<;%Zp;nX^nWyf2H+B_S4V z7eGkcF2GXZoHj1qD9)f5q0Xcjs?dxpMmtHHsVp6P62hEAu^wok-y)MOh!%6k`8GW9 ziAPz?8Nbh2>x$E;BcCH$$l-iTj^L9FqJM#EX_QGHqJd|@9~@?pDhoNQ|0b*U%8)rt{jxp<$-dB zJP2?343^I$yNh%V2oJK$+A)%RF>X69*b&b5Oo3{iXhZD5+GRabd-r$uSexpZg;Edb z)j>aGa3t&Y#A(t+PLq4cJ>_09Emz% z$04v|Vt?O|vmV5sWbWLQ?R2O4J5BeQU?Oq5TI<96yR-NGgD_^S&F3wi6E5-!%MP=o)gE={BcJ_s%U@X$-C%9*L+v^j|niDK3 z$sP?%aWE?jFXCm<|9E$?^Ic43b}*~t!V3YJvoMR^bSuAjM9G};1r<{ZmIkxN7Zv4) zuP!ROxT+*))RI|oMnQhgs6xG{2+c~2ic(Z(E2ESpb}7T=lpDoW@fK|&CgJ^1r1r0f zg5lIGm^C*im{m0rLUAfIcTw@&(u;>JHp+{uFpgl>Pt;)6RRCOr>vUv#9TjhzR%PMU zsjSMfrKK0=;J+oz%9>wRSy5b)wYapRvdmaOOh`0>&fb*Dijv@&UR)y^lYQx7Pt0v` zB_WHALsQaJKdvRrD>HJxEo3`U=51RcIqEGT?(J$!)tIS2N#LyQQSvMC~EGSzr zxAI~XODigjimdXo`DIlXkA&qqFhU0`*abZ>mWDhIIS*M!9*2TnB zt2_wTS;(`kawe{&$aAf-{etBj zPabx>m25|ebaY`RC{|GlBD-MO2~@C>3o}9E7s&<7(Y&;!=ZwsgF;wygl_ce`KcjVgA@zyd&d5xn?@42<5&y8L)eY&%0nIa^Bwr%4ty57xn28^qkXoc{Rl_< zk&gDG9PP(A+F#^opX+FUv7`MsNBcZSd)?7~yrcc4j`kBB?I$_fPjHIDYzI@(|7Xn(z<{Y*#uS&sIz9rdM-`nit!d5-!U9Q8Lk z>gPM^7dYw{I_ht7)K{_* zYaHb}9p$?m<@Jv821ofGM|mUrw|4s7&mOjwQxQ5E9p!heGCdQdA>MuIsK;BoJP|t$ zchUh?neHQLxO3)OW!h_`A>M_pG7B>Nza4{Esa2+Xd3VGsI?JR)x=^CBxX)3j7BtmS zqIwZxsb0`jM~TX_IYkfBZM4PW^mZj5w&+TI;|^5z4Nar#0A8KcA$y#cbxG?LRFI5!Anma;^HrmoK|c9 zO~dJx?Z3)DtzLYEeOiV1-Zoy*;jePywWs|MMX4%XQl*?W?_%hu%~HqkxOp*W9V3K5 z=L~j^K5afbhR3_d>~@S0-Jdqsox{&G^Z#|LHb0nES$SsrwsVTkkq!@`_m0jiH|{T; z!{XjkVRQ`a*qhFTKHa-!m(E%=mwu#TFvX;cXU(c8T`WrFWeZ9LU4f_Z(n?V(H%bIK zr-J_Gkg~wQUk!=>9Tfi8g-rK^t zo5ttMY|!~KwEZ%zD{#lErMbGtzKxJw@}xB^F(_kYDyi+`^1LxnXnFVGR6@^ zJ?ZD~1UJNnOX>tS(S{Re_Z{gs&xY&PiM-XorJ|nnOX&nxXTt?L!ELqSNG_$0^xI{_ zbvI!h;*QvGbk<3!BYAJyaP)l_CBl(U(B3`4#ixOd#3aypok+sx2t#<03V<7g0@+3M zOZKL7NV~ixz=?T9RosU!0Bx670}!31lDwYClt^ANvR&RUfD3{rlF*O7W3$U^08Z#9 z&LK%2ox9rQH33J@mm&#ybbe}Mv#pp^{(rH8PkK@!c}I}#@?L~7#5pHnguKrkxUYe; z%NMu|2(!!k4!AH0vXa1^1CYIa7?WB64B3y)j46?R^qUI1yhnf&>y|J=-Zc(+PXb5n zNuKZrDz68Q+T;8CATB(K`J#f*X2pkI{TZ!r@-Ri`RXgkxVdVzb~!V!l=CfcJN+yf zw~b|NrVxg!kQdj_!o3Szw#~5w?s?SP?UFj7&9Aa-{k{hrZ)3?D0G!rAzi&I_%>Zr? za5RpPg{N^i?Ggjde%>$ibJ}I~rI=q!UbanMeBLbm`d-G`e(4FEkms~Z8E}o39J&ac z(=Nj&w%G+P#uJUhX_qm;+1HVf=d?@MCXc=|qSTRHW)MyY0Y;EcyUd$pzB5X8hKupk zk-wx~-Zi@v0~i0*45W#Eop#v;9Q8x}()U}GI zRy|#WJg2{`22QM_@fM!sIoHvXzzq~aZ1S9TIrbCN?`ht!q!=DiVQ29pdMZ2Z5(BO)b_q{wvy1pXyd%3j0$f+@@&<5t6pbfgBBxynUSVk#fa|DV z`ppIRFQ$+yle9M0w?6H>O`Ij+>kElS7?*B zrW1J!f$L~pI>)=tChyKpr z`CYTiMBv1{-DAm3#?|QuGrK77Hk-VSHhDea&(?XgOze%oeQEhDmBl#dw{4)~Tbo@= O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E05_pit_demo/libraries/zf_device/zf_device_config.h b/Example/E05_pit_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E05_pit_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E05_pit_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E05_pit_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E05_pit_demo/libraries/zf_device/zf_device_type.h b/Example/E05_pit_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E05_pit_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E05_pit_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E05_pit_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E05_pit_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E06_exit_demo/libraries/doc/version.txt b/Example/E06_exit_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E06_exit_demo/libraries/doc/version.txt +++ b/Example/E06_exit_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E06_exit_demo/libraries/zf_common/zf_common_headfile.h b/Example/E06_exit_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E06_exit_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E06_exit_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E06_exit_demo/libraries/zf_device/zf_device_config.a b/Example/E06_exit_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E06_exit_demo/libraries/zf_device/zf_device_config.h b/Example/E06_exit_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E06_exit_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E06_exit_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E06_exit_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E06_exit_demo/libraries/zf_device/zf_device_type.h b/Example/E06_exit_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E06_exit_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E06_exit_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E06_exit_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E06_exit_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E07_encoder_demo/libraries/doc/version.txt b/Example/E07_encoder_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E07_encoder_demo/libraries/doc/version.txt +++ b/Example/E07_encoder_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E07_encoder_demo/libraries/zf_common/zf_common_headfile.h b/Example/E07_encoder_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E07_encoder_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E07_encoder_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E07_encoder_demo/libraries/zf_device/zf_device_config.a b/Example/E07_encoder_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E07_encoder_demo/libraries/zf_device/zf_device_config.h b/Example/E07_encoder_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E07_encoder_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E07_encoder_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E07_encoder_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E07_encoder_demo/libraries/zf_device/zf_device_type.h b/Example/E07_encoder_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E07_encoder_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E07_encoder_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E07_encoder_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E07_encoder_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E08_eeprom_demo/libraries/doc/version.txt b/Example/E08_eeprom_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E08_eeprom_demo/libraries/doc/version.txt +++ b/Example/E08_eeprom_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E08_eeprom_demo/libraries/zf_common/zf_common_headfile.h b/Example/E08_eeprom_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E08_eeprom_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E08_eeprom_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_config.a b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_config.h b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_type.h b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E08_eeprom_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E08_eeprom_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E09_timer_demo/libraries/doc/version.txt b/Example/E09_timer_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E09_timer_demo/libraries/doc/version.txt +++ b/Example/E09_timer_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E09_timer_demo/libraries/zf_common/zf_common_headfile.h b/Example/E09_timer_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E09_timer_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E09_timer_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E09_timer_demo/libraries/zf_device/zf_device_config.a b/Example/E09_timer_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E09_timer_demo/libraries/zf_device/zf_device_config.h b/Example/E09_timer_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E09_timer_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E09_timer_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E09_timer_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E09_timer_demo/libraries/zf_device/zf_device_type.h b/Example/E09_timer_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E09_timer_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E09_timer_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E09_timer_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E09_timer_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E10_printf_debug_log_demo/libraries/doc/version.txt b/Example/E10_printf_debug_log_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E10_printf_debug_log_demo/libraries/doc/version.txt +++ b/Example/E10_printf_debug_log_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_common/zf_common_headfile.h b/Example/E10_printf_debug_log_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E10_printf_debug_log_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E10_printf_debug_log_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_config.a b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_config.h b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_type.h b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E10_printf_debug_log_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E10_printf_debug_log_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E11_interrupt_priority_set_demo/libraries/doc/version.txt b/Example/E11_interrupt_priority_set_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/doc/version.txt +++ b/Example/E11_interrupt_priority_set_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_common/zf_common_headfile.h b/Example/E11_interrupt_priority_set_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_config.a b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_config.h b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_type.h b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E11_interrupt_priority_set_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/doc/version.txt b/Example/E12_cpu1_handles_interrupts_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/doc/version.txt +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_common/zf_common_headfile.h b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_config.a b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_config.h b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_type.h b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E12_cpu1_handles_interrupts_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E13_dual_core_demo/libraries/doc/version.txt b/Example/E13_dual_core_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E13_dual_core_demo/libraries/doc/version.txt +++ b/Example/E13_dual_core_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E13_dual_core_demo/libraries/zf_common/zf_common_headfile.h b/Example/E13_dual_core_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E13_dual_core_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E13_dual_core_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_config.a b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_config.h b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_type.h b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E13_dual_core_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E13_dual_core_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/doc/version.txt b/Example/E14_specifies_variable_or_code_location_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/doc/version.txt +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_common/zf_common_headfile.h b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_config.a b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 zcmeFa3w#vS`Tsw&mt=DxS;9p`)a4RHgx%p%KsJTR29zSjB}PgqCE*eTi)4Z|-c56B7E~@=XeNN?Zke&*)*185 zZ=0EVDv|cQTW+PKt7pi<&6zj9Qkgw}(99&kXLWgU1*9Ae9weoT?8S4+XICzoH>*;_ z=neU@v$K7&N(7jw!@mQP%}tHc6jWBYgARGsx)7!GC*lRQk3}> z#*t^J;vt})@_f=+5$KDLFFf#t2fpyY7asV+17CRH3lDtZfiFDpg$KUyz!x4!>j7K& zYDLliI7U%ctr{J?g&2A4SMv4Y`Ew0TiP`8(MsG8U4Ek^hJCAJpQd2LW56N@|rWY_W zc23FWlSiBuE2~y{+BP09Qk57TB;s&dOJWzo`j+<-_BXbCkg&hGv}!)u1(Oq{b?f{Nxw9n9DU`t`x@jrxP%J?Onr2mRWh_m&(e z>fjetbNAuda~q!7?1)5r6xoXY`?cJh+C*O3_PP$=K03bxw-LjeS!edTZn)mlxT>GN zw5VS~Wv(rS^AXpLxXuZVLi?4=l+kTD5!7zD+|w9!C6u;3uERT%W81^2##Sv$O7+Yh zmp^h5#fJGK(nsVtB0D8wWK!`FnGNX@dATPh8Gq~0whce7Im5mxf9+S1Xw6fR5mVTI zPbvHJ?{B;~$p_8ck`0fPy%$&=4cITwK7L)BY8$RpwfXhSm2jIQLZ6A&mDRS}70%C0 zq~6|IDE2e=KXWmYMr+IR>~>w3uiDnfrBdbz#8{EXS-!ol4Q=f$x9p5xc_VXlTUH{6 zWoOR#dL|t?l*6{7f<&H;5aBkbLLpBUWwh(ks!6o+v*oY3J%8*AGw(h3x&oK8AEw6I zV<>Ao{AKcoa`?+hIcOVAUZNbdjc!YygG-ei>3x4a)s=h0>VK8rDRyN;>>v6(@)WhF zB%fcO2P;tjDMY&M8@ zrVO)b=6Zd&EvOi=w)z`YJ=%qPe6+Le5#zIu?JvgXP}?t!&oQ?9jL$L|L)jV1k8#C} z&Q8^MjP>hXjr0Bp*^QT&c8u)UrG_m-Wu1w;j^+3p6+NMxXm)XG{uZK@A;FDz8%J)t z?ys_$@p#B?P)%F2>(LtxB4~#=UNGY@Mzu8&e=Juw%jRz&%P5_{ku0Np{y14i3H>d( zi8$KJ=x!Cf~2*=yY8&bJ?0rbtTG2IZJq?1#>3a9nV2pj((H#W^3j-8qdY# z{41AiIsfVmdN#wb3k7JdNt^a zL0sYS1L&JUe-!lXpzj3z1+wiI(Hp&9rax)7vRzAW^g2p^QvU$# z(_m-N*C&$CW1B07UIRcML$>tQII^V=Cxbo}^!cDyfxZOvDClcJuLpe-=vzSF0s1b` z_k-R7`Wv9X1^S1ee++uAt-ZW%vSoQap!We?W4+My+fdepJ&|nb|EbLMGMVYj2zxH; zf}hX2uvfA!m^G{m`$5n*fWC=!?o9OB!n&}x1HTjaeXNVLUSM6=hk<_;_@k_gIFGR| z>{FmC_I5p+Y{}<=-UD%yMGdN0!t(^wbw&8&+&FJN8R zHNf8v{BqVsoGV!u_Jg2r0DT+iJ3xsN35%jH~H-o+h z^!=c>fKJP_M0q~|-9;Ni(hs?0OFwi6{W8$|fZh*uooqRljsrUg_7t!yz@9_4tkavx zmTjp9n8nNpA1+}=*vo)f3w8t8TflB4Tb6e#*|NONpzi_w1+rzij)46(*dKs>8tjbB z_O!CemT47`E#vG1wioOXU^H%Fmu#6<8`(0gkAQK}y&VDBbd#=nnQ=3x}sG7r}PQwny}#w!cClG&8lD}-GKTKVvPLiqY~+;xDx zQyDL>t{3F`)2woe(yzH;?PKPUuRgL|4zgvrvRM~>B#(7r8*3tQT`<-}!tMw041joy zHIWEwtcip@68KTTmys>o^AupF0dq6xy!MfKUPQJG8v&*km=(a(gUzeKc8|2jBRze1 z2<*3CPy6j>V88wP_FcjMsQvc#ZwSga)9yQ!#rTFKI@H`dkjH+V*7#kFwL0y*@TWYJ zmNfSr8q7WWXtuG#oi^U+?4-E*;1TZ|;j!4$zp_2$q_bs7M>R=Do%zUil?>?@Ia_tF zN6Bw&h{@yTZo^%3BhPGdM55h`oc@^0QJ(einb)$nuazNFO4}m+A_;#aMTyyHUna}g zg-B4Xq_yQs&D_WH`CC3iresi>$=;zpkz8u3 zk>oZ=A*_C2zZWLOOn$fcioKr9kk^x$l>SJ2qvl?4!fz2$lFL9lss4CovX5FxYqj{T zjX6slE3|(aN!BP2#>gmBq+L=yBRTdK+JO~&kCO7YrfShKekCs{WV9^V1JT(jZIgPV z-1SYw-9W7~rXtmTO0r1pha3e`YVBqi=7AEl&KktXIg`7J@B z_0q1r#YgUx)IAhaLvs03ycS7mr!i72bw>T!5|6(zC0v{+PjYJhIMsH{GK#dMw24-t zDw4hAZ%b)i3Vn0aW{Jy9-`^zXmA~If8QWc{J)z2F^Jx zs=-pCUJQ$aJVSaQGeH>UVBPCji- zj@#doLbVbVv($fE3Z+n)t#P?iJmVqC8dpmS)k;*vlCQQDN+Hi!<8r6?&qI_oE-i)9 z)6_*UrQfCN!Rbd3OTMVaD?8* zswg9xQ{?dLj>h&GuAk=9=C`(T#Gtru6>|v@_w?)JIe%P^CPg`@`Qyp+AIP6MD~r>; zNAh|izGq+19z&yS%MdGRG&fGZR#J=eD-BLc*^Fbfd9TdeWQtp%61OL)>n)Th)oa%e ziX@oPer2Gt#C|xtC~=S0GSWJmcUrV`Z7aGM*?d#iI<^&c0A0@^o$l9YDY6}INDd)l zZ@*80V$WAb)BOv6j@|C3xF{ymThwP#?y93+lQQ3?7S*15n%O$FulDmPp<{41-CVx` z&!>cLlr15VYib+*R(oDE{ccs`|6EpRrS-&^r~O6W+3_MT+6mKfb1VfA}M`<)TX z(xuUe=Tp*%r=-zBX;}Tb!LUV2h(vnXrQfq9aDakzt>c$uo*PeMTf4L(2 zRdfv3%Btr4Ny$p$sLUU<&IsD?rCD})%FYA%kHVUxZ|d2WPd!U3%1;T)Ys*M-+5Eh= zY_weSt4LEUErjN^DXTl0*-EWwa-zJ_AMdTYTtACXXl9VoJ5!XZl-U*SaSE$9*ihefw#}l~QtAbI}|wxh?Uk%j%)VG#by>t*ic)r1;Ew{_(LM7XLM! ztv&f0c@<{XP7&X;XY>rw3Y+rZTXp?ez3!nak7B9o)Lx;dp@P=FLw({)Nuv?vD&hMd zTYV2b$n3|hynkS6VQs8g{H)NZV67vaTd`%v<4M`I`Iqhf_#>27@+cTf8O<6}n8uVG z#(BRaH@RK4aCt4`R%=SgwlpCX-tSEgnKJ6qwVm#GOiq!n?iH3Xfv)A2{j4gYEcHdP z7bdj;8ksD9q0xx$@JmjQ#~^EZJO))IUore{(lkq3^^m4pW+EDC9?STub9|PT6eKNT zX>k=CU$W0=%||{;zVh;D56H&5;bzzgl6{k@N4b0Zt;pj zb);Fm;wH_ypX}lKwe&2Fw3x+HI)}B4TtU*TBUc4!){(1^N{qu=w1$*j z#73g5Gx9iT*72r=vZvNyte%Q+Sc|7@3y4jCauMi zXAfx=mON{$S+2Y~$7ktTLDFPJYc zveZnBQb_JK4MeqCs76j9x$IP?q!kx^ZyQg}J$-MRv@VIxwj9@3L-1V{w9Aq_L#Mkc zlEd+xDi($As7Q$`o+d8(4%!luR(=+R*L^8@p!$j=m!Im`+Ey#L)mU<0m2!oOrGztD zswG@wO1Kt^z0K0cxlLNy8h^8vGD5qlOtUPq6JBd zSV~rrCTtaH)^RzOCTs&~9!q?UX~NR}fM2nURTZpR!d9ixBBVtu<%p%x8aS+lYh=!{ z!fc`ZS+1BVS6=?^E2*#e>ANq>6^Ot2N@n<*uL?^J-10k_#Jt=1<}10}*1k(CU~Am8 z+ePpqviHAQJl zQ7S0zR_O${Zt-MvIZwnB2Ggjm%kc8fVVZn_5V-%=e;0WjnWR zkiUvS_ZMHG7%vCCyM)cpUrOB#dJoV&pd0rci?GIh$HL}&jb%I|fDeFv4d@eD?@Mp= zDy2V{u=)8*sZR%e4(NP8vgG;sOUd*7$WmVddKC2Kpsxg-pTCsxtOtDq=o>+A1br*$ zyFhOSeLw5MS1qgy`(?7_@1Pt3rWKf@z#M0rZ?LAm@;6d0aF3YY+!B%rV5xE zU={;oJXb2pZah~i>}9~LfOujM&pKe%1M?s-4+FCqm`8!x2FxC|h0osv{%zpfm|1H2 z^8;W$0>)-*XEMl6)HT_Ox(22jFg<|j2h0FqG+>H=(U}o_b__GZu47&Jb~)?9=I2vo zS=Irw9vFUBRWcia*$hk*>msdftP49%whX(Q8IkT@W`unJm_xwu^Q@A26PUMwc^8FS5S(o+By0F)fEz@1cjNsQZBW!*yR)*ck zx(M4ywhX(K8NqL7M%c~3>;YyUF#PPSjEA3{mGQg^%-g`c3rrg@r+`uD!YSi%kS+6* zN489>02qEAS27-8_!(RoPd{Mz8C)692w;kUxdxc=!0GOek=7|-kqzZuW$3VS{< zRS=Ky{H|akz|;b>jBJ?}Kff#UTo23xz-$C&Gcb<=vjdo2z%&E%0x$=FIRs2AFmD3G z&-ltbe*nx!z?=fcLC>eka=G}qRpFCder{FR{Oqq}x&w0=F#UiT0E`CANMMX-f<^qs zGr_{1089|#;b($nex?I66PP)`Q~|@!1j};W4on1?T40s|vj&)Tz^n)6VPG}^vjv## z!0ZGj4$OXFT7WqSOe-*N0`oR7{LHbeuaAH^1&kx3opF&Z{bM|rEbAQ@;~8b48_y^U zyFV~qh-Wa_vc5(E69DEKV1mGu0mIKR%Xlh)nGMWbV5)&x1PnjZEaRyIW;rk`fmsjC zgTQP6#(36Q%v&0PF`ji6{@Dfb7|%Tm-FWU<*e$>ugm_*iTju#qVEB1xSzqr0^C2)F z19KV}S7v*?=aMbsag#06>JH3h!1Myfcz#-xeK0V?fYHg8?Qje*j~2Fwm%_5iaF7=Aum z#`7{TM}TPs<|r`7fH@A#DPR;=yAK^?%e35N%d+$H+|tk8fbjs+2bg}q3zSz)U7v=4UD}{EWEFv+<0$h-W@9RlwXywu~nNOf4`gfms6#KSwUp+5pT( zU^WBO1Pnh@E`7KI7=ET)=7*mtm&|@(UIyj}Fs;BG1?Ctq$ALKwjE$cozrtKYW$<(4 z!p`Go$Au3Ifawa%Wx(_ThM!rN@fgpni+F|s!_TivW(?Uft#QCi0A?~UQ-PTd%v@mR z15*XeoxntZsRd>QFfm}(0`nj+8-UpeOd~K`f!PksZeaETvmcm4z#InVRbY++a}1c{ zz?=rgmJRhzwyX;`*|IJ=1JezdKEU(?W&kk5fEfwQC}73|GZC0lV5R|60nBV*s(`5h z=5}CefmsI33Sia&vmTfSf!Peqqrfx)vlEy&FuQ?i0p=huF9Y)iFmC~K6qpZz`52hf zz_{o?_{ciVC0q7)H`%h@djR7BrVlV)Ucy2r$cmSqaP*c!127wbX#{2~Fx!FI4a{C(_5*VWn8U!l3d~VpjsbHVm{Y(g zv`H=N)IqkaQ#aYN-a7-+4VYfQ^aZ9rFvEZu3Ct*9#sM<{m>@9IfT;jxHZTi-sRm{d zFi~LYfLRXAT43sdc>tJAz-$4g5ttpo>;k44m=}OK0L&p^T7h{Jn74uX0GN+}IR#8c zhxR(nCR^5f9@(Fuj234~&8mCOix9qS^_^{fl~VX|fXn}K;0m>t0E0;U<5eZaf`%mHAI0Mp8h$lIID2>V^u zMc&$27xu?w%X}*IqcoCnkS!TE*^=oDOgCWqurAW-$GWhGkuAfHWJaVriWy;#XI=0U zSr_&+vSru`U}gie0Q73mqoCJ;z8>@kL2m+m8|eE%Zvnj(^fy62#kwe$lHXp&T(V_Z z++<6pGcX=t`T)}p7>#w|pP{S^TPIt_KZY5RhjGjZJIK1=%UBoobh2gGnal`&4l}}D zz`Ee8Sr_&avSrvPGlH*UM%XJ^7yKI5h5Z28GHe4gf`6D9VLu8?6ENF=X$EEwF#CWx zz`98H5bMHzgKU|Hx0n&>9%V+@$5|KrhpY=*p)XTqSO?iMtcz?Jwg8x}z;p+uFEIUq z@d7gfm?B_wU?u<)1f~p_>A=hcW)3jbz$^l0F)+2jECXf*F!jJZ089fgn^+hA+`_uB zx05Y>yOSAF7jb5Uy_a>t?`K`uhsc&;4>Ke9SD6v^TdWKIDC@%hkZc+DV`c<@ni*kd zbZifsO|}f%nQR%h8#99M!Hlr`0@EKDFEAs483jxLnDMNOJWpg@*i*@td6>?ONOvYP z!oHbx!7pH4*te4{!`{h^;3LckdpR&Gfms90gTQP6W+O0-z-$F(J21O}*$d2mU=9NF zGB8Jgc?+1Mz#IeSLts7z<}@&_f_DGpk}dt?CR_TaJ2004(+e0cFoS^^2222$Yk(OK z%w%Au0y7<$n}JyXOf@izfms4f6quF3tN~^nFdKl`2+U?+nt<5`%no371G5*H{lL5o z%n@K(fjJ7yF<_1Za~c?1r}jF{AY0aH0ok%&bOok6FnxjP4~!R>5x^7yqXRPmm>@7^ zz*GP;8<@GkQ~^`NjO^pg2s_HU=+||u3ws6G@*a=1z|;ftATwf5Yy&VGfoTM0D=^!E ziL);9vzv8czd*K({{S;0Z-_N%N5{tecJ{Vv%uEdBI-BJ2muh_I(v7d-t0L?Uc9 z*)nV%*)rV%W<=QTtc$Rhu`cX>WXrGvm=V0jjIfJ<(SaEQOc0ndV5R^w8<@Gk%m?On zVD1Da0?Z0v)&R2(m4a~d1 zv;p%G>!Myxu`X;^m-c+-k}d1VO}4C~ZmbKw2kXM_OSUXye`Z9TdYKXS2w;kU(SaEc z%tT;Hfte1>Okm~!Qw_`_U={;Y2h4I{Rsypgmm}X%1FeCi7j~QVf zU|sm?5bMG|LbhyUZvyi+Fvpk?ZR|KO9|B|R+RnJhmTBdZEz>GsMzrV4fawKHKW0Q) z1Ax(hDFQ|ZW(+VBfhh%MGB7iNnFGwtz|;V9J1}t0E0cIaCF935Gm{);$1DIpL90%q@U~Ke%FJzuG$d-A|CR^sY zGcetN=>be%VEO~&1!e>=MZoC5j0a{SFr~mu1EvC)*}yCSrW%+w$R~m`%WJ0cIO8JAl~*%syaV0OkNNuLAQ1FmD0V2FwS*d<2Z6TYK4EWXpQb zC0o{eH(+`I;{m20FavVbIxm;`5pFb9Eo8JHu$yba8|z_bB#3K-?$_BwTtE$h@xw(Ren zf$0WJA7J_cGXR(oz!U+a12X}bATVXXQ~)y@n7P2z0CPJqcLK8vm=(apfO!Cz24Efr zhW_zj!arM?5o7yyW`y0$x){&*urBNtvZZei0`oF3Zvyi+Fz*8M5iqBKQM$LMl}olv z%T2b-PiJ5}!1Mv8A236K839ZYFynxk089{=X~0wfGaHyHU}}K59hh2RmI1Q@n0jCy z0Hy($ExS12YkrQedV7GZUCOz*GaX2$;pd)B&>`n3ce+2j)RwHURS| zFipU01Ev|6J;3Y(<`6K4fq4~}qre;k<~T5?fw9qpK(f9v$d+S50ok%ny909>F#UiT z0E`Aq5imM1V}J<)QwGcwU}gg|7nu3L+z!m0z(jyq0Za^-wZJq0^Dr=*fY}Pnc3^e_ zvlp2Cz_b8!1ejJ}-UOx%m=A#Y2pGqu?e*m%Th?hV*|JW%0n-B*4=@9O(SR8Wj1J5g zV8#Jc3e03+rUEkun45uF0L)@wmH-n4W+gCdfLRC324FS$OM zz`P2~8^F8;%yD2o1mS3o#v4(>$E#CmjTlY7%wn`ff)u&0GMll84t{4 zV5R~y9hjSeSpZBmFn0nI0j3t17%*#rsR!m^U^W4>1(@x?>;xtb%zj{6fH??ED==>Y z^ENOa0P_(rr+{%?-d?AEQA9554rnF7o-U@Cx_ z4@?y>HNZrGsRd>kFl&LS2j&4_HUYB*m_}f>1G5vDI57Kwc>$OMz#IXl6__`HX#?g1 zU_JuI;c2f^7um8-bIF!<+7+1Yz+47QKVSv`qXAO{j1J5gV1mGu0W$@dnZV2e=4N0P z0kasGCBQ5LW(6=YVAcckATS$%c@&r?V739%49p&2_5pJcn3sV$0?b>$90leWFdqYR z8W>y8_BzcYTh5UR$d>iq6_{SY^aZ9rFvEZu3Ct*9#sf1Em{MS-12YqtIlxo{vj~{Q zz|;Y=9GI2BtOw>nU^W2rC@@XHYy+klm_5Mk1LhDghkQlFh_wo2F!6_P6K1>4RuO(qE5+9 z)G09Cf$0TIUtszJGYpuKz>ETBJTMc1DFtR4FcrYe2Br#_8enb*rWTlGz^nkK9+(G! zX#i#mFpa=$1!fm8&A{vd<^V8lu%yeL80^YG4)t69uLYnB~B%17no3JS*HbL%R21}OfO*i0@ELu z!N3dyW+X6UfEfqO1YjluGZmQWz{~|^J}_0l+zCtsm|9>~0<#8~b--)@W+O10foTF} z8!$V7*$vEIVDokLGS*HbL%f8$dnC`&z0j3`?1ArL@%t&BH z0W%($iNKTsGYyyuU}gie0GMiE76B6hrWTlGz^nmg9Wd*G*$B*LU>*f#2Qa&UX$EFL zFfG6w1f~_3H-UK@m=A#Y2$)mAxcax(X)f8aFT2T>_1*&*4={az(SR8W%m`p~V8#G5 z4wy1vrT{Yyn7P2r2c`;`JAsJ+Qwz*WVAcS$4wwdD9tLI;FipU017-&>&A{vdW*;zz zfH@4ztH2xu<`^)?fjJF~?W*=V%^+LWX#v@Zz6?xvVEO{n9~dt%BY_zOOaPb(z?lCF z+%|5tlK7w5V{f5d7CILHn`ps8`hU`GiSzQm@toy9@kG=9cOu&f5vTcI2jX_!qO_za z^xL8qrj37D)bd-6{L7+^mfvcu;@|YN{F-uvH0yuBh_!1)iT|{h`0q>qlK(bj{lC=w zUjWIw$-lnZVErxE_Ft70wMF$K$At{CWgDW$+!AewZlO=yYeKi@CGIt$ZJ9(^nj$8` z4j|her8jyFr9T<}2(o4TqsW$RGyu#szyyIQ17->^Gl7`{%+0{m0CPJqcLGxf%yM8> z0#gsn1Hd!@vjvz&V73Ai2WB@gdx1F!%*((W0p@LB-UX%&m{Y*;Z%WF#;NO&#b&*T9 ztgmjs@NY^=rWZ3yDKdKX1*ShR{F{=J;op>$Y0@G7#E>`43n_54rxzggB1<)0Zpc+8M~rQ3@Ve)W(o+Z|0& z6AX_Z()WXz5xyS=%t&B(%#h4%VCDj|fEh6+Ee2)@FtyBxw3Y$00+@3d12#iEk3u|6 z5YH}Pnt|B^ObakP9!MYZcp&}L3e20p@Yo=k4}kdy7#C=_c>Q(` z`^YGVN&bcQCCSGe2mNZ;+uOzoAemPq=k8rlew2zf_ z%5_;Cm5z!{8K@q-!>_)w*rANR8=zk0_(hT>Qb56LU_?J`sPfO=(qrtG=YZqMiw#QQuT* zPQI^vtehFW&pv;|T-33 zx=Q`Nx<*~C{z>_-*9JnU_2N4>hNq&fy<#P&ca&shiXWb(3?ex>bEa zX;Drozf#Y9@|dEGP_)0FICbK;YJ*aKM$ykGO5~ROca-p%<`Z*IKK|ZK`QON&ksryQ za`GD|@5--Js`Ky8-}7ELfBs3z`k5C`+>^gN|BStD^!JpNN{oCv@Wj3o&#Ru}pS4H- zlj75Y_1-_^1qauAKej7cTUeof-a>zB#I@lQU%hvSy{GqLMfDz2l%`CdO19Eu_o+d9 zX}vddzv}%H9be&ddY3CsQhxoc-TOa^-qaR$3D)6LXiWGYrQW;sG1c3RXt&QvX@2!N zexLg5dhg%1)_cpE>b*B@tM^{i#3RUUl-^&7bWr+>pWyI+CFP*vcr=G%w5Z|Tq-&K@Y%=?~A_5MMG_2qHcJLudUq!dtC8g*kfiuLlmtbz63r5%h|Ns;9@ z={t#zd9&=Q_fAC}q`J(UT>HG4x22k)lRCp^_ugydtbS+xc4t%ml-|C~SXP;$4fk~^ zb`&4kHD=e59Rt)EO8(^W`MJIq18cWG8|bJxy*Hm6@U-vANRz8qz4y5%dJdeS^`^YB z%{iWWqT9gN!$FPfB)>E>7z|Wt9m)cMCDAuRk)}Yv>FY_fo6bM?gneKIg*a&BA|uv~ z%D70$Da$Nv4U_MleLdvru4^uX_YnV!C(M#Msq`ZZ?~q3*{GCd-f$R(WW|h1%HjnMm z5&H(!r+96|ej`t#&@ULd`>tZfp;A35O?`+z@x0ypd!=KUn!U63uDYJy->9v6r_$Ye zRNwSuX`p1+4FN}XFz|Y~ZBVg(JXH9!%Vo=Mq5N(7UB=EALvMs!*^xlKcZw1FF@@{D zC)IMq`+?fMPcQm>S9J$JA^v^)*MgsfRPEbk9Rq>9Q@*%Y4YZY;;}ee7>s9`R=Kt-N zC-~pt55pOQ^Sv`poX(0r?(kit`KaX%q~i}m{~c;A-|ID*YqWgt!|(0Niaeg->p-5a z{e{ifRU1gHw2s~@5;S@EWY*67?bK(e{BA9W+S_tv-Oe9x*PEPV&pr8|VP}%PL@ADO z-5s&p2XKupQ9cQ^m2amMTf?7Fuf8H!@AdD!lHPy1SEctG_rD&xiauL^^GQh2TFW`a zcJIQVs(np(ce~fTqQ~iT{ClzB$?#j@--maH9}hnij)kM)JE%s!^aS^mA2!;(tCURd zYQ^b&Oc}l7$JzOB?&%S;~ucuY-wu=yQ%k%qFmWDRdW!{rJ0Sv`d0HS*m`~ z!M{Ctsx<2)q(d9nAs9)2Aa#YkL!C3)lu1dS{++dJic}YYXY!HmHzll*h-MV9XV1 z%Av7x--)(SF;^jdI%&?-I-2dTpNNGX3Oyd$9r}IftN7J=_-Lfcr@viU z8^V!r z_P$IbsjBs-a|e|%)UU2>QnZ28n(kDt8ff?a{e;oSVx8&ysS`iq{uaw4`z!AimW_Am zF&BA{dx2ZC`-0>H8kcFj{Dm==-Kk^`bb9BV9B7R7+(N&r^rm=Q2lW(VLWD|e*7+Tw z)kbM6CS?~6TlPWtov<=^Q0ZW;6ZyT%^Vx+%Y7c}<=zkRsq*j05vj;*~(B~h1-M_H0 zE*^d<{EONvgYSi?KkV&a_~`P@%Z@L&D)?;ZrO*fDfo*$R7bs1GeM8Fbs(UZ=T-c#$ z+6Up5a8vlt+OI;B^|8hMT=vd+TU|S&x;xuf*4Mc@Jf`1IDC8gGt|y0RH)I(xh3>lO zT77<(rqHgeTXSN8v4Kf>gLm5QeJHe~&Wz2WtqvXXy%TDfzTIo5UVX{Vir|lT=5B8b z>rL;3uOgp?m114>?p4(89eu;6^d`$)+z=kIR4s0y)?M$N{kxV>X5^tzN9u`>g;csy zs$N>tY_e<5_ZnZQQuv~Kzf|fhtM~4H;n`3dmG{2iIR>hlX;I2F-q~r4u?=q1?1Qx6 za+k~XysI@FX?j2WO1O}6u#ZMb8WrejyN||+(e}78j?%nVD|Ynu9wu!~le@4jq>!%C zv5i`JPx{oGR2n(X3iRm#6tB)2wIzv()2D^%FIc!|yfm zx{%gyO(?qJkx-~~Uf$JZulO!*=t8ZGNB5;_Huc1%sE-%(NnE0j2dD#TIdTBWg!&bw5QfB+H%0J_@Ux%=_o9 zDy67wV(S}a_eG+5q{*faTrs+I9i44{{K~vV6!JH;tGu+|*wV+Th3D`4W?6*#>_d8W zI7&SCTKL zyHxu?oxF9IdX@KXbt;`xR$o=V4&yz~bnVWhHb@`T2?7uk|Yl{IP+q6*L+j2rZ@dKC3LF zUo3EUAZvh);v4BRpcw572br7mA(pfXSrxwR&-2rC_?JE@X%>DJPm1WO{ zBD&I4GG$(HjPJ&2Pu#O2zk_$3x?3OSE1vwly#BtN(ueZ0$#bjJ&PGqUuFRG{FX+@N z%eqkSUa5X{+RFTq#(A!(>&v3~PHkSWvP|>cQrbletQZ?`XjcuWE%{byV1?qnyQGWO zXTaFN%6t#a!&a(~<@KOmzEbTzFfZ>S-$VIb=;-@uCmPRd;w5FxlyYUz5y{aqqB()@ zM2htSx}L63)qt5sZM39z*NR%buDI`&YXiGh{yu#1LnV3+5w-fSi@$m06<3Z8)CQWv zsxSWdrIg3D>W>;!U*z#l^w*8FuD$|Y)z?rvsfn)%x$`~L*ZHctg!($aXAbljNA`iH z+8kn^@2s^^e^IEV{61v!b)mlWzP)(0Q_J+-6#R1JD)N*w;GnkQ4A=%Jnxbt8)i1Bp zBR_Q-<3-#U8!`&J7rqf%6kVrJE}4|~iSMb9Mx&WZvov*3u}g3A1dnSr*C%0BqqUoN zzp^ye8n%;f_S1NIBdyvl{iVC`6B-#?jggT@WzOM#nt`@bJjx{Jly}1Y3-2urO}#hR zsW?M_TGud zw`Dhn;)$a`HubxUio4z0_4RHo-5v^GQP`E@`A+?J z;k$cTamZ1;BHy8P_0=v@ypCdrlh5S)qRR%+8S}{HyURGo9FJT7rP7GFnrA2vsl~?Z zgp~>XdefO}8ZvxKYrkJQE*jN)()mDO8uf3dcQcKnHtj|V^D}i#$Q*+y_xXxu)5iNY zgzhO_t=wHYDbGgNgc1tT9154N&a-Jnl-s3r1?F+^ajmD}(ZS@c$F%~(4ul#LHpSQP zE}EyD{!O!pncMwClyU);C=jxHf39+z1-??Ux2UW0ZCWmsXS143W3Qe3^ZhBVdyDms zB?`?}A5ss7R+TCxBkxtb?h<#&3~H%%Z-d&gyUk}S>`B%;A%)u8>QXnA;l9bGf$M0E z`2DhF(H~5X1a1iEfk53|WpQsa)yPjul}V-gwR(4&Rs2v{wX3@BlW>l9=QEE4-LBVm zR4x1Hndbv9h37wY>ZxC4$HJF{b4ub(e+fSk-bigS=I!xBruTpnr@8zOOI7c0l_=Hg zQ~PtY;iN`Gu~7FyrRjU&&c2OL7e2l1NnYn4Y|QojsOcR_ae>(X&*VU!YV0CyF#nv2uom%aS*&O@tX-!Za`eEt+nO5)3_-${B|3{_q zCdbod`Y)awtG^z$X&Jsa)ur8c|Fi;aZOPpw_Gdy*MIQI~GD3aTuAv3?v4ME(O79EG z{iU6WQM^AWt}Fht&mF!9T^H*@3-dGSx=FG6%4k$B&>RCgYBu_#cbe-T2rEr| z^*lu@vtO%j@^?@Av=6imP-*7eNUi(6-@O=WFh1W1{g{06f)dq(f!qNBn#1)buSlwa zR_{zJURrfhUENiuQvX}4_vx0Q+>m#@?Qg#A-k+5!-U_;ocGy|JlUDe&D*Sor4MnB8 zu3x7_yY_uj-CnG_T|eBey5e4%A-YQH3U!D6@~#0ny*ic!?2+s8KBQQF9CQc&tJLXz zN#WIRC;bP3Vrnn--bbFO_ulh6)%!pIzBSnW&2V*Ha>e?uei52 zg)sLkCe!ZLSDtfgyb|Z}uqVwrd4~Fu(sjFS==j{8-hn5We@U_L>`6N)yo;jC9WZ0I z^D?b%dFB}+t|#TLqqfwg((ci>NB4eOrCk(OZ$3%)#nN~?l~U#XD_*(qZpm{`@LcAg zu@7J`jL@2dcS`=*Kh^uqldheSEqPDTh(NRDXh!^DMeFF(e`fdTt2_9VpXShY?C~i! zU+kg2ojkqGH97qnE79A%zYKPBxppqw*5RT(PfybT< zk__M1^_S~+W^9jaD$dUHMQCO+FgPwh%lAx!!}m-q!}mnlKAKt3Y-hj|r2|Wk58?Ur zC!zO-Q!8<`l|M82$+8xGH(hc6{{AzivB28EeRO4hHkiLGgXTQz0>283+qF>ZKAN_Ysh_pZ&| z3%?s}qn)n7g2Jy=QM#bcKSiaY84<%)itqa`E0 z^+b?!L_T<;ID?=Si9@<)3d_%EXGBjKn?mOr& zwC1k&4&OI8bZh7?Jy6^`TtIcA7fzzQ4Byu|N;Oo9D@YN^WMC=1}LHD@l9qC(o{WGt?4# z%h#E%c%c)f+HK%(Cp!lJGSowzR9ss8oc_!3n-uQy+&4o#?@>w|gMU{xHSe#!E@fHN z8hTMYx1IbX6r8@@>kjfB6pb3;Nj|k{oX^%o`w6khzCV(ZARA&&mzdHcIsMwo>{m*1MFA&l~9*8Kr(i*W|nNbsAmky^rPc z&MWV=@_3Qr<_VQQ&0Gz>CP+lX8C_%#BvlKIB2#8@uDAPU)Nbf>pFuy_&9iuMeI{T=VW< zPJSfxbJyz7b*|SY?+*3O`s$7!>|BxaVkjr;`O?>?PY(Qol-^IT&HhVh?o;o$o_=!H zu1`Xxfj`p-R1%1lzZkT83*YZV^U(Wu-oMrL^!6v~cOK4mZM(N?oOa-5+RX9L+;1PG zxg5NU%j4}K%IhC!OyoU#I~|Rq^-hF#=eK+R9PBw%4MeqPjr}zG9+B3y<7uak&Xl$J z@6um({e?WDXm@GB!0y3U&<@jDB}mu!mqyp>-;Ms+r3daJ_D`jXrU&kW#BmNY-PSGj`sYiRW8No^)~V5axm`JJ^M zS>`Bl?XDlV*3vHJZ72V`EEpJ1GmP!tAgvEe>i$A|w0{mC2*+tJgKJsQ$2oYuciHBb zLY=k8LVxZRr*;0Dp$T~fG`Dz%<}P*ldaNT|w|kStv-6hFC!t2V?&!hy!r6sIb?=0W zhx9UPhjwzbBU#r@X%4N;dS}YbPaSb>ee$uV|7YrbuAWbS_{?oNlXkrqdWY(xEWq^< zFAoM!1P5sy1D}NN&~oS+Y>V_Bq6X}=;})^=HL-W;8?+S7%+_f`K?fa1@cnoauHimMx+r5|2o@!&bigsFi5@DXH z_udk(_kJ_}{{`#4W1jyjyJBgmY@sMp$LEz^@a%dGv^N7Iv z!%voe5*(v%$PNU)Hz>gI$G!C=tH!-0y%-!@Qal1DNno@icsC! zX&>hOGKa=#tM|^#``A}P<^3eY<8fp8v*Q)zmai$wZ7UU}^~{+wFVWv$=-`P{;}q3RmXyahFi&FOUP zCW-FWaJ-ll44BOJ$mWL@+++lFWM--zv%0w!&YE9dHE)4(f&x3}SxVQ!*)vdZxMs|r zU9D`Q)2gkv%Qd@l{*3QPI@>jG-mG$pLV3mv?ly(lGo;X2ab#0@+B3kJc4THP{LaFf z%3H|y6kGW%3l;U!i&c7M*UY=6k`At2#7@ZJRI?U_=G2s%>CBp0ep~gtn#%I(%A4j< z1mu^?%y0=PH1lQ>gWsm`*^(+>FoR>gta=NpvuD)Ipo3K^$8M&Pn+U#e7Nt>LIb${? zarwnY={b7|&Pe9+w8>mv?dHa6R7(fdv49Tp%BgwHuB@t|46AAtDb9$_k!GA3t>oN8 z$C;`+Y%G;}y*XW#$Yl9BT4W9_b=9*KrP@ZqM#ykifd-|yqo6M zET~+#P-fUHssPNQiUYH#;=pBQboRVOGGI1jT|l|6dAH2CsnRTt(DGc|63VG>-!dcN zCAaIA84GTmF~9t_nKHTp(=Q@aXDa5bStEuG)2vQ--EIrh$l|=mXjmC_s**FqLB6L~ z2L189+5CE#{^(k5ywr}W-Bswi#MLQ3a!szAFk2tR?#js@MgMfb?kAJlQNHpOy3jaP zH7B2qjGl^*&SrK}N9OzUug=e*16Kz^ztSlue?%5_7%xR?o*R~bMegX_BDx(b+ew5e zawIu@jYxCb(XVuBhdXpphEc3}U6aDlLX3w_dYnM9si(5CxhZomRh9JPD3>skn#Jc~ zwB@`~Rw=Wxg;UQ-RPd}>GZpm_m0ZG?5H54#C$)5L0 zCG{5&w~=AP8IP%#$T;ZJ=mWw#Mjz13lROO4j)3v{FSh$r^Q6xggw5xF&-TUiMlafT zG3;s7)agzh#r7>l;d>|FXPd(EmFT35p~#j!wy9n|OZZu`S{(5H`ozNANr< z_7nVf>GNvPzby26VuC{7O?H{ke?p&?Lg#qq37z_i!vDXX^TRs-|9Z~PAo^ShI^ToL z`c1@a0DYs-`HHbq=adCe5is@jR(hbvR^4N4^ zhA}#QS?T7cP6ES*+Z;AJss*Y}RZRb3IWf+-Z6r8zC?fW6#!$-{Wkb$+k0;KanTnG# zM*%mgs?(EYQ|xxtIgmb8=Vg54P@PWkc}13s)I#H&p-~8*&>VEendMOIpm7{l4z;f) zg{8D8tke=5sSDHS;XIzZG!CyGgRcHkq5C)Y@;Z>Hg(fyRMu9$af2bl?N7){FU*qA{YQfLS6# z-7|?}K*pFSK%@33Kt~DmF{;9EM4M%#H-S&7&T`|#Y{RZL-fuGAJ912v6b9tjRp)sH z9AHG2XS|;^pph2k7Sp(xuJ25a0Qz6 z!UT0N4$9T!H%@Zv;v>_;)kffN8sJ^30Yp`vJ2=;wM{CWGkp^**@!p-|qdMqd91S#c z<`!aaBSQ1k5cAY^LNXhT$2b~hynn@b_Zsm`G~O$WEKE0YaD!nlH1s;vK)-DqaHmk6 zZhGfz^fF*hUv+-jO!2FR)LRz3W7beQ*VBl>Xp+=4KRp|hjTGh@(cEE#n`6XpW@)Jk z*|=O}qeIp(N`(8O>I@mdx&G|Vbe_K3bSgQV`(3?xBpiNrPhTv{WB8h?5PfZSDH5-2 zFD5mPPcPEK$^+aW0Cf3UZW=1zXT+$g!(YepGWH_1?njAEEoYW80m z!OSjU4z*{4`x`FlO7Gmy`Wn#;GBnM2zf#1KWwbBza@L7yYL!F8r`a!i7<^YAAF1t` zF)^V!&G9!B~-MI3|LkLaA)wT*LhbhQz)JSs{$N+z#2&iM^zasS|S(rLO# z%_PhwDtYrLmqSzYGbxu;gfV)iHO7WNpYGZx9|z}(<_aOCzXG! z5nzhp6C)YY%uFU{M`qPbCjF6FM2xW;CoQhPs`E?c<=d==u||@{rJwvVT;!XgpbW^Q z&BVqemB~EEL$;mn2;ym*J@eB;m>DuEoU$@jv_ms)I7hiKy_d^%MY%}ZhRo#05F!$% z8pjgLsxmcM(dN+%(FkgcqJPII)(X`)xZOBdZ4SXP^MkH=d@-47yg#Ix*OaX$|D<_t zzj?IXJbKX#*J6IWWQspBj|z=gWUkD@Uu$UA9HV2*c44@V9P(v@ce3lrksLiWX|7XR z?p{rkZMjaOjqfu&`Q{g|mE_AohGc9s*Z=%3`Dwo`wD8vIN@LTFb~btC|08?amH&L+ zu;Q};>4wAtp9N#RJJ>vBtapc+wz1wFV%oUgHP*Pa4&(Dj=+7n=&#l7VK%Z~2Jzr7y zlw9xfdd^tylFl!FhEIm&^(NaK_A^`0Ddu`k;YHnfZU;G?iRIgRYG}QT9@3Y4IyJ%( z#)xQ6=7t#!GHCQ@p48LeD=(@2j6fp|*j#;?N#7FI)%mW%L)p zxIWkYg|^s5FWH{Hmk^+++wG#k(*}XLm$lt~opc8D8l%tfL%sAe`pgK^Hu}tP)5bpY zJW0HF!RHUK-NR%K2|JrUc~8VfKM=w0{%^Jg|Blc(+P?{%`_kWqP9L<-*&Zi-!(znG zaen4~X(~l}zI~}zqAxv3O+D8fw2ci69>P=Gr0@;4NiK_g8EsN9AAauIq}-EF*|w#7 ziMfQIzHPh0VcoV};kZURCec34ZChh&bCpB%UfST2oOyb#qW*;cHL&?IHQJ_q*wHDW z!G7u^ASZ9YZiF+l=FY1!_E~@G=#q%V*k_$nO`EXgx6PYfL+Nfxe|B!Ad7=6loL)F< z#(cWQQJ~H3s>m{Z*hZSR(Fco6+vtOS)5boSvQK-d$^4N%Y-CTqO6=2qTTup3yOP(f zXXw0f-6DM)=_&iPr1Q(zrxkG;`?MlXxlhacmc~9U@%PyjdT!cGcRz*YeN~xpnqNHD#bG&bpAaF=D$X9()T)vc$N$OLDKIRI*%bg7CJYQCqaK&=zRWV z(2odx7JV9fvy@Mc=eW>!ll_^EITTU){n%Nw3xB?YQ2Paa6?F zrzd~XMPr1K-j|K^JR-f}hW2SkyaU9k>js%^teA|Qc+$=#w7Hr*d+7cmexET@yO=L* zH1+z2o4~yF!iBoT2xc?pi*$H}oH&j$vRh&l_6kv0sj+jC zoW^4DZp?ML7`?@Hn)im;iM^Pmu5+RK6&w%6FLT9B!djwq8kc;s;h8IFO3nT=V=#9j zxkGa<&#sjj-cIKJ2`xjWVeWdEIhrc!it?4nL%Q>r$8_hCsPM4Pp)c!%wxX}Ke-2P>qr}GtQ z{~#}>ug(%SrOwmEmmD^o?>{vS$X}vOrf3&ZAIbSUKi{WI_gv%qPv_E=EuBW?fci*R zzi0R91%^#&fB%B~T}T?|^+5`Eu4Vh*;Qlw#_^kbRf$^PF z`@6t2QtJGR_|jj0FVHXal`qa;++xjOe%ofu@onO(5_2w(@APddrGBS5ujlVpX?9Na z*4vmZw;%D?eYPWW3{RfbC&qP4JL@R&X5LC-ehD2kzm&VlnB31d68<(}=2ya;nQ_LM zuNr3z2U;RcH#sxDLZh(qD>N>^RdO#qU_@ws`82^u>MF6i!81luiTUvaBl#PR_qj&+ zGBNAVg<1dEsE%1gQCwJVw_Na<6~$SQ_mYe>U7{OO7tR|M#r#6SXJ`dRKEz!f=GT*- z6=p6xM~Os@+eE%AZZe^-InOJv=G_5iUPp0h+)X2a8fIEAc&$a&3O?S?sol{;eB<#87`CPfP6hgH#&lCIl9U(F&VIp8cQH+; zoom_Bg-xejNPOwSrb~k~@WJ`DgR{iDo(5dDDeWr=4rM>B5qh(x=mL=UTt#5jG{=v!wA4e0BCd z^UuY1-u(^gEs+<{{$1^!^J3$*Dfv11fl9iU-*`q$Jkx;B+BRQKoG?v!a`}@yv>d z2%lLoo)r_%f*8-KTyFAzq7NI{kCMM%XS+&K=F%tsI37Pc@)~^_&x(=GuhaC$Jim-* z#Y9-+ITaCqSAK?r_*!EA_0MpOrYBd<_Zg1-#DiqN$ritQ#D#-@PjHDhcV zW7@{pRASmVHoZuad`|6Uwml|uMA&Zfbt~J|^naJ>Q$A1k8rjD4bfoj^6#dDt#&h5v z`ZuZ+mj7h@o!KUyv-htbo0d{)|NPkWu^gK$O*umhIP}98)W7J;pWGjfTcKbM!$X&~ zck-CSzgl6ZuWyapz3A42E3>+#iS2xQce);Gj*rQsz*#sdjpWRHr-tQku({OOyR(F5 z4%F$M1*W#ZFYMdgF67JT+aB}i^Y?r@_U-oP(>L%BWu`s|Y&@U7A!mqL*u?Yc8*;9b zN@D&Y`m%U1*yzjSOvvcV*P1r=<>yI~ea)D2^fVdc`E;_o(xLHu`a(tF$KF$(PbZz9 zAvNY4V*c@WI<}F{FJsOj;xwL57jb@OeOdn2Lj@&vzFoI>Vp{PNdNR)JmBw|4dgG^E zcSL!xZL*)_%V?W|;b(?FU)LS^^P=X@7}L)}&lVS*XlKDX`D_z7%i zp6krta!uDn*Qv#_?1>g>{O-XZMXgsm$#aG@n5B!QWPBR!cA_a6?KWuIM!UVc{)+KCsh`riDVp?8YSQNI1Ubf{fq!zY{kBBD z^_`E*Ur0w2F_~}#IykK}d_Mti=&w6Q&>{C>v&?e6M>tSYX2zY*8Bf(FNr1rqg%gW$@HGk^pQm;f5lLM0&leppsiY~j0S=TaER$>xTA+@!& zvgK}Bt|j~Xb@#ci-+BEWm)iX!?5R1g&*}c1)7|Hu+xO$$d3T({{1QbKWbPmKzC@2Z z7x-7!BR_kvDE&KS)RR626HodCEVjpzpI=S0{&H@|nvkQCg#12E-=m3U^URMw%rnkk z$gZs(^C>EiuRN3U(vm!TDSpA}^6aIPr^@t8^K6l8vg>BElWm@T)5#U{>>P)&c?LPj zv%WHUhI*3CGjD72%-jBn<=M-)Tr8hwe*6{l%wu>C|EHd3SPC%6p5-g?S_1qeyL**M zOBdciVlu-c?QaHUPIQxS>(gQy81pw^t|cQ;zUJjkaP~Ik4fp^RZ&%d&-vAGP&ikvQ zs`zVw`@qLXsN^)fXGM?v%)iOpZMS$)oR%;G#c_HCI%CE+Uc5hZ=q=!n zk35nSgrZgHJ0psgC6`MbrEz){Rm>&6gN6%n)ddcdX8pGN+kW7WvpA`BY3+z`VZwCm z+SKLZ5atw@7FnCP99K?6 z=FXHcji;jEfjeVb@M%dL5K#jL$~EAg00g;LkPBq~9HP{>2C}$9mHl1PjOnCEk|tj4 z*MrduzlGtiDQ67tCs-0x7TOexT09-a!4rw{CvOE`tX^atES`s8&Ie~qQ_V@Zp#g^I zy(XQnsWRp{FlPTL(s(lF7YPKdIIdWf`I0&}<|WO5I5CNr44-jxO*h_(L3Ox+&B36) z9v>J0-r%NY$V;5T41j0G4LHVMfFr4e`I*nHRrBSDV;eYQ{6$hBc3Tj;r)*dox1$&a zpJ+Db9?zMbUd0yL1#wTI<)>an%c~Ig7h2wf_&yjdEIzbi%SR|a2Ybh#K^$Rc*2p*H zQ1mTXhQy>cPH+;&j`RWHN(7lFe`#nq7X}vH;>ji*BkzY^D@P z)#mwFXKeR7FJFl&`F-zYf&5q?zZ%HD3S@gf&HK3oStEYB0-4_oO8wJ;`~bG0)XQYx z+VB=(WdCNli8Hi%uewkeNd$cgJvaQR0lwxD2EF)A>5*qW8>v;f#=bi%>O z80yhB&3b5LF~^Ec{C0DUb=Jt@0xKr#qRo45Fi?sVcR6lN7Z})MVm!6(@n1v>1NQ0bhFxt&Pl<|c-ZnO zG8`ouQ8=+=U0#jETLZ=x*@EJ)owy6dPn`G$ihWLe8wK9NPVBExeCWjgLh*?cKSOcZ z7c4-JhB}83+fHobcTkbsV+=WS1dlP~%po#{oH<0saDkoWjdVkjI5Kd~wwZx*w#^Kj zvu$SJoNY;3tw8YjN;WLNx1-?ZL}$)_p@$u){;5OlM6nUyaAeF)gQs9CgORwb*=%bY zS!}an)21_w*$M`h#SSYrviMsoHhqZGvV&ms&f-6;*mM@Y`#cAXS{9S7*d${LN}I#> z{MYZBUcLz!{suB>8(8Fhfy@&Tsh=OnO9Pqjv=hv)1DUU5lX}?*>?>FYxbsC0y+pAo zmK`-{b4y|)i|JrQwjafvR%~R!-4nI=^kid@bBbO2ylmG#FPDxnaS%3*hLk>P_%ZM{y95oK_y~cY#&&i&h{Ze*x_O$Gn?AYwN* z%|``5eI6mTlvuKh+Vky(_3ge*>i;iaL!BFJsB7q-k(;x!r?(?F zWlDWR!==-w;q|QO^IFUcC#2zca8p&(g21uItFvwqJTF zAYHfD@6J>CmJ^ws`VYyXO#6-x(ZLGA4C@9VGa?OEQFpEV7!jYJ_*g}|T(e0L7+ z2Hyr=21eSOr@+sGNnCdL^%8z!-*AoR688l7c`%7f2fu^A6wEbsCU`6O1u%(A!60}D zd=D9%&YV8T*~!*TAHS;Kkr2;G4lM;Ag;l!K4ep ztzbs81Kb7P1%4Au!t!YD1AmVSXfpVI@Pkx9wcrilA5a0+fj5FTQ2|{HehBC@F6KJs*-5z^r!`;`8X(oYQs1pLKHU!e4rN`FM@FDU(8rGKpSQ>wxN9X@h_(&s9@ zUFr8K{n0=_0r7mhNFQrHDbl}aCZ15}{{-wQi;DDf%!5UG&g?GI$D2PC={4r85uv{c z=ISDSqPeR`ztB8gq+ev-DbgpK&x`b0GvUP0f1R0Mq+e_Xi}ZT)qawY*yi=r4G5=kp zPc|2z5tFmub_8rQ;OWAiT``eWLGG)J9 z+4m{?Zz=nJWuI5}gUWtL+25h;?^5=6EBkwt{c2^uM%k}b_UlypeX9L?s{MY|{-A2# zpxS?++Bd59O{)DN)&4`({;+D_qS_x(?T?y^i}uIIl>UU$w<>*`(zh%9DW&gF`c9<} zEBzUz?=rkOD|CYSiPE1{`twSELFq3l{bx#lN$D>u{S~FZru4l^f74u5H2$~DwShhw z6T406>%7kE&uX06J)zp4@j8oY9IxK+`ZlYdV}9@TldYaJpL(6wh}Ae#t3C-0AZK4= z@GPVyUguTgOpM<=ka#^;jWe%Suk$>m8fRLAUN<>oPQ#hc175!m?Wf_)=Q}7vqQ2Hw z@X#-^VAw8)WVVYe?bPq}3fo1NcG{m1w2Lh5)Yk;MPf9t!{3>;By#+D-Bgb`>zC1C@w}4^1TQlg8pF1xniG$(@o0d0ZuFkXc2$OB%~` z7kxr6ab5CNeOr*i1h{i~z1ZRJuv+Sq66oZQ;h*55fOT5r#aPLca@Be8QpwBEjU5$!uTP2GyV ze5V=c>&mzEVDy+tTZ`L4u?c&4Y*3AMcTC!3pVnzRa0g76x42h^E+0saOFCae`^cgn zHYX`1(Jtw;y?q8AByQ1tgm}H6hixj$!=|L~=$0$lK&Gz0v$yqFm%$V^dM!+0qN9{% zXgY#vY}ij^3#K(qB3#KJ+$8>Caa6Tc47b=E%bdi9bJ7`;c6=(E(weC_L>DI6D~c8- zn+lcTdUaxs#uq5*Az4SQ_sZC0F)cq5iEGM%C-B(7%dM8tJ=8_NoJq<4>)_!k>*jBl zU0G^_D!1MS6|(3CRd(eKbie%C8oLHB?eAN8yQv$vV|l(6DV=W}ScY#g>hQ*6xaUfb z$JlMlK)09V(%`7&&A3+?UVn{Pk}*qBr>RNdx))~5WBxia#C`=hxwc~cj;k}~qpYiw zYZP8XUjp1|f#JTZGA0L|W0CGzYTTg!C$~Xkxa_=wKYuxG{c3-c0-Q`I=5Jnr!*ndg zaNPk8w*$)J)(1FV_mg7&b_BSQ4i?4j3vi<<;0^`2Q!3!H*lszrb9#BTVvsSjfIZ4Dmvb0XGi{et9n}^!MBZ_u!+r6n`TD3jOT?j^n1koCi~%t^Dl=j`!z; z#NSNiuLfVNZe8H~jrU;s<9BlSOY-3LC*yJXvBJF#9Pj%HNx$1s7tUkoNBGVYli)ls zR7>plH_G3Rr`&x*4@tHM-`^hk+x@gL{9cg$CVDXajllp=oy_CGAG_ZG@sPyd>A;2l zwgXoK5dB@~!Sr`Ea9P&-{ew-iKT;MSLlN8<0z3(BryrmA+lPLojZidOdQai@m%&wG zzh7 z&HjJHwuBL?%~Ws9?eU)ScM!N|d^-#A_eX`>^iKspAubu85By%>M#@GA{OR!>cn8l1 zpfiq-&rOhu#^-&k{%1UC>YD9m$@o0(x4=Cm2UH*hcMu(faasTC!g|29mc)MfPX^Y; z``Zj$mbUIr&^`CSxbS%pQY%gUn%LjqKxq&|&mqWzKpnwxm$K~VSx#v|F zmn#E*Nj_J(%Eu0-i_5JKLi*Klng9DjTzGsX#p2QoT$;Gt9{9V)xr^q@D&Rhq zK>;VCj?2&=@C*zZ8JGEiKOL9Re@wR@^#iw*58HT>esx?vz%%NM1N*(+V`FhS1YDZ9 z82o^!_`@OA5_O#~qkubG28DJJbzCNo%h>0eIKCUKH@Dq%T;2t)&9}1vJr`>A0-I;A9?)yx&+{)&rL&E?WbC&4E81mto-en=e8l>bUH~5B}@`h;iZbTqKT9 z$L02O)5YZ%zn3{BP83Ua7>k8(f<5C0M zpGz=;@#(nKPr!Wvv@>721AjU$`+>XGx3dt}Ixb`Je=S21oQ}(8;A9@lJU$ket-z(p zm)(IsUK5e%PsinT;E)OliKydpXky0f0g7?y^Jx0haoI5`V{Y~BEX1FVOZLKy`E~@S zh8MriY84mpMnO0IPF1vyI+%?-znTL+c?!U~~=QbIaL648cW!^>U z_M=CDlXaBtq+cDEkARc7@cCL&EH0k`mnJS}OfLB2v$~{MTynsriA%1w5Enj&ONzy1 z7jSa?BSz+{^CeT4E-uZ$NnBRbAt)A?4&c(nWmVvBjdK@`%X;8&DUguNL+48~9(Jt< ziutnEqhoPd4_t70p2S7(zs~}3)9+T$=grXeji{ z=SE1e`MwWantn6*-|M%W8~a%<&ijFrIB)RySiheEm!{tdQ`7bP5pdG)#tQxBrlsrm zYT*7M#eB!$A9gx^>EIqqw~$#pq>NnT}v!(T$50mpTN`!CNENbFbpJ7Y%txUc;^ z2%N<43F|HH@8`hnj+~EcfBCNz&R@1x@HZMa`qIpI9&j?>Z59083S6UaXHhPG&jDA1 zcE)czfuLCY-Um+3n~5psZ^o>GKimqm6!W(PxHR+K44llD*A1kYzhU6^*jD#ZZhXC$ z7sj{K<756d0{3`|?OQ)PV~-n*-*5$g&jA-ZztZ_KZBAi)a$hVqzGmRkY~SI)->zVM zXJaRl7_s^QaMOG{3u#MmJ{BY9y6iWJ!QU$2zU13kl$-CCz~74%{Ow9PzCD3I`5&xU{N7LL?@-|Hr3&LSSESp% zqk)s{`*H<;lYmPTzbgWNuT=22B<1*e1Anho@V7Rlzs-Tay%qcor}X#pz~7sJzl*UG ko#gZ^i+6$hII<4Sb^Gr<-qdVq#Q6b|lk1S==xE6Q1G z|7U&F^r=(7I(6#QsngXp(;ty|1({3vPI2I|I#@{vr8A3 zm6Tc%6(i*L`$MKl1PnIm*k;+PI*QCS;=&8Ym`!H-qZ6*URFWi^&P);;&e}?hy<5%s z!I3NoVhF2iS8KNU@$*Lu{Aht6E%2iSezd@k7WmNuKU(1bZwt7JiZQ_T>&Jz)FXw|A z9he6ymj$%5`M_QHbob&UOD1}@N%yzW8yIVTs}+oeW?h2WlzC8;Et-0%_LzORLS_%t z-}?2z=EuHZwbWAdBNJUp9L9Pg3%Xhkrn=T7txnxa(%zmi{6BM>0-8_r`_?r3eS4Ze zyS6~9YQ7?`{J2lA^?joI^o_nxB0{@$Q+Kp#U#z=&O{m(lW=oB4-A}b|*1TNf0q>eM zp_QIV-}?RQu6^>$Nna%U*Il>cy)U<{D|+%PU(pu%$&D3ZeQZxEZ?B=fhW1*!_QTBf3Gw#Ouko!H8LMin`n=#} zvV|V-H6N4@ejW{YnGZ9$BSa(G_{x@tR<^pDbHXGYJxe=|jb>r?`j&&|ZV7BmA01e@ zi7d5czXKH{)WNHAw@I2F0II3F7md2Qr|VIE9pw6$Uq`xr%dg{I_tCZB^XdYi!<>G( zdbXfxCUdpkoSz#5z3nWMt_59tHm7~9jq+!Sx!aiLYdI*Bgj_bF`LXr6$C&17;pJ4f zmb=hpwhV&aB$>48)~c`Oh_D;2|G--py;Kp)txeWUjdM4F;yUMU1I4w@Z3JcN-IRMQ zSsTqP%^P!@+Df^p-P&|-PHxkkfiHA#Zj`@D%nf#H)4eIKb*)Y7O*XB!#kHQqdc27=RC? zi;!iDj)8Vl@IzXQEa-cPo=aTDet|6bkJ;#LHhLG)7XJ4{_r?cO6SCk>lc2-7#AWPy z(6U8Wffn+siSBD+4%+CiKqs7I^1lWxTl5XMafr4RHhQUzuC~!@ZS?&%dW((zjg5ZR zM*rSMziFdCvC&`JXy$Iy&2OW7+vq_yTCve%Y_x8p!#4VQ8-0U~UTmYQZS+PP{qHvV zaU1=Njc&BjFWTsLZS*HL`b!&~fSa-=hi>D(BQ)0@+Pn*{b?wHcB zEv7u|Hp^^VSWQ>1X-UQB4J|Px7qg1K`$=pdTf|r@OMQiH&yOkWzz-oe6_NG`81Y1r zt$mXFF}B)bd7B;|<87){zh?Kd$-eHaJ9Dut>GfN4rFWKk*tlC?DnH~|;XCB{$6t~! zmDqW#A8?x>KbbX;WjGUcgHD009Oh-8VG$ew?O|KJpCvF)gKIlmk=VX(v$O-Pb|crt zDe(e{D=X(DQ?$qEN{q+{cU! zU;InV_`g($8m?3RloHOVQ@(aHwK>YL&W|BWF?q|WP@VFuJ6-9=Bn2Dr`oxd~n$^2Q zQrI1-Qxad4ls}_XnH&&xbJXX=zb^%OyFMt`3J=|TTXcT)S$!Fio|ev<^L)MH|Zdb>M? z)w@E};&#;E&RA`&a@-{;f3n(!QmE~%sJj)MG_-vk7#F0To8rr=QKf{HdFum(8KJ~lUjb7`hkE6C^4{Gy ze&4ws5qVA|z@v6=zhh$fAvxAe_= zKN?nPP6Cm{a9Cfcb}P{JJE}i0V)eT24W$E}iuyx4-B~ly;&rY?LTz7+aWP9ONQ^W^ zVY>tG8*+b5l{r2L{8Ky4k$N%uG2A+^2-@Gq`eucAJ&V&@A$Hm-Rq!3eFz+Ri8 zqV*rRcDFNAhJ<-y^@D(KIqFv4VBHHOe?!gkmFdd!Qj^vra#*X@w(gGT`TM5o9)DPW zKiZs~r+r~$?v-Vi{}}Y!`f@_UE5-+g?2qYnN+Fm28Ke16$1KN`FQxv22IBe;DK&fw z_!I7*hEExidQ(AnT~GNY)Tl^$bCDUJ?9uw?(nx;)`G33Qg5keLzltX01eD^I?|hBh zJ)u5o2%ejT@>j-Rji#a_iix>Y4JeNs-{*^MPY88`rE8vYg?g)5@Y0p|oEb;M!Y6$V zfn8WL7=Nmo1b4HbqZi zRi78GQ*w_C#pf@NNcg<^#rKV2xHdh1%3x|!5w+N*RE8z>r>l>(N8er=weVci-hFxo2IUY4rncV`kk#CI8C%xX18|z2GYsg{=mbDNK4Lk>;bPJ+o zKOSE}spMNd5G4+^B*Q1u)Krgq+u+P}ekZtcC&k9km`j}*%|yGIkl^K!|L?3Rn8d>OuKeokd9rH@@dJTJ^Apt7~ zE2}m`c@vRTQqM=->ufyM)n)Ze&4M@G#)f6Nm2X@48msMz`fpl(M(eFM1@xrjnFW{2 zTCEK0(JDw)-JvjSfVhl!`4o?3w=sW~S1CK0#bZ5r=a!YVh97E3-qjq{>OYMRgUzBW zPm`1*OzPh~G`cVYRBGO)=$K_v-Z6N0oih97V@6_Zv(X(Z@o7WCol;W1VQi~gJv#96 zObPABuDKxMEvQot|KWhqjPc(0vL{PYO$t3D-nkKDTsh6EJ6jE}m1X&;+!T$~pNPH_ z&4dOoAW9-C;BNZ@;>0+2Bafrl*Q$A*4CQU`?x|1BY&ID963Q-kc{;9Iy@bedM0&?) zGLGSnbKlF7+Qj?s&Skv=?k?q6nC9u~@T<`eqV9E#(LGV7dZ%AlFeUHN=>70lvZz;W zi3T$_7`cTP&&ZvIUC)aLu;L?HIR5~mYieel^4;_FS=G4GP>0-ORIhu~Fd}6s7Z$t| z>bI#Eyo{pzGRcpXxJ>d6(MM6ql|r$f?vH7zq>+p%M$(MCQ*w=;7P^4HPnuwyf7h$g zqtPBAmpTp_ZcRxEH5yY3Tx?2#o|39w6G6np-QJxQ)^$BieHB(S`-(|v=<9jrig}fo z)Lq>$glUP75aF2(A5 zsw{*OBvcy9v=6j0Pxrw4T5t8cp+_}WXt}XGFfer4v>t&p_2$qdj4n;B46zLq(e9M` zZFQ;Tp^`9D`siML-taUvDN_!FRToz0a><>g!CK3uVaf_=I_lVlVVNGFU1}e_&u|xZ zDMBmieOb-5YPB{Rcvnhds3@YTv$Q;I1LlHccvX^;rj8okTkVy(%r>HaTfo6s9*|;2 zHMinQDPc&uvQkPy#91X375rq#2CRWayD6h#V@_OZEKNg*DZyy@(+z zbZQWL6^^jl(iS{m-B>m*4x`>3hTui3Y*Mq8OTc<4rb-`#IS`)$tGl7Ohup3A## z=y^jY=r#Jms1$14el~R6DE(}c6pC%{f!r6o-k~&2((ZwuR5jjXqy~am>vUJW18bc= z6SIQ6vR~rsYpbIThMtsEB3~c4<;}o~+de!(XT_`BYR= z@$9C&$d=VMMcuH?i-?z3k&&V@Y4{>`piPj&rg#fKjh>&mCSpuq z6Yi0hplz3W>qmPhXeV4f^wN};kXP%e4j<~#<;_g3RU*%9U%hSZGc}K3ulZZV#CxKZ zsz<$A)3vpIPRKV(wXUhVCRhJ@-%Zg8eqTWikE#zFw-y}JAC7(zor&mrld)*}&4stj zSj6M&)5a_#tUn#yu2NhLyij8Vhu&n|V?2rx-;h!Xn;gRmcqO_6l7{Wl zjF)sj)?J^xzH55F-}hMG&C&BRdqd7GjdvE*LMCEcZMV?vk$Z4A2)s~l)TSha?hN-- zbz_RrQ%}=rSDB5vs>VEn?f_Md)kdl(KOzOZ%2C{RJZgGqijiNqF2$n`2(4J1XL$0~ z1w3l+P|a$lc=9}6stJUuS7)QfEXkqeypC`bw|*@lB5t4^%4R8#?@oww#gGitT)HVC zw5;Z?$i(VuEgki`J_GC9t2~Z4>Qb*pn_o%y7-kHH_5r54)XPI#j8*t8g&u0nZDp4L5|VYj+jdfiwbVfh!WVM=O# zYJM?1)vaujy7za5T$$;hJ~bHpZ9^m#W4LcxM4yaj#JdVsSKm7=rcc#1U0=Dppiw!9 z8F@IurbM*MwEoytJiylPt5|s|nxx*g|Iu)&{NA$*SO4e!qxx&n@;%?|`JKNudR8cu++Nd@9XR`V`qdh~9?akc# z%x-$le|=kW=w}5FPD@gg@I3H(zEeM{uZ&jK{BqhM`ND`dToEmSw1bWB z!)sshlk_+6Oi*Dw5c#(mbxOiZ8Ib?8NMpTcZ-MsI?g`raQJ0z!YQ$W+Ll4eKQ#aA1SHT*D>ooVUTd?|bg!Q*k8`L*}O-;GV_0P~QX@7>2Z>b zU1U)PxalazaOyotNBvJ1#%lk(?+UqS_ca4!crJC1JS2Z{ zkzaOQ&{%u9f8xMKB?B$Y^NMLW-I{bLRi!6!iihdgb*K}5iAxjLco5vFzzX}@xZv<=-t z?3YQnk8Lk>g=#ks?h(u|pUGcLVLDK4>d#5$*EPVS}k94*_6?g8O z%n9yO(XV(U8T~@<-~PNIVOMNxo%Y?{?yFS0 z;d$?>XKQq~zHGY-yAz`&0ncbRpWHj`UOa{0d~#1grgE?)5i)dj$B4K6SFrOy=WDNz zdsog!T{9j3#P!YR~R}zr{qmorswt0a@R6#vgcSr7YH&ua;JHD2{P*YmyKlV4+Zxt?lxdiOQ{QloqR<{go|sd-ZV$Y^PFaQ4S|=B`sl zzmQ`rGL~z4UPd$xbE0KVfi9z8=xGGK3yn;pEOCpGZ6v84{XzXs{c1fYs{QJaaT6lY zG3^j`1lopP@Pi&9_DJ_o&0gFiU%1-XSx}Hy%}$J)kayJe6>Ks3g$s;FjJ$lDQsqBl zTwwI!cglM;y_)46V(xqz)kZBZ?+Vvp34QDIuwTV#rmG^Mu-Ip+7}#iRs$18ipH8opNvTTLpg#Z`SJeR%@43zwIBd-P!v? zHWj{+ul?K=!8K3oRd9LAMWKtTv5s(0UJ=j`UF(#mlj-D@&RQv6Fg1qr);~vH!@2KO zHI?c+k>&bX>Wz8^PEP*BMnjWyoGvY`>4O-n@^zk;m5x|S=g5cxCzG=Jz}i!i-v}pH zSKu7-b)1dedQwCG=DFZPJgZ)ayWaabvw%Bz__xy@HJ*?+7?b7qrX4mid{;huZ^OEz zSBxaz(a8JPPt%_QCu8qM|HsC>J)g>ZcbDutWkmE35rOjc+M-v&ZYA?X59~u9YPr)U%E!*>6uY;$+>6vl%>DVt=xR zok!<2h(77?ndGcQ<)%PSb%4)|5|{0}SKf$I%9~IAwIHltjvdA>C5-38{FNW$jP}Fm ztI|Is{wA${tZ)bp_-T5)& zl(7x>9W8u3>dzdz^3!PEh=F`|aFV0G>$|M*ps~^SY2gif-j#RketPfUrr#&0@BM23 z%}G=C9XCG3d=%(3AB{!fa7#E_?XI7S-l`_y9_)%`jF5CUPTXQ{x+i8tKESCF?Qx$; zc?IY1{WEV}c`Pc8NaMW`ht+oreP~F)Pf?#+nW3bAAvZL_zaQO6G4PnO%}CniR?fni z>bB@YoV2C`Vb;_s^Be1w>l*(fT&Ijb`Z+!?J#-wOQ=hv4pR@67Kqra8!HtG1J57IL zL=v7Nv5(MCj6NAT6&|l`@$34X**@j^lm9IEP=?p*86zg+IVVXQp)S{x^rq-5(7SNw zD@F`+>&7|Ei2{#GeM@U*rFz5dww1mQAIVA+*($Fzk2T6;2>7!j_)eUXE76;f z;AXDpTHk>LNlIS_zFFmw6eV=pdrBp&AaCmANk6$PIIS?N$}r0D;#6>sQ4!3$Ix?v+ zIKFgoX}Pg*e(8d$;MA%`v&)R&kOjtqtP*4X{L+e&vf}cg7X|Z!C@#c1RTX&Hm{GQ1 zPSMRq#f_Bk<#+g;>yw)ESX!ywP-8@Jq8Fqb#A z#_VFj=*c{OjHgWjQreT~tGuPMs&qcy5red%`ISr>&<`(nNq%~94TZ}VlM#}rS6`(u zr>e;8r({;q%@t);rSv9S83e#CXPfQfAY;}IV1{o(d%r*xEhr|bXIDH)+}Xud#VD+o zNV?faa=bacY6t1Xvu$0R(~pmy)QjVIH|KQN%{djRltl~wpMJZKY zSWU;u+mtHcqvi5s9068sHBQX0oN~S)NyNJ2^d9{R%JgI_XzF?UYLN?$-oEF zBgn2noMcjW$t`EfXURPRu}hOv0Yi;jP6}KSzzWU<2^$C4Bm`lvBqariNJwWP)F$?j zE(+uZE(|20Aa?_FQjes-7$2NTfl#whcS*&Jmz2z6 z(jyW~LgAIh98aG3{PWfFh@^-r&#Xmr=1{Xs1qY6R=|f0ZSTqYRC_N_O+eb4c%r9P2 zL|!ia(#GUab182%dna^)saiRcer3ZFlNJM*nU+wNU@i!TUjw!EWUdI}SxyLv6{S^+ zDi*+di>nYro|JmVC78i$!J_$0!f{!gU4mePS8EZhrQg_ObA`Dfwn=9RFs|JH2b&D; z|3gfg!h`EPlm0c)1L2yu{=uTD{tcr0-~$Qg5u85aVGO@;VXmtg+m7oAqS2Nj^ht}q zAM@lzCO*EqVm_jQr<6i8bReq)Eeu73K^Ep?TraTkFSPh|z+7SR4}%U{{NeDOVjI5H z;*Z6ZqCDw9@|RltCAhA&@$a_y_;n8ZcN>3;#h(uOyDUE0q`~6<74*wC{%aP07WjX$ z_|)&;Ej~@bHx{4n9^~_6lL)TuW6{+KJQ`ih`le!0*uq4r878_*X_AI%_1NM{stXKn zl5{mL2_xHL2j{aanL@$$iXPtdMCOHRX!xikc>`{IixTvCnAOWxtUn+)E%uhn`u zFPS{5Cy7)ic?AxAgJ;L}C4F4P!!_E5L@yn49qmaL$;{xRYhM~cb&$d>0i9{=lDC&H zfwwr@($M6dZE-s)i56+p0`k&H*J~`Dhe_TZXe)V>Elma|@@}&DrU58x5lFp?~L6 zP3xra7S2A0TMC=C6FKHAlIp==Os8-sfOIdFyytQc>1UaVxPZHFgOl;may`g5d}LLy zD@YDt)e;wb9Us>H62Ap1ye)^Rsda+Wn_zhxSjXbM+)ELZDX$vcfZlsWC^Tch;$Cfmc# zLum>JQvm^BD2)^4^L)uLrEqx8g&Xyt!DA}Y=n88Lr7QRY=z6OJk!TH@4dxxUmz7Nz zNbW%x7%-j6=zai|ZnKVWbxmrG414aTr!bUr~`|`1 zGN&=qDvfJbXCi5SX`E)b6+Cn7c3!4!?CyDzH{act8ks;c0WtH=$jq<|(v7Pylt&*} zp^#*l25GOjP}P**amiF1BKndD%)iFxPXvb1mVW3)$Tp>o=Q`+??vu!OxrGut22QYm z=1pq?xdh~(y9t&nnNlZkslqApcAm+*xS7pu4Ix`;p%)Bh& z!Z(;H?f*n_^6lmLW*lH@B4iD)(Zh+hw#P1X`on!(>EJKpNOkTGpIXYx z=FY=2Y@J)j=y~D~C!&B29COjjFi4LeCZ@@v z!?=D#^fbokxj^jKX>ZE+>)=zu@7UsP@m$GiYWpwSn=;zBLSO^(_uY(o z68A+5Lk|4IjI-v^ERMQon}2!?uVr=P%TWxIdAKL8kwyxR2cF1)yFxJ99FhBBj>+eK zXf+}~b6Kuz_rqhvw@zVRw`h7@_f4V;85@i1$3$Dc`ZtS@D)yDdC*S+p;^V^Trs_h! zbPMd7ztIUmC(r+kp8wem$luq~y2U+hHMWWw6kewyIAX_zJs%DnX#<(d8F@S~Vy8eG z23tI|Y-9I9>vd+RgRvrU0w2V;m+fE7a9_1#4FFEqobMHSnG(+V!TK;i`nS38edbwR zM{azdlxL0>2Rnk`Cz#nxdO+&Yj+H~KeuBlX+`mVeEbiZ9Oq%;Q1w`%x<2XTFe=mLBoeS$1}{U1bwPxE!0Xsd0DMF(;9V9o@d?uUe@9T0sskUE|7_yPNl)4ctm#>kj|&vD9e(!6M0P23_<1cBwhiM`@e`&F@|hS@b;+ z#^?P;6Vra)fw#UJw13ezF4^S+`Z?tP?V;T?)oFhZTKX!1`%2tQrky65Hn7`iKUie5 zEs(_5O1X*o9(FqNgRztNRYci>GV!wrCf&v#t=jq1<)_=}fMqB8wG26ii#F&;U9l7Q zrXSA2i(3gl7^7driC+WVel`u*G8B)=6o`=Q{&W~+@+bP?5MOt^(f6>^?;zlZvFe1K z78lJbFJ5pXlVVabnM1gex#oUCtoAnAhcek{HO9&9#Xa!!tBd>UZ7!! z=OTNfAn|P~+Uuwji4{Nds`P4NK^$ znyhJ?Tw;sS5dC{gs%?^mP&DL8V%JdkHm!1v#e~djgdC89E85a|KE-s2UE33vz9t#O z#T0X`XaE3-G0ha`3NdY{*+kYLpJ5eIwZsZB8mosw;!pyYdUzGl6XbWe^al#0S>0y% zftaqb$gtK#TxOf3K#8kRZ62ykt*;kVxKjV(`&RN*u_ice)e|jzob&sDfh72Jr7V1$ zR;!T1X_RTL5G~|zz9mQSNe0nE&iSB)ZsS3JOA8!{(^gxeNhY-=TC|-ATHra2GKEQ^ zg$|r=$q{_n!U#EYP!>8Yv(dk>(VIYvzBr9Cg#n^PUqpXv^(FY!7tx}xM?ecXoJN^! zK(vs<`Ia2PCpkn5IXgiMoj;d1X}3u9Lcoih10;&ybvv9a=s-~@JS}oLgrDM98RO2=7ne> zhx08tf=_aY7IOXuTIlv4Hkq6TmUJUp$mD!Wrr?uIqJ_-kHaVO|J?TcYki+?w9Kk0! zL<>1?L{i~1oVM^plN`bmE%1ppJf~4lK0~zVm-8(-f=_aY7IIY3!Y0?-Xc6H7=W?-^ zB9fB5iguy)Etnbm`*R#SmntpV-iYihv8zo`dwHauUEb-<;%Zp;nX^nWyf2H+B_S4V z7eGkcF2GXZoHj1qD9)f5q0Xcjs?dxpMmtHHsVp6P62hEAu^wok-y)MOh!%6k`8GW9 ziAPz?8Nbh2>x$E;BcCH$$l-iTj^L9FqJM#EX_QGHqJd|@9~@?pDhoNQ|0b*U%8)rt{jxp<$-dB zJP2?343^I$yNh%V2oJK$+A)%RF>X69*b&b5Oo3{iXhZD5+GRabd-r$uSexpZg;Edb z)j>aGa3t&Y#A(t+PLq4cJ>_09Emz% z$04v|Vt?O|vmV5sWbWLQ?R2O4J5BeQU?Oq5TI<96yR-NGgD_^S&F3wi6E5-!%MP=o)gE={BcJ_s%U@X$-C%9*L+v^j|niDK3 z$sP?%aWE?jFXCm<|9E$?^Ic43b}*~t!V3YJvoMR^bSuAjM9G};1r<{ZmIkxN7Zv4) zuP!ROxT+*))RI|oMnQhgs6xG{2+c~2ic(Z(E2ESpb}7T=lpDoW@fK|&CgJ^1r1r0f zg5lIGm^C*im{m0rLUAfIcTw@&(u;>JHp+{uFpgl>Pt;)6RRCOr>vUv#9TjhzR%PMU zsjSMfrKK0=;J+oz%9>wRSy5b)wYapRvdmaOOh`0>&fb*Dijv@&UR)y^lYQx7Pt0v` zB_WHALsQaJKdvRrD>HJxEo3`U=51RcIqEGT?(J$!)tIS2N#LyQQSvMC~EGSzr zxAI~XODigjimdXo`DIlXkA&qqFhU0`*abZ>mWDhIIS*M!9*2TnB zt2_wTS;(`kawe{&$aAf-{etBj zPabx>m25|ebaY`RC{|GlBD-MO2~@C>3o}9E7s&<7(Y&;!=ZwsgF;wygl_ce`KcjVgA@zyd&d5xn?@42<5&y8L)eY&%0nIa^Bwr%4ty57xn28^qkXoc{Rl_< zk&gDG9PP(A+F#^opX+FUv7`MsNBcZSd)?7~yrcc4j`kBB?I$_fPjHIDYzI@(|7Xn(z<{Y*#uS&sIz9rdM-`nit!d5-!U9Q8Lk z>gPM^7dYw{I_ht7)K{_* zYaHb}9p$?m<@Jv821ofGM|mUrw|4s7&mOjwQxQ5E9p!heGCdQdA>MuIsK;BoJP|t$ zchUh?neHQLxO3)OW!h_`A>M_pG7B>Nza4{Esa2+Xd3VGsI?JR)x=^CBxX)3j7BtmS zqIwZxsb0`jM~TX_IYkfBZM4PW^mZj5w&+TI;|^5z4Nar#0A8KcA$y#cbxG?LRFI5!Anma;^HrmoK|c9 zO~dJx?Z3)DtzLYEeOiV1-Zoy*;jePywWs|MMX4%XQl*?W?_%hu%~HqkxOp*W9V3K5 z=L~j^K5afbhR3_d>~@S0-Jdqsox{&G^Z#|LHb0nES$SsrwsVTkkq!@`_m0jiH|{T; z!{XjkVRQ`a*qhFTKHa-!m(E%=mwu#TFvX;cXU(c8T`WrFWeZ9LU4f_Z(n?V(H%bIK zr-J_Gkg~wQUk!=>9Tfi8g-rK^t zo5ttMY|!~KwEZ%zD{#lErMbGtzKxJw@}xB^F(_kYDyi+`^1LxnXnFVGR6@^ zJ?ZD~1UJNnOX>tS(S{Re_Z{gs&xY&PiM-XorJ|nnOX&nxXTt?L!ELqSNG_$0^xI{_ zbvI!h;*QvGbk<3!BYAJyaP)l_CBl(U(B3`4#ixOd#3aypok+sx2t#<03V<7g0@+3M zOZKL7NV~ixz=?T9RosU!0Bx670}!31lDwYClt^ANvR&RUfD3{rlF*O7W3$U^08Z#9 z&LK%2ox9rQH33J@mm&#ybbe}Mv#pp^{(rH8PkK@!c}I}#@?L~7#5pHnguKrkxUYe; z%NMu|2(!!k4!AH0vXa1^1CYIa7?WB64B3y)j46?R^qUI1yhnf&>y|J=-Zc(+PXb5n zNuKZrDz68Q+T;8CATB(K`J#f*X2pkI{TZ!r@-Ri`RXgkxVdVzb~!V!l=CfcJN+yf zw~b|NrVxg!kQdj_!o3Szw#~5w?s?SP?UFj7&9Aa-{k{hrZ)3?D0G!rAzi&I_%>Zr? za5RpPg{N^i?Ggjde%>$ibJ}I~rI=q!UbanMeBLbm`d-G`e(4FEkms~Z8E}o39J&ac z(=Nj&w%G+P#uJUhX_qm;+1HVf=d?@MCXc=|qSTRHW)MyY0Y;EcyUd$pzB5X8hKupk zk-wx~-Zi@v0~i0*45W#Eop#v;9Q8x}()U}GI zRy|#WJg2{`22QM_@fM!sIoHvXzzq~aZ1S9TIrbCN?`ht!q!=DiVQ29pdMZ2Z5(BO)b_q{wvy1pXyd%3j0$f+@@&<5t6pbfgBBxynUSVk#fa|DV z`ppIRFQ$+yle9M0w?6H>O`Ij+>kElS7?*B zrW1J!f$L~pI>)=tChyKpr z`CYTiMBv1{-DAm3#?|QuGrK77Hk-VSHhDea&(?XgOze%oeQEhDmBl#dw{4)~Tbo@= O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_config.h b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_type.h b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E14_specifies_variable_or_code_location_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Example/E15_fft_demo/libraries/doc/version.txt b/Example/E15_fft_demo/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Example/E15_fft_demo/libraries/doc/version.txt +++ b/Example/E15_fft_demo/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Example/E15_fft_demo/libraries/zf_common/zf_common_headfile.h b/Example/E15_fft_demo/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Example/E15_fft_demo/libraries/zf_common/zf_common_headfile.h +++ b/Example/E15_fft_demo/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Example/E15_fft_demo/libraries/zf_device/zf_device_config.a b/Example/E15_fft_demo/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 zcmeFa3w#vS`Tsw&mt=DxS;9p`)a4RHgx%p%KsJTR29zSjB}PgqCE*eTi)4Z|-c56B7E~@=XeNN?Zke&*)*185 zZ=0EVDv|cQTW+PKt7pi<&6zj9Qkgw}(99&kXLWgU1*9Ae9weoT?8S4+XICzoH>*;_ z=neU@v$K7&N(7jw!@mQP%}tHc6jWBYgARGsx)7!GC*lRQk3}> z#*t^J;vt})@_f=+5$KDLFFf#t2fpyY7asV+17CRH3lDtZfiFDpg$KUyz!x4!>j7K& zYDLliI7U%ctr{J?g&2A4SMv4Y`Ew0TiP`8(MsG8U4Ek^hJCAJpQd2LW56N@|rWY_W zc23FWlSiBuE2~y{+BP09Qk57TB;s&dOJWzo`j+<-_BXbCkg&hGv}!)u1(Oq{b?f{Nxw9n9DU`t`x@jrxP%J?Onr2mRWh_m&(e z>fjetbNAuda~q!7?1)5r6xoXY`?cJh+C*O3_PP$=K03bxw-LjeS!edTZn)mlxT>GN zw5VS~Wv(rS^AXpLxXuZVLi?4=l+kTD5!7zD+|w9!C6u;3uERT%W81^2##Sv$O7+Yh zmp^h5#fJGK(nsVtB0D8wWK!`FnGNX@dATPh8Gq~0whce7Im5mxf9+S1Xw6fR5mVTI zPbvHJ?{B;~$p_8ck`0fPy%$&=4cITwK7L)BY8$RpwfXhSm2jIQLZ6A&mDRS}70%C0 zq~6|IDE2e=KXWmYMr+IR>~>w3uiDnfrBdbz#8{EXS-!ol4Q=f$x9p5xc_VXlTUH{6 zWoOR#dL|t?l*6{7f<&H;5aBkbLLpBUWwh(ks!6o+v*oY3J%8*AGw(h3x&oK8AEw6I zV<>Ao{AKcoa`?+hIcOVAUZNbdjc!YygG-ei>3x4a)s=h0>VK8rDRyN;>>v6(@)WhF zB%fcO2P;tjDMY&M8@ zrVO)b=6Zd&EvOi=w)z`YJ=%qPe6+Le5#zIu?JvgXP}?t!&oQ?9jL$L|L)jV1k8#C} z&Q8^MjP>hXjr0Bp*^QT&c8u)UrG_m-Wu1w;j^+3p6+NMxXm)XG{uZK@A;FDz8%J)t z?ys_$@p#B?P)%F2>(LtxB4~#=UNGY@Mzu8&e=Juw%jRz&%P5_{ku0Np{y14i3H>d( zi8$KJ=x!Cf~2*=yY8&bJ?0rbtTG2IZJq?1#>3a9nV2pj((H#W^3j-8qdY# z{41AiIsfVmdN#wb3k7JdNt^a zL0sYS1L&JUe-!lXpzj3z1+wiI(Hp&9rax)7vRzAW^g2p^QvU$# z(_m-N*C&$CW1B07UIRcML$>tQII^V=Cxbo}^!cDyfxZOvDClcJuLpe-=vzSF0s1b` z_k-R7`Wv9X1^S1ee++uAt-ZW%vSoQap!We?W4+My+fdepJ&|nb|EbLMGMVYj2zxH; zf}hX2uvfA!m^G{m`$5n*fWC=!?o9OB!n&}x1HTjaeXNVLUSM6=hk<_;_@k_gIFGR| z>{FmC_I5p+Y{}<=-UD%yMGdN0!t(^wbw&8&+&FJN8R zHNf8v{BqVsoGV!u_Jg2r0DT+iJ3xsN35%jH~H-o+h z^!=c>fKJP_M0q~|-9;Ni(hs?0OFwi6{W8$|fZh*uooqRljsrUg_7t!yz@9_4tkavx zmTjp9n8nNpA1+}=*vo)f3w8t8TflB4Tb6e#*|NONpzi_w1+rzij)46(*dKs>8tjbB z_O!CemT47`E#vG1wioOXU^H%Fmu#6<8`(0gkAQK}y&VDBbd#=nnQ=3x}sG7r}PQwny}#w!cClG&8lD}-GKTKVvPLiqY~+;xDx zQyDL>t{3F`)2woe(yzH;?PKPUuRgL|4zgvrvRM~>B#(7r8*3tQT`<-}!tMw041joy zHIWEwtcip@68KTTmys>o^AupF0dq6xy!MfKUPQJG8v&*km=(a(gUzeKc8|2jBRze1 z2<*3CPy6j>V88wP_FcjMsQvc#ZwSga)9yQ!#rTFKI@H`dkjH+V*7#kFwL0y*@TWYJ zmNfSr8q7WWXtuG#oi^U+?4-E*;1TZ|;j!4$zp_2$q_bs7M>R=Do%zUil?>?@Ia_tF zN6Bw&h{@yTZo^%3BhPGdM55h`oc@^0QJ(einb)$nuazNFO4}m+A_;#aMTyyHUna}g zg-B4Xq_yQs&D_WH`CC3iresi>$=;zpkz8u3 zk>oZ=A*_C2zZWLOOn$fcioKr9kk^x$l>SJ2qvl?4!fz2$lFL9lss4CovX5FxYqj{T zjX6slE3|(aN!BP2#>gmBq+L=yBRTdK+JO~&kCO7YrfShKekCs{WV9^V1JT(jZIgPV z-1SYw-9W7~rXtmTO0r1pha3e`YVBqi=7AEl&KktXIg`7J@B z_0q1r#YgUx)IAhaLvs03ycS7mr!i72bw>T!5|6(zC0v{+PjYJhIMsH{GK#dMw24-t zDw4hAZ%b)i3Vn0aW{Jy9-`^zXmA~If8QWc{J)z2F^Jx zs=-pCUJQ$aJVSaQGeH>UVBPCji- zj@#doLbVbVv($fE3Z+n)t#P?iJmVqC8dpmS)k;*vlCQQDN+Hi!<8r6?&qI_oE-i)9 z)6_*UrQfCN!Rbd3OTMVaD?8* zswg9xQ{?dLj>h&GuAk=9=C`(T#Gtru6>|v@_w?)JIe%P^CPg`@`Qyp+AIP6MD~r>; zNAh|izGq+19z&yS%MdGRG&fGZR#J=eD-BLc*^Fbfd9TdeWQtp%61OL)>n)Th)oa%e ziX@oPer2Gt#C|xtC~=S0GSWJmcUrV`Z7aGM*?d#iI<^&c0A0@^o$l9YDY6}INDd)l zZ@*80V$WAb)BOv6j@|C3xF{ymThwP#?y93+lQQ3?7S*15n%O$FulDmPp<{41-CVx` z&!>cLlr15VYib+*R(oDE{ccs`|6EpRrS-&^r~O6W+3_MT+6mKfb1VfA}M`<)TX z(xuUe=Tp*%r=-zBX;}Tb!LUV2h(vnXrQfq9aDakzt>c$uo*PeMTf4L(2 zRdfv3%Btr4Ny$p$sLUU<&IsD?rCD})%FYA%kHVUxZ|d2WPd!U3%1;T)Ys*M-+5Eh= zY_weSt4LEUErjN^DXTl0*-EWwa-zJ_AMdTYTtACXXl9VoJ5!XZl-U*SaSE$9*ihefw#}l~QtAbI}|wxh?Uk%j%)VG#by>t*ic)r1;Ew{_(LM7XLM! ztv&f0c@<{XP7&X;XY>rw3Y+rZTXp?ez3!nak7B9o)Lx;dp@P=FLw({)Nuv?vD&hMd zTYV2b$n3|hynkS6VQs8g{H)NZV67vaTd`%v<4M`I`Iqhf_#>27@+cTf8O<6}n8uVG z#(BRaH@RK4aCt4`R%=SgwlpCX-tSEgnKJ6qwVm#GOiq!n?iH3Xfv)A2{j4gYEcHdP z7bdj;8ksD9q0xx$@JmjQ#~^EZJO))IUore{(lkq3^^m4pW+EDC9?STub9|PT6eKNT zX>k=CU$W0=%||{;zVh;D56H&5;bzzgl6{k@N4b0Zt;pj zb);Fm;wH_ypX}lKwe&2Fw3x+HI)}B4TtU*TBUc4!){(1^N{qu=w1$*j z#73g5Gx9iT*72r=vZvNyte%Q+Sc|7@3y4jCauMi zXAfx=mON{$S+2Y~$7ktTLDFPJYc zveZnBQb_JK4MeqCs76j9x$IP?q!kx^ZyQg}J$-MRv@VIxwj9@3L-1V{w9Aq_L#Mkc zlEd+xDi($As7Q$`o+d8(4%!luR(=+R*L^8@p!$j=m!Im`+Ey#L)mU<0m2!oOrGztD zswG@wO1Kt^z0K0cxlLNy8h^8vGD5qlOtUPq6JBd zSV~rrCTtaH)^RzOCTs&~9!q?UX~NR}fM2nURTZpR!d9ixBBVtu<%p%x8aS+lYh=!{ z!fc`ZS+1BVS6=?^E2*#e>ANq>6^Ot2N@n<*uL?^J-10k_#Jt=1<}10}*1k(CU~Am8 z+ePpqviHAQJl zQ7S0zR_O${Zt-MvIZwnB2Ggjm%kc8fVVZn_5V-%=e;0WjnWR zkiUvS_ZMHG7%vCCyM)cpUrOB#dJoV&pd0rci?GIh$HL}&jb%I|fDeFv4d@eD?@Mp= zDy2V{u=)8*sZR%e4(NP8vgG;sOUd*7$WmVddKC2Kpsxg-pTCsxtOtDq=o>+A1br*$ zyFhOSeLw5MS1qgy`(?7_@1Pt3rWKf@z#M0rZ?LAm@;6d0aF3YY+!B%rV5xE zU={;oJXb2pZah~i>}9~LfOujM&pKe%1M?s-4+FCqm`8!x2FxC|h0osv{%zpfm|1H2 z^8;W$0>)-*XEMl6)HT_Ox(22jFg<|j2h0FqG+>H=(U}o_b__GZu47&Jb~)?9=I2vo zS=Irw9vFUBRWcia*$hk*>msdftP49%whX(Q8IkT@W`unJm_xwu^Q@A26PUMwc^8FS5S(o+By0F)fEz@1cjNsQZBW!*yR)*ck zx(M4ywhX(K8NqL7M%c~3>;YyUF#PPSjEA3{mGQg^%-g`c3rrg@r+`uD!YSi%kS+6* zN489>02qEAS27-8_!(RoPd{Mz8C)692w;kUxdxc=!0GOek=7|-kqzZuW$3VS{< zRS=Ky{H|akz|;b>jBJ?}Kff#UTo23xz-$C&Gcb<=vjdo2z%&E%0x$=FIRs2AFmD3G z&-ltbe*nx!z?=fcLC>eka=G}qRpFCder{FR{Oqq}x&w0=F#UiT0E`CANMMX-f<^qs zGr_{1089|#;b($nex?I66PP)`Q~|@!1j};W4on1?T40s|vj&)Tz^n)6VPG}^vjv## z!0ZGj4$OXFT7WqSOe-*N0`oR7{LHbeuaAH^1&kx3opF&Z{bM|rEbAQ@;~8b48_y^U zyFV~qh-Wa_vc5(E69DEKV1mGu0mIKR%Xlh)nGMWbV5)&x1PnjZEaRyIW;rk`fmsjC zgTQP6#(36Q%v&0PF`ji6{@Dfb7|%Tm-FWU<*e$>ugm_*iTju#qVEB1xSzqr0^C2)F z19KV}S7v*?=aMbsag#06>JH3h!1Myfcz#-xeK0V?fYHg8?Qje*j~2Fwm%_5iaF7=Aum z#`7{TM}TPs<|r`7fH@A#DPR;=yAK^?%e35N%d+$H+|tk8fbjs+2bg}q3zSz)U7v=4UD}{EWEFv+<0$h-W@9RlwXywu~nNOf4`gfms6#KSwUp+5pT( zU^WBO1Pnh@E`7KI7=ET)=7*mtm&|@(UIyj}Fs;BG1?Ctq$ALKwjE$cozrtKYW$<(4 z!p`Go$Au3Ifawa%Wx(_ThM!rN@fgpni+F|s!_TivW(?Uft#QCi0A?~UQ-PTd%v@mR z15*XeoxntZsRd>QFfm}(0`nj+8-UpeOd~K`f!PksZeaETvmcm4z#InVRbY++a}1c{ zz?=rgmJRhzwyX;`*|IJ=1JezdKEU(?W&kk5fEfwQC}73|GZC0lV5R|60nBV*s(`5h z=5}CefmsI33Sia&vmTfSf!Peqqrfx)vlEy&FuQ?i0p=huF9Y)iFmC~K6qpZz`52hf zz_{o?_{ciVC0q7)H`%h@djR7BrVlV)Ucy2r$cmSqaP*c!127wbX#{2~Fx!FI4a{C(_5*VWn8U!l3d~VpjsbHVm{Y(g zv`H=N)IqkaQ#aYN-a7-+4VYfQ^aZ9rFvEZu3Ct*9#sM<{m>@9IfT;jxHZTi-sRm{d zFi~LYfLRXAT43sdc>tJAz-$4g5ttpo>;k44m=}OK0L&p^T7h{Jn74uX0GN+}IR#8c zhxR(nCR^5f9@(Fuj234~&8mCOix9qS^_^{fl~VX|fXn}K;0m>t0E0;U<5eZaf`%mHAI0Mp8h$lIID2>V^u zMc&$27xu?w%X}*IqcoCnkS!TE*^=oDOgCWqurAW-$GWhGkuAfHWJaVriWy;#XI=0U zSr_&+vSru`U}gie0Q73mqoCJ;z8>@kL2m+m8|eE%Zvnj(^fy62#kwe$lHXp&T(V_Z z++<6pGcX=t`T)}p7>#w|pP{S^TPIt_KZY5RhjGjZJIK1=%UBoobh2gGnal`&4l}}D zz`Ee8Sr_&avSrvPGlH*UM%XJ^7yKI5h5Z28GHe4gf`6D9VLu8?6ENF=X$EEwF#CWx zz`98H5bMHzgKU|Hx0n&>9%V+@$5|KrhpY=*p)XTqSO?iMtcz?Jwg8x}z;p+uFEIUq z@d7gfm?B_wU?u<)1f~p_>A=hcW)3jbz$^l0F)+2jECXf*F!jJZ089fgn^+hA+`_uB zx05Y>yOSAF7jb5Uy_a>t?`K`uhsc&;4>Ke9SD6v^TdWKIDC@%hkZc+DV`c<@ni*kd zbZifsO|}f%nQR%h8#99M!Hlr`0@EKDFEAs483jxLnDMNOJWpg@*i*@td6>?ONOvYP z!oHbx!7pH4*te4{!`{h^;3LckdpR&Gfms90gTQP6W+O0-z-$F(J21O}*$d2mU=9NF zGB8Jgc?+1Mz#IeSLts7z<}@&_f_DGpk}dt?CR_TaJ2004(+e0cFoS^^2222$Yk(OK z%w%Au0y7<$n}JyXOf@izfms4f6quF3tN~^nFdKl`2+U?+nt<5`%no371G5*H{lL5o z%n@K(fjJ7yF<_1Za~c?1r}jF{AY0aH0ok%&bOok6FnxjP4~!R>5x^7yqXRPmm>@7^ zz*GP;8<@GkQ~^`NjO^pg2s_HU=+||u3ws6G@*a=1z|;ftATwf5Yy&VGfoTM0D=^!E ziL);9vzv8czd*K({{S;0Z-_N%N5{tecJ{Vv%uEdBI-BJ2muh_I(v7d-t0L?Uc9 z*)nV%*)rV%W<=QTtc$Rhu`cX>WXrGvm=V0jjIfJ<(SaEQOc0ndV5R^w8<@Gk%m?On zVD1Da0?Z0v)&R2(m4a~d1 zv;p%G>!Myxu`X;^m-c+-k}d1VO}4C~ZmbKw2kXM_OSUXye`Z9TdYKXS2w;kU(SaEc z%tT;Hfte1>Okm~!Qw_`_U={;Y2h4I{Rsypgmm}X%1FeCi7j~QVf zU|sm?5bMG|LbhyUZvyi+Fvpk?ZR|KO9|B|R+RnJhmTBdZEz>GsMzrV4fawKHKW0Q) z1Ax(hDFQ|ZW(+VBfhh%MGB7iNnFGwtz|;V9J1}t0E0cIaCF935Gm{);$1DIpL90%q@U~Ke%FJzuG$d-A|CR^sY zGcetN=>be%VEO~&1!e>=MZoC5j0a{SFr~mu1EvC)*}yCSrW%+w$R~m`%WJ0cIO8JAl~*%syaV0OkNNuLAQ1FmD0V2FwS*d<2Z6TYK4EWXpQb zC0o{eH(+`I;{m20FavVbIxm;`5pFb9Eo8JHu$yba8|z_bB#3K-?$_BwTtE$h@xw(Ren zf$0WJA7J_cGXR(oz!U+a12X}bATVXXQ~)y@n7P2z0CPJqcLK8vm=(apfO!Cz24Efr zhW_zj!arM?5o7yyW`y0$x){&*urBNtvZZei0`oF3Zvyi+Fz*8M5iqBKQM$LMl}olv z%T2b-PiJ5}!1Mv8A236K839ZYFynxk089{=X~0wfGaHyHU}}K59hh2RmI1Q@n0jCy z0Hy($ExS12YkrQedV7GZUCOz*GaX2$;pd)B&>`n3ce+2j)RwHURS| zFipU01Ev|6J;3Y(<`6K4fq4~}qre;k<~T5?fw9qpK(f9v$d+S50ok%ny909>F#UiT z0E`Aq5imM1V}J<)QwGcwU}gg|7nu3L+z!m0z(jyq0Za^-wZJq0^Dr=*fY}Pnc3^e_ zvlp2Cz_b8!1ejJ}-UOx%m=A#Y2pGqu?e*m%Th?hV*|JW%0n-B*4=@9O(SR8Wj1J5g zV8#Jc3e03+rUEkun45uF0L)@wmH-n4W+gCdfLRC324FS$OM zz`P2~8^F8;%yD2o1mS3o#v4(>$E#CmjTlY7%wn`ff)u&0GMll84t{4 zV5R~y9hjSeSpZBmFn0nI0j3t17%*#rsR!m^U^W4>1(@x?>;xtb%zj{6fH??ED==>Y z^ENOa0P_(rr+{%?-d?AEQA9554rnF7o-U@Cx_ z4@?y>HNZrGsRd>kFl&LS2j&4_HUYB*m_}f>1G5vDI57Kwc>$OMz#IXl6__`HX#?g1 zU_JuI;c2f^7um8-bIF!<+7+1Yz+47QKVSv`qXAO{j1J5gV1mGu0W$@dnZV2e=4N0P z0kasGCBQ5LW(6=YVAcckATS$%c@&r?V739%49p&2_5pJcn3sV$0?b>$90leWFdqYR z8W>y8_BzcYTh5UR$d>iq6_{SY^aZ9rFvEZu3Ct*9#sf1Em{MS-12YqtIlxo{vj~{Q zz|;Y=9GI2BtOw>nU^W2rC@@XHYy+klm_5Mk1LhDghkQlFh_wo2F!6_P6K1>4RuO(qE5+9 z)G09Cf$0TIUtszJGYpuKz>ETBJTMc1DFtR4FcrYe2Br#_8enb*rWTlGz^nkK9+(G! zX#i#mFpa=$1!fm8&A{vd<^V8lu%yeL80^YG4)t69uLYnB~B%17no3JS*HbL%R21}OfO*i0@ELu z!N3dyW+X6UfEfqO1YjluGZmQWz{~|^J}_0l+zCtsm|9>~0<#8~b--)@W+O10foTF} z8!$V7*$vEIVDokLGS*HbL%f8$dnC`&z0j3`?1ArL@%t&BH z0W%($iNKTsGYyyuU}gie0GMiE76B6hrWTlGz^nmg9Wd*G*$B*LU>*f#2Qa&UX$EFL zFfG6w1f~_3H-UK@m=A#Y2$)mAxcax(X)f8aFT2T>_1*&*4={az(SR8W%m`p~V8#G5 z4wy1vrT{Yyn7P2r2c`;`JAsJ+Qwz*WVAcS$4wwdD9tLI;FipU017-&>&A{vdW*;zz zfH@4ztH2xu<`^)?fjJF~?W*=V%^+LWX#v@Zz6?xvVEO{n9~dt%BY_zOOaPb(z?lCF z+%|5tlK7w5V{f5d7CILHn`ps8`hU`GiSzQm@toy9@kG=9cOu&f5vTcI2jX_!qO_za z^xL8qrj37D)bd-6{L7+^mfvcu;@|YN{F-uvH0yuBh_!1)iT|{h`0q>qlK(bj{lC=w zUjWIw$-lnZVErxE_Ft70wMF$K$At{CWgDW$+!AewZlO=yYeKi@CGIt$ZJ9(^nj$8` z4j|her8jyFr9T<}2(o4TqsW$RGyu#szyyIQ17->^Gl7`{%+0{m0CPJqcLGxf%yM8> z0#gsn1Hd!@vjvz&V73Ai2WB@gdx1F!%*((W0p@LB-UX%&m{Y*;Z%WF#;NO&#b&*T9 ztgmjs@NY^=rWZ3yDKdKX1*ShR{F{=J;op>$Y0@G7#E>`43n_54rxzggB1<)0Zpc+8M~rQ3@Ve)W(o+Z|0& z6AX_Z()WXz5xyS=%t&B(%#h4%VCDj|fEh6+Ee2)@FtyBxw3Y$00+@3d12#iEk3u|6 z5YH}Pnt|B^ObakP9!MYZcp&}L3e20p@Yo=k4}kdy7#C=_c>Q(` z`^YGVN&bcQCCSGe2mNZ;+uOzoAemPq=k8rlew2zf_ z%5_;Cm5z!{8K@q-!>_)w*rANR8=zk0_(hT>Qb56LU_?J`sPfO=(qrtG=YZqMiw#QQuT* zPQI^vtehFW&pv;|T-33 zx=Q`Nx<*~C{z>_-*9JnU_2N4>hNq&fy<#P&ca&shiXWb(3?ex>bEa zX;Drozf#Y9@|dEGP_)0FICbK;YJ*aKM$ykGO5~ROca-p%<`Z*IKK|ZK`QON&ksryQ za`GD|@5--Js`Ky8-}7ELfBs3z`k5C`+>^gN|BStD^!JpNN{oCv@Wj3o&#Ru}pS4H- zlj75Y_1-_^1qauAKej7cTUeof-a>zB#I@lQU%hvSy{GqLMfDz2l%`CdO19Eu_o+d9 zX}vddzv}%H9be&ddY3CsQhxoc-TOa^-qaR$3D)6LXiWGYrQW;sG1c3RXt&QvX@2!N zexLg5dhg%1)_cpE>b*B@tM^{i#3RUUl-^&7bWr+>pWyI+CFP*vcr=G%w5Z|Tq-&K@Y%=?~A_5MMG_2qHcJLudUq!dtC8g*kfiuLlmtbz63r5%h|Ns;9@ z={t#zd9&=Q_fAC}q`J(UT>HG4x22k)lRCp^_ugydtbS+xc4t%ml-|C~SXP;$4fk~^ zb`&4kHD=e59Rt)EO8(^W`MJIq18cWG8|bJxy*Hm6@U-vANRz8qz4y5%dJdeS^`^YB z%{iWWqT9gN!$FPfB)>E>7z|Wt9m)cMCDAuRk)}Yv>FY_fo6bM?gneKIg*a&BA|uv~ z%D70$Da$Nv4U_MleLdvru4^uX_YnV!C(M#Msq`ZZ?~q3*{GCd-f$R(WW|h1%HjnMm z5&H(!r+96|ej`t#&@ULd`>tZfp;A35O?`+z@x0ypd!=KUn!U63uDYJy->9v6r_$Ye zRNwSuX`p1+4FN}XFz|Y~ZBVg(JXH9!%Vo=Mq5N(7UB=EALvMs!*^xlKcZw1FF@@{D zC)IMq`+?fMPcQm>S9J$JA^v^)*MgsfRPEbk9Rq>9Q@*%Y4YZY;;}ee7>s9`R=Kt-N zC-~pt55pOQ^Sv`poX(0r?(kit`KaX%q~i}m{~c;A-|ID*YqWgt!|(0Niaeg->p-5a z{e{ifRU1gHw2s~@5;S@EWY*67?bK(e{BA9W+S_tv-Oe9x*PEPV&pr8|VP}%PL@ADO z-5s&p2XKupQ9cQ^m2amMTf?7Fuf8H!@AdD!lHPy1SEctG_rD&xiauL^^GQh2TFW`a zcJIQVs(np(ce~fTqQ~iT{ClzB$?#j@--maH9}hnij)kM)JE%s!^aS^mA2!;(tCURd zYQ^b&Oc}l7$JzOB?&%S;~ucuY-wu=yQ%k%qFmWDRdW!{rJ0Sv`d0HS*m`~ z!M{Ctsx<2)q(d9nAs9)2Aa#YkL!C3)lu1dS{++dJic}YYXY!HmHzll*h-MV9XV1 z%Av7x--)(SF;^jdI%&?-I-2dTpNNGX3Oyd$9r}IftN7J=_-Lfcr@viU z8^V!r z_P$IbsjBs-a|e|%)UU2>QnZ28n(kDt8ff?a{e;oSVx8&ysS`iq{uaw4`z!AimW_Am zF&BA{dx2ZC`-0>H8kcFj{Dm==-Kk^`bb9BV9B7R7+(N&r^rm=Q2lW(VLWD|e*7+Tw z)kbM6CS?~6TlPWtov<=^Q0ZW;6ZyT%^Vx+%Y7c}<=zkRsq*j05vj;*~(B~h1-M_H0 zE*^d<{EONvgYSi?KkV&a_~`P@%Z@L&D)?;ZrO*fDfo*$R7bs1GeM8Fbs(UZ=T-c#$ z+6Up5a8vlt+OI;B^|8hMT=vd+TU|S&x;xuf*4Mc@Jf`1IDC8gGt|y0RH)I(xh3>lO zT77<(rqHgeTXSN8v4Kf>gLm5QeJHe~&Wz2WtqvXXy%TDfzTIo5UVX{Vir|lT=5B8b z>rL;3uOgp?m114>?p4(89eu;6^d`$)+z=kIR4s0y)?M$N{kxV>X5^tzN9u`>g;csy zs$N>tY_e<5_ZnZQQuv~Kzf|fhtM~4H;n`3dmG{2iIR>hlX;I2F-q~r4u?=q1?1Qx6 za+k~XysI@FX?j2WO1O}6u#ZMb8WrejyN||+(e}78j?%nVD|Ynu9wu!~le@4jq>!%C zv5i`JPx{oGR2n(X3iRm#6tB)2wIzv()2D^%FIc!|yfm zx{%gyO(?qJkx-~~Uf$JZulO!*=t8ZGNB5;_Huc1%sE-%(NnE0j2dD#TIdTBWg!&bw5QfB+H%0J_@Ux%=_o9 zDy67wV(S}a_eG+5q{*faTrs+I9i44{{K~vV6!JH;tGu+|*wV+Th3D`4W?6*#>_d8W zI7&SCTKL zyHxu?oxF9IdX@KXbt;`xR$o=V4&yz~bnVWhHb@`T2?7uk|Yl{IP+q6*L+j2rZ@dKC3LF zUo3EUAZvh);v4BRpcw572br7mA(pfXSrxwR&-2rC_?JE@X%>DJPm1WO{ zBD&I4GG$(HjPJ&2Pu#O2zk_$3x?3OSE1vwly#BtN(ueZ0$#bjJ&PGqUuFRG{FX+@N z%eqkSUa5X{+RFTq#(A!(>&v3~PHkSWvP|>cQrbletQZ?`XjcuWE%{byV1?qnyQGWO zXTaFN%6t#a!&a(~<@KOmzEbTzFfZ>S-$VIb=;-@uCmPRd;w5FxlyYUz5y{aqqB()@ zM2htSx}L63)qt5sZM39z*NR%buDI`&YXiGh{yu#1LnV3+5w-fSi@$m06<3Z8)CQWv zsxSWdrIg3D>W>;!U*z#l^w*8FuD$|Y)z?rvsfn)%x$`~L*ZHctg!($aXAbljNA`iH z+8kn^@2s^^e^IEV{61v!b)mlWzP)(0Q_J+-6#R1JD)N*w;GnkQ4A=%Jnxbt8)i1Bp zBR_Q-<3-#U8!`&J7rqf%6kVrJE}4|~iSMb9Mx&WZvov*3u}g3A1dnSr*C%0BqqUoN zzp^ye8n%;f_S1NIBdyvl{iVC`6B-#?jggT@WzOM#nt`@bJjx{Jly}1Y3-2urO}#hR zsW?M_TGud zw`Dhn;)$a`HubxUio4z0_4RHo-5v^GQP`E@`A+?J z;k$cTamZ1;BHy8P_0=v@ypCdrlh5S)qRR%+8S}{HyURGo9FJT7rP7GFnrA2vsl~?Z zgp~>XdefO}8ZvxKYrkJQE*jN)()mDO8uf3dcQcKnHtj|V^D}i#$Q*+y_xXxu)5iNY zgzhO_t=wHYDbGgNgc1tT9154N&a-Jnl-s3r1?F+^ajmD}(ZS@c$F%~(4ul#LHpSQP zE}EyD{!O!pncMwClyU);C=jxHf39+z1-??Ux2UW0ZCWmsXS143W3Qe3^ZhBVdyDms zB?`?}A5ss7R+TCxBkxtb?h<#&3~H%%Z-d&gyUk}S>`B%;A%)u8>QXnA;l9bGf$M0E z`2DhF(H~5X1a1iEfk53|WpQsa)yPjul}V-gwR(4&Rs2v{wX3@BlW>l9=QEE4-LBVm zR4x1Hndbv9h37wY>ZxC4$HJF{b4ub(e+fSk-bigS=I!xBruTpnr@8zOOI7c0l_=Hg zQ~PtY;iN`Gu~7FyrRjU&&c2OL7e2l1NnYn4Y|QojsOcR_ae>(X&*VU!YV0CyF#nv2uom%aS*&O@tX-!Za`eEt+nO5)3_-${B|3{_q zCdbod`Y)awtG^z$X&Jsa)ur8c|Fi;aZOPpw_Gdy*MIQI~GD3aTuAv3?v4ME(O79EG z{iU6WQM^AWt}Fht&mF!9T^H*@3-dGSx=FG6%4k$B&>RCgYBu_#cbe-T2rEr| z^*lu@vtO%j@^?@Av=6imP-*7eNUi(6-@O=WFh1W1{g{06f)dq(f!qNBn#1)buSlwa zR_{zJURrfhUENiuQvX}4_vx0Q+>m#@?Qg#A-k+5!-U_;ocGy|JlUDe&D*Sor4MnB8 zu3x7_yY_uj-CnG_T|eBey5e4%A-YQH3U!D6@~#0ny*ic!?2+s8KBQQF9CQc&tJLXz zN#WIRC;bP3Vrnn--bbFO_ulh6)%!pIzBSnW&2V*Ha>e?uei52 zg)sLkCe!ZLSDtfgyb|Z}uqVwrd4~Fu(sjFS==j{8-hn5We@U_L>`6N)yo;jC9WZ0I z^D?b%dFB}+t|#TLqqfwg((ci>NB4eOrCk(OZ$3%)#nN~?l~U#XD_*(qZpm{`@LcAg zu@7J`jL@2dcS`=*Kh^uqldheSEqPDTh(NRDXh!^DMeFF(e`fdTt2_9VpXShY?C~i! zU+kg2ojkqGH97qnE79A%zYKPBxppqw*5RT(PfybT< zk__M1^_S~+W^9jaD$dUHMQCO+FgPwh%lAx!!}m-q!}mnlKAKt3Y-hj|r2|Wk58?Ur zC!zO-Q!8<`l|M82$+8xGH(hc6{{AzivB28EeRO4hHkiLGgXTQz0>283+qF>ZKAN_Ysh_pZ&| z3%?s}qn)n7g2Jy=QM#bcKSiaY84<%)itqa`E0 z^+b?!L_T<;ID?=Si9@<)3d_%EXGBjKn?mOr& zwC1k&4&OI8bZh7?Jy6^`TtIcA7fzzQ4Byu|N;Oo9D@YN^WMC=1}LHD@l9qC(o{WGt?4# z%h#E%c%c)f+HK%(Cp!lJGSowzR9ss8oc_!3n-uQy+&4o#?@>w|gMU{xHSe#!E@fHN z8hTMYx1IbX6r8@@>kjfB6pb3;Nj|k{oX^%o`w6khzCV(ZARA&&mzdHcIsMwo>{m*1MFA&l~9*8Kr(i*W|nNbsAmky^rPc z&MWV=@_3Qr<_VQQ&0Gz>CP+lX8C_%#BvlKIB2#8@uDAPU)Nbf>pFuy_&9iuMeI{T=VW< zPJSfxbJyz7b*|SY?+*3O`s$7!>|BxaVkjr;`O?>?PY(Qol-^IT&HhVh?o;o$o_=!H zu1`Xxfj`p-R1%1lzZkT83*YZV^U(Wu-oMrL^!6v~cOK4mZM(N?oOa-5+RX9L+;1PG zxg5NU%j4}K%IhC!OyoU#I~|Rq^-hF#=eK+R9PBw%4MeqPjr}zG9+B3y<7uak&Xl$J z@6um({e?WDXm@GB!0y3U&<@jDB}mu!mqyp>-;Ms+r3daJ_D`jXrU&kW#BmNY-PSGj`sYiRW8No^)~V5axm`JJ^M zS>`Bl?XDlV*3vHJZ72V`EEpJ1GmP!tAgvEe>i$A|w0{mC2*+tJgKJsQ$2oYuciHBb zLY=k8LVxZRr*;0Dp$T~fG`Dz%<}P*ldaNT|w|kStv-6hFC!t2V?&!hy!r6sIb?=0W zhx9UPhjwzbBU#r@X%4N;dS}YbPaSb>ee$uV|7YrbuAWbS_{?oNlXkrqdWY(xEWq^< zFAoM!1P5sy1D}NN&~oS+Y>V_Bq6X}=;})^=HL-W;8?+S7%+_f`K?fa1@cnoauHimMx+r5|2o@!&bigsFi5@DXH z_udk(_kJ_}{{`#4W1jyjyJBgmY@sMp$LEz^@a%dGv^N7Iv z!%voe5*(v%$PNU)Hz>gI$G!C=tH!-0y%-!@Qal1DNno@icsC! zX&>hOGKa=#tM|^#``A}P<^3eY<8fp8v*Q)zmai$wZ7UU}^~{+wFVWv$=-`P{;}q3RmXyahFi&FOUP zCW-FWaJ-ll44BOJ$mWL@+++lFWM--zv%0w!&YE9dHE)4(f&x3}SxVQ!*)vdZxMs|r zU9D`Q)2gkv%Qd@l{*3QPI@>jG-mG$pLV3mv?ly(lGo;X2ab#0@+B3kJc4THP{LaFf z%3H|y6kGW%3l;U!i&c7M*UY=6k`At2#7@ZJRI?U_=G2s%>CBp0ep~gtn#%I(%A4j< z1mu^?%y0=PH1lQ>gWsm`*^(+>FoR>gta=NpvuD)Ipo3K^$8M&Pn+U#e7Nt>LIb${? zarwnY={b7|&Pe9+w8>mv?dHa6R7(fdv49Tp%BgwHuB@t|46AAtDb9$_k!GA3t>oN8 z$C;`+Y%G;}y*XW#$Yl9BT4W9_b=9*KrP@ZqM#ykifd-|yqo6M zET~+#P-fUHssPNQiUYH#;=pBQboRVOGGI1jT|l|6dAH2CsnRTt(DGc|63VG>-!dcN zCAaIA84GTmF~9t_nKHTp(=Q@aXDa5bStEuG)2vQ--EIrh$l|=mXjmC_s**FqLB6L~ z2L189+5CE#{^(k5ywr}W-Bswi#MLQ3a!szAFk2tR?#js@MgMfb?kAJlQNHpOy3jaP zH7B2qjGl^*&SrK}N9OzUug=e*16Kz^ztSlue?%5_7%xR?o*R~bMegX_BDx(b+ew5e zawIu@jYxCb(XVuBhdXpphEc3}U6aDlLX3w_dYnM9si(5CxhZomRh9JPD3>skn#Jc~ zwB@`~Rw=Wxg;UQ-RPd}>GZpm_m0ZG?5H54#C$)5L0 zCG{5&w~=AP8IP%#$T;ZJ=mWw#Mjz13lROO4j)3v{FSh$r^Q6xggw5xF&-TUiMlafT zG3;s7)agzh#r7>l;d>|FXPd(EmFT35p~#j!wy9n|OZZu`S{(5H`ozNANr< z_7nVf>GNvPzby26VuC{7O?H{ke?p&?Lg#qq37z_i!vDXX^TRs-|9Z~PAo^ShI^ToL z`c1@a0DYs-`HHbq=adCe5is@jR(hbvR^4N4^ zhA}#QS?T7cP6ES*+Z;AJss*Y}RZRb3IWf+-Z6r8zC?fW6#!$-{Wkb$+k0;KanTnG# zM*%mgs?(EYQ|xxtIgmb8=Vg54P@PWkc}13s)I#H&p-~8*&>VEendMOIpm7{l4z;f) zg{8D8tke=5sSDHS;XIzZG!CyGgRcHkq5C)Y@;Z>Hg(fyRMu9$af2bl?N7){FU*qA{YQfLS6# z-7|?}K*pFSK%@33Kt~DmF{;9EM4M%#H-S&7&T`|#Y{RZL-fuGAJ912v6b9tjRp)sH z9AHG2XS|;^pph2k7Sp(xuJ25a0Qz6 z!UT0N4$9T!H%@Zv;v>_;)kffN8sJ^30Yp`vJ2=;wM{CWGkp^**@!p-|qdMqd91S#c z<`!aaBSQ1k5cAY^LNXhT$2b~hynn@b_Zsm`G~O$WEKE0YaD!nlH1s;vK)-DqaHmk6 zZhGfz^fF*hUv+-jO!2FR)LRz3W7beQ*VBl>Xp+=4KRp|hjTGh@(cEE#n`6XpW@)Jk z*|=O}qeIp(N`(8O>I@mdx&G|Vbe_K3bSgQV`(3?xBpiNrPhTv{WB8h?5PfZSDH5-2 zFD5mPPcPEK$^+aW0Cf3UZW=1zXT+$g!(YepGWH_1?njAEEoYW80m z!OSjU4z*{4`x`FlO7Gmy`Wn#;GBnM2zf#1KWwbBza@L7yYL!F8r`a!i7<^YAAF1t` zF)^V!&G9!B~-MI3|LkLaA)wT*LhbhQz)JSs{$N+z#2&iM^zasS|S(rLO# z%_PhwDtYrLmqSzYGbxu;gfV)iHO7WNpYGZx9|z}(<_aOCzXG! z5nzhp6C)YY%uFU{M`qPbCjF6FM2xW;CoQhPs`E?c<=d==u||@{rJwvVT;!XgpbW^Q z&BVqemB~EEL$;mn2;ym*J@eB;m>DuEoU$@jv_ms)I7hiKy_d^%MY%}ZhRo#05F!$% z8pjgLsxmcM(dN+%(FkgcqJPII)(X`)xZOBdZ4SXP^MkH=d@-47yg#Ix*OaX$|D<_t zzj?IXJbKX#*J6IWWQspBj|z=gWUkD@Uu$UA9HV2*c44@V9P(v@ce3lrksLiWX|7XR z?p{rkZMjaOjqfu&`Q{g|mE_AohGc9s*Z=%3`Dwo`wD8vIN@LTFb~btC|08?amH&L+ zu;Q};>4wAtp9N#RJJ>vBtapc+wz1wFV%oUgHP*Pa4&(Dj=+7n=&#l7VK%Z~2Jzr7y zlw9xfdd^tylFl!FhEIm&^(NaK_A^`0Ddu`k;YHnfZU;G?iRIgRYG}QT9@3Y4IyJ%( z#)xQ6=7t#!GHCQ@p48LeD=(@2j6fp|*j#;?N#7FI)%mW%L)p zxIWkYg|^s5FWH{Hmk^+++wG#k(*}XLm$lt~opc8D8l%tfL%sAe`pgK^Hu}tP)5bpY zJW0HF!RHUK-NR%K2|JrUc~8VfKM=w0{%^Jg|Blc(+P?{%`_kWqP9L<-*&Zi-!(znG zaen4~X(~l}zI~}zqAxv3O+D8fw2ci69>P=Gr0@;4NiK_g8EsN9AAauIq}-EF*|w#7 ziMfQIzHPh0VcoV};kZURCec34ZChh&bCpB%UfST2oOyb#qW*;cHL&?IHQJ_q*wHDW z!G7u^ASZ9YZiF+l=FY1!_E~@G=#q%V*k_$nO`EXgx6PYfL+Nfxe|B!Ad7=6loL)F< z#(cWQQJ~H3s>m{Z*hZSR(Fco6+vtOS)5boSvQK-d$^4N%Y-CTqO6=2qTTup3yOP(f zXXw0f-6DM)=_&iPr1Q(zrxkG;`?MlXxlhacmc~9U@%PyjdT!cGcRz*YeN~xpnqNHD#bG&bpAaF=D$X9()T)vc$N$OLDKIRI*%bg7CJYQCqaK&=zRWV z(2odx7JV9fvy@Mc=eW>!ll_^EITTU){n%Nw3xB?YQ2Paa6?F zrzd~XMPr1K-j|K^JR-f}hW2SkyaU9k>js%^teA|Qc+$=#w7Hr*d+7cmexET@yO=L* zH1+z2o4~yF!iBoT2xc?pi*$H}oH&j$vRh&l_6kv0sj+jC zoW^4DZp?ML7`?@Hn)im;iM^Pmu5+RK6&w%6FLT9B!djwq8kc;s;h8IFO3nT=V=#9j zxkGa<&#sjj-cIKJ2`xjWVeWdEIhrc!it?4nL%Q>r$8_hCsPM4Pp)c!%wxX}Ke-2P>qr}GtQ z{~#}>ug(%SrOwmEmmD^o?>{vS$X}vOrf3&ZAIbSUKi{WI_gv%qPv_E=EuBW?fci*R zzi0R91%^#&fB%B~T}T?|^+5`Eu4Vh*;Qlw#_^kbRf$^PF z`@6t2QtJGR_|jj0FVHXal`qa;++xjOe%ofu@onO(5_2w(@APddrGBS5ujlVpX?9Na z*4vmZw;%D?eYPWW3{RfbC&qP4JL@R&X5LC-ehD2kzm&VlnB31d68<(}=2ya;nQ_LM zuNr3z2U;RcH#sxDLZh(qD>N>^RdO#qU_@ws`82^u>MF6i!81luiTUvaBl#PR_qj&+ zGBNAVg<1dEsE%1gQCwJVw_Na<6~$SQ_mYe>U7{OO7tR|M#r#6SXJ`dRKEz!f=GT*- z6=p6xM~Os@+eE%AZZe^-InOJv=G_5iUPp0h+)X2a8fIEAc&$a&3O?S?sol{;eB<#87`CPfP6hgH#&lCIl9U(F&VIp8cQH+; zoom_Bg-xejNPOwSrb~k~@WJ`DgR{iDo(5dDDeWr=4rM>B5qh(x=mL=UTt#5jG{=v!wA4e0BCd z^UuY1-u(^gEs+<{{$1^!^J3$*Dfv11fl9iU-*`q$Jkx;B+BRQKoG?v!a`}@yv>d z2%lLoo)r_%f*8-KTyFAzq7NI{kCMM%XS+&K=F%tsI37Pc@)~^_&x(=GuhaC$Jim-* z#Y9-+ITaCqSAK?r_*!EA_0MpOrYBd<_Zg1-#DiqN$ritQ#D#-@PjHDhcV zW7@{pRASmVHoZuad`|6Uwml|uMA&Zfbt~J|^naJ>Q$A1k8rjD4bfoj^6#dDt#&h5v z`ZuZ+mj7h@o!KUyv-htbo0d{)|NPkWu^gK$O*umhIP}98)W7J;pWGjfTcKbM!$X&~ zck-CSzgl6ZuWyapz3A42E3>+#iS2xQce);Gj*rQsz*#sdjpWRHr-tQku({OOyR(F5 z4%F$M1*W#ZFYMdgF67JT+aB}i^Y?r@_U-oP(>L%BWu`s|Y&@U7A!mqL*u?Yc8*;9b zN@D&Y`m%U1*yzjSOvvcV*P1r=<>yI~ea)D2^fVdc`E;_o(xLHu`a(tF$KF$(PbZz9 zAvNY4V*c@WI<}F{FJsOj;xwL57jb@OeOdn2Lj@&vzFoI>Vp{PNdNR)JmBw|4dgG^E zcSL!xZL*)_%V?W|;b(?FU)LS^^P=X@7}L)}&lVS*XlKDX`D_z7%i zp6krta!uDn*Qv#_?1>g>{O-XZMXgsm$#aG@n5B!QWPBR!cA_a6?KWuIM!UVc{)+KCsh`riDVp?8YSQNI1Ubf{fq!zY{kBBD z^_`E*Ur0w2F_~}#IykK}d_Mti=&w6Q&>{C>v&?e6M>tSYX2zY*8Bf(FNr1rqg%gW$@HGk^pQm;f5lLM0&leppsiY~j0S=TaER$>xTA+@!& zvgK}Bt|j~Xb@#ci-+BEWm)iX!?5R1g&*}c1)7|Hu+xO$$d3T({{1QbKWbPmKzC@2Z z7x-7!BR_kvDE&KS)RR626HodCEVjpzpI=S0{&H@|nvkQCg#12E-=m3U^URMw%rnkk z$gZs(^C>EiuRN3U(vm!TDSpA}^6aIPr^@t8^K6l8vg>BElWm@T)5#U{>>P)&c?LPj zv%WHUhI*3CGjD72%-jBn<=M-)Tr8hwe*6{l%wu>C|EHd3SPC%6p5-g?S_1qeyL**M zOBdciVlu-c?QaHUPIQxS>(gQy81pw^t|cQ;zUJjkaP~Ik4fp^RZ&%d&-vAGP&ikvQ zs`zVw`@qLXsN^)fXGM?v%)iOpZMS$)oR%;G#c_HCI%CE+Uc5hZ=q=!n zk35nSgrZgHJ0psgC6`MbrEz){Rm>&6gN6%n)ddcdX8pGN+kW7WvpA`BY3+z`VZwCm z+SKLZ5atw@7FnCP99K?6 z=FXHcji;jEfjeVb@M%dL5K#jL$~EAg00g;LkPBq~9HP{>2C}$9mHl1PjOnCEk|tj4 z*MrduzlGtiDQ67tCs-0x7TOexT09-a!4rw{CvOE`tX^atES`s8&Ie~qQ_V@Zp#g^I zy(XQnsWRp{FlPTL(s(lF7YPKdIIdWf`I0&}<|WO5I5CNr44-jxO*h_(L3Ox+&B36) z9v>J0-r%NY$V;5T41j0G4LHVMfFr4e`I*nHRrBSDV;eYQ{6$hBc3Tj;r)*dox1$&a zpJ+Db9?zMbUd0yL1#wTI<)>an%c~Ig7h2wf_&yjdEIzbi%SR|a2Ybh#K^$Rc*2p*H zQ1mTXhQy>cPH+;&j`RWHN(7lFe`#nq7X}vH;>ji*BkzY^D@P z)#mwFXKeR7FJFl&`F-zYf&5q?zZ%HD3S@gf&HK3oStEYB0-4_oO8wJ;`~bG0)XQYx z+VB=(WdCNli8Hi%uewkeNd$cgJvaQR0lwxD2EF)A>5*qW8>v;f#=bi%>O z80yhB&3b5LF~^Ec{C0DUb=Jt@0xKr#qRo45Fi?sVcR6lN7Z})MVm!6(@n1v>1NQ0bhFxt&Pl<|c-ZnO zG8`ouQ8=+=U0#jETLZ=x*@EJ)owy6dPn`G$ihWLe8wK9NPVBExeCWjgLh*?cKSOcZ z7c4-JhB}83+fHobcTkbsV+=WS1dlP~%po#{oH<0saDkoWjdVkjI5Kd~wwZx*w#^Kj zvu$SJoNY;3tw8YjN;WLNx1-?ZL}$)_p@$u){;5OlM6nUyaAeF)gQs9CgORwb*=%bY zS!}an)21_w*$M`h#SSYrviMsoHhqZGvV&ms&f-6;*mM@Y`#cAXS{9S7*d${LN}I#> z{MYZBUcLz!{suB>8(8Fhfy@&Tsh=OnO9Pqjv=hv)1DUU5lX}?*>?>FYxbsC0y+pAo zmK`-{b4y|)i|JrQwjafvR%~R!-4nI=^kid@bBbO2ylmG#FPDxnaS%3*hLk>P_%ZM{y95oK_y~cY#&&i&h{Ze*x_O$Gn?AYwN* z%|``5eI6mTlvuKh+Vky(_3ge*>i;iaL!BFJsB7q-k(;x!r?(?F zWlDWR!==-w;q|QO^IFUcC#2zca8p&(g21uItFvwqJTF zAYHfD@6J>CmJ^ws`VYyXO#6-x(ZLGA4C@9VGa?OEQFpEV7!jYJ_*g}|T(e0L7+ z2Hyr=21eSOr@+sGNnCdL^%8z!-*AoR688l7c`%7f2fu^A6wEbsCU`6O1u%(A!60}D zd=D9%&YV8T*~!*TAHS;Kkr2;G4lM;Ag;l!K4ep ztzbs81Kb7P1%4Au!t!YD1AmVSXfpVI@Pkx9wcrilA5a0+fj5FTQ2|{HehBC@F6KJs*-5z^r!`;`8X(oYQs1pLKHU!e4rN`FM@FDU(8rGKpSQ>wxN9X@h_(&s9@ zUFr8K{n0=_0r7mhNFQrHDbl}aCZ15}{{-wQi;DDf%!5UG&g?GI$D2PC={4r85uv{c z=ISDSqPeR`ztB8gq+ev-DbgpK&x`b0GvUP0f1R0Mq+e_Xi}ZT)qawY*yi=r4G5=kp zPc|2z5tFmub_8rQ;OWAiT``eWLGG)J9 z+4m{?Zz=nJWuI5}gUWtL+25h;?^5=6EBkwt{c2^uM%k}b_UlypeX9L?s{MY|{-A2# zpxS?++Bd59O{)DN)&4`({;+D_qS_x(?T?y^i}uIIl>UU$w<>*`(zh%9DW&gF`c9<} zEBzUz?=rkOD|CYSiPE1{`twSELFq3l{bx#lN$D>u{S~FZru4l^f74u5H2$~DwShhw z6T406>%7kE&uX06J)zp4@j8oY9IxK+`ZlYdV}9@TldYaJpL(6wh}Ae#t3C-0AZK4= z@GPVyUguTgOpM<=ka#^;jWe%Suk$>m8fRLAUN<>oPQ#hc175!m?Wf_)=Q}7vqQ2Hw z@X#-^VAw8)WVVYe?bPq}3fo1NcG{m1w2Lh5)Yk;MPf9t!{3>;By#+D-Bgb`>zC1C@w}4^1TQlg8pF1xniG$(@o0d0ZuFkXc2$OB%~` z7kxr6ab5CNeOr*i1h{i~z1ZRJuv+Sq66oZQ;h*55fOT5r#aPLca@Be8QpwBEjU5$!uTP2GyV ze5V=c>&mzEVDy+tTZ`L4u?c&4Y*3AMcTC!3pVnzRa0g76x42h^E+0saOFCae`^cgn zHYX`1(Jtw;y?q8AByQ1tgm}H6hixj$!=|L~=$0$lK&Gz0v$yqFm%$V^dM!+0qN9{% zXgY#vY}ij^3#K(qB3#KJ+$8>Caa6Tc47b=E%bdi9bJ7`;c6=(E(weC_L>DI6D~c8- zn+lcTdUaxs#uq5*Az4SQ_sZC0F)cq5iEGM%C-B(7%dM8tJ=8_NoJq<4>)_!k>*jBl zU0G^_D!1MS6|(3CRd(eKbie%C8oLHB?eAN8yQv$vV|l(6DV=W}ScY#g>hQ*6xaUfb z$JlMlK)09V(%`7&&A3+?UVn{Pk}*qBr>RNdx))~5WBxia#C`=hxwc~cj;k}~qpYiw zYZP8XUjp1|f#JTZGA0L|W0CGzYTTg!C$~Xkxa_=wKYuxG{c3-c0-Q`I=5Jnr!*ndg zaNPk8w*$)J)(1FV_mg7&b_BSQ4i?4j3vi<<;0^`2Q!3!H*lszrb9#BTVvsSjfIZ4Dmvb0XGi{et9n}^!MBZ_u!+r6n`TD3jOT?j^n1koCi~%t^Dl=j`!z; z#NSNiuLfVNZe8H~jrU;s<9BlSOY-3LC*yJXvBJF#9Pj%HNx$1s7tUkoNBGVYli)ls zR7>plH_G3Rr`&x*4@tHM-`^hk+x@gL{9cg$CVDXajllp=oy_CGAG_ZG@sPyd>A;2l zwgXoK5dB@~!Sr`Ea9P&-{ew-iKT;MSLlN8<0z3(BryrmA+lPLojZidOdQai@m%&wG zzh7 z&HjJHwuBL?%~Ws9?eU)ScM!N|d^-#A_eX`>^iKspAubu85By%>M#@GA{OR!>cn8l1 zpfiq-&rOhu#^-&k{%1UC>YD9m$@o0(x4=Cm2UH*hcMu(faasTC!g|29mc)MfPX^Y; z``Zj$mbUIr&^`CSxbS%pQY%gUn%LjqKxq&|&mqWzKpnwxm$K~VSx#v|F zmn#E*Nj_J(%Eu0-i_5JKLi*Klng9DjTzGsX#p2QoT$;Gt9{9V)xr^q@D&Rhq zK>;VCj?2&=@C*zZ8JGEiKOL9Re@wR@^#iw*58HT>esx?vz%%NM1N*(+V`FhS1YDZ9 z82o^!_`@OA5_O#~qkubG28DJJbzCNo%h>0eIKCUKH@Dq%T;2t)&9}1vJr`>A0-I;A9?)yx&+{)&rL&E?WbC&4E81mto-en=e8l>bUH~5B}@`h;iZbTqKT9 z$L02O)5YZ%zn3{BP83Ua7>k8(f<5C0M zpGz=;@#(nKPr!Wvv@>721AjU$`+>XGx3dt}Ixb`Je=S21oQ}(8;A9@lJU$ket-z(p zm)(IsUK5e%PsinT;E)OliKydpXky0f0g7?y^Jx0haoI5`V{Y~BEX1FVOZLKy`E~@S zh8MriY84mpMnO0IPF1vyI+%?-znTL+c?!U~~=QbIaL648cW!^>U z_M=CDlXaBtq+cDEkARc7@cCL&EH0k`mnJS}OfLB2v$~{MTynsriA%1w5Enj&ONzy1 z7jSa?BSz+{^CeT4E-uZ$NnBRbAt)A?4&c(nWmVvBjdK@`%X;8&DUguNL+48~9(Jt< ziutnEqhoPd4_t70p2S7(zs~}3)9+T$=grXeji{ z=SE1e`MwWantn6*-|M%W8~a%<&ijFrIB)RySiheEm!{tdQ`7bP5pdG)#tQxBrlsrm zYT*7M#eB!$A9gx^>EIqqw~$#pq>NnT}v!(T$50mpTN`!CNENbFbpJ7Y%txUc;^ z2%N<43F|HH@8`hnj+~EcfBCNz&R@1x@HZMa`qIpI9&j?>Z59083S6UaXHhPG&jDA1 zcE)czfuLCY-Um+3n~5psZ^o>GKimqm6!W(PxHR+K44llD*A1kYzhU6^*jD#ZZhXC$ z7sj{K<756d0{3`|?OQ)PV~-n*-*5$g&jA-ZztZ_KZBAi)a$hVqzGmRkY~SI)->zVM zXJaRl7_s^QaMOG{3u#MmJ{BY9y6iWJ!QU$2zU13kl$-CCz~74%{Ow9PzCD3I`5&xU{N7LL?@-|Hr3&LSSESp% zqk)s{`*H<;lYmPTzbgWNuT=22B<1*e1Anho@V7Rlzs-Tay%qcor}X#pz~7sJzl*UG ko#gZ^i+6$hII<4Sb^Gr<-qdVq#Q6b|lk1S==xE6Q1G z|7U&F^r=(7I(6#QsngXp(;ty|1({3vPI2I|I#@{vr8A3 zm6Tc%6(i*L`$MKl1PnIm*k;+PI*QCS;=&8Ym`!H-qZ6*URFWi^&P);;&e}?hy<5%s z!I3NoVhF2iS8KNU@$*Lu{Aht6E%2iSezd@k7WmNuKU(1bZwt7JiZQ_T>&Jz)FXw|A z9he6ymj$%5`M_QHbob&UOD1}@N%yzW8yIVTs}+oeW?h2WlzC8;Et-0%_LzORLS_%t z-}?2z=EuHZwbWAdBNJUp9L9Pg3%Xhkrn=T7txnxa(%zmi{6BM>0-8_r`_?r3eS4Ze zyS6~9YQ7?`{J2lA^?joI^o_nxB0{@$Q+Kp#U#z=&O{m(lW=oB4-A}b|*1TNf0q>eM zp_QIV-}?RQu6^>$Nna%U*Il>cy)U<{D|+%PU(pu%$&D3ZeQZxEZ?B=fhW1*!_QTBf3Gw#Ouko!H8LMin`n=#} zvV|V-H6N4@ejW{YnGZ9$BSa(G_{x@tR<^pDbHXGYJxe=|jb>r?`j&&|ZV7BmA01e@ zi7d5czXKH{)WNHAw@I2F0II3F7md2Qr|VIE9pw6$Uq`xr%dg{I_tCZB^XdYi!<>G( zdbXfxCUdpkoSz#5z3nWMt_59tHm7~9jq+!Sx!aiLYdI*Bgj_bF`LXr6$C&17;pJ4f zmb=hpwhV&aB$>48)~c`Oh_D;2|G--py;Kp)txeWUjdM4F;yUMU1I4w@Z3JcN-IRMQ zSsTqP%^P!@+Df^p-P&|-PHxkkfiHA#Zj`@D%nf#H)4eIKb*)Y7O*XB!#kHQqdc27=RC? zi;!iDj)8Vl@IzXQEa-cPo=aTDet|6bkJ;#LHhLG)7XJ4{_r?cO6SCk>lc2-7#AWPy z(6U8Wffn+siSBD+4%+CiKqs7I^1lWxTl5XMafr4RHhQUzuC~!@ZS?&%dW((zjg5ZR zM*rSMziFdCvC&`JXy$Iy&2OW7+vq_yTCve%Y_x8p!#4VQ8-0U~UTmYQZS+PP{qHvV zaU1=Njc&BjFWTsLZS*HL`b!&~fSa-=hi>D(BQ)0@+Pn*{b?wHcB zEv7u|Hp^^VSWQ>1X-UQB4J|Px7qg1K`$=pdTf|r@OMQiH&yOkWzz-oe6_NG`81Y1r zt$mXFF}B)bd7B;|<87){zh?Kd$-eHaJ9Dut>GfN4rFWKk*tlC?DnH~|;XCB{$6t~! zmDqW#A8?x>KbbX;WjGUcgHD009Oh-8VG$ew?O|KJpCvF)gKIlmk=VX(v$O-Pb|crt zDe(e{D=X(DQ?$qEN{q+{cU! zU;InV_`g($8m?3RloHOVQ@(aHwK>YL&W|BWF?q|WP@VFuJ6-9=Bn2Dr`oxd~n$^2Q zQrI1-Qxad4ls}_XnH&&xbJXX=zb^%OyFMt`3J=|TTXcT)S$!Fio|ev<^L)MH|Zdb>M? z)w@E};&#;E&RA`&a@-{;f3n(!QmE~%sJj)MG_-vk7#F0To8rr=QKf{HdFum(8KJ~lUjb7`hkE6C^4{Gy ze&4ws5qVA|z@v6=zhh$fAvxAe_= zKN?nPP6Cm{a9Cfcb}P{JJE}i0V)eT24W$E}iuyx4-B~ly;&rY?LTz7+aWP9ONQ^W^ zVY>tG8*+b5l{r2L{8Ky4k$N%uG2A+^2-@Gq`eucAJ&V&@A$Hm-Rq!3eFz+Ri8 zqV*rRcDFNAhJ<-y^@D(KIqFv4VBHHOe?!gkmFdd!Qj^vra#*X@w(gGT`TM5o9)DPW zKiZs~r+r~$?v-Vi{}}Y!`f@_UE5-+g?2qYnN+Fm28Ke16$1KN`FQxv22IBe;DK&fw z_!I7*hEExidQ(AnT~GNY)Tl^$bCDUJ?9uw?(nx;)`G33Qg5keLzltX01eD^I?|hBh zJ)u5o2%ejT@>j-Rji#a_iix>Y4JeNs-{*^MPY88`rE8vYg?g)5@Y0p|oEb;M!Y6$V zfn8WL7=Nmo1b4HbqZi zRi78GQ*w_C#pf@NNcg<^#rKV2xHdh1%3x|!5w+N*RE8z>r>l>(N8er=weVci-hFxo2IUY4rncV`kk#CI8C%xX18|z2GYsg{=mbDNK4Lk>;bPJ+o zKOSE}spMNd5G4+^B*Q1u)Krgq+u+P}ekZtcC&k9km`j}*%|yGIkl^K!|L?3Rn8d>OuKeokd9rH@@dJTJ^Apt7~ zE2}m`c@vRTQqM=->ufyM)n)Ze&4M@G#)f6Nm2X@48msMz`fpl(M(eFM1@xrjnFW{2 zTCEK0(JDw)-JvjSfVhl!`4o?3w=sW~S1CK0#bZ5r=a!YVh97E3-qjq{>OYMRgUzBW zPm`1*OzPh~G`cVYRBGO)=$K_v-Z6N0oih97V@6_Zv(X(Z@o7WCol;W1VQi~gJv#96 zObPABuDKxMEvQot|KWhqjPc(0vL{PYO$t3D-nkKDTsh6EJ6jE}m1X&;+!T$~pNPH_ z&4dOoAW9-C;BNZ@;>0+2Bafrl*Q$A*4CQU`?x|1BY&ID963Q-kc{;9Iy@bedM0&?) zGLGSnbKlF7+Qj?s&Skv=?k?q6nC9u~@T<`eqV9E#(LGV7dZ%AlFeUHN=>70lvZz;W zi3T$_7`cTP&&ZvIUC)aLu;L?HIR5~mYieel^4;_FS=G4GP>0-ORIhu~Fd}6s7Z$t| z>bI#Eyo{pzGRcpXxJ>d6(MM6ql|r$f?vH7zq>+p%M$(MCQ*w=;7P^4HPnuwyf7h$g zqtPBAmpTp_ZcRxEH5yY3Tx?2#o|39w6G6np-QJxQ)^$BieHB(S`-(|v=<9jrig}fo z)Lq>$glUP75aF2(A5 zsw{*OBvcy9v=6j0Pxrw4T5t8cp+_}WXt}XGFfer4v>t&p_2$qdj4n;B46zLq(e9M` zZFQ;Tp^`9D`siML-taUvDN_!FRToz0a><>g!CK3uVaf_=I_lVlVVNGFU1}e_&u|xZ zDMBmieOb-5YPB{Rcvnhds3@YTv$Q;I1LlHccvX^;rj8okTkVy(%r>HaTfo6s9*|;2 zHMinQDPc&uvQkPy#91X375rq#2CRWayD6h#V@_OZEKNg*DZyy@(+z zbZQWL6^^jl(iS{m-B>m*4x`>3hTui3Y*Mq8OTc<4rb-`#IS`)$tGl7Ohup3A## z=y^jY=r#Jms1$14el~R6DE(}c6pC%{f!r6o-k~&2((ZwuR5jjXqy~am>vUJW18bc= z6SIQ6vR~rsYpbIThMtsEB3~c4<;}o~+de!(XT_`BYR= z@$9C&$d=VMMcuH?i-?z3k&&V@Y4{>`piPj&rg#fKjh>&mCSpuq z6Yi0hplz3W>qmPhXeV4f^wN};kXP%e4j<~#<;_g3RU*%9U%hSZGc}K3ulZZV#CxKZ zsz<$A)3vpIPRKV(wXUhVCRhJ@-%Zg8eqTWikE#zFw-y}JAC7(zor&mrld)*}&4stj zSj6M&)5a_#tUn#yu2NhLyij8Vhu&n|V?2rx-;h!Xn;gRmcqO_6l7{Wl zjF)sj)?J^xzH55F-}hMG&C&BRdqd7GjdvE*LMCEcZMV?vk$Z4A2)s~l)TSha?hN-- zbz_RrQ%}=rSDB5vs>VEn?f_Md)kdl(KOzOZ%2C{RJZgGqijiNqF2$n`2(4J1XL$0~ z1w3l+P|a$lc=9}6stJUuS7)QfEXkqeypC`bw|*@lB5t4^%4R8#?@oww#gGitT)HVC zw5;Z?$i(VuEgki`J_GC9t2~Z4>Qb*pn_o%y7-kHH_5r54)XPI#j8*t8g&u0nZDp4L5|VYj+jdfiwbVfh!WVM=O# zYJM?1)vaujy7za5T$$;hJ~bHpZ9^m#W4LcxM4yaj#JdVsSKm7=rcc#1U0=Dppiw!9 z8F@IurbM*MwEoytJiylPt5|s|nxx*g|Iu)&{NA$*SO4e!qxx&n@;%?|`JKNudR8cu++Nd@9XR`V`qdh~9?akc# z%x-$le|=kW=w}5FPD@gg@I3H(zEeM{uZ&jK{BqhM`ND`dToEmSw1bWB z!)sshlk_+6Oi*Dw5c#(mbxOiZ8Ib?8NMpTcZ-MsI?g`raQJ0z!YQ$W+Ll4eKQ#aA1SHT*D>ooVUTd?|bg!Q*k8`L*}O-;GV_0P~QX@7>2Z>b zU1U)PxalazaOyotNBvJ1#%lk(?+UqS_ca4!crJC1JS2Z{ zkzaOQ&{%u9f8xMKB?B$Y^NMLW-I{bLRi!6!iihdgb*K}5iAxjLco5vFzzX}@xZv<=-t z?3YQnk8Lk>g=#ks?h(u|pUGcLVLDK4>d#5$*EPVS}k94*_6?g8O z%n9yO(XV(U8T~@<-~PNIVOMNxo%Y?{?yFS0 z;d$?>XKQq~zHGY-yAz`&0ncbRpWHj`UOa{0d~#1grgE?)5i)dj$B4K6SFrOy=WDNz zdsog!T{9j3#P!YR~R}zr{qmorswt0a@R6#vgcSr7YH&ua;JHD2{P*YmyKlV4+Zxt?lxdiOQ{QloqR<{go|sd-ZV$Y^PFaQ4S|=B`sl zzmQ`rGL~z4UPd$xbE0KVfi9z8=xGGK3yn;pEOCpGZ6v84{XzXs{c1fYs{QJaaT6lY zG3^j`1lopP@Pi&9_DJ_o&0gFiU%1-XSx}Hy%}$J)kayJe6>Ks3g$s;FjJ$lDQsqBl zTwwI!cglM;y_)46V(xqz)kZBZ?+Vvp34QDIuwTV#rmG^Mu-Ip+7}#iRs$18ipH8opNvTTLpg#Z`SJeR%@43zwIBd-P!v? zHWj{+ul?K=!8K3oRd9LAMWKtTv5s(0UJ=j`UF(#mlj-D@&RQv6Fg1qr);~vH!@2KO zHI?c+k>&bX>Wz8^PEP*BMnjWyoGvY`>4O-n@^zk;m5x|S=g5cxCzG=Jz}i!i-v}pH zSKu7-b)1dedQwCG=DFZPJgZ)ayWaabvw%Bz__xy@HJ*?+7?b7qrX4mid{;huZ^OEz zSBxaz(a8JPPt%_QCu8qM|HsC>J)g>ZcbDutWkmE35rOjc+M-v&ZYA?X59~u9YPr)U%E!*>6uY;$+>6vl%>DVt=xR zok!<2h(77?ndGcQ<)%PSb%4)|5|{0}SKf$I%9~IAwIHltjvdA>C5-38{FNW$jP}Fm ztI|Is{wA${tZ)bp_-T5)& zl(7x>9W8u3>dzdz^3!PEh=F`|aFV0G>$|M*ps~^SY2gif-j#RketPfUrr#&0@BM23 z%}G=C9XCG3d=%(3AB{!fa7#E_?XI7S-l`_y9_)%`jF5CUPTXQ{x+i8tKESCF?Qx$; zc?IY1{WEV}c`Pc8NaMW`ht+oreP~F)Pf?#+nW3bAAvZL_zaQO6G4PnO%}CniR?fni z>bB@YoV2C`Vb;_s^Be1w>l*(fT&Ijb`Z+!?J#-wOQ=hv4pR@67Kqra8!HtG1J57IL zL=v7Nv5(MCj6NAT6&|l`@$34X**@j^lm9IEP=?p*86zg+IVVXQp)S{x^rq-5(7SNw zD@F`+>&7|Ei2{#GeM@U*rFz5dww1mQAIVA+*($Fzk2T6;2>7!j_)eUXE76;f z;AXDpTHk>LNlIS_zFFmw6eV=pdrBp&AaCmANk6$PIIS?N$}r0D;#6>sQ4!3$Ix?v+ zIKFgoX}Pg*e(8d$;MA%`v&)R&kOjtqtP*4X{L+e&vf}cg7X|Z!C@#c1RTX&Hm{GQ1 zPSMRq#f_Bk<#+g;>yw)ESX!ywP-8@Jq8Fqb#A z#_VFj=*c{OjHgWjQreT~tGuPMs&qcy5red%`ISr>&<`(nNq%~94TZ}VlM#}rS6`(u zr>e;8r({;q%@t);rSv9S83e#CXPfQfAY;}IV1{o(d%r*xEhr|bXIDH)+}Xud#VD+o zNV?faa=bacY6t1Xvu$0R(~pmy)QjVIH|KQN%{djRltl~wpMJZKY zSWU;u+mtHcqvi5s9068sHBQX0oN~S)NyNJ2^d9{R%JgI_XzF?UYLN?$-oEF zBgn2noMcjW$t`EfXURPRu}hOv0Yi;jP6}KSzzWU<2^$C4Bm`lvBqariNJwWP)F$?j zE(+uZE(|20Aa?_FQjes-7$2NTfl#whcS*&Jmz2z6 z(jyW~LgAIh98aG3{PWfFh@^-r&#Xmr=1{Xs1qY6R=|f0ZSTqYRC_N_O+eb4c%r9P2 zL|!ia(#GUab182%dna^)saiRcer3ZFlNJM*nU+wNU@i!TUjw!EWUdI}SxyLv6{S^+ zDi*+di>nYro|JmVC78i$!J_$0!f{!gU4mePS8EZhrQg_ObA`Dfwn=9RFs|JH2b&D; z|3gfg!h`EPlm0c)1L2yu{=uTD{tcr0-~$Qg5u85aVGO@;VXmtg+m7oAqS2Nj^ht}q zAM@lzCO*EqVm_jQr<6i8bReq)Eeu73K^Ep?TraTkFSPh|z+7SR4}%U{{NeDOVjI5H z;*Z6ZqCDw9@|RltCAhA&@$a_y_;n8ZcN>3;#h(uOyDUE0q`~6<74*wC{%aP07WjX$ z_|)&;Ej~@bHx{4n9^~_6lL)TuW6{+KJQ`ih`le!0*uq4r878_*X_AI%_1NM{stXKn zl5{mL2_xHL2j{aanL@$$iXPtdMCOHRX!xikc>`{IixTvCnAOWxtUn+)E%uhn`u zFPS{5Cy7)ic?AxAgJ;L}C4F4P!!_E5L@yn49qmaL$;{xRYhM~cb&$d>0i9{=lDC&H zfwwr@($M6dZE-s)i56+p0`k&H*J~`Dhe_TZXe)V>Elma|@@}&DrU58x5lFp?~L6 zP3xra7S2A0TMC=C6FKHAlIp==Os8-sfOIdFyytQc>1UaVxPZHFgOl;may`g5d}LLy zD@YDt)e;wb9Us>H62Ap1ye)^Rsda+Wn_zhxSjXbM+)ELZDX$vcfZlsWC^Tch;$Cfmc# zLum>JQvm^BD2)^4^L)uLrEqx8g&Xyt!DA}Y=n88Lr7QRY=z6OJk!TH@4dxxUmz7Nz zNbW%x7%-j6=zai|ZnKVWbxmrG414aTr!bUr~`|`1 zGN&=qDvfJbXCi5SX`E)b6+Cn7c3!4!?CyDzH{act8ks;c0WtH=$jq<|(v7Pylt&*} zp^#*l25GOjP}P**amiF1BKndD%)iFxPXvb1mVW3)$Tp>o=Q`+??vu!OxrGut22QYm z=1pq?xdh~(y9t&nnNlZkslqApcAm+*xS7pu4Ix`;p%)Bh& z!Z(;H?f*n_^6lmLW*lH@B4iD)(Zh+hw#P1X`on!(>EJKpNOkTGpIXYx z=FY=2Y@J)j=y~D~C!&B29COjjFi4LeCZ@@v z!?=D#^fbokxj^jKX>ZE+>)=zu@7UsP@m$GiYWpwSn=;zBLSO^(_uY(o z68A+5Lk|4IjI-v^ERMQon}2!?uVr=P%TWxIdAKL8kwyxR2cF1)yFxJ99FhBBj>+eK zXf+}~b6Kuz_rqhvw@zVRw`h7@_f4V;85@i1$3$Dc`ZtS@D)yDdC*S+p;^V^Trs_h! zbPMd7ztIUmC(r+kp8wem$luq~y2U+hHMWWw6kewyIAX_zJs%DnX#<(d8F@S~Vy8eG z23tI|Y-9I9>vd+RgRvrU0w2V;m+fE7a9_1#4FFEqobMHSnG(+V!TK;i`nS38edbwR zM{azdlxL0>2Rnk`Cz#nxdO+&Yj+H~KeuBlX+`mVeEbiZ9Oq%;Q1w`%x<2XTFe=mLBoeS$1}{U1bwPxE!0Xsd0DMF(;9V9o@d?uUe@9T0sskUE|7_yPNl)4ctm#>kj|&vD9e(!6M0P23_<1cBwhiM`@e`&F@|hS@b;+ z#^?P;6Vra)fw#UJw13ezF4^S+`Z?tP?V;T?)oFhZTKX!1`%2tQrky65Hn7`iKUie5 zEs(_5O1X*o9(FqNgRztNRYci>GV!wrCf&v#t=jq1<)_=}fMqB8wG26ii#F&;U9l7Q zrXSA2i(3gl7^7driC+WVel`u*G8B)=6o`=Q{&W~+@+bP?5MOt^(f6>^?;zlZvFe1K z78lJbFJ5pXlVVabnM1gex#oUCtoAnAhcek{HO9&9#Xa!!tBd>UZ7!! z=OTNfAn|P~+Uuwji4{Nds`P4NK^$ znyhJ?Tw;sS5dC{gs%?^mP&DL8V%JdkHm!1v#e~djgdC89E85a|KE-s2UE33vz9t#O z#T0X`XaE3-G0ha`3NdY{*+kYLpJ5eIwZsZB8mosw;!pyYdUzGl6XbWe^al#0S>0y% zftaqb$gtK#TxOf3K#8kRZ62ykt*;kVxKjV(`&RN*u_ice)e|jzob&sDfh72Jr7V1$ zR;!T1X_RTL5G~|zz9mQSNe0nE&iSB)ZsS3JOA8!{(^gxeNhY-=TC|-ATHra2GKEQ^ zg$|r=$q{_n!U#EYP!>8Yv(dk>(VIYvzBr9Cg#n^PUqpXv^(FY!7tx}xM?ecXoJN^! zK(vs<`Ia2PCpkn5IXgiMoj;d1X}3u9Lcoih10;&ybvv9a=s-~@JS}oLgrDM98RO2=7ne> zhx08tf=_aY7IOXuTIlv4Hkq6TmUJUp$mD!Wrr?uIqJ_-kHaVO|J?TcYki+?w9Kk0! zL<>1?L{i~1oVM^plN`bmE%1ppJf~4lK0~zVm-8(-f=_aY7IIY3!Y0?-Xc6H7=W?-^ zB9fB5iguy)Etnbm`*R#SmntpV-iYihv8zo`dwHauUEb-<;%Zp;nX^nWyf2H+B_S4V z7eGkcF2GXZoHj1qD9)f5q0Xcjs?dxpMmtHHsVp6P62hEAu^wok-y)MOh!%6k`8GW9 ziAPz?8Nbh2>x$E;BcCH$$l-iTj^L9FqJM#EX_QGHqJd|@9~@?pDhoNQ|0b*U%8)rt{jxp<$-dB zJP2?343^I$yNh%V2oJK$+A)%RF>X69*b&b5Oo3{iXhZD5+GRabd-r$uSexpZg;Edb z)j>aGa3t&Y#A(t+PLq4cJ>_09Emz% z$04v|Vt?O|vmV5sWbWLQ?R2O4J5BeQU?Oq5TI<96yR-NGgD_^S&F3wi6E5-!%MP=o)gE={BcJ_s%U@X$-C%9*L+v^j|niDK3 z$sP?%aWE?jFXCm<|9E$?^Ic43b}*~t!V3YJvoMR^bSuAjM9G};1r<{ZmIkxN7Zv4) zuP!ROxT+*))RI|oMnQhgs6xG{2+c~2ic(Z(E2ESpb}7T=lpDoW@fK|&CgJ^1r1r0f zg5lIGm^C*im{m0rLUAfIcTw@&(u;>JHp+{uFpgl>Pt;)6RRCOr>vUv#9TjhzR%PMU zsjSMfrKK0=;J+oz%9>wRSy5b)wYapRvdmaOOh`0>&fb*Dijv@&UR)y^lYQx7Pt0v` zB_WHALsQaJKdvRrD>HJxEo3`U=51RcIqEGT?(J$!)tIS2N#LyQQSvMC~EGSzr zxAI~XODigjimdXo`DIlXkA&qqFhU0`*abZ>mWDhIIS*M!9*2TnB zt2_wTS;(`kawe{&$aAf-{etBj zPabx>m25|ebaY`RC{|GlBD-MO2~@C>3o}9E7s&<7(Y&;!=ZwsgF;wygl_ce`KcjVgA@zyd&d5xn?@42<5&y8L)eY&%0nIa^Bwr%4ty57xn28^qkXoc{Rl_< zk&gDG9PP(A+F#^opX+FUv7`MsNBcZSd)?7~yrcc4j`kBB?I$_fPjHIDYzI@(|7Xn(z<{Y*#uS&sIz9rdM-`nit!d5-!U9Q8Lk z>gPM^7dYw{I_ht7)K{_* zYaHb}9p$?m<@Jv821ofGM|mUrw|4s7&mOjwQxQ5E9p!heGCdQdA>MuIsK;BoJP|t$ zchUh?neHQLxO3)OW!h_`A>M_pG7B>Nza4{Esa2+Xd3VGsI?JR)x=^CBxX)3j7BtmS zqIwZxsb0`jM~TX_IYkfBZM4PW^mZj5w&+TI;|^5z4Nar#0A8KcA$y#cbxG?LRFI5!Anma;^HrmoK|c9 zO~dJx?Z3)DtzLYEeOiV1-Zoy*;jePywWs|MMX4%XQl*?W?_%hu%~HqkxOp*W9V3K5 z=L~j^K5afbhR3_d>~@S0-Jdqsox{&G^Z#|LHb0nES$SsrwsVTkkq!@`_m0jiH|{T; z!{XjkVRQ`a*qhFTKHa-!m(E%=mwu#TFvX;cXU(c8T`WrFWeZ9LU4f_Z(n?V(H%bIK zr-J_Gkg~wQUk!=>9Tfi8g-rK^t zo5ttMY|!~KwEZ%zD{#lErMbGtzKxJw@}xB^F(_kYDyi+`^1LxnXnFVGR6@^ zJ?ZD~1UJNnOX>tS(S{Re_Z{gs&xY&PiM-XorJ|nnOX&nxXTt?L!ELqSNG_$0^xI{_ zbvI!h;*QvGbk<3!BYAJyaP)l_CBl(U(B3`4#ixOd#3aypok+sx2t#<03V<7g0@+3M zOZKL7NV~ixz=?T9RosU!0Bx670}!31lDwYClt^ANvR&RUfD3{rlF*O7W3$U^08Z#9 z&LK%2ox9rQH33J@mm&#ybbe}Mv#pp^{(rH8PkK@!c}I}#@?L~7#5pHnguKrkxUYe; z%NMu|2(!!k4!AH0vXa1^1CYIa7?WB64B3y)j46?R^qUI1yhnf&>y|J=-Zc(+PXb5n zNuKZrDz68Q+T;8CATB(K`J#f*X2pkI{TZ!r@-Ri`RXgkxVdVzb~!V!l=CfcJN+yf zw~b|NrVxg!kQdj_!o3Szw#~5w?s?SP?UFj7&9Aa-{k{hrZ)3?D0G!rAzi&I_%>Zr? za5RpPg{N^i?Ggjde%>$ibJ}I~rI=q!UbanMeBLbm`d-G`e(4FEkms~Z8E}o39J&ac z(=Nj&w%G+P#uJUhX_qm;+1HVf=d?@MCXc=|qSTRHW)MyY0Y;EcyUd$pzB5X8hKupk zk-wx~-Zi@v0~i0*45W#Eop#v;9Q8x}()U}GI zRy|#WJg2{`22QM_@fM!sIoHvXzzq~aZ1S9TIrbCN?`ht!q!=DiVQ29pdMZ2Z5(BO)b_q{wvy1pXyd%3j0$f+@@&<5t6pbfgBBxynUSVk#fa|DV z`ppIRFQ$+yle9M0w?6H>O`Ij+>kElS7?*B zrW1J!f$L~pI>)=tChyKpr z`CYTiMBv1{-DAm3#?|QuGrK77Hk-VSHhDea&(?XgOze%oeQEhDmBl#dw{4)~Tbo@= O7@G+Otq*~r`T4&9l9<{6 diff --git a/Example/E15_fft_demo/libraries/zf_device/zf_device_config.h b/Example/E15_fft_demo/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Example/E15_fft_demo/libraries/zf_device/zf_device_config.h +++ b/Example/E15_fft_demo/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.c b/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.c +++ b/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.h b/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.h +++ b/Example/E15_fft_demo/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Example/E15_fft_demo/libraries/zf_device/zf_device_type.h b/Example/E15_fft_demo/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Example/E15_fft_demo/libraries/zf_device/zf_device_type.h +++ b/Example/E15_fft_demo/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.c b/Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.h b/Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Example/E15_fft_demo/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.c b/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.c +++ b/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.h b/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.h +++ b/Example/E15_fft_demo/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数==================================================== diff --git a/Seekfree_TC264_Opensource_Library/libraries/doc/version.txt b/Seekfree_TC264_Opensource_Library/libraries/doc/version.txt index bc77a80..54d38d6 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/doc/version.txt +++ b/Seekfree_TC264_Opensource_Library/libraries/doc/version.txt @@ -1,3 +1,6 @@ +V3.2.8 + 新增凌瞳无MCU版本驱动 + 新增SBUS遥控器底层驱动 V3.2.7 新增RTK "D" 报头协议 更正陀螺仪宏转换函数 变量增加括号 防止计算错误 diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_common/zf_common_headfile.h b/Seekfree_TC264_Opensource_Library/libraries/zf_common/zf_common_headfile.h index 86762db..c0d833b 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/zf_common/zf_common_headfile.h +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_common/zf_common_headfile.h @@ -100,6 +100,7 @@ #include "zf_device_tft180.h" #include "zf_device_tsl1401.h" #include "zf_device_type.h" +#include "zf_device_uart_receiver.h" #include "zf_device_virtual_oscilloscope.h" #include "zf_device_wifi_uart.h" #include "zf_device_wifi_spi.h" diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_config.a b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_config.a index 11bd1cc7deddee7f060888769dd39154d8f3b93f..ce7da964bf7fa810285ec9ae8037d9d8015c3ce7 100644 GIT binary patch literal 98860 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 O7@G+Otq*~r`T4&9l9<{6 diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_config.h b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_config.h index 6c8147d..2dffad7 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_config.h +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_config.h @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增凌瞳静态库函数 ********************************************************************************************************************/ #ifndef _zf_device_config_h_ @@ -43,5 +44,10 @@ unsigned char mt9v03x_set_config_sccb (void *soft_iic_obj, short int b unsigned char mt9v03x_set_exposure_time_sccb (unsigned short int light); unsigned char mt9v03x_set_reg_sccb (unsigned char addr, unsigned short int data); +unsigned char scc8660_set_config_sccb (void *soft_iic_obj, short int buff[10][2]); +unsigned char scc8660_set_brightness_sccb (unsigned short int brightness); +unsigned char scc8660_set_manual_wb_sccb (unsigned short int manual_wb); +unsigned char scc8660_set_reg_sccb (unsigned char reg, unsigned short int data); + #endif diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.c b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.c index 38d65ff..ffbe0ee 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.c +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.c @@ -31,6 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -55,9 +56,12 @@ #include "zf_driver_exti.h" #include "zf_driver_gpio.h" #include "zf_driver_uart.h" +#include "zf_driver_soft_iic.h" #include "zf_device_camera.h" -#include "zf_device_scc8660.h" #include "zf_device_type.h" +#include "zf_device_config.h" + +#include "zf_device_scc8660.h" vuint8 scc8660_finish_flag = 0; // 一场图像采集完成标志位 IFX_ALIGN(4) uint16 scc8660_image[SCC8660_H][SCC8660_W]; @@ -68,6 +72,7 @@ uint8 scc8660_lost_flag = 1; uint8 scc8660_dma_int_num; // 当前DMA中断次数 uint8 scc8660_dma_init_flag; // 是否需要重新初始化 +static scc8660_type_enum scc8660_type; // 需要配置到摄像头的数据 不允许在这修改参数 static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= @@ -77,7 +82,7 @@ static int16 scc8660_set_confing_buffer[SCC8660_CONFIG_FINISH][2]= {SCC8660_AUTO_EXP, SCC8660_AUTO_EXP_DEF}, // 自动曝光 {SCC8660_BRIGHT, SCC8660_BRIGHT_DEF}, // 亮度设置 {SCC8660_FPS, SCC8660_FPS_DEF}, // 图像帧率 - {SCC8660_SET_COL, SCC8660_W}, // 图像列数 + {SCC8660_SET_COL, SCC8660_W * 4}, // 图像列数 {SCC8660_SET_ROW, SCC8660_H}, // 图像行数 {SCC8660_PCLK_DIV, SCC8660_PCLK_DIV_DEF}, // PCLK分频系数 {SCC8660_PCLK_MODE, SCC8660_PCLK_MODE_DEF}, // PCLK模式 @@ -214,71 +219,6 @@ static void scc8660_uart_callback (void) fifo_write_element(&camera_receiver_fifo, data); } -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头场中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_vsync_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_vsync_handler(void) -{ - exti_flag_clear(SCC8660_VSYNC_PIN); - scc8660_dma_int_num = 0; - if(scc8660_dma_init_flag || scc8660_lost_flag) - { - scc8660_dma_init_flag = 0; - IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_link_list_num = dma_init(SCC8660_DMA_CH, - SCC8660_DATA_ADD, - (uint8 *)scc8660_image[0], - SCC8660_PCLK_PIN, - EXTI_TRIGGER_RISING, - SCC8660_IMAGE_SIZE); // 如果超频到300M 倒数第二个参数请设置为FALLING - dma_enable(SCC8660_DMA_CH); - } - else - { - if(1 == scc8660_link_list_num) - { - dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 - } - dma_enable(SCC8660_DMA_CH); - } - scc8660_lost_flag = 1; -} - -//------------------------------------------------------------------------------------------------------------------- -// 函数简介 SCC8660摄像头DMA完成中断 -// 参数说明 void -// 返回参数 void -// 使用示例 scc8660_dma_handler(); -//------------------------------------------------------------------------------------------------------------------- -static void scc8660_dma_handler(void) -{ - clear_dma_flag(SCC8660_DMA_CH); - - if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 - { - scc8660_finish_flag = 0; - dma_disable(SCC8660_DMA_CH); - IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); - scc8660_dma_init_flag = 1; - } - else - { - scc8660_dma_int_num++; - if(scc8660_dma_int_num >= scc8660_link_list_num) - { - // 采集完成 - // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) - scc8660_dma_int_num = 0; - scc8660_lost_flag = 0; - scc8660_finish_flag = 1; - dma_disable(SCC8660_DMA_CH); - } - } -} - //------------------------------------------------------------------------------------------------------------------- // 函数简介 获取摄像头 ID // 参数说明 void @@ -390,38 +330,46 @@ uint16 scc8660_get_version (void) // 函数简介 单独设置图像亮度 // 参数说明 data 需要设置的亮度值 // 返回参数 uint8 1-失败 0-成功 -// 使用示例 scc8660_set_bright(data); +// 使用示例 scc8660_set_brightness(data); // 备注信息 调用该函数前请先初始化摄像头配置串口 通过该函数设置的参数,不会被51单片机保存 //------------------------------------------------------------------------------------------------------------------- -uint8 scc8660_set_bright (uint16 data) +uint8 scc8660_set_brightness (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_BRIGHT; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_BRIGHT; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_brightness_sccb(data); } return return_state; } @@ -436,32 +384,40 @@ uint8 scc8660_set_bright (uint16 data) uint8 scc8660_set_white_balance (uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_MANUAL_WB; - uart_buffer[2] = data >> 8; - uart_buffer[3] = (uint8)data; - - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_MANUAL_WB; + uart_buffer[2] = data >> 8; + uart_buffer[3] = (uint8)data; + + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + } + else { - return_state = 1; + return_state = scc8660_set_manual_wb_sccb(data); } return return_state; } @@ -477,43 +433,117 @@ uint8 scc8660_set_white_balance (uint16 data) uint8 scc8660_set_reg (uint8 addr, uint16 data) { uint8 return_state = 0; - uint8 uart_buffer[4]; - uint16 temp; - uint16 timeout_count = 0; - uint32 uart_buffer_index = 0; - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_ADDR; - uart_buffer[2] = 0x00; - uart_buffer[3] = (uint8)addr; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - system_delay_ms(10); - uart_buffer[0] = 0xA5; - uart_buffer[1] = SCC8660_SET_REG_DATA; - temp = data; - uart_buffer[2] = temp >> 8; - uart_buffer[3] = (uint8)temp; - uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); - - do + if(SCC8660_UART == scc8660_type) { - if(3 <= fifo_used(&camera_receiver_fifo)) + uint8 uart_buffer[4]; + uint16 temp; + uint16 timeout_count = 0; + uint32 uart_buffer_index = 0; + + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_ADDR; + uart_buffer[2] = 0x00; + uart_buffer[3] = (uint8)addr; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + system_delay_ms(10); + uart_buffer[0] = 0xA5; + uart_buffer[1] = SCC8660_SET_REG_DATA; + temp = data; + uart_buffer[2] = temp >> 8; + uart_buffer[3] = (uint8)temp; + uart_write_buffer(SCC8660_COF_UART, uart_buffer, 4); + + do { - uart_buffer_index = 3; - fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); - temp = uart_buffer[1] << 8 | uart_buffer[2]; - break; + if(3 <= fifo_used(&camera_receiver_fifo)) + { + uart_buffer_index = 3; + fifo_read_buffer(&camera_receiver_fifo, uart_buffer, &uart_buffer_index, FIFO_READ_AND_CLEAN); + temp = uart_buffer[1] << 8 | uart_buffer[2]; + break; + } + system_delay_ms(1); + }while(SCC8660_INIT_TIMEOUT > timeout_count ++); + if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + { + return_state = 1; } - system_delay_ms(1); - }while(SCC8660_INIT_TIMEOUT > timeout_count ++); - if((temp != data) || (SCC8660_INIT_TIMEOUT <= timeout_count)) + + } + else { - return_state = 1; + return_state = scc8660_set_reg_sccb(addr, data); } return return_state; } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头场中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_vsync_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_vsync_handler(void) +{ + exti_flag_clear(SCC8660_VSYNC_PIN); + scc8660_dma_int_num = 0; + if(scc8660_dma_init_flag || scc8660_lost_flag) + { + scc8660_dma_init_flag = 0; + IfxDma_resetChannel(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_link_list_num = dma_init(SCC8660_DMA_CH, + SCC8660_DATA_ADD, + (uint8 *)scc8660_image[0], + SCC8660_PCLK_PIN, + EXTI_TRIGGER_RISING, + SCC8660_IMAGE_SIZE); + dma_enable(SCC8660_DMA_CH); + } + else + { + if(1 == scc8660_link_list_num) + { + dma_set_destination(SCC8660_DMA_CH, (uint8 *)scc8660_image[0]); // 没有采用链接传输模式 重新设置目的地址 + } + dma_enable(SCC8660_DMA_CH); + } + scc8660_lost_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SCC8660摄像头DMA完成中断 +// 参数说明 void +// 返回参数 void +// 使用示例 scc8660_dma_handler(); +//------------------------------------------------------------------------------------------------------------------- +static void scc8660_dma_handler(void) +{ + clear_dma_flag(SCC8660_DMA_CH); + + if(IfxDma_getChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH)) // 图像错位判断 + { + scc8660_finish_flag = 0; + dma_disable(SCC8660_DMA_CH); + IfxDma_clearChannelTransactionRequestLost(&MODULE_DMA, SCC8660_DMA_CH); + scc8660_dma_init_flag = 1; + } + else + { + scc8660_dma_int_num++; + if(scc8660_dma_int_num >= scc8660_link_list_num) + { + // 采集完成 + // 一副图像从采集开始到采集结束耗时3.8MS左右(50FPS、188*120分辨率) + scc8660_dma_int_num = 0; + scc8660_lost_flag = 0; + scc8660_finish_flag = 1; + dma_disable(SCC8660_DMA_CH); + } + } +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 SCC8660 摄像头初始化 // 参数说明 void @@ -524,51 +554,54 @@ uint8 scc8660_set_reg (uint8 addr, uint16 data) uint8 scc8660_init (void) { uint8 return_state = 0; - uint16 scc8660_version = 0; + soft_iic_info_struct scc8660_iic_struct; + // 初始化之前拉高场与像素引脚 gpio_init(P02_0, GPO, GPIO_HIGH, GPO_PUSH_PULL); gpio_init(P02_1, GPO, GPIO_HIGH, GPO_PUSH_PULL); - // 初始换串口 配置摄像头 - uart_init(SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); - uart_rx_interrupt(SCC8660_COF_UART, 1); - - system_delay_ms(200); - - set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, scc8660_uart_callback); // 设置连接摄像头类型 - camera_fifo_init(); do { - // 等待摄像头上电初始化成功 方式有两种:延时或者通过获取配置的方式 二选一 - // system_delay_ms(1000); // 延时方式 - scc8660_version = scc8660_get_version(); // 获取配置的方式 - if(scc8660_set_config(scc8660_set_confing_buffer)) + system_delay_ms(200); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, NULL); // 设置连接摄像头类型 + // 首先尝试SCCB通讯 + scc8660_type = SCC8660_SCCB; + soft_iic_init(&scc8660_iic_struct, 0, SCC8660_COF_IIC_DELAY, SCC8660_COF_IIC_SCL, SCC8660_COF_IIC_SDA); + if(scc8660_set_config_sccb(&scc8660_iic_struct, scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; - // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 - // 检查一下接线有没有问题 如果没问题可能就是坏了 - zf_log(0, "SCC8660 set config error."); - break; - } + // SCCB通讯失败,尝试串口通讯 + scc8660_type = SCC8660_UART; + camera_fifo_init(); + set_camera_type(CAMERA_COLOR, scc8660_vsync_handler, scc8660_dma_handler, &scc8660_uart_callback); // 设置连接摄像头类型 + uart_init (SCC8660_COF_UART, SCC8660_COF_BAUR, SCC8660_COF_UART_RX, SCC8660_COF_UART_TX); //初始换串口 配置摄像头 + uart_rx_interrupt(SCC8660_COF_UART, 1); + fifo_clear(&camera_receiver_fifo); - if(0 == return_state) - { - // 获取配置便于查看配置是否正确 - if(scc8660_get_config(scc8660_get_confing_buffer)) + if(scc8660_set_config(scc8660_set_confing_buffer)) { - set_camera_type(NO_CAMERE, NULL, NULL, NULL); - return_state = 1; // 如果程序在输出了断言信息 并且提示出错位置在这里 - // 那么就是串口通信出错并超时退出了 + // 那么就是通信出错并超时退出了 // 检查一下接线有没有问题 如果没问题可能就是坏了 zf_log(0, "SCC8660 set config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; break; } - scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); + // 获取配置便于查看配置是否正确 + if(scc8660_get_config(scc8660_get_confing_buffer)) + { + // 如果程序在输出了断言信息 并且提示出错位置在这里 + // 那么就是串口通信出错并超时退出了 + // 检查一下接线有没有问题 如果没问题可能就是坏了 + zf_log(0, "SCC8660 get config error."); + set_camera_type(NO_CAMERE, NULL, NULL, NULL); + return_state = 1; + break; + } } + + scc8660_link_list_num = camera_init(SCC8660_DATA_ADD, (uint8 *)scc8660_image[0], SCC8660_IMAGE_SIZE); }while(0); return return_state; diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.h b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.h index 537283a..6790330 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.h +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_scc8660.h @@ -31,7 +31,7 @@ * 修改记录 * 日期 作者 备注 * 2022-09-15 pudding first version -* 2023-04-28 pudding 增加中文注释说明 +* 2024-02-02 pudding 新增无MCU凌瞳驱动 ********************************************************************************************************************/ /********************************************************************************************************************* * 接线定义: @@ -59,35 +59,36 @@ #define SCC8660_COF_UART_TX (UART1_RX_P02_3) // 凌瞳 UART-TX 引脚 要接在单片机 RX 上 #define SCC8660_COF_UART_RX (UART1_TX_P02_2) // 凌瞳 UART-RX 引脚 要接在单片机 TX 上 +#define SCC8660_COF_IIC_DELAY (800) // 凌瞳 IIC 延时 +#define SCC8660_COF_IIC_SCL (P02_3) // 凌瞳 IIC-SCL 引脚 +#define SCC8660_COF_IIC_SDA (P02_2) // 凌瞳 IIC-SDA 引脚 + #define SCC8660_DMA_CH (IfxDma_ChannelId_5) - #define SCC8660_PCLK_PIN (ERU_CH2_REQ14_P02_1) // PCLK 触发信号 TIM_ETR 引脚禁止随意修改 - #define SCC8660_VSYNC_PIN (ERU_CH3_REQ6_P02_0 ) // 场中断引脚 - #define SCC8660_DATA_PIN (P00_0) // 数据引脚 这里是 只能是 GPIOx0 或者 GPIOx8 开始 连续八个引脚例如 F0-F7 #define SCC8660_DATA_ADD (get_port_in_addr(SCC8660_DATA_PIN)) #define SCC8660_INIT_TIMEOUT (0x00F0) // 默认的摄像头初始化超时时间 毫秒为单位 //================================================定义 SCC8660 基本配置================================================ -//================================================定义 SCC8660 参数配置================================================ -#define SCC8660_W (160) // 实际图像分辨率宽度 可选参数为:160 180 -#define SCC8660_H (120) // 实际图像分辨率高度 可选参数为:120 160 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== +#define SCC8660_W (160) // 图像宽度 可选参数为:160 80 40 +#define SCC8660_H (120) // 图像高度 可选参数为:120 160 240 #define SCC8660_IMAGE_SIZE (SCC8660_W * 2 * SCC8660_H) // 整体图像大小 SCC8660_W*2*SCC8660_H 不能超过 65535 #define SCC8660_AUTO_EXP_DEF (0 ) // 自动曝光 默认不开启自动曝光设置 范围 [0-1] 0为关闭 -#define SCC8660_BRIGHT_DEF (300) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 +#define SCC8660_BRIGHT_DEF (500) // 亮度设置 手动曝光默认:300 手动曝光时:参数范围0-65535 自动曝光推荐值:100 自动曝光时参数设置范围0-255 #define SCC8660_FPS_DEF (50 ) // 图像帧率 默认:50 可选参数为:60 50 30 25。 实际帧率还需要看SCC8660_PCLK_DIV参数的设置 -#define SCC8660_PCLK_DIV_DEF (5 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> +#define SCC8660_PCLK_DIV_DEF (2 ) // PCLK分频系数 默认:5 可选参数为:<0:1/1> <1:2/3> <2:1/2> <3:1/3> <4:1/4> <5:1/8> // 分频系数越大,PCLK频率越低,降低PCLK可以减轻DVP接口的干扰,但降低PCLK频率则会影响帧率。若无特殊需求请保持默认。 // 例如设置FPS为50帧,但是pclk分频系数选择的为5,则摄像头输出的帧率为50*(1/8)=6.25帧 // 其他参数不变的情况下,SCC8660_PCLK_DIV参数越大图像会越亮 -#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> -#define SCC8660_COLOR_MODE_DEF (1 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) -#define SCC8660_DATA_FORMAT_DEF (1 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) -#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 -//================================================定义 SCC8660 参数配置================================================ +#define SCC8660_PCLK_MODE_DEF (0 ) // PCLK模式 默认:0 可选参数为:[0,1] 0:不输出消隐信号 1:输出消隐信号 <通常都设置为0,如果使用STM32的DCMI接口采集需要设置为1> +#define SCC8660_COLOR_MODE_DEF (0 ) // 图像色彩模式 默认:0 可选参数为:[0,1] 0:正常彩色模式 1:鲜艳模式(色彩饱和度提高) +#define SCC8660_DATA_FORMAT_DEF (0 ) // 输出数据格式 默认:0 可选参数为:[0-3] 0:RGB565 1:RGB565(字节交换) 2:YUV422(YUYV) 3:YUV422(UYVY) +#define SCC8660_MANUAL_WB_DEF (0 ) // 手动白平衡 默认:0 可选参数为:[0,0x65-0xa0] 0:关闭手动白平衡,启用自动白平衡 其他:手动白平衡 手动白平衡时 参数范围0x65-0xa0 +//================================================定义 SCC8660 参数配置(仅支持凌瞳高帧率版本)=========================== //===============================================定义 SCC8660 参数结构体================================================ typedef enum @@ -116,6 +117,14 @@ typedef enum }scc8660_cmd_enum; //===============================================定义 SCC8660 参数结构体================================================ +//===============================================摄像头类型枚举体======================================================= +typedef enum +{ + SCC8660_UART, + SCC8660_SCCB, +}scc8660_type_enum; +//===============================================摄像头类型枚举体======================================================= + //===============================================声明 SCC8660 全局变量================================================= extern vuint8 scc8660_finish_flag; // 一场图像采集完成标志位 extern uint16 scc8660_image[SCC8660_H][SCC8660_W]; // 图像保存数组 diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_type.h b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_type.h index 3b124fe..6c2b8da 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_type.h +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_type.h @@ -56,6 +56,7 @@ typedef enum WIRELESS_UART, // 无线串口 BLUETOOTH_CH9141, // 蓝牙 CH9141 WIFI_UART, // 串口 WiFi + RECEIVER_UART, // 枪式遥控器 }wireless_type_enum; typedef enum diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.c b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.c new file mode 100644 index 0000000..3ebb3bd --- /dev/null +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.c @@ -0,0 +1,134 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ + +#include "zf_device_type.h" +#include "zf_driver_uart.h" +#include "zf_driver_timer.h" +#include "zf_device_uart_receiver.h" + +uart_receiver_struct uart_receiver ; // 串口接收机通道数据与状态 + +uint8 uart_receiver_data[REV_DATA_LEN] = {0}; // 接收器原始数据 + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 获取两次调用uart_receiver_interval_time函数时间间隔 +// 参数说明 void +// 返回参数 uint32 返回从开始到现在的时间(单位1us) +// 使用示例 uint32 time = uart_receiver_interval_time(); +// 备注信息 内部调用 +//------------------------------------------------------------------------------------------------------------------- +static uint32 uart_receiver_interval_time (void) +{ + static uint32 time_last = 0; + uint32 time, interval_time; + uint32 stm_clk; + + stm_clk = IfxStm_getFrequency(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + + time = IfxStm_getLower(IfxStm_getAddress((IfxStm_Index)(IfxCpu_getCoreId()))); + interval_time = time - time_last; + time_last = time; + interval_time = (uint32)((uint64)interval_time * 1000000 / stm_clk); + + return interval_time; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 SBUS数据解析 +// 参数说明 *remote_data 接收遥控器数据的地址 +// 参数说明 *bufer 原始数据 +// 返回参数 void +// 使用示例 +// 备注信息 对sbus数据解析进行解析 +//------------------------------------------------------------------------------------------------------------------- +static void uart_receiver_analysis (uart_receiver_struct *remote_data,uint8 * buffer) +{ + uint8 num = 0; + remote_data->channel[num++] = (buffer[1] |buffer[ 2] << 8 ) & 0x07FF; + remote_data->channel[num++] = (buffer[2] >> 3 | buffer[3] << 5 ) & 0x07FF; + remote_data->channel[num++] = (buffer[3] >> 6 | buffer[4] << 2 | buffer[5] << 10 ) & 0x07FF; + remote_data->channel[num++] = (buffer[5] >> 1 | buffer[6] << 7 ) & 0x07FF; + remote_data->channel[num++] = (buffer[6] >> 4 | buffer[7] << 4 ) & 0x07FF; + remote_data->channel[num++] = (buffer[7] >> 7 | buffer[8] << 1 | buffer[9] << 9 ) & 0x07FF; + remote_data->state = (SBUS_NORMAL_STATE == buffer[23]) ? 1 : 0; + uart_receiver.finsh_flag = 1; +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机模块 串口中断回调函数 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_callback(); +// 备注信息 该函数在 ISR 文件 串口中断程序通过uart_receiver_uart_handler函数指针被调用 +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_callback(void) +{ + static vuint8 length = 0; + + if (uart_receiver_interval_time() > 3000) + { + length = 0; + } + uart_receiver_data[length++] = uart_read_byte(UART_RECEVIER_UART_INDEX); + if ( (REV_DATA_LEN == length) // 如果帧长、帧头、帧尾满足协议 + && (FRAME_STAR == uart_receiver_data[0]) + && (FRAME_END == uart_receiver_data[24])) + { + uart_receiver_analysis(&uart_receiver, uart_receiver_data); + } +} + +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 串口接收机初始化 +// 参数说明 void +// 返回参数 void +// 使用示例 uart_receiver_init(); +//------------------------------------------------------------------------------------------------------------------- +void uart_receiver_init(void) +{ + uart_sbus_init(UART_RECEVIER_UART_INDEX, SBUS_UART_BAUDRATE, UART_RECEVIER_TX_PIN, UART_RECEVIER_RX_PIN); + + // 设置串口中断回调函数 + set_wireless_type(RECEIVER_UART, uart_receiver_callback); +} diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.h b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.h new file mode 100644 index 0000000..948ab2f --- /dev/null +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_device/zf_device_uart_receiver.h @@ -0,0 +1,72 @@ +/********************************************************************************************************************* +* TC264 Opensourec Library 即(TC264 开源库)是一个基于官方 SDK 接口的第三方开源库 +* Copyright (c) 2022 SEEKFREE 逐飞科技 +* +* 本文件是 TC264 开源库的一部分 +* +* TC264 开源库 是免费软件 +* 您可以根据自由软件基金会发布的 GPL(GNU General Public License,即 GNU通用公共许可证)的条款 +* 即 GPL 的第3版(即 GPL3.0)或(您选择的)任何后来的版本,重新发布和/或修改它 +* +* 本开源库的发布是希望它能发挥作用,但并未对其作任何的保证 +* 甚至没有隐含的适销性或适合特定用途的保证 +* 更多细节请参见 GPL +* +* 您应该在收到本开源库的同时收到一份 GPL 的副本 +* 如果没有,请参阅 +* +* 额外注明: +* 本开源库使用 GPL3.0 开源许可证协议 以上许可申明为译文版本 +* 许可申明英文版在 libraries/doc 文件夹下的 GPL3_permission_statement.txt 文件中 +* 许可证副本在 libraries 文件夹下 即该文件夹下的 LICENSE 文件 +* 欢迎各位使用并传播本程序 但修改内容时必须保留逐飞科技的版权声明(即本声明) +* +* 文件名称 zf_device_uart_receiver +* 公司名称 成都逐飞科技有限公司 +* 版本信息 查看 libraries/doc 文件夹内 version 文件 版本说明 +* 开发环境 ADS v1.9.20 +* 适用平台 TC264D +* 店铺链接 https://seekfree.taobao.com/ +* +* 修改记录 +* 日期 作者 备注 +* 2022-11-04 JKS first version +********************************************************************************************************************/ +/********************************************************************************************************************* +* 接线定义: +* ------------------------------------ +* 模块管脚 单片机管脚 +* TXD 查看 zf_device_uart_receiver.h 中 UART_RECEVIER_RX_PIN 宏定义 +* GND 电源地 +* 5V 5V电源 +* ------------------------------------ +********************************************************************************************************************/ +#ifndef _zf_device_uart_receiver_h +#define _zf_device_uart_receiver_h + +#include "zf_common_typedef.h" + +#define UART_RECEVIER_UART_INDEX UART_2 // 定义串口接收机使用的串口 +#define UART_RECEVIER_TX_PIN UART2_TX_P10_5 // 遥控器接收机没有这个引脚,仅用于串口初始化时占位使用 +#define UART_RECEVIER_RX_PIN UART2_RX_P10_6 // 串口接收机的TX引脚 连接单片机的RX引脚 +#define SBUS_UART_BAUDRATE (100000) // 指定 SBUS 串口所使用的的串口波特率 (用户不可修改) +#define UART_RECEVIER_CHANNEL_NUM ( 6 ) // 定义遥控器通道数量 (用户不可修改) + +#define REV_DATA_LEN ( 25 ) // SBUS帧长 +#define FRAME_STAR ( 0X0F ) // 帧头信息 +#define FRAME_END ( 0X00 ) // 帧尾信息 +#define SBUS_NORMAL_STATE ( 0X03 ) // 正常状态 +#define SBUS_ABNORMAL_STATE ( 0X0F ) // 失控状态 + +typedef struct +{ + uint16 channel[UART_RECEVIER_CHANNEL_NUM]; // CH1-CH6通道数据 + uint8 state; // 遥控器状态(1表示正常,否则表示失控) + uint8 finsh_flag; // 1:表示成功接收到一帧遥控器数据 +}uart_receiver_struct; + +extern uart_receiver_struct uart_receiver; // 串口接收机通道数据与状态 + +void uart_receiver_init(void); + +#endif diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.c b/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.c index fb89b55..b2fa521 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.c +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.c @@ -404,6 +404,55 @@ void uart_rx_interrupt (uart_index_enum uart_n, uint32 status) } } +//------------------------------------------------------------------------------------------------------------------- +// 函数简介 sbus初始化 +// 参数说明 uartn 串口通道(UART_0,UART_1,UART_2,UART_3) +// 参数说明 baud 串口波特率 +// 参数说明 tx_pin 串口发送引脚号 +// 参数说明 rx_pin 串口接收引脚号 +// 返回参数 void +// 使用示例 uart_sbus_init(UART_2, 100000, UART2_TX_P10_5, UART2_RX_P10_6); +// 备注信息 +//------------------------------------------------------------------------------------------------------------------- +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin) +{ + + boolean interrupt_state = disableInterrupts(); + + volatile Ifx_ASCLIN *moudle = IfxAsclin_getAddress((IfxAsclin_Index)uartn); + + IfxAsclin_Asc_initModuleConfig(&uart_config, moudle); // 初始化化配置结构体 + + uart_set_buffer(uartn); // 设置缓冲区 + + uart_set_interrupt_priority(uartn); // 设置中断优先级 + + uart_config.clockSource = IfxAsclin_ClockSource_ascFastClock; // 使用高速时钟 最大波特率6.25M + uart_config.baudrate.prescaler = 4; + uart_config.baudrate.baudrate = (float32)baud; + uart_config.baudrate.oversampling = IfxAsclin_OversamplingFactor_8; + + uart_config.frame.stopBit = IfxAsclin_StopBit_2; //停止位 + uart_config.frame.parityType = IfxAsclin_ParityType_even; //偶校验 + uart_config.frame.dataLength = IfxAsclin_DataLength_8; + uart_config.frame.parityBit = TRUE; //启动校验 + + IfxAsclin_Asc_Pins pins; // 设置引脚 + pins.cts = NULL; + pins.rts = NULL; + uart_mux(uartn, tx_pin, rx_pin, (uint32 *)&pins.tx, (uint32 *)&pins.rx); + pins.rxMode = IfxPort_InputMode_pullUp; + pins.txMode = IfxPort_OutputMode_pushPull; + pins.pinDriver = IfxPort_PadDriver_cmosAutomotiveSpeed1; + uart_config.pins = &pins; + + IfxAsclin_Asc_initModule(uart_get_handle(uartn), &uart_config); + uart_rx_interrupt(uartn, 1); + uart_tx_interrupt(uartn, 0); + restoreInterrupts(interrupt_state); + +} + //------------------------------------------------------------------------------------------------------------------- // 函数简介 串口初始化 // 参数说明 uartn 串口模块号(UART_0,UART_1,UART_2,UART_3) diff --git a/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.h b/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.h index cdc55ab..abdc10a 100644 --- a/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.h +++ b/Seekfree_TC264_Opensource_Library/libraries/zf_driver/zf_driver_uart.h @@ -125,6 +125,7 @@ uint8 uart_query_byte (uart_index_enum uartn, uint8 *dat); void uart_tx_interrupt (uart_index_enum uartn, uint32 status); void uart_rx_interrupt (uart_index_enum uartn, uint32 status); +void uart_sbus_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); void uart_init (uart_index_enum uartn, uint32 baud, uart_tx_pin_enum tx_pin, uart_rx_pin_enum rx_pin); //====================================================串口 基础函数====================================================