韦东山嵌入式Linux视频教程_3期项目实战之ALSA声卡_从零编写之参数设置(基于优龙FS2410开发板,UDA1341声卡)

一、实验环境

1.1 虚拟机环境

a) Vmware版本:Vmware Workstation 12.5.7

b) Ubuntu版本:9.10

c) 内核版本:2.6.31.14

d) toolchain版本:arm-linux-gcc 4.3.2

1.2 开发板

优龙FS2410开发板,UDA1341声卡

内核版本:3.4.2

二、概述

2.1 目标

之前在写裸板程序时,已经了解了怎样写代码来操作硬件,设置参数,传输数据。现在的任务就是按照ASOC的框架,来重新写这些代码(难点在于理解软件框架)

2.2 哪些地方的代码会涉及到参数设置

根据之前“分析调用过程”那节视频中,用strace跟踪的结果,总结出以下几个地方的代码会涉及到参数设置:

1. soc_pcm_open依次调用cpu_dai, platform(dma), codec_dai, machine的open或startup函数,经查:

  • cpu_dai

s3c24xx_i2s_dai.ops(即s3c24xx_i2s_dai_ops),无startup函数

  • platform(dma)

samsung_asoc_platform.ops(即dma_ops).dma_open里:snd_pcm_hw_constraint_integer,snd_soc_set_runtime_hwparams(&dma_hardware)

  • codec_dai

uda134x_dai_ops.startup即uda134x_startup 里:

snd_pcm_hw_constraint_minmax(SNDRV_PCM_HW_PARAM_RATE), snd_pcm_hw_constraint_minmax(SNDRV_PCM_HW_PARAM_SAMPLE_BITS)

  • machine

s3c24xx_uda134x_dai_link.ops(即s3c24xx_uda134x_ops).startup即s3c24xx_uda134x_startup里:

主要工作是设置rate[]的值(算法原理可参考在uda1341的i2s中256fs,384fs和512fs表示的实际意义和如何auto智能选择

通过分析这些函数可知,它们并没有涉及到硬件操作,所以我们把它们都归并到dma_open里实现

2. soc_pcm_hw_params依次调用machine,codec_dai,cpu_dai,platform(dma)的hw_params函数

  • machine

s3c24xx_uda134x .hw_params 即s3c24xx_uda134x_hw_params

  • codec_dai

uda134x_dai_ops.hw_params 即uda134x_hw_params

  • cpu_dai

s3c24xx_i2s_dai_ops.hw_params 即s3c24xx_i2s_hw_params

  • platform(dma)

samsung_asoc_platform.ops(即dma_ops). hw_params 即dma_hw_params

通过分析这些函数可知,它们涉及到了硬件操作,所以我们需要分别在这些hw_params函数所属的驱动中实现

三、具体实现

3.1 实现dma_open

(参考:sound\soc\samsung\dma.c)

static const struct snd_pcm_hardware s3c2440_dma_hardware = {
	.info			= SNDRV_PCM_INFO_INTERLEAVED |
				    SNDRV_PCM_INFO_BLOCK_TRANSFER |
				    SNDRV_PCM_INFO_MMAP |
				    SNDRV_PCM_INFO_MMAP_VALID |
				    SNDRV_PCM_INFO_PAUSE |
				    SNDRV_PCM_INFO_RESUME,
	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
				    SNDRV_PCM_FMTBIT_U16_LE |
				    SNDRV_PCM_FMTBIT_U8 |
				    SNDRV_PCM_FMTBIT_S8,
	.channels_min		= 2,
	.channels_max		= 2,
	.buffer_bytes_max	= 128*1024,
	.period_bytes_min	= PAGE_SIZE,
	.period_bytes_max	= PAGE_SIZE*2,
	.periods_min		= 2,
	.periods_max		= 128,
	.fifo_size		= 32,
};
static int s3c2440_dma_open(struct snd_pcm_substream *substream)
{
    struct snd_pcm_runtime *runtime = substream->runtime;
    int ret;
    //去掉了和prtd相关的代码,因为这是samsung自己定义的用于dma操作的数据结构,我们不使用,而是自己来实现dma操作
    /* 设置属性 */
    snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); //约束:采样周期必须是整数
    snd_soc_set_runtime_hwparams(substream, &s3c2440_dma_hardware); //后续的snd_pcm_hw_constraints_complete会使用runtime->hw里的信息来调用一系列的snd_pcm_hw_constraint_xxx
    return 0;
}

3.2 实现machine、codec_dai、cpu_dai、platform(dma)的hw_params函数

注:由于codec_dai(uda1341_hw_params)涉及代码最复杂,所以放在最后实现

3.2.1 实现s3c2440_uda1341.hw_params 即s3c2440_uda1341_hw_params

分析内核的s3c24xx_uda134x_hw_params()可知:它主要是调用了snd_soc_dai_set_fmt、snd_soc_dai_set_sysclk、snd_soc_dai_set_clkdiv来设置cpu_dai和codec_dai的数据格式以及时钟,而这些工作可以拆开后分别放在cpu_dai(见下文s3c2440_i2s_hw_params)和codec_dai(见下文uda1341_hw_params ())中。所以s3c2440_uda1341_hw_params不用实现。

注:关于怎样根据app提供的rate来计算clk、clk_source、fs_mod、div,可参考:在uda1341的i2s中256fs,384fs和512fs表示的实际意义和如何auto智能选择

3.2.2 实现s3c2440_i2s_dai_ops.hw_params 即s3c2440_i2s_hw_params

struct s3c2440_iis_regs {
    unsigned int iiscon ;
    unsigned int iismod ;
    unsigned int iispsr ;
    unsigned int iisfcon;
    unsigned int iisfifo;
};
static volatile unsigned int *gpecon;
static volatile struct s3c2440_iis_regs *iis_regs;

static int s3c2440_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
/* 根据params设置IIS控制器 */
/* 参考裸板程序soc/iis.c的iis_init */
    int tmp_fs;
    int i;
    int min = 0xffff;
    int pre = 0;
    unsigned int fs;
    struct clk *clk = clk_get(NULL, "pclk");
    /* 配置GPIO用于IIS */
    *gpecon &= ~((3<<0) | (3<<2) | (3<<4) | (3<<6) | (3<<8));
    *gpecon |= ((2<<0) | (2<<2) | (2<<4) | (2<<6) | (2<<8));
    /* bit[9] : Master clock select, 0-PCLK
     * bit[8] : 0 = Master mode
     * bit[7:6] : 10 = Transmit mode
     * bit[4] : 0-IIS compatible format
     * bit[3] : serial bit clock frequency select,1: 32fs,这样可以兼容8bit 和16bit的serial data bit per channel
     * bit[2] : 384fs, 确定了MASTER CLOCK之后, fs = MASTER CLOCK/384
     * bit[1:0] : Serial bit clock frequency select, 32fs
     */
    if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
        iis_regs->iismod = (2<<6) | (0<<4) | (1<<3) | (1<<2) | (1);
    else if (params_format(params) == SNDRV_PCM_FORMAT_S8)
        iis_regs->iismod = (2<<6) | (0<<4) | (0<<3) | (1<<2) | (1);
    else
        return -EINVAL;
	 /* 参考: s3c2440 datasheet: IIS prescaler(IISPSR) register
	  * Master clock = PCLK/(n+1)
	  * fs = Master clock / 384
	  * fs = PCLK / (n+1) / 384
	  */
//根据以上公式,对于app传入的fs采样率,计算出最接近的tmp_fs,以及对应的iispsr
fs = params_rate(params);
    for (i = 0; i <= 31; i++) //IISPSR controlA, data value:[0~31]
    {
        tmp_fs = clk_get_rate(clk)/384/(i+1);
        if (ABS(tmp_fs, fs) < min)
        {
            min = ABS(tmp_fs, fs);
            pre = i;
        }
    }
    iis_regs->iispsr = (pre << 5) | (pre);
    /*
     * bit15 : Transmit FIFO access mode select, 1-DMA
     * bit13 : Transmit FIFO, 1-enable
     */
    iis_regs->iisfcon = (1<<15) | (1<<13);
    /*
     * bit[5] : Transmit DMA service request, 1-enable
     * bit[1] : IIS prescaler, 1-enable
     */
    iis_regs->iiscon = (1<<5) | (1<<1) ;
    clk_put(clk);
    return 0;
}
static int s3c2440_iis_init(void)
{
    gpecon   = ioremap(0x56000040, 4);
    iis_regs = ioremap(0x55000000, sizeof(struct s3c2440_iis_regs));
    platform_device_register(&s3c2440_iis_dev);
    platform_driver_register(&s3c2440_iis_drv);
    return 0;
}
static void s3c2440_iis_exit(void)
{
    platform_device_unregister(&s3c2440_iis_dev);
    platform_driver_unregister(&s3c2440_iis_drv);
    iounmap(gpecon);
    iounmap(iis_regs);
}

3.2.3 实现s3c2440_dma_ops. hw_params 即s3c2440_dma_hw_params

分析内核的dma_hw_params()可知:主要工作涉及到数据的传输,所以我们把s3c2440_dma_hw_params留到下一节“数据传输”再实现。

3.2.4 实现uda1341_dai_ops.hw_params 即uda1341_hw_params

(为了简单, 在uda1341_init_regs里就设置好固定的参数(比如时钟、格式),并且由uda1341_soc_probe一次性调用)

#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | 		SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
/* status control */
#define STAT0 (0x00)
#define STAT0_RST (1 << 6)
#define STAT0_SC_MASK (3 << 4)
#define STAT0_SC_512FS (0 << 4)
#define STAT0_SC_384FS (1 << 4)
#define STAT0_SC_256FS (2 << 4)
#define STAT0_IF_MASK (7 << 1)
#define STAT0_IF_I2S (0 << 1)
#define STAT0_IF_LSB16 (1 << 1)
#define STAT0_IF_LSB18 (2 << 1)
#define STAT0_IF_LSB20 (3 << 1)
#define STAT0_IF_MSB (4 << 1)
#define STAT0_IF_LSB16MSB (5 << 1)
#define STAT0_IF_LSB18MSB (6 << 1)
#define STAT0_IF_LSB20MSB (7 << 1)
#define STAT0_DC_FILTER (1 << 0)
#define STAT0_DC_NO_FILTER (0 << 0)

#define STAT1 (0x80)
#define STAT1_DAC_GAIN (1 << 6) /* gain of DAC */
#define STAT1_ADC_GAIN (1 << 5) /* gain of ADC */
#define STAT1_ADC_POL (1 << 4) /* polarity of ADC */
#define STAT1_DAC_POL (1 << 3) /* polarity of DAC */
#define STAT1_DBL_SPD (1 << 2) /* double speed playback */
#define STAT1_ADC_ON (1 << 1) /* ADC powered */
#define STAT1_DAC_ON (1 << 0) /* DAC powered */

/* data0 direct control */
#define DATA0 (0x00)
#define DATA0_VOLUME_MASK (0x3f)
#define DATA0_VOLUME(x) (x)

#define DATA1 (0x40)
#define DATA1_BASS(x) ((x) << 2)
#define DATA1_BASS_MASK (15 << 2)
#define DATA1_TREBLE(x) ((x))
#define DATA1_TREBLE_MASK (3)

#define DATA2 (0x80)
#define DATA2_PEAKAFTER (0x1 << 5)
#define DATA2_DEEMP_NONE (0x0 << 3)
#define DATA2_DEEMP_32KHz (0x1 << 3)
#define DATA2_DEEMP_44KHz (0x2 << 3)
#define DATA2_DEEMP_48KHz (0x3 << 3)
#define DATA2_MUTE (0x1 << 2)
#define DATA2_FILTER_FLAT (0x0 << 0)
#define DATA2_FILTER_MIN (0x1 << 0)
#define DATA2_FILTER_MAX (0x3 << 0)
/* data0 extend control */
#define EXTADDR(n) (0xc0 | (n))
#define EXTDATA(d) (0xe0 | (d))

#define EXT0 0
#define EXT0_CH1_GAIN(x) (x)
#define EXT1 1
#define EXT1_CH2_GAIN(x) (x)
#define EXT2 2
#define EXT2_MIC_GAIN_MASK (7 << 2)
#define EXT2_MIC_GAIN(x) ((x) << 2)
#define EXT2_MIXMODE_DOUBLEDIFF (0)
#define EXT2_MIXMODE_CH1 (1)
#define EXT2_MIXMODE_CH2 (2)
#define EXT2_MIXMODE_MIX (3)
#define EXT4 4
#define EXT4_AGC_ENABLE (1 << 4)
#define EXT4_INPUT_GAIN_MASK (3)
#define EXT4_INPUT_GAIN(x) ((x) & 3)
#define EXT5 5
#define EXT5_INPUT_GAIN(x) ((x) >> 2)
#define EXT6 6
#define EXT6_AGC_CONSTANT_MASK (7 << 2)
#define EXT6_AGC_CONSTANT(x) ((x) << 2)
#define EXT6_AGC_LEVEL_MASK (3)
#define EXT6_AGC_LEVEL(x) (x)

#define UDA1341_L3ADDR	5 //即UDA1341的设备地址,见 uda1341 datasheet p.11.
#define UDA1341_DATA0_ADDR	((UDA1341_L3ADDR << 2) | 0)
#define UDA1341_DATA1_ADDR	((UDA1341_L3ADDR << 2) | 1)
#define UDA1341_STATUS_ADDR	((UDA1341_L3ADDR << 2) | 2)

/* UDA1341 registers */
#define UDA1341_DATA00 0
#define UDA1341_DATA01 1
#define UDA1341_DATA10 2
#define UDA1341_EA000  3
#define UDA1341_EA001  4
#define UDA1341_EA010  5
#define UDA1341_EA100  6
#define UDA1341_EA101  7
#define UDA1341_EA110  8
#define UDA1341_DATA1  9
#define UDA1341_STATUS0 10
#define UDA1341_STATUS1 11

#define UDA1341_REG_NUM 12

#define UDA1341_EXTADDR_PREFIX	0xC0
#define UDA1341_EXTDATA_PREFIX	0xE0

/* 所有寄存器的默认值 */
static const char uda1341_reg[UDA1341_REG_NUM] = {
    /* DATA0 */
    0x00, 0x40, 0x80,
    /* Extended address registers */
    0x04, 0x04, 0x04, 0x00, 0x00, 0x00,
    /* data1 */
    0x00,
    /* status regs */
    0x00, 0x83,
};

static const char uda1341_reg_addr[UDA1341_REG_NUM] = {
    UDA1341_DATA0_ADDR, UDA1341_DATA0_ADDR, UDA1341_DATA0_ADDR,
    0, 1, 2, 4, 5, 6, //扩展寄存器的地址EA2,EA1,EA0,见:UDA1341 datasheet “7.21 programming the sound processing and other features”.
    UDA1341_DATA1_ADDR,
    UDA1341_STATUS_ADDR, UDA1341_STATUS_ADDR
};
static const char uda1341_data_bit[UDA1341_REG_NUM] = {
    0 /* VC */, (1<<6)/* BB,TR */, (1<<7)/* PP,DE,MT,M */,
    0, 0, 0, 0, 0, 0,//6个扩展寄存器不使用uda1341_data_bit,而是在发送数据时,直接| UDA1341_EXTDATA_PREFIX
    0, //data1 用于读数据,用不着
    0/* status0 */, (1<<7)/* status1 */,
};

static volatile unsigned int *gpbdat;
static volatile unsigned int *gpbcon;

static int uda1341_soc_probe(struct snd_soc_codec *codec)
{
    int ret;
    uda1341_init_regs(codec);
    return ret;
}
/*
 * The codec has no support for reading its registers except for peak level...
 */
static inline unsigned int uda1341_read_reg_cache(struct snd_soc_codec *codec,	unsigned int reg)
{
	u8 *cache = codec->reg_cache;
	if (reg >= UDA1341_REG_NUM)
	    return -1;
	return cache[reg];
}
/*以下有关用GPIO模拟L3接口的函数,参考裸板程序的set_mod、set_clk、set_dat、sendbyte、l3_write */
static void set_mod(int val)
{
    if (val)
    {
        *gpbdat |= (1<<2);
    }
    else
    {
        *gpbdat &= ~(1<<2);
    }
}
static void set_clk(int val)
{
    if (val)
    {
        *gpbdat |= (1<<4);
    }
    else
    {
        *gpbdat &= ~(1<<4);
    }
}
static void set_dat(int val)
{
    if (val)
    {
        *gpbdat |= (1<<3);
    }
    else
    {
        *gpbdat &= ~(1<<3);
    }
}
static void sendbyte(unsigned int byte)
{
    int i;
    for (i = 0; i < 8; i++) {
	set_clk(0);
	udelay(1);
	set_dat(byte & 1);
	udelay(1);
	set_clk(1);
	udelay(1);
	byte >>= 1;
    }
}
static void l3_write(u8 addr, u8 data)
{
    set_clk(1);
    set_dat(1);
    set_mod(1);
    udelay(1);

    set_mod(0);
    udelay(1);
    sendbyte(addr);
    udelay(1);

    set_mod(1);
    sendbyte(data);

    set_clk(1);
    set_dat(1);
    set_mod(1);
}
static int uda1341_write_reg(struct snd_soc_codec *codec, unsigned int reg,	unsigned int value)
{
    u8 *cache = codec->reg_cache;
    /* 先保存 */
    if (reg >= UDA1341_REG_NUM)
	return -1;
    cache[reg] = value;
    /* 再写入硬件 */
    /* 对于EA,需要调用2次l3_write */
    if ((reg >= UDA1341_EA000) && (reg <= UDA1341_EA110))
    {
        l3_write(UDA1341_DATA0_ADDR, uda1341_reg_addr[reg] | UDA1341_EXTADDR_PREFIX);
        l3_write(UDA1341_DATA0_ADDR, value | UDA1341_EXTDATA_PREFIX);
    }
    else
    {
        l3_write(uda1341_reg_addr[reg], value | uda1341_data_bit[reg]);
    }
    return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_uda1341 = {
	.probe =        uda134x_soc_probe,
//	.remove =       uda134x_soc_remove,
//	.suspend =      uda134x_soc_suspend,
//	.resume =       uda134x_soc_resume,
    /* UDA1341的寄存器不支持读操作
     * 要知道某个寄存器的当前值,
     * 只能在写入时保存起来
     */
	.reg_cache_size = sizeof(uda134x_reg),
	.reg_word_size = sizeof(u8),
	.reg_cache_default = uda134x_reg,
	.reg_cache_step = 1,
	.read = uda134x_read_reg_cache,
	.write = uda134x_write,
//	.set_bias_level = uda134x_set_bias_level,
};
//参考: 裸板程序uda1341_init
static void uda1341_init_regs(struct snd_soc_codec *codec)
{
    /* GPB 4: L3CLOCK */
    /* GPB 3: L3DATA */
    /* GPB 2: L3MODE */
    *gpbcon &= ~((3<<4) | (3<<6) | (3<<8));
    *gpbcon |= ((1<<4) | (1<<6) | (1<<8));
    /*
	bit[6] : reset
	bit[5:4] : system clk frequency, 1:384fs
	bit[3~1] : input data format, 0:iis
	bit[0] : DC filter, 1:yes
     */
    uda1341_write_reg(codec, UDA1341_STATUS0, 0x40 | STAT0_SC_384FS | STAT0_DC_FILTER); // reset uda1341
    uda1341_write_reg(codec, UDA1341_STATUS1, STAT1_ADC_ON | STAT1_DAC_ON); //打开ADC和DAC通道
    uda1341_write_reg(codec, UDA1341_DATA00, DATA0_VOLUME(0x0)); // maximum volume
    uda1341_write_reg(codec, UDA1341_DATA01, DATA1_BASS(0)| DATA1_TREBLE(0));
    uda1341_write_reg(codec, UDA1341_DATA10, 0);  // not mute
}
static int uda1341_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
    /* 根据params的值,设置UDA1341的寄存器
     * 比如时钟设置,格式
     */
    /* 为了简单, 在uda1341_init_regs里就设置好时钟、格式等参数 */
    return 0;
}

四、参考资料

1. 韦东山 嵌入式Linux视频教程_3期项目实战之ALSA声卡:第2课第1.1_17节_ALSA声卡08_从零编写之框架

2. DroidPhone 《Linux ALSA 声卡驱动》

3. gliethttp 在uda1341的i2s中256fs,384fs和512fs表示的实际意义和如何auto智能选择

原文地址:https://www.cnblogs.com/normalmanzhao2003/p/12327117.html

时间: 2024-09-29 17:01:20

韦东山嵌入式Linux视频教程_3期项目实战之ALSA声卡_从零编写之参数设置(基于优龙FS2410开发板,UDA1341声卡)的相关文章

HTML5视频教程,HTML5项目实战,HTML5中文指南,HTML5使用手册

HTML5视频教程,HTML5项目实战,HTML5中文指南,HTML5使用手册. 超过2G 的 HTML5 视频教程免费分享,免费下载! 尚硅谷前端HTML5视频_HTML & CSS 核心基础教程(103集实战教学,从入门到精通) 本套视频适合零基础并且对前端知识感兴趣的同学.内容涵盖HTML基础.标签.CSS 选择器.盒子模型.浮动.定位.图片整合.PS 切图等页面相关常用技术. 视频最后包含一个实战项目:将一个 PSD 设计图转换为一个商业网站的首页.让同学们体验前端页面开发的全过程. 通

【java项目实战】Servlet详解以及Servlet编写登陆页面(二)

Servlet是Sun公司提供的一门用于开发动态web网页的技术.Sun公司在API中提供了一个servlet接口,我们如果想使用java程序开发一个动态的web网页,只需要实现servelet接口,并把类部署到web服务器上就可以运行了. 到底什么是Servlet呢? 通俗一点,只要是实现了servlet接口的java程序,均称Servlet.Servlet是由sun公司命名的,Servlet = Server + Applet(Applet表示小应用程序),Servlet是在服务器端运行的小

Linux sudo权限管理项目实战

企业生产环境用户权限集中管理项目方案 问题现状当前我们公司里服务器上百台,各个服务器上的管理人员很多(开发+运维+架构DBA+产品+市场),在大家登录使用Linux服务器时,不同职能的员工水平不同,因此导致操作系统很不规范,root权限泛滥(几乎大部分人员都有root权限),经常导致文件等莫名其妙的丢失,老手和新手员工对服务器的熟知度也不同,这样使得公司服务器安全存在很大不稳定性.及操作安全隐患,据调查企业服务器环境,50%以上的安全问题都来自于内部,而不是外部.为了解决以上问题,单个用户管理权

Python网络爬虫实战-Scrapy视频教程 Python系统化项目实战课程 Scrapy技术课程

课程目录01.scrapy是什么.mp4Python实战-02.初步使用scrapy.mp4Python实战-03.scrapy的基本使用步骤.mp4Python实战-04.基本概念介绍1-scrapy命令行工具.mp4Python实战-05.本概念介绍2-scrapy的重要组件.mp4Python实战-06.基本概念介绍3-scrapy中的重要对象.mp4Python实战-07.scrapy内置服务介绍.mp4Python实战-08.抓取进阶-对"西刺"网站的抓取.mp4Python

【java项目实战】Servlet具体解释以及Servlet编写登陆页面(二)

Servlet是Sun公司提供的一门用于开发动态web网页的技术. Sun公司在API中提供了一个servlet接口,我们假设想使用java程序开发一个动态的web网页,仅仅须要实现servelet接口,并把类部署到webserver上就能够执行了. 究竟什么是Servlet呢? 通俗一点,仅仅要是实现了servlet接口的java程序,均称Servlet. Servlet是由sun公司命名的,Servlet = Server + Applet(Applet表示小应用程序),Servlet是在s

Asp.NET Core2.0 项目实战入门视频课程_完整版

END OR START? 看到这个标题,你开不开心,激不激动呢? 没错,.net core的入门课程已经完毕了.52ABP.School项目从11月19日,第一章视频的试录制,到今天完整版出炉,离不开各位的帮助和加油. 课程概述 52ABP大学例子程序演示如何使用Entity Framework(EF) Core 2.0 和 Visual Studio 2017 创建一个 ASP.NET Core 2.0 MVC web 应用. 例子是一个大学的网站.它包括了学生入学,创建课程.教师管理等功能

韦东山linux视频第一期前两节观看收获

刚刚看了韦东山的linux视频第一期,主要讲解的ARM的硬件基础,对于我这样一个从单片机转过来的人来说,的确震撼! 我看过很多书和视频关于单片机的,但是从来没有一个会做到这么精练的.对,精练,归纳总结的相当好. 第一节 原理图之GPIO和门电路 第一节里,简要介绍了一些模拟电路,内容简单,但是却话出了最实用的的部分. (1)以前在模电课上,三极管这一节课可是花费了相当章节,结果让人云里雾里,不知道怎么去用.但是在这里,韦东山老 师没有多余的部分,直接把最直接.最有效的部分给了我们.P即正,N即负

嵌入式linux C++语言(二)——C++对C语言基础语法的扩展

嵌入式linux C++语言(二)--C++对C语言基础语法的扩展 C++是基于C语言扩展发展而来的面向对象的程序设计语言,本文将主要讨论C++语言基于C语言扩展的方面. 一.类型增强 1.类型检查更严格 在C语言中: const int a = 100; int *p = &a; 在C++语言中: const int a = 100;//必须在定义的时候初始化 const int *p = &a; 在C++语言中不能隐式转换数据类型. error: invalid conversion

为什么要有uboot?带你全面分析嵌入式linux系统启动过程中uboot的作用

1.为什么要有uboot 1.1.计算机系统的主要部件 (1)计算机系统就是以CPU为核心来运行的系统.典型的计算机系统有:PC机(台式机+笔记本).嵌入式设备(手机.平板电脑.游戏机).单片机(家用电器像电饭锅.空调) (2)计算机系统的组成部件非常多,不同的计算机系统组成部件也不同.但是所有的计算机系统运行时需要的主要核心部件都是3个东西: CPU + 外部存储器(Flash/硬盘) + 内部存储器(DDR SDRAM/SDRAM/SRAM) 1.2.PC机的启动过程 (1)部署:典型的PC