cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
30,648 Views
Registered: ‎03-27-2014

Re: how to read/write from/to a register in Linux?


I have a design which is working well. Till now i am writing my c program in sdk for standalone version and launching through JTAG.

But now I would like to know that if I use linux OS and want to read and write to specific registers how could I do it ?

 

this subject has been discussed many times,

 

in a baremetal apps you can directly address physical addresses,

on Linux you can only use a virtual address mapped to the physical address.

 

That means you can't do stuff like this anymore

(unsigned int*)(FPGA_BASE+0x04) = 0x01; -- write example
val = (unsigned char *)(FPGA_BASE+0x00); -- reading one byte

 

you can use the /dev/mem driver which allows you to address physical addresses  from userspace

fd = open ("/dev/mem", O_RDWR);
page_addr = (fpga_base_addr & (~(page_size-1))); 
page_offset = fpga_base_addr - page_addr;
virtual_address = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, page_addr); //memory map

 see this page for nice tutorials mmap

 

this job is usually done in the kernel space by a driver, here's how to map a virtual pointer to a physical address retrieved from the devicetree

sdev->regs = devm_ioremap_resource(&pdev->dev, res);
if(IS_ERR(sdev->regs)){
     printk(KERN_ERR "devm_ioremap failed for %s\n",
          sdev->name);
     status = -ENOMEM;
     goto free_dev_name;
}

 

gw.
Embedded Systems, DSP, cyber
2 Replies
Highlighted
Observer
Observer
3,169 Views
Registered: ‎09-06-2018

Hi,

I followed your instructions to read the register of the global timer (physical address 0xF8F00200 defined in xparameter.h)

so, I open the /dev/mem file as follow:

 

int memfd;
	memfd = open("/dev/mem", O_RDWR | O_SYNC); // to open this, the program needs to be run as root
	if (memfd == -1) {
		printf("Can't open /dev/mem.\n");
		exit(0);
	}

to provide the virtual address, I use a custom function as follow:

 

 

void *getvaddr(int phys_addr, int memfd) {
	void *mapped_base;

	void *mapped_dev_base;
	off_t dev_base = phys_addr;



	// Map one page of memory into user space such that the device is in that page, but it may not
	// be at the start of the page

	mapped_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd,
			dev_base & ~MAP_MASK);
	if (mapped_base == (void *) -1) {
		printf("Can't map the memory to user space.\n");
		exit(0);
	}

	// get the address of the device in user space which will be an offset from the base
	// that was mapped as memory is mapped at the start of the page

	mapped_dev_base = mapped_base + (dev_base & MAP_MASK);
	return mapped_dev_base;
}

Then I initialized a variable as follow:

 

 

int *global_timer_addr = getvaddr(XPAR_PS7_GLOBALTIMER_0_S_AXI_BASEADDR, memfd);
	int *timer_0 = global_timer_addr;

I'm using a while statement to test the timer register as follow:

while (1) {
		if (*timer_0 > 333333333) {
			SetLedPin();
			*timer_0 = 0;
		}
		else
			ClearLedPin();
	}

I have no problem in reading *timer0 but whe I attempt to write 0 value in *timer, my MicroZed freezes and I need to hardware reset the board.

Do you have any idea how to solve it?

Thank you for your support.

 

0 Kudos
Highlighted
Explorer
Explorer
1,115 Views
Registered: ‎02-15-2019

有人解决这个问题吗?
0 Kudos