Difference between revisions of "FPGA registers access from Linux userspace"
m (→fpgaregs user binary) |
|||
Line 1: | Line 1: | ||
[[Category:FPGA]] | [[Category:FPGA]] | ||
+ | = 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 : | ||
− | + | <source lang="bash"> | |
+ | arm-linux-gcc -mcpu=arm920t fpgaregs.c -o fpgaregs | ||
+ | </source> | ||
− | === | + | == use == |
− | + | ||
− | + | ||
− | + | fpgaregs can be used to read and write 16 or 32 bits registers. | |
− | + | ||
− | + | '''read 16 bits''' | |
− | + | <source lang="bash"> | |
+ | fpgaregs w <address> | ||
+ | </source> | ||
− | + | Where <address> is an address relative to fpga mapping in hexadecimal value. | |
− | + | '''write 16 bits''' | |
− | + | <source lang="bash"> | |
+ | fpgaregs w <address> <value> | ||
+ | </source> | ||
− | + | Where <value> is hexadecimal value to write. | |
− | + | ||
− | = | + | '''read 32 bits''' |
+ | <source lang="bash"> | ||
+ | fpgaregs l <address> | ||
+ | </source> | ||
− | + | '''write 32 bits''' | |
+ | <source lang="bash"> | ||
+ | fpgaregs l <address> <value> | ||
+ | </source> | ||
− | + | = the mmap problem = | |
− | + | ||
− | + | To access fpga register, fpgaregs use the ''mmap()'' system call : | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | <source lang="c"> | |
+ | ptr_fpga = mmap (0, 8192, PROT_READ|PROT_WRITE, MAP_SHARED, ffpga, FPGA_ADDRESS); | ||
+ | </source> | ||
− | + | 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'' | ||
+ | <source lang="c"> | ||
+ | *(unsigned short*)(ptr_fpga+(address)) = (unsigned short)value; | ||
+ | </source> | ||
+ | ''read'' | ||
+ | <source lang="c"> | ||
+ | value = *(unsigned short*)(ptr_fpga+(address)); | ||
+ | </source> | ||
− | ** | + | '''32 bits''' |
+ | ''write'' | ||
+ | <source lang="c"> | ||
+ | *(unsigned short*)(ptr_fpga+(address)) = (unsigned short)value; | ||
+ | </source> | ||
− | + | ''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.