`
isiqi
  • 浏览: 16028762 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

linux spi子系统驱动分析

阅读更多

linux spi子系统驱动分析

2.6.18内核下已经添加了完整的spi子系统了,参考mtd的分析,将从下到上层,再从上到下层的对其进行分析。

以下先从下到上的进行分析:

driver/spi下有两个底层相关的spi驱动程序:

spi_s3c24xx.c和spi_s3c24xx_gpio.c

其中spi_s3c24xx.c是基于s3c24xx下相应的spi接口的驱动程序,spi_s3c24xx_gpio.c允许用户指定3个gpio口,分别充当spi_clk、spi_mosi和spi_miso接口,模拟标准的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;

/* pi_alloc_master函数申请了struct spi_master+struct s3c24xx_spi大小的数据,

* spi_master_get_devdata和pi_master_get分别取出struct s3c24xx_spi和struct spi_master结构指针

*/

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;

}

/* 填充struct spi_master结构 */

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);

/* setup the state for the bitbang driver */

/* 填充hw->bitbang结构(hw->bitbang结构充当一个中间层,相当与input system的input_handle struct) */

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);

/* find and map our resources */

/* 申请spi所用到的资源:io、irq、时钟等 */

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;

}

/* for the moment, permanently enable the clock */

clk_enable(hw->clk);

/* program defaults into the registers */

/* 初始化spi相关的寄存器 */

writeb(0xff, hw->regs + S3C2410_SPPRE);

writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);

writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);

/* add by lfc */

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);

/* end add */

/* setup any gpio we can */

/* 片选 */

if (!hw->pdata->set_cs) {

s3c2410_gpio_setpin(hw->pdata->pin_cs, 1);

s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT);

}

/* register our spi controller */

/* 最终通过调用spi_register_master来注册spi控制器(驱动) */

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);

/* register all the devices associated */

/* 注册所用使用本spi驱动的设备 */

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;

}

/*

* spi_alloc_master - allocate SPI master controller

* @dev: the controller, possibly using the platform_bus

* @size: how much driver-private data to preallocate; the pointer to this

* memory is in the class_data field of the returned class_device,

* accessible with spi_master_get_devdata().

*

* This call is used only by SPI master controller drivers, which are the

* only ones directly touching chip registers. It's how they allocate

* an spi_master structure, prior to calling spi_register_master().

*

* This must be called from context that can sleep. It returns the SPI

* master structure on success, else NULL.

*

* The caller is responsible for assigning the bus number and initializing

* the master's methods before calling spi_register_master(); and (after errors

* adding the device) calling spi_master_put() to prevent a memory leak.

*/

/*注释已经写得很清楚了,本函数旨在分配spi_master struct

*其中,device为主控制设备,size为需要预分配的设备私有数据大小

*该函数被spi主控制器驱动所调用,用于在调用spi_register_master注册主控制器前

*分配spi_master struct,分配bus number和初始化主控制器的操作方法

*注意在分配spi_master struct的时候多分配了大小为size的设备私有数据

*并通过spi_master_set_devdata函数把其放到class_data field里,以后可以通过spi_master_get_devdata来访问

*/

struct spi_master * __init_or_module

spi_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;

}

/*

* spi_bitbang_start - start up a polled/bitbanging SPI master driver

* @bitbang: driver handle

*

* Caller should have zero-initialized all parts of the structure, and then

* provided callbacks for chip selection and I/O loops. If the master has

* a transfer method, its final step should call spi_bitbang_transfer; or,

* that's the default if the transfer routine is not initialized. It should

* also set up the bus number and number of chipselects.

*

* For i/o loops, provide callbacks either per-word (for bitbanging, or for

* hardware that basically exposes a shift register) or per-spi_transfer

* (which takes better advantage of hardware like fifos or DMA engines).

*

* Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and

* spi_bitbang_cleanup to handle those spi master methods. Those methods are

* the defaults if the bitbang->txrx_bufs routine isn't initialized.

*

* This routine registers the spi_master, which will process requests in a

* dedicated task, keeping IRQs unblocked most of the time. To stop

* processing those requests, call spi_bitbang_stop().

*/

int spi_bitbang_start(struct spi_bitbang *bitbang)

{

int status;

if (!bitbang->master || !bitbang->chipselect)

return -EINVAL;

/*bitbang_work

* 初始化a work,后面再create_singlethread_workqueue,

* 等到有数据要传输的时候,在spi_bitbang_transfer函数中通过调用queue_work(bitbang->workqueue, &bitbang->work)

* 把work扔进workqueue中调度运行

* 这是内核的一贯做法,在mmc/sd驱动中也是这样处理的^_^

*/

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数据的传输就是通过调用这个方法来实现的

/* spi_s3c24xx.c驱动中有相应的txrx_bufs处理方法,在bitbang_work中被调用 */

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;

}

/* spi_s3c24xx.c驱动中有相应的setup处理方法,在稍后的spi_new_device中被调用 */

} else if (!bitbang->master->setup)

return -EINVAL;

/* this task is the only thing to touch the SPI bits */

bitbang->busy = 0;

/* 创建工作者进程 */

bitbang->workqueue = create_singlethread_workqueue(

bitbang->master->cdev.dev->bus_id);

if (bitbang->workqueue == NULL) {

status = -EBUSY;

goto err1;

}

/* driver may get busy before register() returns, especially

* if someone registered boardinfo for devices

*/

status = spi_register_master(bitbang->master);

if (status < 0)

goto err2;

return status;

err2:

destroy_workqueue(bitbang->workqueue);

err1:

return status;

}

/**

* spi_register_master - register SPI master controller

* @master: initialized master, originally from spi_alloc_master()

*

* SPI master controllers connect to their drivers using some non-SPI bus,

* such as the platform bus. The final stage of probe() in that code

* includes calling spi_register_master() to hook up to this SPI bus glue.

*

* SPI controllers use board specific (often SOC specific) bus numbers,

* and board-specific addressing for SPI devices combines those numbers

* with chip select numbers. Since SPI does not directly support dynamic

* device identification, boards need configuration tables telling which

* chip is at which address.

*

* This must be called from context that can sleep. It returns zero on

* success, else a negative error code (dropping the master's refcount).

* After a successful return, the caller is responsible for calling

* spi_unregister_master().

*/

int __init_or_module

spi_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;

/* convention: dynamically assigned bus IDs count down from the max */

if (master->bus_num < 0) {

master->bus_num = atomic_dec_return(&dyn_bus_id);

dynamic = 1;

}

/* register the device, then userspace will see it.

* registration fails if the bus ID is in use.

*/

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)" : "");

/* populate children from any spi device tables */

scan_boardinfo(master);

status = 0;

done:

return status;

}

/* FIXME someone should add support for a __setup("spi", ...) that

* creates board info from kernel command lines

*/

/*

* scan board_list for spi_board_info which is registered by spi_register_board_info

* 很可惜,s3c24xx的spi驱动中不支持spi_register_board_info这种标准方式注册方式,而是直接调用spi_new_device内部函数

*/

static void __init_or_module

scan_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;

/* some controllers only have one chip, so they

* might not use chipselects. otherwise, the

* chipselects are numbered 0..max.

*/

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);

}

/*

* Board-specific early init code calls this (probably during arch_initcall)

* with segments of the SPI device table. Any device nodes are created later,

* after the relevant parent SPI controller (bus_num) is defined. We keep

* this table of devices forever, so that reloading a controller driver will

* not make Linux forget about these hard-wired devices.

*

* Other code can also call this, e.g. a particular add-on board might provide

* SPI devices through its expansion connector, so code initializing that board

* would naturally declare its SPI devices.

*

* The board info passed can safely be __initdata ... but be careful of

* any embedded pointers (platform_data, etc), they're copied as-is.

*/

int __init

spi_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;

}

/* On typical mainboards, this is purely internal; and it's not needed

* after board init creates the hard-wired devices. Some development

* platforms may not be able to use spi_register_board_info though, and

* this is exported so that for example a USB or parport based adapter

* driver could add devices (which it would learn about out-of-band).

*/

struct spi_device *__init_or_module

spi_new_device(struct spi_master *master, struct spi_board_info *chip)

{

struct spi_device *proxy;//这个结构很重要,以后就是通过这个结构来操作实际的spi设备的

struct device *dev = master->cdev.dev;

int status;

/* NOTE: caller did any chip->bus_num checks necessary */

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;

}

/* 初始化spi_device 结构各成员 */

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;

/* drivers may modify this default i/o setup */

/* 调用master->setup(即s3c24xx_spi_setup)函数初始化spi设备 */

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;

}

/* driver core catches callers that misbehave by defining

* devices that already exist.

*/

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;

/* is clk = pclk / (2 * (pre+1)), or is it

* clk = (pclk * 2) / ( pre + 1) */

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

/* need to ndelay for 0.5 clocktick ? */

}

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:

/* 禁用spi(禁用片选) */

if (hw->pdata->set_cs)

hw->pdata->set_cs(hw->pdata, value, cspol);

else

s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1);

break;

case BITBANG_CS_ACTIVE:

/*

* 启用spi:根据需要设置寄存器并启用使能片选

* (如果spi_board_info中没有设置相应的mode选项的话,那就只能使用默认值SPPIN_DEFAULT和SPCON_DEFAULT了)

*/

spcon = readb(hw->regs + S3C2410_SPCON);

if (spi->mode & SPI_CPHA)

spcon |= S3C2410_SPCON_CPHA_FMTB;

else

spcon &= ~S3C2410_SPCON_CPHA_FMTB;

if (spi->mode & SPI_CPOL)

spcon |= S3C2410_SPCON_CPOL_HIGH;

else

spcon &= ~S3C2410_SPCON_CPOL_HIGH;

spcon |= S3C2410_SPCON_ENSCK;

/* write new configration */

writeb(spcon, hw->regs + S3C2410_SPCON);

if (hw->pdata->set_cs)

hw->pdata->set_cs(hw->pdata, value, cspol);

else

s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol);

break;

}

}

分享到:
评论

相关推荐

    linux SPI子系统驱动分析

    linux SPI子系统驱动分析

    Linux SPI 子系统驱动程序结构分析

    Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix...

    Linux下spi驱动开发

    SPI子系统的开发和I2C有很多的相似性,大家可以对比学习。本主题分为两个部分叙述,第一部分介绍基于SPI子系统开发的理论框架;第二部分以华清远见教学平台FS_S5PC100上的M25P10芯片为例(内核版本2.6.29),编写一...

    Linux常见驱动源码分析(kernel hacker修炼之道全集)--李万鹏

    Linux驱动修炼之道-RTC子系统框架与源码分析.pdf Linux驱动修炼之道-platform.pdf Linux驱动修炼之道-LCD背光与gpio控制.pdf Linux驱动修炼之道-INPUT子系统(下).pdf Linux驱动修炼之道-INPUT子系统(上...

    Linux内核驱动之spi子系统(一)spi协议

    一、 SPI接口是摩托罗拉首先提出的全双工三线同步串行外围接口SCK,MOSI,MISO,采用主从模式(Master Slave)架构;支持多slave模式应用(此时使用四线模式进行通信,在原有三线模式下多出一根片选信号CS),一般一个...

    linux 2.6.36+ok6410 SPI子系统接口讨论

    linux下的设备模型包括几个主要的概念sysfs (dev是用户空间接口,根据...driver是设备驱动class是类别,从功能角度对设备进行分类注意,在sys/bus目录下有platform目录和spi目录这两个目录下面的设备分别代表什么呢?

    Linux驱动开发:Linux内核模块、字符设备驱动、IO模型、设备树、GPIO子系统、中断子系统.zip

    Linux驱动开发:Linux内核模块、字符设备驱动、IO模型、设备树、GPIO子系统、中断子系统、platform总线驱动、I2C总线驱动、SPI总线驱动 Linux项目是一个开放源代码的操作系统项目,由林纳斯·托瓦兹(Linus Torvalds...

    ARM 嵌入式LINUX 系统构建与驱动开发

    1 ARM嵌入式LINUX系统构建与驱动开发,北航版 驱动写的很详细,前期开发介绍也很好 2 ARM 嵌入式系统实验教程(二),北航版 有ZLG2200的原理图,实验程序和注释,了解人家是怎么开发的。 3 ARM嵌入式系统基础教程 ...

    《精通Linux 设备驱动程序开发》.(Sreekrishnan).pdf

    12.2 linux视频子系统249 12.3 显示参数251 12.4 帧缓冲api252 12.5 帧缓冲驱动程序254 12.6 控制台驱动程序265 12.6.1 设备实例:手机266 12.6.2 启动logo270 12.7 调试270 12.8 查看源代码271 ...

    精通LINUX设备驱动程序开发

    sensors监控硬件 174 8.8 spi总线 174 8.9 1-wire总线 176 8.10 调试 176 8.11 查看源代码 176 第9章 pcmcia和cf 179 9.1 pcmcia/cf是什么 179 9.2 linux-pcmcia子系统 181 9.3 主机控制器驱动程序 ...

    ads1282内核驱动程序及其应用测试程序

    压缩包包含内核驱动源码和应用程序源码。ADS1282使用字符设备驱动在SPI子系统下开发而成的内核驱动。

    基于Raspberry+Pi的数据采集系统的研究与实现

    SPI子系统驱动框架,基于Raspberry Pi平台设计并实现SPI总线直接驱动数据采 集卡,实现多通道数据的快速采集。实现了在工业生产领域中使用Python语言的 开源框架与硬件交互开发的案例。再次,在本系统中提出了使用...

    网上收集的某人的驱动总结

    收集的linux环境下的驱动。总结的文档说明加代码分析。 主要包括以下部分: pci buttons mcse-device adc clock dm9000 dma framebuffer ...spi ...还有设备模型以及子系统的说明 个人认为还可以,挺不错的。

    rk3288 使用iio接口获取adc数据 .zip

    内核adc下的驱动文件,使用linux iio 子系统获取adc数据,还有一个简单的测试程序。

    嵌入式课件

    11.4.1核心子系统 11.4.2设备驱动程序 11.5 Linux目录结构 11.5.1 Linux源文件的目录结构 11.5.2 Linux 运行系统的目录结构 11.6 Linux文件系统 11.6.1 文件系统与内核的关系 11.6.2 常见通用Linux文件系统 11.6.3 ...

    SX1302/SX1303硬件抽象层和工具(包转发器...)_C语言_代码_相关文件_下载

    该库还附带了一些基本测试程序,用于测试库的不同子模块。 2. 帮助程序 这些程序包含在项目中,以提供有关如何使用 HAL 库的示例,并帮助系统构建者测试它的不同部分。 2.1。包转发器 包转发器是运行在 Lora 网关...

    ARM 实验指导书第一册UCOS-II.doc

    此时出现了我们都较为熟悉的Palm OS,Windows CE,嵌入式Linux,Uc/OS操作系统,我们国内也出现了Hopen,Delta OS等操作系统。到今天,RTOS已经在全球形成了一个产业,每年RTOS和相关的开发工具(包括仿真器,逻辑...

    【RT-Thread 作品秀】瞎转悠-电路方案

    物联网操作系统是指以操作系统内核(可以是 RTOS、Linux 等)为基础,包括如文件系统、图形库等较为完整的中间件组件,具备低功耗、安全、通信协议支持和云端连接能力的软件平台,RT-Thread 就是一个 IoT OS。...

    IBM WebSphere Portal门户开发笔记01

    6、Portal中调用PUMA SPI管理用户和组信息 51 7、WCM内存溢出的解决方法 53 七、组件及其标签 53 (一)、标签 53 1、jsp组件 53 2、组件关联格式 54 3、IDCmpnt标签 55 4、workflowcmpnt标签 55 5、securitycmpnt...

Global site tag (gtag.js) - Google Analytics