out8 problem with a watchdog timer on QNX 6.3

Hello,

SUMMARY: I am NOT able to refresh the Advantech PCM 5820 (i386 compatible) board watchdog timer.

SUMMARY2: I am able to arm the watchdog timer, but consecutive writting operations on the output port don’t seem to happen really because the device resets. The first output operation works, otherwise the watchdog would not reset the board.

This is not a hardware problem since I am able to make it work properly with another operating system (which calls directly the machine code from my source code)

The environment that I’m using is the following:

QNX VERSION: QNX 6.3.0 SP2 (also fails without SP2)
HARDWARE:
SBC board ADVANDTECH PCM5820
CPU: AMD GEODE (386 compatible)

Here is a test program, that is not able to refresh the watchdog:

/* for mmap_device_io() */ 
#include <stdint.h> 
#include <sys/mman.h> 

/* for out8 */ 
#include <hw/inout.h> 

/* for ThreadCtl */ 
#include <sys/neutrino.h> 

#include <stdio.h> 

#define WATCHDOG_IO  0x443 


main (int argc, char argv[]) 
   { 
   uintptr_t resu; 
   int res;    
   struct timespec tiempo_espera; 
  /* Handle for port writting*/ 
  uintptr_t port_handle=NULL; 
    

   /* Get IO grant access*/ 

   res=ThreadCtl(_NTO_TCTL_IO, 0); 
   if (res==-1) 
      { 
      printf("NO PERMISSION\n"); 
      } 


   /* Get zone grant access and handle port */ 

   port_handle=mmap_device_io(1, WATCHDOG_IO); 
   if (port_handle==MAP_DEVICE_FAILED) 
      { 
      printf("mmap failure\n"); 
      } 

   while (1) 
       { 
       out8(port_handle, 1); 
       tiempo_espera.tv_sec=0;
       tiempo_espera.tv_nsec= 100000000 ;  /* Nanosegundos 10-9 */  /* 0.1s */ 
       nanosleep( &tiempo_espera ,NULL);  
       } 

} 

Many thanks in advance,

Julián Muñoz
TCP Sistemas e Ingeniería

What do you mean by “which calls directly the machine code from my source code”. Do you mean it’s in assembler or it’s a BIOS call.

The program should do what you asked it to do (write 1 at address 0x443). My guess is what you are doing is wrong. Usually enabling a watchdog is a different operation then petting it. Otherwise how would be able to disable it.

I think your program only enables the watchdog and ever pets it.

I mean that in the test I have done with another operating system (FYI ORK, Openranvenscar), I call directly assembler. Exactly what I do is embbed assembler into Ada:

– Put on DX the address (0x443)
System.Machine_Code.Asm(“movw $0x443, %%dx”);
– Put on AL the value to write
System.Machine_Code.Asm(“movb $1, %%al”);
– Do the out operation
System.Machine_Code.Asm(“outb %%al ,%%dx”);

The fact is that, doing a temporized loop calling this code works well, the watchdog is not reseting the board until the writting to the port stops. That means this is the way of using the watchdog, and it is working.

Today I have repeated the same test, but with the parallel port, writting at the address 0x378 (but only once, without a loop) in order to put to “1” the parallel port output (with a similar program, see code next).

Same result: not working on Qnx, but it works with ORK (parallel port output goes for 0V to 5V).

So, I am really using badly the out8 function, or something else is failling between the hardware and the software !!

/* Para mmap_device_io() */
#include <stdint.h>
#include <sys/mman.h>

/* para out8 */
#include <hw/inout.h> 

/* Para ThreadCtl */
#include <sys/neutrino.h>

#include <stdio.h>

#define WATCHDOG_IO  0x378


main (int argc, char argv[])
   {
   uintptr_t resu;
   int res;   
   struct timespec tiempo_espera;
  /* Handle para escritura en el puerto */
  uintptr_t port_handle=NULL;
   

   /* Obtener permiso de acceso a io*/

   res=ThreadCtl(_NTO_TCTL_IO, 0);
   printf("0");
   if (res==-1)
      {
      printf("NO PERMISSION\n");
      }


   /* Obtener permiso de acceso a la zona y port handle*/

   port_handle=mmap_device_io(1, WATCHDOG_IO);
   if (port_handle==MAP_DEVICE_FAILED)
      {
      printf("mmap failure\n");
      }
   printf("3");
   out8(port_handle, 0xff); 
}

You are using it right, my guess is your code rely on something that is performed by the other OS/compiler behind your back. For example a parallel port needs to be setup properly to work in output mode. Also with QNX there is already a driver for parallel port, having two programs accessing the same hardware can result in strange behavior.

For the watchdog it’s quite possible something else somewhere is enabling the watchdog. I have NEVER seen a watchdog that can only be enabled and not disable. It just doesn’t make sense, but then again there is always a first.

I’m very confident your code is doing what you expect it to.

Julian, you really should use more informative prinfs, like

   port_handle=mmap_device_io(1, WATCHDOG_IO);
   printf("I/O port %u mapped as %u", WATCHDOG_IO, port_handle);

And slay devc-par before starting your testcase controling LPT.
Eduard.

Both WATCHDOG_IO and port_handle should be the same on x86.

You are right. In this case I’ve done it work changing the mode of the parallel port in the bios. I think that devc-par disabled the output on that mode, so writing to the address had any effect.

Conclusion: out8 is working. But I’m still no able to refresh the watchdog, even if I am able to do it on another operating system.

Probably something similar is happening, qnx is touching something on the board provoking that the watchdog doesn’t work, and I should to reestablish this thing. On the image, only 2 drivers are launched: the serial ports, and the console.

Ok, I’ve done it, and checked that the value of port_handle is correct: it is.

Any idea ?

I don’t think QNX is touching something that disables the watchdog. QNX has not support for watchdog. Like I said I’m pretty sure it’s something in the OS or a BIOS calls that is perform by your other setup that makes the difference.

Contact Advantech and ask for the detailed specs of the watchdog circuit.

Update:

From boards manuel:

To enable the watchdog timer, you must write a program which
writes 1 to I/O port address 443 (hex) at regular intervals. The first
time your program reads the port, it enables the watchdog timer.
After that, your program must write 1 to the port at time interval of
less than 1.6 seconds, otherwise the watchdog timer will activate
and reset the CPU or generate an interrupt on IRQ11. When you
want to disable the watchdog timer, your program should write 0
to I/O port 443.

So apprently it should work. Only think I can see is that it actually works ;-) Something is preventing your program from updating the watchdog. Replace the out8 by a printf of time (clock() ) and see if everything is fine time wise.

I can’t find where you enabled watchdog (in8(port_handle)), how do you know this program is not able to refresh watchdog? This program seems to feed watch dog despite the fact dog is not waiting for any food. Nothing wrong, still should work with no effect.
Eduard.

Look at the original post Edouard. The board resets which says the watchdog is enables but feeding doesn’t seems to make it less hungry ;-)

Ok, I’ve done printf’s, and I see that the loop is looping at the specified rate, so the out8 operation is done at the good rate.

I am not sure of what is the most probable: the other setup is touching something that makes the watchdog work, or qnx is touching something that makes it not to work.

None of them has support for watchdog, and qnx is much more powerfull, so I imagine that qnx is touching something on the bios is more probable than the other is doing it. I could test with a third operating system, in order to see who is doing something “wrong”…

Mario, I’m refering to the original post to the code example and not to the conclusion (qnx doesn’t allow to write to i/o port 0x443) as it doesn’t make sense for me. According to quote from documentation you provided, in order to enable watchdog one must read from the port - there is no such action before while(1) loop in the code. For me, that means watchdog is disabled (exept if some qnx stuff scans ports and arrarently reads this port for some stupid reason - then watchdog feeder program has to be started right after procnto). Second thought, if board resets how do you know what was a reason for reset? Why do you assume that was watchdog?
Eduard.

Ah ok I missed the read part.

First of all, many thanks mario and ed1k ! :slight_smile:

ed1k, I am duplicating all the tests I am doing: the first one without reading, and the second one reading before entering into the write loop. I does this just in case, because the board documentation is not enough clear (there are examples that don’t clarify really this point). But I do it, every time, and in fact for now I have maybe done thousands of test, and none has worked yet. :angry:

Because when I run the executable from the shell, the board resets after 1s.

Or because if I generate a flash bootable image running only this executable, the board resets. It also resets when I generate an image substituting the executable file which don’t access the watchdog port with this one.

So it seem to be an incompatibility between qnx and this board.

Maybe should I change some parameters of procnto, or the .build file ???

First the fact that it works on the other OS you are using is strange, because in your code (the assembly stuff) you aren’t reading the port to enable the watchdog. Does the board resets if you stop the program? Is it possible the watchdog isn’t working at all and never resets the board.

In QNX since you aren’t reading the port the watchdog shouldn’t be activated thus it should never reset.

I really doubt it’s an incompatiblity with QNX and your hardware. There is definitely something strange going on, the documentation doesn’t seem to match the behavior.

Also did you make sure the while loop executes as you think it does?

What if you do a write 1 and a write of 0 to disable the watchdog, does it still crash?

According to advantechwdt.c from linux 2.6.15 kernel, this watchdog is disabled on startup; to enable watchdog one has to write timeout in seconds (from 1 to 63… could be this particular board supports only 1 sec) to the port; to disable watchdog one has to read from the port. I’ve never seen so stupid watchdog management, bravo Advantech!

Julian, are you saying Neutrino reboots in 1 seconds if you start very simple image with procnto, devc-con and shell (nothing else)? Then try to boot this particular board in DOS and see if it also reboots.

Answering mario:

Yes, it does. What I do is: refresh the watchdog every 0.1s, during a minute, and then when a counter reach a value, I go out of the loop, and go to an empty loop. The result is the expected one, the board resets when it should (I do also printfs on the serial port to check this, and all is right, the board resets when it enters on the empty loop).

I am duplicating all the tests, this case is included.

It’s a while(1) loop, and I do printfs to check it is looping at the specified rate.

I have done the following interesting tests (in all possible variations…):

  1. in a while(1) loop: write 1 and then write 0: the board resets.
  2. without loop: write 1: the board resets
  3. without loop: write 1 and then write 0: the board doesn’t reset.

I have also checked that this behaviour is not caused by the presence of the nanosleep(), it acts exactly the same way repeating this test writing at the port without any delay between the writes.

answering ed1k:

Yes, and even more: I have also tested without devc-con and without shell, only with procnto and my test application.

Sorry, currently I can’t do this test.

Hmm… very odd behaviour. I’d try to write someting like 63 instead of 1 in a loop :slight_smile: Or use this catch and forget about watchdog altogether, it doesn’t seem to work as documented.

Just tested with the value 63 in the while(1) loop : the board resets also.