Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++

How to use the mutex

Altera_Forum
Honored Contributor II
2,238 Views

Hello to everyone i am developing an application with two processor, one is using pure C code and the other one has an uCLinux running in it. 

 

I want them to share the same onchip memory so they can comunicate with each other, i've done with no mutex and it works fine as long as one processor only reads and the other one only writes. 

 

However i want both to be able to read and write from the same onchipmemory, how can i do it using mutex? I haven't understood how to use mutex properly, do i need two mutex (one for each processor) and how should i connect them on Q-Sys? 

 

I've read the altera documentation but it isn't clear for me yet. Thanks
0 Kudos
13 Replies
Altera_Forum
Honored Contributor II
980 Views

You'll need a locking primitive that can be understood by both pieces of code, this effectively means you'll need to write something for the standalone C code and use the same algorithm from withing uCLinux. 

Locking is usually based on a locked 'read-write' bus cycle, however the Nios2 cpu and avalon bus don't support them, so you have to do something else instead. 

The usual solution is Dekker's algorithm which works provided the memory cycles aren't re-ordered. 

Basically you have 1 shared memory location per cpu, to acquire the mutex you: 

a) Loop until all the locations are zero 

b) Write a 1 onto your own location 

c) Check all the other locations are zero - if so you have the lock, if not write back 0, delay a bit and repeat from (a). 

The delays during (c) need to be different for the 2 cpus - otherwise they will collide forever [1]. 

Depending on what you are doing, the 'lock collision' might be treatable as 'nothing to do'. 

 

[1] Ethernet CSMCAD (on coax) uses random backoffs, 2 chips have been known to have synchronised random numbers and backoff forever!
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Thanks for your post dsl. So basically i connect both CPU Data masters to a shared memory and to the mutex slave in QSys. 

 

Then i have to write the C Code in each CPU, my code looks like this: 

 

CPU1: 

/* get the mutex device handle */ alt_mutex_dev* mutex = altera_avalon_mutex_open( "/dev/mutex" ); /* acquire the mutex, setting the value to one */ while(1){ altera_avalon_mutex_lock( mutex, 1 ); if(altera_avalon_mutex_is_mine(mutex)) { IOWR_32DIRECT(SHARED_MEM_BASE, 0x00, 0x54); IOWR_32DIRECT(SHARED_MEM_BASE, 0x04, 0x64); alt_printf("%x\n", IORD_32DIRECT(SHARED_MEM_BASE, 0x00)); alt_printf("%x\n", IORD_32DIRECT(SHARED_MEM_BASE, 0x04)); } altera_avalon_mutex_unlock( mutex ); }  

 

 

CPU2: 

/* get the mutex device handle */ alt_mutex_dev* mutex = altera_avalon_mutex_open( "/dev/mutex" ); /* acquire the mutex, setting the value to one */ while(1){ altera_avalon_mutex_lock( mutex, 1 ); if(altera_avalon_mutex_is_mine(mutex)) { IOWR_32DIRECT(SHARED_MEM_BASE, 0x00, 0x04); IOWR_32DIRECT(SHARED_MEM_BASE, 0x04, 0x14); alt_printf("%x\n", IORD_32DIRECT(SHARED_MEM_BASE, 0x00)); alt_printf("%x\n", IORD_32DIRECT(SHARED_MEM_BASE, 0x04)); } altera_avalon_mutex_unlock( mutex ); }  

 

 

Both are writing and reading from the same mem adress and showing that value to the terminal. And both are showing the right value 

 

Is my project correct? (i want both processors to communicate between them using a shared memory)
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

I've NFI what those altera_avalon mutex functions do, but at best they look like bloat. 

For synchronisation you need a memory block that is accessible uncached by both processors - this could be tightly coupled memory on both cpus. Since you'll need to carefully flush caches on any shared memory, the same memory can be used for all inter-cpu communications. On the linux side you probably have to go through several layers of code to access specific physical addresses - but I assume you've sorted that out already. 

 

I would use a memory section for the shared area, and get the linker to assign variables to that area. This tends top make the coding much less error prone. 

For a single mutex both sides could then run something like: 

 

unsigned int interlock __attribute__((".data.shared")) = {0, 0}; void get_interlock(int cpu); { int i; for (;;) { while (interlock != 0) continue; interlock = 1; if (interlock == 0) return; interlock = 0; for (i = (cpu + 1) * 8; i != 0; i--) continue; } } void release_interlock(int cpu) { interlock = 0; }
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Thanks for the input DSL. 

Could you explain a little better? I am not very advanced on this subject. 

Should i use an onchip memory as tightly coupled memory of both CPUs? Is it pretty straightforward? Just instantiate and set in the same adress for both Processors/connect both data masters to it? Do i need to make any configuration on the NIOS2 Q-Sys screen?
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Hello to everyone! I am struggling to make this work, let me share my efforts to make the mutex work between a NIOS2-MMU Linux and a NIOS2- w/o LINUX 

 

My NIOS2 NO-LINUX is running this program: 

 

int main() { alt_putstr("Proc 2!\n"); /* get the mutex device handle */ alt_mutex_dev* mutex = altera_avalon_mutex_open( "/dev/mutex" ); /* acquire the mutex, setting the value to one */ altera_avalon_mutex_trylock( mutex, 1 ); while(1){ if(altera_avalon_mutex_is_mine(mutex)) { usleep(100); alt_printf("%x\n", IORD_32DIRECT(SHARED_MEM_BASE, 0x00)); } altera_avalon_mutex_unlock( mutex ); } return 0; } My Device Driver of the MMU Linux is written here: http://pastebin.com/gwlfqawv 

 

However it is'nt working. When i boot my Linux it says that my Mutex 

is at the adress e0000001c4, i dont understand why it has this "e" in 

the front of the adress? Also it isn't locking because when i lock in 

Linux i still can lock/unlock at NIOS2-NOLINUX 

 

outl(0x00000001, shmem.mutex); 

 

if (inl(shmem.mutex) == 0x00000001) {printk(KERN_INFO "locked\n"); return 1;} 

 

I get the locked message at Linux, however the mutex isnt locking. 

 

Any help is appreciated
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

The e000001c4 address is a virtual address which will be translated by the mmu to some physical address (setup by the ioremap() call). 

 

You seem to be relying on the Altera mutex implementation matching what your linux driver does - there is no reason to suppore they match. 

Somewhere you'll have to have two matching copies of Dekker's algorithm - you might as well write your own. 

You might want to initialise some field of your mutex structure to a known conatant value - just to verify that both sides are actually referencing teh same memory locations. 

Also ensure that both sides are using cache-disabled instructions/mappings.
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Thanks managed to make it work, here goes my driver.. http://pastebin.com/2zabsbzh

0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Hello, 

 

This conversation helped a lot. 

I want to know from where to get the MUTEX NAME to be used in the "altera_avalon_mutex_open( MUTEX NAME )" command. 

I have two mutex in my qsys system. I don't know how to find their registered names to point them from the C code. 

 

Please suggest.
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

hi, 

 

I got it. It's the hierarchy name based on my Qsys Design. 

 

Thanks.
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Hi Aprado, 

 

I have two cores sharing a particular memory address. I also implemented the mutex same way you did. 

But when I program and start my first core it works. As I program and start the second core, it freezes the first code. 

These happen only when i implement the mutex for sharing some common address space between two cores. Otherwise if I run two cores independently, it RUNs. 

 

Below is a template for my code: 

 

if (!altera_avalon_mutex_trylock (m1, ALT_CPU_CPU_ID_VALUE)) 

if (!altera_avalon_mutex_trylock (m2, ALT_CPU_CPU_ID_VALUE)) 

IORD(BASE, 0x00); //Memory Operation 

altera_avalon_mutex_unlock (m2); 

}  

 

I used IORD. Does IORD & IORD_32DIRECT will make a difference in this case. 

 

Please suggest.
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Hi, 

 

I know it's been a while since you've posted to this thread but if you don't mind and still remember how you were able to get two processors to work without using the mutex, can you please explain the approach you took to solving this. I'm currently having issues with getting two processors to correctly read and write using uart.
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

 

--- Quote Start ---  

Hi, 

 

I know it's been a while since you've posted to this thread but if you don't mind and still remember how you were able to get two processors to work without using the mutex, can you please explain the approach you took to solving this. I'm currently having issues with getting two processors to correctly read and write using uart. 

--- Quote End ---  

 

 

Hi, 

For multi-core system, make sure that your Qsys system is correct and each core has a different(exclusive) memory space allocated. Do verify it from BSP Editor->Linker Script that each core has the correct memory span allocated. In qsys, try NOT connecting Interrupt pin from JTAG UART to NIOS. 

 

For an application where 2 cores doesn't share memory/peripherals, you can directly make different applications for both cores and make them RUN.  

Example: LED blinking. You can assign separate LED for blinking, to each core.
0 Kudos
Altera_Forum
Honored Contributor II
980 Views

Thanks for the reply. I got it working.

0 Kudos
Reply