diff --git a/pattern_frame_buffer/Makefile b/pattern_frame_buffer/Makefile
index 3be4be6c6d07b77d8897994428ed716654cf8366..c144ed4391c5262d283c7797896cfd7becdb3aac 100755
--- a/pattern_frame_buffer/Makefile
+++ b/pattern_frame_buffer/Makefile
@@ -11,6 +11,8 @@ COMPILE_OPTS_M0 = -mfloat-abi=softfp -mcpu=cortex-m0
 COMPILE_OPTS_M0plus = -mfloat-abi=softfp -mcpu=cortex-m0plus
 COMPILE_OPTS_M3 = -mfloat-abi=softfp -mcpu=cortex-m3
 
+MACROS = -DFB_MAX_BUFFER_LEN=16384 -DFBC_MAX_PATTERN_FUNC=16 -DFBC_MAX_DATA_PATTERN_LEN=32 -D FBC_MAX_COPY_FUNC=4 -DIMG_MAX_NUM_IMAGES=3 -DIMG_MAX_IMAGE_WIDTH=15 -DIMG_MAX_IMAGE_HEIGHT=15 -DMTN_X_LED_SPACING=10 -DMTN_Y_LED_SPACING=10
+
 INCLUDE_DIRS = -I./include/ -I../memory/include -I../scheduler/include 
 
 DOC_DIR = ./doc
@@ -49,13 +51,13 @@ PATTERN_FB_M3_OBJS = $(patsubst %,$(PATTERN_FB_M3_OBJ_DIR)%,$(PATTERN_FB_M3_OBJS
 
 all: $(PATTERN_FB_OUT_M4_FPU) $(PATTERN_FB_OUT_M0) $(PATTERN_FB_OUT_M0plus) $(PATTERN_FB_OUT_M3)
 $(PATTERN_FB_M4_FPU_OBJ_DIR)%.o: $(SRC_DIR)%.c
-	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M4_FPU) -o $@ $<
+	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M4_FPU) $(MACROS) -o $@ $<
 $(PATTERN_FB_M0_OBJ_DIR)%.o: $(SRC_DIR)%.c
-	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M0) -o $@ $<
+	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M0) $(MACROS) -o $@ $<
 $(PATTERN_FB_M0plus_OBJ_DIR)%.o: $(SRC_DIR)%.c
-	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M0plus) -o $@ $<
+	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M0plus) $(MACROS) -o $@ $<
 $(PATTERN_FB_M3_OBJ_DIR)%.o: $(SRC_DIR)%.c
-	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M3) -o $@ $<
+	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M3) $(MACROS) -o $@ $<
 mkdir_build: 
 	mkdir -p build/m4_fpu
 	mkdir -p build/m0
diff --git a/pattern_frame_buffer/include/frame_buffer.h b/pattern_frame_buffer/include/frame_buffer.h
index edf28ebf3b9ee5e993060749835fcb8d8b432177..6b48631151c97075bff569fdc8c376095b4c3f50 100644
--- a/pattern_frame_buffer/include/frame_buffer.h
+++ b/pattern_frame_buffer/include/frame_buffer.h
@@ -5,17 +5,25 @@
 extern "C" {
 #endif
 
-#include "memory.h"
-#include "frame_buffer_registers.h"
-
 #ifndef FB_MAX_BUFFER_LEN
-  #define FB_MAX_BUFFER_LEN    16*1024
+  #error "Please, specify the maximum frame buffer length with the FB_MAX_BUFFER_LEN macro"
 #endif
 
-#define BYTES_PER_PIXEL   3
-#define LEDS_BYTES_PER_PIXEL   12
-
-unsigned char frame_buffer_init(TFrameBuffer *fb,TMemory *memory);
+#define FB_BYTES_PER_PIXEL     3
+
+typedef struct
+{
+  unsigned short int ram_base_address;
+  unsigned short int eeprom_base_address;
+  unsigned short int num_rows;
+  unsigned short int num_pixels_per_row;
+  unsigned short int num_buffers;
+  unsigned short int buffer_size;
+  unsigned short int free_mem;
+  unsigned char pixel_buffer[FB_MAX_BUFFER_LEN];
+}TFrameBuffer;
+
+void frame_buffer_init(TFrameBuffer *fb,unsigned short int ram_base_address,unsigned short int eeprom_base_address);
 void frame_buffer_set_num_rows(TFrameBuffer *fb,unsigned short int rows);
 unsigned short int frame_buffer_get_num_rows(TFrameBuffer *fb);
 void frame_buffer_set_pixels_per_row(TFrameBuffer *fb,unsigned short int pixels);
@@ -23,10 +31,8 @@ unsigned short int frame_buffer_get_pixels_per_row(TFrameBuffer *fb);
 void frame_buffer_set_num_buffers(TFrameBuffer *fb,unsigned char num);
 unsigned char frame_buffer_get_num_buffers(TFrameBuffer *fb);
 unsigned short int frame_buffer_get_free_memory(TFrameBuffer *fb);
-unsigned char frame_buffer_update_buffer(TFrameBuffer *fb);
-unsigned char *frame_buffer_get_pixel_buffer(TFrameBuffer *fb);
-void frame_buffer_set_pixel_buffer(TFrameBuffer *fb,unsigned char *buffer);
-void frame_buffer_set_pixel(TFrameBuffer *fb,unsigned char R,unsigned char G,unsigned char B,unsigned short int row,unsigned short int col, unsigned char *buffer);
+unsigned char *frame_buffer_get_buffer(TFrameBuffer *fb,unsigned char buffer_id);
+void frame_buffer_set_pixel(TFrameBuffer *fb,unsigned char buffer_id,unsigned char R,unsigned char G,unsigned char B,unsigned short int row,unsigned short int col);
 
 #ifdef __cplusplus
 }
diff --git a/pattern_frame_buffer/include/frame_buffer_control.h b/pattern_frame_buffer/include/frame_buffer_control.h
new file mode 100644
index 0000000000000000000000000000000000000000..ed4deeed49e34676641ff1bf7423c07a28a3f337
--- /dev/null
+++ b/pattern_frame_buffer/include/frame_buffer_control.h
@@ -0,0 +1,74 @@
+#ifndef _FRAME_BUFFER_CONTROL_H
+#define _FRAME_BUFFER_CONTROL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "frame_buffer.h"
+#include "patterns.h"
+#include "memory.h"
+#include "scheduler.h"
+
+#ifndef FBC_MAX_PATTERN_FUNC
+  #error "Please, specify the maximum number of pattern functions with the FBC_MAX_PATTERN_FUNC macro"
+#endif
+
+#ifndef FBC_MAX_DATA_PATTERN_LEN
+  #error "Please, specify the maximum number of dtaa for each pattern with the FBC_MAX_DATA_PATTERN_LEN macro"
+#endif
+
+#ifndef FBC_MAX_COPY_FUNC
+  #error "Please, specify the maximum number of copy functions with the FBC_MAX_COPY_FUNC macro"
+#endif
+
+#include "frame_buffer_control_registers.h"
+
+typedef void (*copy_func_t)(void *data);
+
+typedef struct TFBControl
+{
+  TFrameBuffer frame_buffer;
+  TScheduler *scheduler;
+  sched_channel_t sch_channel;
+  unsigned short int period_ms;
+  TMemModule mem_module;
+  unsigned short int ram_base_address;
+  unsigned short int eeprom_base_address;
+  // pattern attributes
+  unsigned char num_patterns;
+  void (*pat_functions[FBC_MAX_PATTERN_FUNC])(TLEDArea *area,void *pattern_data,unsigned char buffer_id,unsigned short int period,struct TFBControl *control);
+  TLEDArea pat_area[FBC_MAX_PATTERN_FUNC];
+  unsigned char pat_buffer_id[FBC_MAX_PATTERN_FUNC];
+  unsigned char pat_parameters[FBC_MAX_PATTERN_FUNC][FBC_MAX_DATA_PATTERN_LEN];
+  // copy attributes
+  unsigned char num_copy_functions;
+  copy_func_t copy_functions[FBC_MAX_COPY_FUNC];
+  void *copy_data[FBC_MAX_COPY_FUNC];
+}TFBControl;
+
+typedef void (*pattern_func_t)(TLEDArea *area,void *pattern_data,unsigned char buffer_id,unsigned short int period,TFBControl *control);
+
+unsigned char frame_buffer_control_init(TFBControl *control,TMemory *memory,TScheduler *scheduler,sched_channel_t ch,unsigned short int ram_base_address,unsigned short int eeprom_base_address);
+void frame_buffer_control_start(TFBControl *control);
+void frame_buffer_control_stop(TFBControl *control);
+void frame_buffer_control_set_period(TFBControl *control,unsigned short int period_ms);
+unsigned short int frame_buffer_control_get_period(TFBControl *control);
+// pattern functions
+unsigned char frame_buffer_control_add_pattern(TFBControl *control,pattern_func_t function,TLEDArea *area,void *data,unsigned char data_length,unsigned char buffer_id);
+void frame_buffer_control_remove_pattern(TFBControl *control,unsigned char index);
+void frame_buffer_control_clear_patterns(TFBControl *control);
+unsigned char frame_buffer_control_get_num_patterns(TFBControl *control);
+unsigned char *frame_buffer_control_get_parameters(TFBControl *control, unsigned char index);
+void frame_buffer_control_update(TFBControl *control);
+// copy functions
+unsigned char frame_buffer_control_add_copy_function(TFBControl *control,copy_func_t function,void *data);
+void frame_buffer_control_remove_copy_function(TFBControl *control,unsigned char index);
+void frame_buffer_control_clear_copy_functions(TFBControl *control);
+unsigned char frame_buffer_control_get_num_copy_functions(TFBControl *control);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pattern_frame_buffer/include/frame_buffer_control_registers.h b/pattern_frame_buffer/include/frame_buffer_control_registers.h
new file mode 100644
index 0000000000000000000000000000000000000000..f44d32dd4e0a7187e457a68f0d1ac9294f072b83
--- /dev/null
+++ b/pattern_frame_buffer/include/frame_buffer_control_registers.h
@@ -0,0 +1,62 @@
+#ifndef _FRAME_BUFFER_CONTROL_REGISTERS_H
+#define _FRAME_BUFFER_CONTROL_REGISTERS_H
+
+#define RAM_FRAME_BUFFER_CONTROL_LENGTH                       (18+FBC_MAX_DATA_PATTERN_LEN+IMG_MAX_NUM_IMAGES*IMG_MAX_IMAGE_WIDTH*IMG_MAX_IMAGE_HEIGHT*3)
+
+#define FRAME_BUFFER_CONTROL_NUM_PATTERN_OFFSET               0
+#define FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET             1
+#define FRAME_BUFFER_CONTROL_OFFSET                           2
+#define FRAME_BUFFER_CONTROL_PATTERN_ID_OFFSET                3
+#define FRAME_BUFFER_CONTROL_MIN_ROW_OFFSET                   4
+#define FRAME_BUFFER_CONTROL_MAX_ROW_OFFSET                   6
+#define FRAME_BUFFER_CONTROL_MIN_COL_OFFSET                   8
+#define FRAME_BUFFER_CONTROL_MAX_COL_OFFSET                   10
+#define FRAME_BUFFER_CONTROL_BUFFER_ID_OFFSET                 12
+#define FRAME_BUFFER_CONTROL_DATA_OFFSET                      13
+#define FRAME_BUFFER_CONTROL_FREE_MEMORY_OFFSET               (13+FBC_MAX_DATA_PATTERN_LEN)
+#define FRAME_BUFFER_CONTROL_IMG_MAX_WIDTH_OFFSET             (15+FBC_MAX_DATA_PATTERN_LEN)
+#define FRAME_BUFFER_CONTROL_IMG_MAX_HEIGHT_OFFSET            (16+FBC_MAX_DATA_PATTERN_LEN)
+#define FRAME_BUFFER_CONTROL_IMG_NUM_IMGS_OFFSET              (17+FBC_MAX_DATA_PATTERN_LEN)
+#define FRAME_BUFFER_CONTROL_IMG_DATA_OFFSET                  (18+FBC_MAX_DATA_PATTERN_LEN)
+
+
+#define FRAME_BUFFER_CONTROL_LOAD                             0x01
+#define FRAME_BUFFER_CONTROL_REMOVE                           0x02
+#define FRAME_BUFFER_CONTROL_CLEAR                            0x04
+#define FRAME_BUFFER_CONTROL_START                            0x08
+#define FRAME_BUFFER_CONTROL_STOP                             0x10
+#define FRAME_BUFFER_CONTROL_RUNNING                          0x80
+
+#define EEPROM_FRAME_BUFFER_CONTROL_LENGTH                    8
+
+#define FRAME_BUFFER_CONTROL_PERIOD_OFFSET                    0
+#define FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET                  2
+#define FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET                4
+#define FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET               6
+
+
+#ifndef DEFAULT_FRAME_BUFFER_CONTROL_PERIOD
+  #define DEFAULT_FRAME_BUFFER_CONTROL_PERIOD                 0x0004
+#endif
+#ifndef DEFAULT_FRAME_BUFFER_CONTROL_NUM_ROWS
+  #define DEFAULT_FRAME_BUFFER_CONTROL_NUM_ROWS               0x0004
+#endif
+#ifndef DEFAULT_FRAME_BUFFER_CONTROL_NUM_PIXELS
+  #define DEFAULT_FRAME_BUFFER_CONTROL_NUM_PIXELS             0x0030
+#endif
+#ifndef DEFAULT_FRAME_BUFFER_CONTROL_NUM_BUFFERS
+  #define DEFAULT_FRAME_BUFFER_CONTROL_NUM_BUFFERS            0x0001
+#endif
+
+#define frame_buffer_control_eeprom_data(name,section_name,base_address) \
+unsigned short int name##_eeprom_data[] __attribute__ ((section (section_name)))={DEFAULT_FRAME_BUFFER_CONTROL_PERIOD&0x00FF,base_address+FRAME_BUFFER_CONTROL_PERIOD_OFFSET, \
+                                                                                  (DEFAULT_FRAME_BUFFER_CONTROL_PERIOD>>8)&0x00FF,base_address+FRAME_BUFFER_CONTROL_PERIOD_OFFSET+1, \
+                                                                                  DEFAULT_FRAME_BUFFER_CONTROL_NUM_ROWS&0x00FF,base_address+FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET, \
+                                                                                  (DEFAULT_FRAME_BUFFER_CONTROL_NUM_ROWS>>8)&0x00FF,base_address+FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET+1, \
+                                                                                  DEFAULT_FRAME_BUFFER_CONTROL_NUM_PIXELS&0x00FF,base_address+FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET, \
+                                                                                  (DEFAULT_FRAME_BUFFER_CONTROL_NUM_PIXELS>>8)&0x00FF,base_address+FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET+1, \
+                                                                                  DEFAULT_FRAME_BUFFER_CONTROL_NUM_BUFFERS&0x00FF,base_address+FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET, \
+                                                                                  (DEFAULT_FRAME_BUFFER_CONTROL_NUM_BUFFERS>>8)&0x00FF,base_address+FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET+1};
+
+#endif
+
diff --git a/pattern_frame_buffer/include/frame_buffer_registers.h b/pattern_frame_buffer/include/frame_buffer_registers.h
deleted file mode 100644
index 40c70306879ae7c0c13bbb6ebb448de5bd29c34d..0000000000000000000000000000000000000000
--- a/pattern_frame_buffer/include/frame_buffer_registers.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _FRAME_BUFFER_REGISTERS_H
-#define _FRAME_BUFFER_REGISTERS_H
-
-#ifndef RAM_FB_BASE_ADDRESS
-  #define RAM_FB_BASE_ADDRESS               ((unsigned short int)0x0000)
-#endif
-
-#define RAM_FB_LENGTH                       2 
-
-#define FB_FREE_MEMORY                      (RAM_FB_BASE_ADDRESS)
-
-#ifndef EEPROM_FB_BASE_ADDRESS
-  #define EEPROM_FB_BASE_ADDRESS            ((unsigned short int)0x0000)
-#endif
-
-#define EEPROM_FB_LENGTH                    6
-
-#define FB_NUM_ROWS                         (EEPROM_FB_BASE_ADDRESS)
-#define FB_NUM_PIXELS                       (EEPROM_FB_BASE_ADDRESS+2)
-#define FB_NUM_BUFFERS                      (EEPROM_FB_BASE_ADDRESS+4)
-
-#ifndef DEFAULT_FB_NUM_ROWS
-  #define DEFAULT_FB_NUM_ROWS               0x0004
-#endif
-#ifndef DEFAULT_FB_NUM_PIXELS
-  #define DEFAULT_FB_NUM_PIXELS             0x0030
-#endif
-#ifndef DEFAULT_FB_NUM_BUFFERS
-  #define DEFAULT_FB_NUM_BUFFERS            0x0001
-#endif
-
-#define frame_buffer_eeprom_data(name,section_name) \
-unsigned short int name##_eeprom_data[] __attribute__ ((section (".section_nane")))={DEFAULT_FB_NUM_ROWS&0x00FF,FB_NUM_ROWS, \
-                                                                                     (DEFAULT_FB_NUM_ROWS>>8)&0x00FF,FB_NUM_ROWS+1, \
-                                                                                     DEFAULT_FB_NUM_PIXELS&0x00FF,FB_NUM_PIXELS, \
-                                                                                     (DEFAULT_FB_NUM_PIXELS>>8)&0x00FF,FB_NUM_PIXELS+1, \
-                                                                                     DEFAULT_FB_NUM_BUFFERS&0x00FF,FB_NUM_BUFFERS, \
-                                                                                     (DEFAULT_FB_NUM_BUFFERS>>8)&0x00FF,FB_NUM_BUFFERS+1}; \
-#endif
-
diff --git a/pattern_frame_buffer/include/image_patterns.h b/pattern_frame_buffer/include/image_patterns.h
index fe385c1e2c2f009b4e4afba0f1b5500ecfeb4fa8..69696474c272258aeb2b0e0c7b105b83a7b626bc 100644
--- a/pattern_frame_buffer/include/image_patterns.h
+++ b/pattern_frame_buffer/include/image_patterns.h
@@ -2,25 +2,25 @@
 #define IMAGE_PATTERNS_H
 
 #include "patterns.h"
-#include "memory.h"
+#include "frame_buffer_control.h"
 
-#ifndef MAX_NUM_IMAGES
-  #define MAX_NUM_IMAGES             1
+#ifndef IMG_MAX_NUM_IMAGES
+  #error "Please, specify the maximum number of images with the IMG_MAX_NUM_IMAGES macro"
 #endif
 
-#ifndef MAX_IMAGE_WIDTH
-  #define MAX_IMAGE_WIDTH            15
+#ifndef IMG_MAX_IMAGE_WIDTH
+  #error "Please, specify the maximum image width with the IMG_MAX_IMAGE_WIDTH macro"
 #endif
 
-#ifndef MAX_IMAGE_HEIGHT
-  #define MAX_IMAGE_HEIGHT           15
+#ifndef IMG_MAX_IMAGE_HEIGHT
+  #error "Please, specify the maximum image height with the IMG_MAX_IMAGE_HEIGHT macro"
 #endif
 
-#include "image_patterns_registers.h"
-
 #define IMAGE_GROUP                  0x20
 
-unsigned char img_patterns_init(TMemory *memory);
+extern unsigned char img_pattern_data[IMG_MAX_NUM_IMAGES][IMG_MAX_IMAGE_WIDTH][IMG_MAX_IMAGE_HEIGHT][3];
+
+void img_patterns_init(unsigned short int ram_base_address);
 
 #pragma pack (push, 1)
 typedef struct
@@ -40,6 +40,6 @@ typedef struct
 #define IMG_WF_INDEX_OFFSET             5
 #define IMG_MTN_INDEX_OFFSET            6
 
-void img_general(TLEDArea *area,TIMGDisplayData *pattern_data,unsigned short int period,unsigned char *buffer);
+void img_general(TLEDArea *area,TIMGDisplayData *pattern_data,unsigned char buffer_id,unsigned short int period,TFBControl *control);
 
 #endif
diff --git a/pattern_frame_buffer/include/image_patterns_registers.h b/pattern_frame_buffer/include/image_patterns_registers.h
deleted file mode 100644
index bf3e8b9146ab3bcc1695e7e7cc7810e445d4ee27..0000000000000000000000000000000000000000
--- a/pattern_frame_buffer/include/image_patterns_registers.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _IMAGE_PATTERNS_REGISTERS_H
-#define _IMAGE_PATTERNS_REGISTERS_H
-
-#ifndef RAM_IMG_PATTERNS_BASE_ADDRESS
-  #define RAM_IMG_PATTERNS_BASE_ADDRESS               ((unsigned short int)0x0000)
-#endif
-
-#define RAM_IMG_PATTERNS_LENGTH                       MAX_NUM_IMAGES*MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT*3+3
-
-#define IMG_PATTERNS_MAX_WIDTH                        (RAM_IMG_PATTERNS_BASE_ADDRESS)
-#define IMG_PATTERNS_MAX_HEIGHT                       (RAM_IMG_PATTERNS_BASE_ADDRESS+1)
-#define IMG_PATTERNS_NUM_IMGS                         (RAM_IMG_PATTERNS_BASE_ADDRESS+2)
-#define IMG_PATTERNS_DATA                             (RAM_IMG_PATTERNS_BASE_ADDRESS+3)
-
-#endif
-
diff --git a/pattern_frame_buffer/include/led_control.h b/pattern_frame_buffer/include/led_control.h
deleted file mode 100644
index c5a30f0ef62dd2c05c01987aca8278842ca33fc3..0000000000000000000000000000000000000000
--- a/pattern_frame_buffer/include/led_control.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _LED_CONTROL_H
-#define _LED_CONTROL_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "stm32f4xx.h"
-#include "patterns.h"
-#include "memory.h"
-
-#ifndef MAX_PATTERN_FUNC
-  #define MAX_PATTERN_FUNC     16
-#endif
-
-#ifndef MAX_DATA_PATTERN_LEN
-  #define MAX_DATA_PATTERN_LEN 32
-#endif
-
-#include "led_control_registers.h"
-
-typedef void (*pattern_func_t)(TLEDArea *area,void *pattern_data,uint16_t period,unsigned char *buffer);
-
-typedef struct
-{
-  unsigned char num_patterns;
-  pattern_func_t functions[MAX_PATTERN_FUNC];
-  TLEDArea area[MAX_PATTERN_FUNC];
-  unsigned char parameters[MAX_PATTERN_FUNC][MAX_DATA_PATTERN_LEN];
-}TPatterns;
-
-unsigned char led_control_init(TMemory *memory);
-unsigned char led_control_add_pattern(pattern_func_t function,TLEDArea *area,void *data,unsigned char data_length);
-void led_control_remove_pattern(unsigned char index);
-void led_control_clear_patterns(void);
-unsigned char led_control_get_num_patterns(void);
-unsigned char *led_control_get_parameters(unsigned char index);
-void led_control_loop(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pattern_frame_buffer/include/led_control_registers.h b/pattern_frame_buffer/include/led_control_registers.h
deleted file mode 100644
index 18f73d8986a839c18e47ee8413c6642e74b5a6b6..0000000000000000000000000000000000000000
--- a/pattern_frame_buffer/include/led_control_registers.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef _LED_CONTROL_REGISTERS_H
-#define _LED_CONTROL_REGISTERS_H
-
-#ifndef RAM_LED_CONTROL_BASE_ADDRESS
-  #define RAM_LED_CONTROL_BASE_ADDRESS               ((unsigned short int)0x0000)
-#endif
-
-#define RAM_LED_CONTROL_LENGTH                       12+MAX_DATA_PATTERN_LEN
-
-#define LED_CONTROL_NUM_PATTERN                      (RAM_LED_CONTROL_BASE_ADDRESS)
-#define LED_CONTROL_PATTERN_INDEX                    (RAM_LED_CONTROL_BASE_ADDRESS+1)
-#define LED_CONTROL                                  (RAM_LED_CONTROL_BASE_ADDRESS+2)
-#define LED_CONTROL_PATTERN_ID                       (RAM_LED_CONTROL_BASE_ADDRESS+3)
-#define LED_CONTROL_MIN_ROW                          (RAM_LED_CONTROL_BASE_ADDRESS+4)
-#define LED_CONTROL_MAX_ROW                          (RAM_LED_CONTROL_BASE_ADDRESS+6)
-#define LED_CONTROL_MIN_COL                          (RAM_LED_CONTROL_BASE_ADDRESS+8)
-#define LED_CONTROL_MAX_COL                          (RAM_LED_CONTROL_BASE_ADDRESS+10)
-#define LED_CONTROL_DATA                             (RAM_LED_CONTROL_BASE_ADDRESS+12)
-
-#define LED_CONTROL_LOAD     0x01
-#define LED_CONTROL_REMOVE   0x02
-#define LED_CONTROL_CLEAR    0x04
-
-#endif
-
diff --git a/pattern_frame_buffer/include/motion_patterns.h b/pattern_frame_buffer/include/motion_patterns.h
index 39a8a1d3162d37e12b765e2fcc439548401de129..146cffdf9e89d6efbce129212d6ce65fd0749b72 100644
--- a/pattern_frame_buffer/include/motion_patterns.h
+++ b/pattern_frame_buffer/include/motion_patterns.h
@@ -2,16 +2,17 @@
 #define _MOTION_PATTERNS_H
 
 #include "patterns.h"
+#include "frame_buffer_control.h"
 
 #ifndef MTN_X_LED_SPACING
-  #define MTN_X_LED_SPACING         10
+  #error "Please, specify the LED spacing in mm in the X direction with the MTN_X_LED_SPACING macro"
 #endif
 
 #ifndef MTN_Y_LED_SPACING
-  #define MTN_Y_LED_SPACING         10
+  #error "Please, specify the LED spacing in mm in the Y direction with the MTN_Y_LED_SPACING macro"
 #endif
 
-#define MOTION_GROUP                 0x30
+#define MOTION_GROUP                0x30
 
 typedef enum {MTN_RAMP=0x01,MTN_TRIANGLE=0x02,MTN_CIRCLE=0x03,MTN_NONE=0x04} mtn_id_t;
 
@@ -68,7 +69,7 @@ typedef struct
 #define MTN_CURRENT_COL_OFFSET       12
 #define MTN_CURRENT_ROW_OFFSET       14
 #define MTN_CURRENT_TIME_OFFSET      16
-void mtn_general(TLEDArea *area,TMotion *pattern_data,unsigned short int period,unsigned char *buffer);
+void mtn_general(TLEDArea *area,TMotion *pattern_data,unsigned char buffer_id,unsigned short int period,TFBControl *control);
 
 void mtn_compute(TMotion *pattern_data);
 
diff --git a/pattern_frame_buffer/include/patterns.h b/pattern_frame_buffer/include/patterns.h
index bbf52cf8e0280b5d5804ea7c626ae37cd0be73bf..351756ccece8bb0e64da236b606ad5d4db5fff87 100644
--- a/pattern_frame_buffer/include/patterns.h
+++ b/pattern_frame_buffer/include/patterns.h
@@ -19,6 +19,4 @@ typedef struct
   unsigned char B;
 }TPixelRGB;
 
-
-
 #endif
diff --git a/pattern_frame_buffer/include/waveform_patterns.h b/pattern_frame_buffer/include/waveform_patterns.h
index ad5bab637fc93c94d1be19c2d9d8b2304686cac4..6e4cbea53e85ac6cf00d7ebda2635db61ba0ba41 100644
--- a/pattern_frame_buffer/include/waveform_patterns.h
+++ b/pattern_frame_buffer/include/waveform_patterns.h
@@ -2,6 +2,7 @@
 #define WAVEFORM_PATTERNS_H
 
 #include "patterns.h"
+#include "frame_buffer_control.h"
 
 #define WAVEFORM_GROUP               0x10
 
@@ -59,7 +60,7 @@ typedef struct
 #define WF_DATA_OFFSET            9
 #define WF_ACTIVE                 11
 #define WF_CURRENT_PERIOD_OFFSET  12
-void wf_general(TLEDArea *area,TWaveform *pattern_data,unsigned short int period,unsigned char *buffer);
+void wf_general(TLEDArea *area,TWaveform *pattern_data,unsigned char buffer_id,unsigned short int period,TFBControl *control);
 
 TPixelRGB wf_pixel(TWaveform *pattern_data);
 
diff --git a/pattern_frame_buffer/src/frame_buffer.c b/pattern_frame_buffer/src/frame_buffer.c
index 7cdf725562c0a5cbbd363d8072c30053c0aebc5e..4e35ec0c62296d8b1c294fde8d6e280acb18deac 100644
--- a/pattern_frame_buffer/src/frame_buffer.c
+++ b/pattern_frame_buffer/src/frame_buffer.c
@@ -1,296 +1,92 @@
 #include "frame_buffer.h"
-
-typedef enum {FB_SRAM1,FB_SRAM2} fb_segment_t;
-
-typedef struct
-{
-  TMemModule *mem_module;
-  TScheduler *scheduler;
-  unsigned short int num_rows;
-  unsigned short int num_pixels_per_row;
-  unsigned short int num_buffers;
-  unsigned short int buffer_size;
-  unsigned short int free_mem;
-  fb_segment_t read_current_segment;
-  unsigned char read_current_buffer;
-  fb_segment_t write_current_segment;
-  unsigned char write_current_buffer;
-  unsigned char buffer1[FB_MAX_BUFFER_LEN];
-  unsigned char buffer2[FB_MAX_BUFFER_LEN];
-  unsigned char pixel_buffer[FB_MAX_BUFFER_LEN/(FB_BYTES_PER_PIXEL/FB_BYTES_PER_PIXEL)];
-}TFrameBuffer;
+#include "frame_buffer_control_registers.h"
+#include "ram.h"
 
 // private functions
-void fb_write_cmd(void *module,unsigned short int address,unsigned short int length,unsigned char *data)
-{
-  TFrameBuffer *fb=(TFrameBuffer *)module;
-  unsigned short int new_value;
-  unsigned char *data_ptr;
-
-  if(ram_in_window(FB_NUM_ROWS,2,address,length))
-  {
-    new_value=fb->num_rows;
-    data_ptr=(unsigned char *)&new_value;
-    if(ram_in_range(FB_NUM_ROWS,address,length))
-      data_ptr[0]=data[FB_NUM_ROWS-address];
-    if(ram_in_range(FB_NUM_ROWS+1,address,length))
-      data_ptr[1]=data[FB_NUM_ROWS+1-address];
-    fb_set_num_rows(new_value);
-  }
-  if(ram_in_window(FB_NUM_PIXELS,2,address,length))
-  {
-    new_value=fb->num_pixels_per_row;
-    data_ptr=(unsigned char *)&new_value;
-    if(ram_in_range(FB_NUM_PIXELS,address,length))
-      data_ptr[0]=data[FB_NUM_PIXELS-address];
-    if(ram_in_range(FB_NUM_PIXELS+1,address,length))
-      data_ptr[1]=data[FB_NUM_PIXELS+1-address];
-    fb_set_pixels_per_row(new_value);
-  }
-  if(ram_in_window(FB_NUM_BUFFERS,2,address,length))
-  {
-    new_value=fb->num_buffers;
-    data_ptr=(unsigned char *)&new_value;
-    if(ram_in_range(FB_NUM_BUFFERS,address,length))
-      data_ptr[0]=data[FB_NUM_BUFFERS-address];
-    if(ram_in_range(FB_NUM_BUFFERS+1,address,length))
-      data_ptr[1]=data[FB_NUM_BUFFERS+1-address];
-    fb_set_num_buffers(new_value);
-  }
-}
-
-void fb_read_cmd(void *module,unsigned short int address,unsigned short int length,unsigned char *data)
+void frame_buffer_compute_free_memory(TFrameBuffer *fb)
 {
-  ram_read_table(address,length,data);
-}
-
-void fb_compute_free_memory(TFrameBuffer *fb)
-{
-  leds_buffer_size=leds_num_rows*leds_num_pixels_per_row*FB_BYTES_PER_PIXEL+RESET_LENGTH;
-  leds_free_mem=MAX_BUFFER_LEN-leds_buffer_size*leds_num_buffers;
-  ram_data[FB_FREE_MEMORY]=leds_free_mem&0x00FF;
-  ram_data[FB_FREE_MEMORY+1]=(leds_free_mem&0xFF00)>>8;
-}
-
-void leds_write_buffer(TFrameBuffer *fb,unsigned char *pixel_buffer,unsigned char *led_buffer)
-{
-  unsigned short int i,j,k,offset_pixel,offset_leds;
-  unsigned char pixel_g,pixel_r,pixel_b;
-
-  for(i=0;i<leds_num_rows;i++)
-  {
-    for(j=0;j<leds_num_pixels_per_row;j++)
-    {
-        offset_pixel=(i*leds_num_pixels_per_row+j)*BYTES_PER_PIXEL;
-      pixel_r=pixel_buffer[offset_pixel];
-      pixel_g=pixel_buffer[offset_pixel+1];
-      pixel_b=pixel_buffer[offset_pixel+2];
-      if(i%2)//odd
-        offset_leds=((i+1)*leds_num_pixels_per_row-1-j)*FB_BYTES_PER_PIXEL;
-      else//even
-        offset_leds=(i*leds_num_pixels_per_row+j)*FB_BYTES_PER_PIXEL;
-      for(k=0;k<4;k++)
-      {
-        if(pixel_g&(0x80>>(k*2)))
-          led_buffer[offset_leds+k]=0xC0;
-        else
-          led_buffer[offset_leds+k]=0x80;
-        if(pixel_g&(0x80>>((k*2)+1)))
-          led_buffer[offset_leds+k]|=0x0C;
-        else
-          led_buffer[offset_leds+k]|=0x08;
-        if(pixel_r&(0x80>>(k*2)))
-          led_buffer[offset_leds+(k+4)]=0xC0;
-        else
-          led_buffer[offset_leds+(k+4)]=0x80;
-        if(pixel_r&(0x80>>((k*2)+1)))
-          led_buffer[offset_leds+(k+4)]|=0x0C;
-        else
-          led_buffer[offset_leds+(k+4)]|=0x08;
-        if(pixel_b&(0x80>>(k*2)))
-          led_buffer[offset_leds+(k+8)]=0xC0;
-        else
-          led_buffer[offset_leds+(k+8)]=0x80;
-        if(pixel_b&(0x80>>((k*2)+1)))
-          led_buffer[offset_leds+(k+8)]|=0x0C;
-        else
-          led_buffer[offset_leds+(k+8)]|=0x08;
-      }
-      pixel_buffer[offset_pixel]=0x00;
-      pixel_buffer[offset_pixel+1]=0x00;
-      pixel_buffer[offset_pixel+2]=0x00;
-    }
-  }
-}
-
-void leds_write_reset(TFrameBuffer *fb,unsigned char *led_buffer)
-{
-  unsigned short int i;
-
-  for(i=0;i<RESET_LENGTH;i++)
-    led_buffer[leds_num_rows*leds_num_pixels_per_row*FB_BYTES_PER_PIXEL+i]=0x00;
-}
-
-/* Interrupt handlers */
-void leds_scheduler(void)
-{
-  unsigned char *start_address;
-
-  /* switch to the next buffer*/
-  if(leds_spi_current_buffer>=leds_num_buffers)
-  {
-    leds_spi_current_buffer=0;
-    if(leds_spi_current_segment==FB_SRAM1)
-    {
-      leds_spi_current_segment=FB_SRAM2;
-      start_address=&leds_buffer2[0];
-    }
-    else
-    {
-      leds_spi_current_segment=FB_SRAM1;
-      start_address=&leds_buffer1[0];
-    }
-  }
-  else
-  {
-    if(leds_spi_current_segment==FB_SRAM1)
-      start_address=&leds_buffer1[leds_spi_current_buffer*leds_buffer_size];
-    else
-      start_address=&leds_buffer2[leds_spi_current_buffer*leds_buffer_size];
-  }
-  leds_spi_current_buffer++;
-  HAL_SPI_Transmit_DMA(&led_spi,start_address,leds_buffer_size);
-  leds_update=0x01;
+  fb->buffer_size=fb->num_rows*fb->num_pixels_per_row*FB_BYTES_PER_PIXEL;
+  fb->free_mem=FB_MAX_BUFFER_LEN-fb->buffer_size*fb->num_buffers;
+  ram_data[fb->ram_base_address+FRAME_BUFFER_CONTROL_FREE_MEMORY_OFFSET]=fb->free_mem&0x00FF;
+  ram_data[fb->ram_base_address+FRAME_BUFFER_CONTROL_FREE_MEMORY_OFFSET+1]=(fb->free_mem&0xFF00)>>8;
 }
 
 // public functions
-unsigned char fb_init(TFrameBuffer *fb,TMemory *memory)
+void frame_buffer_init(TFrameBuffer *fb,unsigned short int ram_base_address,unsigned short int eeprom_base_address)
 {
   unsigned int i;
 
   /* initialize internal data */
-  fb_set_period(fb,DEFAULT_FB_PERIOD);
-  fb_set_num_rows(fb,DEFAULT_FB_NUM_ROWS);
-  fb_set_pixels_per_row(fb,DEFAULT_FB_NUM_PIXELS);
-  fb_set_num_buffers(fb,DEFAULT_FB_NUM_BUFFERS);
-  fb->read_current_buffer=0;
-  fb->read_current_segment=FB_SRAM2;
-  fb->write_current_buffer=0;
-  fb->write_current_segment=FB_SRAM2;
+  frame_buffer_set_num_rows(fb,DEFAULT_FRAME_BUFFER_CONTROL_NUM_ROWS);
+  frame_buffer_set_pixels_per_row(fb,DEFAULT_FRAME_BUFFER_CONTROL_NUM_PIXELS);
+  frame_buffer_set_num_buffers(fb,DEFAULT_FRAME_BUFFER_CONTROL_NUM_BUFFERS);
+  fb->ram_base_address=ram_base_address;
+  fb->eeprom_base_address=eeprom_base_address;
 
-  for(i=0;i<FB_MAX_BUFFER_LEN/(FB_BYTES_PER_PIXEL/FB_BYTES_PER_PIXEL);i++)
+  for(i=0;i<FB_MAX_BUFFER_LEN;i++)
     fb->pixel_buffer[i]=0x00;
-  for(i=0;i<fb->num_buffers;i++)
-  {
-    fb_write_buffer(fb,fb->pixel_buffer,&fb->buffer1[fb->buffer_size*i]);
-    fb_write_reset(fb,&fb->buffer1[fb->buffer_size*i]);
-    fb_write_buffer(fb,fb->pixel_buffer,&fb->buffer2[fb->buffer_size*i]);
-    fb_write_reset(fb,&fb->buffer2[fb->buffer_size*i]);
-  }
-
-  mem_module_init(&fb->mem_module);
-  fb->mem_module.write_cmd=fb_write_cmd;
-  fb->mem_module.read_cmd=fb_read_cmd;
-  fb->data=fb;
-  if(!mem_module_add_ram_segment(&fb->mem_module,RAM_FB_BASE_ADDRESS,RAM_FB_LENGTH))
-    return 0x00;
-  if(!mem_module_add_eeprom_segment(&fb->mem_module,EEPROM_FB_BASE_ADDRESS,EEPROM_FB_LENGTH))
-    return 0x00;
-  if(!mem_add_module(memory,&fb->mem_module))
-    return 0x00;
-
-  return 0x01;
-}
-
-void fb_set_num_rows(TFrameBuffer *fb,unsigned short int rows)
-{
-  leds_num_rows=rows;
-  ram_data[FB_NUM_ROWS]=rows&0x00FF;
-  ram_data[FB_NUM_ROWS+1]=(rows&0xFF00)>>8;
-  leds_compute_free_memory();
 }
 
-unsigned short int fb_get_num_rows(TFrameBuffer *fb)
+void frame_buffer_set_num_rows(TFrameBuffer *fb,unsigned short int rows)
 {
-  return leds_num_rows;
+  fb->num_rows=rows;
+  ram_data[fb->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET]=rows&0x00FF;
+  ram_data[fb->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET+1]=(rows&0xFF00)>>8;
+  frame_buffer_compute_free_memory(fb);
 }
 
-void fb_set_pixels_per_row(TFrameBuffer *fb,unsigned short int pixels)
+unsigned short int frame_buffer_get_num_rows(TFrameBuffer *fb)
 {
-  leds_num_pixels_per_row=pixels;
-  ram_data[FB_NUM_PIXELS]=pixels&0x00FF;
-  ram_data[FB_NUM_PIXELS+1]=(pixels&0xFF00)>>8;
-  leds_compute_free_memory();
+  return fb->num_rows;
 }
 
-unsigned short int fb_get_pixels_per_row(TFrameBuffer *fb)
+void frame_buffer_set_pixels_per_row(TFrameBuffer *fb,unsigned short int pixels)
 {
-  return leds_num_pixels_per_row;
+  fb->num_pixels_per_row=pixels;
+  ram_data[fb->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET]=pixels&0x00FF;
+  ram_data[fb->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET+1]=(pixels&0xFF00)>>8;
+  frame_buffer_compute_free_memory(fb);
 }
 
-void fb_set_num_buffers(TFrameBuffer *fb,unsigned char num)
+unsigned short int frame_buffer_get_pixels_per_row(TFrameBuffer *fb)
 {
-  leds_num_buffers=num;
-  ram_data[FB_NUM_BUFFERS]=num&0x00FF;
-  ram_data[FB_NUM_BUFFERS+1]=(num&0xFF00)>>8;
-  leds_compute_free_memory();
+  return fb->num_pixels_per_row;
 }
 
-unsigned char fb_get_num_buffers(TFrameBuffer *fb)
+void frame_buffer_set_num_buffers(TFrameBuffer *fb,unsigned char num)
 {
-  return leds_num_buffers;
+  fb->num_buffers=num;
+  ram_data[fb->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET]=num&0x00FF;
+  ram_data[fb->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET+1]=(num&0xFF00)>>8;
+  frame_buffer_compute_free_memory(fb);
 }
 
-unsigned short int fb_get_free_memory(TFrameBuffer *fb)
+unsigned char frame_buffer_get_num_buffers(TFrameBuffer *fb)
 {
-  return leds_free_mem;
+  return fb->num_buffers;
 }
 
-unsigned char fb_update_buffer(TFrameBuffer *fb)
+unsigned short int frame_buffer_get_free_memory(TFrameBuffer *fb)
 {
-  if(leds_update)
-  {
-    leds_update=0x00;
-    return 0x01;
-  }
-  else
-    return 0x00;
+  return fb->free_mem;
 }
 
-unsigned char *fb_get_pixel_buffer(TFrameBuffer *fb)
+void frame_buffer_set_pixel(TFrameBuffer *fb,unsigned char buffer_id,unsigned char R,unsigned char G,unsigned char B,unsigned short int row,unsigned short int col)
 {
-  return leds_pixel_buffer;
-}
+  unsigned short int offset;
 
-void fb_set_pixel_buffer(TFrameBuffer *fb,unsigned char *buffer)
-{
-  if(leds_user_current_segment==FB_SRAM1)
-  {
-    leds_write_buffer(buffer,&leds_buffer1[leds_buffer_size*leds_user_current_buffer]);
-    leds_write_reset(&leds_buffer1[leds_buffer_size*leds_user_current_buffer]);
-    leds_user_current_buffer++;
-    if(leds_user_current_buffer>=leds_num_buffers)
-    {
-      leds_user_current_buffer=0;
-      leds_user_current_segment=FB_SRAM2;
-    }
-  }
+  if(buffer_id>=fb->num_buffers)
+    return;
   else
   {
-    leds_write_buffer(buffer,&leds_buffer2[leds_buffer_size*leds_user_current_buffer]);
-    leds_write_reset(&leds_buffer2[leds_buffer_size*leds_user_current_buffer]);
-    leds_user_current_buffer++;
-    if(leds_user_current_buffer>=leds_num_buffers)
-    {
-      leds_user_current_buffer=0;
-      leds_user_current_segment=FB_SRAM1;
-    }
+    offset=fb->num_rows*fb->num_pixels_per_row*FB_BYTES_PER_PIXEL*buffer_id;
+    fb->pixel_buffer[offset+((row*fb->num_pixels_per_row+col)*FB_BYTES_PER_PIXEL)]=R;
+    fb->pixel_buffer[offset+((row*fb->num_pixels_per_row+col)*FB_BYTES_PER_PIXEL)+1]=G;
+    fb->pixel_buffer[offset+((row*fb->num_pixels_per_row+col)*FB_BYTES_PER_PIXEL)+2]=B;
   }
 }
 
-void fb_set_pixel(TFrameBuffer *fb,unsigned char R,unsigned char G,unsigned char B,unsigned short int row,unsigned short int col, unsigned char *buffer)
+unsigned char *frame_buffer_get_buffer(TFrameBuffer *fb,unsigned char buffer_id)
 {
-  buffer[((row*leds_num_pixels_per_row+col)*BYTES_PER_PIXEL)]=R;
-  buffer[((row*leds_num_pixels_per_row+col)*BYTES_PER_PIXEL)+1]=G;
-  buffer[((row*leds_num_pixels_per_row+col)*BYTES_PER_PIXEL)+2]=B;
+  return &fb->pixel_buffer[fb->num_rows*fb->num_pixels_per_row*FB_BYTES_PER_PIXEL*buffer_id];
 }
diff --git a/pattern_frame_buffer/src/frame_buffer_control.c b/pattern_frame_buffer/src/frame_buffer_control.c
new file mode 100644
index 0000000000000000000000000000000000000000..12efbd809630cd1fe262fc46e5c4f34b7271bd68
--- /dev/null
+++ b/pattern_frame_buffer/src/frame_buffer_control.c
@@ -0,0 +1,392 @@
+#include "frame_buffer_control.h"
+#include "patterns.h"
+#include "waveform_patterns.h"
+#include "image_patterns.h"
+#include "motion_patterns.h"
+#include "ram.h"
+
+/* private functions */
+void frame_buffer_control_write_cmd(void *module,unsigned short int address,unsigned short int length,unsigned char *data)
+{
+  TFBControl *control=(TFBControl *)module;
+  static TLEDArea ptrn_area={0};
+  static unsigned char ptrn_data[FBC_MAX_DATA_PATTERN_LEN]={0},data_len=0,pattern_id=0,pattern_index=0,buffer_id=0;
+  unsigned char *data_ptr;
+  unsigned short int new_value,ram_offset,eeprom_offset,i;
+  pattern_func_t function=0x00000000;
+
+  ram_offset=address-control->ram_base_address;
+  eeprom_offset=address-control->eeprom_base_address;
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_OFFSET,1,address,length))
+  {
+    if(data[FRAME_BUFFER_CONTROL_OFFSET-ram_offset]&FRAME_BUFFER_CONTROL_LOAD)// add the new pattern
+    {
+      switch(pattern_id&PATTERN_GROUP)
+      {
+        case WAVEFORM_GROUP:
+          function=(pattern_func_t)wf_general;
+          // initialize static data
+          ptrn_data[WF_CURRENT_PERIOD_OFFSET]=0x00;
+          ptrn_data[WF_CURRENT_PERIOD_OFFSET+1]=0x00;
+          data_len+=2;
+          break;
+        case MOTION_GROUP:
+          function=(pattern_func_t)mtn_general;
+          ptrn_data[MTN_CURRENT_COL_OFFSET]=0x00;
+          ptrn_data[MTN_CURRENT_COL_OFFSET+1]=0x00;
+          ptrn_data[MTN_CURRENT_ROW_OFFSET]=0x00;
+          ptrn_data[MTN_CURRENT_ROW_OFFSET+1]=0x00;
+          ptrn_data[MTN_CURRENT_TIME_OFFSET]=0x00;
+          ptrn_data[MTN_CURRENT_TIME_OFFSET+1]=0x00;
+          data_len+=6;
+          break;
+        case IMAGE_GROUP:
+          function=(pattern_func_t)img_general;
+          break;
+        default: break;
+      }
+      frame_buffer_control_add_pattern(control,function,&ptrn_area,ptrn_data,data_len,buffer_id);
+      /* clear the internal data for the next pattern */
+      data_len=0;
+      ptrn_area.min_row=0;
+      ptrn_area.max_row=0;
+      ptrn_area.min_col=0;
+      ptrn_area.max_col=0;
+      pattern_id=0;
+      buffer_id=0;
+      for(i=0;i<FBC_MAX_DATA_PATTERN_LEN;i++)
+        ptrn_data[i]=0;
+    }
+    else if(data[FRAME_BUFFER_CONTROL_OFFSET-ram_offset]&FRAME_BUFFER_CONTROL_REMOVE)
+      frame_buffer_control_remove_pattern(control,pattern_index);
+    else if(data[FRAME_BUFFER_CONTROL_OFFSET-ram_offset]&FRAME_BUFFER_CONTROL_CLEAR)
+      frame_buffer_control_clear_patterns(control);
+    else if(data[FRAME_BUFFER_CONTROL_OFFSET-ram_offset]&FRAME_BUFFER_CONTROL_START)
+      frame_buffer_control_start(control);
+    else if(data[FRAME_BUFFER_CONTROL_OFFSET-ram_offset]&FRAME_BUFFER_CONTROL_STOP)
+      frame_buffer_control_stop(control);
+  }
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET,1,address,length))
+    pattern_index=data[FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET-ram_offset];
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_ID_OFFSET,1,address,length))
+    pattern_id=data[FRAME_BUFFER_CONTROL_PATTERN_ID_OFFSET-ram_offset];
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_MIN_ROW_OFFSET,2,address,length))
+  {
+    data_ptr=(unsigned char *)&ptrn_area.min_row;
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MIN_ROW_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_MIN_ROW_OFFSET-ram_offset];
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MIN_ROW_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_MIN_ROW_OFFSET+1-ram_offset];
+  }
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_MAX_ROW_OFFSET,2,address,length))
+  {
+    data_ptr=(unsigned char *)&ptrn_area.max_row;
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MAX_ROW_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_MAX_ROW_OFFSET-ram_offset];
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MAX_ROW_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_MAX_ROW_OFFSET+1-ram_offset];
+  }
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_MIN_COL_OFFSET,2,address,length))
+  {
+    data_ptr=(unsigned char *)&ptrn_area.min_col;
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MIN_COL_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_MIN_COL_OFFSET-ram_offset];
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MIN_COL_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_MIN_COL_OFFSET+1-ram_offset];
+  }
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_MAX_COL_OFFSET,2,address,length))
+  {
+    data_ptr=(unsigned char *)&ptrn_area.max_col;
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MAX_COL_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_MAX_COL_OFFSET-ram_offset];
+    if(ram_in_range(control->ram_base_address+FRAME_BUFFER_CONTROL_MAX_COL_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_MAX_COL_OFFSET+1-ram_offset];
+  }
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_BUFFER_ID_OFFSET,1,address,length))
+    buffer_id=data[FRAME_BUFFER_CONTROL_BUFFER_ID_OFFSET-ram_offset];
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_DATA_OFFSET,FBC_MAX_DATA_PATTERN_LEN,address,length))
+  {
+    for(i=0;i<length-(FRAME_BUFFER_CONTROL_DATA_OFFSET-ram_offset) && i<FBC_MAX_DATA_PATTERN_LEN;i++)
+    {
+      ptrn_data[i]=data[FRAME_BUFFER_CONTROL_DATA_OFFSET-ram_offset+i];
+      data_len++;
+    }
+  }
+  if(ram_in_window(control->eeprom_base_address+FRAME_BUFFER_CONTROL_PERIOD_OFFSET,2,address,length))
+  {
+    new_value=control->period_ms;
+    data_ptr=(unsigned char *)&new_value;
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_PERIOD_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_PERIOD_OFFSET-eeprom_offset];
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_PERIOD_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_PERIOD_OFFSET+1-eeprom_offset];
+    frame_buffer_control_set_period(control,new_value);
+  }
+  if(ram_in_window(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET,2,address,length))
+  {
+    new_value=control->frame_buffer.num_rows;
+    data_ptr=(unsigned char *)&new_value;
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET-eeprom_offset];
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_NUM_ROWS_OFFSET+1-eeprom_offset];
+    frame_buffer_set_num_rows(&control->frame_buffer,new_value);
+  }
+  if(ram_in_window(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET,2,address,length))
+  {
+    new_value=control->frame_buffer.num_pixels_per_row;
+    data_ptr=(unsigned char *)&new_value;
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET-eeprom_offset];
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_NUM_PIXELS_OFFSET+1-eeprom_offset];
+    frame_buffer_set_pixels_per_row(&control->frame_buffer,new_value);
+  }
+  if(ram_in_window(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET,2,address,length))
+  {
+    new_value=control->frame_buffer.num_buffers;
+    data_ptr=(unsigned char *)&new_value;
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET,address,length))
+      data_ptr[0]=data[FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET-eeprom_offset];
+    if(ram_in_range(control->eeprom_base_address+FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET+1,address,length))
+      data_ptr[1]=data[FRAME_BUFFER_CONTROL_NUM_BUFFERS_OFFSET+1-eeprom_offset];
+    frame_buffer_set_num_buffers(&control->frame_buffer,new_value);
+  }
+  if(ram_in_window(control->ram_base_address+FRAME_BUFFER_CONTROL_IMG_DATA_OFFSET,IMG_MAX_NUM_IMAGES*IMG_MAX_IMAGE_WIDTH*IMG_MAX_IMAGE_HEIGHT*3,address,length))
+  {
+    for(i=0;i<length;i++)
+      ((unsigned char *)img_pattern_data)[address-control->ram_base_address-FRAME_BUFFER_CONTROL_IMG_DATA_OFFSET+i]=data[i];
+  }
+}
+
+void frame_buffer_control_read_cmd(void *module,unsigned short int address,unsigned short int length,unsigned char *data)
+{
+  ram_read_table(address,length,data);
+}
+
+void frame_buffer_control_scheduler(void *data)
+{
+  TFBControl *control=(TFBControl *)data;
+  unsigned char i;
+
+  frame_buffer_control_update(control);
+  for(i=0;i<control->num_copy_functions;i++)
+    control->copy_functions[i](control->copy_data[i]);
+}
+
+/* public functions */
+unsigned char frame_buffer_control_init(TFBControl *control,TMemory *memory,TScheduler *scheduler,sched_channel_t ch,unsigned short int ram_base_address,unsigned short int eeprom_base_address)
+{
+  // initialize internal variables
+  frame_buffer_control_clear_patterns(control);
+  frame_buffer_control_clear_copy_functions(control);
+  frame_buffer_init(&control->frame_buffer,ram_base_address,eeprom_base_address);
+  control->ram_base_address=ram_base_address;
+  control->eeprom_base_address=eeprom_base_address;
+
+  /* assigna a scheduler channel */
+  scheduler_set_channel(scheduler,ch,frame_buffer_control_scheduler,DEFAULT_FRAME_BUFFER_CONTROL_PERIOD,control);
+  control->scheduler=scheduler;
+  control->sch_channel=ch;
+
+  img_patterns_init(ram_base_address);
+
+  /* initialize memory module */
+  mem_module_init(&control->mem_module);
+  control->mem_module.write_cmd=frame_buffer_control_write_cmd;
+  control->mem_module.read_cmd=frame_buffer_control_read_cmd;
+  control->mem_module.data=control;
+  if(!mem_module_add_ram_segment(&control->mem_module,ram_base_address,RAM_FRAME_BUFFER_CONTROL_LENGTH))
+    return 0x00;
+  if(!mem_module_add_eeprom_segment(&control->mem_module,eeprom_base_address,EEPROM_FRAME_BUFFER_CONTROL_LENGTH))
+    return 0x00;
+  if(!mem_add_module(memory,&control->mem_module))
+    return 0x00;
+
+  return 0x01;
+}
+
+void frame_buffer_control_start(TFBControl *control)
+{
+  scheduler_enable_channel(control->scheduler,control->sch_channel);
+  ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_OFFSET]|=FRAME_BUFFER_CONTROL_RUNNING;
+}
+
+void frame_buffer_control_stop(TFBControl *control)
+{
+  scheduler_disable_channel(control->scheduler,control->sch_channel);
+  ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_OFFSET]&=(~FRAME_BUFFER_CONTROL_RUNNING);
+}
+
+void frame_buffer_control_set_period(TFBControl *control,unsigned short int period_ms)
+{
+  scheduler_change_period(control->scheduler,control->sch_channel,period_ms);
+  ram_data[control->eeprom_base_address+FRAME_BUFFER_CONTROL_PERIOD_OFFSET]=period_ms&0x00FF;
+  ram_data[control->eeprom_base_address+FRAME_BUFFER_CONTROL_PERIOD_OFFSET+1]=(period_ms&0xFF00)>>8;
+  control->period_ms=period_ms;
+}
+
+unsigned short int frame_buffer_control_get_period(TFBControl *control)
+{
+  return control->period_ms;
+}
+
+// pattern functions
+unsigned char frame_buffer_control_add_pattern(TFBControl *control,pattern_func_t function,TLEDArea *area,void *data,unsigned char data_length,unsigned char buffer_id)
+{
+  unsigned short int num_rows,num_cols;
+  unsigned char i,j;
+
+  num_rows=frame_buffer_get_num_rows(&control->frame_buffer);
+  num_cols=frame_buffer_get_pixels_per_row(&control->frame_buffer); 
+  if(area->min_row>num_rows || area->max_row>num_rows || area->min_row>area->max_row)
+  {
+    ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET]=0xFF;
+    return 0xFF;
+  }
+  if(area->min_col>num_cols || area->max_col>num_cols || area->min_col>area->max_col)
+  {
+    ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET]=0xFF;
+    return 0xFF;
+  }
+  if(data_length>FBC_MAX_DATA_PATTERN_LEN)
+  {
+    ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET]=0xFF;
+    return 0xFF;
+  }
+  if(buffer_id>=frame_buffer_get_num_buffers(&control->frame_buffer))
+  {
+    ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET]=0xFF;
+    return 0xFF;
+  }
+
+  for(j=0;j<FBC_MAX_PATTERN_FUNC;j++)
+  {
+    // find the first empty pattern
+    if(control->pat_functions[j]==0x00000000)
+    {
+      control->pat_area[j].min_row=area->min_row;
+      control->pat_area[j].max_row=area->max_row;
+      control->pat_area[j].min_col=area->min_col;
+      control->pat_area[j].max_col=area->max_col;
+      control->pat_buffer_id[j]=buffer_id;
+      for(i=0;i<data_length;i++)
+        control->pat_parameters[j][i]=((unsigned char *)data)[i];
+      control->pat_functions[j]=function;
+      control->num_patterns++;
+      ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_NUM_PATTERN_OFFSET]=control->num_patterns;
+      ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET]=j;
+      return j;
+    }
+  }
+  // the pattern could not be added
+  ram_data[control->ram_base_address+FRAME_BUFFER_CONTROL_PATTERN_INDEX_OFFSET]=0xFF;
+  return 0xFF;
+}
+
+void frame_buffer_control_remove_pattern(TFBControl *control,unsigned char index)
+{
+  unsigned char i;
+
+  if(control->num_patterns>0 && index<FBC_MAX_PATTERN_FUNC)
+  {
+    control->pat_functions[index]=0x00000000;
+    control->pat_area[index].min_row=0;
+    control->pat_area[index].max_row=0;
+    control->pat_area[index].min_col=0;
+    control->pat_area[index].max_col=0;
+    control->pat_buffer_id[index]=-1;
+    for(i=0;i<FBC_MAX_DATA_PATTERN_LEN;i++)
+      control->pat_parameters[index][i]=0;
+    control->num_patterns--; 
+  } 
+}
+
+void frame_buffer_control_clear_patterns(TFBControl *control)
+{
+  unsigned char i,j;
+
+  control->num_patterns=0;
+  for(i=0;i<FBC_MAX_PATTERN_FUNC;i++)
+  {
+    control->pat_functions[i]=0x00000000;
+    control->pat_area[i].min_row=0;
+    control->pat_area[i].max_row=0;
+    control->pat_area[i].min_col=0;
+    control->pat_area[i].max_col=0;
+    control->pat_buffer_id[i]=-1;
+    for(j=0;j<FBC_MAX_DATA_PATTERN_LEN;j++)
+      control->pat_parameters[i][j]=0;
+  }
+}
+
+unsigned char frame_buffer_control_get_num_patterns(TFBControl *control)
+{
+  return control->num_patterns;
+}
+
+unsigned char *frame_buffer_control_get_parameters(TFBControl *control,unsigned char index)
+{
+  if(index>=0 && index<FBC_MAX_PATTERN_FUNC)
+    return (unsigned char *)&control->pat_parameters[index];
+  else
+    return (unsigned char *)0x00000000;
+}
+
+void frame_buffer_control_update(TFBControl *control)
+{
+  unsigned char i;
+
+  for(i=0;i<FBC_MAX_PATTERN_FUNC;i++)
+  {
+    if(control->pat_functions[i]!=0x00000000)
+      control->pat_functions[i](&control->pat_area[i],&control->pat_parameters[i],control->pat_buffer_id[i],control->period_ms,control);
+  }
+}
+
+// copy functions
+unsigned char frame_buffer_control_add_copy_function(TFBControl *control,copy_func_t function,void *data)
+{
+  unsigned char i;
+
+  for(i=0;i<FBC_MAX_COPY_FUNC;i++)
+  {
+    // find the first empty pattern
+    if(control->copy_functions[i]==0x00000000)
+    {
+      control->copy_functions[i]=function;
+      control->copy_data[i]=data;
+      control->num_copy_functions++;
+      return i;
+    }
+  }
+
+  return 0xFF;
+}
+
+void frame_buffer_control_remove_copy_function(TFBControl *control,unsigned char index)
+{
+  if(control->num_copy_functions>0 && index<FBC_MAX_COPY_FUNC)
+  {
+    control->copy_functions[index]=0x00000000;
+    control->copy_data[index]=0x0000000;
+    control->num_copy_functions--;
+  }
+}
+
+void frame_buffer_control_clear_copy_functions(TFBControl *control)
+{
+  unsigned char i;
+
+  control->num_copy_functions=0;
+  for(i=0;i<FBC_MAX_COPY_FUNC;i++)
+  {
+    control->copy_functions[i]=0x00000000;
+    control->copy_data[i]=0x00000000;
+  }
+}
+
+unsigned char frame_buffer_control_get_num_copy_functions(TFBControl *control)
+{
+  return control->num_copy_functions;
+}
diff --git a/pattern_frame_buffer/src/image_patterns.c b/pattern_frame_buffer/src/image_patterns.c
new file mode 100644
index 0000000000000000000000000000000000000000..f49a883511e192516bc59d9508efcc551d841141
--- /dev/null
+++ b/pattern_frame_buffer/src/image_patterns.c
@@ -0,0 +1,100 @@
+#include "image_patterns.h"
+#include "frame_buffer_control.h"
+#include "waveform_patterns.h"
+#include "motion_patterns.h"
+#include "ram.h"
+
+// private variables
+unsigned char img_pattern_data[IMG_MAX_NUM_IMAGES][IMG_MAX_IMAGE_WIDTH][IMG_MAX_IMAGE_HEIGHT][3]={{{{0}}}};
+
+// private functions
+void img_patterns_compute_range(unsigned short int area_min,unsigned short int area_max,short int pattern_start,unsigned short int max_size,unsigned short int *buff_start, unsigned short int *buff_end,unsigned char *img_start)
+{
+  unsigned short int cp_size;
+
+  if(pattern_start<0)
+  {
+    *buff_start=area_min;
+    *img_start=-pattern_start;
+    if((-pattern_start)<max_size)
+      cp_size=max_size+pattern_start;
+    else
+      cp_size=0;
+  } 
+  else if(pattern_start>(area_max-area_min))
+  {
+    *buff_start=0;
+    *img_start=0;
+    cp_size=0;
+  }
+  else
+  {
+    *buff_start=area_min+pattern_start;
+    *img_start=0;
+    cp_size=max_size-1;
+  }
+  if(*buff_start+cp_size>area_max)
+  {
+    *buff_end=area_max;
+    cp_size-=area_max;
+  }
+  else
+    *buff_end=*buff_start+cp_size;
+}
+
+// public functions
+void img_patterns_init(unsigned short int ram_base_address)
+{
+  //initialize internal variables (read only variables)
+  ram_data[ram_base_address+FRAME_BUFFER_CONTROL_IMG_MAX_WIDTH_OFFSET]=IMG_MAX_IMAGE_WIDTH;
+  ram_data[ram_base_address+FRAME_BUFFER_CONTROL_IMG_MAX_HEIGHT_OFFSET]=IMG_MAX_IMAGE_HEIGHT;
+  ram_data[ram_base_address+FRAME_BUFFER_CONTROL_IMG_NUM_IMGS_OFFSET]=IMG_MAX_NUM_IMAGES;
+}
+
+void img_general(TLEDArea *area,TIMGDisplayData *pattern_data,unsigned char buffer_id,unsigned short int period,TFBControl *control)
+{
+  unsigned short int buff_row=0,buff_col=0,img_row=0,img_col=0;
+  unsigned short int buff_start_row=0,buff_end_row=0,buff_start_col=0,buff_end_col=0;
+  unsigned char img_start_row=0,img_start_col=0;
+  short int row_offset,col_offset;
+  TWaveform *waveform;
+  TMotion *motion;
+  TPixelRGB pixel;
+
+  // execute motion
+  if(pattern_data->motion_index!=0xFF)
+  {
+    motion=(TMotion *)frame_buffer_control_get_parameters(control,pattern_data->motion_index);
+    mtn_compute(motion);
+    col_offset=motion->current_col;
+    row_offset=motion->current_row;
+  }
+  else
+  {
+    col_offset=0;
+    row_offset=0;
+  }
+  // compute displayed area
+  img_patterns_compute_range(area->min_row,area->max_row,row_offset,IMG_MAX_IMAGE_HEIGHT,&buff_start_row,&buff_end_row,&img_start_row);
+  img_patterns_compute_range(area->min_col,area->max_col,col_offset,IMG_MAX_IMAGE_WIDTH,&buff_start_col,&buff_end_col,&img_start_col);
+  // execute waveform
+  for(buff_row=buff_start_row,img_row=img_start_row;buff_row<=buff_end_row;buff_row++,img_row++)
+    for(buff_col=buff_start_col,img_col=img_start_col;buff_col<=buff_end_col;buff_col++,img_col++)
+    {
+      if(pattern_data->waveform_index!=0xFF)
+      {
+        waveform=(TWaveform *)frame_buffer_control_get_parameters(control,pattern_data->waveform_index);
+        waveform->max.R=img_pattern_data[pattern_data->buffer_id][img_row][img_col][0];
+        waveform->max.G=img_pattern_data[pattern_data->buffer_id][img_row][img_col][1];
+        waveform->max.B=img_pattern_data[pattern_data->buffer_id][img_row][img_col][2];
+        pixel=wf_pixel(waveform);
+      }
+      else
+      {
+        pixel.R=img_pattern_data[pattern_data->buffer_id][img_row][img_col][0];
+        pixel.G=img_pattern_data[pattern_data->buffer_id][img_row][img_col][1];
+        pixel.B=img_pattern_data[pattern_data->buffer_id][img_row][img_col][2];
+      }
+      frame_buffer_set_pixel(&control->frame_buffer,buffer_id,pixel.R,pixel.G,pixel.B,buff_row,buff_col);
+    }
+}
diff --git a/pattern_frame_buffer/src/motion_patterns.c b/pattern_frame_buffer/src/motion_patterns.c
new file mode 100644
index 0000000000000000000000000000000000000000..041243bbb103de18f7f8b6e49f188f4bb8e0ef23
--- /dev/null
+++ b/pattern_frame_buffer/src/motion_patterns.c
@@ -0,0 +1,108 @@
+#include "motion_patterns.h"
+#include <math.h>
+
+// private functions
+void mtn_ramp(TMotion *pattern_data)
+{
+  unsigned short int ms_pixel_x,delta_x_mm;
+  unsigned short int ms_pixel_y,delta_y_mm;
+  unsigned short int dist_mm;
+
+  delta_x_mm=(pattern_data->motion_data.ramp_data.max_coord_x-pattern_data->motion_data.ramp_data.min_coord_x)*MTN_X_LED_SPACING;
+  delta_y_mm=(pattern_data->motion_data.ramp_data.max_coord_y-pattern_data->motion_data.ramp_data.min_coord_y)*MTN_Y_LED_SPACING;
+
+  dist_mm=sqrt(pow(delta_x_mm,2)+pow(delta_y_mm,2));
+
+  ms_pixel_x=(dist_mm*1000)/(delta_x_mm*pattern_data->speed_mm_s);
+  ms_pixel_y=(dist_mm*1000)/(delta_y_mm*pattern_data->speed_mm_s);
+
+  if(pattern_data->motion_data.ramp_data.direction==0x01)
+  {
+    pattern_data->current_col=pattern_data->motion_data.ramp_data.min_coord_x+(pattern_data->current_time/ms_pixel_x);
+    pattern_data->current_row=pattern_data->motion_data.ramp_data.min_coord_y+(pattern_data->current_time/ms_pixel_y);
+
+    if((pattern_data->current_col>=pattern_data->motion_data.ramp_data.max_coord_x) &&
+       (pattern_data->current_row>=pattern_data->motion_data.ramp_data.max_coord_y))
+    {
+      pattern_data->current_col=pattern_data->motion_data.ramp_data.min_coord_x;
+      pattern_data->current_row=pattern_data->motion_data.ramp_data.min_coord_y;
+      pattern_data->current_time=0;
+    }
+  }
+  else
+  {
+    pattern_data->current_col=pattern_data->motion_data.ramp_data.max_coord_x-(pattern_data->current_time/ms_pixel_x);
+    pattern_data->current_row=pattern_data->motion_data.ramp_data.max_coord_y-(pattern_data->current_time/ms_pixel_y);
+
+    if((pattern_data->current_col<=pattern_data->motion_data.ramp_data.min_coord_x) &&
+       (pattern_data->current_row<=pattern_data->motion_data.ramp_data.min_coord_y))
+    {
+      pattern_data->current_col=pattern_data->motion_data.ramp_data.max_coord_x;
+      pattern_data->current_row=pattern_data->motion_data.ramp_data.max_coord_y;
+      pattern_data->current_time=0;
+    }
+  }
+}
+
+void mtn_triangle(TMotion *pattern_data)
+{
+  unsigned short int ms_pixel_x,delta_x_mm;
+  unsigned short int ms_pixel_y,delta_y_mm;
+  unsigned short int dist_mm;
+
+  delta_x_mm=(pattern_data->motion_data.ramp_data.max_coord_x-pattern_data->motion_data.ramp_data.min_coord_x)*MTN_X_LED_SPACING;
+  delta_y_mm=(pattern_data->motion_data.ramp_data.max_coord_y-pattern_data->motion_data.ramp_data.min_coord_y)*MTN_Y_LED_SPACING;
+
+  dist_mm=sqrt(pow(delta_x_mm,2)+pow(delta_y_mm,2));
+
+  ms_pixel_x=(dist_mm*1000)/(delta_x_mm*pattern_data->speed_mm_s);
+  ms_pixel_y=(dist_mm*1000)/(delta_y_mm*pattern_data->speed_mm_s);
+
+  if(pattern_data->motion_data.ramp_data.direction==0x01)
+  {
+    pattern_data->current_col=pattern_data->motion_data.ramp_data.min_coord_x+(pattern_data->current_time/ms_pixel_x);
+    pattern_data->current_row=pattern_data->motion_data.ramp_data.min_coord_y+(pattern_data->current_time/ms_pixel_y);
+
+    if((pattern_data->current_col>=pattern_data->motion_data.ramp_data.max_coord_x) &&
+       (pattern_data->current_row>=pattern_data->motion_data.ramp_data.max_coord_y))
+    {
+      pattern_data->current_time=0;
+      pattern_data->motion_data.ramp_data.direction=0x00;
+    }
+  }
+  else
+  {
+    pattern_data->current_col=pattern_data->motion_data.ramp_data.max_coord_x-(pattern_data->current_time/ms_pixel_x);
+    pattern_data->current_row=pattern_data->motion_data.ramp_data.max_coord_y-(pattern_data->current_time/ms_pixel_y);
+
+    if((pattern_data->current_col<=pattern_data->motion_data.ramp_data.min_coord_x) &&
+       (pattern_data->current_row<=pattern_data->motion_data.ramp_data.min_coord_y))
+    {
+      pattern_data->current_time=0;
+      pattern_data->motion_data.ramp_data.direction=0x01;
+    }
+  }
+}
+
+// public functions
+void mtn_general(TLEDArea *area,TMotion *pattern_data,unsigned char buffer_id,unsigned short int period,TFBControl *control)
+{
+  pattern_data->current_time+=period;
+}
+
+void mtn_compute(TMotion *pattern_data)
+{
+  // image pattern motion
+  switch(pattern_data->motion_id)
+  {
+    case MTN_RAMP: mtn_ramp(pattern_data);
+                   break;
+    case MTN_TRIANGLE: mtn_triangle(pattern_data);
+                       break;
+    case MTN_CIRCLE:
+                     break;
+    case MTN_NONE: pattern_data->current_col=0;
+                   pattern_data->current_row=0;
+                   break;
+  }
+}
diff --git a/pattern_frame_buffer/src/waveform_patterns.c b/pattern_frame_buffer/src/waveform_patterns.c
new file mode 100644
index 0000000000000000000000000000000000000000..af76f80d641eaccb997efeb6d3aa8bba20cc9507
--- /dev/null
+++ b/pattern_frame_buffer/src/waveform_patterns.c
@@ -0,0 +1,146 @@
+#include "waveform_patterns.h"
+#include "frame_buffer.h"
+#include <math.h>
+
+float sin_lut[256]={0,0.0245,0.0491,0.0736,0.0980,0.1224,0.1467,0.1710,0.1951,0.2191,0.2430,0.2667,0.2903,0.3137,0.3369,0.3599,
+                    0.3827,0.4052,0.4276,0.4496,0.4714,0.4929,0.5141,0.5350,0.5556,0.5758,0.5957,0.6152,0.6344,0.6532,0.6716,0.6895,
+                    0.7071,0.7242,0.7410,0.7572,0.7730,0.7883,0.8032,0.8176,0.8315,0.8449,0.8577,0.8701,0.8819,0.8932,0.9040,0.9142,
+                    0.9239,0.9330,0.9415,0.9495,0.9569,0.9638,0.9700,0.9757,0.9808,0.9853,0.9892,0.9925,0.9952,0.9973,0.9988,0.9997,
+                    1.0000,0.9997,0.9988,0.9973,0.9952,0.9925,0.9892,0.9853,0.9808,0.9757,0.9700,0.9638,0.9569,0.9495,0.9415,0.9330,
+                    0.9239,0.9142,0.9040,0.8932,0.8819,0.8701,0.8577,0.8449,0.8315,0.8176,0.8032,0.7883,0.7730,0.7572,0.7410,0.7242,
+                    0.7071,0.6895,0.6716,0.6532,0.6344,0.6152,0.5957,0.5758,0.5556,0.5350,0.5141,0.4929,0.4714,0.4496,0.4276,0.4052,
+                    0.3827,0.3599,0.3369,0.3137,0.2903,0.2667,0.2430,0.2191,0.1951,0.1710,0.1467,0.1224,0.0980,0.0736,0.0491,0.0245,
+                    0.0000,-0.0245,-0.0491,-0.0736,-0.0980,-0.1224,-0.1467,-0.1710,-0.1951,-0.2191,-0.2430,-0.2667,-0.2903,-0.3137,-0.3369,
+                    -0.3599,-0.3827,-0.4052,-0.4276,-0.4496,-0.4714,-0.4929,-0.5141,-0.5350,-0.5556,-0.5758,-0.5957,-0.6152,-0.6344,-0.6532,
+                    -0.6716,-0.6895,-0.7071,-0.7242,-0.7410,-0.7572,-0.7730,-0.7883,-0.8032,-0.8176,-0.8315,-0.8449,-0.8577,-0.8701,-0.8819,
+                    -0.8932,-0.9040,-0.9142,-0.9239,-0.9330,-0.9415,-0.9495,-0.9569,-0.9638,-0.9700,-0.9757,-0.9808,-0.9853,-0.9892,-0.9925,
+                    -0.9952,-0.9973,-0.9988,-0.9997,-1.0000,-0.9997,-0.9988,-0.9973,-0.9952,-0.9925,-0.9892,-0.9853,-0.9808,-0.9757,-0.9700,
+                    -0.9638,-0.9569,-0.9495,-0.9415,-0.9330,-0.9239,-0.9142,-0.9040,-0.8932,-0.8819,-0.8701,-0.8577,-0.8449,-0.8315,-0.8176,
+                    -0.8032,-0.7883,-0.7730,-0.7572,-0.7410,-0.7242,-0.7071,-0.6895,-0.6716,-0.6532,-0.6344,-0.6152,-0.5957,-0.5758,-0.5556,
+                    -0.5350,-0.5141,-0.4929,-0.4714,-0.4496,-0.4276,-0.4052,-0.3827,-0.3599,-0.3369,-0.3137,-0.2903,-0.2667,-0.2430,-0.2191,
+                    -0.1951,-0.1710,-0.1467,-0.1224,-0.0980,-0.0736,-0.0491,-0.0245};
+
+TPixelRGB wf_sine(TWaveform *pattern_data)
+{
+  unsigned char amplitude,mean,value;
+  TPixelRGB pixel;
+
+  amplitude=(pattern_data->max.R-pattern_data->min.R)/2;
+  mean=(pattern_data->max.R+pattern_data->min.R)/2;
+  value=(255*pattern_data->current_period/pattern_data->period)+pattern_data->data.sine_data.phase;
+  pixel.R=(unsigned char)(amplitude*sin_lut[value]+mean);
+  amplitude=(pattern_data->max.G-pattern_data->min.G)/2;
+  mean=(pattern_data->max.G+pattern_data->min.G)/2;
+  value=(255*pattern_data->current_period/pattern_data->period)+pattern_data->data.sine_data.phase;
+  pixel.G=(unsigned char)(amplitude*sin_lut[value]+mean);
+  amplitude=(pattern_data->max.B-pattern_data->min.B)/2;
+  mean=(pattern_data->max.B+pattern_data->min.B)/2;
+  value=(255*pattern_data->current_period/pattern_data->period)+pattern_data->data.sine_data.phase;
+  pixel.B=(unsigned char)(amplitude*sin_lut[value]+mean);
+
+  return pixel;
+}
+
+TPixelRGB wf_square(TWaveform *pattern_data)
+{
+  TPixelRGB pixel;
+
+  if(pattern_data->current_period<pattern_data->data.square_data.t_on)
+  {
+    pixel.R=pattern_data->max.R;
+    pixel.G=pattern_data->max.G;
+    pixel.B=pattern_data->max.B;
+  }
+  else
+  {
+    pixel.R=pattern_data->min.R;
+    pixel.G=pattern_data->min.G;
+    pixel.B=pattern_data->min.B;
+  }
+
+  return pixel;
+}
+
+TPixelRGB wf_ramp(TWaveform *pattern_data)
+{
+  TPixelRGB pixel;
+
+  pixel.R=pattern_data->min.R+((pattern_data->max.R-pattern_data->min.R)*pattern_data->current_period)/pattern_data->period;
+  pixel.G=pattern_data->min.G+((pattern_data->max.G-pattern_data->min.G)*pattern_data->current_period)/pattern_data->period;
+  pixel.B=pattern_data->min.B+((pattern_data->max.B-pattern_data->min.B)*pattern_data->current_period)/pattern_data->period;
+
+  return pixel;
+}
+
+TPixelRGB wf_triangle(TWaveform *pattern_data)
+{
+  unsigned short int time;
+  TPixelRGB pixel;
+
+  if(pattern_data->current_period<(pattern_data->period/2))
+  {
+    pixel.R=pattern_data->min.R+((pattern_data->max.R-pattern_data->min.R)*pattern_data->current_period)/(pattern_data->period/2);
+    pixel.G=pattern_data->min.G+((pattern_data->max.G-pattern_data->min.G)*pattern_data->current_period)/(pattern_data->period/2);
+    pixel.B=pattern_data->min.B+((pattern_data->max.B-pattern_data->min.B)*pattern_data->current_period)/(pattern_data->period/2);
+  }
+  else
+  {
+    time=pattern_data->current_period-(pattern_data->period/2);
+    pixel.R=pattern_data->max.R-((pattern_data->max.R-pattern_data->min.R)*time)/(pattern_data->period/2);
+    pixel.G=pattern_data->max.G-((pattern_data->max.G-pattern_data->min.G)*time)/(pattern_data->period/2);
+    pixel.B=pattern_data->max.B-((pattern_data->max.B-pattern_data->min.B)*time)/(pattern_data->period/2);
+  }
+
+  return pixel;
+}
+
+TPixelRGB wf_none(TWaveform *pattern_data)
+{
+  TPixelRGB pixel;
+
+  pixel.R=pattern_data->max.R;
+  pixel.G=pattern_data->max.G;
+  pixel.B=pattern_data->max.B;
+
+  return pixel;
+}
+
+TPixelRGB wf_pixel(TWaveform *pattern_data)
+{
+  TPixelRGB pixel;
+
+  switch(pattern_data->waveform_id)
+  {
+    case WF_SINE: pixel=wf_sine(pattern_data);
+                  break;
+    case WF_SQUARE: pixel=wf_square(pattern_data);
+                    break;
+    case WF_RAMP: pixel=wf_ramp(pattern_data);
+                  break;
+    case WF_TRIANGLE: pixel=wf_triangle(pattern_data);
+                      break;
+    case WF_NONE: pixel=wf_none(pattern_data);
+                  break;
+  }
+
+  return pixel;
+}
+
+// public functions
+void wf_general(TLEDArea *area,TWaveform *pattern_data,unsigned char buffer_id,unsigned short int period,TFBControl *control)
+{
+  unsigned short int i,j;
+  TPixelRGB pixel;
+
+  // always compute time
+  pattern_data->current_period+=period;
+  if(pattern_data->current_period>=pattern_data->period)
+    pattern_data->current_period-=pattern_data->period;
+  if(pattern_data->active)// motion only when active
+  {
+    pixel=wf_pixel(pattern_data);
+    for(i=area->min_row;i<=area->max_row;i++)
+      for(j=area->min_col;j<=area->max_col;j++)
+        frame_buffer_set_pixel(&control->frame_buffer,buffer_id,pixel.R,pixel.G,pixel.B,i,j);
+  }
+}