【S3C2440 Linux 按键驱动】-【鹏哥教学】

合集下载

SPI驱动程序(S3C2440)

SPI驱动程序(S3C2440)

2410_SPI接口与linux驱动以下先从下到上的进行分析:driver/spi下有两个底层相关的spi驱动程序:spi_s3c24xx.c和spi_s3c24xx_gpio.c其中spi_s3c24xx.c是基于s3c24xx下相应的spi接口的驱动程序,spi_s3c24xx_gpio.c允许用户指定3个gpio口接口,模拟标准的spi总线。

s3c2410自带了两个spi接口(spi0和spi1),在此我只研究基于s3c2410下spi接口的驱动程序spi_s3c24xx.c。

首先从spi驱动的检测函数进行分析:static int s3c24xx_spi_probe(struct platform_device *pdev){struct s3c24xx_spi *hw;struct spi_master *master;struct spi_board_info *bi;struct resource *res;int err = 0;int i;master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); if (master == NULL) {dev_err(&pdev->dev, "No memory for spi_master\n");err = -ENOMEM;goto err_nomem;}hw = spi_master_get_devdata(master);memset(hw, 0, sizeof(struct s3c24xx_spi));hw->master = spi_master_get(master);hw->pdata = pdev->dev.platform_data;hw->dev = &pdev->dev;if (hw->pdata == NULL) {dev_err(&pdev->dev, "No platform data supplied\n");err = -ENOENT;goto err_no_pdata;}platform_set_drvdata(pdev, hw);//dev_set_drvdata(&pdev->dev, hw) init_completion(&hw->done);hw->bitbang.master = hw->master;hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;hw->bitbang.chipselect = s3c24xx_spi_chipsel;hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;hw->bitbang.master->setup = s3c24xx_spi_setup;dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL) {dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");err = -ENOENT;goto err_no_iores;}hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1, pdev->name);if (hw->ioarea == NULL) {dev_err(&pdev->dev, "Cannot reserve region\n");err = -ENXIO;goto err_no_iores;}hw->regs = ioremap(res->start, (res->end - res->start)+1);if (hw->regs == NULL) {dev_err(&pdev->dev, "Cannot map IO\n");err = -ENXIO;goto err_no_iomap;}hw->irq = platform_get_irq(pdev, 0);if (hw->irq < 0) {dev_err(&pdev->dev, "No IRQ specified\n");err = -ENOENT;goto err_no_irq;}err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);if (err) {dev_err(&pdev->dev, "Cannot claim IRQ\n");goto err_no_irq;}hw->clk = clk_get(&pdev->dev, "spi");if (IS_ERR(hw->clk)) {dev_err(&pdev->dev, "No clock for device\n");err = PTR_ERR(hw->clk);goto err_no_clk;}clk_enable(hw->clk);writeb(0xff, hw->regs + S3C2410_SPPRE);writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);s3c2410_gpio_setpin(S3C2410_GPE13, 0);s3c2410_gpio_setpin(S3C2410_GPE12, 0);s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0); s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0); s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);if (!hw->pdata->set_cs) {s3c2410_gpio_setpin(hw->pdata->pin_cs, 1);s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT); }err = spi_bitbang_start(&hw->bitbang);if (err) {dev_err(&pdev->dev, "Failed to register SPI master\n");goto err_register;}dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown);bi = &hw->pdata->board_info[0];for (i = 0; i < hw->pdata->board_size; i++, bi++) {dev_info(hw->dev, "registering %s\n", bi->modalias);bi->controller_data = hw;spi_new_device(master, bi);}return 0;err_register:clk_disable(hw->clk);clk_put(hw->clk);err_no_clk:free_irq(hw->irq, hw);err_no_irq:iounmap(hw->regs);err_no_iomap:release_resource(hw->ioarea);kfree(hw->ioarea);err_no_iores:err_no_pdata:spi_master_put(hw->master);;err_nomem:return err;}struct spi_master * __init_or_modulespi_alloc_master(struct device *dev, unsigned size) {struct spi_master *master;if (!dev)return NULL;master = kzalloc(size + sizeof *master, SLAB_KERNEL); if (!master)return NULL;class_device_initialize(&master->cdev);master->cdev.class = &spi_master_class;master->cdev.dev = get_device(dev);spi_master_set_devdata(master, &master[1]);return master;}int spi_bitbang_start(struct spi_bitbang *bitbang){int status;if (!bitbang->master || !bitbang->chipselect)return -EINVAL;INIT_WORK(&bitbang->work, bitbang_work, bitbang);spin_lock_init(&bitbang->lock);spi_new_device INIT_LIST_HEAD(&bitbang->queue);if (!bitbang->master->transfer)bitbang->master->transfer = spi_bitbang_transfer;//spi数据的传输就是通过调用这个方法来实现的if (!bitbang->txrx_bufs) {bitbang->use_dma = 0;bitbang->txrx_bufs = spi_bitbang_bufs;if (!bitbang->master->setup) {if (!bitbang->setup_transfer)bitbang->setup_transfer =spi_bitbang_setup_transfer;bitbang->master->setup = spi_bitbang_setup;bitbang->master->cleanup = spi_bitbang_cleanup;}} else if (!bitbang->master->setup)return -EINVAL;bitbang->busy = 0;bitbang->workqueue = create_singlethread_workqueue(bitbang->master->cdev.dev->bus_id);if (bitbang->workqueue == NULL) {status = -EBUSY;goto err1;}status = spi_register_master(bitbang->master);if (status < 0)goto err2;return status;err2:destroy_workqueue(bitbang->workqueue);err1:return status;}int __init_or_modulespi_register_master(struct spi_master *master){static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1);struct device *dev = master->cdev.dev;int status = -ENODEV;int dynamic = 0;if (!dev)return -ENODEV;if (master->bus_num < 0) {master->bus_num = atomic_dec_return(&dyn_bus_id); dynamic = 1;}snprintf(master->cdev.class_id, sizeof master->cdev.class_id, "spi%u", master->bus_num);status = class_device_add(&master->cdev);//注册设备if (status < 0)goto done;dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, dynamic ? " (dynamic)" : "");scan_boardinfo(master);status = 0;done:return status;}static void __init_or_modulescan_boardinfo(struct spi_master *master){struct boardinfo *bi;struct device *dev = master->cdev.dev;down(&board_lock);list_for_each_entry(bi, &board_list, list) {struct spi_board_info *chip = bi->board_info;unsigned n;for (n = bi->n_board_info; n > 0; n--, chip++) {if (chip->bus_num != master->bus_num)continue;if (chip->chip_select >= master->num_chipselect&& master->num_chipselect) {dev_dbg(dev, "cs%d > max %d\n",chip->chip_select,master->num_chipselect);continue;}(void) spi_new_device(master, chip);}}up(&board_lock);}int __initspi_register_board_info(struct spi_board_info const *info, unsigned n)struct boardinfo *bi;bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);if (!bi)return -ENOMEM;bi->n_board_info = n;memcpy(bi->board_info, info, n * sizeof *info);down(&board_lock);list_add_tail(&bi->list, &board_list);up(&board_lock);return 0;}struct spi_device *__init_or_modulespi_new_device(struct spi_master *master, struct spi_board_info *chip){struct spi_device *proxy;//这个结构很重要,以后就是通过这个结构来操作实际的spi设备的struct device *dev = master->cdev.dev;int status;if (!spi_master_get(master))return NULL;proxy = kzalloc(sizeof *proxy, GFP_KERNEL);if (!proxy) {dev_err(dev, "can't alloc dev for cs%d\n",chip->chip_select);goto fail;}proxy->master = master;proxy->chip_select = chip->chip_select;proxy->max_speed_hz = chip->max_speed_hz;proxy->mode = chip->mode;proxy->irq = chip->irq;proxy->modalias = chip->modalias;snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,"%s.%u", master->cdev.class_id,chip->chip_select);proxy->dev.parent = dev;proxy->dev.bus = &spi_bus_type;proxy->dev.platform_data = (void *) chip->platform_data; proxy->controller_data = chip->controller_data;proxy->controller_state = NULL;proxy->dev.release = spidev_release;status = master->setup(proxy);if (status < 0) {dev_dbg(dev, "can't %s %s, status %d\n","setup", proxy->dev.bus_id, status);goto fail;}status = device_register(&proxy->dev);//真正注册原始设备if (status < 0) {dev_dbg(dev, "can't %s %s, status %d\n","add", proxy->dev.bus_id, status);goto fail;}dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); return proxy;fail:spi_master_put(master);kfree(proxy);return NULL;}static int s3c24xx_spi_setup(struct spi_device *spi){int ret;if (!spi->bits_per_word)spi->bits_per_word = 8;if ((spi->mode & SPI_LSB_FIRST) != 0)return -EINVAL;ret = s3c24xx_spi_setupxfer(spi, NULL);if (ret < 0) {dev_err(&spi->dev, "setupxfer returned %d\n", ret);return ret;}dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",__FUNCTION__, spi->mode, spi->bits_per_word,spi->max_speed_hz);return 0;}static int s3c24xx_spi_setupxfer(struct spi_device *spi,struct spi_transfer *t){struct s3c24xx_spi *hw = to_hw(spi);unsigned int bpw;unsigned int hz;unsigned int div;bpw = t ? t->bits_per_word : spi->bits_per_word;hz = t ? t->speed_hz : spi->max_speed_hz;if (bpw != 8) {dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);return -EINVAL;}div = clk_get_rate(hw->clk) / hz;div = (div / 2) - 1;//求出预分频值if (div < 0)div = 1;if (div > 255)div = 255;dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", div, hz);writeb(div, hw->regs + S3C2410_SPPRE);//设置预分频值spin_lock(&hw->bitbang.lock);if (!hw->bitbang.busy) {hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);//修改时钟,先禁用spi}spin_unlock(&hw->bitbang.lock);return 0;}static void s3c24xx_spi_chipsel(struct spi_device *spi, int value){struct s3c24xx_spi *hw = to_hw(spi);unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;unsigned int spcon;switch (value) {case BITBANG_CS_INACTIVE:if (hw->pdata->set_cs)hw->pdata->set_cs(hw->pdata, value, cspol);elses3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1);break;case BITBANG_CS_ACTIVE:spcon = readb(hw->regs + S3C2410_SPCON);if (spi->mode & SPI_CPHA)spcon |= S3C2410_SPCON_CPHA_FMTB;elsespcon &= ~S3C2410_SPCON_CPHA_FMTB;if (spi->mode & SPI_CPOL)spcon |= S3C2410_SPCON_CPOL_HIGH;elsespcon &= ~S3C2410_SPCON_CPOL_HIGH;spcon |= S3C2410_SPCON_ENSCK;writeb(spcon, hw->regs + S3C2410_SPCON);if (hw->pdata->set_cs)hw->pdata->set_cs(hw->pdata, value, cspol);elses3c2410_gpio_setpin(hw->pdata->pin_cs, cspol);break;}}好了,至此spi主控制器(驱动)和板上spi设备注册完毕,以后要使用spi来传输数据的话,只要先获得spi设备交道了(就好像你要操作一个文件,先要获取文件句柄一样,明白吧^_^)原文地址/luofuchong/archive/2007/09/24/33942.html~~~~~~~~~~~~~~~~~~``任何SPI都有4种模式2008-11-06 22:17void McBSPObj::McBSP0Init(void)//McBSP从设备SPI硬件配置{//PCR设置过程(FSM=0,CLKM=0)McBSP0->SPSA = PCR;McBSP1->SPSD = (0 << PCR_XIOEN) //发送非通用I/O模式位| (0 << PCR_RIOEN) //接收非通用I/O模式位| (0 << PCR_FSXM) //外部发送帧同步脉冲(外部片选)| (0 << PCR_FSRM) //外部接收帧同步脉冲(外部片选)| (0 << PCR_CLKXM) //外部发送时钟(外部时钟源)| (0 << PCR_CLKRM) //外部接收时钟(外部时钟源)#if SPIMODE == 0//SPI设置过程00(0--FS高电平有效,0--CLK上升沿收发数据)| (0 << PCR_FSXP) //发送帧同步脉冲极性(高电平有效)| (0 << PCR_FSRP) //接收帧同步脉冲极性(高电平有效)| (0 << PCR_CLKXP) //发送时钟极性(上升沿发送数据)| (0 << PCR_CLKRP);//接收时钟极性(上升沿接收数据)#endif#if SPIMODE == 1//SPI设置过程01(0--FS高电平有效,1--CLK下降沿收发数据)| (0 << PCR_FSXP) //发送帧同步脉冲极性(高电平有效)| (0 << PCR_FSRP) //接收帧同步脉冲极性(高电平有效)| (1 << PCR_CLKXP) //发送时钟极性(下降沿发送数据)| (1 << PCR_CLKRP);//接收时钟极性(下降沿接收数据)#endif#if SPIMODE == 2//SPI设置过程10(1--FS低电平有效,0--CLK上升沿收发数据)| (1 << PCR_FSXP) //发送帧同步脉冲极性(低电平有效)| (1 << PCR_FSRP) //接收帧同步脉冲极性(低电平有效)| (0 << PCR_CLKXP) //发送时钟极性(上升沿发送数据)| (0 << PCR_CLKRP);//接收时钟极性(上升沿接收数据)#endif#if SPIMODE == 3//SPI设置过程11(1--FS低电平有效,1--CLK下降沿收发数据)| (1 << PCR_FSXP) //发送帧同步脉冲极性(低电平有效)| (1 << PCR_FSRP) //接收帧同步脉冲极性(低电平有效)| (1 << PCR_CLKXP) //发送时钟极性(下降沿发送数据)| (1 << PCR_CLKRP);//接收时钟极性(下降沿接收数据)#endif//MCR1设置过程(RMCM=0)McBSP0->SPSA = MCR1;//McBSP0->SPSD = (0 << MCR1_RMCM) //允许接收多通道选择(0)| (0x00 << MCR1_RPBBLK)| (0x00 << MCR1_RPABLK)| (0x00 << MCR1_RCBLK);//MCR2设置过程(XMCM=0)McBSP0->SPSA = MCR2;//McBSP0->SPSD = (0x00 << MCR2_XMCM) //允许发送多通道选择(00b) | (0x00 << MCR2_XPBBLK)| (0x00 << MCR2_XPABLK)| (0x00 << MCR2_XCBLK);//RCERA设置过程McBSP0->SPSA = RCERA;//McBSP0->SPSD = 0;//RCERB设置过程McBSP0->SPSA = RCERB;//McBSP0->SPSD = 0;//XCERA设置过程McBSP0->SPSA = XCERA;//McBSP0->SPSD = 0;//XCERB设置过程McBSP0->SPSA = XCERB;//McBSP0->SPSD = 0;//XCR1设置过程McBSP0->SPSA = XCR1;//McBSP0->SPSD = (0x00 << XCR1_XFRLEN1) //每帧1个字(每帧中断的次数1!!!) // | (0x02 << XCR1_XWDLEN1);//每字16位长(每次中断的字节数2!!!)| (0x00 << XCR1_XWDLEN1);//每字8位长(每次中断的字节数2!!!)//XCR2设置过程McBSP0->SPSA = XCR2;McBSP0->SPSD = (0 << XCR2_XPHASE) //单相帧(其他设置都为0)| (0x00 << XCR2_XCOMPAND)//发送数据从最高位(MSB)开始| (0x00 << XCR2_XDATDLY);//同步后延迟0位数据//RCR1设置过程McBSP0->SPSA = RCR1;McBSP0->SPSD = (0x00 << RCR1_RFRLEN1) //每帧1个字(每帧中断的次数1!!!) // | (0x02 << RCR1_RWDLEN1);//每字16位长(每次中断的字节数2!!!)| (0x00 << RCR1_RWDLEN1);//每字8位长(每次中断的字节数2!!!)//RCR2设置过程McBSP0->SPSA = RCR2;McBSP0->SPSD = (0 << RCR2_RPHASE) //单相帧(其他设置都为0)| (0x00 << RCR2_RCOMPAND)//接收数据从最高位(MSB)开始| (0x00 << RCR2_RDATDLY);//同步后延迟0位数据//SRGR1设置过程McBSP0->SPSA = SRGR1;McBSP0->SPSD = (0x00 << SRGR1_CLKGDV);//1//SRGR2设置过程McBSP0->SPSA = SRGR2;McBSP0->SPSD = (0 << SRGR2_FSGM)| (1 << SRGR2_CLKSM)//由CPU时钟产生的采样率时钟1| (0 << SRGR2_CLKSP)//0| (1 << SRGR2_GSYNC)//| (0x0f << SRGR2_FPER);//0x0f//SPCR1设置过程(CLKSTP=1Xb,RINTM=00b)McBSP0->SPSA = SPCR1;McBSP0->SPSD = (0x00 << SPCR1_RINTM) //接收中断模式00(每帧接收1次中? | (0 << SPCR1_DLB) //禁止回送| (1 << SPCR1_DXENA) //DX使能| (0x00 << SPCR1_RJUST) //接收符号不扩展| (0x02 << SPCR1_CLKSTP);//SPI模式时钟开始于上升沿(无延迟)//SPCR2设置过程(XINTM=02b)McBSP0->SPSA = SPCR2;McBSP0->SPSD = (0x02 << SPCR2_XINTM)//发送中断模式02| (1 << SPCR2_XEMPTY) //发送移位寄存器空| (1 << SPCR2_XRDY); //发送准备好//SPCR1复位过程McBSP0->SPSA = SPCR1;McBSP0->SPSD|= (1 << SPCR1_RRST);//接收器复位//SPCR2复位过程McBSP0->SPSA = SPCR2;McBSP0->SPSD|= (1 << SPCR2_XRST)//发送器复位| (1 << SPCR2_GRST)//采样率发生器复位| (1 << SPCR2_FRST);//帧同步发生器复位//清除允许BXINT0中断过程// SREG->IFR = (1 << IFR_BXINT0);//清除BXINT0中断标志// SREG->IMR |= (1 << IMR_BXINT0);//允许BXINT0中断//清除允许BRINT0中断过程SREG->IFR = (1 << IFR_BRINT0);//清除BRINT0中断标志SREG->IMR |= (1 << IMR_BRINT0);//允许BRINT0中断}void McBSPObj::McBSP1Init(void)//GPIO配置{McBSP1->SPSA = SPCR1;McBSP1->SPSD = 0;McBSP1->SPSA = SPCR2;McBSP1->SPSD = 0;McBSP1->SPSA = PCR;//设置收发。

linux在TQ2440上移植6--完善串口驱动

linux在TQ2440上移植6--完善串口驱动

1、s3c2440有3个串口,其中串口2在linux-2.6.35.3里作了红外模式,我们要把它改为普通的串口用。

2、在smdk2440平台第100行修改线控制寄存器 ULCONnvi arch/arm/mach-s3c2440/mach-smdk2440.c/* IR port */[2] = {.hwport = 2,.flags = 0,.ucon = 0x3c5,.ulcon = 0x03,.ufcon = 0x51,}3、增加UART2 收发引脚功能vi drivers/serial/samsung.cdbg("s3c24xx_serial_startup ok\n");/* the port reset code should have done the correct* register setup for the port controls */if (port->line == 2){s3c2410_gpio_cfgpin(S3C2410_GPH6, S3C2410_GPH6_TXD2);s3c2410_gpio_pullup(S3C2410_GPH6, 1);s3c2410_gpio_cfgpin(S3C2410_GPH7, S3C2410_GPH7_RXD2); s3c2410_gpio_pullup(S3C2410_GPH7, 1);}a. 上面的函数s3c2410...cfg , pull都定义在arch/arm/mach-s3c2410/include/mach/gpio-fns.h中所以要在drivers/serial/samsung.c 中添加头文件 #include<mach/gpio-fns.h>b. S3C2410_GPH6, 7 也需要自己定义在arch/arm/mach-s3c2410/include/mach/gpio-nrs.h中#define S3C2410_GPH6 S3C2410_GPH(6)#define S3C2410_GPH7 S3C2410_GPH(7)同样也要在drivers/serial/samsung.c 中添加头文件 #include<mach/gpio-nrs.h>c. S3C2410_GPH6_TXD2S3C2410_GPH7_RXD2定义在arch/arm/mach-s3c2410/include/mach/regs-gpio.h同样也要在drivers/serial/samsung.c 中添加头文件 #include<mach/regs-gpio.h>4、下面还有一个重要的数据结构第889行static struct uart_driver s3c24xx_uart_drv = {.owner = THIS_MODULE,.dev_name = "s3c2410_serial", //这个是串口设备的名称,必须和文件系统的inittab里控制台的名称相对应.nr = CONFIG_SERIAL_SAMSUNG_UARTS,.cons = S3C24XX_SERIAL_CONSOLE,.driver_name = S3C24XX_SERIAL_NAME,.major = S3C24XX_SERIAL_MAJOR,.minor = S3C24XX_SERIAL_MINOR,};5、make menuconfigDdvices Drivers --->Character devices --->Serial Drivers --->1、s3c2440有3个串口,其中串口2在linux-2.6.35.3里作了红外模式,我们要把它改为普通的串口用。

精品课件-基于S3C2440的嵌入式Linux开发-第5章

精品课件-基于S3C2440的嵌入式Linux开发-第5章

默 认值 0x0
未 定义 0x0 —
第5章 S3C2440 I/O接口Linux驱动及应用实例
GPCCON GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8 GPC7 GPC6 GPC5 GPC4 GPC3 GPC2 GPC1 GPC0
表5-9 端口C控制寄存器位定义
第5章 S3C2440 I/O接口Linux驱动及应用实例
表5-7 端口B上拉寄存器位定义
GPBUP GPB[10:0]
位 [10:0]
描述
0=允许端口 B 相应引脚的上拉功能 1=禁止上拉功能
第5章 S3C2440 I/O接口Linux驱动及应用实例
3.端口C控制寄存器(GPCCON,GPCDAT,GPCUP) 端口C控制寄存器各位定义如表5-8~表5-11所示。 4.端口D控制寄存器(GPDCON,GPDDAT,GPDUP) 端口D控制寄存器各位定义如表5-12~表5-15所示。
第5章 S3C2440 I/O接口Linux驱动及应用实例
5.1 GPIO接口基础 5.2 S3C2440 GPIO接口硬件及寄存器 5.3 S3C2440 GPIO驱动及LED应用程序分析 5.4 S3C2440 LED应用程序设计例程
第5章 S3C2440 I/O接口Linux驱动及应用实例
5.1 GPIO接口基础
其中,volatile关键字是嵌入式系统开发的一个重要特点。 上述表达式拆开分析,(volatile unsigned long *)0x48000000是把0x48000000强制转换成volatile unsigned long类型的指针,暂记为p,那么就是#define A *p,即A为p 指针指向位置的内容。这里通过内存寻址访问到寄存器A,可 以进行读/写操作。

基于S3C2440和Linux的嵌入式驱动程序设计的开题报告

基于S3C2440和Linux的嵌入式驱动程序设计的开题报告

基于S3C2440和Linux的嵌入式驱动程序设计的开题报告一、题目意义S3C2440是指三星公司开发的一款嵌入式微处理器,其性能稳定、功耗低、体积小巧,因此广泛应用于各种嵌入式设备中。

而Linux是目前应用最广泛的开源操作系统之一,其优秀的稳定性和可扩展性,使其成为嵌入式设备的首选操作系统之一。

本课题旨在基于S3C2440和Linux,设计开发一种嵌入式驱动程序,以满足嵌入式设备在使用过程中对于驱动程序的需求。

二、研究内容和目标本课题研究内容主要包括以下方面:1.设计S3C2440与Linux的嵌入式开发环境,包括编译器、调试器和开发板等。

2.研究嵌入式驱动程序的设计原理,包括驱动程序框架、驱动程序接口和驱动程序逻辑等。

3.设计并实现S3C2440和Linux下的嵌入式驱动程序,包括对设备的初始化、操作、控制和数据传输等。

4.测试驱动程序的正确性和稳定性,以及对系统的性能进行优化。

本课题的研究目标是:1.设计开发一种基于S3C2440和Linux的嵌入式驱动程序,使其可以良好地与各种设备进行交互,完成设备的配置和数据传输等相关操作。

2.使得驱动程序的设计和实现更具有可重用性和可扩展性,以适应不同的应用需求。

3.保证驱动程序的稳定性和正确性,通过对系统的性能进行优化,提高系统的响应速度和效率。

三、研究方法和技术路线本课题主要采用以下研究方法和技术路线:1.文献调研法:通过查阅相关的文献,了解嵌入式驱动程序的设计原理和实现方法。

2.实验法:通过实验,测试驱动程序的性能和稳定性,并对系统进行优化。

3.程序设计法:通过程序设计,实现嵌入式驱动程序,并改进其可重用性和可扩展性。

本课题的技术路线如下:1.搭建基于S3C2440和Linux的嵌入式开发环境。

2.设计嵌入式驱动程序的框架和接口,并实现设备的初始化、操作、控制和数据传输等相关操作。

3.进行驱动程序的调试和测试,优化系统的性能和稳定性。

四、预期成果及意义本课题的预期成果包括:1.设计开发一种基于S3C2440和Linux的嵌入式驱动程序,能够满足嵌入式设备在使用过程中对于驱动程序的需求。

基于S3C2440嵌入式Linux的伺服电机控制

基于S3C2440嵌入式Linux的伺服电机控制
操作 。
t c f g 0 1 = ( 5 0 -1 ) ; / / 设 置预 分频 率为 5 0
赫 兹
t c f gl &= ̄ S3 C2 4 1 o _ TCFGI _ _ M UX 1 _ M ASK ;
1 . 1 伺 服 电机的 驱动 与控 制 直 流 伺服 电机 速度 由P WM 的 占空 比来 决定 , 占空 比越 大 电机 转 速 越 大 , 设 置
作。
2. 3主 函数
主 函 数 中循 环 检 测 有 无 按 键 按 下 , 并
2 详细设计
2 . 1 P W M 驱 动
判 断是 哪个 按 键 , 调 用i o c t l 函数 调用 各设 备
高 新 技 术
S C I E N C E &T E C H N 0 L O G Y .
墨圆
基于 ¥ 3 C2 4 4 0嵌 入 式 L i n u x的伺 服 电机控 制
刘 亚 茹 王 贵 山
( 国 防科学 技术 大学 机 电工 程 与 自动化学 院 湖南 长沙
4 1 0 0 0 3 )
c md ) ; //设 置 引脚 状态 o u t — t a b l e [ a r g ] 为 需要 设 置状态 的 引脚 ,
主 函数 主 要 完 成 的 工 作 为 检 测 判 断 按 图 1 嵌入式 L i n u x 的硬件设备驱动过程
下的按键 , 并 调用相应的i o c t l 函数 进 行 操 c md 为 状 态值 。
摘 要: 介 绍一 种基 于¥ 3 C2 4 4 0 微 处理 器 的伺服 电机控 制 方案 。 AR M微 处理 器几乎 已经 深入 到工 业控 制 、 无 线通 讯 、 网络 应 用、 消 费类 电子 产品 , 威像 和安 全 产品各个 领 域 。 本文 实现 基于¥ 3 C 2 4 4 0 的L i f l U X 的 伺服 电机 的按键 控 制 , 控 制 伺服 电机转 动方 向及速 度 , 并通 过 L ED指示 灯 . 蜂 鸣 器等表 征 伺服 电机 的工 作状 态 。 关键 词 : AR M ¥ 3 C 2 4 4 0 L i n u x 伺服 电机 中图分类 号 : T P 2 7 4 文献标识码 : A 文 章编 号 : I 6 7 2 — 3 7 9 I ( 2 o I 3 ) 1 0 ( a ) 一0 0 0 7 — 0 I

【总结】S3C2440PLL设置详解总结

【总结】S3C2440PLL设置详解总结

S3C2440 PLL设置详解CPU上电几毫秒后,晶振输出稳定,FCLK=Fin(晶振频率),CPU开始执行指令。

但实际上,FCLK可以高于Fin,为了提高系统时钟,需要用软件来启用PLL。

这就需要设置CLKDIVN,MPLLCON,UPLLCON这3个寄存器。

CLKDIVN寄存器用于设置FCLK,HCLK,PCLK三者的比例,MPLLCON用于设置主频FCLK,UPLLCON用于设置USB时钟UCLK。

S3C2440APLL源有两个,一个是MPLL,另一个是UPLL. MPLL用于CPU用外设,UPLL只用于USB.,包括CPU的FCLK,AHB总线外设的HCLK以及APB总线外设的PCLK。

S3C2440A包含两个锁相环(PLL):MPLL提供给FCLK、HCLK和PCLK,UPLL 专用于USB模块(48MHz)。

时钟控制逻辑可以不使用PLL来减慢时钟,并且可以由软件连接或断开各外设模块的时钟,以降低功耗。

S3C2440A的主时钟源由外部时钟(EXTCLK)或者外部晶振(XTIPll)提供,输入时钟源由模式控制引脚OM3和OM2控制选择,在复位信号的上升沿参考OM3和OM2的引脚将OM[3:2]的状态在内部锁定,如图1所示图1 引导启动时的时钟源选择选择不同输入时钟源时连接方式如图2所示:图2 时钟连接参考通过在片内集成的2个锁相环:MPLL和UPLL,可对输入的Fin=12MHz的晶振频率进行倍频。

S3C2440使用了三个倍频因子MDIV、PDIV和SDIV来设置倍频,通过寄存器MPLLCON和UPLLCON可分别设置各自的倍频因子。

其中MPLLCON寄存器用于设置处理器内核时钟主频FCLK,其输入输出频率间的关系为FCLK=MPLL=(2*m*Fin)/(p*2^s)其中m=(MDIV+8), p=(PDIV+2), s=SDIV。

其中UPLLCON寄存器用于产生48MHz或96MHz,提供USB时钟(UCLK),其输入输出频率间的关系为UCLK=UPLL=(m * Fin) / (p * 2^s)其中m=(MDIV+8), p=(PDIV+2), s=SDIV。

嵌入式Linux初级实验s3c2410 中

嵌入式Linux初级实验s3c2410 中

第三篇基础实验篇本篇内容Linux设备驱动概述★LED实例★按键中断实例★数码管实例★4*4键盘实例★LCD实例★触摸屏实例★本篇目标了解Linux设备驱动的相关概念及开发基础★掌握简单字符设备驱动的程序结构及设计流程★学习嵌入式Linux中断机制及其驱动程序结构★学习数码管的显示原理及其驱动程序的设计方法★熟悉键盘驱动原理,学会为自己的系统添加键盘设备驱动程序★了解移植LCD显示设备驱动及触摸屏输入设备驱动的过程★本篇实例实例一:LED驱动及测试实例★实例二:按键中断驱动及测试实例★实例三:数码管实例★实例四:4*4键盘实例★实例五:LCD驱动移植实例★实例六:触摸屏驱动移植实例★第8章Linux设备驱动概述在前一篇中,我们介绍了开发嵌入式Linux的基本过程,本章开篇在前一篇的基础上进行设备驱动程序的开发,使得目标板上的硬件资源为板上系统所用,这也是所有设备驱动的巨大贡献。

本章将带领你走进Linux设备驱动开发的世界。

本章首先介绍的是设备驱动的作用及其分类,不同驱动程序的特点等,然后介绍驱动模块的加载和卸载方式等。

8.1 设备驱动的角色任何计算机系统的运行都是系统中软硬件相辅相成的结果,没有硬件的软件是空中楼阁,而没有软件的硬件则只是一堆的电子元器件而已。

硬件是底层基础,是所有软件得以运行的平台,程序最终会实现为硬件上的逻辑电路;软件则是具体应用的实现,根据不同的业务需求而设计。

硬件一般是固定的,软件则很灵活,可以适应各种复杂多变的应用。

从某种程度上来看,计算机系统的软硬件相互成就了对方。

但是,软硬件之间同样存在着悖论,那就是软件和硬件不应该互相渗透入对方的领地。

为尽可能快速地完成设计,应用软件工程师不想也不必关心硬件,而硬件工程师也难有足够的闲暇和能力来顾及软件。

譬如,应用软件工程师在调用套接字发送和接收数据包的时候,他不必关心网卡上的中断、寄存器、存储空间、I/O端口、片选以及其他任何硬件词汇;在使用scanf()函数获取输入的时候,他不用知道底层究竟是怎样把终端设备的操作转化成程序输入的。

s3c2440触摸屏驱动(针对android版)

s3c2440触摸屏驱动(针对android版)

s3c2440触摸屏驱动(针对android版)s3c2440 触摸屏驱动(针对android版)和原来的触摸屏驱动区别不是很⼤,增加了report函数来将事件发送到应⽤层。

驱动结构:很简单的字符设备+平台设备驱动,总的结构来说,主要四个部分构成:proberemoveresumesuspend⼯作机制则是注册设备,然后发⽣ts按下事件后产⽣ts中断以及adc中断,获得按下坐标。

没有读写函数,重点就是在两个中断处理函数上。

1,平台设备架构部分分析:probe函数:流程:ts基址的重映射->获得并启动时钟->ADCCON、ADCDLY、ADCTSC的初始化->初始化input设备完善ts结构体->建⽴ts_filter_chain->申请中断->注册input设备(2.6.27后为event0不再是ts0)。

static int __init s3c2410ts_probe(struct platform_device *pdev){int rc;struct s3c2410_ts_mach_info *info;struct input_dev *input_dev;int ret = 0;dev_info(&pdev->dev,"Starting\n");info =(struct s3c2410_ts_mach_info*)pdev->dev.platform_data;//获得平台设备数据if(!info){dev_err(&pdev->dev,"Hm... too bad: no platform data forts\n");return-EINVAL;}#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUGprintk(DEBUG_LVL "Entering s3c2410ts_init\n");#endifadc_clock = clk_get(NULL,"adc");if(!adc_clock){dev_err(&pdev->dev,"failed to get adc clock source\n");return-ENOENT;}clk_enable(adc_clock);#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUGprintk(DEBUG_LVL "got and enabled clock\n");#endifbase_addr = ioremap(S3C2410_PA_ADC,0x20);//将PA_ADC寄存器重映射到内存上if(base_addr ==NULL){dev_err(&pdev->dev,"Failed to remap register block\n"); ret =-ENOMEM;goto bail0;}/* If we acutally are a S3C2410: Configure GPIOs */if(!strcmp(pdev->name,"s3c2410-ts"))s3c2410_ts_connect();//初始化相关gpio⼝if((info->presc & 0xff)> 0)writel(S3C2410_ADCCON_PRSCEN |S3C2410_ADCCON_PRSCVL(info->presc&0xFF),base_addr + S3C2410_ADCCON);elsewritel(0, base_addr+S3C2410_ADCCON);/* Initialise registers */if((info->delay & 0xffff)> 0)writel(info->delay & 0xffff, base_addr + S3C2410_ADCDLY);writel(WAIT4INT(0), base_addr + S3C2410_ADCTSC);/* Initialise input stuff */memset(&ts, 0,sizeof(struct s3c2410ts));input_dev = input_allocate_device();if(!input_dev){dev_err(&pdev->dev,"Unable to allocate the input device\n");ret =-ENOMEM;}//初始化input设备ts.dev = input_dev;ts.dev->evbit[0]= BIT_MASK(EV_SYN)| BIT_MASK(EV_KEY)|BIT_MASK(EV_ABS);ts.dev->keybit[BIT_WORD(BTN_TOUCH)]= BIT_MASK(BTN_TOUCH);input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);ts.dev->name = s3c2410ts_name;ts.dev->id.bustype = BUS_RS232;ts.dev->id.vendor = 0xDEAD;ts.dev->id.product = 0xBEEF;ts.dev->id.version = S3C2410TSVERSION;ts.state = TS_STATE_STANDBY;//设置ts状态为就绪ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL);//为event队列申请内存空间if(IS_ERR(ts.event_fifo)){ret =-EIO;goto bail2;}/* create the filter chain set up for the 2 coordinates we produce */ts.chain = ts_filter_chain_create(pdev, info->filter_config, 2);//针对android的,建⽴filter_chainif(IS_ERR(ts.chain))goto bail2;ts_filter_chain_clear(ts.chain);/* Get irqs */if(request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,"s3c2410_action", ts.dev)){dev_err(&pdev->dev,"Could not allocate ts IRQ_ADC !\n"); iounmap(base_addr);goto bail3;}if(request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c2410_action", ts.dev)){dev_err(&pdev->dev,"Could not allocate ts IRQ_TC !\n"); free_irq(IRQ_ADC, ts.dev);iounmap(base_addr);ret =-EIO;goto bail4;}dev_info(&pdev->dev,"Successfully loaded\n");/* All went ok, so register to the input system */rc = input_register_device(ts.dev);if(rc){ret =-EIO;goto bail5;}return 0;bail5:free_irq(IRQ_TC, ts.dev);free_irq(IRQ_ADC, ts.dev);clk_disable(adc_clock);iounmap(base_addr);disable_irq(IRQ_TC);bail4:disable_irq(IRQ_ADC);bail3:ts_filter_chain_destroy(ts.chain);kfifo_free(ts.event_fifo);bail2:input_unregister_device(ts.dev);bail1:iounmap(base_addr);bail0:return ret;}remove:就是probe的逆运算,static int s3c2410ts_remove(struct platform_device *pdev) {disable_irq(IRQ_ADC);disable_irq(IRQ_TC);free_irq(IRQ_TC,ts.dev);free_irq(IRQ_ADC,ts.dev);if(adc_clock){clk_disable(adc_clock);clk_put(adc_clock);adc_clock =NULL;}input_unregister_device(ts.dev);iounmap(base_addr);ts_filter_chain_destroy(ts.chain);kfifo_free(ts.event_fifo);return 0;}resume与suspend函数可有可⽆,完成触摸屏的激活和挂起,2,中断处理分析:三种模式转换过程:等待down中断模式->x,y连续坐标转换模式->等待up中断模式->等待down中断模式->..两个中断的发⽣:触摸屏按下,发⽣ts中断,开始ad转换,ad转换结束,发⽣adc中断。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*定义并赋值 misc 设备结构体*/ static struct miscdevice misc =
{ .minor = MISC_DYNAMIC_MINOR,//次设备号 //动态分配设备的次设备号 //(注:使用 MISC_DYNAMIC_MINOR 这个宏有一个限制,次设备号不允许超过 63。) .name = DEVICE_NAME,//驱动名字 .fops = &dev_fops,//文件操作函数结构体
/*按键结构体实际内容*/ static struct dev_description button_irqs[] = {
{IRQ_EINT8 , S3C2410_GPG(0) , S3C2410_GPG0_EINT8 , 0, "KEY0"}, {IRQ_EINT11, S3C2410_GPG(3) , S3C2410_GPG3_EINT11 , 1, "KEY1"}, {IRQ_EINT13, S3C2410_GPG(5) , S3C2410_GPG5_EINT13 , 2, "KEY2"}, {IRQ_EINT14, S3C2410_GPG(6) , S3C2410_GPG6_EINT14 , 3, "KEY3"}, {IRQ_EINT15, S3C2410_GPG(7) , S3C2410_GPG7_EINT15 , 4, "KEY4"}, {IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 5, "KEY5"}, };
/*定义设备结构体*/ //( 这里的设备指的是按键) struct dev_description {
int irq;//按键对应的中断号 int pin;//按键所对应的 GPIO 端口 int pin_setting;//按键对应的引脚描述,实际并未用到,保留 int number;//定义键值,以传递给应用层/用户态 char *name;//每个按键的名称 };
/*****************************************************************************************/ //定义结构体//
/*****************************************************************************************/
#include <linux/miscdevice.h>//与 misc 混杂设备有关
#include <linux/ioctl.h>//与 ioctl 有关 #include <linux/gpio.h>//与 gpio 有关 #include <mach/regs-gpio.h>//与 gpio 有关 #include <linux/interrupt.h>//与 interrupt 有关 #include <linux/irq.h>//与 irq 有关 #include <asm/irq.h>//与 irq 有关
//本驱动模块加载后,会自动在/dev 目录里创建该名字(My_Buttons)的设备文件。
/*定义运算*/ #define Min(num1, num2) ((num1)<(num2) ? (num1):(num2))//定义比较获取最小值的宏 Min
/*定义变量*/ static volatile char wait_flag = 0;//定义:等待标识符,并初始化为:0 (0.等待,1.不等待) static volatile int key_values[6];//定义:6 个按键值变量 /*注:按键按下时为 0,弹起时为非 0 (注意:非 0 但并不一定是 1!具体请参阅 s3c2410_gpio_getpin() 的 相关资料!!!)*/
wake_up_interruptible(&button_wait_queue);// 唤醒列入等待队列中的进程( 让其能够响应)
wait_flag = 1;//取消等待 }
//mdelay(10);//延时 10ms 去抖 }
return IRQ_RETVAL(IRQ_HANDLED);// }
/*-----------------------------//【杨鹏(AdvancyYP)@制作】//-----------------------------*/
/* 名称 :
按键
类型 : 驱动模块
处理器型号: ARM9-S3C2440
*/
/*-----------------------------//【杨鹏(AdvancyYP)@制作】//-----------------------------*/ /*定义名称*/ #define DEVICE_NAME "MY_BUTTONS"//定义设备名称为:My_Buttons
/*定义并赋值文件操作结构体*/ static struct file_operations dev_fops = {
.owner = THIS_MODULE, .open = Buttons_Open,//open()函数的接口 .release = Buttons_Close,//close()函数的接口 .read = Buttons_Read,//read()函数的接口 };
{
key_values[button_irqs->number]=s3c2410_gpio_getpin(button_irqs->pin);//获取管脚值(注:对应的 管脚值会赋给对应的数组元素)
/*注:管脚接地时获取到的值为 0,接高电平时为非 0 (注意:非 0 但并不一定是 1!具体请参阅 s3c2410_gpio_getpin() 的相关资料!!!)*/
};
/*****************************************************************************************/ //定义及初始化等待的队列//
/*****************************************************************************************/ static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); //静态方式定义及初始化等待的队列头:button_wait_queue
struct dev_description *button_irqs = (struct dev_description *)dev_id; //将 dev_id 定义为和 dev_description 相同的结构体指针,定义 button_irqs 为和 dev_description 相同的结 构体指针, //并且与 dev_id 的地址进行对接 //即:request_irq 的 dev_id 参数会传递给该中断服务程序的 dev_id. //因此也可以将驱动程序的设备结构体通过 dev_id 传递给中断服务程序()
/*****************************************************************************************/ // 按键打开函数//
/*****************************************************************************************/ static int Buttons_Open(struct inode *inode , struct file *filp) {
static int Buttons_Open(struct inode * inode , struct file * filp);//按键打开函数 static int Buttons_Close(struct inode *inode, struct file *file);//按键关闭函数 static signed int Buttons_Read(struct file *filp, char __user *buffer, size_t size, loff_t *p);//按键读数据函数
S3C2440 Linux 按键驱动 解析
【说明】 本程序所采用的测试板为【友善之臂 mini2440】开发板,但适用于 TQ2440、TE2440
和 OK2440 等目前几乎所有主流的 S3C2440 开发板的学习!
【硬件资源】:
/*****************************************************************************************/ /************************************【驱动程序解析】*************************************/ /*****************************************************************************************/ #include <linux/kernel.h>//与内核有关 #include <linux/module.h>//与模块有关 #include <linux/types.h>//与类定义有关 #include <mach/hardware.h>//与硬件设备有关 #include <linux/platform_device.h>//与描述平台设备有关 #include <linux/sched.h>//与进程有关 #include <linux/fs.h>//与文件函数有关 #include <asm/uaccess.h>//与进程空间和内核空间交换数据 #include <linux/delay.h>//与延时函数有关 #include <linux/cdev.h>//与字符设备驱动有关
相关文档
最新文档