diff --git a/pattern_frame_buffer/Makefile b/pattern_frame_buffer/Makefile
new file mode 100755
index 0000000000000000000000000000000000000000..3be4be6c6d07b77d8897994428ed716654cf8366
--- /dev/null
+++ b/pattern_frame_buffer/Makefile
@@ -0,0 +1,89 @@
+# setup
+# modified by zerom for WinARM 8/2010
+
+COMPILE_OPTS = -mlittle-endian -mthumb -mthumb-interwork
+COMPILE_OPTS += -Wall -O2 -fno-common
+#COMPILE_OPTS += -Wall -g -fno-common
+COMPILE_OPTS += -ffreestanding -nostdlib
+
+COMPILE_OPTS_M4_FPU = -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mcpu=cortex-m4
+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
+
+INCLUDE_DIRS = -I./include/ -I../memory/include -I../scheduler/include 
+
+DOC_DIR = ./doc
+
+TCHAIN_PREFIX=arm-none-eabi-
+
+CC = $(TCHAIN_PREFIX)gcc
+CFLAGS = $(COMPILE_OPTS) $(INCLUDE_DIRS)
+
+AR = $(TCHAIN_PREFIX)ar
+ARFLAGS = cr
+
+PATTERN_FB_OUT_M4_FPU = ./lib/pattern_fb_m4_fpu.a
+PATTERN_FB_OUT_M0 = ./lib/pattern_fb_m0.a
+PATTERN_FB_OUT_M0plus = ./lib/pattern_fb_m0plus.a
+PATTERN_FB_OUT_M3 = ./lib/pattern_fb_m3.a
+
+SRC_DIR=./src/
+SRC=$(wildcard $(SRC_DIR)*.c)
+
+PATTERN_FB_M4_FPU_OBJ_DIR=build/m4_fpu/
+PATTERN_FB_M4_FPU_OBJS_TMP = $(notdir $(SRC:.c=.o))
+PATTERN_FB_M4_FPU_OBJS = $(patsubst %,$(PATTERN_FB_M4_FPU_OBJ_DIR)%,$(PATTERN_FB_M4_FPU_OBJS_TMP))
+
+PATTERN_FB_M0_OBJ_DIR=build/m0/
+PATTERN_FB_M0_OBJS_TMP = $(notdir $(SRC:.c=.o))
+PATTERN_FB_M0_OBJS = $(patsubst %,$(PATTERN_FB_M0_OBJ_DIR)%,$(PATTERN_FB_M0_OBJS_TMP))
+
+PATTERN_FB_M0plus_OBJ_DIR=build/m0plus/
+PATTERN_FB_M0plus_OBJS_TMP = $(notdir $(SRC:.c=.o))
+PATTERN_FB_M0plus_OBJS = $(patsubst %,$(PATTERN_FB_M0plus_OBJ_DIR)%,$(PATTERN_FB_M0plus_OBJS_TMP))
+
+PATTERN_FB_M3_OBJ_DIR=build/m3/
+PATTERN_FB_M3_OBJS_TMP = $(notdir $(SRC:.c=.o))
+PATTERN_FB_M3_OBJS = $(patsubst %,$(PATTERN_FB_M3_OBJ_DIR)%,$(PATTERN_FB_M3_OBJS_TMP))
+
+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 $@ $<
+$(PATTERN_FB_M0_OBJ_DIR)%.o: $(SRC_DIR)%.c
+	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M0) -o $@ $<
+$(PATTERN_FB_M0plus_OBJ_DIR)%.o: $(SRC_DIR)%.c
+	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M0plus) -o $@ $<
+$(PATTERN_FB_M3_OBJ_DIR)%.o: $(SRC_DIR)%.c
+	$(CC) -c $(CFLAGS) $(COMPILE_OPTS_M3) -o $@ $<
+mkdir_build: 
+	mkdir -p build/m4_fpu
+	mkdir -p build/m0
+	mkdir -p build/m0plus
+	mkdir -p build/m3
+$(PATTERN_FB_OUT_M4_FPU): mkdir_build $(PATTERN_FB_M4_FPU_OBJS)
+	mkdir -p lib
+	$(AR) $(ARFLAGS) $@ $(PATTERN_FB_M4_FPU_OBJS)
+$(PATTERN_FB_OUT_M0): mkdir_build $(PATTERN_FB_M0_OBJS)
+	mkdir -p lib
+	$(AR) $(ARFLAGS) $@ $(PATTERN_FB_M0_OBJS)
+$(PATTERN_FB_OUT_M0plus): mkdir_build $(PATTERN_FB_M0plus_OBJS)
+	mkdir -p lib
+	$(AR) $(ARFLAGS) $@ $(PATTERN_FB_M0plus_OBJS)
+$(PATTERN_FB_OUT_M3): mkdir_build $(PATTERN_FB_M3_OBJS)
+	mkdir -p lib
+	$(AR) $(ARFLAGS) $@ $(PATTERN_FB_M3_OBJS)
+
+doc: 
+	doxygen $(DOC_DIR)/doxygen.conf 
+
+clean:
+	rm -f $(PATTERN_FB_M4_FPU_OBJS)
+	rm -f $(PATTERN_FB_M0_OBJS)
+	rm -f $(PATTERN_FB_M0plus_OBJS)
+	rm -f $(PATTERN_FB_M3_OBJS)
+	rm -rf lib
+	rm -rf build
+	rm -rf doc/html
+
+.PHONY: all clean doc
diff --git a/pattern_frame_buffer/include/frame_buffer.h b/pattern_frame_buffer/include/frame_buffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..edf28ebf3b9ee5e993060749835fcb8d8b432177
--- /dev/null
+++ b/pattern_frame_buffer/include/frame_buffer.h
@@ -0,0 +1,36 @@
+#ifndef _FRAME_BUFFER_H
+#define _FRAME_BUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "memory.h"
+#include "frame_buffer_registers.h"
+
+#ifndef FB_MAX_BUFFER_LEN
+  #define FB_MAX_BUFFER_LEN    16*1024
+#endif
+
+#define BYTES_PER_PIXEL   3
+#define LEDS_BYTES_PER_PIXEL   12
+
+unsigned char frame_buffer_init(TFrameBuffer *fb,TMemory *memory);
+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);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/pattern_frame_buffer/include/frame_buffer_registers.h b/pattern_frame_buffer/include/frame_buffer_registers.h
new file mode 100644
index 0000000000000000000000000000000000000000..40c70306879ae7c0c13bbb6ebb448de5bd29c34d
--- /dev/null
+++ b/pattern_frame_buffer/include/frame_buffer_registers.h
@@ -0,0 +1,40 @@
+#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
new file mode 100644
index 0000000000000000000000000000000000000000..fe385c1e2c2f009b4e4afba0f1b5500ecfeb4fa8
--- /dev/null
+++ b/pattern_frame_buffer/include/image_patterns.h
@@ -0,0 +1,45 @@
+#ifndef IMAGE_PATTERNS_H
+#define IMAGE_PATTERNS_H
+
+#include "patterns.h"
+#include "memory.h"
+
+#ifndef MAX_NUM_IMAGES
+  #define MAX_NUM_IMAGES             1
+#endif
+
+#ifndef MAX_IMAGE_WIDTH
+  #define MAX_IMAGE_WIDTH            15
+#endif
+
+#ifndef MAX_IMAGE_HEIGHT
+  #define MAX_IMAGE_HEIGHT           15
+#endif
+
+#include "image_patterns_registers.h"
+
+#define IMAGE_GROUP                  0x20
+
+unsigned char img_patterns_init(TMemory *memory);
+
+#pragma pack (push, 1)
+typedef struct
+{
+  short int start_row;
+  short int start_col;
+  unsigned char buffer_id;
+  unsigned char waveform_index;
+  unsigned char motion_index;
+}TIMGDisplayData;
+#pragma pack (pop)
+
+#define IMG_ID_OFFSET                   0x01
+#define IMG_START_ROW_OFFSET            0
+#define IMG_START_COL_OFFSET            2
+#define IMG_BUFFER_ID_OFFSET            4
+#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);
+
+#endif
diff --git a/pattern_frame_buffer/include/image_patterns_registers.h b/pattern_frame_buffer/include/image_patterns_registers.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf3e8b9146ab3bcc1695e7e7cc7810e445d4ee27
--- /dev/null
+++ b/pattern_frame_buffer/include/image_patterns_registers.h
@@ -0,0 +1,16 @@
+#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
new file mode 100644
index 0000000000000000000000000000000000000000..c5a30f0ef62dd2c05c01987aca8278842ca33fc3
--- /dev/null
+++ b/pattern_frame_buffer/include/led_control.h
@@ -0,0 +1,44 @@
+#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
new file mode 100644
index 0000000000000000000000000000000000000000..18f73d8986a839c18e47ee8413c6642e74b5a6b6
--- /dev/null
+++ b/pattern_frame_buffer/include/led_control_registers.h
@@ -0,0 +1,25 @@
+#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
new file mode 100644
index 0000000000000000000000000000000000000000..39a8a1d3162d37e12b765e2fcc439548401de129
--- /dev/null
+++ b/pattern_frame_buffer/include/motion_patterns.h
@@ -0,0 +1,75 @@
+#ifndef _MOTION_PATTERNS_H
+#define _MOTION_PATTERNS_H
+
+#include "patterns.h"
+
+#ifndef MTN_X_LED_SPACING
+  #define MTN_X_LED_SPACING         10
+#endif
+
+#ifndef MTN_Y_LED_SPACING
+  #define MTN_Y_LED_SPACING         10
+#endif
+
+#define MOTION_GROUP                 0x30
+
+typedef enum {MTN_RAMP=0x01,MTN_TRIANGLE=0x02,MTN_CIRCLE=0x03,MTN_NONE=0x04} mtn_id_t;
+
+typedef struct
+{
+  short int max_coord_x;
+  short int max_coord_y;
+  short int min_coord_x;
+  short int min_coord_y;
+  unsigned char direction;
+}TMTNRampData;
+
+typedef struct
+{
+  short int max_coord_x;
+  short int max_coord_y;
+  short int min_coord_x;
+  short int min_coord_y;
+  unsigned char direction;
+}TMTNTriangleData;
+
+typedef struct
+{
+  short int radius_mm;
+  short int center_x;
+  short int center_y;
+  short int dummy1;
+  unsigned char dummy2;
+}TMTNCircleData;
+
+typedef union
+{
+  TMTNRampData ramp_data;
+  TMTNTriangleData triangle_data;
+  TMTNCircleData circle_data;
+}TMTNData;
+
+#pragma pack (push, 1)
+typedef struct
+{
+  mtn_id_t motion_id;
+  unsigned short int speed_mm_s;
+  TMTNData motion_data;
+  // internal data
+  short int current_col;
+  short int current_row;
+  unsigned short int current_time;
+}TMotion;
+#pragma pack (pop)
+
+#define MTN_ID_OFFSET                0
+#define MTN_SPEED_OFFSET             1
+#define MTN_DATA                     3
+#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_compute(TMotion *pattern_data);
+
+#endif
diff --git a/pattern_frame_buffer/include/patterns.h b/pattern_frame_buffer/include/patterns.h
new file mode 100644
index 0000000000000000000000000000000000000000..bbf52cf8e0280b5d5804ea7c626ae37cd0be73bf
--- /dev/null
+++ b/pattern_frame_buffer/include/patterns.h
@@ -0,0 +1,24 @@
+#ifndef PATTERNS_H
+#define PATTERNS_H
+
+#define PATTERN_GROUP          0xF0
+#define PATTERN_ID             0x0F
+
+typedef struct
+{
+  unsigned short int min_row;
+  unsigned short int max_row;
+  unsigned short int min_col;
+  unsigned short int max_col;
+}TLEDArea;
+
+typedef struct
+{
+  unsigned char R;
+  unsigned char G;
+  unsigned char B;
+}TPixelRGB;
+
+
+
+#endif
diff --git a/pattern_frame_buffer/include/waveform_patterns.h b/pattern_frame_buffer/include/waveform_patterns.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad5bab637fc93c94d1be19c2d9d8b2304686cac4
--- /dev/null
+++ b/pattern_frame_buffer/include/waveform_patterns.h
@@ -0,0 +1,66 @@
+#ifndef WAVEFORM_PATTERNS_H
+#define WAVEFORM_PATTERNS_H
+
+#include "patterns.h"
+
+#define WAVEFORM_GROUP               0x10
+
+typedef enum {WF_SINE=0x01,WF_SQUARE=0x02,WF_RAMP=0x03,WF_TRIANGLE=0x04,WF_NONE=0x05} wf_id_t;
+
+typedef struct
+{
+  unsigned short int phase;
+}TWFSineData;
+
+typedef struct
+{
+  unsigned short int t_on;
+}TWFSquareData;
+
+typedef struct
+{
+  unsigned short int dummy;
+}TWFRampData;
+
+typedef struct
+{
+  unsigned short int dummy;
+}TWFTriangleData;
+
+typedef union{
+  TWFSineData sine_data;
+  TWFSquareData square_data;
+  TWFRampData ramp_data;
+  TWFTriangleData trinagle_data;
+}TWFData;
+
+#pragma pack (push, 1)
+typedef struct
+{
+  wf_id_t waveform_id;
+  TPixelRGB max;
+  TPixelRGB min;
+  unsigned short int period;
+  TWFData data;
+  unsigned char active;
+  // internal data (static)
+  unsigned short int current_period;
+}TWaveform;
+#pragma pack (pop)
+
+#define WF_ID_OFFSET              0
+#define WF_MAX_R_OFFSET           1 
+#define WF_MAX_G_OFFSET           2
+#define WF_MAX_B_OFFSET           3
+#define WF_MIN_R_OFFSET           4
+#define WF_MIN_G_OFFSET           5
+#define WF_MIN_B_OFFSET           6
+#define WF_PERIOD_OFFSET          7
+#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);
+
+TPixelRGB wf_pixel(TWaveform *pattern_data);
+
+#endif
diff --git a/pattern_frame_buffer/src/frame_buffer.c b/pattern_frame_buffer/src/frame_buffer.c
new file mode 100644
index 0000000000000000000000000000000000000000..7cdf725562c0a5cbbd363d8072c30053c0aebc5e
--- /dev/null
+++ b/pattern_frame_buffer/src/frame_buffer.c
@@ -0,0 +1,296 @@
+#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;
+
+// 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)
+{
+  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;
+}
+
+// public functions
+unsigned char fb_init(TFrameBuffer *fb,TMemory *memory)
+{
+  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;
+
+  for(i=0;i<FB_MAX_BUFFER_LEN/(FB_BYTES_PER_PIXEL/FB_BYTES_PER_PIXEL);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)
+{
+  return leds_num_rows;
+}
+
+void fb_set_pixels_per_row(TFrameBuffer *fb,unsigned short int pixels)
+{
+  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();
+}
+
+unsigned short int fb_get_pixels_per_row(TFrameBuffer *fb)
+{
+  return leds_num_pixels_per_row;
+}
+
+void fb_set_num_buffers(TFrameBuffer *fb,unsigned char num)
+{
+  leds_num_buffers=num;
+  ram_data[FB_NUM_BUFFERS]=num&0x00FF;
+  ram_data[FB_NUM_BUFFERS+1]=(num&0xFF00)>>8;
+  leds_compute_free_memory();
+}
+
+unsigned char fb_get_num_buffers(TFrameBuffer *fb)
+{
+  return leds_num_buffers;
+}
+
+unsigned short int fb_get_free_memory(TFrameBuffer *fb)
+{
+  return leds_free_mem;
+}
+
+unsigned char fb_update_buffer(TFrameBuffer *fb)
+{
+  if(leds_update)
+  {
+    leds_update=0x00;
+    return 0x01;
+  }
+  else
+    return 0x00;
+}
+
+unsigned char *fb_get_pixel_buffer(TFrameBuffer *fb)
+{
+  return leds_pixel_buffer;
+}
+
+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;
+    }
+  }
+  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;
+    }
+  }
+}
+
+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)
+{
+  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;
+}