This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

GPMC read and write

Other Parts Discussed in Thread: ASH

Hi I actually have a 8 and 16 bit gpmc memory maped region connected to fpga.


my question is how do i go about writing to individual registers within the external devices. say for example i have fpga1 connected to cs region 2 with a base address of 0x02000000 and a size of 10000000. how do i send the register address and the value needed to be written to that register address within the cs region.

how do i go about reading back from that individual register to which i wrote the data to.

Regards

-Parker

  • Your external FPGA registers must be memory mapped within the CS space. Then you can simply R/W to the necessary address.
  • Hi Biser thanks for the quick reply.

    so in case if my cs base address is 0x02000000 and size is 0x01000000 and my bus width is 8bits wde.then i will have to

       
    write_fpga2(int register_add, int reg_value){
    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
       printf("/dev/mem opened.\n");  
       map_base = mmap(0, 0x01000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x02000000);
       __raw_writeb(register number, value);
       close(fd);
    }
    int read_fpga2(int register_add){
    int value;
    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
       printf("/dev/mem opened.\n");
       map_base = mmap(0, 0x01000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x02000000);
      int= __raw_readb(register number);
    close(fd);
    return value;
    }

    is what i am doing correct ??

    regards

    
    

  • Hi,

    This is a user space application, right? If so, what is the implementation of __raw_writeb() & __raw_readb(), as far as I know those are kernel functions.

    Usually, when I want to write something to, lets say, 0x02000000 I've done the following:
    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    printf("/dev/mem opened.\n");
    volatile uint8_t *map_base;
    map_base =(uint8_t *) mmap(0, 0x01000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x02000000);
    volatile uint32_t *p32 = (uint32_t *) &map_base[0x100020];
    p32 = 0xAA00AA00;             //write to 0x02000000
    uint32_t val = *p32;
    printf ("val=%x\n", val);         //read from 0x02000000

    Hope this helps.

    Best Regards,
    Yordan

  • Hi yordan,

    thanks for the reply i have a few questions.

    Yordan Kovachev said:
    volatile uint32_t *p32 = (uint32_t *) &map_base[0x100020]; 

    How did you arrive at value 0x100020 ??

    so does this mean 0x02000000 is actually register 0x00 in my asic ??

    say for instance if i have to write value of 0x02 to address 0x00000004 should i just do

    volatile uint32_t *p32 = (uint32_t *) &map_base[0x100024]; 

    would actually write to address 0x00000004 0n my fpga ??

    regards

    -Parker

  • Hi Parker,

    ash parker said:
    so does this mean 0x02000000 is actually register 0x00 in my asic ??

    Yes, the 0x02000000 is the starting address of the mmaped space, so you can think of it as a register 0x00. 

    To write to address 0x00000004 you can mmap this starting address & use as shown above. 

    ash parker said:
    volatile uint32_t *p32 = (uint32_t *) &map_base[0x100024];

     

    I don't think this will work. After associating p32 with the address of the mmapped address space, you could increment the pointer to point the next address, which in your case is 0x00000004. 

    Best Regards, 
    Yordan

  • Hi Yordan,


    Based on your suggestions i have made some changes to the source code for memory access. but i have problems reading back data written to address registers. to be specific i always read back the data of last write despite me trying to read from various registers. below is a snippet of my source.

    void write1(unsigned char address,unsigned char value)
    {
    	int fd;
    	volatile uint16_t *p1_32;
    	if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1){printf("failed \n");}else{printf("/dev/mem opened.\n");}
    	volatile uint8_t *map_base;
    	map_base =(uint8_t *) mmap(0, 0x01000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x02000000);
    	volatile uint8_t *p32 = (uint8_t *) &map_base[0x100020];
    	*p32 = address;
    	*p32 =value;
    	printf ("addr=%x....val=%x\n",address,value);         //read from 0x02000000
    }
    void readc(unsigned char address)
    {
    	int fd;
    	uint16_t value,i;
    	volatile uint16_t *p1_32;
    	if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1){printf("failed \n");}else{printf("/dev/mem opened.\n");}
    	volatile uint8_t *map_base;
    	map_base =(uint8_t *) mmap(0,0x01000000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x02000000);
    	volatile uint16_t *p32 = (uint16_t *) &map_base[0x100020];
    	value=*p32+address;
    	printf ("addr=%x....val=%x\n",address,value);         //read from 0x02000000
    
    }
    
    int main(int argc, char const *argv[])
    {
    	unsigned int task,i,address,data;
    	task = strtoul(argv[1], 0, 0);
    	if(task==1){
    		write1(0x00,0x01); 
    		write1(0x0a,0x01);
    		write1(0x0b,0x02);
    		write1(0x08,0x03);
    		write1(0x09,0x04);
    	return 0;
    	}
    
    	if(task==2){
    
    		readc(0x0a);
    		readc(0x0b);
    		readc(0x08);
    		readc(0x09);
    	return 0;
    	}
    }

    my console output is always 0x04 for all register reads (which is the last value i wrote to register 0x09

    root@am437x-evm:/bin# ./main 1                                                   
    /dev/mem opened.                                                                
    addr=0....val=1                                                                 
    /dev/mem opened.                                                                
    addr=a....val=1                                                                 
    /dev/mem opened.                                                                
    addr=b....val=2                                                                 
    /dev/mem opened.                                                                
    addr=8....val=3                                                                 
    /dev/mem opened.                                                                
    addr=9....val=4                                                                 
    root@am437x-evm:/bin# ./main 2                                                   
    /dev/mem opened.                                                                
    addr=a....val=04                                                              
    /dev/mem opened.                                                                
    addr=b....val=04                                                              
    /dev/mem opened.                                                                
    addr=8....val=04                                                              
    /dev/mem opened.                                                                
    addr=9....val=04                                                              
    root@am437x-evm:/bin# 

    i have rechecked my timings and the look right. for your reference i am attaching the timing diagram i am trying to achieve.

    any suggestions are welcome

    -Parker

  • *p32 = address;
    *p32 =value;
    

    This code seem nonsense to me.

  • Hi

    inorder to make my chip enable to behave like as described in the timing diagram i had to send the address as one transmission and data as another transmission. that is the reason why i had to do two writes. If you believe thats the wrong way i have even tried to do the following with still the same readbacks.

    	*(p32+address)=value;

    it would be great if you could suggest me what would be the right way of writing if you believe what i am doing is wrong in both the cases.

    -Parker

  • I do not know which address line you are using for the "AD" signal.

    Assuming that you are using A2 as "AD" signal:

    *p32++ = address;

    *p32-- = value;

    If that is not working, I suggest you wrote a kernel driver to access the hardware. This is what everyone does, and it works.

    It may be that the memory you are mapping with mmap() is cachable. This will not work.

  • HI wolfgand

    I dont have any address pins i just use [ad0-ad7] to communicate with the asic. the ad0-ad7 pins act as both address and data bus.the AD signal is address latch enable (ALE_ADV)For the kernel driver i do not see any gpmc.c i n my project folder in ccs project includes.

    Regards
    -Parker

  • If AD == address latch enable, you have a data/address multiplexed bus. So you have to set
    GPMC_CONFIG1_i[11-10] DEVICETYPE field = 00
    GPMC_CONFIG1_i[9-8] MUXADDDATA bit = 10b

    And the access is done via:

    p32[address] = value;

    or
    value = p32[address];

    Regarding kernel drivers: simply wrote your own. It's easy. There is a good book "linux device drivers" available online.
  • Hi Wolfgang

    tried your advice and approach with still the same result. below is my dts





    nor@3,0{
    reg = <3 0 0x00100000>; /* device IO registers */ bank-width = <1>; /*changed to 1*/ gpmc,cs-on-ns = <0>; gpmc,cs-rd-off-ns = <80>; gpmc,cs-wr-off-ns = <80>; gpmc,adv-on-ns = <0>; gpmc,adv-rd-off-ns = <2>; gpmc,adv-wr-off-ns = <2>; gpmc,we-on-ns = <0>; gpmc,we-off-ns = <20>; gpmc,oe-on-ns = <3>; gpmc,oe-off-ns = <30>; gpmc,access-ns = <30>; gpmc,rd-cycle-ns = <40>; gpmc,wr-cycle-ns = <40>; gpmc-mux-add-data=<2>; #address-cells=<2>; #size-cells=<1>;
    }

    regards

    -Parker