当前位置:   article > 正文

单片机并口总线与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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/429358
推荐阅读
相关标签
  

闽ICP备14008679号