| Author |
Message |
|
|
Posted: Jul 12, 2012 - 04:14 AM |
|


Joined: May 05, 2010
Posts: 213
|
|
Imagine there is a common bus to drive TFT LCD , Analog Switches , LEDs ,Relays and so on .
This bus is protected by a mutex .
Now I think there are 4 ways to make use of this mutex . As an instance on TFT :
1- Use it in application layer
Code:
__GetBus
GLCD_DisplayString(0,0,Str);
__ReleaseBus
2- Use it in top functions
Code:
void GLCD_DisplayString (unsigned int ln, unsigned int col, char *s)
{
__GetBus
GLCD_WindowMax();
while (*s)
{
GLCD_DisplayChar(ln, col++, *s++);
}
__ReleaseBus
}
3- Use it in medium functions
Code:
static __inline void wr_reg (unsigned char reg, unsigned short val)
{
__GetBus
LCD_CS(0)
wr_cmd(reg);
wr_dat(val);
LCD_CS(1)
__ReleaseBus
}
4- Use it in bottom functions
Code:
static __inline unsigned char lcd_send (unsigned short byte)
{
__GetBus
BUS_Direction(Output);
LCD_DIR(1)
LCD_EN(0)
BUS_Write(byte);
LCD_LE(1)
LCD_LE(0)
BUS_Write(byte >> 8);
__ReleaseBus
return(1);
}
Which of them is true ?
Thanks in advanced |
Last edited by LOSTISLAND on Jul 12, 2012 - 04:30 AM; edited 2 times in total
|
| |
|
|
|
|
|
Posted: Jul 12, 2012 - 04:17 AM |
|


Joined: May 05, 2010
Posts: 213
|
|
By the way how can I widen the page on my posts ?
Are there any other consideration on this issue ? |
|
|
| |
|
|
|
|
|
Posted: Jul 12, 2012 - 05:26 AM |
|

Joined: Dec 18, 2001
Posts: 4779
|
|
MUTEX only needed if you have a preemptive multitasking scheduler like FreeRTOS or a DIY scheduler.
For mutual exclusion with an interrupt service routine (ISR) and a program (non-ISR), without a preemptive RTOS, it's usually simpler to just disable interrupts for a few instructions. |
|
|
| |
|
|
|
|
|
Posted: Jul 12, 2012 - 06:44 AM |
|

Joined: Jun 19, 2002
Posts: 981
Location: SF Bay area
|
|
The idea is that you should hold the Mutex for 'short' periods of time. Unless GLCD_DisplayChar is very slow, I'd probably do it at that level rather than anything lower.
You also need to be sure that you wouldn't leave mid-level functions unprotected. For instance, I think doing the mutex in GLCD_DisplayString() would be a bad idea since there is a reasonable changce that GLCD_DisplayChar is used by users as well. |
|
|
| |
|
|
|
|
|
Posted: Jul 12, 2012 - 10:14 AM |
|


Joined: Jul 18, 2005
Posts: 62899
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
To make the decision I'd want to understand more about the CPU overhead of mutex acquire/release. If it's microseconds do it at the lowest level just for the actually bus access. If it's milliseconds do it at the highest level as you don't want to do it 100 or 1,000 times during the printing of one string.
As for widening a thread so code samples don't wrap. Watch this (and apologies if it makes the thread TOO wide!):
Code:
===============================================================================
(the point being that in code blocks the forum software will not break adjacent '=' characters in order to word wrap). |
_________________
|
| |
|
|
|
|
|
Posted: Jul 12, 2012 - 04:33 PM |
|


Joined: May 05, 2010
Posts: 213
|
|
Cliff ,
Got a question ,
Imagine somewhere the Lowest level function is repeatedly invoked , for 1000 times as an instance , Now when 500 times the Mutex is got and then released , suddenly another task sees the mutex released and gets the mutex . That interrupt which may take a considerable time might cause problems . For that I'm worried of using a mutex in the lowest level functions even if the overhead is low .
Isn't that true ? |
|
|
| |
|
|
|
|
|
Posted: Jul 12, 2012 - 04:56 PM |
|


Joined: Jul 18, 2005
Posts: 62899
Location: (using avr-gcc in) Finchingfield, Essex, England
|
|
|
Quote:
Isn't that true ?
That depends on the device involved. If it's the case that once a long access operation has started it must complete and there cannot be long periods of inactivity or it might timeout then you are right - wrap the mutex at the highest level. The downside of doing it at the highest level is, of course, the opposite, this one operation now hogs the entire bus until it completes. So again the relative merits of each have to be weighed and things like timing/indivisibility and so on have to be weighed up. That's why there is no "right answer" for your original question. There are too many variables and you have to weigh the importance of each up to make a decision.
(this is a bit like thread priorities - if you have just 3 or 5 tasks it's often easy to weigh up the relative importance of the tasks and how high a priority each thing should have but I remember being involved in a project that had more than 100 tasks and 99 priority levels which gave an astronomical number of possible thread priority options and it actually became more of an art than a science with someone employed almost full time "tuning" the system for the best performance by trying to balance the priorities!) |
_________________
|
| |
|
|
|
|
|
Posted: Jul 13, 2012 - 07:43 AM |
|


Joined: May 05, 2010
Posts: 213
|
|
|
|
|
|
|
Posted: Jul 16, 2012 - 08:15 PM |
|

Joined: Dec 08, 2004
Posts: 4719
Location: Nova Scotia, Canada
|
|
If preemption is a possibility, then think about what would happen if you got preempted in each situation. Specifically, consider your third case, if you failed to include the mutex protection at that level:
Code:
static __inline void wr_reg (unsigned char reg, unsigned short val)
{
LCD_CS(0)
wr_cmd(reg);
wr_dat(val);
LCD_CS(1)
}
If you managed to assert the LCD chip select, but you were preempted before you managed to send all the relevant data, then is there a possibility that some other task may step in, assert a different chip select to access a different peripheral on the same bus, and both devices might end up receiving scrambled data?
The MINIMUM level for your mutex must be chosen to ensure that you are effectively protected from preemption causing the transmission to be broken up in a way that leads to data corruption. If you choose any level lower than that, then your mutex won't be doing its job.
You are, of course, free to place the mutex at a HIGHER position if you so choose, keeping in mind the trade-off that higher levels will lead to longer waits for any of your other, higher-priority peripherals. |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2012 - 04:16 AM |
|

Joined: Dec 18, 2001
Posts: 4779
|
|
MUTEXES with preemption in task scheduling is subject to timing/race conditions that are rare and almost impossible to cure by debugging. Read about "priority inversion". They have to be avoided by DESIGN. Or better, avoid using them at all costs:
For mutual exclusion with an interrupt service routine (ISR) and a program (non-ISR), without a preemptive RTOS, it's usually simpler to just disable interrupts for a few instructions. |
|
|
| |
|
|
|
|
|
Posted: Jul 17, 2012 - 11:14 AM |
|


Joined: Oct 30, 2002
Posts: 5727
Location: The Netherlands
|
|
Even better...
* Store current interrupt enable status
* Disable interrupts
* Do work
* Restore from previously stored status
This way you never unintentionally reenable interrupts, if you happen to nest calls. |
|
|
| |
|
|
|
|
|