Unable to access Znyq AXI BRAM from Linux

0

In my project, data is written to a BRAM (generated through the Block Ram IP generator) from a custom IP. Then, I use an AXI BRAM controller to interface the memory with the AXI bus and make it accessible to the Linux running on the ARM.

The base address for the controller is 0x4200_0000 with a range of 8K (up to 0x4200_1FFF). The memory has 8K positions too, each with a width of 32 bits.

To make sure the access problem isn't in the data generated in my custom IP, I initialize the memory simply numbering each of the 8K address (so address 1 contains 0x01, etc, up to 0x1fff).

The problem comes when attempting to read those values from Linux. Using devmem 0x42000001 on command line returns 0x04000000 and the following:

Alignment trap: devmem (1257) PC=0x0001ca94 Instr=0xe7902005 Address=0xb6f9d2fd FSR 0x011

Which seems to indicate Linux is expecting each address value to map to a byte, not a 32bits word. The alignment traps happen until devmem 0x42000004, which returns 0x00000004, the correct value for the fourth direction, but the values in addresses not multiple of 4 can't be accessed. devmem 0x42000002 returns 0x00040000 (notice the 0x04 shifting) as well as the alignment trap. I found the problem with my original python script which uses mmap to map /dev/mem: I have to read each 4 address values since each individual address seems to map to a byte, but that means I only get one of each four values.

Any ideas on how to properly interface with the AXI controller and the memory behind it?

******* Edit to clarify the issue I have. When in doubt, add a picture:

Figure of the issue

memory
embedded-linux
fpga
xilinx
zynq
asked on Stack Overflow Nov 12, 2018 by Ironil • edited Nov 13, 2018 by Ironil

1 Answer

1

Which seems to indicate Linux is expecting each address value to map to a byte

That is the standard mapping in all modern CPUs. When you use AXI with a data bus wider then 8 bits, the bottom address bits select a byte from the AXI data bus. Go to the ARM website and download the AXI specification.

The base address for the controller is 0x4200_0000 with a range of 8K (up to 0x4200_1FFF). The memory has 8K positions too, each with a width of 32 bits.

That is wrong 8K of 32 bits has an address range of 8K*4 = 0x0000 .. 0x7FFF.

I suggest you re-build the BRAM but use different parameters for the Block Ram IP generator.


I changed the RAM so that the port exposed to the AXI controller operates with 8 bits. .....

Your Zynq AXI bus is probably 32 bits wide. Thus a standard connected memory should be 32 bits wide, where you should have byte-write enables.
If you connect an 8-bit memory to a 32-bit bus and do not, or wrongly adapt the address you may lose 3 out of 4 bytes.

What is not clear to me is which behavior you exactly want.

  1. Standard 8Kx32 bit memory with byte access
    or
  2. 8kx8 bit memory where you have a byte at 0x0, 0x4, 0x8 etc.

In case 2 you should use the AXI address different: you should shift the address bits up two positions so each byte occupies 4 address locations. You also have to decide where to place the byte:

  • LS position only: tie the MS 24 bits to zero

  • MS position only: tie the LS 24 bits to zero

  • Repeated over all 4 locations: replicate the byte four times over the 32 bits.

  • Whatever else you fancy. (It's your hardware, you can do what you want.)

Beware that for any module you connect to an AXI bus, the preceding AXI splitters should be set up to cover the correct address range. But I assume you have none of those.

answered on Stack Overflow Nov 12, 2018 by Oldfart • edited Nov 13, 2018 by Oldfart

User contributions licensed under CC BY-SA 3.0