diff --git a/applications/app_uartcomm.c b/applications/app_uartcomm.c
new file mode 100644
index 00000000..9d65fbfb
--- /dev/null
+++ b/applications/app_uartcomm.c
@@ -0,0 +1,223 @@
+/*
+ Copyright 2012-2014 Benjamin Vedder benjamin@vedder.se
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+ */
+
+/*
+ * app_uartcomm.c
+ *
+ * Created on: 2 jul 2014
+ * Author: benjamin
+ */
+
+#include "app.h"
+#ifdef USE_APP_UARTCOMM
+
+#include "ch.h"
+#include "hal.h"
+#include "stm32f4xx_conf.h"
+#include "servo_dec.h"
+#include "mcpwm.h"
+#include "utils.h"
+#include "packet.h"
+#include "buffer.h"
+#include
+
+// Settings
+#define TIMEOUT_MSEC 1000
+#define BAUDRATE 115200
+#define UART_DEV UARTD6
+#define PACKET_HANDLER 1
+#define SERIAL_RX_BUFFER_SIZE 1024
+
+// Threads
+static msg_t uart_thread(void *arg);
+static msg_t packet_process_thread(void *arg);
+static WORKING_AREA(uart_thread_wa, 1024);
+static WORKING_AREA(packet_process_thread_wa, 1024);
+static Thread *process_tp;
+
+// Variables
+static volatile systime_t last_uart_update_time;
+static uint8_t serial_rx_buffer[SERIAL_RX_BUFFER_SIZE];
+static int serial_rx_read_pos = 0;
+static int serial_rx_write_pos = 0;
+
+// Private functions
+static void process_packet(unsigned char *buffer, unsigned char len);
+static void send_packet(unsigned char *buffer, unsigned char len);
+
+typedef enum {
+ UARTCOMM_CMD_SET_DUTY = 0,
+ UARTCOMM_CMD_SET_CURRENT,
+ UARTCOMM_CMD_SET_CURRENT_BRAKE,
+ UARTCOMM_CMD_SET_RPM
+} UARTCOMM_CMD;
+
+/*
+ * This callback is invoked when a transmission buffer has been completely
+ * read by the driver.
+ */
+static void txend1(UARTDriver *uartp) {
+ (void)uartp;
+}
+
+/*
+ * This callback is invoked when a transmission has physically completed.
+ */
+static void txend2(UARTDriver *uartp) {
+ (void)uartp;
+}
+
+/*
+ * This callback is invoked on a receive error, the errors mask is passed
+ * as parameter.
+ */
+static void rxerr(UARTDriver *uartp, uartflags_t e) {
+ (void)uartp;
+ (void)e;
+}
+
+/*
+ * This callback is invoked when a character is received but the application
+ * was not ready to receive it, the character is passed as parameter.
+ */
+static void rxchar(UARTDriver *uartp, uint16_t c) {
+ (void)uartp;
+ serial_rx_buffer[serial_rx_write_pos++] = c;
+
+ if (serial_rx_write_pos == SERIAL_RX_BUFFER_SIZE) {
+ serial_rx_write_pos = 0;
+ }
+
+ chEvtSignal(process_tp, (eventmask_t) 1);
+}
+
+/*
+ * This callback is invoked when a receive buffer has been completely written.
+ */
+static void rxend(UARTDriver *uartp) {
+ (void)uartp;
+}
+
+/*
+ * UART driver configuration structure.
+ */
+static UARTConfig uart_cfg = {
+ txend1,
+ txend2,
+ rxend,
+ rxchar,
+ rxerr,
+ BAUDRATE,
+ 0,
+ USART_CR2_LINEN,
+ 0
+};
+
+static void process_packet(unsigned char *buffer, unsigned char len) {
+ if (!len) {
+ return;
+ }
+
+ int32_t ind = 1;
+
+ switch (buffer[0]) {
+ case UARTCOMM_CMD_SET_DUTY:
+ mcpwm_set_duty((float)buffer_get_int16(buffer, &ind) / 1000.0);
+ last_uart_update_time = chTimeNow();
+ break;
+
+ case UARTCOMM_CMD_SET_CURRENT:
+ mcpwm_set_current((float)buffer_get_int32(buffer, &ind) / 1000.0);
+ last_uart_update_time = chTimeNow();
+ break;
+
+ case UARTCOMM_CMD_SET_CURRENT_BRAKE:
+ mcpwm_set_brake_current((float)buffer_get_int32(buffer, &ind) / 1000.0);
+ last_uart_update_time = chTimeNow();
+ break;
+
+ case UARTCOMM_CMD_SET_RPM:
+ mcpwm_set_pid_speed((float)buffer_get_int32(buffer, &ind));
+ last_uart_update_time = chTimeNow();
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void send_packet(unsigned char *buffer, unsigned char len) {
+ uartStartSend(&UART_DEV, len, buffer);
+}
+
+void app_uartcomm_init(void) {
+ packet_init(send_packet, process_packet, PACKET_HANDLER);
+ chThdCreateStatic(uart_thread_wa, sizeof(uart_thread_wa), NORMALPRIO - 1, uart_thread, NULL);
+ chThdCreateStatic(packet_process_thread_wa, sizeof(packet_process_thread_wa), NORMALPRIO, packet_process_thread, NULL);
+}
+
+static msg_t uart_thread(void *arg) {
+ (void)arg;
+
+ chRegSetThreadName("UARTCOMM");
+
+ uartStart(&UART_DEV, &uart_cfg);
+ palSetPadMode(GPIOC, 6, PAL_MODE_ALTERNATE(GPIO_AF_USART6) |
+ PAL_STM32_OSPEED_HIGHEST |
+ PAL_STM32_PUDR_PULLUP);
+ palSetPadMode(GPIOC, 7, PAL_MODE_ALTERNATE(GPIO_AF_USART6) |
+ PAL_STM32_OSPEED_HIGHEST |
+ PAL_STM32_PUDR_PULLUP);
+
+ systime_t time = chTimeNow();
+
+ for(;;) {
+ time += MS2ST(40);
+
+ if (chTimeElapsedSince(last_uart_update_time) > MS2ST(TIMEOUT_MSEC)) {
+ mcpwm_set_duty(0.0);
+ }
+
+ chThdSleepUntil(time);
+ }
+
+ return 0;
+}
+
+static msg_t packet_process_thread(void *arg) {
+ (void)arg;
+
+ chRegSetThreadName("uartcomm process");
+
+ process_tp = chThdSelf();
+
+ for(;;) {
+ chEvtWaitAny((eventmask_t) 1);
+
+ while (serial_rx_read_pos != serial_rx_write_pos) {
+ packet_process_byte(serial_rx_buffer[serial_rx_read_pos++], PACKET_HANDLER);
+
+ if (serial_rx_read_pos == SERIAL_RX_BUFFER_SIZE) {
+ serial_rx_read_pos = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif