开发环境:
RT-Thread Studio:v2.2.7
开发板:RA8D1 Vision Board开发板
MCU:R7FA8D1BHEC337AS02
1 硬件连接
Camera Interface接口如下:
USB Interface接口如下:
2 RA8D1 Camera与USB配置
接下来配置Camera与USB,只需要简单配置就可使用。双击工程中的 RA Smart Configurator 图标,第一次打开需要配置正确的 FSP 安装路径。
在 FSP 配置界面里面我们依次点击 “Stacks”-> “New Stack”-> “Graphics”-> “Capture Engine Unit(r_ceu) ”
主要配置Camera的尺寸,Swap和回调函数名字。
依次点击 “Pin”-> “USB”,然后打开USB。
配置完成之后可以按下快捷键“Ctrl + S”保存, 最后点右上角的 “Generate Project Content” 按钮,让软件自动生成配置代码即可。
需要打开SRAM,Camera UVC等设备硬件。
另外还需要打开TinyUSB软件包。
并配置相应的参数。
3 Camera代码实现
这里需要适配Camera和LCD硬件,参考官网的代码。
核心应用代码如下:
#include <drv_lcd.h>
#include <tusb.h>
#include "sensor.h"
#define CAM_WIDTH 320
#define CAM_HEIGHT 240
extern sensor_t sensor;
uint8_t g_image_yuv422_sdram_buffer[CAM_WIDTH * CAM_HEIGHT * 16 / 8] BSP_PLACE_IN_SECTION(".sdram") BSP_ALIGN_VARIABLE(8);
void hal_entry(void)
{
sensor_init();
sensor_reset();
sensor_set_hmirror(true);
sensor_set_vflip(true);
sensor_set_pixformat(PIXFORMAT_YUV422);
sensor_set_framesize(FRAMESIZE_QVGA);
while (1)
{
sensor_snapshot(&sensor, g_image_yuv422_sdram_buffer, 0);
if (tud_video_n_streaming(0, 0))
{
tud_video_n_frame_xfer(0, 0, (void *)g_image_yuv422_sdram_buffer, CAM_WIDTH * CAM_HEIGHT * 16 / 8);
}
rt_thread_mdelay(20);
}
}
值得注意的是,USB UVC需要相应的中断函数,如果使用FSP生成则需要修改相应的切换中断上下文以此适配RT-Thread,为了方便,直接在ra_gen/vector_data.c和ra_gen/vector_data.h文件中修改,修改后如下。
【vector_data.c】
#include "bsp_api.h"
#if VECTOR_DATA_IRQ_COUNT > 0
#if __has_include("r_ioport.h")
BSP_DONT_REMOVE const fsp_vector_t g_vector_table[BSP_ICU_VECTOR_MAX_ENTRIES] BSP_PLACE_IN_SECTION(BSP_SECTION_APPLICATION_VECTORS) =
{
[0] = sci_b_uart_rxi_isr,
[1] = sci_b_uart_txi_isr,
[2] = sci_b_uart_tei_isr,
[3] = sci_b_uart_eri_isr,
[4] = ceu_isr,
[5] = usbfs_interrupt_handler,
[6] = usbfs_resume_handler,
[7] = usbfs_d0fifo_handler,
[8] = usbfs_d1fifo_handler,
[9] = usbhs_interrupt_handler,
[10] = usbhs_d0fifo_handler,
[11] = usbhs_d1fifo_handler,
};
const bsp_interrupt_event_t g_interrupt_event_link_select[BSP_ICU_VECTOR_MAX_ENTRIES] =
{
[0] = BSP_PRV_IELS_ENUM(EVENT_SCI9_RXI),
[1] = BSP_PRV_IELS_ENUM(EVENT_SCI9_TXI),
[2] = BSP_PRV_IELS_ENUM(EVENT_SCI9_TEI),
[3] = BSP_PRV_IELS_ENUM(EVENT_SCI9_ERI),
[4] = BSP_PRV_IELS_ENUM(EVENT_CEU_CEUI),
[5] = BSP_PRV_IELS_ENUM(EVENT_USBFS_INT),
[6] = BSP_PRV_IELS_ENUM(EVENT_USBFS_RESUME),
[7] = BSP_PRV_IELS_ENUM(EVENT_USBFS_FIFO_0),
[8] = BSP_PRV_IELS_ENUM(EVENT_USBFS_FIFO_1),
[9] = BSP_PRV_IELS_ENUM(EVENT_USBHS_USB_INT_RESUME),
[10] = BSP_PRV_IELS_ENUM(EVENT_USBHS_FIFO_0),
[11] = BSP_PRV_IELS_ENUM(EVENT_USBHS_FIFO_1),
};
#elif __has_include("r_ioport_b.h")
BSP_DONT_REMOVE const fsp_vector_t g_vector_table[BSP_IRQ_VECTOR_MAX_ENTRIES] BSP_PLACE_IN_SECTION(BSP_SECTION_APPLICATION_VECTORS) =
{
[BSP_PRV_IELS_ENUM(SCI9_RXI)] = sci_b_uart_rxi_isr,
[BSP_PRV_IELS_ENUM(SCI9_TXI)] = sci_b_uart_txi_isr,
[BSP_PRV_IELS_ENUM(SCI9_TEI)] = sci_b_uart_tei_isr,
[BSP_PRV_IELS_ENUM(SCI9_ERI)] = sci_b_uart_eri_isr,
[BSP_PRV_IELS_ENUM(CEU_CEUI)] = ceu_isr,
[BSP_PRV_IELS_ENUM(USBFS_INT)] = usbfs_interrupt_handler,
[BSP_PRV_IELS_ENUM(USBFS_RESUME)] = usbfs_resume_handler,
[BSP_PRV_IELS_ENUM(USBFS_FIFO_0)] = usbfs_d0fifo_handler,
[BSP_PRV_IELS_ENUM(USBFS_FIFO_1)] = usbfs_d1fifo_handler,
[BSP_PRV_IELS_ENUM(USBHS_USB_INT_RESUME)] = usbhs_interrupt_handler,
[BSP_PRV_IELS_ENUM(USBHS_FIFO_0)] = usbhs_d0fifo_handler,
[BSP_PRV_IELS_ENUM(USBHS_FIFO_1)] = usbhs_d1fifo_handler,
};
#endif
#endif
【vector_data.h】
#ifndef VECTOR_DATA_H
#define VECTOR_DATA_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef VECTOR_DATA_IRQ_COUNT
#define VECTOR_DATA_IRQ_COUNT (20)
#endif
void sci_b_uart_rxi_isr(void);
void sci_b_uart_txi_isr(void);
void sci_b_uart_tei_isr(void);
void sci_b_uart_eri_isr(void);
void ceu_isr(void);
void usbfs_interrupt_handler(void);
void usbfs_resume_handler(void);
void usbfs_d0fifo_handler(void);
void usbfs_d1fifo_handler(void);
void usbhs_interrupt_handler(void);
void usbhs_d0fifo_handler(void);
void usbhs_d1fifo_handler(void);
#if __has_include("r_ioport.h")
#define VECTOR_NUMBER_SCI9_RXI ((IRQn_Type) 0)
#define SCI9_RXI_IRQn ((IRQn_Type) 0)
#define VECTOR_NUMBER_SCI9_TXI ((IRQn_Type) 1)
#define SCI9_TXI_IRQn ((IRQn_Type) 1)
#define VECTOR_NUMBER_SCI9_TEI ((IRQn_Type) 2)
#define SCI9_TEI_IRQn ((IRQn_Type) 2)
#define VECTOR_NUMBER_SCI9_ERI ((IRQn_Type) 3)
#define SCI9_ERI_IRQn ((IRQn_Type) 3)
#define VECTOR_NUMBER_CEU_CEUI ((IRQn_Type) 4)
#define CEU_CEUI_IRQn ((IRQn_Type) 4)
#define VECTOR_NUMBER_USBFS_INT ((IRQn_Type) 13)
#define USBFS_INT_IRQn ((IRQn_Type) 13)
#define VECTOR_NUMBER_USBFS_RESUME ((IRQn_Type) 14)
#define USBFS_RESUME_IRQn ((IRQn_Type) 14)
#define VECTOR_NUMBER_USBFS_FIFO_0 ((IRQn_Type) 15)
#define USBFS_FIFO_0_IRQn ((IRQn_Type) 15)
#define VECTOR_NUMBER_USBFS_FIFO_1 ((IRQn_Type) 16)
#define USBFS_FIFO_1_IRQn ((IRQn_Type) 16)
#define VECTOR_NUMBER_USBHS_USB_INT_RESUME ((IRQn_Type) 17)
#define USBHS_USB_INT_RESUME_IRQn ((IRQn_Type) 17)
#define VECTOR_NUMBER_USBHS_FIFO_0 ((IRQn_Type) 18)
#define USBHS_FIFO_0_IRQn ((IRQn_Type) 18)
#define VECTOR_NUMBER_USBHS_FIFO_1 ((IRQn_Type) 19)
#define USBHS_FIFO_1_IRQn ((IRQn_Type) 19)
#endif
#ifdef __cplusplus
}
#endif
#endif
4 测试验证
编译下载,调试信息如下:
笔者这里开发一个上位机来接收UVC数据,效果如下。