Difference between revisions of "FPGA registers access from Linux userspace"

From ArmadeusWiki
Jump to: navigation, search
m (fpgaregs user binary)
Line 1: Line 1:
 
[[Category:FPGA]]
 
[[Category:FPGA]]
  
 +
= fpgaregs =
  
==Changing FPGA IP's registers from Linux user space with fpgaregs==
 
  
 +
== compile ==
 +
To access FPGA registers a tool named ''fpgaregs'' is available under ''target/linux/module/fpga/dev_tools/'' directory. To compile it for apf9328, use the command above :
  
This tool allows you to access FPGA registers from linux userspace/console. This way you can easily debug your driver and your IP directly from the Linux console.
+
<source lang="bash">
 +
arm-linux-gcc -mcpu=arm920t fpgaregs.c -o fpgaregs
 +
</source>
  
=== fpgaaccess driver ===
+
== use ==
First, you have to compile fpgaaccess driver, select it from linux-menuconfig menu (Device Drivers ---> Armadeus specific drivers  ---> FPGA Drivers  ---> Armadeus fpgaaccess driver) :
+
$ make linux-menuconfig
+
  
You can select it under kernel or as module then compile it:
+
fpgaregs can be used to read and write 16 or 32 bits registers.
$ make
+
  
If you choose module (M) you have to insert it in kernel (the module is in armadeus/target/linux/modules/fpga/fpgaaccess/fpgaaccess.ko):
+
'''read 16 bits'''
$ insmod fpgaaccess.ko
+
<source lang="bash">
 +
fpgaregs w <address>
 +
</source>
  
This will load a characters device, you can find Major and minor number in dmesg :
+
Where <address> is an address relative to fpga mapping in hexadecimal value.
  
$ dmesg | grep fpgaaccess
+
'''write 16 bits'''
fpgaaccess: MAJOR: 250 MINOR: 0
+
<source lang="bash">
 +
fpgaregs w <address> <value>
 +
</source>
  
Then make the node :
+
Where <value> is hexadecimal value to write.
$ mknod /dev/fpgaaccess c 250 0
+
  
=== fpgaregs user binary ===
+
'''read 32 bits'''
 +
<source lang="bash">
 +
fpgaregs l <address>
 +
</source>
  
If you want you can use the driver with system call '''pread()''' and '''pwrite()''', but it easiest to use the program provided by driver : fpgaregs.
+
'''write 32 bits'''
 +
<source lang="bash">
 +
fpgaregs l <address> <value>
 +
</source>
  
To compile it, go to ''target/linux/module/fpga/fpgaaccess'' directory then make it :
+
= the mmap problem =
$ make fpgaregs
+
  
The generated file is located in ''target/linux/module/fpga/fpgaaccess''. Now you can copy it on your target.
+
To access fpga register, fpgaregs use the ''mmap()'' system call :
Then in linux, launch it like that:
+
*for read:
+
# fpgaregs w hex_address or fpgaregs l hex_address where 'w' means a 16bits access and 'l' a 32bits access
+
*for write
+
# fpgaregs w hex_address hex_value or fpgaregs l hex_address hex_value
+
  
*Examples:
+
<source lang="c">
 +
ptr_fpga = mmap (0, 8192, PROT_READ|PROT_WRITE, MAP_SHARED, ffpga, FPGA_ADDRESS);
 +
</source>
  
** Read a 32bits register at internal FPGA address 0x0010:
+
Thanks to this function, fpga registers are accessible directly on memory with pointer ptr_fpga. To read and write in 16bits or in 32 bits we will cast the pointer value in ''unsigned short'' or ''unsigned int'' :
  
# fpgaregs l 0x10
+
'''16bits'''
 +
''write''
 +
<source lang="c">
 +
        *(unsigned short*)(ptr_fpga+(address)) = (unsigned short)value;
 +
</source>
 +
''read''
 +
<source lang="c">
 +
          value = *(unsigned short*)(ptr_fpga+(address));
 +
</source>
  
** Write 0x0123 (16bits) to FPGA register 0x0020:
+
'''32 bits'''
 +
''write''
 +
<source lang="c">
 +
        *(unsigned short*)(ptr_fpga+(address)) = (unsigned short)value;
 +
</source>
  
# fpgaregs w 0x20 0x0123
+
''read''
 +
<source lang="bash">
 +
          value = *(unsigned int*)(ptr_fpga+(address));
 +
</source>
 +
 
 +
== The problem ==
 +
 
 +
By default, if the exact ARM920t name is not given, gcc will try to generate compatible read/write for all arm model when it access register in 16bits. Because not all ARM9 has 16bits read/write capabilities.
 +
 
 +
But the interface between i.MX and fpga on apf9328 has no 8bits read/write capabilities, then each 8 bits access is recognized by fpga as 16bits access. On each 16bits access, i.MX will then do two 16bits access instead of 1.
 +
 
 +
To avoid this painful problem don't forget the ''-mcpu=arm920t'' option when compile ''fpgaregs'' for apf9328.

Revision as of 10:12, 19 November 2008


fpgaregs

compile

To access FPGA registers a tool named fpgaregs is available under target/linux/module/fpga/dev_tools/ directory. To compile it for apf9328, use the command above :

arm-linux-gcc -mcpu=arm920t fpgaregs.c -o fpgaregs

use

fpgaregs can be used to read and write 16 or 32 bits registers.

read 16 bits

fpgaregs w <address>

Where <address> is an address relative to fpga mapping in hexadecimal value.

write 16 bits

fpgaregs w <address> <value>

Where <value> is hexadecimal value to write.

read 32 bits

fpgaregs l <address>

write 32 bits

fpgaregs l <address> <value>

the mmap problem

To access fpga register, fpgaregs use the mmap() system call :

ptr_fpga = mmap (0, 8192, PROT_READ|PROT_WRITE, MAP_SHARED, ffpga, FPGA_ADDRESS);

Thanks to this function, fpga registers are accessible directly on memory with pointer ptr_fpga. To read and write in 16bits or in 32 bits we will cast the pointer value in unsigned short or unsigned int :

16bits write

        *(unsigned short*)(ptr_fpga+(address)) = (unsigned short)value;

read

          value = *(unsigned short*)(ptr_fpga+(address));

32 bits write

        *(unsigned short*)(ptr_fpga+(address)) = (unsigned short)value;

read

          value = *(unsigned int*)(ptr_fpga+(address));

The problem

By default, if the exact ARM920t name is not given, gcc will try to generate compatible read/write for all arm model when it access register in 16bits. Because not all ARM9 has 16bits read/write capabilities.

But the interface between i.MX and fpga on apf9328 has no 8bits read/write capabilities, then each 8 bits access is recognized by fpga as 16bits access. On each 16bits access, i.MX will then do two 16bits access instead of 1.

To avoid this painful problem don't forget the -mcpu=arm920t option when compile fpgaregs for apf9328.