Sleep functionality is not working in Interrupt service routine in PIC controller - sleep

I am using Pic controller (PIC16F15325) in simulaotor window, and I am facing one issue regarding Sleep functionality. I have declared Pin "RA2" as external interrupt pin (High to low transition) and I am changing forcefully value of "RA2" from 1 to 0, from variable window. After doing that "ISR" is never got called.
All the Initialization code i have used, it is generated from MPLAB code configurator only. Can anyone tell me the reason, why interrupt is not generated after triggering the value.
I am putting my sample code here, which i used for testing:
/* code */
SYSTEM_Initialize();
INTERRUPT_GlobalInterruptEnable();
INTERRUPT_PeripheralInterruptEnable();
while (1)
{
if(PORTAbits.RA2 == 1)
{
SLEEP();
__nop();
}
else
{
PORTCbits.RC3 = 1;
PORTCbits.RC4 = 1;
}
}

Related

Modal MFC dialog not shown due to idle checks in CWnd::RunModalLoop

Below I've put the source to CWnd::RunModal, which is the message loop run when you call CDialog::DoModal - it takes over as a nested message loop until the dialog is ended.
Note that with a couple of special case exception ShowWindow is only called when the message queue is idle.
This is causing a dialog not to appear for many seconds in some cases in our application when DoModal is called. If I debug into the code and put breakpoints, I see the phase 1 loop is not reached until this time. However if I create the same dialog modelessly (call Create then ShowWindow it appears instantly) - but this would be an awkward change to make just to fix a bug without understanding it well.
Is there a way to avoid this problem? Perhaps I can call ShowWindow explicitly at some point for instance or post a message to trigger the idle behaviour? I read "Old New Thing - Modality" which was very informative but didn't answer this question and I can only find it rarely mentioned on the web, without successful resolution.
wincore.cpp: CWnd::RunModalLoop
int CWnd::RunModalLoop(DWORD dwFlags)
{
ASSERT(::IsWindow(m_hWnd)); // window must be created
ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
HWND hWndParent = ::GetParent(m_hWnd);
m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
MSG *pMsg = AfxGetCurrentMessage();
// acquire and dispatch messages until the modal state is done
for (;;)
{
ASSERT(ContinueModal());
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
{
ASSERT(ContinueModal());
// show the dialog when the message queue goes idle
if (bShowIdle)
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
// call OnIdle while in bIdle state
if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
{
// send WM_ENTERIDLE to the parent
::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
}
if ((dwFlags & MLF_NOKICKIDLE) ||
!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
{
// stop idle processing next time
bIdle = FALSE;
}
}
// phase2: pump messages while available
do
{
ASSERT(ContinueModal());
// pump message, but quit on WM_QUIT
if (!AfxPumpMessage())
{
AfxPostQuitMessage(0);
return -1;
}
// show the window when certain special messages rec'd
if (bShowIdle &&
(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
bShowIdle = FALSE;
}
if (!ContinueModal())
goto ExitModal;
// reset "no idle" state after pumping "normal" message
if (AfxIsIdleMessage(pMsg))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
}
ExitModal:
m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
return m_nModalResult;
}
So to answer my own question, the solution I found was to explicitly call the following two methods:
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
CWnd::RunModalLoop is supposed to call these, but only when it detects the message queue is empty/idle. If that doesn't happen then the dialog exists and blocks input to other windows, but isn't visible.
From tracking messages I found WM_ACTIVATE was the last message being sent before things got stuck, so I added an OnActivate() handler to my Dialog class.
I found a very similar problem in my application. It only happened when the application was under a heavy load for drawing (the user can open many views, the views show real time data, so they are constantly refreshing, and each view must be drawn independently, and the process of drawing takes a lot of time). So, if under that scenario, the user tries to open any modal dialog (let's say, the "About" dialog, or if the app needs to show any modal dialog like a MessageBox), it "freezes" and the dialog only shows after pressing the ALT key.
Analyzing RunModalLoop() I got to the same conclusion as you did, that is, the first loop (titled "phase1" in the code comments), is never called, since it needs the message queue to be empty, and it never is; the app then falls in the second loop, phase2, from which it never exits, because the call to PeekMessage() at the end of phase2 never returns zero (the message queue is very busy for so many views constantly updating).
Since this code is in wincore.cpp, my solution was to find the closest function that could be overloaded, and lucky me found ContinueModal() which is virtual. Since I already had a class derived from CDialog which I always use as a replacement, I only had to define in that class a BOOL variable m_bShown, and an overload of ContinueModal():
BOOL CMyDialog::ContinueModal()
{
// Begin extra code by Me
if (m_nFlags & WF_CONTINUEMODAL)
{
if (!m_bShown && !(GetStyle() & WS_VISIBLE))
{
ShowWindow(SW_SHOWNORMAL);
UpdateWindow();
m_bShown = TRUE;
}
}
// End extra code
return m_nFlags & WF_CONTINUEMODAL;
}
This causes ContinueModal() to actually show the window if it has never been shown before. I set m_bShown to FALSE both in its declaration and in OnInitDialog(), so it arrives to RunModalLoop() in FALSE, and set it to TRUE immediately after showing the window to disable the little additional code snippet.
This solved the problem for me and supposedly should solve it for anybody. The only doubts remaining are, 1) is RunModalLoop() called from somewhere else within MFC that would conflict with this modification? and 2) Why did Microsoft program RunModalLoop() this weird way leaving this glaring hole there that can cause an app to freeze without any apparent reason?
I recently had the same problem.
I solved by sending the undocumented message 0x118 before calling DoModal(), which is handled in the phase2.
...
PostMessage(0x118, 0, 0);
return CDialog::DoModal();

Low Power Mode on the TI MSP430

I am using the MSP430F2274 and trying to understand better the uses of Low Power mode.
In my program I am also using the SimplicTi API in order for two devices (one is the AP which is being connected by the other ,ED) to communicate.
AP - Access Point , which is also connected to a PC via the UART in order to recive a string from the user.
ED - End Device , simply connetes to the AP (with the SimplicTi protocol) and waits for messages form it.
I want to be sure I understand the low power mode uses , and to see how it "comes along" with the SimplicTi API.
The "flow" of the AP is as follows (after it is "linked" to the ED , see the code bellow):
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
// **A)** extract the "RXed" character (8 bits received from user) , use the while
// in order to be sure all the 8 bits are "desirialized" into a byte
while (!(IFG2 & UCA0RXIFG));
input_char = UCA0RXBUF; // input_char is global variable.
// **B)** if we received the "Enter" character , which indicates the
// end of the string
if(input_char == '\r' && input_count > 0)
{
TACCR0 = 10; // **F)**
TACTL = TASSEL_1 + MC_1; // ACLK, up mode
// **E)** Enter LPM3, interrupts enabled !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
__bis_SR_register(LPM3_bits + GIE);
}//end if Enter
// **C)** Any other char of the user's string when we
// have not got more than the maximum amount of bytes(chars)
else if (((FIRST_CHAR <= input_char && input_char <= LAST_CHAR) || ('a' <= input_char && input_char <= 'z')) && (input_count < INPUT_MAX_LENGTH))
{
input[input_count++] = input_char;
}
} //end of UART RX INTERRUPT
The TIMERA0 Interrupt Handler is the following code:
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A(void)
{
if (i == strlen(morse)) // **D)** morse is a global array of chars who holds the string that we wish to send
{
SMPL_Send(sLID[0], (uint8_t*)EOT, 1); // EOT is the last char to send
TACTL = MC_0; //disable TimerA0
}
else if (!letterSpace)
{
char ch = morse[i++];
SMPL_Send(sLID[0], (char*)ch, 1);
switch(ch)
{
case '.':
{
TACCR0 = INTERVAL * 3;
letterSpace = 1;
break;
}
case '-':
{
TACCR0 = INTERVAL * 3 * 3;
letterSpace = 1;
break;
}
} // switch
} // else if
} //end TIMERA0 interrupt handler
The thing is like that:
I use the TIMERA0 handler in order to send each byte after a different amount of type , whether the char was transformed into a "-" or a "."
To do so I set the timer accordingly to a different value ( 3 times larger for "-").
Finnaly when I am done transmitting the whole string (D) , I disable the timer.
NOTE : The following method is performed at the begining of the AP code in order to configure the UART:
void UARTinit()
{
P3SEL = 0x30; // P3.4 and P3.5 as the UART TX/RX pins: P3SEL |= BIT4 + BIT5;
UCA0CTL1 |= UCSSEL_2; // SMCLK
// pre scale 1MHz/9600 =~ 104.
UCA0BR0 = 104;
UCA0BR1 = 0;
// 8-bit character and Modulation UCBRSx = 1
UCTL0 |= CHAR;
UCA0MCTL = UCBRS0;
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IE2 |= UCA0RXIE; // Enable UART INPUT interrupt
} // end of UARTinit
So my questions are:
1) Just to be sure, in A) where I am "polling" the Rx buffer of the UART , is it necceary or is it just good practise for "any case" , cause AFAIK the UART handler gets called once the UART module recived the whole BYTE (as I configured it)?
2) In the main program of the AP , the last instruction is the one that "puts" it into LPM0 with interrupts enables : __bis_SR_register(LPM0_bits + GIE);
When for LPM0:
CPU is disable
ACLK and SMCLK remain active
MCLK is disabled
And for LPM3:
CPU is disable
MCLK and SMCLK are disabled
ACLK remains active
As I see it ,I can not enter LPM3 cause the AP needs the SMCLK clock not to be disable? (cause the UART uses it)
Is that correct?
3) In F) , is it a proper way to call the TIMERA0 handler ? I perfrom TACRR0 = 10 , cause it is a small value which the timer will reach "in no time" just so it will enter the TIMERA0 handler to perform the task of sending the bytes of the string.
4) For the "roll back" in the AP: As I see it , the "flow" is like that:
enters LPM0 (main) --> UART gets interrputed --> exit LPM0 and goes to the UART handler --> when it is done reciving the bytes (usually 5) it enters LPM3 --> the timer finishes counting to TACRR0 value (which is 10) --> the TIMERA0 handler gets called --> when the TIMERA0 handler done sending the last byte it disables the timer (TACTL0 = MC_0;) --> we "roll back" to the instruction which got us to LPM3 within the UART handler --> ??
Now , does ?? is "rolling back" to the instrcution which took us to LPM0 within the main program , OR do we "stay here" (in the instruction that entered us to LPM3 within the UART handler E) ?
If we do stay on E) , do I need to change it to LPM0 cause , again, the UART uses the SMCLK which is NOT active in LPM3 but indeed active in LPM0 ?
5) Any other comments will be super !!
Thanks allot,
Guy.
1) This will work
2) When you config this:
UCA0CTL1 |= UCSSEL_2; // SMCLK
This mean that UART used SMCLK, SMCLK will stop when you make MCU turn to LPM3;so that
UART will not work, you should config UART use ACLK, this will make UART work in LPM3 mode.
3) ...
4) ...
5) See 2
I hope this will help you

timer & overflow interrupt MikroC code

void TimerFunction()
{
TIMSK=(1<<TOIE0);
TCNT0=0x00;
TCCR0 |= (0<<CS02) | (1<<CS00) | (0<<CS01);
}
//##############################################################################
ISR(TIMER0_OVF_vect)
{
// process the timer0 overflow here
countClock ++;
count++;
delay++;
//some extra code
}
then
void main()
{
//someCode
TimerFunction();
}
but it doesnt work for me ,so is that the right way to start the timer 0 and its interrupt service routine ??
At first sight I'd say you miss
sei(); // set global interrupt flag
if this is not within //someCode ... in any case I recommend turning on the global interrupt enable flag only after initializing all specific interrupt sources (timers, USART, etc)
Yes, in your code global interrupt flag is not set. If solutions which purposed MikeD are not working, try this:
asm{sei};
use SREG.SREG_I = 1; to enable global interrupts

Interrupt performance on linux kernel with RT patches - should be better?

I have bumped into a bit inconsistent IRQ/ISR performance on Freescales imx.233 running linux kernel (3.8.13) with CONFIG_PREEMPT_RT patches.
I am little bit surprised why this processor (ARM9, 454mhz) is unable to keep up even with 74kHz IRQ requests.. ?
In my kernel config I have set following flags:
CONFIG_TINY_PREEMPT_RCU=y
CONFIG_PREEMPT_RCU=y
CONFIG_PREEMPT=y
CONFIG_PREEMPT_RT_BASE=y
CONFIG_HAVE_PREEMPT_LAZY=y
CONFIG_PREEMPT_LAZY=y
CONFIG_PREEMPT_RT_FULL=y
CONFIG_PREEMPT_COUNT=y
CONFIG_DEBUG_PREEMPT=y
On the system there is basically nothing running (created by buildroot), and I set PWM to generate a pulse of 74kHz, that serves as interrupt.
Then in the ISR, I just trigger another GPIO output pin, and check the output.
What I find is that sometimes I miss an interrupt -
You can see the missed interrupt here:
And also the the triggering of output pin seems to be a bit inconsistent, the output pin is triggered usually within "5% window", that might still be acceptable. But I worry, that when I start implementing data transfer logic, instead of just triggering the pin, I might run into further problems...
My simple driver code looks like this:
#needed includes
uint16_t INPUT_IRQ = 39;
uint16_t OUTPUT_GPIO = 38;
struct test_device *device;
//Prototypes
void irqtest_exit(void);
int irqtest_init(void);
void free_device(void);
//Default functions
module_init(irqtest_init);
module_exit(irqtest_exit);
//triggering flag
uint16_t pulse = 0x1;
irqreturn_t irq_handle_function(int irq, void *device_id)
{
pulse = !pulse;
gpio_set_value(OUTPUT_GPIO, pulse);
return IRQ_HANDLED;
}
struct test_device {
int huuhaa;
};
void free_device() {
if (device)
kfree(device);
}
int irqtest_init(void) {
int result = 0;
device = kmalloc(sizeof *device, GFP_KERNEL);
device->huuhaa = 10;
printk("IRB/irqtest_init: Inserting IRQ module\n");
printk("IRB/irqtest_init: Requesting GPIO (%d)\n", INPUT_IRQ);
result = gpio_request_one(INPUT_IRQ, GPIOF_IN, "PWM input");
if (result != 0) {
free_device();
printk("IRB/irqtest_init: Failed to set GPIO (%d) as input.. exiting\n", INPUT_IRQ);
return -EINVAL;
}
result = gpio_request_one(OUTPUT_GPIO, GPIOF_OUT_INIT_LOW , "IR OUTPUT");
if (result != 0) {
free_device();
printk("IRB/irqtest_init: Failed to set GPIO (%d) as output.. exiting\n", OUTPUT_GPIO);
return -EINVAL;
}
//Set our desired interrupt line as input
result = gpio_direction_input(INPUT_IRQ);
if (result != 0) {
printk("IRB/irqtest_init: Failed to set IRQ as input.. exiting\n");
free_device();
return -EINVAL;
}
//Set flags for our interrupt, guessing here..
irq_flags |= IRQF_NO_THREAD;
irq_flags |= IRQF_NOBALANCING;
irq_flags |= IRQF_TRIGGER_RISING;
irq_flags |= IRQF_NO_SOFTIRQ_CALL;
//register interrupt
result = request_irq(gpio_to_irq(INPUT_IRQ), irq_handle_function, irq_flags, "irq testing", device);
if (result != 0) {
printk("IRB/irqtest_init: Failed to reserve GPIO 38\n");
return -EINVAL;
}
printk("IRB/irqtest_init: insert success\n");
return 0;
}
void irqtest_exit(void) {
if (device)
kfree(device);
gpio_free(INPUT_IRQ);
gpio_free(OUTPUT_GPIO);
printk("IRB/irqtest_exit: Removing irqtest module\n");
}
int irqtest_open(struct inode *inode, struct file *filp) {return 0;}
int irqtest_release(struct inode *inode, struct file *filp) {return 0;}
In the system, I have following interrupts registered, after the driver is loaded:
# cat /proc/interrupts
CPU0
16: 36379 - MXS Timer Tick
17: 0 - mxs-spi
18: 2103 - mxs-dma
60: 0 gpio-mxs irq testing
118: 0 - mxs-spi
119: 0 - mxs-dma
120: 0 - RTC alarm
124: 0 - 8006c000.serial
127: 68050 - uart-pl011
128: 151 - ci13xxx_imx
Err: 0
I wonder if the flags I declare to my IRQ are good ? I noticed that with this configuration, I can no longer reach console, so kernel seems totally consumed with servicing this 74kHz trigger now.. this can't be right ?
I suppose it's not a big deal for me since this is only during data transfer, but still I feel I'm doing something wrong..
Also, I wonder if it would be more efficient to map the registers with ioremap, and trigger the output with direct memory writes ?
Is there some way I could increase the priority of the interrupt even higher ? Or could I somehow lock the kernel for the duration of the data transfer (~400ms), and generate somehow else my timing for the output ?
Edit: Forgot to add /proc/interrupts output to the question...
What you experience here is interrupt jitter. This is to be expected on Linux, because the kernel regularly disables the interrupts for various tasks (entering a spinlock, handling an interrupt, etc.).
This will happen, regardless wether you have PREEMPT_RT or not, so expecting to generate 74kHz signal with regular interrupts is pretty much unrealistic.
Now, ARM has higher priority interrupts called FIQs, that will never be masked or disabled.
Linux doesn't use FIQ, and is not built to deal with the fact that an FIQ could be used, so you won't be able to use the generic kernel framework.
From Linux driver development point of view however, it's not really different as long as you keep this in mind: you have to write a handler, and associate it to an IRQ. You'll also have to poke into the interrupt controller to make it generate a FIQ for the interrupt you want to use (the details on how to change it are platform-dependant. Some platforms have functions to do that (like imx25 and mxc_set_irq_fiq), some others don't. imx23/28 don't, so you'll have to do it by hand).
The only thing that the functions to setup a fiq handler only work with a assembly-written handler, so you'll have to rewrite your handler in assembly (with your current code, it should be trivial though).
You can grab additional details to the blog post Alexandre posted (http://free-electrons.com/blog/fiq-handlers-in-the-arm-linux-kernel/), where you'll find working code, samples, and explanations on how it all works together.
You can have a look at what my colleague Maxime Ripard did using an FIQ on a similar SoC (i.mx28) :
http://free-electrons.com/blog/fiq-handlers-in-the-arm-linux-kernel/
Try this flags:
int irq_flags;
...
irq_flags = IRQF_TRIGGER_RISING | IRQF_EARLY_RESUME
I had a kernel 3.8.11 and can't find IRQF_NO_SOFTIRQ_CALL define. It's only for 3.8.13?
Also I didn't see irq_flags define. Where is it?

application exits prematurely with OpenMp with the error code : Fatal User Error 1002: Not all work-sharing constructs executed by all threads

I added openMp code to some serial code in a simulator applicaton, when I run a program that uses this application the program exits unexpectedly with the output "The thread 'Win32 Thread' (0x1828) has exited with code 1 (0x1)", this happens in the parallel region where I added the OpenMp code,
here's a code sample:
#pragma omp parallel for private (curr_proc_info, current_writer, method_h) shared (exceptionOccured) schedule(dynamic, 1)
for (i = 0 ; i < method_process_num ; i++)
{
current_writer = 0;
// we need to add protection before we can dequeue a method from the methods queue,
#pragma omp critical(dequeueMethod)
method_h = pop_runnable_method(curr_proc_info, current_writer);
if(method_h !=0 && exceptionOccured == false){
try {
method_h->semantics();
}
catch( const sc_report& ex ) {
::std::cout << "\n" << ex.what() << ::std::endl;
m_error = true;
exceptionOccured = true; // we cannot jump outside the loop, so instead of return we use a flag and return somewhere else
}
}
}
The scheduling was static before I made it dynamic, after I added dynamic with a chunk size of 1 the application proceeded a little further before it exited, can this be an indication of what is happening inside the parallel region?
thanks
As I read it, and I'm more of a Fortran programmer than C/C++, your private variable curr_proc_info is not declared (or defined ?) before it first appears in the call to pop_runnable_method. But private variables are undefined on entry to the parallel region.
I also think your sharing of exception_occurred is a little fishy since it suggests that an exception on any thread should be noticed by any thread, not just the thread in which it is noticed. Of course, that may be your intent.
Cheers
Mark

Resources