【Camera专题】Qcom-高通OTP完全调试指南-上-程序员宅基地

技术标签: 移动开发  嵌入式  

一、前言

关于高通OTP编程的知识,网上少得可怜,官方文档又没有那么清晰,于是就来一篇干货吧! OTP编程完全指南分上、下2篇。 上:主要讲OTP的知识和调试流程。 下:主要讲OTP的源码。

本文知识点:

  • 1.OTP的基本概念
  • 2.OTP的作用
  • 3.OTP的调试流程

二、知识点

1.OTP的基本概念(是什么)

OTP(One Time Programmable)意思是一次性可编程,程序或者数据烧入【存储器】后,将不可再次更改和清除。


OTP烧录的数据类型 一般包括:

  • AF:自动对焦校准数据
  • AWB:白平衡校准数据
  • LSC:镜头阴影校准 (Lens Shading Calibration)
  • Moudle Info:模组信息,包含模组的生产年日月,模组ID等

以AF为例子:
vendor厂烧录的AF数据:

Page:3,Addr:0x01D0,Data:0x00
Page:3,Addr:0x01D8,Data:0x04
Page:3,Addr:0x01E0,Data:0x0F
Page:3,Addr:0x01E8,Data:0x0C
Page:3,Addr:0x01F0,Data:0x02
Page:3,Addr:0x01F8,Data:0x00
复制代码

OTP存储器的类型 按照调试的经验,目前主流的有2种:

  • 1.OTP数据烧录在sensor的寄存器中。 这种方案省钱,不需要额外的存储器件,但是存储空间小,如果需要烧录的数据量过大,就不适用。

  • OTP数据烧录在EEPROM 中: EEPROM(Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器, 是一种掉电后数据不丢失的存储芯片。 该方案优势是存储空间大,如果数据量过多,就需要这种方案,缺点是多一个独立的EEPROM存储器件, 花点钱(5毛钱左右)。

2.OTP的作用(为什么)

OTP是用来给camera sensor做calibration(校准)用的。 因为模组生产出来会有很大的差异性,为了保证效果一致性, 模组厂会挑选一部分模组作为golden,然后将其他模组的相应参数校准到和这些golden一样, (golden不是最好的模组,也不是最差的模组,而是各方面最平均的模组)。

3.OTP调试流程(怎么做)

调试平台:8909(较为低端)

PS:在高通源码的OTP指的就是EEPROM驱动。

例子一:以OV5675为例子(数据烧录在Camera Sensor中)

3.1 OTP调试准备工作
  • 从datasheet获取相关信息 OTP Datasheet(OV5675 Calibration and OTP Programming Guid) Camera sensor Datasheet(sensor_OV05675-GA4A.pdf) a.弄明白上电时序(这个和camera上电时序是一致的)

b.获得slave address

硬件上我们这个pin脚是拉高的,所以I2C addr = 0x20

c.弄清楚读写规则

d.其他

1. 供电:cam_vio-supply = <&pm8916_l10>;
2. clock:
   clocks = <&clock_gcc clk_mclk0_clk_src>,<&clock_gcc clk_gcc_camss_mclk0_clk>;
   clock-names = "cam_src_clk", "cam_clk";
3.GPIO pins
  gpios = 
        <&msm_gpio 26 0>,
        <&msm_gpio 28 0>,
        <&msm_gpio 33 0>;
复制代码
3.2 配置 DTSI文件

EEPROM数据在设备启动时读取。需要将内存映射转换为dtsi中的对应的属性节点。 其中必须指定调节器(供电)、时钟信号、电源启动序列、设备地址和读取序列。 路径:kernel/arch/arm/boot/dts/qcom/msm8909-pm8916-camera-sensor-i18.dtsi

eeprom1: qcom,eeprom@20 {
        cell-index = <1>;/*分配给eeprom subdev,唯一即可*/
        reg = <0x20>;/*注册地址*/
        qcom,eeprom-name = "ov5675_back";/*eeprom驱动名称,必须与驱动力的名称一致*/
        compatible = "qcom,eeprom";/*匹配节点,都是这个值*/
        qcom,slave-addr = <0x20>;/*i2c地址*/
        qcom,cci-master = <0>;/*默认都为0即可*/
        qcom,num-blocks = <10>;/*下面配置的page个数*/

        /*读写规则*/
        qcom,page0 = <1 0x0100 2 0x01 1 10>;/*steam on 该操作非必须*/
        qcom,pageen0 = <0 0x0 0 0x0 0 0>;
        qcom,poll0 = <0 0x0 0 0x0 0 0>;
        qcom,mem0 = <0 0x0 2 0 1 1>;
        /*初始化操作*/
        qcom,page1 = <1 0x5001 2 0x02 1 1>;/*往0x5001写0x02:OTP enable*/
        qcom,pageen1 = <0 0x0 0 0x0 0 0>;
        qcom,poll1 = <0 0x0 0 0x0 0 0>;
        qcom,mem1 = <0 0x5001 2 0 1 1>;

        qcom,page2 = <1 0x3d84 2 0xc0 1 1>;/*往0x3d84写入0xc0:Enable partial OTP write */
        qcom,pageen2 = <0 0x0 2 0x0 0 0>;
        qcom,poll2 = <0 0x0 2 0x0 0 0>;
        qcom,mem2 = <0 0x0 2 0 0 0>;

        qcom,page3 = <1 0x3d88 2 0x70 1 1>;/*往0x3d88写入0x70:start address 高8位地址*/
        qcom,pageen3 = <0 0x0 2 0x0 1 1>;
        qcom,poll3 = <0 0x0 2 0x0 0 0>;
        qcom,mem3 = <0 0x0 2 0 0 0>;

        qcom,page4 = <1 0x3d89 2 0x10 1 1>;/*往0x3d88写入0x10:start address 低8位地址*/
        qcom,pageen4 = <0 0x0 2 0x0 1 1>;
        qcom,poll4 = <0 0x0 2 0x0 0 0>;
        qcom,mem4 = <0 0x0 2 0 0 0>;

        qcom,page5 = <1 0x3d8a 2 0x72 1 1>;/*往0x3d8a写入0x72:end address 高8位地址*/
        qcom,pageen5 = <0 0x0 2 0x0 1 1>;
        qcom,poll5 = <0 0x0 2 0x0 0 0>;
        qcom,mem5 = <0 0x0 2 0 0 0>;

        qcom,page6 = <1 0x3d8b 2 0x29 1 1>;/*往0x3d8b写入0x29:end address 低8位地址*/
        qcom,pageen6 = <0 0x0 2 0x0 1 1>;
        qcom,poll6 = <0 0x0 2 0x0 0 0>;
        qcom,mem6 = <0 0x0 2 0 0 0>;

        qcom,page7 = <1 0x3d81 2 0x01 1 10>;/*往0x3d81写入0x01:把OTP数据加载到buffer中 */
        qcom,pageen7 = <0 0x0 0 0x0 0 0>;
        qcom,poll7 = <0 0x0 0 0x0 0 0>;
        qcom,mem7 = <256 0x7010 2 0 1 1>;/*从0x7010开始读取256个数据*/

        qcom,page8 = <1 0x5001 2 0x0a 1 1>;/*往0x5001写0x0a:OTP disable*/
        qcom,pageen8 = <0 0x0 0 0x0 0 0>;
        qcom,poll8 = <0 0x0 0 0x0 0 0>;
        qcom,mem8 = <0 0x0 2 0 1 1>;

        qcom,page9 = <1 0x0100 2 0x00 1 10>;/*steam off*/
        qcom,pageen9 = <0 0x0 0 0x0 0 0>;
        qcom,poll9 = <0 0x0 0 0x0 0 0>;
        qcom,mem9 = <0 0x0 2 0 1 1>;

        cam_vio-supply = <&pm8916_l10>;/*供电相关:和camera一致即可*/
        qcom,cam-vreg-name = "cam_vio";;/*硬件上只需IO供电,其他AVDD和DVDD都会被IO拉起来*/
        qcom,cam-vreg-type = <0>;
        qcom,cam-vreg-min-voltage = <1800000>;
        qcom,cam-vreg-max-voltage = <2800000>;
        qcom,cam-vreg-op-mode = <80000>;
        pinctrl-names = "cam_default", "cam_suspend";
        pinctrl-0 = <&cam_sensor_mclk1_default &cam_sensor_front_default>;
        pinctrl-1 = <&cam_sensor_mclk1_sleep &cam_sensor_front_sleep>;
        gpios = <&msm_gpio 26 0>,/*GPIO相关:和camera一致即可*/
        <&msm_gpio 28 0>,
        <&msm_gpio 33 0>;
        qcom,gpio-reset = <1>;
        qcom,gpio-standby = <2>;
        qcom,gpio-req-tbl-num = <0 1 2>;
        qcom,gpio-req-tbl-flags = <1 0 0>;
        qcom,gpio-req-tbl-label = "CAMIF_MCLK",
        "CAM_RESET1",
        "CAM_STANDBY";
        qcom,cam-power-seq-type =/*eeprom的上电时序:和camera sensor的一致*/
        "sensor_vreg","sensor_gpio", "sensor_gpio","sensor_clk";
        qcom,cam-power-seq-val =
        "cam_vio",
        "sensor_gpio_standby",
        "sensor_gpio_reset",
        "sensor_cam_mclk";
        qcom,cam-power-seq-cfg-val = <1 1 1 24000000>;
        qcom,cam-power-seq-delay = <10 10 10 5>;

        clocks = <&clock_gcc clk_mclk0_clk_src>,/*clock:和camera一致即可*/
        <&clock_gcc clk_gcc_camss_mclk0_clk>;
        clock-names = "cam_src_clk", "cam_clk";
    };
复制代码
qcom,camera@1 {
    //在camera中应用eeprom1
···
        qcom,eeprom-src = <&eeprom1>;
···
}
复制代码

属性节点含义

  • cell-index = <1>; 该节点用于eeprom subdev注册subdev_id,唯一即可!
  • reg = <0x20> 注册地址:高端平台要求这个地址唯一即可,低端平台借助这个地址和i2c通信, 保险起见,统一设置为i2c地址。
  • qcom,eeprom-name = "ov5675_back"; 这个名称必须和eeprom驱动的名称一致,例如
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/
modules/sensors/sensor_libs/ov5675_back/ov5675_back_lib.c
static sensor_lib_t sensor_lib_ptr = { 
  /* sensor eeprom name */
  .eeprom_name = "ov5675_back",
}
```c

* qcom,slave-addr = <0x20>;
  I2C 设备地址
* cam_vio-supply = <&pm8916_l10>;
  供电电源
* qcom,cam-power-seq-type
上电时序
```c
上电的类型
qcom,cam-power-seq-type = "sensor_vreg","sensor_gpio", "sensor_gpio","sensor_clk";
上电类型的对应的val
qcom,cam-power-seq-val = "cam_vio","sensor_gpio_standby","sensor_gpio_reset","sensor_cam_mclk";
上电时序的值:除了clock配置成相应的值,其他全配置1
qcom,cam-power-seq-cfg-val = <1 1 1 24000000>;
上电延迟时间
qcom,cam-power-seq-delay = <10 10 10 5>;
复制代码

事实上,这个上电时序跟Camera Sensor的上电时序是一致的!举个例子

  • qcom,page0 = = <有效值 地址 地址类型 数据 数据类型 延迟> 地址类型:1代表1 byte ,2代表2byte = 1 word 数据类型:1代表1 byte ,2代表2byte = 1 word 读写规则
qcom,page7 = <1 0x3d81 2 0x01 1 10>;/*往0x3d81写入0x01:把OTP数据加载到buffer中 */
qcom,pageen7 = <0 0x0 0 0x0 0 0>;
qcom,poll7 = <0 0x0 0 0x0 0 0>;
qcom,mem7 = <256 0x7010 2 0 1 1>;/*从0x7010开始读取256个数据*/
复制代码

到此,dtsi的配置就完成了!!!

3.3 软件驱动配置

1.添加新的EEPROM驱动

vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/
sensors/eeprom_libs/ov5675_back
* ov5675_back.c
* Android.mk
复制代码

任何新 .c 文件都应映射和定义以下函数指针。 所有未在此 EEPROM 驱动程 序中定义的函数必须设置为 NULL。

.get_calibration_items() – 此函数应返回 EEPROM 模块所支持的配置。 基于 EEPROM 所支持的配置,将指定标记设置为 TRUE 或 FALSE。

  • Is_insensor – 如果传感器模块本身支持 EEPROM 配置,则将此标记设置为 TRUE。 外部 EEPROM 均不可用。
  • Is_afc – 如果支持 AF 校准,将此标记设置为 TRUE。
  • Is_wbc – 如果支持白平衡校准,将此标记设置为 TRUE。
  • Is_lsc – 如果支持镜头阴影校准,将此标记设置为 TRUE。
  • Is_dpc – 如果支持缺陷像素校正,将此标记设置为 TRUE

.format_calibration_data() – 此函数用于格式化可写入 eeprom/ 传感器模块的数据

OTP数据应用

  • .do_af_calibration() – 此函数用于处理所有与 AF 相关的校准操作, 如格式化数据和将 其写入 EEPROM 以执行 AF 校准。
  • .do_wbc_calibration() – 此函数用于处理所有与白平衡相关的校准操作, 如格式化数据 和将其写入 EEPROM 以执行白平衡校准。
  • .do_lsc_calibration() – 此函数用于处理所有与镜头阴影校正相关的校准操作, 如格式化 数据和将其写入 EEPROM 以执行镜头阴影校准。
  • .do_dpc_calibration() – 此函数用于处理所有与缺陷像素校正相关的校准操作, 如格式化 数据和将其写入 EEPROM 以执行缺陷像素校正

例子二:以独立EEPROM为例子(数据烧录在独立的EEPROM中)

步骤和例子1是一样的,关键在于dtsi的配置

eeprom0: qcom,eeprom@a0 { 
        cell-index = <0>; 
        reg = <0xa0>; 
        qcom,eeprom-name = "gc8034_otp"; 
        compatible = "qcom,eeprom"; 
        qcom,slave-addr = <0xa0>; 
        qcom,cci-master = <0>; 
        qcom,num-blocks = <1>; 
        qcom,page0 = <0 0 0 0 0 0>; 
        qcom,pageen0 = <0 0x0 0 0x0 0 0>; 
        qcom,poll0 = <0 0x0 0 0x0 0 0>; 
        qcom,mem0 = <1813 0x0000 2 0 1 1>; 
        cam_vio-supply = <&pm8916_l10>; 
        qcom,cam-vreg-name = "cam_vio"; 
        qcom,cam-vreg-type = <0>; 
        qcom,cam-vreg-min-voltage = <1800000>; 
        qcom,cam-vreg-max-voltage = <2800000>; 
        qcom,cam-vreg-op-mode = <80000>;
        qcom,cam-power-seq-type = "sensor_vreg"; 
        qcom,cam-power-seq-val ="cam_vio"; 
        qcom,cam-power-seq-cfg-val = <1>; 
        qcom,cam-power-seq-delay = <10>; 
    }; 
复制代码

最关键的地方就是reg = <0xa0>; 这里要配置成I2C地址,读取数组的时候,I2C会自动把a0>>1=0x50去通信! 当然高端点的平台就不需要关注reg,只需配置唯一即可,最好的办法还是配置为i2c地址!

8909平台不支持reg配置成a0,内核中有效地址是0x00~0x7f直接,如果配置成a0, 会报错:Invalid7-bit I2C address 0xa0!!! 因此需要修改一下内核: kernel/drivers/i2c/i2c-core.c

static int i2c_check_client_addr_validity(const struct i2c_client *client)
{
    
    if (client->flags & I2C_CLIENT_TEN) {
        /* 10-bit address, all values are valid */
        if (client->addr > 0x3ff)
            return -EINVAL;
    } else {
        if (client->addr == 0xa0)//让a0地址合法化!!!
            return 0;
        /* 7-bit address, reject the general call address */
        if (client->addr == 0x00 || client->addr > 0x7f)
            return -EINVAL;
    }    
    return 0;
}

复制代码

供电这一块,eeprom只需要IO供电即可:因此配置就更简单了

        cam_vio-supply = <&pm8916_l10>; 
        qcom,cam-vreg-name = "cam_vio"; 
        qcom,cam-vreg-type = <0>; 
        qcom,cam-vreg-min-voltage = <1800000>; 
        qcom,cam-vreg-max-voltage = <2800000>; 
        qcom,cam-vreg-op-mode = <80000>;
        qcom,cam-power-seq-type = "sensor_vreg"; 
        qcom,cam-power-seq-val ="cam_vio"; 
        qcom,cam-power-seq-cfg-val = <1>; 
        qcom,cam-power-seq-delay = <10>; 
复制代码

读写规则:直接从0x00开始读1813个数据,不需要操作任何寄存器!

qcom,mem0 = <1813 0x0000 2 0 1 1>; 
复制代码

例子三:以GC8034为例子(数据烧录在Camera Sensor中)

GC8034的读写规则比较复杂,和高通要求的不一样!

高通的源码是给一个初始地址,然后不停+1的往后读取数据,最后保存在buffer中! GC8034是去读d7这个寄存器的值!(这些读写规则,要多和模组厂跟sensor厂沟通) 因此要改动kernel层的源码

static int read_eeprom_memory(struct msm_eeprom_ctrl_t *e_ctrl,
    struct msm_eeprom_memory_block_t *block)
        if (emap[j].mem.valid_size) {
            /*   galaxycore start  */
            if(0 == strcmp(eb_info->eeprom_name,"gc8034_otp")){
                    e_ctrl->i2c_client.addr_type = 1;  /* luyi */
                    /*读取0xf4到gc_readf4变量中*/
                    rc=e_ctrl->i2c_client.i2c_func_tbl->i2c_read(
                            &(e_ctrl->i2c_client), 0xf4, &gc_readf4, emap[j].mem.data_t);
                    /*往d4寄存器写page和高8位地址*/
                    e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
                            &(e_ctrl->i2c_client), 0xd4, (emap[j].mem.addr >> 8) & 0xff, emap[j].mem.data_t);
                    /*往d5寄存器写低8位地址*/
                    e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
                            &(e_ctrl->i2c_client), 0xd5, emap[j].mem.addr & 0xff, emap[j].mem.data_t);
                    /*往f3寄存器写入0x20:OTP read 模式*/
                    e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
                            &(e_ctrl->i2c_client), 0xf3, 0x20, emap[j].mem.data_t);
                    /*往f4寄存器的第2位置1,表示地址自动++(按照1 个byte=8bit的方式)*/
                    e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
                            &(e_ctrl->i2c_client), 0xf4, gc_readf4 | 0x02, emap[j].mem.data_t);
                    /*往f3寄存器写入80,设置自动读取信号*/
                    e_ctrl->i2c_client.i2c_func_tbl->i2c_write(
                            &(e_ctrl->i2c_client), 0xf3, 0x80, emap[j].mem.data_t);
                    msleep(emap[j].mem.delay);//延时
                    for(gc = 0; gc < emap[j].mem.valid_size; gc++){
                        msleep(emap[j].mem.delay);
                        rc=e_ctrl->i2c_client.i2c_func_tbl->i2c_read(//读d7寄存器的值到gc_read变量中
                                &(e_ctrl->i2c_client), 0xd7, &gc_read, emap[j].mem.data_t);
                        if (rc < 0) {
                            pr_err("%s: read failed %d \n", __func__, __LINE__);
                            return rc;
                        }
                        *memptr = (uint8_t)gc_read;//把读出来的值保持到memptr 中
                        memptr++;
                    }
                    e_ctrl->i2c_client.i2c_func_tbl->i2c_write(//读完复位成初始状态
                            &(e_ctrl->i2c_client), 0xf3, 0x00, emap[j].mem.data_t);
                    e_ctrl->i2c_client.i2c_func_tbl->i2c_write(//读完复位成初始状态
                            &(e_ctrl->i2c_client), 0xf4, gc_readf4 & 0xfd, emap[j].mem.data_t);
                }
                /*galaxycore end*/
            else{
    //高通平台默认的读取方式
                e_ctrl->i2c_client.addr_type = emap[j].mem.addr_t;
            rc = e_ctrl->i2c_client.i2c_func_tbl->i2c_read_seq(
                &(e_ctrl->i2c_client), emap[j].mem.addr,
                memptr, emap[j].mem.valid_size);
                pr_err("%s:travis read addr = %d,value = %d\n\n", __func__,emap[j].mem.addr,memptr[0]);
            if (rc < 0) {
                pr_err("%s: read failed\n", __func__);
                return rc;
            }
            memptr += emap[j].mem.valid_size;
            }
        }
}
复制代码

Stay Hungry,Stay Foolish!

转载于:https://juejin.im/post/5c79d7cf6fb9a049fe35db4d

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33795806/article/details/91439782

智能推荐

chatgpt赋能python:Python建立一个简单的Server_python server-程序员宅基地

文章浏览阅读887次。Python提供了一个轻量级和简单的方法来建立Web Server。它是HTTPServer模块,一个内置的模块,无需其他配置文件或工具。当然,还有其他的Python框架可以用来建立更复杂的Web应用程序。如果您刚开始学习Python Web开发,HTTPServer是一个很好的起点。在实际的Web开发中,使用Python建立Server可能需要处理更复杂的逻辑和处理,包括与数据库的交互和安全性等问题。但是,使用Python作为Server可以快速启动原型应用程序,并提供后续的扩展方便性。_python server

X11 Xlib截屏问题及深入分析二 —— 源码实现1_xgrabkey使用-程序员宅基地

文章浏览阅读642次。X11 Xlib截屏问题及深入分析二 —— 源码实现_xgrabkey使用

MTK ATM流程-程序员宅基地

文章浏览阅读1.4k次。# Android Test Mode FeatureMTK_ATM_SUPPORT := yes-------------------------------bool get_atm_enable_status(void){ bool atm_enable_flag = false;#if defined (MTK_ATM_SUPPORT) char part_nam...

Feign 中的继承、日志与数据压缩_feign继承性案例-程序员宅基地

文章浏览阅读687次,点赞2次,收藏4次。上篇文章和大家分享了声明式微服务调用组件 Feign 的基本用法,相信大家已经了解到使用 Feign 的好处了,使用 Feign 有效地解决了使用 RestTemplate 时的代码模板化的问题,使服务之间的调用更加简单方便,同时也不易出错。不过,细心的读者可能也发现,上篇文章中我们学的 Feign 还是有一些明显的缺陷,例如,当我们在 provider 中定义接口时,可能是下面这样:@Rest..._feign继承性案例

算法通关村——原来如此简单-程序员宅基地

文章浏览阅读46次。本篇博客讲述了有关层序遍历方面的知识和相应的题目讲解

多元分类预测 | Matlab基于KOA-CNN开普勒优化卷积神经网络的数据分类预测_开普勒优化算法koa-程序员宅基地

文章浏览阅读227次。多元分类预测 | Matlab基于KOA-CNN开普勒优化卷积神经网络的数据分类预测_开普勒优化算法koa

随便推点

简单的病毒编程代码python,如何用python做恶搞病毒-程序员宅基地

文章浏览阅读309次,点赞3次,收藏5次。这篇文章主要介绍了简单的病毒编程代码python,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。这篇文章主要介绍了python简单的病毒编程代码,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。50次机会用完或点击”是“就会出现白屏(因为explorer进程被结束)不知道为啥,按win+Shift+S截不了图了,2、按下Ctrl+Alt+Delete组合键,选择任务管理器。

顶刊TPAMI 2023!Food2K:大规模食品图像识别-程序员宅基地

文章浏览阅读1k次。点击下方卡片,关注“CVer”公众号AI/CV重磅干货,第一时间送达点击进入—>【计算机视觉】微信技术交流群来源:美团技术团队美团基础研发平台视觉智能部与中科院计算所展开科研课题合作,共同构建大规模数据集Food2K,并提出渐进式区域增强网络用于食品图像识别,相关研究成果已发表于T-PAMI 2023。本文主要介绍了数据集特点、方法设计、性能对比,以及基于该数据集的迁移实验等方面的内容,并对..._food2k数据集

stm32L系列简介问答-程序员宅基地

文章浏览阅读1.3k次。STM32L特性[问] 请问STM32L与STM32的固件库相同吗?现在最新版是多少? [答] 目前的固件库(3.3.0)针对STM32 Value line,Connectivity line; [1900-1-1] [问:] STM32L eneryLite系列采用什么样的内核?它和STM32F-2系列有何不同或优势? [答:] 仍然是cortex-m3,只是工艺是一个新的平..._stm32l系列有百兆网口引脚吗

将我的ASP.NET网站从.NET 2.2 Core Preview 2升级到.NET 2.2 Core Preview 3-程序员宅基地

文章浏览阅读119次。I've recently returned from a month in South Africa and I was looking to unwind while the jetlagged kids sleep. I noticed that .NET Core 2.2 Preview 3 came out while I wasn't paying attention. My podc..._microsoft.aspnetcore.razor.design 从2.2.0降级到2.2.0-preview3-35497

Hbase-程序员宅基地

文章浏览阅读525次,点赞24次,收藏9次。是一种思想概念,一种抽象思维,用来描述数据的数据,比如有一张学生表,记录着学生的基本信息,我们通过表可以获取学生信息(数据),但是有时候也要得到表本身的信息数据(比如表结构信息:字段名称,字段数据类型,长度等信息),对于这种基础信息的描述,就会使用META的概念,使用META元数据来描述表本身。如果在一些Region中有大量的数据(存着那个列族中的列的数据),而剩下的Region仅有少量的数据,那么就会生成多个的小文件。当一个行键在不同的列族中都有相应的列值的话,不同列族中的文件都会存储这个行键的值。

Create.js实战-音乐播放操作-程序员宅基地

文章浏览阅读787次。大家好,我又来了,今天要跟大家墨迹墨迹关于Create.js实战-音乐播放操作, 话不多少直接官方链接入口http://www.createjs.cc/src/docs/soundjs/modules/SoundJS.html SoundJS库管理在网络上播放的音频。它是通过实际的音频实现..._createjs.sound.play

推荐文章

热门文章

相关标签