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:
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.
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.
User contributions licensed under CC BY-SA 3.0