K210 standalone C development

Posted by michalchojno on Tue, 18 Jan 2022 03:39:33 +0100

  • As the bare metal development foundation of K210 development board, the environment adopts cmake+vs code2019. For authority, please refer to the official development manual of Jianan. The problems in the article are inevitable. Welcome to discuss~

Basic routine

Turn on the LED

1. Corresponding API in SDK

The hardware pin and software function of K210 use FPIOA mapping relationship

2. Steps

  1. In the hardware initialization function, set the fpioa relationship

fpioa_ set_ Function (connection pins of hardware peripherals (those 48), FUNC_LED0: FUNC_GPIO0 + software (gpio port);

fpioa_function_t func in SDK_ Function definition of pins such as gpio0

LED The lamp is lit at a low level
//Bind GPIO pin
void hardware_init(void)
{
    fpioa_set_function(PIN_LED_0, FUNC_LED0);
    fpioa_set_function(PIN_LED_1, FUNC_LED1);
}

//Header file
/*****************************HEAR-FILE************************************/
#include "fpioa.h"

/*****************************HARDWARE-PIN*********************************/
// Hardware IO port, corresponding to the schematic diagram
#define PIN_LED_0             (0)
#define PIN_LED_1             (17)

/*****************************SOFTWARE-GPIO********************************/
// Software GPIO port, corresponding to the program
#define LED0_GPIONUM          (0)
#define LED1_GPIONUM          (1)

/*****************************FUNC-GPIO************************************/
// The function of GPIO port is bound to the hardware IO port
#define FUNC_LED0             (FUNC_GPIO0 + LED0_GPIONUM)
#define FUNC_LED1             (FUNC_GPIO0 + LED1_GPIONUM)

8 General GPIO 

Use an interrupt source to set edge trigger and level trigger

each IO Ports can be assigned to FPIOA One of the 48 pins on the

FPIOA (Field programmable IO Array) allows the user to map 255 internal functions to 48 free ports on the periphery of the chip IO upper


  1. Main function
  • Initialize hardware pin
  • Enable GPIO clock_ init
  • Set the GPIO input / output mode of the hardware pin
User interface:

• gpio_init: GPIO Port initialization
• gpio_set_drive_mode: set up GPIO Port input or output mode
• gpio_set_pin: set up GPIO Pin level high/low
• gpio_get_pin: read GPIO Pin level

- definition GPIO Value of
typedef enum_gpio_pin_value
{
    GPIO_PV_HIGH,
    GPIO_PV_LOW
}gpio_pin_value_pin ;

  1. Burn

cmake ... -DPROJ=gpio_led -G "MinGW Makefiles"

The reason for the problem here: there should be no spaces before and after the equal value, and there should be no spaces before and after the file name

make

Dual core parallel

Dual core peer-to-peer, each core has an independent FPU (floating point unit)

The system uses core 0 by default. If you need to use core 1, you need to manually start the service of core 1.

1. Corresponding API in SDK

Board level header file BSP h

bsp.h header file is a general function related to the platform and the related operation of locks between cores.

It provides an interface to obtain the CPU core number of the currently running program and an entry to start the second core.

The following interfaces are provided for users:
• register_core1: Register functions with core 1 and start core 1
• current_coreid: Get current CPU Core number of (0)/1)
• read_cycle: obtain CPU Number of clocks since startup. You can use this function to accurately determine the program running clock. Can cooperate sysctl_clock_get_freq(SYSCTL_CLOCK_CPU)Calculate the running time.
• spinlock_lock: Spin locks cannot be nested. They are not recommended for use in interrupts. They can be used in interrupts spinlock_trylock. 
• spinlock_unlock: Spin lock unlock.
• spinlock_trylock: To obtain a spin lock, 0 will be returned if the lock is successfully obtained, and 0 will be returned if the lock is failed-1. 
• corelock_lock: Obtain inter core locks, mutually exclusive locks between cores. The locks in the same core will be nested, and only different cores will be blocked. This function is not recommended for interrupts. It can be used in interrupts corelock_trylock. 
• corelock_trylock: Obtain inter core locks. Locks will be nested in the same core and non blocking in different cores. 0 will be returned if the lock is obtained successfully, and 0 will be returned if it fails-1. 
• corelock_unlock: The inter nuclear lock is unlocked.
• sys_register_putchar: Register the system output callback function, printf This function is called when. Used by default UART3,If it needs to be modified UART Then call uart_debug_init Function.
• sys_register_getchar: Register the system input callback function, scanf This function is called when. Used by default UART3,If it needs to be modified UART Then call uart_debug_init Function.
• sys_stdin_flush: clear stdin Cache.
• get_free_heap_size: Gets the free memory size.
• printk: Print the core debugging information, which users don't have to pay attention to.

The printf of the system uses the high-speed serial port UARTHS(UART0) by default

External interrupt

The BOOT key is pressed to low level

1. Corresponding API in SDK

Corresponding header file Plic h

PLIC can assign any external interrupt source to the external interrupt of each CPU separately. This provides strong flexibility and can adapt to different application requirements.

The PLIC module can set the interrupt callback function. When an interrupt is triggered, the interrupt callback function will run automatically, and the interrupt priority can be configured.

The following interfaces are provided for users:
• plic_init: PLIC Initialize external interrupt.
• plic_irq_enable: Enable external interrupts.
• plic_irq_disable: Disable external interrupts.
• plic_set_priority: Set interrupt priority.
• plic_get_priority: Gets the interrupt priority.
• plic_irq_register: Register external interrupt functions.
• plic_irq_deregister: Unregister external interrupt function.

Timer experiment

There are 3 chip timers in total, and each timer has 4 channels

Each timer can set the trigger interval and timer interrupt processing function.

The timer can set the timeout of nanosecond level, and can set the interrupt callback.

The timer can be suspended and restarted by controlling enable and disable without reconfiguration.

1. Corresponding API functions in SDK

Corresponding header file timer H) provide the following interfaces for users:

• timer_init: Initialize the timer.
• timer_set_interval: Set the timing interval.
//timer_ set_ IRQ (no longer supported after 0.6.0, please use timer_irq_register)
• timer_set_enable: Enable/Disable timer. 0 disable 1 enable
• timer_irq_register: Register timer interrupt callback function.
int timer_irq_register(
    timer_device_number_t device, //Timer number
    timer_channel_number_t channel, //Timer channel number
    int is_single_shot, //Single channel
    uint32_t priority, //Interrupt priority
    timer_callback_t callback, //Interrupt callback function
    void *ctx//Interrupt callback function parameters
    );
//Return 0 success 1 Failure

• timer_irq_deregister: The logoff timer is interrupted.

2. Steps

  1. Hardware initialization, defining FPIOA mapping
  2. Initialize external interrupt service to enable global interrupt
    /* Initialize system interrupt and enable */
    plic_init();
    sysctl_enable_irq();

  1. Before using RGB lights, you need to initialize and set GPIO to output mode.
  2. Press the key to initialize, set the BOOT as the pull-up input mode, set the GPIO level trigger mode of the key as the rising / falling edge, and set the interrupt callback function
  3. External interrupt function key triggered by BOOT_ irq_ cb
  4. Initialization timer
void init_timer(void) {
    /* timer initiated  */
    timer_init(TIMER_DEVICE_0);
    /* Set timer timeout */==Unit is ns==
    timer_set_interval(TIMER_DEVICE_0, TIMER_CHANNEL_0, 500 * 1e6);//0.5s
    /* Set timer interrupt callback */
    timer_irq_register(TIMER_DEVICE_0, TIMER_CHANNEL_0, 0, 1, timer_timeout_cb, &g_count);
    /* Enable timer */
    timer_set_enable(TIMER_DEVICE_0, TIMER_CHANNEL_0, 1);
}
  1. Timer internal interrupt processing timer_timeout_cb

PWM experiment

The internal implementation of PWM is based on the timing function of timer.

2 the two important factors controlling PWM are frequency and duty cycle.

1. Corresponding API functions in SDK

Corresponding header file PWM H pulse width modulator PWM is used to control the duty cycle of pulse output. Its essence is a timer,
Therefore, when setting PWM number and channel, do not conflict with TIMER timer.

• pwm_init
• pwm_set_frequency
• pwm_set_enable   1 Enable 0 disable

2. Steps

  1. Hardware initialization, defining FPIOA mapping
  2. Initialize external interrupt service to enable global interrupt
  3. Initialization timer
  4. Initialize PWM timer 1 channel 0 frequency 200k duty cycle 0.5
void init_pwm(void)
{
    /* Initialize PWM */
    pwm_init(PWM_DEVICE_1);
    /* Set the PWM frequency as 200KHZ and the duty cycle as 0.5 square wave */
    pwm_set_frequency(PWM_DEVICE_1, PWM_CHANNEL_0, 200000, 0.5);
    /* Enable PWM output */
    pwm_set_enable(PWM_DEVICE_1, PWM_CHANNEL_0, 1);
}
  1. Interrupt processing timer inside timer_ timeout_ In the CB function, set the duty cycle of PWM

Camera display

ov2640 camera, LCD display

  1. The on-board DVP interface of K210 development board can be connected with ov2640 camera compatible with DVP interface.
  2. The K210 development board displays the camera picture by refreshing the LCD interface frame by frame to achieve the dynamic effect.

0. Component introduction

OV2640 camera is connected with K210 development board through digital camera interface (DVP), which is a common camera interface module
It has the following characteristics:

  • Support SCCB protocol configuration camera register
  • Support 640 × 48.03 million pixels) and below, and the size of each frame can be configured
  • Support image input in YUV422 and RGB565 formats
  • Support image output to KPU and display screen at the same time:
  • The format of output to KPU can be RGB888 or Y component of YUV422 input
  • The format of output to the display is RGB565
  • When the start of a frame or the completion of image transmission of a frame are detected, an interrupt can be sent to the CPU

1. Corresponding API functions in SDK

Corresponding header file DVP h

• dvp_init : DVP initialization. 
• dvp_set_output_enable: Set output mode (memory or AI)Enable or prohibit.
• dvp_set_image_format: Set the image receiving mode, RGB or YUV. 
• dvp_set_image_size: set up DVP Image acquisition size. 
• dvp_set_ai_addr: set up AI The address where the image is stored for AI Module for algorithm processing. 
• dvp_set_display_addr: Set the storage address of the collected image in the memory, which can be used for display. 
• dvp_config_interrupt: Set the image start and end interrupt status, enable or disable.
• dvp_get_interrupt: Judge whether it is the input interrupt type. The return value is: 0 is no, non-0 is yes.
• dvp_clear_interrupt: Clear interrupt. 
• dvp_start_convert: The image is started and is called after the image acquisition is interrupted. 
• dvp_enable_burst: Enable burst transmission mode. 
• dvp_disable_burst: Disable burst transmission mode. 
• dvp_enable_auto: Enables automatic image reception mode. 
• dvp_disable_auto: Disable auto receive image mode. 
• dvp_sccb_send_data: adopt sccb The protocol sends data. 
• dvp_sccb_receive_data: adopt SCCB Receive data. 
• dvp_sccb_set_clk_rate: set up sccb Rate of. 
• dvp_set_xclk_rate: Sets the rate of the input clock.

2. Steps

  1. Hardware initialization, defining FPIOA mapping

Add an enable SPI0 and DVP

  1. To initialize the power domain voltage, both the camera and the display need a 1.8V level signal. Set the voltage of bank6 and bank7 to 1.8V according to the power domain

void io_set_power

  1. Set system clock DVP clock
  2. Enable global interrupt
  3. Initialize LCD
  4. Initialize DVP
void dvp_cam_init(void)
{
    /* DVP Initialization, set the register length of sccb to 8bit */
    dvp_init(8);
    /* Set the input clock to 24000000*/
    dvp_set_xclk_rate(24000000);
    /* Enable burst transmission mode */
    dvp_enable_burst();
    /* Turn off AI output mode and enable display mode */
    dvp_set_output_enable(DVP_OUTPUT_AI, 0);
    dvp_set_output_enable(DVP_OUTPUT_DISPLAY, 1);
    /* Set the output format to RGB */
    dvp_set_image_format(DVP_CFG_RGB_FORMAT);
    /* Set the output pixel size to 320 * 240 */
    dvp_set_image_size(CAM_WIDTH_PIXEL, CAM_HIGHT_PIXEL);

    /* Set DVP display address parameters and interrupts */
    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. Set DVP interrupt service
Configure the interrupt and clear the interrupt flag bit
  1. DVP interrupts the callback and saves the camera content to display_buf_addr is in this address variable
  2. Initialize ov2640 and send the corresponding register and data directly
 for (index = 0; ov2640_config[index][0]; index++)
        dvp_sccb_send_data(OV2640_ADDR, ov2640_config[index][0], ov2640_config[index][1]);
  1. After the DVP transmission is completed, the LCD displays the data of the address variable
while (1)
    {
        /* Wait for the camera acquisition to end, and then clear the end flag */
        while (g_dvp_finish_flag == 0);
        g_dvp_finish_flag = 0;
        /* display frame */
        lcd_draw_picture(0, 0, 320, 240, display_buf_addr);
    }

cmake ... -DPROJ=camera -G "MinGW Makefiles

Topics: Embedded system Single-Chip Microcomputer