Discussion:
stm32_i2c isr and sig_timedwait
(too old to reply)
max.kriegleder-/E1597aS9LQAvxtiuMwx3w@public.gmane.org [nuttx]
2014-08-19 12:30:25 UTC
Permalink
Hi Greg,I am observing some strange behaviour, which I can not make sense of and I am hoping that you can point me in the right direction. It is related to I2C on a stm32f103 when run in interrupt driven mode. I am using nuttx 7.2.

I am reading out a sensor at 500 Hz and the read operation takes about 400 us to complete. At the same time I am runnig a different app, where I want to output some data to the nsh.

The code is the following

while(true){
printf("\033[H"); // move cursor home and clear screen
printf("Hello World! %u\n",count++);
printf("Hello World, again %u", count++);

/* Sleep 20 ms waiting for user input five times ~ 0.1s */
for (int k = 0; k < 5; k++) {
char c;
struct pollfd fds;
int ret;
fds.fd = 0; /* stdin */
fds.events = POLLIN;
ret = poll(&fds, 1, 20);

if (ret > 0) {
read(0, &c, 1);

switch (c) {
case 0x03: // ctrl-c
case 0x1b: // esc
case 'c':
case 'q':
printf("\n");
exit(0);
return 0;
/* not reached */
}
}
//usleep(20000);
}
}


This works in principle. However, if I add a few more printf lines, the app blocks and only if I hit the keyboard (or hold a key down) the output refreshes. So I guess the poll blocks?.

If I then uncomment the usleep I get an assertion failed error in sig_timedwait at the line DEBUGASSERT(rtcb->waitdog); and I have no clue how the I2C ISR and that part of the code could be related. The odd thing is that if I run the I2C in polled mode, everything works fine (more printfs or the usleep cause no problem). Any ideas?

Thanks!
Max
spudarnia-/E1597aS9LQAvxtiuMwx3w@public.gmane.org [nuttx]
2014-08-19 15:00:46 UTC
Permalink
Hi, Max,
Post by max.kriegleder-/***@public.gmane.org [nuttx]
I am observing some strange behaviour, which I can not make sense of and I am hoping that you can point me in the right direction. It is related to I2C on a stm32f103 when run in interrupt driven mode. I am using nuttx 7.2.
I am reading out a sensor at 500 Hz and the read operation takes about 400 us to complete. At the same time I am runnig a different app, where I want to output some data to the nsh.
The code is the following
... snip ...
Post by max.kriegleder-/***@public.gmane.org [nuttx]
This works in principle. However, if I add a few more printf lines, the app blocks and only if I hit the keyboard (or hold a key down) the output refreshes. So I guess the poll blocks?.
stdin will be blocking so 'read(0, &c, 1)' should block until some key is pressed (or a signal is received). But you call poll on stdin before that POLL_IN so I think your analysis is correct.




There must be an error in the serial poll logic. That is the code in drivers/serial.c.




When data is received, the function uart_datareceived() should be called. It should be called from drivers/serialirq.c as part of the USART interrupt handling whenever any characters are received.




uart_datareceived() will call uart_pollnotify(dev, POLLIN) which should wake up any thread waiting for the POLLIN event.




So something in that above sequence must not be working.




Debugging serial behavior with serial debug output is pretty difficult. I would probably use a RAMLOG and the dmesg comment to get the serial port out of the debug path. See SYSLOG - NuttX Real-Time Operating System http://www.nuttx.org/doku.php?id=wiki:howtos:syslog


SYSLOG - NuttX Real-Time Operating System http://www.nuttx.org/doku.php?id=wiki:howtos:syslog Table of Contents SYSLOG SYSLOG Character Device RAM Logging Device dmesg RAMLOG Configuration options SYSLOG



View on www.nuttx.org http://www.nuttx.org/doku.php?id=wiki:howtos:syslog
Preview by Yahoo
Post by max.kriegleder-/***@public.gmane.org [nuttx]
If I then uncomment the usleep I get an assertion failed error in sig_timedwait at the line DEBUGASSERT(rtcb->waitdog); and I have no clue how the I2C ISR and that part of the code could be related. The odd thing is that if I run the I2C in polled mode, everything works fine (more printfs or the usleep cause no problem). Any ideas?
This one is easy. That assertion happens because CONFIG_PREALLOC_WDOGS is too small.




Greg
max.kriegleder-/E1597aS9LQAvxtiuMwx3w@public.gmane.org [nuttx]
2014-08-19 15:46:17 UTC
Permalink
Hi Greg,Thanks for the quick answer. Still, does it make sense to you that I see these issues only in the ISR driven mode, but not the polled one? Are maybe the interrupts interferring?

Max
spudarnia-/E1597aS9LQAvxtiuMwx3w@public.gmane.org [nuttx]
2014-08-19 15:58:26 UTC
Permalink
Hi, Max, > Thanks for the quick answer. Still, does it make sense to you that I see these issues only in the ISR driven mode, but not the polled one? Are maybe the interrupts interferring?


Yes, if I understand you right. You say that when you enable the interrupt, then the assertion occurs when you call usleep(). Do I understand that right?


The assertion occurs because you have run out of timer resources. So I believe that you are on the borderline: If you don't enable interrupts, they you have just enough timers. If you do enable interrupts, then your run out of timers and get the assertion.


Greg
max.kriegleder-/E1597aS9LQAvxtiuMwx3w@public.gmane.org [nuttx]
2014-08-19 21:14:58 UTC
Permalink
Awesome, increasing the CONFIG_PREALLOC_WDOGS from 4 to 5 solved both problems:- assertion error does not occur anymore
- output refreshes as expected

I am not familiar with this low level stuff. What is the purpose of these watchdog timers and is the number of them limited (hence should I be careful increasing this number?)? While we are at it, what is the purpose of the POSIX timers defined by CONFIG_PRALLOC_TIMERS and also, is there a limit on them?

Max
spudarnia-/E1597aS9LQAvxtiuMwx3w@public.gmane.org [nuttx]
2014-08-20 13:19:36 UTC
Permalink
The watchdog structures are timers. The must be capable of being allocated from interrupt handlers so they cannot be allocated with malloc(). Instead they are pre-allocated in pools of timers and the size of that pool must be configured correctly.

Most other operating system structures that are managed from interrupt handlers work this way. POSIX message queues do the same thing, but the allocation logic is more complex:


- It keeps a reserve of pre-allocated structure for the exclusive use by interrupt handling.
- It keeps a pool of pre-allocated structures for general use, and
- It can use malloc to temporarily allocate more if the pre-allocated number is exceeded.


That requires more logic thatnis currently implemented for the pre-allocated timers. I should put that on my To-Do list.


Another thing... the default value for the number of timers is 64 but some very small numbers (like 8) have crept into many configurations. Copying configurations is a simple way to start, but is like a contagion. It spreads bad configuration settings too.


Greg
spudarnia-/E1597aS9LQAvxtiuMwx3w@public.gmane.org [nuttx]
2014-08-21 15:02:03 UTC
Permalink
Hi, > The watchdog structures are timers. The must be capable of being allocated from interrupt handlers so they cannot be allocated with malloc(). Instead they are pre-allocated in pools of timers and the size of that pool must be configured correctly.
Post by spudarnia-/***@public.gmane.org [nuttx]
- It keeps a reserve of pre-allocated structure for the exclusive use by interrupt handling.
- It keeps a pool of pre-allocated structures for general use, and
- It can use malloc to temporarily allocate more if the pre-allocated number is exceeded.
That requires more logic thatnis currently implemented for the pre-allocated timers. I should put that on my To-Do list.
Not only did I put this on my To-Do list, bit I did it. I guess it is now on the Done-Did list: NuttX / GIT / Commit [4d7063] https://sourceforge.net/p/nuttx/git/ci/4d70630480d6a9f478948d85a56069e78f4c071e/


NuttX / GIT / Commit [4d7063] https://sourceforge.net/p/nuttx/git/ci/4d70630480d6a9f478948d85a56069e78f4c071e/ If we run out of pre-allocated watchdog times, the logic will allocate additional timers from the heap.



View on sourceforge.net https://sourceforge.net/p/nuttx/git/ci/4d70630480d6a9f478948d85a56069e78f4c071e/
Preview by Yahoo




This still does not take away responsibility for tuning the number of pre-allocated timers. If your trying to do fine, critical timing and allocating structures from the heap, you won't like the result. Nor will you like the result if there are many, many tiny structure allocations chopping up your heap.


The use of the heap to allocate timers should be thought of as just a failsafe back up so that you can optimize the number of pre-allocated timers and not be concerned about something disastrous happening in the final buckled up product.


Greg

Loading...