A Guide to Adapt Kendryte KD233 Kpu Demo to Sipeed M1


  • Staff

    A Guide to Adapt Kendryte KD233 Kpu Demo to Sipeed M1

    IO & Power Bank Settings

    KD233 and Sipeed M1 use different IOs and power banks to interface camera and LCD, so different IO maps and power bank settings are needed. You can view the schematics of them to determine the differences.

    KD233

    /* main.c */			
    ...				
    static void io_mux_init(void)
    {
        /* Init DVP IO map and function settings */
        fpioa_set_function(11, FUNC_CMOS_RST);
        fpioa_set_function(13, FUNC_CMOS_PWDN);
        fpioa_set_function(14, FUNC_CMOS_XCLK);
        fpioa_set_function(12, FUNC_CMOS_VSYNC);
        fpioa_set_function(17, FUNC_CMOS_HREF);
        fpioa_set_function(15, FUNC_CMOS_PCLK);
        fpioa_set_function(10, FUNC_SCCB_SCLK);
        fpioa_set_function(9, FUNC_SCCB_SDA);
    
        /* Init SPI IO map and function settings */
        fpioa_set_function(8, FUNC_GPIOHS0 + DCX_GPIONUM);
        fpioa_set_function(6, FUNC_SPI0_SS3);
        fpioa_set_function(7, FUNC_SPI0_SCLK);
    
        sysctl_set_spi0_dvp_data(1);
    }
    
    static void io_set_power(void)
    {
        /* Set dvp and spi pin to 1.8V */
        sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18);
        sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18);
    }
    ...
    

    Sipeed M1

    /* main.c */			
    ...				
    static void io_mux_init(void)
    {
        /* Init DVP IO map and function settings */
        fpioa_set_function(42, FUNC_CMOS_RST);
        fpioa_set_function(44, FUNC_CMOS_PWDN);
        fpioa_set_function(46, FUNC_CMOS_XCLK);
        fpioa_set_function(43, FUNC_CMOS_VSYNC);
        fpioa_set_function(45, FUNC_CMOS_HREF);
        fpioa_set_function(47, FUNC_CMOS_PCLK);
        fpioa_set_function(41, FUNC_SCCB_SCLK);
        fpioa_set_function(40, FUNC_SCCB_SDA);
    
        /* Init SPI IO map and function settings */
        fpioa_set_function(38, FUNC_GPIOHS0 + DCX_GPIONUM);
        fpioa_set_function(36, FUNC_SPI0_SS3);
        fpioa_set_function(39, FUNC_SPI0_SCLK);
        fpioa_set_function(37, FUNC_GPIOHS0 + RST_GPIONUM);
    
        sysctl_set_spi0_dvp_data(1);
    }
    
    static void io_set_power(void)
    {
        /* Set dvp and spi pin to 1.8V */
        sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
        sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
    }
    ...
    

    Camera Driver

    KD233 uses a camera with ov5640 driver IC, while Sipeed M1 uses a camera with ov2640 driver IC. They have to be configured correspondingly.

    First, Replace the ov5640.c, ov5640.h and ov5640cfg.h in src/kpu with attached ov2640.c, ov2640.h, and ov2640cfg.h.

    Then, make the following modifications.

    KD233

    /* main.c */
    ...
    #include "ov5640.h"
    ...
    int main(void)
    {
    	...
        dvp_init(16);
        ...
        ov5640_init();
        ...
    }
    ...
    
    /* lib/drivers/dvp.c */
    ...
    void dvp_init(uint8_t reg_len)
    {
     	...
        dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(0) | DVP_CMOS_CLK_ENABLE;
        ...
    }
    ...
    

    Sipeed M1

    /* main.c */
    ...
    #include "ov2640.h"
    ...
    int main(void)
    {
    	...
        dvp_init(8);
        ...
        ov2640_init();
        ...
    }
    ...
    
    /* lib/drivers/dvp.c */
    ...
    void dvp_init(uint8_t reg_len)
    {
     	...
        dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(4) | DVP_CMOS_CLK_ENABLE;
        ...
    }
    ...
    

    LCD Driver

    KD233 doesn't interface the RESET pin of LCD, while Sipeed M1 does. Additionally, KD233 uses a LCD with nt35310 driver IC, while Sipeed M1 uses a LCD with st7789 driver IC.

    First, rename nt35310.c and nt35310.h in src/kpu as st7789.c and st7789.h and replace all #include "nt35310.h" in kpu demo with #include "st7789.h".
    Note: To rename the files is just to be clear, while you can also still use the origin name.

    Then, make the following modifications.

    KD233

    /* nt35310.c */
    ...
    void tft_hard_init(void)
    {
        init_dcx();
        spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
        uint32_t clk = spi_set_clk_rate(SPI_CHANNEL, 25000000);
        printf("clk is %d\n", clk);
    }
    ...
    
    /* lcd.c */
    ...
    void lcd_init(void)
    {
    	...
        tft_hard_init();
        /*soft reset*/
        tft_write_command(SOFTWARE_RESET);
        usleep(100000);
        /*exit sleep*/
        tft_write_command(SLEEP_OFF);
        ...
        lcd_set_direction(DIR_YX_RLUD);
        ...
    }
    
    void lcd_set_direction(lcd_dir_t dir)
    {
         dir |= 0x08; 
        lcd_ctl.dir = dir;
    	...
    }
    ...
    

    Sipeed M1

    /* st7789.c */
    ...
    /* Add this include directive */
    #include "sleep.h"
    ...
    /* Add this hardware reset function */
    static void init_rst(void)
    {
        gpiohs_set_drive_mode(RST_GPIONUM, GPIO_DM_OUTPUT);
        gpiohs_set_pin(RST_GPIONUM, GPIO_PV_LOW);
        usleep(100000);
        gpiohs_set_pin(RST_GPIONUM, GPIO_PV_HIGH);
        usleep(100000);
    }
    
    void tft_hard_init(void)
    {
        init_dcx();
        /* Hardware Reset */
        init_rst();		
        spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
        /* Change SPI clock */
        uint32_t clk = spi_set_clk_rate(SPI_CHANNEL, 20000000);		
        printf("clk is %d\n", clk);
    }
    ...
    
    /* st7789.h */
    ...
    /* Add this macro definition */
    #define RST_GPIONUM             (0)
    ...
    
    /* lcd.c */
    void lcd_init(void)
    {
    	...
        tft_hard_init();
        /* hardware reset has been done, and software reset is not needed any more */
    	/*    
     	tft_write_command(SOFTWARE_RESET);
        usleep(100000);
    	*/
        /*exit sleep*/
        tft_write_command(SLEEP_OFF);
        ...
        /* Change display direction */
        lcd_set_direction(DIR_YX_RLDU); 
        ...
    }
    
    void lcd_set_direction(lcd_dir_t dir)
    {
        /* comment this line */
        /* dir |= 0x08; */
        lcd_ctl.dir = dir;
    	...
    }
    ...
    

    Attachment

    ov2640.c

    #include <stdio.h>
    #include <unistd.h>
    #include "ov2640.h"
    #include "ov2640cfg.h"
    #include "dvp.h"
    
    static void hal_delay(uint32_t delay)
    {
        usleep(delay * 1000);
    }
    
    static void ov2640_wr_reg(uint16_t reg,uint8_t data)
    {
        dvp_sccb_send_data(OV2640_ADDR, reg, data);
    }
    
    static uint8_t ov2640_rd_reg(uint16_t reg)
    {
        return dvp_sccb_receive_data(OV2640_ADDR, reg);
    }
    
    uint8_t ov2640_init(void)
    {
        uint16_t i = 0;
        uint16_t reg = 0;
    
        reg = ov2640_rd_reg(OV2640_CHIPIDH);
        reg <<= 8;
        reg |= ov2640_rd_reg(OV2640_CHIPIDL);
        printf("ID: %X \r\n", reg);
        if(reg != OV2640_ID)
        {
            printf("ID: %d \r\n", reg);
            return 1;
        }
    
        for(i = 0; i<sizeof(ov2640_init_reg_tbl) / 4; i++)
        {
            ov2640_wr_reg(ov2640_init_reg_tbl[i][0], ov2640_init_reg_tbl[i][1]);
        }
    
        hal_delay(50);
    
        return 0x00;
    }
    

    ov2640.h

    #ifndef _OV2640_H
    #define _OV2640_H
    
    #define OV2640_ID           0x2642
    #define OV2640_ADDR         0x60
    #define OV2640_CHIPIDH      0x0A
    #define OV2640_CHIPIDL      0x0B
    
    uint8_t ov2640_init(void);
    
    #endif
    

    ov2640cfg.h

    #ifndef _OV2640CFG_H
    #define _OV2640CFG_H
    
    const uint16_t ov2640_init_reg_tbl[][2]=
    {
        {0xff, 0x01},
        {0x12, 0x80},
        {0xff, 0x00},
        {0x2c, 0xff},
        {0x2e, 0xdf},
        {0xff, 0x01},
        {0x3c, 0x32},
        {0x11, 0x00},
        {0x09, 0x02},
        {0x04, 0x88},
        {0x13, 0xe5},
        {0x14, 0x48},
        {0x2c, 0x0c},
        {0x33, 0x78},
        {0x3a, 0x33},
        {0x3b, 0xfb},
        {0x3e, 0x00},
        {0x43, 0x11},
        {0x16, 0x10},
        {0x39, 0x92},
        {0x35, 0xda},
        {0x22, 0x1a},
        {0x37, 0xc3},
        {0x23, 0x00},
        {0x34, 0xc0},
        {0x36, 0x1a},
        {0x06, 0x88},
        {0x07, 0xc0},
        {0x0d, 0x87},
        {0x0e, 0x41},
        {0x4c, 0x00},
        {0x48, 0x00},
        {0x5b, 0x00},
        {0x42, 0x03},
        {0x4a, 0x81},
        {0x21, 0x99},
        {0x24, 0x40},
        {0x25, 0x38},
        {0x26, 0x82},
        {0x5c, 0x00},
        {0x63, 0x00},
        {0x46, 0x22},
        {0x0c, 0x3c},
        {0x61, 0x70},
        {0x62, 0x80},
        {0x7c, 0x05},
        {0x20, 0x80},
        {0x28, 0x30},
        {0x6c, 0x00},
        {0x6d, 0x80},
        {0x6e, 0x00},
        {0x70, 0x02},
        {0x71, 0x94},
        {0x73, 0xc1},
        {0x3d, 0x34},
        {0x5a, 0x57},
        {0x12, 0x40},
        {0x17, 0x11},
        {0x18, 0x43},
        {0x19, 0x00},
        {0x1a, 0x4b},
        {0x32, 0x09},
        {0x37, 0xc0},
        {0x4f, 0xca},
        {0x50, 0xa8},
        {0x5a, 0x23},
        {0x6d, 0x00},
        {0x3d, 0x38},
        {0xff, 0x00},
        {0xe5, 0x7f},
        {0xf9, 0xc0},
        {0x41, 0x24},
        {0xe0, 0x14},
        {0x76, 0xff},
        {0x33, 0xa0},
        {0x42, 0x20},
        {0x43, 0x18},
        {0x4c, 0x00},
        {0x87, 0xd5},
        {0x88, 0x3f},
        {0xd7, 0x03},
        {0xd9, 0x10},
        {0xd3, 0x82},
        {0xc8, 0x08},
        {0xc9, 0x80},
        {0x7c, 0x00},
        {0x7d, 0x00},
        {0x7c, 0x03},
        {0x7d, 0x48},
        {0x7d, 0x48},
        {0x7c, 0x08},
        {0x7d, 0x20},
        {0x7d, 0x10},
        {0x7d, 0x0e},
        {0x90, 0x00},
        {0x91, 0x0e},
        {0x91, 0x1a},
        {0x91, 0x31},
        {0x91, 0x5a},
        {0x91, 0x69},
        {0x91, 0x75},
        {0x91, 0x7e},
        {0x91, 0x88},
        {0x91, 0x8f},
        {0x91, 0x96},
        {0x91, 0xa3},
        {0x91, 0xaf},
        {0x91, 0xc4},
        {0x91, 0xd7},
        {0x91, 0xe8},
        {0x91, 0x20},
        {0x92, 0x00},
        {0x93, 0x06},
        {0x93, 0xe3},
        {0x93, 0x05},
        {0x93, 0x05},
        {0x93, 0x00},
        {0x93, 0x04},
        {0x93, 0x00},
        {0x93, 0x00},
        {0x93, 0x00},
        {0x93, 0x00},
        {0x93, 0x00},
        {0x93, 0x00},
        {0x93, 0x00},
        {0x96, 0x00},
        {0x97, 0x08},
        {0x97, 0x19},
        {0x97, 0x02},
        {0x97, 0x0c},
        {0x97, 0x24},
        {0x97, 0x30},
        {0x97, 0x28},
        {0x97, 0x26},
        {0x97, 0x02},
        {0x97, 0x98},
        {0x97, 0x80},
        {0x97, 0x00},
        {0x97, 0x00},
        {0xc3, 0xed},
        {0xa4, 0x00},
        {0xa8, 0x00},
        {0xc5, 0x11},
        {0xc6, 0x51},
        {0xbf, 0x80},
        {0xc7, 0x10},
        {0xb6, 0x66},
        {0xb8, 0xa5},
        {0xb7, 0x64},
        {0xb9, 0x7c},
        {0xb3, 0xaf},
        {0xb4, 0x97},
        {0xb5, 0xff},
        {0xb0, 0xc5},
        {0xb1, 0x94},
        {0xb2, 0x0f},
        {0xc4, 0x5c},
        {0xc0, 0x64},
        {0xc1, 0x4b},
        {0x8c, 0x00},
        {0x86, 0x3d},
        {0x50, 0x00},
        {0x51, 0xc8},
        {0x52, 0x96},
        {0x53, 0x00},
        {0x54, 0x00},
        {0x55, 0x00},
        {0x5a, 0xc8},
        {0x5b, 0x96},
        {0x5c, 0x00},
        {0xd3, 0x02},
        {0xc3, 0xed},
        {0x7f, 0x00},
        {0xda, 0x08},
        {0xe5, 0x1f},
        {0xe1, 0x67},
        {0xe0, 0x00},
        {0xdd, 0x7f},
        {0x05, 0x00},
        {0xff, 0x00},
        {0xe0, 0x04},
        {0x5a, 0x50},
        {0x5b, 0x3c},
        {0x5c, 0x00},
        {0xe0, 0x00},
        {0x00, 0x00}
    };
    
    #endif