BB方案大结局之BB端软件实现篇——基于BB及FPGA的DAQ及DDS设计与实现
[复制链接]
本帖最后由 黑非拉 于 2014-6-22 19:01 编辑
BB方案大结局之BB端软件实现篇——基于BB及FPGA的高速数据采集及DDS信号发生器设计与实现 ( 1 )开发平台及语言为: Linux C
( 2 )主要包括如下三个层次: 系统层:
BB管脚配置,对应板文件的修改。
驱动层:
DDS芯片AD9832驱动;
读写FPGA的GPMC驱动。
应用层:
TCPServer Socket通信;
DDS芯片控制;
GPMC读写FPGA:DDS波形数据及频率控制字设置(GPMC写),数据采集与传输(GPMC读);
CAN通信(本方案没有用到,实际项目中用过)。
( 3 )系统层的 BB 管脚配置
需要修改板文件 board-am335xevm.c 的内容,该文件路径如下:
root@gao:~# cd bone-linux/arch/arm/mach-omap2/
root@gao:~/bone-linux/arch/arm/mach-omap2# ls board-am335xevm.c
board-am335xevm.c 复制代码 关键部分代码:
/* Beaglebone Rev A3 and after */
static struct evm_dev_cfg beaglebone_dev_cfg[] = {
{tps65217_init, DEV_ON_BASEBOARD, PROFILE_NONE},
{mii1_init, DEV_ON_BASEBOARD, PROFILE_NONE},
{usb0_init, DEV_ON_BASEBOARD, PROFILE_NONE},
{usb1_init, DEV_ON_BASEBOARD, PROFILE_NONE},
{mmc0_init, DEV_ON_BASEBOARD, PROFILE_NONE},
{dcan0_beaglebone_init, DEV_ON_BASEBOARD, PROFILE_NONE},
{dcan1_beaglebone_init, DEV_ON_BASEBOARD, PROFILE_NONE},
{bone_fpga_init, DEV_ON_BASEBOARD, PROFILE_NONE},//配置相关管脚
{NULL, 0, 0},
};
static void bone_fpga_init(int evm_id, int profile)
{
setup_pin_mux(fpga_pin_mux);
}
/* Pin mux for fpga module */
static struct pinmux_config fpga_pin_mux[] = {
//配置GPMC相关管脚
//配置GPMC数据端口
{"gpmc_ad0.gpmc_ad0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad1.gpmc_ad1", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad2.gpmc_ad2", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad3.gpmc_ad3", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad4.gpmc_ad4", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad5.gpmc_ad5", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad6.gpmc_ad6", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad7.gpmc_ad7", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad8.gpmc_ad8", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad9.gpmc_ad9", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad10.gpmc_ad10", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad11.gpmc_ad11", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad12.gpmc_ad12", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad13.gpmc_ad13", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad14.gpmc_ad14", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
{"gpmc_ad15.gpmc_ad15", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
//配置GPMC地址端口
{"lcd_data0.gpmc_a0", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data1.gpmc_a1", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data2.gpmc_a2", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data3.gpmc_a3", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data4.gpmc_a4", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data5.gpmc_a5", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data6.gpmc_a6", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data7.gpmc_a7", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_vsync.gpmc_a8", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_hsync.gpmc_a9", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_pclk.gpmc_a10", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_ac_bias_en.gpmc_a11", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
{"lcd_data8.gpmc_a12", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
// {"lcd_data9.gpmc_a13", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
// {"lcd_data10.gpmc_a14", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
// {"lcd_data11.gpmc_a15", OMAP_MUX_MODE1 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA},
//配置GPMC片选管脚,gpmc_csn1作为片选
// {"gpmc_csn0.gpmc_csn0", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{"gpmc_csn1.gpmc_csn1", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
// {"gpmc_csn2.gpmc_csn2", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
//配置GPMC控制管脚
// {"gpmc_wait0.gpmc_wait0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
// {"gpmc_wpn.gpmc_wpn", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLUP},
// {"gpmc_advn_ale.gpmc_advn_ale", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{"gpmc_oen_ren.gpmc_oen_ren", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},//读
{"gpmc_wen.gpmc_wen", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},//写
// {"gpmc_ben0_cle.gpmc_ben0_cle", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
{"gpmc_clk.gpmc_clk", OMAP_MUX_MODE0 | AM33XX_PULL_DISA | AM33XX_INPUT_EN},//时钟,AM33XX_INPUT_EN属性一定要加上!!!
//配置控制DDS芯片AD9832的管脚为GPIO
{"lcd_data9.gpio2_15", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},//AD9832 SCLK
{"lcd_data10.gpio2_16", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},//AD9832 SDATA
{"lcd_data11.gpio2_17", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},//AD9832 FSYNC
//配置同步数据采集与数据传输的WR_RDN信号管脚及RD_INT_PULSE信号管脚
{"gpmc_csn0.gpio1_29", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},//RD_INT_PULSE信号是FPGA在采集完一行(512个点)数据后发送的一个正脉冲信号,该正脉冲信号会引起BB发生外部IO中断,从而触发一次读操作!!!
{"gpmc_csn2.gpio1_31", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},//WDRDN信号是控制采集数据与读数据的信号,在高电平期间FPGA会采集数据并写入缓存,在低电平期间BB会读取缓存数据,这时FPGA不会写缓存,从而有效防止了读写错乱!!!
{NULL, 0},
}; 复制代码 ( 4 ) DDS 芯片 AD9832 驱动及读写 FPGA 的 GPMC 驱动的实现
( 4.1 ) DDS 芯片 AD9832 驱动程序 AD9832是ADI公司集成DDS芯片,可以很方便快速地设置输出正弦波的频率,这是本方案实现DDS信号发生器的方法之一,类比基于FPGA的DDS信号发生器,其优点是使用方便,缺点是输出波形单一,应用灵活性差。
驱动源文件为: ddsdev.c
设备驱动文件为: #define DDS_CHIP_DEV "/dev/ddsdev0"
主要功能函数:
图 6
是 AD9832
的读写时序图, dds_byte_shift 函数 通过 GPIO 端口模拟了 AD9832 读写时序,其代码如下:
static void dds_byte_shift(unsigned int data_16)
{
unsigned int temp;
gpio_set_value(GPIO_FSYNC, 0);//FSYNC = 0;
gpio_set_value(GPIO_SCLK, 1);//SCLK = 1;
udelay(1);
for (temp = 0x8000; temp != 0; ){
if ((data_16 & temp) == 0)//MSB First
gpio_set_value(GPIO_SDATA, 0);//SDATA = 0;
else
gpio_set_value(GPIO_SDATA, 1);//SDATA = 1;
udelay(1);//Data setup time
gpio_set_value(GPIO_SCLK, 0);//SCLK = 0;
temp = temp >> 1;
udelay(1);//Data hold time
gpio_set_value(GPIO_SCLK, 1);//SCLK=1;
}
udelay(1);
gpio_set_value(GPIO_FSYNC, 1);//FSYNC = 1;
udelay(1000);
} 复制代码
函数 dds_freq_process 及函数 dds_freq_adjust 用于设置相关控制方式及频率控制字 , 具体含义可以参考 AD9832 的 datasheet ,并提供两篇 CNKI 上的论文作为参考:
直接数字频率合成芯片 AD9832 原理及其典型应用设计【作者】 沈拓 ; 董德存 ;
相关代码如下:
static void dds_freq_process(
unsigned char freq0_lsbs_l,
unsigned char freq0_lsbs_h,
unsigned char freq0_msbs_l,
unsigned char freq0_msbs_h,
unsigned char freq1_lsbs_l,
unsigned char freq1_lsbs_h,
unsigned char freq1_msbs_l,
unsigned char freq1_msbs_h
)
{
dds_byte_shift(0xd000); //11 010 00000000000
//SLEEP RESET CLR
dds_byte_shift(0x3000 + freq0_lsbs_l);
dds_byte_shift(0x2100 + freq0_lsbs_h);
dds_byte_shift(0x3200 + freq0_msbs_l);
dds_byte_shift(0x2300 + freq0_msbs_h);
dds_byte_shift(0x3400 + freq1_lsbs_l);
dds_byte_shift(0x2500 + freq1_lsbs_h);
dds_byte_shift(0x3600 + freq1_msbs_l);
dds_byte_shift(0x2700 + freq1_msbs_h);
dds_byte_shift(0x9000); //10 01 000000000000
//SYNC SELSRC
dds_byte_shift(0xc000); //11 000 00000000000
//SLEEP RESET CLR
//dds_byte_shift(0x5555);
}
static void dds_freq_adjust(unsigned long freq_reg0, unsigned long freq_reg1)
{
unsigned char ll0, lh0, hl0, hh0;
unsigned char ll1, lh1, hl1, hh1;
printk(KERN_ALERT "Adjust DDS frequency0: %08lx\n", freq_reg0);
printk(KERN_ALERT "Adjust DDS frequency1: %08lx\n", freq_reg1);
ll0 = (freq_reg0 >> 0) & 0x000000ff;
lh0 = (freq_reg0 >> 8) & 0x000000ff;
hl0 = (freq_reg0 >> 16) & 0x000000ff;
hh0 = (freq_reg0 >> 24) & 0x000000ff;
ll1 = (freq_reg1 >> 0) & 0x000000ff;
lh1 = (freq_reg1 >> 8) & 0x000000ff;
hl1 = (freq_reg1 >> 16) & 0x000000ff;
hh1 = (freq_reg1 >> 24) & 0x000000ff;
dds_freq_process(ll0, lh0, hl0, hh0, ll1, lh1, hl1, hh1);
}
复制代码
( 4.2 )读写 FPGA 的 GPMC 驱动程序
这里面最关键的几个函数是:
(A) 设置 GPMC 相关寄存器的函数: fpga_gpmc_init ( 对应的释放函数为 fpga_gpmc_exit ),其关键代码是对 6 个 GPMC 配置基础的设置,如下标红部分:
static int fpga_gpmc_init(void)
{
u32 l;
int ret = -EINVAL;
gpmc = kmalloc(sizeof(struct gpmc), GFP_KERNEL);
if (!gpmc){
ret = -ENOMEM;
goto err_kmalloc;
}
// printk(KERN_ALERT "gpmc: %p, gpmc->mem_root: %p, gpmc->cs_mem: %p\n",
// gpmc, &gpmc->mem_root, gpmc->cs_mem);
printk(KERN_ALERT "gpmc: %p, gpmc_mem_root: %p, gpmc_cs_mem: %p\n",
gpmc, &gpmc_mem_root, gpmc_cs_mem);
gpmc->phys_base = AM33XX_GPMC_BASE;
gpmc->memsize = AM33XX_GPMC_SIZE;
if (request_mem_region(gpmc->phys_base,
gpmc->memsize, "gpmc") == NULL) {
// if (request_mem_region(AM33XX_GPMC_BASE,
// AM33XX_GPMC_SIZE, "gpmc") == NULL) {
ret = -ENOMEM;
printk(KERN_ALERT "Failed to request memory region\n");
goto err_mem;
}
gpmc->io_base = ioremap(gpmc->phys_base, gpmc->memsize);
// gpmc->io_base = ioremap(AM33XX_GPMC_BASE, AM33XX_GPMC_SIZE);
if (!gpmc->io_base) {
ret = -ENOMEM;
printk(KERN_ALERT "Failed to ioremap memory\n");
goto err_remap;
}
printk(KERN_ALERT "GPMC physical base: %08lx, GPMC IO base: %p\n", gpmc->phys_base, gpmc->io_base);
// printk(KERN_ALERT "GPMC physical base: %08lx, GPMC IO base: %p\n", AM33XX_GPMC_BASE, gpmc->io_base);
spin_lock_init(&gpmc->mem_lock);
//Configure GPMC registers
printk(KERN_ALERT "*****Configure GPMC registers*****\n");
l = gpmc_read_reg(GPMC_REVISION);
printk(KERN_ALERT "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
gpmc_write_reg(GPMC_IRQENABLE, 0x0000);//Interrupts are masked
gpmc_write_reg(GPMC_TIMEOUT_CONTROL, 0x0000);//TimeOut feature is disabled
printk(KERN_ALERT "SYNC_NOR_CONFIG1: %08x\n", SYNC_NOR_CONFIG1);
printk(KERN_ALERT "SYNC_NOR_CONFIG2: %08x\n", SYNC_NOR_CONFIG2);
printk(KERN_ALERT "SYNC_NOR_CONFIG3: %08x\n", SYNC_NOR_CONFIG3);
printk(KERN_ALERT "SYNC_NOR_CONFIG4: %08x\n", SYNC_NOR_CONFIG4);
printk(KERN_ALERT "SYNC_NOR_CONFIG5: %08x\n", SYNC_NOR_CONFIG5);
printk(KERN_ALERT "SYNC_NOR_CONFIG6: %08x\n", SYNC_NOR_CONFIG6);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG1, SYNC_NOR_CONFIG1);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG2, SYNC_NOR_CONFIG2);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG3, SYNC_NOR_CONFIG3);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG4, SYNC_NOR_CONFIG4);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG5, SYNC_NOR_CONFIG5);
gpmc_cs_write_reg(GPMC_CS, GPMC_CS_CONFIG6, SYNC_NOR_CONFIG6);
l = gpmc_cs_read_reg(GPMC_CS, GPMC_CS_CONFIG7);
printk(KERN_ALERT "Before CS, GPMC_CS_CONFIG7: %08x\n", l);
gpmc_mem_init();
return 0;
err_remap:
release_mem_region(gpmc->phys_base, gpmc->memsize);
// release_mem_region(AM33XX_GPMC_BASE, AM33XX_GPMC_SIZE);
err_mem:
kfree(gpmc);
err_kmalloc:
return ret;
}
复制代码
这 6 个寄存器的值如何设置需要非常详细地阅读《 AM335x ARM ®Cortex™-A8 Microprocessors(MPUs) TechnicalReferenceManual 》文档的 7.1 GPMC 部分,驱动中给出了这 6 个寄存器设置值的详细含义说明,如下代码所示:
/* GPMC register offsets */
#define GPMC_REVISION 0x00
#define GPMC_SYSCONFIG 0x10
#define GPMC_SYSSTATUS 0x14
#define GPMC_IRQSTATUS 0x18
#define GPMC_IRQENABLE 0x1c
#define GPMC_TIMEOUT_CONTROL 0x40
#define GPMC_ERR_ADDRESS 0x44
#define GPMC_ERR_TYPE 0x48
#define GPMC_CONFIG 0x50
#define GPMC_STATUS 0x54
#define GPMC_PREFETCH_CONFIG1 0x1e0
#define GPMC_PREFETCH_CONFIG2 0x1e4
#define GPMC_PREFETCH_CONTROL 0x1ec
#define GPMC_PREFETCH_STATUS 0x1f0
#define GPMC_ECC_CONFIG 0x1f4
#define GPMC_ECC_CONTROL 0x1f8
#define GPMC_ECC_SIZE_CONFIG 0x1fc
#define GPMC_ECC1_RESULT 0x200
#define GPMC_ECC_BCH_RESULT_0 0x240
#define GPMC_CS0_OFFSET 0x60
#define GPMC_CS_SIZE 0x30
#define GPMC_MEM_START 0x00000000
#define GPMC_MEM_END 0x3FFFFFFF
#define BOOT_ROM_SPACE 0x100000 /* 1MB */
#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
#define GPMC_SECTION_SHIFT 28 /* 128 MB */
#define CS_NUM_SHIFT 24
#define ENABLE_PREFETCH (0x1 << 7)
#define DMA_MPU_MODE 2
#define AM33XX_GPMC_BASE 0x50000000
#define AM33XX_GPMC_SIZE SZ_16M
#define GPMC_CS 1
#define FPGA_SIZE SZ_512
#define GPMCFCLKDIVIDER 0<<0//GPMC_CLK frequency = GPMC_FCLK frequency
#define TIMEPARAGRANULARITY 0<<4//脳1 latencies
#define MUXADDDATA 0<<8//Non-multiplexed attached device
#define DEVICETYPE 0<<10//NOR Flash like, asynchronous and synchronous devices
#define DEVICESIZE 1<<12//16 bit
#define WAITPINSELECT 0<<16//WAIT input pin is WAIT0
#define WAITMONITORINGTIME 0<<18//WAIT pin is monitored with valid data
#define WAITWRITEMONITORING 0<<21//WAIT pin is not monitored for write accesses
#define WAITREADMONITORING 0<<22//WAIT pin is not monitored for read accesses
#define ATTACHEDDEVICEPAGELENGTH 2<<23//Specifies the attached device page (burst) length (1 Word = Interface size), 16Words
#define CLKACTIVATIONTIME 0<<25//First rising edge of GPMC_CLK at start access time
#define WRITETYPE 1<<27//Write Synchronous
#define WRITEMULTIPLE 1<<28//Selects the write single or multiple access, Single access
#define READTYPE 1<<29//Read Synchronous
#define READMULTIPLE 1<<30//Selects the read single or multiple access, Single access
#define WRAPBURST 1<<31//Synchronous wrapping burst not supported
#define SYNC_NOR_CONFIG1 WRAPBURST | \
READMULTIPLE | READTYPE | WRITEMULTIPLE | WRITETYPE | \
CLKACTIVATIONTIME | \
ATTACHEDDEVICEPAGELENGTH | \
WAITREADMONITORING | WAITWRITEMONITORING | WAITMONITORINGTIME | WAITPINSELECT | \
DEVICESIZE | DEVICETYPE | MUXADDDATA | \
TIMEPARAGRANULARITY | GPMCFCLKDIVIDER
#define CSONTIME 1<<0//CS# assertion time from start cycle time, 1 GPMC_FCLK cycle
#define CSEXTRADELAY 0<<7//CS i Timing control signal is not delayed
#define CSRDOFFTIME 15<<8//CS# de-assertion time from start cycle time for read accesses, 15 GPMC_FCLK cycles
#define CSWROFFTIME 15<<16//CS# de-assertion time from start cycle time for write accesses, 15 GPMC_FCLK cycles
#define SYNC_NOR_CONFIG2 CSWROFFTIME | CSRDOFFTIME | CSEXTRADELAY | CSONTIME
#define ADVONTIME 1<<0//ADV# assertion time from start cycle time, 1 GPMC_FCLK cycle
#define ADVAADMUXONTIME 0<<4//ADV# assertion for first address phase when using the AAD-Multiplexed protocol
#define ADVEXTRADELAY 0<<7//ADV Timing control signal is not delayed
#define ADVRDOFFTIME 15<<8//ADV# de-assertion time from start cycle time for read accesses, 15 GPMC_FCLK cycles
#define ADVWROFFTIME 15<<16//ADV# de-assertion time from start cycle time for write accesses, 15 GPMC_FCLK cycles
#define ADVAADMUXRDOFFTIME 0<<24//ADV# de-assertion for first address phase when using the AAD-Mux protocol for read accesses
#define ADVAADMUXWROFFTIME 0<<28//ADV# de-assertion for first address phase when using the AAD-Mux protocol for write accesses
#define SYNC_NOR_CONFIG3 ADVAADMUXWROFFTIME | ADVAADMUXRDOFFTIME | \
ADVWROFFTIME | ADVRDOFFTIME | ADVEXTRADELAY | ADVAADMUXONTIME | ADVONTIME
#define OEONTIME 1<<0//OE# assertion time from start cycle time
#define OEAADMUXONTIME 0<<4//OE# assertion time for the first address phase in an AAD-Multiplexed access
#define OEEXTRADELAY 0<<7//OE Timing control signal is not delayed
#define OEOFFTIME 15<<8//OE# de-assertion time from start cycle time
#define OEAADMUXOFFTIME 0<<13//OE# de-assertion time for the first address phase in an AAD-Multiplexed access
#define WEONTIME 1<<16//WE# assertion time from start cycle time
#define WEEXTRADELAY 0<<23//WE Timing control signal is not delayed
#define WEOFFTIME 15<<24//WE# de-assertion time from start cycle time
#define SYNC_NOR_CONFIG4 WEOFFTIME | WEEXTRADELAY | WEONTIME | \
OEAADMUXOFFTIME | OEOFFTIME | OEEXTRADELAY | OEAADMUXONTIME |OEONTIME
#define RDCYCLETIME 15<<0//Total read cycle time
#define WRCYCLETIME 15<<8//Total write cycle time
#define RDACCESSTIME 12<<16//Delay between start cycle time and first data valid
#define PAGEBURSTACCESSTIME 3<<24//Delay between successive words in a multiple access
#define SYNC_NOR_CONFIG5 PAGEBURSTACCESSTIME | RDACCESSTIME | WRCYCLETIME | RDCYCLETIME
#define BUSTURNAROUND 3<<0//Bus turn around latency between two successive accesses to the same chip-select (read to write) or to a different chip-select (read to read and read to write)
#define CYCLE2CYCLEDIFFCSEN 1<<6//Add Cycle2CycleDelay between two successive accesses to a different chip-select (any access type)
#define CYCLE2CYCLESAMECSEN 1<<7//Add Cycle2CycleDelay between two successive accesses to the same chip-select (any access type)
#define CYCLE2CYCLEDELAY 3<<8//Chip select high pulse delay between two successive accesses
#define WRDATAONADMUXBUS 3<<16//Specifies on which GPMC.FCLK rising edge the first data of the synchronous burst write is driven in the add/data multiplexed bus
#define WRACCESSTIME 12<<24//Delay from StartAccessTime to the GPMC.FCLK rising edge corresponding the the GPMC.CLK rising edge used by the attached memory for the first data capture
#define SYNC_NOR_CONFIG6 WRACCESSTIME | WRDATAONADMUXBUS | \
CYCLE2CYCLEDELAY | CYCLE2CYCLESAMECSEN | CYCLE2CYCLEDIFFCSEN | \
BUSTURNAROUND
复制代码
这些设置确实很繁琐,所以真的需要仔细阅读下文档。
(B)!!!用于申请 GPMC片选的函数:
gpmc_cs_request (对应的释放函数为 gpmc_cs_free )得到申请到的 GPMC 物理地址空间 fpga_phy_base , fpga_cs_request (对应的释放函数为 fpga_cs_free )根据上述物理地址空间 fpga_phy_base 最终获得操作 GPMC 的虚拟地址空间 fpga_vir_base 。
(C)GPMC读写函数:
写函数,在设置 FPGADDS波形数据及频率控制字的时候应用层会调用该函数,代码如下:
static ssize_t fpgadev_write(struct file *p_file, const char __user *u_buf, size_t size, loff_t *p_pos)
{
size_t len = FPGADEV_SIZE;
int i;
int tmp;
struct fpgadev *p_fpgadev = p_file->private_data;
if (size == 0)
return 0;
if (len > size)
len = size;
memset(p_fpgadev->m_buf, 0, FPGADEV_SIZE);
if (copy_from_user(p_fpgadev->m_buf, u_buf, len))
return -EFAULT;
for (i=0; i<len; i=i+2)
{
tmp = (p_fpgadev->m_buf[i]) | ((p_fpgadev->m_buf[i+1])<<8);
writew(tmp, fpga_vir_base+i);
printk(KERN_ALERT "*****Write*****%p, %04x\n", fpga_vir_base+i, tmp);
}
return 0;
} 复制代码 读函数,在数据采集读取采集的数据时会调用该函数,代码如下,特别注意标红加粗的部分:
static ssize_t fpgadev_read(struct file *p_file, char __user *u_buf, size_t size, loff_t *p_pos)
{
size_t len = FPGADEV_SIZE;
int i;
int tmp;
struct fpgadev *p_fpgadev = p_file->private_data;
if (size == 0)
return 0;
if (len > size)
len = size;
if (*p_pos > 0)
return 0;
memset(p_fpgadev->m_buf, 0, FPGADEV_SIZE);
down(&sync_sema);//wait until read enabled
for (i=0; i<len; i=i+2)
{
tmp = readw(fpga_vir_base + i);
p_fpgadev->m_buf[i] = tmp&0xff;
p_fpgadev->m_buf[i+1] = (tmp>>8)&0xff;
//printk(KERN_ALERT "*****Read*****%p, %04x\n", fpga_vir_base+i, tmp);
}
gpio_set_value(GPIO_RSTN, 1);//enable write
if (copy_to_user(u_buf, p_fpgadev->m_buf, len))
return -EFAULT;
return 0;
} 复制代码
sync_sema是一个初值为0的信号量,如果没有数据可读,读函数会进入阻塞状态,在FPGA采集完一行数据后会产生一个RD_INT_PULSE正脉冲信号,该正脉冲信号会引起BB发生外部IO中断,中断处理函数会up sync_sema信号量,从而触发一次读操作,外部中断处理函数会同时清零WDRDN(对应代码中的GPIO_RSTN),使能读缓存失能写缓存,在读函数完成读操作后会置一WDRDN,使能写缓存失能读缓存,WDRDN信号是控制读写数据缓的信号,在高电平期间FPGA将采集的数据写入缓存,在低电平期间BB从缓存中读取数据,这时FPGA不会写缓存,从而保证了读写缓存不会发生错乱。外部中断处理函数代码如下:
static irqreturn_t irq_handler(int irq, void *dev_id)
{
disable_irq_nosync(irq_no);
up(&sync_sema);
gpio_set_value(GPIO_RSTN, 0);//enable read
enable_irq(irq_no);
return IRQ_HANDLED;
}
复制代码
( 5 ) BB 应用层程序流程如图 7 所示:
图 7: BB 应用程序简易流程图
( 6 )附件 2 为 BB 端的全部源代码:
附件 2: DDS_DAQ_BB.rar
( 6.1 ) 其目录树如下所示:
root@gao:~/bone-fs/home/root/DDS_DAQ_BB# tree
.
├── APP(应用程序)
│ ├── canbus.c
│ ├── canbus.o
│ ├── canconfig.c
│ ├── can_config.h
│ ├── canconfig.o
│ ├── candump.c
│ ├── candump.o
│ ├── cansend.c
│ ├── cansend.o
│ ├── dds.c
│ ├── dds.o
│ ├── ethernet.c
│ ├── ethernet.o
│ ├── libsocketcan.a
│ ├── lscm_debug.h
│ ├── lscm_protocol.h
│ ├── main
│ ├── main.c
│ ├── main.o
│ └── Makefile
├── board-am335xevm.c(板文件)
├── DDS_DRV(DDS芯片驱动程序)
│ ├── ddsdev.c
│ ├── ddsdev.ko
│ ├── ddsdev.mod.c
│ ├── ddsdev.mod.o
│ ├── ddsdev.o
│ ├── Makefile
│ ├── modules.order
│ ├── Module.symvers
│ ├── test_ddsdev
│ └── test_ddsdev.c
└── GPMC_DRV(GPMC FPGA驱动程序)
├── fpgadev.c
├── fpgadev.ko
├── fpgadev.mod.c
├── fpgadev.mod.o
├── fpgadev.o
├── Makefile
├── modules.order
├── Module.symvers
├── test_fpgadev
└── test_fpgadev.c
3 directories, 41 files 复制代码
( 6.2 ) BB 端源代码的编译过程如下:
( A )应用程序编译: root@gao:~/bone-fs/home/root/DDS_DAQ_BB# ls
APP board-am335xevm.c DDS_DRV GPMC_DRV
root@gao:~/bone-fs/home/root/DDS_DAQ_BB# cd APP
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/APP# ls
canbus.c can_config.h cansend.c ethernet.c lscm_debug.h main.c
canconfig.c candump.c dds.c libsocketcan.a lscm_protocol.h Makefile
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/APP# make
arm-arago-linux-gnueabi-gcc -c main.c
arm-arago-linux-gnueabi-gcc -c ethernet.c
arm-arago-linux-gnueabi-gcc -c canbus.c
arm-arago-linux-gnueabi-gcc -c dds.c
arm-arago-linux-gnueabi-gcc -c canconfig.c
arm-arago-linux-gnueabi-gcc -c cansend.c
arm-arago-linux-gnueabi-gcc -c candump.c
arm-arago-linux-gnueabi-gcc -o main main.o \
ethernet.o canbus.o \
dds.o \
canconfig.o cansend.o candump.o libsocketcan.a \
-lpthread \
-lm 复制代码 ( B ) GPMC FPGA 设备驱动程序编译: root@gao:~/bone-fs/home/root/DDS_DAQ_BB/APP# cd ../GPMC_DRV/
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV# ls
fpgadev.c Makefile test_fpgadev.c
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV# make
make -C /root/bone-linux M=/root/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV modules ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi-
make[1]: 正在进入目录 `/root/ti-sdk-am335x-evm/board-support/linux-3.2.0-psp04.06.00.08.sdk'
CC [M] /root/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV/fpgadev.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV/fpgadev.mod.o
LD [M] /root/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV/fpgadev.ko
make[1]:正在离开目录 `/root/ti-sdk-am335x-evm/board-support/linux-3.2.0-psp04.06.00.08.sdk'
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV# make app
arm-arago-linux-gnueabi-gcc test_fpgadev.c -o test_fpgadev 复制代码 ( C ) DDS 芯片驱动程序编译: root@gao:~/bone-fs/home/root/DDS_DAQ_BB/GPMC_DRV# cd ../DDS_DRV/
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/DDS_DRV# ls
ddsdev.c Makefile test_ddsdev.c
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/DDS_DRV# make
make -C /root/bone-linux M=/root/bone-fs/home/root/DDS_DAQ_BB/DDS_DRV modules ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi-
make[1]: 正在进入目录 `/root/ti-sdk-am335x-evm/board-support/linux-3.2.0-psp04.06.00.08.sdk'
CC [M] /root/bone-fs/home/root/DDS_DAQ_BB/DDS_DRV/ddsdev.o
Building modules, stage 2.
MODPOST 1 modules
CC /root/bone-fs/home/root/DDS_DAQ_BB/DDS_DRV/ddsdev.mod.o
LD [M] /root/bone-fs/home/root/DDS_DAQ_BB/DDS_DRV/ddsdev.ko
make[1]:正在离开目录 `/root/ti-sdk-am335x-evm/board-support/linux-3.2.0-psp04.06.00.08.sdk'
root@gao:~/bone-fs/home/root/DDS_DAQ_BB/DDS_DRV# make app
arm-arago-linux-gnueabi-gcc test_ddsdev.c -o test_ddsdev 复制代码 ( 6.3 ) BB 端程序如下执行: ( A )挂载开发主机文件系统,开发主机的 IP 地址为 192.168.1.106 , BB 的 IP 地址为 192.168.1.2 : root@am335x-evm:~# ifconfig eth0
eth0 Link encap:Ethernet HWaddr D4:94:A1:97:90:BA
inet addr:192.168.1.2 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:98 errors:0 dropped:40 overruns:0 frame:0
TX packets:51 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:23520 (22.9 KiB) TX bytes:4596 (4.4 KiB)
root@am335x-evm:~# ls
fs_mount.sh tftptest
root@am335x-evm:~# ./fs_mount.sh
mount 192.168.1.106/root/bone-fs /mnt/nfs -o nolock,proto=tcp
Can't set permissions on mtab: Operation not permitted
root@am335x-evm:~# cd /mnt/nfs/home/root/DDS_DAQ_BB/ 复制代码 ( B )加载驱动程序: root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB# ls
APP DDS_DRV GPMC_DRV board-am335xevm.c
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB# cd DDS_DRV/
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/DDS_DRV# ls
Makefile ddsdev.ko ddsdev.o test_ddsdev.c
Module.symvers ddsdev.mod.c modules.order
ddsdev.c ddsdev.mod.o test_ddsdev
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/DDS_DRV# insmod ddsdev.ko
[ 231.552669] *****Init*****
[ 231.555528] GPIO_SCLK is valid return: 1
[ 231.559650] GPIO_SDATA is valid return: 1
[ 231.563911] GPIO_FSYNC is valid return: 1
[ 231.568135] Request GPIO_SCLK return: 0
[ 231.572184] Request GPIO_SDATA return: 0
[ 231.576308] Request GPIO_FSYNC return: 0
[ 231.580434] GPIO_SCLK set output return: 0
[ 231.584881] GPIO_SDATA set output return: 0
[ 231.589283] GPIO_FSYNC set output return: 0
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/DDS_DRV# cd ../GPMC_DRV/
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/GPMC_DRV# ls
Makefile fpgadev.ko fpgadev.o test_fpgadev.c
Module.symvers fpgadev.mod.c modules.order
fpgadev.c fpgadev.mod.o test_fpgadev
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/GPMC_DRV# insmod fpgadev.ko
[ 268.803402] *****Init*****
[ 268.809626] GPIO_EINT is valid return: 1
[ 268.813844] GPIO_RSTN is valid return: 1
[ 268.817976] Request GPIO_EINT return: 0
[ 268.822024] Request GPIO_RSTN return: 0
[ 268.826059] GPIO_RSTN set input return: 0
[ 268.830276] GPIO_RSTN set output return: 0
[ 268.834599] EINT irq: 221
[ 268.837359] Set EINT rising edge return: 0
[ 268.841805] Request irq return: 0(0)
[ 268.845572] gpmc: cee42680, gpmc_mem_root: bf016624, gpmc_cs_mem: bf016544
[ 268.853412] GPMC physical base: 50000000, GPMC IO base: d1000000
[ 268.859727] *****Configure GPMC registers*****
[ 268.864420] GPMC revision 6.0
[ 268.867537] SYNC_NOR_CONFIG1: f9001000
[ 268.871476] SYNC_NOR_CONFIG2: 000f0f01
[ 268.875428] SYNC_NOR_CONFIG3: 000f0f01
[ 268.879367] SYNC_NOR_CONFIG4: 0f010f01
[ 268.883339] SYNC_NOR_CONFIG5: 030c0f0f
[ 268.887279] SYNC_NOR_CONFIG6: 0c0303c3
[ 268.891220] Before CS, GPMC_CS_CONFIG7: 00000f00
[ 268.896091] *****Request GPMC CS*****
[ 268.899949] Got GPMC CS1, FPGA physical base: 01000000
[ 268.905364] After CS, GPMC_CS_CONFIG7: 00000f41
[ 268.910149] FPGA virtual base: d087e000 复制代码 ( C )运行应用程序 main 可执行文件: root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/GPMC_DRV# cd ../APP/
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/APP# ls
Makefile canconfig.o dds.c lscm_debug.h
can_config.h candump.c dds.o lscm_protocol.h
canbus.c candump.o ethernet.c main
canbus.o cansend.c ethernet.o main.c
canconfig.c cansend.o libsocketcan.a main.o
root@am335x-evm:/mnt/nfs/home/root/DDS_DAQ_BB/APP# ./main
this is main function.
socket ok.
bind ok.
listen.
server_bind_listen ok, server_ip: 192.168.1.2, server_port: 5000.
pthread_create ok, thread id: 1086289008.
accept thread is waiting a client to connect...... 复制代码 下一篇: BB方案大结局之FPGA端软件实现篇—— 基于BB及FPGA的DAQ及DDS设计与实现