单片机并口总线与FPGA通信

话不多说,直接开讲。
单片机使用的是GD32F450XX 主要功能是用GD32F450的EXMC总线与FPGA通信。初次使用所以网上查了很多资料,其实GD32F450的EXMC与STM32的FSMC相差无几,与FPGA通信我是将FPGA模拟成SRAM进行通信。具体单片机型号是 GD32F450ZIT6。
1,因为官方例程只有SDRAM的初始化所以我贴下SRAM的初始化代码:

void exmc_sram_init()
{
	exmc_norsram_parameter_struct        sdram_init_struct;
    exmc_norsram_timing_parameter_struct  read_write_timing;

    uint32_t command_content = 0, bank_select;
    uint32_t timeout = SDRAM_TIMEOUT;

    /* enable EXMC clock*/
    rcu_periph_clock_enable(RCU_EXMC);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOD);
    rcu_periph_clock_enable(RCU_GPIOE);
    rcu_periph_clock_enable(RCU_GPIOF);
    rcu_periph_clock_enable(RCU_GPIOG);
    rcu_periph_clock_enable(RCU_GPIOH);

    /* common GPIO configuration */
	
	/* NL(PB7), pin configuration */ 
    gpio_af_set(GPIOB, GPIO_AF_12, GPIO_PIN_7 );
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);

    /* D2(PD0),D3(PD1),CLK(PD3),NOE(PD4),NWE(PD5),NWAIT(PD6),NE0(PD7),D13(PD8),D14(PD9),D15(PD10),D0(PD14),D1(PD15) pin configuration */
    gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4 | 
								   GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |
                                   GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4 | 
														 GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |
														 GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4 | 
																	 GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |
																	 GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);

    /* NBL0(PE0),NBL1(PE1),D4(PE7),D5(PE8),D6(PE9),D7(PE10),D8(PE11),D9(PE12),D10(PE13),D11(PE14),D12(PE15) pin configuration */
    gpio_af_set(GPIOE, GPIO_AF_12, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_7  | GPIO_PIN_8 |
                                   GPIO_PIN_9  | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
                                   GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_7  | GPIO_PIN_8 |
                                                         GPIO_PIN_9  | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
                                                         GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_7  | GPIO_PIN_8 |
                                                                     GPIO_PIN_9  | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
                                                                     GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);

    /* A0(PF0),A1(PF1),A2(PF2),A3(PF3),A4(PF4),A5(PF5),A6(PF12),A7(PF13),A8(PF14),A9(PF15) pin configuration */
    gpio_af_set(GPIOF, GPIO_AF_12, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3  |
								   GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_12 | GPIO_PIN_13 |
								   GPIO_PIN_14 | GPIO_PIN_15);
    gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3  |
                                                         GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_12 | GPIO_PIN_13 |
                                                         GPIO_PIN_14 | GPIO_PIN_15);
    gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0  | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3  |
																	 GPIO_PIN_4  | GPIO_PIN_5  | GPIO_PIN_12 | GPIO_PIN_13 |
																	 GPIO_PIN_14 | GPIO_PIN_15);

    /* A10(PG0),A11(PG1),A12(PG2),A13(PG3), pin configuration */
    gpio_af_set(GPIOG, GPIO_AF_12, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
    gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);

	/* configure read/write timing */
    read_write_timing.asyn_address_setuptime = 0x0U;					//地址建立时间(ADDSET)为1个HCLK 1/36M=27ns
    read_write_timing.asyn_address_holdtime = 0x0U;						//地址保持时间(ADDHLD)模式A未用到
    read_write_timing.asyn_data_setuptime = 0x08U;						//数据保持时间(DATAST)为9个HCLK 6*9=54ns  
    read_write_timing.bus_latency = 0xFU;								
    read_write_timing.syn_clk_division = EXMC_SYN_CLOCK_RATIO_16_CLK;
    read_write_timing.syn_data_latency = EXMC_DATALAT_17_CLK;
    read_write_timing.asyn_access_mode = EXMC_ACCESS_MODE_A;
	
	/* configure the structure with default values */
    sdram_init_struct.norsram_region = EXMC_BANK0_NORSRAM_REGION0; 		//这里我们使用NE0,也就对应BTCR[0],[1]。
    sdram_init_struct.address_data_mux = DISABLE;				   		//地址和数据复用数据线
    sdram_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM;		   		//SRAM   
    sdram_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;		//存储器数据宽度为16bit 
    sdram_init_struct.burst_mode = DISABLE;								//突发访问模式
    sdram_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;			//设置WAIT信号的有效电平
    sdram_init_struct.wrap_burst_mode = DISABLE;						//是否使用回环模式
    sdram_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;			//设置WAIT信号有效时机
    sdram_init_struct.memory_write = ENABLE;							//存储器写使能 
    sdram_init_struct.nwait_signal = DISABLE;							//是否使用WAIT信号
    sdram_init_struct.extended_mode = DISABLE;							//是否使用扩展模式,扩展模式用于访问不同读写操作时序的存储器
    sdram_init_struct.asyn_wait = DISABLE;								/*!< enable or disable the asynchronous wait function */
    sdram_init_struct.write_mode = EXMC_ASYN_WRITE;						/*!< asynchronous write mode */
	sdram_init_struct.read_write_timing = &read_write_timing;
	sdram_init_struct.write_timing = &read_write_timing;
   

	exmc_norsram_init(&sdram_init_struct);
	exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION0);
	delay_1ms(10);
}

2,因为用的是EXMC的异步通信,一开始对这些概念不是很熟悉,所以自己弄了半天,最后查官方用户手册找到了一张时序表:
在这里插入图片描述
读数据函数:

void sdram_readbuffer_16(uint32_t sdram_device,uint16_t* pbuffer, uint32_t readaddr, uint32_t numtowrite)
{
    uint32_t temp_addr;
    __IO uint32_t write_addr_prt = readaddr;    
    
    /* select the base address according to EXMC_Bank */
//    if(sdram_device == EXMC_SDRAM_DEVICE0){
//        temp_addr = SDRAM_DEVICE0_ADDR;
//    }else{
//        temp_addr = SDRAM_DEVICE1_ADDR;
//    }
    temp_addr = SRAM_DEVICE0_ADDR;
    /* while there is data to read */
    for(; numtowrite != 0; numtowrite--){
        /* read a byte from the memory */
        *pbuffer++ = *(uint16_t*) (temp_addr + write_addr_prt);
    
        /* increment the address */
        write_addr_prt += 2;
    }
}

首先单片机不断发送读地址命令,然后用示波器看看这些引脚上有没有对应的时序输出,如果有了的话再去找FPGA工程师或者自己根据这个时序来读数据,读数据的时候依据EXMC_NOE的电平变换将对应地址的数据放到数据引脚上,这样就能获取数据了

总结:
不要把EXMC看的很复杂,根据用户手册配置好之后读写数据非常方便,就跟读单片机内存一样。
而与FPGA通信用到的EXMC更简单,因为FPGA可以自行编程,所以只需要你这边地址,数据,信号线上有数据,那边就能更改时序进行处理!所以困难不可怕,相信自己!

  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值