Posts by fs-support_HK

    Quote from "hamid"

    I would like send data to DIO at least with 100kHz but I can not do it.
    Max frequency of DIO is 15.6kHz and it is vely slow for me.


    Here you see one disadvantage of using an OS. Let me explain this a little bit more.


    The main problem is that the processor of the NetDCU8 has no special set and clear commands for the individual GPIO port bits. It only has port data registers. To set a single bit, you have to read the data register, add the new bit by OR, then write back the data register. To clear a single bit, you have to read the data register, remove the bit by AND, then write back the data register. Therefore all accesses are Read-Modify-Write cycles. These accesses have to be atomic. They must not be interrupted before having successfully modified the register.


    If you don't use an OS, this is easy. Simply disable all interrupts, do the Read-Modify-Write access, enable the interrupts again and you're done. This is very fast.


    Now when you do use an OS, disabling interrupts in a user space program is strictly forbidden. Only the kernel is allowed to do this. There are other means of synchronising things, like mutexes and critical sections. But all these data structures have in common, that they must be shared by everybody who wants to access them. As the GPIO pins must be accessed by almost every driver, the best place to do this is within the kernel.


    Now let's exercise an example. What happens when you access port 1 of GPIO. Even as this port only has 4 valid bits, they are located in two different internal port registers, namely Port E and Port G. Now when you write a new value to this port 1, the context is switched from your user space program to the driver program. There the corresponding masks for Port E and G are computed. Then Port E is modified by calling an Atomic Read-Modify-Write function in the kernel. This happens immediately again, when changing port G. Then the driver is done and returns to the user program.


    So there are 6 context changes:


    1. user program to driver
    2. driver to kernel (for port E)
    3. kernel to driver
    4. driver to kernel (for port G)
    5. kernel to driver
    6. driver to user program


    These context switches are the slow part of the whole process. And as I already explained, you can't get rid of the kernel call for the atomic Read-Modify-Write cycle.


    Quote

    could you tell me how can I acces to DIO Faster than that?


    Well it depends a little bit on your application. If your access uses several port bits at once, I see no way other than writing your own device driver.


    But if your access is restricted to one single pin, there is a way of directly setting, clearing and reading a port bit by DeviceIoControl() and codes IOCTL_DIO_SET_PIN, IOCTL_DIO_CLR_PIN and IOCTL_DIO_GET_PIN. Simply give the pin number in the lpInBuffer of DeviceIoControl().


    The pin number is the sum of the bit number and the port number multiplied by 8. For example to modify Pin 11 of connector J5, look at the table in the NetDCU device driver document. It shows that this is bit 2 of port 1. So the pin number is 2 + 1*8 = 10.


    So the call to set this pin would be:

    Code
    1. BYTE pin = 10;
    2. DeviceIoControl(hDev, IOCTL_DIO_SET_PIN, &pin, 1, NULL, 0, NULL, NULL);


    But please keep in mind that all these solutions, even the special purpose device driver, have to call the atomic access function in the kernel, which slows down things noticeably. Really high speeds are not possible this way.


    Best regards,


    H. Keller

    Quote from "hamid"

    I would like access to ports and interrupt pins directly.


    Well the problem is that different GPIOs of the microcrontroller are used internally for different purposes, not just the external GPIO that you see. When accessing the (internal) ports, you have to make sure, that your access does not interfere with the internal access of other device drivers using the other pins.


    So you can't just read and write the processor registers, but you *must* call some functions providing mutual exclusive access. There is no way of avoiding this or the board will eventually crash. And exactly this mutual exclusive access is provided by our DIO driver. Therefore I can't see how you can get much faster by direct access to the GPIO.


    Regards,


    H. Keller

    Quote from "hamid"

    I Used FS-Bus and measured ADE signal and was not compatible with fs-document. I saw in document that pulse width of ADE is (Tas+Tcwc+Tah = 20+180+20 = 220 ns) but when I measure that in oscope i saw it was 5.8µs and difference between those are very high.


    The document only shows minimal times. They are determined by the hardware gate delay times and are more or less the same on all our NetDCU boards.


    However, some signals, and ADE is one of them, are driven by General Purpose I/Os (GPIO). The way how GPIOs are handled differs from microcontroller to microcontroller. The NetDCU8 (and I assume we are talking about this board) requires some overhead to handle GPIOs, making GPIO access a little slower than on other NetDCU boards. This results in the longer ADE pulse on this board.


    However this should still give you speeds of about 100000 Hz on the parallel FS-Bus.


    Regards,


    H. Keller

    Quote from "YoMas"

    After writing the application it should stay 'forever' on the NETDCU8. Clearly I have to flash the .exe, but libraries are demanded, too.


    In EVC++ you can see what files are downloaded. And you can see on the device itself, what files are there when debugging. These are the files you need.


    Quote

    How can I get the information which pieces of code I also have to flash?


    While debugging your code, use the Remote Process Viewer. In the top window, click on your program. Then you'll find all required DLLs listed in the bottom window. Most of them should already be available from the kernel (in the windows subdirectory), so you won't need to store them yourself.


    Regards,


    H. Keller

    Quote from "DennisB"

    The PicoMOD1 is delivered with Win CE 5.0. By default Win CE 5.0 already has its own FTP-server but you deliver your own.


    No. The FTP server included with the PicoMOD1 is the common one from Win CE 5.0.


    Quote

    Thus I got the question what servers and other modules can I expect to have installed (especially RAS-server)?


    The current state of the PicoMOD1 is similar to the NetDCU8. You can have a look here or here for German documents, or here and here for English documents. Especially the FirstSteps and the Drivers documents should give some hints about the usable modules.


    Regards,


    H. Keller

    Quote from "oscar"

    Do you know anything more about the dialogs and Compact Framework ?
    I still have problems.


    I assume you have installed the kernel with CF1.1. Now when you store your application on the board, e.g. in FFSDISK, then restart the board and start your application, the problem should not appear.


    On the other hand, if you use the VS2005, download the code to the board and run it from the debugger, then VS2005 will download the new CF2.0 together with the program. So in this constellation the problem will appear again *even* with the CF1.1-Kernel. Because the downloaded CF2.0 from the debugger will override the pre-installed CF1.1.


    My suggestion is: test your application, ignore the window error. When everything is done, store your applicatiojn in FFSDISK, reboot the board and try again (without debugging). Then the window error should have disappeared.


    Quote from "oscar"

    My application works now in a competitor PC board with Win CE 4.2 and CF 1.0


    I'm sorry to hear this. But as the problem is inside of CF2.0, we have no influence on it. The problem is a problem of Microsoft, not our company. You will have the same problems on the other board when using CF2.0 there. In fact I can't believe that you are using VS2005 there, as this requires CF2.0 on the target.


    Regards,


    H. Keller

    Quote from "Kelkafa"

    But when i try to start the download i get the error Can't start block mode.


    This download feature is a special feature required on our DCU boards. You can *not* use it on the NetDCU boards. There instead you have to prepare the boot monitor to accept the download file (as Mr. Zutter already told) and then you have to transmit the file with "Transmit Binary File..." from the "File" menu.


    Regards,


    H. Keller

    OK, we have narrowed it down a little bit more. The problem depends on the Compact Framework. When using CF1.1, the problem does not exist, only when using CF2.0. Currently we are investigating further, what we can do.


    Regards,


    H. Keller

    Quote from "YoMas"
    Code
    1. m_hSPort = CreateFile( pszName,
    2. GENERIC_READ | GENERIC_WRITE,
    3. 0,
    4. NULL,
    5. OPEN_EXISTING,
    6. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_RANDOM_ACCESS,
    7. NULL
    8. );
    9. ...
    10. WriteFile (m_hSPort, &bDaten[0], 1, &dwBytesTransferred, NULL);


    When using FILE_FLAG_OVERLAPPED, you have to give the OVERLAPPED structure to the WriteFile() function. However overlapped access is not supported in WinCE anyway, so maybe removing the FILE_FLAG_OVERLAPPED is already the solution.


    In addition the serial port is a hardware device that can only be read and written sequentially. There is no way of using random access (seek, etc). So you have to remove the FILE_FLAG_RANDOM_ACCESS also. And you can not change the attribute of the COM-port file, therefore also leave out FILE_ATTRIBUTE_NORMAL.


    Now try again...


    Regards,


    H. Keller

    Hi Paul,


    now I've also had time to investigate your RS232 problem. I think the main problem is that you continuously are creating new data and the garbage collector never gets a chance to run, until the memory is very low, when it is forced to run or otherwise new memory could not be allocated.


    I don't have the source code of the Rs232 class, but I assume that the IN and OUT buffers are some dynamically allocated arrays with a write and a read pointer. For example when you write a byte to the port, you add it at the current write position to the OUT buffer and the write pointer is incremented. When the hardware can accept the next byte to send, it takes the next byte from the read position of the OUT buffer and increments the read position. This is a rather common implementation of a FIFO.


    When you discard the contents of the buffer, the buffer is not really deleted, but only the read pointer is immediately moved to the same value as the write pointer, which means there is no valid byte in the buffer anymore.


    When writing new data, the buffer is continuously appended by newly allocated memory, and the garbage collector has the job to "clean up" the old unused memory behind the read pointer.


    Quote from "Paul Metcalfe"


    Using my theory above, the automatic garbage collector never gets a chance, as you continuously do something. But the garbage collector only runs, when the board is idle. Therefore from my point of view, forcing the garbage collector to run by calling GC.Collect() somewhere within this loop should help in this case.


    Nevertheless this code is very bad style. Software accessing asynchronous hardware should not poll it in a busy loop, but instead should be event-driven, i.e. the reading thread should go into a wait-function and sleep until the port reports that bytes are available and wakes up the thread.


    Now let's look at the next example.

    Code
    1. ...
    2. While (True)
    3. x(0) = 42
    4. Rs232.Write(x, 0, 1)
    5. If (Rs232.BytesToRead > 0) Then Rs232.Read(x, 0, 1)
    6. Rs232.DiscardInBuffer()
    7. End While
    8. ...


    This code definitely won't work and will fill up the write buffer. Every time the loop runs, it will write one byte into the write buffer. Always and ever. The write buffer will grow very fast. Sometimes you will read a character when transmission of one byte at serial speed is finished. The DiscardInBuffer() usually has no job, as the one byte that you may have gotten is already read in the line before. Only in the rare case, when a character is fully received in the tiny time period after the read and before the discard line, this function will have any effect.


    Result: These examples are no proof that the Rs232 class is not working properly. Both programs have a flaw and most probably will work when done correctly.


    Regards,


    Hartmut Keller

    Quote from "oscar"

    3. Code example :
    ....
    if (Form5.ShowDialog() == DialogResult.OK)
    {
    .....
    }


    Are you sure that you're not running in some loop, opening the dialog again yourself? Can't you set a breakpoint after the dialog and step through the program?


    Did you override any functions of the dialog class? Probably there is the part where the redrawing occurs. Try to comment away the code of these functions one by one to narrow down the position of the error.


    Regards,


    H. Keller

    Quote from "YoMas"

    In the projects setting I used for the output "minimize size". This seems to corrupt the output, so that threads do not work anymore.


    Sometimes this is a hint for some programming bug, for example uninitialised variables or missing "volatile" on variables. When optimizing for size, the compiler rearranges the code and often uses processor registers instead of variables in RAM. Example:


    Code
    1. static BOOL flag = FALSE;
    2. // then later within thread function:
    3. while (!flag)
    4. Sleep(1000);


    This code waits until the "flag" variable is set by another thread, e.g. the main program, and then continues. For not using all CPU time, it waits for 1 second before checking "flag" again. This code will most probably work with optimization turned off, but it will definitely fail with optimization turned on.


    Why?


    With optimization turned off, the compiler transfers the code line by line to the internal machine code. So it always uses the RAM variable "flag" directly. If another thread modifies the variable, this thread will automatically see it when loading "flag" the next time. The internal step by step machine code will basically look like this:

    Code
    1. 1: Load register X from RAM with value flag
    2. 2: If register X is non-zero, goto 5
    3. 3: Call subroutine Sleep
    4. 4: Goto 1
    5. 5: ...


    But when optimizing the code, the compiler will look at the whole function at once, trying to rearrange things in a better (more optimal) way, avoiding unnecessary work at runtime. And therefore it will recognize that you are never changing the value of variable "flag". Therefore this is a loop invariant and the compiler will move the loading of the variable and the check in front of the loop. If the value is FALSE the first time and as it is not changed within the loop, then it will stay FALSE and it does not make sense to perform this check over and over again. So the resulting code will look like this:

    Code
    1. 1: Load register X from RAM with value flag
    2. 2: If register X is non-zero, goto 5
    3. 3: Call subroutine Sleep
    4. 4: Goto 3
    5. 5: ...


    Please note that lines 1 and 2 are not in the loop anymore. So in fact lines 3 and 4 are an endless loop now.


    The solution is to use "volatile". We have to tell the compiler by hand, that "flag" is a special kind of variable, that can change the value at any time.

    Code
    1. static volatile BOOL flag = FALSE;


    Now the compiler is forced to always use the RAM variable, because the value may change for other reasons than from our own local code. This will result in code semantically more similar to the first version, that will work again. For example:

    Code
    1. 1: Goto 3
    2. 2: Call subroutine Sleep
    3. 3: Load register X from RAM with value flag
    4. 4: If register X is zero, goto 2
    5. 5: ...


    Please note that this is an improved (optimized) version compared to the first one, as the loop now only consists of three instructions (2-4) instead of four as before. This could only be achieved by rearranging the sequence of the commands. And that is exactly what is done during optimization.


    Summary:
    Working with threads is more or less parallel programming. This requires a *very* thorough attention how to synchronize all parallel tasks. Sometimes it requires mutexes, semaphores or critical sections. And of course "volatile" variables. Almost all variables that are accessed from different threads need "volatile".


    Regards,


    H. Keller

    Here is a first remark, that will not solve your problem, but may help you (and others) posting further program examples. If you use the Code-Tag of this forum, then your source code will look much nicer. Well, ok, coloured highlighting is not possible anymore then, but the correctly indented lines outweigh this small disadvantage.



    Regards,


    H. Keller

    Quote from "JimmyFung"

    I want to define the memory allocation between the programs memory and the storage memory.


    Are you talking about the flash memory or RAM?


    H. Keller

    Quote from "JimmyFung"

    thank you to answer me, but there is always a shift in the middle of the screen. The display driver is not good.
    Maybe that the problem comes from the display.


    Or maybe your connection cable is too long. On VGA resolution, it should be less than 10cm.


    Regards,


    H. Keller

    Well, it is not a question of modifying some settings. It would require much more.


    Explanation:


    The touch panel driver is regularly called from Windows to return a pair of measured values. Then Windows itself does the conversion to display coordinates, depending on the current calibration parameters. The result is used as a mouse click, mouse drag, or mouse release event.


    If you want to have a bigger panel than the display size, the following two problems occur:


    1. Windows may clip the measurement values when converting them to coordinates, reducing them to the display size. I.e. if you want to have buttons left of the display, you would need negative coordinates, but Windows will restrict these values to zero.


    2. You would have to draw virtual buttons at some coordinates outside of the visible window, so that the mouse click produced by Windows would activate the button. This is not possible.


    So how about modifying the touch panel driver? Difficult!


    3. The driver does not know the mapping of analogue values to display coordinates, as all calibration stuff is done by Windows, not by the driver. Therefore the driver can not tell when you are inside the visible area (=display), to produce a mouse clicks, and when you are outside of the visible area (=key region) to produce (virtual) function key activations.


    4. The outside region would have to produce a completely different way of communicating the pressed virtual key back to Windows. But neither has the touch panel driver direct access to the keyboard driver, nor is there another easy way to do this.


    5. The outside part of the touch panel needs some calibration, too. Otherwise, no mapping to virtual function keys would be possible. How can this be done?


    As a result of these thoughts, I have to say this is really no simple task. It involves modifications deep inside of different Windows drivers, even in the structure of the communication paths designed by Microsoft.


    Maybe you can read the raw values of the touch panel. Then you have the full power over the coordinates. But then you have to do all calibration and conversion stuff yourself, too.


    Regards,


    H. Keller

    I found a display setting for this display. Probably you can try this.



    Regards,


    H. Keller

    Quote from "zik"

    2. Power on NetDCU6.
    3. Pressing S while NetDCU6 is booting doesn't start boot loader, I can't step in it, can't get :> prompt.


    It's easier to press the 'S'-key before starting the board. Stay on the key so that the key repeats and then with the other hand switch on the power to the NetDCU. During all this time don't release the 'S' key. It should continuously send the character over the serial line. It is also important to send an upper case 'S', not lower case 's'.


    Regards,


    H. Keller