Programming notes - SC12 @CHIP-RTOS V1.10

    IPC@CHIP Documentation Index


Here are some useful notes for programming applications for the IPC@CHIP.
These notes contains general rules for programming DOS applications for the IPC@CHIP and important information about internals of the @CHIP-RTOS which can prevent the programmers from making fatal errors.

  • Common notes for building IPC@CHIP user applications
  • Using RTOS API
  • Programming CGI functions
  • Configure the FTP server
  • Usage of the TCP/IP API
  • General notes for the usage of the DOS and @CHIP-RTOS int API calls
  • Using Hardware API
  • Using Fossil API
  • Working with Float Data Types
  • Configure PPP client or server

  • Common notes for building IPC@CHIP user applications

    1. Limited Flash Write Cycles (of IPC@CHIPs internal Flash):
      To open files on the flash disk drive A: for reading or writing, you can use the standard C functions fopen or open.   We recommend the use of the fopen/fread/fwrite calls instead of open/read/write to reduce the flash write cycles, because these cycles are limited.
      For further information see the FlashWriteCycles document.

    2. Compiler option settings:
      We recommend the usage of large memory model for user applications.
      The compiler must produce 186 processor instruction code.
      The data alignment must be set to 8 Bit (Byte alignment), not to 16-Bit (Word alignment)!

    3. No "exception handling" at Borland C 4.x or 5.x projects:
      Users of Borland C-Compilers (which provides "exception handling libraries" as it's default setting for 4.5 or 5.02) should choose for their program project "No exceptions" at the "Target Expert" window.   This setting saves Flash and RAM memory space.

    4. Do not select "Test stack overflow" at Borland C 4.x or 5.x project compiler settings:
      If "Test stack overflow" is selected a stack check is done at every function call.   If stack overflow is recognized the program halts.
      This mechanism is not usable in user applications which are using several tasks inside their application, because every task has its own stack and the Borland runtime library stack functions are not aware of this.

    5. Turbo Pascal programmers should include the example file SC12.INC (part of each IPC@CHIP Pascal example program).   At the start of their program, they should install the procedure Terminate_Program as the default exit procedure of the program.   Usage of the standard unit crt is not allowed.

    6. Before starting the first Turbo Pascal program at the IPC@CHIP the memopt 1 command must be executed (e.g. in the autoexec.bat)

    7. If programs that depend on one another are started from a batch file (e.g. if a user program needs a previous driver program) the Batchmode 1 in chip.ini should be set.

    8. The old CLIB library (< V2.00) and some older examples are using the standard int86 and int86x calls from the Borland C standard library.   We used these functions for more readable code.   If developers need higher performance in their applications, it will be better to use the new CLIB library (>= V2.00) which implements the API calls with inline assembler code.   With inline assembler instructions it is possible to load the processor registers directly with the needed parameters and directly invoke the appropriate software interrupt int xxh.

    9. For certain reasons it is not advisable to design an IPC@CHIP application as a set of several DOS programs:
      1. It is more meaningful to run several tasks (built with the RTOS API) inside of one DOS program because this requires much less RAM and Flash memory space, than running several DOS programs as tasks of the @CHIP-RTOS.
      2. It can lead to high memory fragmentation and insufficient memory, if more than one or two DOS programs are running on the IPC@CHIP, which will be often terminated and restarted again.

    10. Most of the used pointer variables and function parameters in the old CLIB library C files (< V2.00) are not declared as FAR pointer, because all of our test programs are using the memory model Large (at model Large all pointers become automatically FAR pointers).   If you want to use e.g. memory model Small for your application you should use the new CLIB (>= V2.00) and declare the pointer variables and function parameters inside your program explicit as FAR pointers.

    11. It is not advisable to use in your application the Borland C-library malloc function with memory model Large.   In that case the DOS program tries to increase its own memory block with int21h 0x4A.   If another program is loaded after that program the malloc call fails, because there is no memory space left between the two programs.   It is possible to define a memory gap between two loaded programs at chip.ini but then you must know what maximum memory is required by your malloc calls.   It is better to reserve inside of your application the memory by declaring an unsigned char array (or the type you require) with the needed memory size.

    12. The @CHIP-RTOS has its own memory strategy.
      The @CHIP-RTOS always allocates memory in the following way:
      DOS programs are always loaded at the first lowest free memory block. For memory blocks allocated inside of the @CHIP-RTOS or e.g. with DOS service 0x48 the @CHIP-RTOS always start searching for a free memory block from the highest possible RAM address.   So the largest free memory block of the system is always located in the middle of the @CHIP-RTOS memory area.   The shell command mem shows the state of the internal memory map.

    Top of list
    Index page

    Using RTOS API

    1. Timer procedures must be implemented as short as possible, because they are executed in the Kernel task. Large timer procedures are blocking the kernel and other tasks of the @CHIP-RTOS.   Do not use large Clib functions like printf inside of a timer procedure.   This can cause a fatal stack overflow in the kernel task (stack size 1024 Bytes)

    2. Declaring of timer procedures with Borland C:
      void huge my_timer(void)

    3. Microsoft C:
      void far _saveregs _loadds my_timer(void)

    4. Turbo Pascal:
          procedure Timer1_Proc;interrupt;
          [... your code ...]
          (* This is needed at the end of the Timer Proc. *)
               POP BP
               POP ES
               POP DS
               POP DI
               POP SI
               POP DX
               POP CX
               POP BX
               POP AX

    5. DOS applications are running as a task of the @CHIP-RTOS with a default priority of 25.   If the users application doesn't go to sleep, lower priority tasks like the FTP server or the Web server will not work.   In major loops within user applications, the programmer should insert sleep calls if the FTP server or Web server should work during the runtime of the user application.

    6. The stack of a task created inside of a DOS application should have a minimum stack size of 1024 Bytes.   Programmers of task functions who are using Microsoft C-Compilers with C-Library functions, e.g. sprintf, which requires a lot of stack space should increase this allocation to 6144 (6 Kbytes).   More stack space for the task is also required if your task function uses a large amount of stack for automatic data (local variables) declared inside the task function call.

    7. Declaring of task functions with Borland C:
      void huge my_task(void)

    8. Declaring of task functions with Microsoft C:
      void far _saveregs _loadds my_task(void)

    9. Before exiting an application, every task or timer procedure created inside of this application program must be removed.

    10. A sleep call with parameter 1 millisecond takes equal or less than one millisecond.   If a user needs a minimal sleep time of 1 millisecond then RTX_SLEEP_TIME must be called with value 2 milliseconds.

    11. It is possible to create tasks with a time slicing value in the taskdefblock structure..   Please note that the kernel executes time slicing only between tasks which have same priority.   Other priority tasks are not affected.

      RTOS API

    Top of list
    Index page

    Programming CGI functions

    1. Avoid large loops inside of CGI functions.   CGI functions must be executed
      as fast as possible.   Large execution times in CGI functions block
      the Web server task preventing response to other http requests.

    2. Declaring of CGI functions with Borland C:
      void huge my_cgi_func(rpCgiPtr CgiRequest)

    3. Declaring of CGI functions with Microsoft C:
      void far _saveregs _loadds my_cgi_func(rpCgiPtr CgiRequest)

    4. Declaring of CGI functions with Borland Turbo Pascal:
      procedure my_cgi_func;interrupt;

    5. Turbo Pascal users must install their CGI functions with API call Install CGI Pascal function

    6. C-Programmers must use Install CGI function

    7. Avoid the declaration of large arrays as local variables inside
      of the CGI function to prevent stack overflows

    8. Users of Microsoft C should set Web server stacksize in chip.ini up to 6144 KBytes,
      to prevent stack overflows, if Microsoft CLib functions like sprintf are used.

    9. Dynamic HTML or text pages, which are created inside of a user CGI function should be as small as possible.   The Web server inside must allocate a temporary buffer for storing this page before sending it to the browser.   If your application builds large dynamic HTML page in RAM, your application should not use all available memory in the IPC@CHIP because the Web server will need some memory for allocating temporary buffers for this page.   How much memory should be left:   This depends on the application and the sizes of the created dynamic HTML or CGI pages.

    10. Before exiting an application, every CGI function installed by the application must be removed with Remove CGI page

      CGI API

    Top of list
    Index page

    Configure the FTP server

    1. The default FTP idle timeout is set to 300 seconds.   This is a very long time for waiting, if FTP commands fail.   The idletimeout can be reduced in chip.ini.

    Top of list
    Index page

    Usage of the TCP/IP API

    1. Processing of a socket callback functions (see Register callback) should be kept at a minimum to prevent stack overflows.

    2. Declaring of socket callback functions with Borland C:
      void huge my_callback(int socketdescriptor, int eventflagmask)

    3. Declaring of socket callback functions with Microsoft C:
      void far _saveregs _loadds my_callback(int sd, int eventmask)

    4. The internal TCP/IP stack of the IPC@CHIP allocates memory for buffers smaller than 4096 bytes from a pre-allocated memory block.   Larger buffers are allocated direct from the CHIP-RTOS.   If user TCP/IP network communication sends/receives packets with a size larger than 4096 bytes, the user application should not use all available memory in the IPC@CHIP because of these additional allocations.   There should be in that case always a minimum of 30-40 KBytes of free available memory in the IPC@CHIP. The mem command shows the whole memory list of the IPC@CHIP at runtime.   The maximum amount of TCP/IP memory can be configured at chip.ini (see Set TCP/IP memory size).   The application programmer can reduce or increase this size in chip.ini.   With the API call Get TCP/IP memory info it is possible to control the TCP/IP memory usage at the application runtime.

      TCP/IP API

    Top of list
    Index page

    General notes for the usage of the DOS and @CHIP-RTOS int API calls

    1. At the start of a user program the Stdio focus should be set to USER. Before ending the application switch the focus back to SHELL or BOTH (see Set Stdio focus).

    2. If more than one user program runs in the IPC@CHIP, only one of them should read characters from Stdin

    3. The functionality of most of the shell commands is also available through calls into the @CHIP-RTOS INT API.   If not, use the @CHIP-RTOS INT call Execute a shell command.   This call executes a shell command from inside the user application.

    4. Install a fatal user error handler, which does a reboot of the IPC@CHIP with Install user fatal error handler

    5. Used software interrupts (all others are free for use):

      0x00 - Reserved (@CHIP-RTOS Divide Overflow Handler)
      0x01 - Reserved (Debugger Trace Interrupt)
      0x02 - Reserved (Hardware Non-Maskable Interrupt (NMI))
      0x03 - Reserved (Debugger Breakpoint Interrupt)
      0x04 - Reserved (@CHIP-RTOS INTO Overflow Handler)
      0x05 - Reserved (@CHIP-RTOS Array Bounds Exception Handler)
      0x06 - Reserved (@CHIP-RTOS Invalid Opcode Exception Handler)
      0x07 - Reserved (@CHIP-RTOS ESC Opcode Exception Handler)
      0x08 - Reserved (Hardware, Timer #0 Handler)
      0x0A - Reserved (Hardware, DMA #0 / INT5 Handler)
      0x0B - Reserved (Hardware, DMA #1 / INT6 Handler)
      0x0C - Reserved (Hardware, INT0 Handler)
      0x0D - Reserved (Hardware, INT1 Ethernet Handler)
      0x0E - Reserved (Hardware, INT2 Handler)
      0x0F - Reserved (Hardware, INT3 Handler)
      0x10 - Biosint
      0x11 - Biosint
      0x12 - Reserved (Hardware, Timer #1 Handler)
      0x13 - Reserved (Hardware, Timer #2 Handler)
      0x14 - Fossil Interface
      0x16 - Biosint
      0x1A - Biosint
      0x1C - Timer Interrupt, see Set timer 1C interval
      0x20 - Terminate Program (Only for compatibility, instead use DOS service 0x4C)
      0x21 - DOSEmu Interrupt Interface
      0xA0 - Several 'chip' related services
      0xA1 - Hardware API (HAL)
      0xA2 - Hardware API (PFE)
      0xAA - I2C Interface
      0xAB - CGI Interface
      0xAC - TCP/IP API
      0xAD - RTOS API
      0xAE - Ethernet Packet Driver
      0xAF - Timer Interrupt, see Set timer AF interval
      0xB0 - External Disk API
      0xB1 - External Disk Driver
      0xBF - This vector is reserved to start a DOS executable

      If you are using a BIOS variant in which some modules are not included, then the interrupts corresponding to these modules are free for use.

    6. External hardware interrupts are enabled (STI opcode) during execution of the following API software interrupts:
      DOS ints 0x10, 0x14(Fossil), 0x16, 0x20, 0x21, @CHIP-RTOS int 0xA0, CGI int 0xAB, PFE int 0xA2, I2C int 0xAA, CGI int 0xAB, Pkt int 0xAE, Extdisk int 0xB0, Extdisk user int 0xB1

      The state of the interrupt flag is not changed during the execution on the following API software interrupts (If interrupts are disabled before the API call, they are kept disabled during execution of the call. If interrupts are enabled before the API call, they get reenabled during execution of the call.):
      TCPIP int 0xAC, RTOS int 0xAD

      External hardware interrupts are disabled during execution of the following API software interrupts:
      HAL int 0xA1

      BIOS ints

    Top of list
    Index page

    Using Hardware API

    1. The HAL functions keep interrupts disabled, so you can call them inside an interrupt routine. The PFE functions are only for choosing and initializing a specific function on the selected pin.   They should be called once in your application for initializing your hardware environment and not at runtime or inside interrupt routines.

    2. Do not use functions of the RTOS API inside of a normal HW API user ISR. For this purpose install a RTX user ISR, see Install ISR.

    3. The latency time of the user ISR (from generation of an interrupt until first line of code inside the user ISR) depends on the used IPC@CHIP, see Performance comparision .

    4. Instead of HAL functions Read data bus and Write data bus you can call C-functions inportb and outportb from DOS.H for faster data bus accesses.

    5. Usage of DMA0/INT5 and DMA1/INT6:
      DMA0 and INT5 are served inside the @CHIP-RTOS with a single shared interrupt handler.   (Likewise for DMA1 and INT6.)
      If an user application has activated serial EXT DMA mode and also wants to use external interrupt INT5, the DMA interrupt event is higher priority.  (And again, likewise for COM DMA mode and INT6.)
      This means that if a DMA0/1 interrupt occurs simultaneous with an external INT5/6 interrupt, the installed user handler for the external interrupt is not called.

      See Hardware API

    6. Usage of NMI/Power fail detection:

      The NMI function of the multifunction pin 17 (RESET/NMI/LINK_LED) of the IPC@CHIP SC11/SC12/SC13 is for power fail purposes only. It is not possible to use NMI as a "normal" interrupt pin like e.g. INT0 for generating interrupts. It can only be used as described in the IPC@CHIP hardware documentation.

      The flowchart below describes how the @CHIP-RTOS handles an incoming NMI interrupt.

      See also:
      Install interrupt service routine
      Init non-volatile data
      Save non-volatile data

    Top of list
    Index page

    Using Fossil API

    1. The receive and send queue size can be configured over the CHIP.INI.

    2. If you want to use external DMA, you have to disable the serial DMA receive mode.   Otherwise the DMA receive mode is recommended.

    3. Since @CHIP-RTOS 1.02B XON/XOFF mode is available also with the serial DMA receive mode in use.
      Please note:   Because of the internal functionality of DMA it is not possible to immediately detect an XON or XOFF character from the connected peer.   It is possible that an overrun situation at the peer (e.g. GSM modem) can occur.   Nevertheless we enable this mode because some GSM modems (any??) support only XON/XOFF as serial flow control mechanism.

    4. The default serial receiver queue size is 1024 bytes.   If the default DMA receive mode is used, it is advised to increase the receiver queue size in Chip.ini up to a minimum value of 2048 bytes to prevent a possible buffer overrun (even if hard handshake is used).   This can only happen with the default queue size of 1024 bytes if the user doesn't call the Fossil API read block function frequently enough.   If the application programmer does not increase this buffer size up to the recommended value, they should call the Fossil API read block function with sufficient buffer size in the CX-Register to flush the internal buffers and prevent a receive buffer overrun.

    5. Serial ports, running with IRQ receive mode:
      The two serial ports of the IPC@CHIP have no hardware FIFO buffer.   Only one incoming character can be stored direct by the ports.   As a consequence of this behaviour, it is possible that incoming characters get lost because of missed or delayed receiver interrupt execution (see Operating mode of serial ports).   E.g.: Writing a flash sector (e.g. happens when writing a file at Drive A:) disables all interrupt execution for about 15 ms.   If the serial port is configured with a baud rate of 9600, incoming characters can be lost during this time.
      Loss or delayed execution of serial receiver interrupts depends on the number and the execution frequency of all enabled interrupts in the IPC@CHIP system.   It depends also on execution times of users interrupt service functions and the duration of interrupt masking periods (CLI / STI instruction sequences).

    6. For a given serial port the fossil functions are not reentrant.   Do not call fossil functions for the same serial port from different tasks.   However for different serial ports, the fossil functions are reentrant.   E.g. task A can operate the COM port using fossil functions concurrently with task B operating the EXT port using the same fossil functions.

      Fossil API

    Top of list
    Index page

    Working with Float Data Types

    1. The IPC@CHIP does not provide a floating point co-processor.   So if you want to use floating point data types you need to enable the math-emulation in your compiler.   In Borland C++ 5.02 see the option "Emulation" under the Target Expert's (right mouse click on your Exe-file in your project) "Math Support".

    2. The Borland Math Emulation libraries are not made for usage in a multitasking system like the @CHIP-RTOS.   If you want to use float data types in tasks other than your main (DOS) task, please pay attention to the following work around solution (Using Borland 5.02, Memory model large):

      a)   For floating point emulator usage, the current stack (the stack of the task) must have offset 0. To achieve this, the task stack must be far array located in a separate segment:

      unsigned int far task_stack[TASK_STACKSIZE];

      Note:  The CGI callbacks execute on the Web server's stack, which satisifies this "offset 0 present" requirement.

      b)   The current stack must be pre-initialized for math emulation:

      void my_emu1st(void)
              mov word ptr ss:[0x2f],0x0065 // set end of FPU stack
              mov word ptr ss:[0x31],0x0125 // set start of FPU stack
              mov word ptr ss:[0x27],0 // no protected mode
              mov byte ptr ss:[0x26],0 // no 8087

      c)   Before executing floating point arithmetic, call the Borland library function _fpreset, which initializes the stack for floating point emulation.

      Example for a task function:

      void huge my_task(void)
          float a;
          // ..... ready for executing floating point arithmetic

      If you are interest in more details, take a look at the Borland 5.02 RTL sources (fpinit.asm).   We will provide an example for using floating point arithmetic in separate tasks or within CGI callbacks.

    3. Using Math emulation with Borland C++ 5.02 (also for older versions of Borland C) produces a conflict between the NMI interrupt of the @CHIP-RTOS (Interrupt Vector 0x02) and the Borland floating exception handling.   Borland C math emulation also uses INT 2 for generating floating point exceptions.   Our internal NMI interrupt service function (normally called at power fail case) will no longer execute during the runtime of the user's application.   We have provided a solution which moves the Borland exception function from INT 2 to another interrupt vector.   We modified the Borland RTL source (fpinit.asm) and include the modifications directly into the application project.   It is planned to provide an example in our Internet download area.

    Top of list
    Index page

    Configure PPP client or server

    1. Connected modems should be configured in chip.ini with the modem command ATE0 INITCMD.   This prevents the modem from echoing characters to the peer in command mode.   The COM and the serial ports of the IPC@CHIP have only 4 lines (TxD/RxD/CTS/RTS) and no line for detecting a hang-up of the modem.   Because of this fact we provided the Idletimeout and the MODEMCTRL configuration features in chip.ini or in the PPP client init structure type. But the idletimeout and modemctrl detection can fail if a modem has switched its echo mode on.   If the peer modem hangs up without correctly closing a PPP session, the IPC@chip modem also hangs up and goes into the command mode.   Because of the missing line for detecting a modem hang-up, the PPP server doesn't know anything about the broken connection and still sends PPP frames to the modem.   It can happen that the modem echoes these characters back to the IPC@CHIP due to being in "Echo on" mode.   This will cause the idletimeout to not work.

    2. We recommend that the PPP server or client and the connected modems should run (if possible) with RTS/CTS flow control (see chip.ini flow control mode or the PPP client init structure type).   Most modems use RTS/CTS flow control, if they get the AT command AT\Q3.

    3. The COM and EXT port of the IPC@CHIP has only CTS, RTS, RxD and TxD lines,
      so you have to configure your modem with DTR always on.
      (e.g. AT cmd for a most modem types: AT&D0)

    4. If the option PPP_IPCP_PROTOCOL (VJ TCP/IP header compression) is set (see PPPCLIENT_SET_OPTIONS), it is possible that the FTP server of the IPC@CHIP is not usable via the PPP interface.   This was noticed at PPP sessions connected to a Linux PPP peer.


    Top of list
    Index page

    End of document