summaryrefslogtreecommitdiff
path: root/msp430
diff options
context:
space:
mode:
authorChristian König <chrissi@zweiundvierzig.(none)>2010-05-16 21:26:27 +0200
committerChristian König <chrissi@zweiundvierzig.(none)>2010-05-16 21:26:27 +0200
commit63d5930e80b3949f7200f398d592c07cd87f0618 (patch)
tree19ab60aeb6263f4c2bfab3c81ef5df270f0606e0 /msp430
Initial commit
Diffstat (limited to 'msp430')
-rw-r--r--msp430/.gdbinit4
-rw-r--r--msp430/Makefile36
-rw-r--r--msp430/buffer.h103
-rw-r--r--msp430/cec.h220
-rw-r--r--msp430/cec_pin.h82
-rw-r--r--msp430/cec_state.h41
-rw-r--r--msp430/cec_timing.h113
-rw-r--r--msp430/i2c.h369
-rw-r--r--msp430/main.c52
9 files changed, 1020 insertions, 0 deletions
diff --git a/msp430/.gdbinit b/msp430/.gdbinit
new file mode 100644
index 0000000..1a44018
--- /dev/null
+++ b/msp430/.gdbinit
@@ -0,0 +1,4 @@
+target remote localhost:2000
+monitor erase all
+load
+monitor reset
diff --git a/msp430/Makefile b/msp430/Makefile
new file mode 100644
index 0000000..49b9d61
--- /dev/null
+++ b/msp430/Makefile
@@ -0,0 +1,36 @@
+# makfile configuration
+NAME = cec
+OBJECTS = main.o
+HEADERS = buffer.h cec.h cec_pin.h cec_state.h cec_timing.h i2c.h
+CPU = msp430x2012
+
+CFLAGS = -mmcu=${CPU} -Os -Wall -g
+
+#switch the compiler (for the internal make rules)
+CC = msp430-gcc
+
+.PHONY: all debug
+
+#all should be the first target. it's built when make is run without args
+all: ${NAME}.elf ${NAME}.a43 ${NAME}.lst
+
+debug: ${NAME}.elf
+ msp430-gdb ${NAME}.elf
+
+#additional rules for files
+${NAME}.elf: ${OBJECTS}
+ ${CC} -mmcu=${CPU} -o $@ ${OBJECTS}
+ msp430-size $@
+
+${NAME}.a43: ${NAME}.elf
+ msp430-objcopy -O ihex $^ $@
+
+${NAME}.lst: ${NAME}.elf
+ msp430-objdump -dSt $^ >$@
+
+clean:
+ rm -f ${NAME}.elf ${NAME}.a43 ${NAME}.lst ${OBJECTS}
+
+main.o: main.c ${HEADERS}
+i2c.o: i2c.c ${HEADERS}
+cec.o: cec.c ${HEADERS}
diff --git a/msp430/buffer.h b/msp430/buffer.h
new file mode 100644
index 0000000..a5142ed
--- /dev/null
+++ b/msp430/buffer.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright
+ *
+ * Copyright (C) 2009-2010 Christian König (deathsimple@vodafone.de)
+ *
+ * License
+ *
+ * This program is free software; you can redistribute and/or modify
+ * program under the terms of GNU General Public license either version 3
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _BUFFER_H_
+#define _BUFFER_H_
+
+#define BUFFER_SIZE 32
+#define BUFFER_MASK 0x1F
+
+typedef int bool;
+#define true 1
+#define false 0
+
+struct buffer {
+ uint8_t start;
+ uint8_t end;
+ uint8_t write;
+
+ uint8_t data[BUFFER_SIZE];
+};
+
+extern struct buffer rx_buf;
+extern struct buffer tx_buf;
+
+static bool buf_empty(struct buffer* buf)
+{
+ return buf->start == buf->end;
+}
+
+static uint8_t* buf_ptr(struct buffer* buf, uint8_t index)
+{
+ return &(buf->data[(index >> 3) & BUFFER_MASK]);
+}
+
+static bool buf_get_bit(struct buffer* buf)
+{
+ uint8_t* ptr = buf_ptr(buf, buf->start++);
+ bool result = *ptr & 0x80;
+ *ptr <<= 1;
+ return result;
+}
+
+static uint8_t buf_get_peak(struct buffer* buf)
+{
+ return *buf_ptr(buf, buf->start);
+}
+
+static uint8_t buf_get_byte(struct buffer* buf)
+{
+ uint8_t result = buf_get_peak(buf);
+ buf->start += 8;
+ return result;
+}
+
+static inline void buf_put_begin(struct buffer* buf)
+{
+ buf->write = 0;
+}
+
+static void buf_put_bit(struct buffer* buf, bool bit)
+{
+ uint8_t* ptr = buf_ptr(buf, buf->end + buf->write + 8);
+ *ptr <<= 1;
+ if(bit) *ptr |= 1;
+ buf->write++;
+}
+
+static inline int buf_put_addr(struct buffer* buf)
+{
+ return buf->write;
+}
+
+static uint8_t buf_put_head(struct buffer* buf)
+{
+ return *buf_ptr(buf, buf->end + 8);
+}
+
+static void buf_put_byte(struct buffer* buf, uint8_t byte)
+{
+ *buf_ptr(buf, buf->end) = byte;
+
+ buf->end += 8;
+}
+
+static void buf_put_done(struct buffer* buf)
+{
+ buf->write &= BUFFER_MASK << 3;
+ buf_put_byte(buf, buf->write);
+
+ buf->end += buf->write;
+}
+
+#endif
diff --git a/msp430/cec.h b/msp430/cec.h
new file mode 100644
index 0000000..318b67f
--- /dev/null
+++ b/msp430/cec.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright
+ *
+ * Copyright (C) 2009-2010 Christian König (deathsimple@vodafone.de)
+ *
+ * License
+ *
+ * This program is free software; you can redistribute and/or modify
+ * program under the terms of GNU General Public license either version 3
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _CEC_H_
+#define _CEC_H_
+
+#include "buffer.h"
+#include "cec_state.h"
+#include "cec_pin.h"
+#include "cec_timing.h"
+
+#define CEC_BroadcastAddr 0xF
+uint8_t CEC_UnicastAddr;
+
+uint8_t CEC_Count;
+bool CEC_IsTxBroadcast;
+
+enum CEC_State CEC_State;
+
+static inline bool CEC_IsRxAddrValid()
+{
+ uint8_t addr = buf_put_head(&rx_buf) & 0xF;
+ return addr == CEC_UnicastAddr ||
+ addr == CEC_BroadcastAddr;
+}
+
+static inline int CEC_IsRxBroadcast()
+{
+ uint8_t addr = buf_put_head(&rx_buf) & 0xF;
+ return addr == CEC_BroadcastAddr;
+}
+
+static inline void CEC_Init()
+{
+ CEC_State = CEC_Idle;
+
+ CEC_SEL &= CEC_MASK;
+
+ InputHight();
+
+ /* clear pending interrupt and enable it */
+ IntFallingEdge();
+ IntClearPending();
+
+ CEC_IE |= CEC_BIT;
+
+ // Reset timerA
+ TACTL |= TACLR;
+}
+
+static void CEC_SendMessage()
+{
+ if(CEC_State == CEC_Idle) {
+ CEC_Count = buf_get_byte(&tx_buf);
+ uint8_t addr = buf_get_peak(&tx_buf);
+ CEC_IsTxBroadcast = (addr & 0xF) == CEC_BroadcastAddr;
+
+ addr >>= 4;
+ if(addr != CEC_BroadcastAddr) {
+ CEC_UnicastAddr = addr;
+ }
+ Timer1(ARBITATION);
+ TimerStart();
+ }
+}
+
+static void CEC_Restart()
+{
+ // reset state maschine
+ CEC_State = CEC_Idle;
+
+ // stop timer
+ TimerStop();
+
+ if(!buf_empty(&tx_buf)) CEC_SendMessage();
+}
+
+static void CEC_LowDuration(unsigned int count)
+{
+ OutputLow();
+ IntClearPending();
+ Timer0(count);
+}
+
+interrupt(CEC_INT_VECTOR) IntServiceRoutineCEC()
+{
+ if(IntSelectedEdge()) {
+ TimerReset();
+ TimerStart();
+
+ int bit = CEC_IsRxBroadcast();
+ switch(CEC_State) {
+ case CEC_RX_ACK:
+ //TODO
+ //bit ^= !CEC_count && CurrentByte(rx_end) == rx_start;
+
+ case CEC_RX_Done:
+ CEC_LowDuration(bit ? DATA_H_AVG : DATA_L_AVG);
+
+ default:
+ Timer1(TIMEOUT);
+ }
+
+ } else {
+ enum DecodeResult result = TimerDecode();
+ if(result == BIT_Start) {
+ CEC_State = CEC_RX_Data;
+ buf_put_begin(&rx_buf);
+
+ } else if(result == BIT_OOR) {
+ buf_put_byte(&rx_buf, CEC_OOR);
+ CEC_Restart();
+
+ } else switch(CEC_State++) {
+ case CEC_Idle:
+ CEC_State = CEC_Idle;
+ TimerStop();
+ break;
+
+ case CEC_RX_Data:
+ buf_put_bit(&rx_buf, result);
+
+ int addr = buf_put_addr(&rx_buf);
+ if(addr == 8 && !CEC_IsRxAddrValid()) {
+ CEC_Restart();
+
+ } else if((addr & 7) != 0) {
+ CEC_State = CEC_RX_Data;
+ }
+ break;
+
+ case CEC_RX_EOM:
+ if(result) CEC_State = CEC_RX_Done;
+ break;
+
+ case CEC_RX_ACK:
+ CEC_State = CEC_RX_Data;
+ break;
+
+ case CEC_RX_Done:
+ buf_put_done(&rx_buf);
+ CEC_Restart();
+ break;
+
+ case CEC_TX_ACK:
+ if(result != CEC_IsTxBroadcast) {
+ buf_put_byte(&rx_buf, CEC_NACK);
+ CEC_Restart();
+
+ } else if(CEC_Count == 0) {
+ buf_put_byte(&rx_buf, CEC_Transmitted);
+ CEC_Restart();
+
+ } else {
+ CEC_State = CEC_TX_Data;
+ }
+ break;
+
+ default:
+ buf_put_byte(&rx_buf, CEC_ARL);
+ CEC_Restart();
+ break;
+ }
+ }
+
+ IntClearPending();
+ IntToggleEdge();
+}
+
+interrupt(TIMERA0_VECTOR) IntServiceRoutineTimerA0()
+{
+ InputHight();
+}
+
+interrupt(TIMERA1_VECTOR) IntServiceRoutineTimerA1()
+{
+ TimerReset();
+ switch(CEC_State) {
+ case CEC_Idle:
+ CEC_State = CEC_TX_Data;
+ CEC_LowDuration(START_AVG);
+ Timer1(START_LEN);
+ return;
+
+ case CEC_TX_Data:
+ CEC_Count--;
+ CEC_LowDuration(buf_get_bit(&tx_buf) ? DATA_H_AVG : DATA_L_AVG);
+ if((CEC_Count & 0x7) == 0) CEC_State = CEC_TX_EOM;
+ break;
+
+ case CEC_TX_EOM:
+ CEC_LowDuration(CEC_Count == 0 ? DATA_H_AVG : DATA_L_AVG);
+ CEC_State = CEC_TX_ACK;
+ break;
+
+ case CEC_TX_ACK:
+ CEC_LowDuration(DATA_H_AVG);
+ IntRisingEdge();
+ break;
+
+ default:
+ buf_put_byte(&rx_buf, CEC_Timeout);
+ CEC_Restart();
+ return;
+ }
+
+ Timer1(DATA_LEN);
+}
+
+#endif
diff --git a/msp430/cec_pin.h b/msp430/cec_pin.h
new file mode 100644
index 0000000..f0dbae5
--- /dev/null
+++ b/msp430/cec_pin.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright
+ *
+ * Copyright (C) 2009-2010 Christian König (deathsimple@vodafone.de)
+ *
+ * License
+ *
+ * This program is free software; you can redistribute and/or modify
+ * program under the terms of GNU General Public license either version 3
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _CEC_PIN_H_
+#define _CEC_PIN_H_
+
+#define CEC_PIN 6
+#define CEC_BIT (1 << CEC_PIN)
+#define CEC_MASK (~CEC_BIT)
+
+#define CEC_IN P2IN
+#define CEC_OUT P2OUT
+#define CEC_DIR P2DIR
+#define CEC_REN P2REN
+#define CEC_IFG P2IFG
+#define CEC_IES P2IES
+#define CEC_IE P2IE
+#define CEC_SEL P2SEL
+#define CEC_REN P2REN
+
+#define CEC_INT_VECTOR PORT2_VECTOR
+
+static inline void InputHight()
+{
+ /* input direction */
+ CEC_DIR &= CEC_MASK;
+
+ /* pull up */
+ CEC_OUT |= CEC_BIT;
+
+ /* enable resistor */
+ CEC_REN |= CEC_BIT;
+}
+
+static inline void OutputLow()
+{
+ /* output direction */
+ CEC_DIR |= CEC_BIT;
+
+ /* pull down */
+ CEC_OUT &= CEC_MASK;
+
+ /* disable resistor */
+ CEC_REN &= CEC_MASK;
+}
+
+static inline void IntClearPending()
+{
+ CEC_IFG &= CEC_MASK;
+}
+
+static inline void IntFallingEdge()
+{
+ CEC_IES |= CEC_BIT;
+}
+
+static inline void IntRisingEdge()
+{
+ CEC_IES &= CEC_MASK;
+}
+
+static inline void IntToggleEdge()
+{
+ CEC_IES ^= CEC_BIT;
+}
+
+static inline uint8_t IntSelectedEdge()
+{
+ return CEC_IES & CEC_BIT;
+}
+
+#endif
diff --git a/msp430/cec_state.h b/msp430/cec_state.h
new file mode 100644
index 0000000..0a11554
--- /dev/null
+++ b/msp430/cec_state.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright
+ *
+ * Copyright (C) 2009-2010 Christian König (deathsimple@vodafone.de)
+ *
+ * License
+ *
+ * This program is free software; you can redistribute and/or modify
+ * program under the terms of GNU General Public license either version 3
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _CEC_STATE_H_
+#define _CEC_STATE_H_
+
+enum CEC_State {
+ CEC_Idle,
+
+ CEC_RX_Data,
+ CEC_RX_EOM,
+ CEC_RX_ACK,
+ CEC_RX_Done,
+
+ CEC_TX_Data,
+ CEC_TX_EOM,
+ CEC_TX_ACK
+
+};
+
+enum CEC_Result {
+ CEC_Transmitted = 0xF0,
+ CEC_Timeout = 0xE0,
+ CEC_OOR = 0xD0,
+ CEC_NACK = 0xC0,
+ CEC_ARL = 0xB0,
+ CEC_Bytes_Max = 0x80
+
+};
+
+#endif
diff --git a/msp430/cec_timing.h b/msp430/cec_timing.h
new file mode 100644
index 0000000..9e1ecd9
--- /dev/null
+++ b/msp430/cec_timing.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright
+ *
+ * Copyright (C) 2009-2010 Christian König (deathsimple@vodafone.de)
+ *
+ * License
+ *
+ * This program is free software; you can redistribute and/or modify
+ * program under the terms of GNU General Public license either version 3
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _CEC_TIMING_H_
+#define _CEC_TIMING_H_
+
+//#define DECODE_USE_HARD_VALUES
+
+//SMCLK=1.5MHz so everything is based on SMCLK/8=187.5kHz
+#define MILLISECONDS(x) ((int)((x)*187.5f))
+
+/* values extracted from the HDMI standard */
+#define START_MIN MILLISECONDS(3.5f)
+#define START_AVG MILLISECONDS(3.7f)
+#define START_MAX MILLISECONDS(3.9f)
+
+#define START_LEN MILLISECONDS(4.5f)
+
+#define DATA_H_MIN MILLISECONDS(0.4f)
+#define DATA_H_AVG MILLISECONDS(0.6f)
+#define DATA_H_MAX MILLISECONDS(0.85f)
+
+#define DATA_L_MIN MILLISECONDS(1.25f)
+#define DATA_L_AVG MILLISECONDS(1.5f)
+#define DATA_L_MAX MILLISECONDS(1.7f)
+
+#define DATA_LEN MILLISECONDS(2.4f)
+
+#define ARBITATION (DATA_LEN * 7)
+
+/* not standard values, but usefull */
+#define DATA_TRIGGER ((DATA_H_AVG + DATA_L_AVG) / 2)
+#define TIMEOUT MILLISECONDS(5.0f)
+
+static inline void TimerStart()
+{
+ TA0CTL = TASSEL_2 | ID_3 | MC_CONT;
+}
+
+static inline void TimerReset()
+{
+ TA0R = 0;
+}
+
+static inline void TimerStop()
+{
+ TA0CTL = TASSEL_2 | ID_3 | MC_STOP;
+ TA0CCTL0 = 0;
+ TA0CCTL1 = 0;
+}
+
+static inline void Timer0(uint16_t count)
+{
+ TA0CCR0 = count;
+ TA0CCTL0 = CCIE;
+}
+
+static inline void Timer1(uint16_t count)
+{
+ TA0CCR1 = count;
+ TA0CCTL1 = CCIE;
+}
+
+static enum DecodeResult
+{
+ BIT_L = 0,
+ BIT_H = 1,
+ BIT_Start = 2,
+ BIT_OOR = 3
+
+} inline TimerDecode()
+{
+ uint16_t count = TA0R;
+#ifdef DECODE_USE_HARD_VALUES
+ if(DATA_L_MIN <= count && count <= DATA_L_MAX) {
+ return BIT_L;
+
+ } else if(DATA_H_MIN <= count && count <= DATA_H_MAX) {
+ return BIT_H;
+
+ } else if(START_MIN <= count && count <= START_MAX) {
+ return BIT_Start;
+
+ } else {
+ return BIT_OOR;
+ }
+#else
+ if(count < DATA_TRIGGER) {
+ return BIT_H;
+
+ } else if(count < START_MIN) {
+ return BIT_L;
+
+ } else if(count <= START_MAX) {
+ return BIT_Start;
+
+ } else {
+ return BIT_OOR;
+ }
+#endif
+}
+
+#endif
diff --git a/msp430/i2c.h b/msp430/i2c.h
new file mode 100644
index 0000000..511c082
--- /dev/null
+++ b/msp430/i2c.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright
+ *
+ * Copyright (C) 2009-2010 Christian König (deathsimple@vodafone.de)
+ *
+ * License
+ *
+ * This program is free software; you can redistribute and/or modify
+ * program under the terms of GNU General Public license either version 3
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _I2C_H_
+#define _I2C_H_
+
+#include <io.h>
+#include <signal.h>
+
+#include "buffer.h"
+#include "cec.h"
+
+#define I2C_Addr ((uint8_t)0xC0)
+
+#define I2C_SDA (1 << 6)
+#define I2C_SCL (1 << 7)
+#define I2C_BOTH (I2C_SDA | I2C_SCL)
+
+static enum {
+ I2C_Idle,
+ I2C_RX_Addr,
+
+ I2C_TX_Ack_RX,
+ I2C_RX_Data,
+
+ I2C_TX_Ack_TX,
+ I2C_TX_Data,
+ I2C_RX_Ack,
+
+} I2C_State;
+
+static inline void I2C_InputHight()
+{
+ /* input direction */
+ P1DIR &= ~I2C_SDA;
+
+ /* pull up */
+ P1OUT |= I2C_SDA;
+
+ /* enable resistor */
+ P1REN |= I2C_SDA;
+}
+
+static inline void I2C_OutputLow()
+{
+ /* output direction */
+ P1DIR |= I2C_SDA;
+
+ /* pull down */
+ P1OUT &= ~I2C_SDA;
+
+ /* disable resistor */
+ P1REN &= ~I2C_SDA;
+}
+
+static inline void I2C_Init()
+{
+ P1IES |= I2C_BOTH;
+ P1IFG &= ~I2C_BOTH;
+ P1IE |= I2C_BOTH;
+}
+
+static inline bool I2C_Start(uint8_t ies, uint8_t ifg)
+{
+ return (ies == I2C_BOTH) && (ifg == I2C_SDA);
+}
+
+static inline bool I2C_Write(uint8_t ies, uint8_t ifg)
+{
+ return (ies & I2C_SCL) && (ifg == I2C_SCL);
+}
+
+static inline bool I2C_Read(uint8_t ies, uint8_t ifg)
+{
+ return !(ies & I2C_SCL) && (ifg == I2C_SCL);
+}
+
+static inline bool I2C_Stop(uint8_t ies, uint8_t ifg)
+{
+ return (ies == I2C_SCL) && (ifg == I2C_SDA);
+}
+
+interrupt(PORT1_VECTOR) IntServiceRoutinePort1()
+{
+ uint8_t ifg = P1IFG & I2C_BOTH;
+ uint8_t ies = P1IES & I2C_BOTH;
+
+ P1IFG ^= ifg;
+ P1IES ^= ifg;
+
+ if(I2C_Start(ies, ifg)) {
+ I2C_State = I2C_RX_Addr;
+ buf_put_begin(&tx_buf);
+
+ } else if(I2C_Write(ies, ifg)) {
+ switch(I2C_State) {
+ case I2C_TX_Data:
+ if(buf_empty(&rx_buf) || buf_get_bit(&rx_buf)) {
+ I2C_InputHight();
+ break;
+ }
+
+ case I2C_TX_Ack_RX:
+ case I2C_TX_Ack_TX:
+ I2C_OutputLow();
+ break;
+
+ default:
+ I2C_InputHight();
+ break;
+ }
+
+ } else if(I2C_Read(ies, ifg)) {
+ switch(I2C_State) {
+ case I2C_Idle:
+ break;
+
+ case I2C_RX_Addr:
+ buf_put_bit(&tx_buf, P1IN & I2C_SDA);
+
+ if(buf_put_addr(&tx_buf) == 8) {
+ uint8_t addr = buf_put_head(&tx_buf);
+
+ // Address match? if yes send [N]Ack depending on buffer state
+ if(addr == I2C_Addr) {
+ buf_put_begin(&tx_buf);
+ I2C_State = I2C_TX_Ack_RX;
+
+ } else if((addr == (I2C_Addr | 1)) && !buf_empty(&rx_buf)) {
+ I2C_State = I2C_TX_Ack_TX;
+
+ } else {
+ // No address match -> ignored
+ I2C_State = I2C_Idle;
+ }
+ }
+ break;
+
+ case I2C_TX_Ack_RX:
+ I2C_State = I2C_RX_Data;
+ break;
+
+ case I2C_RX_Ack:
+ if(P1IN & I2C_SDA) {
+ I2C_State = I2C_Idle;
+ }
+
+ case I2C_TX_Ack_TX:
+ I2C_State = I2C_TX_Data;
+ break;
+
+ case I2C_TX_Data:
+ if((rx_buf.start & 7) == 0) {
+ I2C_State = I2C_RX_Ack;
+ }
+ break;
+
+ case I2C_RX_Data:
+ buf_put_bit(&tx_buf, P1IN & I2C_SDA);
+ if(!(buf_put_addr(&tx_buf) & 7)) {
+ I2C_State = I2C_TX_Ack_RX;
+ }
+ break;
+ }
+
+ } else if(I2C_Stop(ies, ifg)) {
+ if(I2C_State == I2C_RX_Data) {
+ buf_put_done(&tx_buf);
+ CEC_SendMessage();
+ }
+ I2C_State = I2C_Idle;
+
+ }
+}
+
+/*#define I2C_Direction 0x01
+#define I2C_Write 0x00
+#define I2C_Read 0x01
+
+uint8_t I2C_Offset;
+
+static uint8_t TxIndex()
+{
+ return (tx_end + I2C_Offset + 1) & BUFFER_MASK;
+}
+
+enum {
+ I2C_Idle = 0x00,
+ I2C_RX_Addr = 0x01,
+
+ I2C_TX_Ack = 0x02,
+ I2C_TX_Data = 0x03,
+
+ I2C_RX_Ack = 0x04,
+ I2C_RX_Data = 0x05
+
+} I2C_State;
+
+static inline void I2C_Init()
+{
+ // Internal Pullups enable
+ P1OUT |= 0xC0;
+ P1REN |= 0xC0;
+
+ P1DIR &= 0xC0;
+ P1IE |= 0x80;
+ P1IES &= ~0x80;
+ P1IFG &= ~0x80;
+
+ // Port & USI mode setup
+ USICTL0 = USIPE6 | USIPE7 | USISWRST;
+
+ // Set to I2C mode
+ USICTL1 = USII2C;
+
+ // Setup clock pol
+ USICKCTL = USICKPL;
+
+ // Disable automatic clear control
+ USICNT |= USIIFGCC;
+
+ // Enable USI
+ USICTL0 &= ~USISWRST;
+
+ // Clear Flags
+ USICTL1 &= ~(USISTP | USIIFG | USISTTIFG);
+
+ // Enable I2C
+ USICTL1 |= USIIE | USISTTIE;
+
+ I2C_State = I2C_Idle;
+}
+
+static inline void Receive(uint8_t count)
+{
+ // set bit counter
+ USICNT |= count;
+
+ // SDA = input
+ USICTL0 &= ~USIOE;
+}
+
+static void TransmitData()
+{
+ I2C_State = I2C_TX_Data;
+
+ if(rx_start != rx_end) {
+ USISRL = rx_buffer[rx_start];
+ rx_start++;
+ rx_start &= BUFFER_MASK;
+ } else {
+ USISRL = 0x00;
+ }
+
+ // SDA = output
+ USICTL0 |= USIOE;
+
+ // Bit counter = 8
+ USICNT |= 0x08;
+}
+
+static void TransmitAck(uint8_t value)
+{
+ if(value) {
+ I2C_State = I2C_Idle;
+ USISRL = 0xFF;
+
+ } else {
+ I2C_State = I2C_TX_Ack;
+ USISRL = 0x00;
+ }
+
+ // SDA = output
+ USICTL0 |= USIOE;
+
+ // Bit counter = 1
+ USICNT |= 0x01;
+}
+
+interrupt(USI_VECTOR) IntServiceRoutineI2C()
+{
+ if (USICTL1 & USISTTIFG) { // Start?
+ I2C_State = I2C_RX_Addr;
+
+ // Bit counter = 8, RX address
+ USICNT = (USICNT & 0xE0) | 0x08;
+
+ } else switch(I2C_State++) {
+ case I2C_Idle:
+ I2C_State = I2C_Idle;
+ USICTL0 &= ~USIOE;
+ break;
+
+ case I2C_RX_Addr:
+ I2C_Offset = 0;
+
+ // Address match? if yes send [N]Ack depending on buffer state
+ if (USISRL == (I2C_Addr | I2C_Write)) {
+ TransmitAck(TxIndex() == tx_start);
+
+ } else if (USISRL == (I2C_Addr | I2C_Read)) {
+ TransmitAck(rx_start == rx_end);
+ I2C_State = I2C_RX_Ack;
+
+ } else {
+ // No address match -> ignored
+ I2C_State = I2C_Idle;
+ }
+ break;
+
+ case I2C_TX_Ack:
+ I2C_State = I2C_RX_Data;
+ Receive(8);
+ break;
+
+ case I2C_TX_Data:
+ Receive(1);
+ break;
+
+ case I2C_RX_Ack:
+ if(USISRL & 1) {
+ I2C_State = I2C_Idle;
+
+ } else {
+ TransmitData();
+
+ }
+ break;
+
+ case I2C_RX_Data:
+ tx_buffer[TxIndex()] = USISRL;
+ I2C_Offset++;
+
+ TransmitAck(TxIndex() == tx_start);
+ break;
+ }
+
+ // Clear Flags
+ USICTL1 &= ~(USIIFG | USISTTIFG);
+}
+
+interrupt(PORT1_VECTOR) IntServiceRoutinePort1()
+{
+ P1IFG &= ~0x80;
+
+ if(USICTL1 & USISTP) {
+ USICTL0 &= ~USIOE;
+ USICTL1 &= ~USISTP;
+ I2C_State = I2C_Idle;
+ if(I2C_Offset != 0) {
+ tx_buffer[tx_end] = I2C_Offset;
+ tx_end += I2C_Offset + 1;
+ tx_end &= BUFFER_MASK;
+ CEC_SendMessage();
+ }
+ }
+}*/
+
+#endif
diff --git a/msp430/main.c b/msp430/main.c
new file mode 100644
index 0000000..86f1a4f
--- /dev/null
+++ b/msp430/main.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright
+ *
+ * Copyright (C) 2009-2010 Christian König (deathsimple@vodafone.de)
+ *
+ * License
+ *
+ * This program is free software; you can redistribute and/or modify
+ * program under the terms of GNU General Public license either version 3
+ * of the License, or (at your option) any later version.
+ *
+ */
+
+#include <io.h>
+#include <signal.h>
+
+#define DEBUG
+
+#include "i2c.h"
+#include "cec.h"
+
+struct buffer rx_buf;
+struct buffer tx_buf;
+
+static inline void OutputSMCLK()
+{
+#ifdef DEBUG
+ P1SEL |= 1 << 4;
+ P1DIR |= 1 << 4;
+#endif
+}
+
+int main()
+{
+ // disable watchdog timer and RESET pin
+ WDTCTL = WDTPW | WDTHOLD | WDTNMI;
+
+ // DCO=12MHz and SMCLK=1.5MHz
+ DCOCTL = CALDCO_12MHZ;
+ BCSCTL1 = CALBC1_12MHZ;
+ BCSCTL2 = DIVS_3;
+
+ OutputSMCLK();
+
+ I2C_Init();
+ CEC_Init();
+
+ while(1) {
+ WRITE_SR(LPM0_bits|GIE);
+ }
+ return 0;
+}