Skip to content

Porting picoTCP HW

Daniele Lacamera edited this page Jun 10, 2018 · 16 revisions

PicoTCP can run on several different hardware architectures and can be integrated with virtually any operating system or within a standalone application. It is possible to run PicoTCP on big-endian as well as little-endian CPU configurations. PicoTCP uses gcc-specific tags that may not be compatible with other compilers. The amount of resources needed may vary depending on the modules that are compiled-in. However, adapting to a specific hardware platform or for a particular use may require some integration effort.

Warning:

ensure that the license of your Board Support Package (BSP) is compatible with the license of PicoTCP you are using before distributing any derivative works.

Port interface

PicoTCP relies on a simple set of system-specific calls that must be implemented externally from the target. Briefly, the interface needed for the stack to run is composed by:

  • A mechanism to allocate memory dynamically on the target (malloc/free)
  • A stable, monotonic time source variable, in milliseconds, to update internal timers

For the memory allocation interface, two symbols have to be defined by the system:

  • void *pico_zalloc(uint32_t size) - memory allocator that allocates an object of the given size and set its content to 0
  • void pico_free(void *ptr) - memory deallocator

For the time keeping, the following objects must be defined by the system:

  • static inline unsigned long PICO_TIME(void) - Returns current time expressed in seconds
  • static inline unsigned long PICO_TIME_MS(void) - Returns current time expressed in milliseconds
  • static inline void PICO_IDLE(void) - Sleep between two consecutive iterations inside the main protocol loop (e.g. to yield the CPU to some other functionality on the system, waiting for IRQs, etc.)

Finally, whenever debug information is needed, the system will have to provide a dbg() function that accepts the same variadic arguments model as a standard printf(). This way the debugging output of the stack can be redirected elsewhere (e.g. UART or file).

Porting Example

If all the above requirements are satisfied, PicoTCP expects those functions to be mapped to existing code in the BSP of the architecture. An easy way to do so is by means of a new architecture-specific header file under the include/arch subdirectory. Since all the functions above must already be implemented outside the PicoTCP tree, the library will have to be linked to the system support library, either during compilation or at at a subsequent stage when the resulting firmware is being generated. For this reason, a prototype of all the functions used to implement the functionality requested by the BSP must be included from the architecture support header file or incorporated into the file itself. For instance, if the BSP for an architecture called "foobar" and provides the following functions:

void *custom_allocate_and_zero(int size);
void custom_free(void *mem);
int print_serial_debug(...);

and an interrupt handler is attached to a time source in order to increment the pico_ms_tick variable every millisecond, a possible architecture-specific file (arch/pico_foobar.h) should look like the following:

/* declare the prototypes used as extern symbols */
extern void *custom_allocate_and_zero(int size);
extern void *custom_free(void *mem);
extern int print_serial_debug(...);
#define dbg print_serial_debug
#define pico_zalloc(x) custom_allocate_and_zero(x)
#define pico_free(x) custom_free(x)

static inline unsigned long PICO_TIME(void)
{
    return pico_ms_tick / 1000;
}

static inline unsigned long PICO_TIME_MS(void)
{
    return pico_ms_tick;
}

static inline void PICO_IDLE(void)
{
    unsigned long tick_now = pico_tick;
    while(tick_now == pico_tick);
}

Once the architecture-specific file is created, it is possible to add the architecture-specific support to the pico config.h file, the same way it is done for the existing architectures, using an additional preprocessor elif block:

/* ... */
#elif defined FOOBAR
#include "arch/pico_foobar.h"
/* ... */

From this point on, it is sufficient to define a preprocessor variable with the keyword chosen for the architecture, all in capitals ( FOOBAR in this example case). The final step is to create a block in the main PicoTCP makefile that also sets the compiler ags needed to produce objects that are compatible with and/or optimized for the foobar architecture. Additionally, this block also contains the definition of the keyword preprocessor macro in order to have the correct arch-specific header included:

ifeq ($(ARCH),foobar)
    CFLAGS+=-mcustom-foobar-code -DFOOBAR
endif

To compile for the foobar architecture, it is now sufficient to run make ARCH=foobar

Clone this wiki locally