K210 standalone C开发

  • 本文作为K210开发板的裸机开发基础,环境采用cmake+vs code2019,权威请参考嘉楠官方的开发手册。文章中问题在所难免,欢迎讨论~

    文章目录

      • 基础例程
        • 点亮LED灯
          • 1. SDK中对应的API
          • 2. 步骤
        • 双核并行
          • 1. SDK中对应的API
        • 外部中断
          • 1. SDK中对应的API
        • 定时器实验
          • 1.SDK中对应的API功能
          • 2. 步骤
        • PWM实验
          • 1.SDK中对应的API功能
          • 2. 步骤
        • 摄像头显示
          • 0.元件介绍
          • 1.SDK中对应的API功能
          • 2. 步骤

基础例程

点亮LED灯

1. SDK中对应的API

K210的硬件引脚和软件功能使用的是FPIOA映射关系

2. 步骤

  1. 在硬件初始化函数中,设定fpioa的关系

fpioa_set_function(硬件外设的连接引脚(那48个), FUNC_LED0:FUNC_GPIO0+软件gpio口);

fpioa_function_t在SDK里 FUNC_GPIO0之类的管脚的功能定义

LED 灯是低电平点亮的
//绑定GPIO 引脚
void hardware_init(void)
{
    fpioa_set_function(PIN_LED_0, FUNC_LED0);
    fpioa_set_function(PIN_LED_1, FUNC_LED1);
}

//头文件
/*****************************HEAR-FILE************************************/
#include "fpioa.h"

/*****************************HARDWARE-PIN*********************************/
// 硬件IO口,与原理图对应
#define PIN_LED_0             (0)
#define PIN_LED_1             (17)

/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define LED0_GPIONUM          (0)
#define LED1_GPIONUM          (1)

/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
#define FUNC_LED0             (FUNC_GPIO0 + LED0_GPIONUM)
#define FUNC_LED1             (FUNC_GPIO0 + LED1_GPIONUM)

8个通用GPIO 

使用一个中断源可设置边沿触发和电平触发

每个IO口可以分配到FPIOA上的48个管脚之一

FPIOA (现场可编程IO阵列)允许用户将255 个内部功能映射到芯片外围的48个自由IO上


  1. 主函数
  • 初始化硬件引脚
  • 使能GPIO时钟 gpio_init
  • 设置硬件引脚的GPIO输入输出模式
用户接口:

• gpio_init:GPIO口初始化
• gpio_set_drive_mode:设置GPIO口输入或输出模式
• gpio_set_pin:设置GPIO引脚电平高/低
• gpio_get_pin:读取GPIO引脚电平

- 定义GPIO的值
typedef enum_gpio_pin_value
{
    GPIO_PV_HIGH,
    GPIO_PV_LOW
}gpio_pin_value_pin ;

  1. 烧录

cmake … -DPROJ=gpio_led -G “MinGW Makefiles”

这里会出现问题的原因:等于前后不能有空格,文件名不要有前后空格

make

双核并行

双核对等,每个核心具备独立的FPU(浮点运算单元)

系统默认使用核心 0 ,如果需要使用核心 1 需要手动开启核心 1 的服务。

1. SDK中对应的API

板级对应的头文件 bsp.h

bsp.h头文件是与平台相关的通用函数,核之间锁的相关操作。

提供获取当前运行程序的CPU核编号的接口以及启动第二个核的入口。

为用户提供以下接口:
• register_core1:向核心1注册函数,并启动核心1
• current_coreid:获取当前CPU的核心编号(0/1)
• read_cycle:获取CPU开机至今的时钟数。可以用使用这个函数精准的确定程序运行时钟。可以配合sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)计算运行的时间。
• spinlock_lock:自旋锁,不可嵌套,不建议在中断使用,中断中可以使用spinlock_trylock。
• spinlock_unlock:自旋锁解锁。
• spinlock_trylock:获取自旋锁,成功获取锁会返回0,失败返回-1。
• corelock_lock:获取核间锁,核之间互斥的锁,同核内该锁会嵌套,只有异核之间会阻塞。不建议在中断使用该函数,中断中可以使用corelock_trylock。
• corelock_trylock:获取核间锁,同核时锁会嵌套,异核时非阻塞。成功获取锁会返回0,失败返回-1。
• corelock_unlock:核间锁解锁。
• sys_register_putchar:注册系统输出回调函数,printf时会调用该函数。系统默认使用UART3,如果需要修改UART则调用uart_debug_init函数。
• sys_register_getchar:注册系统输入回调函数,scanf时会调用该函数。系统默认使用UART3,如果需要修改UART则调用uart_debug_init函数。
• sys_stdin_flush:清理stdin缓存。
• get_free_heap_size:获取空闲内存大小。
• printk:打印核心调试信息,用户不必理会。

系统的 printf 默认使用高速串口 UARTHS(UART0)

外部中断

BOOT键按下为低电平

1. SDK中对应的API

对应的头文件 plic.h

PLIC可以将任一外部中断源单独分配到每个CPU的外部中断上。这提供了强大的灵活性,能适应不同的应用需求。

PLIC模块可以设置中断回调函数,当触发中断时,会自动运行中断回调函数,并且可以配置中断优先级。

为用户提供以下接口:
• plic_init:PLIC初始化外部中断。
• plic_irq_enable:使能外部中断。
• plic_irq_disable:禁用外部中断。
• plic_set_priority:设置中断优先级。
• plic_get_priority:获取中断优先级。
• plic_irq_register:注册外部中断函数。
• plic_irq_deregister:注销外部中断函数。

定时器实验

芯片定时器总共有3个,每个定时器有4路通道.

每个定时器可以设置触发间隔和定时器中断处理函数。

定时器可以设置纳秒级别的超时时间,并且可以设置中断回调。

定时器可以通过控制 使能与禁止的方式来暂停和重新启动,而不需要重新配置。

1.SDK中对应的API功能

对应的头文件 timer.h 为用户提供以下接口:

• timer_init:初始化定时器。
• timer_set_interval:设置定时间隔。
//timer_set_irq (0.6.0 后不再支持,请使用timer_irq_register)
• timer_set_enable:使能/禁止定时器。  0禁用 1使能
• timer_irq_register:注册定时器中断回调函数。
int timer_irq_register(
    timer_device_number_t device, //定时器号
    timer_channel_number_t channel, //定时器通道号
    int is_single_shot, //是否单次通道
    uint32_t priority, //中断优先级
    timer_callback_t callback, //中断回调函数
    void *ctx//中断回调函数参数
    );
//返回0成功 1失败

• timer_irq_deregister:注销定时器中断。

2. 步骤

  1. 硬件初始化,定义FPIOA 映射
  2. 初始化外部中断服务,使能全局中断
    /* 初始化系统中断并使能 */
    plic_init();
    sysctl_enable_irq();

  1. 在使用RGB灯前需要初始化,把GPIO设置为输出模式。
  2. 按键初始化,设置BOOT为上拉输入模式,设置按键的GPIO电平触发模式为上升/下降沿,设置中断回调函数
  3. BOOT触发的外部中断函数key_irq_cb
  4. 初始化定时器
void init_timer(void) {
    /* 定时器初始化 */
    timer_init(TIMER_DEVICE_0);
    /* 设置定时器超时时间 */==单位为ns==
    timer_set_interval(TIMER_DEVICE_0, TIMER_CHANNEL_0, 500 * 1e6);//0.5s
    /* 设置定时器中断回调 */
    timer_irq_register(TIMER_DEVICE_0, TIMER_CHANNEL_0, 0, 1, timer_timeout_cb, &g_count);
    /* 使能定时器 */
    timer_set_enable(TIMER_DEVICE_0, TIMER_CHANNEL_0, 1);
}
  1. 定时器内部中断处理timer_timeout_cb

PWM实验

1 PWM的内部实现是基于定时器的定时功能 。

2 控制PWM的两个重要因素是频率和占空比。

1.SDK中对应的API功能

对应的头文件 pwm.h 脉冲宽度调制器PWM用于控制脉冲输出的占空比,其本质是一个定时器,
所以注意设置PWM号与通道时,不要与TIMER定时器冲突。

• pwm_init
• pwm_set_frequency
• pwm_set_enable   1开启 0禁用

2. 步骤

  1. 硬件初始化,定义FPIOA 映射
  2. 初始化外部中断服务,使能全局中断
  3. 初始化定时器
  4. 初始化PWM 定时器1通道0 频率200k 占空比0.5
void init_pwm(void)
{
    /* 初始化PWM */
    pwm_init(PWM_DEVICE_1);
    /* 设置PWM频率为200KHZ,占空比为0.5的方波 */
    pwm_set_frequency(PWM_DEVICE_1, PWM_CHANNEL_0, 200000, 0.5);
    /* 使能 PWM 输出 */
    pwm_set_enable(PWM_DEVICE_1, PWM_CHANNEL_0, 1);
}
  1. 在定时器内部中断处理timer_timeout_cb函数中,设置PWM的占空比

摄像头显示

ov2640摄像头、LCD显示屏

  1. K210开发板板载DVP接口可以与兼容DVP接口的ov2640摄像头连接使用。
  2. K210开发板显示摄像头画面是通过一帧一帧刷新LCD界面来达到动态效果的。

0.元件介绍

OV2640 摄像头与K210开发板通过数字摄像头接口(DVP)连接DVP是常用的摄像头接口模块
具有以下特性:

  • 支持 支持 SCCB 协议配置摄像头寄存器
  • 支持 640×480 3 0 万像素) 及以下分辨率,每帧大小可配置
  • 支持 YUV422 和 RGB565 格式的图像输入
  • 支持图像同时输出到 KPU 和显示屏:
  • 输出到 KPU 的格式可选 RGB888 ,或 YUV422 输入时的 Y 分量
  • 输出到显示屏的格式为 RGB565
  • 检测到一帧开始或一帧图像传输完成时可向 CPU 发送中断

1.SDK中对应的API功能

对应的头文件 dvp.h

• dvp_init :DVP初始化。 
• dvp_set_output_enable:设置输出模式(内存或AI)使能或禁止。
• dvp_set_image_format:设置图像接收模式,RGB或YUV。
• dvp_set_image_size:设置DVP图像采集尺寸。 
• dvp_set_ai_addr:设置AI存放图像的地址,供AI模块进行算法处理。 
• dvp_set_display_addr:设置采集图像在内存中的存放地址,可以用来显示。 
• dvp_config_interrupt:设置图像开始和结束中断状态,使能或禁用。
• dvp_get_interrupt:判断是否是输入的中断类型,返回值:0为否,非0为是。
• dvp_clear_interrupt:清除中断。 
• dvp_start_convert:开始采集图像,在确定图像采集开始中断后调用。 
• dvp_enable_burst:使能突发传输模式。 
• dvp_disable_burst:禁用突发传输模式。 
• dvp_enable_auto:使能自动接收图像模式。 
• dvp_disable_auto:禁用自动接收图像模式。 
• dvp_sccb_send_data:通过sccb协议发送数据。 
• dvp_sccb_receive_data:通过SCCB接收数据。 
• dvp_sccb_set_clk_rate:设置sccb的速率。 
• dvp_set_xclk_rate:设置输入时钟的速率。

2. 步骤

  1. 硬件初始化,定义FPIOA 映射

加一个使能SPI0和DVP

  1. 初始化电源域电压,摄像头和显示器都需要1.8V电平信号,根据所电源域设置 bank6 bank7的电压为1.8V

void io_set_power

  1. 设置系统时钟 DVP时钟
  2. 使能全局中断
  3. 初始化LCD
  4. 初始化DVP
void dvp_cam_init(void)
{
    /* DVP初始化,设置sccb的寄存器长度为8bit */
    dvp_init(8);
    /* 设置输入时钟为24000000*/
    dvp_set_xclk_rate(24000000);
    /* 使能突发传输模式 */
    dvp_enable_burst();
    /* 关闭AI输出模式,使能显示模式 */
    dvp_set_output_enable(DVP_OUTPUT_AI, 0);
    dvp_set_output_enable(DVP_OUTPUT_DISPLAY, 1);
    /* 设置输出格式为RGB */
    dvp_set_image_format(DVP_CFG_RGB_FORMAT);
    /* 设置输出像素大小为320*240 */
    dvp_set_image_size(CAM_WIDTH_PIXEL, CAM_HIGHT_PIXEL);

    /* 设置DVP的显示地址参数和中断 */
    display_buf = (uint32_t*)iomem_malloc(CAM_WIDTH_PIXEL * CAM_HIGHT_PIXEL * 2);
    display_buf_addr = display_buf;
    dvp_set_display_addr((uint32_t)display_buf_addr);
    dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
    dvp_disable_auto();
}

  1. 设置DVP中断服务
配置中断,清楚中断标志位
  1. DVP中断回调,把摄像头内容保存到display_buf_addr这个地址变量中
  2. 初始化ov2640 直接发送对应寄存器及数据即可
 for (index = 0; ov2640_config[index][0]; index++)
        dvp_sccb_send_data(OV2640_ADDR, ov2640_config[index][0], ov2640_config[index][1]);
  1. 等待DVP传输完成后,LCD显示地址变量的数据
while (1)
    {
        /* 等待摄像头采集结束,然后清除结束标志 */
        while (g_dvp_finish_flag == 0);
        g_dvp_finish_flag = 0;
        /* 显示画面 */
        lcd_draw_picture(0, 0, 320, 240, display_buf_addr);
    }

cmake … -DPROJ=camera -G "MinGW Makefiles

你可能感兴趣的:(嵌入式,单片机)