一步步写 CMOS 驱动模块 <ELDD 学习笔记>

一步步写 CMOS 驱动模块


 Let's implement a char driver to access the system CMOS.




首先仅仅是创建设备模块,最简单的,类似于前面hello world模块一样的东东,从最简单的框架慢慢搭


/************************************************************
code writer : EOF
code date : 2014.08.15
code file : cmos_demo.c
e-mail:	jasonleaster@gmail.com

code purpose:
	This code is a demo for how to build a CMOS-driver
step by step.

	If there is something wrong with my code, please touch
me by e-mail. Thank you.

************************************************************/
#include <linux/module.h>
#include <linux/moduleparam.h>

#include <linux/fs.h>
#include <linux/init.h> 
#include <linux/cdev.h>  
#include <linux/slab.h> /* kmalloc() */
#include <linux/kernel.h> /* printk */
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/kdev_t.h>

int cmos_major = 0;//defualt
int cmos_minor = 0;

module_param(cmos_major,int,S_IRUGO);
module_param(cmos_minor,int,S_IRUGO);

//static dev_t	cmos_dev_number;	/* Allocated device number */
struct class	*cmos_class;	/* Tie with the device model */

#define NUM_CMOS_BANKS	2	
#define CMOS_BANK_SIZE	(0xFF*8)
#define DEVICE_NAME	"Jason_cmos"

#define CMOS_BANK0_INDEX_PORT	0x70
#define CMOS_BANK0_DATA_PORT	0x71
#define CMOS_BANK1_INDEX_PORT	0x72
#define CMOS_BANK1_DATA_PORT	0x73

unsigned char addrports[NUM_CMOS_BANKS] = {CMOS_BANK0_INDEX_PORT,CMOS_BANK1_INDEX_PORT};
unsigned char dataports[NUM_CMOS_BANKS] = {CMOS_BANK0_DATA_PORT,CMOS_BANK1_DATA_PORT};

MODULE_AUTHOR("Jason Leaster");
MODULE_LICENSE("Dual BSD/GPL");


struct cmos_dev
{
	unsigned short current_pointer; /*Current point within the bank*/
	
	unsigned int size;	/*size of the bank*/
	int bank_number;	/*Size of bank*/
	struct cdev cdev;
	char name[10];		/*Name of I/O regeion*/
	
	/* ... */
	
}*cmos_devp;
 
static struct file_operations cmos_fops = 
{
	.owner	=	THIS_MODULE,
};

int  cmos_init(void)
{
	int i;

	dev_t dev = 0;
	
	if(alloc_chrdev_region(&dev,cmos_minor,NUM_CMOS_BANKS,DEVICE_NAME) < 0)
	{
		printk(KERN_DEBUG "Can't regiester device\n");
		return -1;
	}

	cmos_major = MAJOR(dev);
	
	/*********I don't know what this is************/
	cmos_class = class_create(THIS_MODULE,DEVICE_NAME);
	
	release_region(0x70,0x8);

	for(i = 0;i < NUM_CMOS_BANKS;i++)
	{
		cmos_devp = kmalloc(sizeof(struct cmos_dev),GFP_KERNEL);
		if(!cmos_devp)
		{
			printk("Bad Kmalloc\n");
			return 1;
		}

		sprintf(cmos_devp->name,"cmos%d",i);
	
		if(!(request_region(addrports[i],2,cmos_devp->name)))
		{
			printk("cmos: I/O port 0x%x is not free.\n",addrports[i]);

			return -EIO;
		}

		cmos_devp->bank_number = i;

		cdev_init(&cmos_devp->cdev,&cmos_fops);
		cmos_devp->cdev.owner = THIS_MODULE;

		if(cdev_add(&cmos_devp->cdev,(dev + i),1))
		{
			printk("Bad cdev\n");

			return 1;
		}

		device_create(cmos_class,NULL,(dev + i),NULL,"cmos%d",i);
	}

	printk("CMOS Driver Initialized.\n");

	return 0;
}

void cmos_cleanup(void)
{
	int i;
	
	dev_t  devno = MKDEV(cmos_major,cmos_minor);
	
	cdev_del(&cmos_devp->cdev);
	
	unregister_chrdev_region(devno,NUM_CMOS_BANKS);
	
	for(i = 0;i < NUM_CMOS_BANKS;i++)
	{
		device_destroy(cmos_class,MKDEV(MAJOR(devno),i));
		
		release_region(addrports[i],2);
	}

	class_destroy(cmos_class);
	
	return ;
}

module_init(cmos_init);
module_exit(cmos_cleanup);

这里还每个给出open,writer,read,release的实现,仅仅是实现注册模块的部分。不过,感觉不错~







update : 2014.08.15  17:55


给出完整的cmos driver,只是这个版本还有bug...

上面的demo也是有下面列出的bug的

#bug1:装在之后是不能卸载的,除非重启电脑,而且感觉0x70-0x73口一直被占用,

#bug2:如果init的时候,不释放0x70-0x77口,会装载失败,即使释放用的4个口都不行,必须一次释放1byte,就是八个口


希望高手路过能够交流,好缓解一下渣渣我焦虑的心情啊~


update: 2014.08.15 20:28

我删除了之前贴出来有问题的demo,但保留了发现的bug部分,并给出目前bug最少(我还没发现bug)的版本,希望路过高手批评指正交流

 

void cmos_cleanup(void)
{
	int i;
	
	dev_t  devno = MKDEV(cmos_major,cmos_minor);
	
	cdev_del(&cmos_devp->cdev);
	
	unregister_chrdev_region(devno,NUM_CMOS_BANKS);</span>
	
	for(i = 0;i < NUM_CMOS_BANKS;i++)
	{
		device_destroy(cmos_class,MKDEV(MAJOR(devno),i));
		
		release_region(addrports[i],2);
	}

        class_destroy(cmos_class);</span>
	
	return ;
}


              我是看着ELDD的demo照着写的,这里其是有问题的!unregister_chrdev_region不能发生在class_destory之前的,否则会出现#bug1


#bug3,之前的代码设备名和文件名是不一至的,这倒置/dev目录下面找不到设备!

把文件名和设备名保持一致即可消除#bug3



关于CMOS-PC芯片储存数据地址相关信息:

             在CMOS内存中,0-0DH为实时钟的有关信息,0E-&127;3FH包含计算机的硬件配置信息,如常规内存的大小、扩展内存的大小、&127;软盘的类型、固定盘的类型及其物理参数、显示器的类型等,这些参数与计算机能否正常工作具有密切的关系,另外还有计算机的开机口令和其它辅助设置信息。表1列出了&127;CMOS内存各字节的用途。 


地 址 功能 说明 
0,1    秒,秒报警  
2,3    分,分报警  
4,5    时,时报警  
6      星期几  
7,8,9 日,月,年  
A 状态寄存器A  
B 状态寄存器B  
C 状态寄存器C  
D 状态寄存器D 0=电池失效,80=电池有效 
E 诊断状态  
F 关机状态 由上电诊断定义 
10 软驱 高4位为A驱,低4位为B驱,0=无, 1=360KB, 2=1.2KB, 4=1.44KB, 6=720KB 
11 保留  
12 固定盘 高4位为C驱,低4位为D驱,0=无,F=用户定义盘, 其它为系统定义盘 
13 保留  
14 设备状态 标志驱动器数、显示器类型、有无数学处理器等 
15-16 内存 以KB计的常规内存数,100H=256KB,200H=512KB, 280H=640KB 
17-18 扩展内存 以KB计的扩展内存数,200H=512KB,400H=1024KB等 




2014.08.16 01:35 release version:

/************************************************************
code writer : EOF
code date : 2014.08.16
code file : cmos.c
e-mail:	jasonleaster@gmail.com

code purpose:
	This code is a demo for how to build a CMOS-driver
step by step.

	If you find something wrong with my code, please
touch me by e-mail. Thank you all the time.

************************************************************/
#include <linux/module.h>
#include <linux/moduleparam.h>

#include <linux/fs.h>
#include <linux/init.h> 
#include <linux/cdev.h>  
#include <linux/slab.h> /* kmalloc() */
#include <linux/kernel.h> /* printk */
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/ioport.h>

#include <asm/uaccess.h>

/*
** We allocate the device number dynamically
*/
int cmos_major = 0;
int cmos_minor = 0;

module_param(cmos_major,int,S_IRUGO);
module_param(cmos_minor,int,S_IRUGO);

struct class	*cmos_class;	/* Tie with the device model */

#define NUM_CMOS_BANKS	2	
#define CMOS_BANK_SIZE	(0xFF*8)
#define DEVICE_NAME	"cmos"

#define CMOS_BANK0_INDEX_PORT	0x70
#define CMOS_BANK0_DATA_PORT	0x71
#define CMOS_BANK1_INDEX_PORT	0x72	//At this moment , I still don't know what was stored in port 0x72 and 0x73
#define CMOS_BANK1_DATA_PORT	0x73

unsigned char addrports[NUM_CMOS_BANKS] = {CMOS_BANK0_INDEX_PORT,CMOS_BANK1_INDEX_PORT};
unsigned char dataports[NUM_CMOS_BANKS] = {CMOS_BANK0_DATA_PORT,CMOS_BANK1_DATA_PORT};

MODULE_AUTHOR("Jason Leaster");
MODULE_LICENSE("Dual BSD/GPL");

unsigned char port_data_in(unsigned char offset,int bank)
{
	unsigned char data;
	
	if(unlikely(bank >= NUM_CMOS_BANKS))
	{
		printk("Unknow CMOS Bank\n");
		return 0;
	}
	else
	{
		outb(offset,addrports[bank]);
		data = inb(dataports[bank]);
	}

	return data;
}

void port_data_out(unsigned char offset,unsigned char data,int bank)
{
	if(unlikely(bank >= NUM_CMOS_BANKS))
	{
		printk("Unknow CMOS BANK\n");
		return ;
	}
	else
	{
		outb(offset,addrports[bank]);
		outb(data,dataports[bank]);
	}

	return ;
}

struct cmos_dev
{
	unsigned short current_pointer; /*Current point within the bank*/
	
	unsigned int size;	/*size of the bank*/
	int bank_number;	/*Size of bank*/
	struct cdev cdev;
	char name[10];		/*Name of I/O regeion*/
	
	/* ... */
	
}*cmos_devp;


int cmos_open(struct inode *inode,struct file* file)
{
	struct cmos_dev* cmos_devp;
	
	cmos_devp = container_of(inode->i_cdev,struct cmos_dev,cdev);
	
	file->private_data = cmos_devp;
	
	cmos_devp->size = CMOS_BANK_SIZE;
	
	/* Initialize pointer -- current_pointer */
	cmos_devp->current_pointer = 0;

	return 0;
}

int cmos_release(struct inode* inode,struct file* file)
{
	struct cmos_dev *cmos_devp = file->private_data;

	cmos_devp->current_pointer = 0;

	return 0;
}

ssize_t cmos_read(struct file *file,char* buf,size_t count,loff_t *ppos)
{
	struct cmos_dev *cmos_devp = file->private_data;

	char data[CMOS_BANK_SIZE];
	unsigned char mask;
	
	int xferred = 0,i =0,l,zero_out;

	/*
	** if we run 'read' first time, 'start_byte' must be 0 
	*/
	int start_byte = cmos_devp->current_pointer/8;
	int start_bit = cmos_devp->current_pointer%8;

	if(cmos_devp->current_pointer >= cmos_devp->size)
	{
		return 0;
	}

	/* 
	** 	If 'count' is bigger than the max size of the space left,
	** you can't read data beyond 'cmos_devp->size', so assign the 
	** count by value of the space left.
	*/

	if(cmos_devp->current_pointer + count > cmos_devp->size)
	{
		count = cmos_devp->size - cmos_devp->current_pointer;
	}

	while( xferred < count)
	{
		data[i] = port_data_in(start_byte,cmos_devp->bank_number) >> start_bit;

		xferred += (8-start_bit);

		if((start_bit) && (count + start_bit > 8))
		{
			printk("unalign\n");

			data[i] |= (port_data_in(start_byte+1,cmos_devp->bank_number) << (8-start_bit));
			xferred += start_bit;
		}
	
		printk("%d %X \n",i,data[i]);

		start_byte++;

		i++;
	}

	if(xferred > count)
	{
		zero_out = xferred - count;
		mask = 1 << (8-zero_out);

		for(l = 0; l < zero_out; l++)
		{
			data[i-l] &= ~mask;
			mask <<= 1;
		}

		xferred = count;
	}

	if(!xferred)
	{
		return -EIO;
	}

	if(copy_to_user(buf,(char*)data,((xferred/8)+1)) != 0)
	{
		return -EIO;
	}

	cmos_devp->current_pointer += xferred;

	return xferred;
}

ssize_t cmos_write(struct file * file,const char *buf,size_t count,loff_t *ppos)
{
	struct cmos_dev* cmos_devp = file->private_data;
	
	int xferred = 0,i = 0,l ,end_l,start_l;
	char *kbuf,tmp_kbuf;
	unsigned char tmp_data = 0,mask;

	int start_byte = cmos_devp->current_pointer/8;
	int start_bit  = cmos_devp->current_pointer%8;

	if(cmos_devp->current_pointer >= cmos_devp->size)
	{
		return 0;
	} 

	if(cmos_devp->current_pointer + count > cmos_devp->size)
	{
		count = cmos_devp->size - cmos_devp->current_pointer;
	}

	kbuf = kmalloc((count/8)+1,GFP_KERNEL);
	
	if(kbuf == NULL)
	{
		return -ENOMEM;
	}
	
	if(copy_from_user(kbuf,buf,(count/8)+1))
	{
		kfree(kbuf);
		return -EFAULT;
	}

	while(xferred < count)
	{
		tmp_data = port_data_in(start_byte,cmos_devp->bank_number);
	
		mask = 1<<start_bit;
		end_l = 8;
	
		if((count - xferred) < (8-start_bit))
		{
			end_l = (count - xferred) + start_bit;
		}

		for(l = start_bit; l < end_l;l++)
		{
			tmp_data &= ~mask;
			mask <<= 1;
		}

		tmp_kbuf = kbuf[i];
		mask = 1 << end_l;

		for(l = end_l; l < 8; l++)
		{
			tmp_kbuf &= ~mask;
			mask <<=1;
		}

		port_data_out(start_byte,tmp_data | (tmp_kbuf << start_bit),cmos_devp->bank_number);
		
		xferred += (end_l - start_bit);

		if((xferred < count) && (start_bit) && (count + start_bit > 8))
		{
			tmp_data = port_data_in(start_byte+1,cmos_devp->bank_number);
			start_l = ((start_bit + count) % 8);
			mask = l << start_l;
			for(l = 0;l < start_l;l++)
			{
				mask >>= 1;
				tmp_data &= ~mask;
			}

			port_data_out((start_byte+1),tmp_data | (kbuf[i] >> (8 - start_bit)), cmos_devp->bank_number);

			xferred += start_l;
		}

		start_byte++;
		
		i++;
	}

	if(!xferred)
	{
		return -EIO;
	}

	cmos_devp->current_pointer += xferred;

	return xferred;
}



static loff_t cmos_llseek(struct file* file,loff_t offset,int orig)
{
	struct cmos_dev * cmos_devp = file->private_data;

	switch(orig)
	{
		case 0:
			if(offset >= cmos_devp->size)
			{
				return -EINVAL;
			}
			
			cmos_devp->current_pointer = offset;
			break;

		case 1:
			if((cmos_devp->current_pointer + offset) >= cmos_devp->size)
			{
				return -EINVAL;
			}

			cmos_devp->current_pointer = offset;
			break;

		case 2:
			return -EINVAL;

		default:
			return -EINVAL;		
	}

	return (cmos_devp->current_pointer);
}



static struct file_operations cmos_fops = 
{
	.owner	=	THIS_MODULE,
	.open	=	cmos_open,
	.release=	cmos_release,
	.read	=	cmos_read,
	.write	=	cmos_write,
	.llseek	=	cmos_llseek,

	/* wait for implementation */
//	.ioctl	=	cmos_ioctl,
};


int  cmos_init(void)
{
	int i;

	dev_t devno = 0;
	
	if(alloc_chrdev_region(&devno,cmos_minor,NUM_CMOS_BANKS,DEVICE_NAME) < 0)
	{
		printk(KERN_DEBUG "Can't regiester device\n");
		return -1;
	}

	cmos_major = MAJOR(devno);
	
	/*********I don't know what this is************/
	cmos_class = class_create(THIS_MODULE,DEVICE_NAME);
	
	release_region(0x70,0x8);

	for(i = 0;i < NUM_CMOS_BANKS;i++)
	{
		cmos_devp = kmalloc(sizeof(struct cmos_dev),GFP_KERNEL);

		if(!cmos_devp)
		{
			printk("Bad Kmalloc\n");
			return 1;
		}

		sprintf(cmos_devp->name,"cmos%d",i);
	
		/* 
		** request for two port one for address and the other for data
		*/
		if(!(request_region(addrports[i],2,cmos_devp->name)))
		{
			printk("cmos: I/O port 0x%x is not free.\n",addrports[i]);

			return -EIO;
		}

		cmos_devp->bank_number = i;

		/* 
		** initialization for character device by function cdev_init
		*/
		cdev_init(&cmos_devp->cdev,&cmos_fops);
		cmos_devp->cdev.owner = THIS_MODULE;

		if(cdev_add(&cmos_devp->cdev,(devno + i),1))
		{
			printk("Bad cdev\n");

			return 1;
		}

		device_create(cmos_class,NULL,(devno + i),NULL,"cmos%d",i);

	}

	printk("CMOS Driver Initialized.\n");

	return 0;
}

void cmos_cleanup(void)
{
	int i;
	
	dev_t  devno = MKDEV(cmos_major,cmos_minor);
	
	cdev_del(&cmos_devp->cdev);
	
	for(i = 0;i < NUM_CMOS_BANKS;i++)
	{
		device_destroy(cmos_class,MKDEV(MAJOR(devno),i));
		
		release_region(addrports[i],2);
	}

	class_destroy(cmos_class);

	unregister_chrdev_region(devno,NUM_CMOS_BANKS);
	
	return ;
}

module_init(cmos_init);
module_exit(cmos_cleanup);


测试程序:(update 2014.08.16 17:14,谢谢@浪陨 帮忙找出了测试demo里面的bug)

/*********************************************************************
code writer : EOF
code date : 2014.08.16
code file : cmos_test_user_space.c
e-mail	  : jasonleaster@gmail.com

code purpose:
	This is a demo for user how to use CMOS device driver.
Unfortunately, there are some bugs I can't fix it up.

#BUG1--2014.08.16: mid-night

	You know that data store in CMOS register as BCD-code.If you want
to represent it as deciminal, we could transform two-bits BCD-code into
deciminal number by this way:

	Deciminal number = ((BCD-code&0xF0)>>4)*10+(BCD-code)&0x0F;

But there is something strange, it does work in 'second' which in my
code is cmos[0].

	If you have someidea to fix it up, please touch me. Thank you.


#BUG2--2014.08.16: mid-night
	
	The day value is smaller than the real time by one day.
Eg:
	Today is 08.16, but it print out 'day:15'.God know it...


#BUG1 fixed in 2014.08.16 afternoon by @lang_yun. 

	I have to say thanks to him.

	Hey guys, never forget the () around 'cmos[0]&0xF0' ...

Otherwise, you will be puzzle..

*********************************************************************/
#include <stdio.h>
#include <fcntl.h>

#define BUFSIZE 100
#define CMOS_TO_BE_READ 80

int main()
{
	int fd = 0;
	int counter = 0;
	unsigned char cmos[CMOS_TO_BE_READ];
	unsigned char buf[BUFSIZE];

	if((fd = open("/dev/cmos0",O_RDONLY)) < 0)
	{
		printf("fopen failed!\n");
		return 0;
	}

	if(read(fd,cmos,CMOS_TO_BE_READ) != CMOS_TO_BE_READ)
	{
		printf("read error\n");
		return 0;
	}

	counter += sprintf(buf+counter,"Time now: ");
	counter += sprintf(buf+counter,"Year: 20%d ",((cmos[9]&0xF0)>>4)*10 + (cmos[9]&0x0F));
	counter += sprintf(buf+counter,"month: %d ",((cmos[8]&0xF0)>>4)*10 + (cmos[8]&0x0F));
	counter += sprintf(buf+counter,"day: %d ",((cmos[7]&0xF0)>>4)*10 + (cmos[7]&0x0F));
	counter += sprintf(buf+counter,"hour: %d ",((cmos[4]&0xF0)>>4)*10 + (cmos[4]&0x0F));
	counter += sprintf(buf+counter,"minute: %d ",((cmos[2]&0xF0)>>4)*10 + (cmos[2]&0x0F));
	counter += sprintf(buf+counter,"second: %d \n",((cmos[0]&0xF0)>>4)*10 + (cmos[0]&0x0F));
		
	printf("%s",buf);

	close(fd);

	return 0;
}




运行结果:

















平凡着的,在路上的




  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: CMOS模拟集成电路设计学习笔记 CMOS模拟集成电路设计学习是电子工程领域中的重要一环。CMOS(互补金属氧化物半导体)技术在现代集成电路设计中起着至关重要的作用。在学习CMOS模拟集成电路设计过程中,我对以下几个方面有所收获。 首先,电路的基本理论知识是学习CMOS模拟集成电路设计的基础。了解电路设计中的电压、电流、电阻、电容等基本概念,掌握基本的电路分析方法和技巧,对于有效地进行CMOS模拟集成电路设计非常重要。 其次,掌握CMOS技术的原理和特点。CMOS技术是使用N型和P型MOS管并排组成的电路结构,相比于其他技术,CMOS技术具有功耗低、抗干扰能力强等优势。了解CMOS技术的工作原理和特点,能够更好地应用于模拟集成电路的设计和优化过程中。 再次,学习射极耦合放大器(CAS)的设计和优化方法。CAS是模拟电路设计中常用的基本模块,具有放大增益高、抗干扰能力强等特点。通过学习CAS的设计和优化方法,能够更好地理解和应用于CMOS模拟集成电路设计中。 此外,了解电流镜、共源共排模式放大器、差分放大器、反馈电路等常见的CMOS模拟集成电路结构和设计技巧,对于深入理解CMOS模拟集成电路设计原理和方法非常有帮助。 最后,实践是学习CMOS模拟集成电路设计的重要环节。通过自己动手设计具体的电路实例,理解并解决实际问题,能够增加对理论知识的应用和理解。 总之,学习CMOS模拟集成电路设计需要掌握电路基本知识、了解CMOS技术原理和特点、学习常见的电路结构和设计技巧,并进行实践应用。通过不断学习和实践,我相信在CMOS模拟集成电路设计领域中会有更大的进步。 ### 回答2: cmos模拟集成电路设计是现代电子领域的重要研究方向之一。在学习过程中,我了解到cmos模拟集成电路设计的基本原理和方法,以及在实际应用中的一些注意事项。 首先,cmos模拟集成电路是一种使用cmos(互补金属氧化物半导体)技术制造的集成电路,其中的晶体管由n型和p型金属氧化物半导体场效应晶体管(NMOS和PMOS)组成。cmos模拟集成电路设计主要涉及到电流源、放大器、运算放大器、滤波器等模块的设计。 在设计过程中,要考虑电路的性能指标,如增益、带宽、噪声等。同时,为了提高电路的稳定性和可靠性,需要注意电路中的电源抑制、温度补偿、布线规划等方面的问题。 另外,cmos模拟集成电路设计还需要掌握一些基本的设计工具和方法。如Spice仿真工具的使用,可以通过仿真验证设计的正确性和性能指标。还有一些常用的设计技巧,如工作在互补模式、差分放大器、共模反馈电路等,可以有效提高电路的性能。 在实际应用中,cmos模拟集成电路设计广泛应用于各个领域。例如,用于通信系统中的放大器、滤波器等电路设计,用于传感器中的信号处理电路设计等。因此,掌握cmos模拟集成电路设计的知识和技能对于从事电子工程的相关人员来说是非常重要的。 总之,cmos模拟集成电路设计学习笔记包括了基本原理和方法,设计工具和技巧,以及实际应用等方面的内容。通过学习和掌握这些知识和技能,可以提高我们在cmos模拟集成电路设计方面的能力和水平。 ### 回答3: CMOS模拟集成电路设计学习笔记是我在学习过程中记录的一本笔记,总结了我对CMOS模拟集成电路设计的理解和经验。 首先,CMOS模拟集成电路是一种重要的集成电路设计技术,它利用CMOS工艺制造出的器件来实现各种模拟电路功能。学习CMOS模拟集成电路设计,首先需要了解CMOS工艺的基本原理和特点。CMOS工艺是一种使用N型细长沟道和P型细长沟道场效应管组成的半导体工艺,它具有电压驱动强、功耗低、噪声小等优点。此外,还需要学习CMOS工艺的制造工艺流程和工艺参数的选择。 在设计CMOS模拟集成电路时,首先需要进行电路的建模与分析。我学习了基本的电路理论与分析方法,如放大电路、逻辑电路、反馈电路等,并学会了使用理想运放进行电路近似分析。此外,还学习CMOS器件的模型和特性,如MOSFET的输出特性曲线、小信号模型等。通过电路建模与分析,可以更好地理解电路的工作原理和设计要素。 然后,学习CMOS模拟电路的常见设计技术和方法。其中,包括源随器的设计与优化、偏置电路设计、放大电路设计、运算放大器设计等。在设计过程中,我学会了使用EDA工具进行电路仿真和验证,以及对电路进行性能指标的评估。通过反复实践和调试,我逐渐掌握了设计方法和技巧。 最后,我还学习了一些高级的CMOS模拟集成电路设计技术,如电压参考电路设计、数据转换电路设计、低功耗设计等。这些技术使得我能够设计更加复杂和高性能的CMOS模拟集成电路,提高了我的设计能力和水平。 通过CMOS模拟集成电路设计学习笔记的记录和总结,我不仅巩固了自己的知识和理解,还积累了更多的设计经验。这本笔记对于我今后的工作和学习都具有重要的参考价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值