1. 程式人生 > >IMX6Q下tlv320aic3x音訊驅動移植

IMX6Q下tlv320aic3x音訊驅動移植

原理圖:

tlv320aic3x音訊晶片

功率放大器

移植分為三步:

1.codec 驅動 sound/soc/codecs/tlv320aic3x.c 2.平臺驅動 sound/soc/imx/imx-tlv320aic3x.c 3.新增板檔案 

arch/arm/mach-mx6/board-mx6q_sabresd.c   和  arch/arm/mach-mx6/board-mx6q_sabresd.c

一、codec驅動是linux核心自帶的,在sound/soc/codecs/下面有不同的音訊晶片,根據開發的音訊晶片選擇或者修改。

在tlv320aic3x.c檔案中有幾個重要的結構體需要關注:

static struct snd_soc_dai_ops aic3x_dai_ops = {
    .hw_params    = aic3x_hw_params,  //硬體引數設定
    .digital_mute    = aic3x_mute,   //靜音設定
    .set_sysclk    = aic3x_set_dai_sysclk,  //時鐘設定
    .set_fmt    = aic3x_set_dai_fmt,  //格式設定
};

static struct snd_soc_dai_driver aic3x_dai = {
	.name = "tlv320aic3x-hifi",
	.playback = {
		.stream_name = "Playback",
		.channels_min = 1,
		.channels_max = 2,
		.rates = AIC3X_RATES,
		.formats = AIC3X_FORMATS,},
	.capture = {
		.stream_name = "Capture",
		.channels_min = 1,
		.channels_max = 2,
		.rates = AIC3X_RATES,
		.formats = AIC3X_FORMATS,},
	.ops = &aic3x_dai_ops,
	.symmetric_rates = 1,
};
需要注意的是這個.name,需要和sound/soc/imx/imx-tlv320aic3x.c中的 .codec_dai_name相同。
static struct snd_soc_dai_link imx_tlv320aic3x_dai[] = {
	{
		.name = "TLV320AIC3X",
		.stream_name = "AIC3X",
		.codec_dai_name = "tlv320aic3x-hifi",
		.codec_name = "tlv320aic3x-codec.0-0018",		//I2C-0
		.cpu_dai_name = "imx-ssi.1",			
		.platform_name = "imx-pcm-audio.1",
		
		.init =imx_3stack_tlv320aic3x_init,
		.ops = &imx_tlv320aic3x_hifi_ops,
	},
};
在sound/soc/codecs/tlv320aic3x.c檔案中,我們需要關注 .name,這個名字要和sound/soc/imx/imx-tlv320aic3x.c的 .codec_name關聯,這樣才會呼叫aic_i2c_probe探測函式。如果名字不同的話會發現編譯好的核心找不到音效卡。
/* machine i2c codec control layer */
static struct i2c_driver aic3x_i2c_driver = {
	.driver = {
		.name = "tlv320aic3x-codec",
		.owner = THIS_MODULE,
	},
	.probe	= aic3x_i2c_probe,
	.remove = aic3x_i2c_remove,
	.id_table = aic3x_i2c_id,
};

static struct snd_soc_dai_link imx_tlv320aic3x_dai[] = {
    {
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
        .codec_dai_name = "tlv320aic3x-hifi",
        .codec_name = "tlv320aic3x-codec.0-0018",        //I2C-0
        .cpu_dai_name = "imx-ssi.1",            
        .platform_name = "imx-pcm-audio.1",
        
        .init =imx_3stack_tlv320aic3x_init,
        .ops = &imx_tlv320aic3x_hifi_ops,
    },
};
在static struct snd_soc_dai_link imx_tlv320aic3x_dai[]中,0-0018的含義是這個晶片是掛載在i2c0上,裝置號為0x18,根據晶片的引數進行修改。其他地方基本不用改動。

因為是平臺裝置驅動,所以就要將平臺驅動和平臺裝置進行關聯。

平臺驅動在sound/soc/imx/imx-tlv320aic3x.c檔案中:

static struct platform_driver imx_tlv320aic3x_audio_driver = {
	.probe = imx_tlv320aic3x_probe,
	.remove = imx_tlv320aic3x_remove,
	.driver = {
		   .name = "imx-tlv320",
	},
};
與之相關聯的裝置在板檔案arch/arm/mach-mx6/board-mx6q_sabresd.c中:
static struct platform_device mx6_audio_tlv320_device = {
        .name = "imx-tlv320",
};
因為是通過名字進行匹配,所以二者名字一定要相同。
在板檔案中,要進行i2c0的註冊所和用到的引腳的配置。

 在arch/arm/mach-mx6/board-mx6q_sabresd.c中:

static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
    {
		I2C_BOARD_INFO("ds1338", 0x68),
	},
	{
		I2C_BOARD_INFO("ov5640_mipi", 0x3c),
		.platform_data = (void *)&mipi_csi2_data,
	},
	{
		I2C_BOARD_INFO("tlv320aic3x", 0x18),
	},
};
將音訊裝置掛在i2c0上,tlv320aic3x是裝置名,0x18是從裝置號,可以參考資料手冊查詢。掛在好進行註冊:
imx6q_add_imx_i2c(0, &mx6q_qy_imx6s_i2c_data);
i2c_register_board_info(0, mxc_i2c0_board_info,
            ARRAY_SIZE(mxc_i2c0_board_info));
在arch/arm/mach-mx6/board-mx6q_sabresd.h檔案中配置引腳:
static iomux_v3_cfg_t mx6q_qy_imx6s_i2c_pads[] =
{
    MX6Q_PAD_CSI0_DAT8__I2C1_SDA,//i2c
    MX6Q_PAD_CSI0_DAT9__I2C1_SCL,,
};

static iomux_v3_cfg_t mx6q_qy_imx6s_audio_pads[] = {
	/*MX6Q_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC,
	MX6Q_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD,
	MX6Q_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS,
	MX6Q_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD,*/

	MX6Q_PAD_GPIO_0__CCM_CLKO,   //CLK ouput
	MX6Q_PAD_SD2_CMD__GPIO_1_11, //AUDIO SD
	MX6Q_PAD_SD2_CLK__GPIO_1_10, //AUDIO REST
	
	MX6Q_PAD_SD2_DAT0__AUDMUX_AUD4_RXD,
	MX6Q_PAD_SD2_DAT1__AUDMUX_AUD4_TXFS,
	MX6Q_PAD_SD2_DAT2__AUDMUX_AUD4_TXD,
	MX6Q_PAD_SD2_DAT3__AUDMUX_AUD4_TXC,
};
因為我的開發板是外接喇叭,所以配置了功放:MX6Q_PAD_SD2_CMD__GPIO_1_11, //AUDIO SD

在arch/arm/mach-mx6/board-mx6q_sabresd.c寫功能函式:

1.定義功放和復位

//audio 
#define AUDIO_REST		IMX_GPIO_NR(1 , 10)
#define AUDIO_SD		IMX_GPIO_NR(1 , 11)

static void tlv320_gpio_set(void)
{
    static void __iomem *audio_gpio_base = IO_ADDRESS(0x020e0740);//配置引腳暫存器第13位為 0=keeper
    writel(0x90B0,audio_gpio_base);

    gpio_request(AUDIO_SD, "audio_sd");  
    gpio_direction_output(AUDIO_SD, 0); //低電平有效 
    msleep(1);  
    gpio_set_value(AUDIO_SD, 0);
    
    gpio_request(AUDIO_REST, "audio_rest");  
    gpio_direction_output(AUDIO_REST, 1);  
    msleep(1);  
    gpio_set_value(AUDIO_REST, 1);
}
在函式static int mxc_tlv320_init(void){}中呼叫:
static int mxc_tlv320_init(void)
{
		//struct clk *clko;
		//struct clk *new_parent;
		int rate;

        clko = clk_get(NULL, "clko_clk");
        if (IS_ERR(clko)) {
                pr_err("can't get CLKO clock.\n");
                return PTR_ERR(clko);
        }
		
        /* both audio codec and comera use CLKO clk*/
        rate = clk_round_rate(clko, 24000000);
        clk_set_rate(clko, rate);
        tlv320_data.sysclk = rate;
		clk_enable(clko);
		
		tlv320_gpio_set();
        return 0;
}

下面放上板檔案和imx-tlv320aic3x.c的程式碼片段

arch/arm/mach-mx6/board-mx6q_sabresd.c:

static struct regulator_consumer_supply qy_imx6s_vmmc_consumers[] = {
	REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"),
	REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"),
	REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"),
	REGULATOR_SUPPLY("vcc", "spi4.1"),
	REGULATOR_SUPPLY("IOVDD", "0-0018"),
	REGULATOR_SUPPLY("AVDD", "0-0018"),
	REGULATOR_SUPPLY("DRVDD", "0-0018"),
};

static struct regulator_init_data qy_imx6s_vmmc_init = {
	.num_consumer_supplies = ARRAY_SIZE(qy_imx6s_vmmc_consumers),
	.consumer_supplies = qy_imx6s_vmmc_consumers,
};

static struct fixed_voltage_config qy_imx6s_vmmc_reg_config = {
	.supply_name		= "vmmc",
	.microvolts		= 3300000,
	.gpio			= -1,
	.init_data		= &qy_imx6s_vmmc_init,
};

static struct platform_device qy_imx6s_vmmc_reg_devices = {
	.name	= "reg-fixed-voltage",
	.id	= 3,
	.dev	= {
		.platform_data = &qy_imx6s_vmmc_reg_config,
	},
};

static struct platform_device mx6_audio_tlv320_device = {
        .name = "imx-tlv320",
};

static int tlv320_clk_enable(int enable)
{
        if (enable)
                clk_enable(clko);
        else
                clk_disable(clko);

        return 0;
}
static struct mxc_audio_platform_data tlv320_data;

static void tlv320_gpio_set(void)
{
	static void __iomem *audio_gpio_base = IO_ADDRESS(0x020e0740);//13位  0=keeper
	writel(0x90B0,audio_gpio_base);

	gpio_request(AUDIO_SD, "audio_sd");  
	gpio_direction_output(AUDIO_SD, 0);  
	msleep(1);  
	gpio_set_value(AUDIO_SD, 0);
	
	gpio_request(AUDIO_REST, "audio_rest");  
	gpio_direction_output(AUDIO_REST, 1);  
	msleep(1);  
	gpio_set_value(AUDIO_REST, 1);
}
static int mxc_tlv320_init(void)
{
		//struct clk *clko;
		//struct clk *new_parent;
		int rate;

        clko = clk_get(NULL, "clko_clk");
        if (IS_ERR(clko)) {
                pr_err("can't get CLKO clock.\n");
                return PTR_ERR(clko);
        }
		
        /* both audio codec and comera use CLKO clk*/
        rate = clk_round_rate(clko, 24000000);
        clk_set_rate(clko, rate);
        tlv320_data.sysclk = rate;
		clk_enable(clko);
		
		tlv320_gpio_set();
        return 0;
}
static struct mxc_audio_platform_data tlv320_data = {
        .ssi_num = 1,
        .src_port = 2,
        .ext_port = 4,//control playing stop
        .init = mxc_tlv320_init,
        .clock_enable = tlv320_clk_enable,
};

static struct imx_ssi_platform_data mx6_ssi_pdata = {
        .flags = IMX_SSI_DMA | IMX_SSI_SYN,
};


static struct regulator_consumer_supply qy_imx6s_tlv320_consumers[] = {
	REGULATOR_SUPPLY("DVDD", "0-0018"),
};

static struct regulator_init_data qy_imx6s_tlv320_init = {
	.num_consumer_supplies = ARRAY_SIZE(qy_imx6s_tlv320_consumers),
	.consumer_supplies = qy_imx6s_tlv320_consumers,
};

static struct fixed_voltage_config qy_imx6s_tlv320_reg_config = {
	.supply_name	= "DVDD",
	.microvolts		= 1800000,
	.gpio			= -1,  //if changed no soundcard exist
	.init_data		= &qy_imx6s_tlv320_init,
};

static struct platform_device qy_imx6s_tlv320_reg_devices = {
	.name	= "reg-fixed-voltage",
	.id		= 4,
	.dev	= {
		.platform_data = &qy_imx6s_tlv320_reg_config,
	},
};

static int __init imx6q_init_audio(void)
{
	platform_device_register(&qy_imx6s_tlv320_reg_devices);
	mxc_register_device(&mx6_audio_tlv320_device,
                                    &tlv320_data);
    imx6q_add_imx_ssi(1, &mx6_ssi_pdata);
    mxc_tlv320_init();
	return 0;
}

static void __init mx6_qy_imx6s_board_init(void)
{
    ……………
    ……………
    imx6q_init_audio();
    ……………
    ……………
}
imx-tlv320aic3x.c
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/fsl_devices.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/jack.h>
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
#include <mach/audmux.h>

#include "../codecs/tlv320aic23.h"
#include "imx-ssi.h"

#define CODEC_CLOCK 24000000

static int qiyang_tlv320_hw_params(struct snd_pcm_substream *substream,
			    struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	int ret;

	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
				  SND_SOC_DAIFMT_NB_NF |
				  SND_SOC_DAIFMT_CBM_CFM);
	if (ret) {
		pr_err("%s: failed set cpu dai format\n", __func__);
		return ret;
	}

	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
				  SND_SOC_DAIFMT_NB_NF |
				  SND_SOC_DAIFMT_CBM_CFM);
	if (ret) {
		pr_err("%s: failed set codec dai format\n", __func__);
		return ret;
	}

	ret = snd_soc_dai_set_sysclk(codec_dai, 0,
				     CODEC_CLOCK, SND_SOC_CLOCK_OUT);
	if (ret) {
		pr_err("%s: failed setting codec sysclk\n", __func__);
		return ret;
	}
	snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);

	ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
				SND_SOC_CLOCK_IN);
	if (ret) {
		pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
		return ret;
	}

	return 0;
}

static struct snd_soc_ops qiyang_tlv320_snd_ops = {
	.hw_params	= qiyang_tlv320_hw_params,
};

static struct snd_soc_dai_link qiyang_tlv320_dai = {
	.name		= "tlv320aic3x",
	.stream_name	= "TLV320AIC3X",
	.codec_dai_name	= "tlv320aic3x-hifi",
	.codec_name	= "tlv320aic3x-codec.0-0018",//i2c0
	.platform_name  = "imx-pcm-audio.1",
	.cpu_dai_name	= "imx-ssi.1",
	.ops		= &qiyang_tlv320_snd_ops,
};

static struct snd_soc_card qiyang_tlv320 = {
	.name		= "tlv320-audio",
	.dai_link	= &qiyang_tlv320_dai,
	.num_links	= 1,
};
static int imx_audmux_config(int slave, int master)
{
        unsigned int ptcr, pdcr;
        slave = slave - 1;
        master = master - 1;

        // SSI0 mastered by port 4 
        ptcr = MXC_AUDMUX_V2_PTCR_SYN |
                MXC_AUDMUX_V2_PTCR_TFSDIR |
                MXC_AUDMUX_V2_PTCR_TFSEL(master) |
                MXC_AUDMUX_V2_PTCR_TCLKDIR |
                MXC_AUDMUX_V2_PTCR_TCSEL(master);
        pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(master);
        mxc_audmux_v2_configure_port(slave, ptcr, pdcr);

        ptcr = MXC_AUDMUX_V2_PTCR_SYN;
        pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(slave);
        mxc_audmux_v2_configure_port(master, ptcr, pdcr);

        return 0;
}
static int __devinit imx_tlv320_probe(struct platform_device *pdev)
{
	//printk("*****************888imx_tlv320_probe\n");
        struct mxc_audio_platform_data *plat = pdev->dev.platform_data;

        int ret = 0;

        imx_audmux_config(plat->src_port, plat->ext_port);

        ret = -EINVAL;
        if (plat->init && plat->init())
                return ret;
        return 0;
}
static int imx_tlv320_remove(struct platform_device *pdev)
{
        struct mxc_audio_platform_data *plat = pdev->dev.platform_data;

        if (plat->finit)
                plat->finit();

        return 0;
}

static struct platform_driver imx_tlv320_audio_driver = {
        .probe = imx_tlv320_probe,
        .remove = imx_tlv320_remove,
        .driver = {
                   .name = "imx-tlv320",
                   },
};

static struct platform_device *qiyang_tlv320_snd_device;

static int __init qiyang_tlv320_init(void)
{
	int ret;
	//printk("********************************************************11111!%d\n",machine_arch_type);
	ret = platform_driver_register(&imx_tlv320_audio_driver);
        if (ret)
                return -ENOMEM;
	qiyang_tlv320_snd_device = platform_device_alloc("soc-audio", 6);
	if (!qiyang_tlv320_snd_device)
		return -ENOMEM;
	
	platform_set_drvdata(qiyang_tlv320_snd_device, &qiyang_tlv320);
	ret = platform_device_add(qiyang_tlv320_snd_device);
	
	
	
	if (ret) {
		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
		platform_device_put(qiyang_tlv320_snd_device);
	}
	//printk("********************************************************2222222!\n");
	return ret;
}

static void __exit qiyang_tlv320_exit(void)
{
	platform_driver_unregister(&imx_tlv320_audio_driver);
	platform_device_unregister(qiyang_tlv320_snd_device);
}

module_init(qiyang_tlv320_init);
module_exit(qiyang_tlv320_exit);


MODULE_AUTHOR("allen young <[email protected]>");
MODULE_DESCRIPTION("FUCK ALSA SoC driver");
ODULE_LICENSE("GPL");



相關推薦

IMX6Qtlv320aic3x音訊驅動移植

原理圖: tlv320aic3x音訊晶片 功率放大器 移植分為三步: 1.codec 驅動 sound/soc/codecs/tlv320aic3x.c 2.平臺驅動 sound/soc/imx/imx-tlv320aic3x.c 3.新增板檔案  arch/a

IMX6qgt9xx TP簡易移植

複製驅動到 driver/input/touchscreen 下 修改 Kconfig 和 Makefiel Kconfig: # add gt9xx config TOUCHSCREEN_

linux應用層用C呼叫音訊驅動

static void audio_pause(void) {     int err;     if (alsa_can_pause) {         if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)        

嵌入式LinuxALSA音訊架構ALSA-lib移植與編譯心得

*************************************************************************************************************************** 作者:EasyWave

網路驅動移植之sk_buff結構體及其相關操作函式(

    2、結構體相關操作函式     (1)、dev_alloc_skb     實際上,函式dev_alloc_skb最終是呼叫__alloc_skb函式來分配資料緩衝區和sk_buff結構體的,如下圖:       從dev_alloc_skb到__alloc_skb

Zynq-Linux移植學習筆記之16-Zynqlinux XADC驅動

1、  簡介 XADC是zynq晶片內部進行溫度和電壓檢測的模組,通過(Xilinx Wiki - xadc.html)這篇wiki可以知道,XADC控制器有兩種表現形式,一種是位於PS內部,即文件中提到的the PS-XADC interface for the PS s

Linux RT3070 驅動移植

RT3070驅動移植 無線網絡卡為RT3070,驅動分為STA驅動和SoftAP驅動兩種,STA驅動支援無線網絡卡工作在STA模式下,而SoftAP的驅動支援無線網絡卡工作在軟AP的模式下,可以作為一個軟的接入點。STA驅動為2010_0831_RT3070_Linux_S

[轉]Ubuntu16.04ralink rt3290驅動安裝

update creating sca change other nts ems .net rri 出處:https://askubuntu.com/questions/253632/how-do-i-get-a-ralink-rt3290-wireless-card-w

linux網卡驅動安裝全過程

linux網卡驅動方法一,用RPM包安裝驅動程序方法:1.將驅動程序文件bcm5700-.src.rpm復制到一個臨時目錄中,並在此目錄中運行以下命令:rpm –ivh bcm5700-.src.rpm2.運行以下命令切換到驅動目錄中:cd /usr/src/redhat/SPECS/3.此目錄中會生成一個名

驅動移植過程中DMA內存相關接口替換

linux sylixos dma 1. 相關概念介紹及移植簡介 1.1 物理地址與總線地址 1)物理地址是與CPU相關的。在CPU的地址信號線上產生的就是物理地址,在程序指令中的的虛擬地址經過段映射和頁面映射後,就生成了物理地址,這個物理地址被放到CPU的地址線上。

linuxcan總線移植及測試總結

哪裏 ips sub 開關 switch 發現 開發 主機 編譯工具 Can移植及測試總結 Adding Flexcan driver support on Kernel 一.On kernel menuconfig, add the following items: [*

at91sam9g45 mcp2515 linux3.6.9驅動移植要點

ges static cal str UC data- infineon dts a10 平臺at91sam9g45 linux版本 3.6.91 board-sam9m10g45ek.c 文件添加如下結構體 static struct mcp251x_platform_d

MT7601 WG209模塊驅動移植,並連接路由器

文件 logs 由器 kernel blog 路由 github 版本 分享圖片 驅動位置: https://github.com/Aplexchenfl/WG209_MT7601 下載之後,查看 Makefile 在這裏,我修改了 kernel的位置以及編譯器的版本

VxWorks驅動移植至SylixOS總結

lang str 設備 整合 不同 使用場景 文檔 enable ble 本文檔描述了將VxWorks中的驅動源碼快速移植至SylixOS中的方法,使用時需要結合SylixOS中的VxWorks兼容層實現。 1. 驅動註冊與初始化 1.1 VxWorks中驅動註冊與初始化

ubuntu的更改驅動

手動安裝 賬戶 8.0 網上 apt-get 風扇 驅動 during oot 感覺風扇轉的特別響,網上說是,顯卡驅動要換成專有的。 裝了之後,在設置裏將顯卡切換為集成顯卡,要求重新啟動。 重新啟動,進入圖形界面失敗: Failed to start dGPU off du

音訊驅動曲線

https://www.youtube.com/watch?v=SqFvO462yVw&t=6s音訊驅動曲線 {TimeLine} 修改同步:Av-Sync {Video Sequence Editor} 增加音訊檔案[shift A] sound (*.mp3) {世界場景} 黑色背景{3D視

DS18B20驅動移植和除錯用例

DS18B20時序分析: DS18B20的一線工作協議流程是:初始化->ROM操作指令->儲存器操作指令->資料傳輸, 其工作時序包括:初始化時序、寫時序、讀時序。 1.初始化時序: 主機:首先發出一個480~960us的低電平脈衝,然後釋放匯流排變為高電平。 並在

python 和linux環境音訊處理變頻變調的方法和框架

前戲——音樂基礎 聲音是靠波來傳播的,區別任何的聲音需要依據三個來區分:響度、音高和音色響度 音高:聲音具有確定的音高,聲音就可以使空氣以篤定的方式執行。低音就是頻率低。 一個樂音訊率是另外一個樂音的頻率的2倍,我就就稱為比它高八度,聲音的震動頻率=音源的振動頻率

Android的攝像頭驅動開發

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

mini2440 SPI驅動移植(轉)

按照下面帖子的方法,本人試驗成功,只需按照下面步驟進行就行了。 原帖地址: http://blog.csdn.net/lxmky/article/details/6858322 注:原文最後短接的MISO和MOSI指的是SPI1的,區別於SPI0 min