summaryrefslogtreecommitdiff
path: root/src/arch/msp430fr5994lp/driver
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/msp430fr5994lp/driver')
-rw-r--r--src/arch/msp430fr5994lp/driver/adc.cc71
-rw-r--r--src/arch/msp430fr5994lp/driver/counter.cc7
-rw-r--r--src/arch/msp430fr5994lp/driver/cpufreq.cc24
-rw-r--r--src/arch/msp430fr5994lp/driver/gpio.cc3
-rw-r--r--src/arch/msp430fr5994lp/driver/gpio.su0
-rw-r--r--src/arch/msp430fr5994lp/driver/i2c.cc128
-rw-r--r--src/arch/msp430fr5994lp/driver/spi_a1.cc61
-rw-r--r--src/arch/msp430fr5994lp/driver/spi_b.cc75
-rw-r--r--src/arch/msp430fr5994lp/driver/stdin.cc31
-rw-r--r--src/arch/msp430fr5994lp/driver/stdout.cc61
-rw-r--r--src/arch/msp430fr5994lp/driver/stdout.su5
-rw-r--r--src/arch/msp430fr5994lp/driver/timer.cc3
-rw-r--r--src/arch/msp430fr5994lp/driver/uptime.cc4
-rw-r--r--src/arch/msp430fr5994lp/driver/uptime.su0
14 files changed, 473 insertions, 0 deletions
diff --git a/src/arch/msp430fr5994lp/driver/adc.cc b/src/arch/msp430fr5994lp/driver/adc.cc
new file mode 100644
index 0000000..5a044a6
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/adc.cc
@@ -0,0 +1,71 @@
+#include "driver/adc.h"
+#include <msp430.h>
+
+#define CALADC12_12V_30C *((unsigned int *)0x1A1A)
+#define CALADC12_12V_85C *((unsigned int *)0x1A1C)
+
+float ADC::getTemp()
+{
+ float ret;
+
+ while(REFCTL0 & REFGENBUSY);
+
+ REFCTL0 = REFVSEL_0 | REFON;
+ ADC12CTL0 &= ~ADC12ENC;
+ ADC12CTL0 = ADC12SHT0_8 | ADC12ON;
+ ADC12CTL1 = ADC12SHP;
+ ADC12CTL3 = ADC12TCMAP;
+ ADC12MCTL0 = ADC12VRSEL_1 | ADC12INCH_30;
+ while(!(REFCTL0 & REFGENRDY));
+
+ ADC12CTL0 |= ADC12ENC;
+ ADC12CTL0 |= ADC12SC;
+ while (ADC12CTL1 & ADC12BUSY);
+
+ ret = (float)((long)ADC12MEM0 - CALADC12_12V_30C) * (85 - 30) /
+ (CALADC12_12V_85C - CALADC12_12V_30C) + 30.0f;
+
+ // Disable ADC
+ ADC12CTL0 &= ~ADC12ENC; // disable any conversion to allow ADC configuration
+ ADC12CTL0 &= ~ADC12ON; // Turn off ADC
+
+ // Disable internal 2V reference
+ while(REFCTL0 & REFGENBUSY);
+ REFCTL0 &= ~REFON;
+
+ return ret;
+}
+
+float ADC::getVCC()
+{
+ float ret;
+
+ while(REFCTL0 & REFGENBUSY);
+
+ REFCTL0 = REFVSEL_1 | REFON;
+ ADC12CTL0 &= ~ADC12ENC;
+ ADC12CTL0 = ADC12SHT0_8 | ADC12ON;
+ ADC12CTL1 = ADC12SHP;
+ ADC12CTL3 = ADC12BATMAP;
+ ADC12MCTL0 = ADC12VRSEL_1 | ADC12INCH_31;
+ while(!(REFCTL0 & REFGENRDY));
+
+ ADC12CTL0 |= ADC12ENC;
+ ADC12CTL0 |= ADC12SC;
+ while (ADC12CTL1 & ADC12BUSY);
+
+ ret = (float)ADC12MEM0 / 4096 * 2 * 2;
+ return ret;
+
+ // Disable ADC
+ ADC12CTL0 &= ~ADC12ENC; // disable any conversion to allow ADC configuration
+ ADC12CTL0 &= ~ADC12ON; // Turn off ADC
+
+ // Disable internal 2V reference
+ while(REFCTL0 & REFGENBUSY);
+ REFCTL0 &= ~REFON;
+
+ return ret;
+}
+
+ADC adc;
diff --git a/src/arch/msp430fr5994lp/driver/counter.cc b/src/arch/msp430fr5994lp/driver/counter.cc
new file mode 100644
index 0000000..62ac778
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/counter.cc
@@ -0,0 +1,7 @@
+#include "driver/counter.h"
+
+#if defined(TIMER_CYCLES)
+#warn "timer_cycles and counter are mutually exclusive. Expect odd behaviour."
+#endif
+
+Counter counter;
diff --git a/src/arch/msp430fr5994lp/driver/cpufreq.cc b/src/arch/msp430fr5994lp/driver/cpufreq.cc
new file mode 100644
index 0000000..55a74b5
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/cpufreq.cc
@@ -0,0 +1,24 @@
+void CPUFreq::set(unsigned int freq_khz)
+{
+ /*
+ * Note: arch drivers assume SMCLK freq == F_CPU
+ */
+
+ if (freq_khz == 16000) {
+ FRCTL0 = FWPW; // unlock FRAM Control
+ FRCTL0_L = 0x10; // one wait state before FRAM access (required for 8MHz < F_CPU <= 16 MHz)
+ FRCTL0_H = 0xff; // lock FRAM control by writing an invalid password
+ }
+
+ CSCTL0_H = CSKEY >> 8;
+ if (freq_khz == 16000) {
+ CSCTL1 = DCORSEL | DCOFSEL_4;
+ } else if (freq_khz == 8000) {
+ CSCTL1 = DCOFSEL_6;
+ } else if (freq_khz == 4000) {
+ CSCTL1 = DCOFSEL_3;
+ } else if (freq_khz == 1000) {
+ CSCTL1 = DCOFSEL_0;
+ }
+ CSCTL0_H = 0;
+}
diff --git a/src/arch/msp430fr5994lp/driver/gpio.cc b/src/arch/msp430fr5994lp/driver/gpio.cc
new file mode 100644
index 0000000..1403aed
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/gpio.cc
@@ -0,0 +1,3 @@
+#include "driver/gpio.h"
+
+GPIO gpio;
diff --git a/src/arch/msp430fr5994lp/driver/gpio.su b/src/arch/msp430fr5994lp/driver/gpio.su
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/gpio.su
diff --git a/src/arch/msp430fr5994lp/driver/i2c.cc b/src/arch/msp430fr5994lp/driver/i2c.cc
new file mode 100644
index 0000000..fe5b37b
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/i2c.cc
@@ -0,0 +1,128 @@
+#include "driver/i2c.h"
+#include "arch.h"
+#include <msp430.h>
+
+#ifndef F_I2C
+#define F_I2C 100000
+#endif
+
+volatile unsigned short old_ifg = 0;
+
+#if (F_CPU / F_I2C) < 45
+inline void await_i2c_int(unsigned int ie_flags, unsigned int ifg_flags) {
+ while (!(UCB0IFG & ifg_flags)) ;
+ if (UCB0IFG & (UCNACKIFG | UCCLTOIFG)) {
+ UCB0IFG &= ~(UCNACKIFG | UCCLTOIFG);
+ }
+}
+#else
+inline void await_i2c_int(unsigned int ie_flags, unsigned int ifg_flags)
+{
+ UCB0IFG = 0;
+ old_ifg = 0;
+ UCB0IE = ie_flags;
+ do {
+ arch.idle();
+ } while (!(old_ifg & ifg_flags));
+ UCB0IE = 0;
+}
+#endif
+
+signed char I2C::setup()
+{
+#ifdef I2C_PULLUP_FIXED_GPIO
+ P1DIR |= BIT4 | BIT5;
+ P1OUT |= BIT4 | BIT5;
+#endif
+ UCB0CTL1 = UCSWRST;
+ UCB0CTLW0 = UCMODE_3 | UCMST | UCSYNC | UCSSEL_2 | UCSWRST | UCCLTO_1;
+ UCB0BRW = (F_CPU / F_I2C) - 1;
+ P1DIR &= ~(BIT6 | BIT7);
+ P1SEL0 &= ~(BIT6 | BIT7);
+ P1SEL1 |= BIT6 | BIT7;
+
+ UCB0CTL1 &= ~UCSWRST;
+ UCB0I2CSA = 0;
+
+ arch.delay_us(100);
+
+ if (UCB0STAT & UCBBUSY)
+ return -1;
+
+ return 0;
+}
+
+void I2C::scan(unsigned int *results)
+{
+ for (unsigned char address = 0; address < 128; address++) {
+ UCB0I2CSA = address;
+ UCB0CTL1 |= UCTR | UCTXSTT | UCTXSTP;
+
+ while (UCB0CTL1 & UCTXSTP);
+
+ if (UCB0IFG & UCNACKIFG) {
+ UCB0IFG &= ~UCNACKIFG;
+ } else {
+ results[address / (8 * sizeof(unsigned int))] |= 1 << (address % (8 * sizeof(unsigned int)));
+ }
+ }
+ UCB0IFG = 0;
+}
+
+signed char I2C::xmit(unsigned char address,
+ unsigned char tx_len, unsigned char *tx_buf,
+ unsigned char rx_len, unsigned char *rx_buf)
+{
+ unsigned char i;
+ UCB0I2CSA = address;
+ if (tx_len) {
+ UCB0CTL1 |= UCTR | UCTXSTT;
+ for (i = 0; i < tx_len; i++) {
+ await_i2c_int(UCTXIE0 | UCNACKIE | UCCLTOIE, UCTXIFG0 | UCNACKIFG | UCCLTOIFG);
+ if (old_ifg & (UCNACKIFG | UCCLTOIFG)) {
+ UCB0CTL1 |= UCTXSTP;
+ return -1;
+ }
+ old_ifg = 0;
+ UCB0TXBUF = tx_buf[i];
+ }
+ await_i2c_int(UCTXIE0 | UCNACKIE | UCCLTOIE, UCTXIFG0 | UCNACKIFG | UCCLTOIFG);
+ //if (UCB0IFG & (UCNACKIFG | UCCLTOIFG)) {
+ // UCB0IFG &= ~UCNACKIFG;
+ // UCB0IFG &= ~UCCLTOIFG;
+ // UCB0CTL1 |= UCTXSTP;
+ // return -1;
+ //}
+ }
+ if (rx_len) {
+ UCB0I2CSA = address;
+ UCB0IFG = 0;
+ UCB0CTL1 &= ~UCTR;
+ UCB0CTL1 |= UCTXSTT;
+
+ while (UCB0CTL1 & UCTXSTT);
+ UCB0IFG &= ~UCTXIFG0;
+
+ for (i = 0; i < rx_len; i++) {
+ if (i == rx_len - 1)
+ UCB0CTL1 |= UCTXSTP;
+ await_i2c_int(UCRXIE | UCNACKIE | UCCLTOIE, UCRXIFG0 | UCNACKIFG | UCCLTOIFG);
+ rx_buf[i] = UCB0RXBUF;
+ UCB0IFG &= ~UCRXIFG0;
+ }
+ UCB0IFG &= ~UCRXIFG0;
+ }
+
+ UCB0CTL1 |= UCTXSTP;
+
+ while (UCB0CTL1 & UCTXSTP);
+ return 0;
+}
+
+__attribute__((interrupt(USCI_B0_VECTOR))) __attribute__((wakeup)) void handle_usci_b0()
+{
+ old_ifg = UCB0IFG;
+ UCB0IFG = 0;
+}
+
+I2C i2c;
diff --git a/src/arch/msp430fr5994lp/driver/spi_a1.cc b/src/arch/msp430fr5994lp/driver/spi_a1.cc
new file mode 100644
index 0000000..981bc53
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/spi_a1.cc
@@ -0,0 +1,61 @@
+#include "driver/spi.h"
+#include <msp430.h>
+
+signed char SPI::setup()
+{
+ /* UCA1CLK Pin 2.4 */
+ P2SEL0 &= ~BIT4;
+ P2SEL1 |= BIT4;
+ P2DIR |= BIT4;
+
+ /* UCA1SIMO Pin 2.5 */
+ P2SEL0 &= ~BIT5;
+ P2SEL1 |= BIT5;
+ P2DIR |= BIT5;
+
+ /* UCA1SOMI Pin 2.6 */
+ P2SEL0 &= ~BIT6;
+ P2SEL1 |= BIT6;
+ P2DIR &= ~BIT6;
+ //P2REN |= BIT6;
+
+ UCA1CTLW0 |= UCSWRST;
+ UCA1MCTLW = 0; // no modulation
+
+ UCA1CTLW0 = UCCKPH | UCMSB | UCMST | UCSYNC | UCMODE_0 | UCSSEL__SMCLK | UCSWRST;
+ UCA1BRW = 15; // /16 -> 1MHz
+ UCA1CTLW0 &= ~UCSWRST;
+}
+
+signed char SPI::xmit(unsigned char tx_len, unsigned char *tx_buf,
+ unsigned char rx_len, unsigned char *rx_buf)
+{
+ volatile char rxbuf_cache;
+ if (tx_len < 1) {
+ return -1;
+ }
+
+ UCA1IE &= ~(UCTXIE | UCRXIE);
+
+ while (UCA1STATW & UCBUSY) ;
+
+ rxbuf_cache = UCA1RXBUF;
+ UCA1TXBUF = tx_buf[0];
+
+ unsigned char tx_pos = 1;
+ unsigned char rx_pos = 0;
+
+ while (tx_pos < tx_len || rx_pos < rx_len) {
+ if ((tx_pos < tx_len) && (UCA1IF & UCTXIFG)) {
+ UCBA1TXBUF = tx_buf[tx_pos++];
+ }
+ if (UCA1IFG & UCRXIFG) {
+ if (rx_pos < rx_len) {
+ rx_buf[rx_pos] = UCA1RXBUF;
+ } else {
+ rxbuf_cache = UCA1RXBUF;
+ }
+ }
+ rx_pos++;
+ }
+}
diff --git a/src/arch/msp430fr5994lp/driver/spi_b.cc b/src/arch/msp430fr5994lp/driver/spi_b.cc
new file mode 100644
index 0000000..0fa71da
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/spi_b.cc
@@ -0,0 +1,75 @@
+#include "driver/spi_b.h"
+#include <msp430.h>
+
+#ifndef F_I2C
+#define F_I2C 1000000UL
+#endif
+
+void SPI::setup()
+{
+ UCB0CTLW0 |= UCSWRST;
+
+ /* UCB0CLK Pin 2.2 */
+ P2SEL0 &= ~BIT2;
+ P2SEL1 |= BIT2;
+ P2DIR |= BIT2;
+
+ /* UCB0SIMO Pin 1.6 */
+ P1SEL0 &= ~BIT6;
+ P1SEL1 |= BIT6;
+ P1DIR |= BIT6;
+
+ /* UCB0SOMI Pin 1.7 */
+ P1SEL0 &= ~BIT7;
+ P1SEL1 |= BIT7;
+ P1DIR &= ~BIT7;
+ //P1REN |= BIT6;
+
+ UCB0CTLW0 = UCCKPH | UCMSB | UCMST | UCSYNC | UCMODE_0 | UCSSEL__SMCLK | UCSWRST;
+ UCB0BRW = (F_CPU/F_I2C)-1; // /16 -> 1MHz
+ // UCB0BRW = (F_CPU / F_I2C) - 1
+ UCB0CTLW0 &= ~UCSWRST;
+}
+
+static inline unsigned char clean_rxbuf()
+{
+ return UCB0RXBUF;
+}
+
+signed char SPI::xmit(unsigned char tx_len, unsigned char *tx_buf,
+ unsigned char rx_len, unsigned char *rx_buf)
+{
+ if (tx_len < 1) {
+ return -1;
+ }
+
+ while (UCB0STATW & UCBUSY) ;
+
+ if (!(UCB0IFG & UCTXIFG)) {
+ return -1;
+ }
+
+ UCB0IFG &= ~UCRXIFG;
+ UCB0TXBUF = tx_buf[0];
+
+ unsigned char tx_pos = 1;
+ unsigned char rx_pos = 0;
+
+ while (tx_pos < tx_len || rx_pos < rx_len) {
+ if ((tx_pos < tx_len) && (UCB0IFG & UCTXIFG)) {
+ UCB0TXBUF = tx_buf[tx_pos++];
+ }
+ if (UCB0IFG & UCRXIFG) {
+ if (rx_pos < rx_len) {
+ rx_buf[rx_pos] = UCB0RXBUF;
+ } else {
+ UCB0IFG &= ~UCRXIFG;
+ }
+ rx_pos++;
+ }
+ }
+ while (UCB0STATW & UCBUSY) ;
+ return 0;
+}
+
+SPI spi;
diff --git a/src/arch/msp430fr5994lp/driver/stdin.cc b/src/arch/msp430fr5994lp/driver/stdin.cc
new file mode 100644
index 0000000..cc6e586
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/stdin.cc
@@ -0,0 +1,31 @@
+#include "driver/stdin.h"
+#include <msp430.h>
+
+void StandardInput::setup()
+{
+ UCA0IE |= UCRXIE;
+}
+
+bool StandardInput::hasKey()
+{
+ if (write_pos != read_pos) {
+ return true;
+ }
+ return false;
+}
+
+char StandardInput::getKey()
+{
+ char ret = buffer[read_pos++];
+ read_pos %= 8;
+ return ret;
+}
+
+StandardInput kin;
+
+__attribute__((interrupt(USCI_A0_VECTOR))) __attribute__((wakeup)) void handle_stdin()
+{
+ if (UCA0IFG & UCRXIFG) {
+ kin.addKey(UCA0RXBUF);
+ }
+}
diff --git a/src/arch/msp430fr5994lp/driver/stdout.cc b/src/arch/msp430fr5994lp/driver/stdout.cc
new file mode 100644
index 0000000..b3e8b4d
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/stdout.cc
@@ -0,0 +1,61 @@
+#include "driver/stdout.h"
+#include <msp430.h>
+
+/*
+ * Baud rate calculation according to datasheet:
+ * N := f_{BRCLK} / Baudrate = F_CPU / 115200 in our case
+ * if N <= 16: OS16 = 0, UCBR0 = int(N)
+ * if N > 16: OS16 = 1, UCBR0 = int(N/16), UCBRF0 = int(((n/16) - int(n/16)) * 16) = int(N)%16
+ * Set UCBRS0 according to table 21-4
+ */
+
+void StandardOutput::setup()
+{
+ UCA0CTLW0 |= UCSWRST;
+#if F_CPU == 16000000UL
+ // 16M / 115200 == 138.88889 -> UCOS16 = 1, UCBR0 = 16, UCBRF0 = 10, UCBRS0 = 0xf7 ("0.8751")
+ UCA0CTLW0 = UCSWRST | UCSSEL__SMCLK;
+ UCA0MCTLW = UCOS16 | (10<<4) | 0xF700;
+ UCA0BR0 = 8;
+#elif F_CPU == 8000000UL
+ // 8M / 115200 == 69.444444 -> UCOS16 = 1, UCBR0 = 4, UCBRF0 = 5, UCBRS0 = 0x55 ("0.4378")
+ UCA0CTLW0 = UCSWRST | UCSSEL__SMCLK;
+ UCA0MCTLW = UCOS16 | (5<<4) | 0x5500;
+ UCA0BR0 = 4;
+#elif F_CPU == 4000000UL
+ // 4M / 115200 == 34.722222 -> UCOS16 = 1, UCBR0 = 2, UCBRF0 = 2, UCBRS0 = 0xbb ("0.7147")
+ UCA0CTLW0 = UCSWRST | UCSSEL__SMCLK;
+ UCA0MCTLW = UCOS16 | (2<<4) | 0xbb00;
+ UCA0BR0 = 2;
+#elif F_CPU == 1000000UL
+ // 1M / 115200 == 8.6805556 -> UCOS16 = 0, UCBR0 = 8, UCBRF0 = 0, UCBRS0 = 0xd6 ("0.6667")
+ UCA0CTLW0 = UCSWRST | UCSSEL__SMCLK;
+ UCA0MCTLW = 0x5500;
+ UCA0BR0 = 8;
+#else
+#error Unsupported F_CPU
+#endif
+
+ UCA0IRCTL = 0;
+ UCA0ABCTL = 0;
+
+ P2SEL0 &= ~(BIT0 | BIT1);
+ P2SEL1 |= BIT0 | BIT1;
+ P2DIR |= BIT0;
+
+ UCA0CTLW0 &= ~UCSWRST;
+
+ //UCA0IE |= UCRXIE;
+}
+
+void StandardOutput::put(char c)
+{
+ while (!(UCA0IFG & UCTXIFG));
+ UCA0TXBUF = c;
+
+ if (c == '\n') {
+ put('\r');
+ }
+}
+
+StandardOutput kout;
diff --git a/src/arch/msp430fr5994lp/driver/stdout.su b/src/arch/msp430fr5994lp/driver/stdout.su
new file mode 100644
index 0000000..671f61b
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/stdout.su
@@ -0,0 +1,5 @@
+outputstream.h:21:15:virtual void OutputStream::write(const char*) 6 static
+outputstream.h:27:15:virtual void OutputStream::flush() 2 static
+stdout.cc:51:6:virtual void StandardOutput::put(char) 2 static
+stdout.cc:12:6:void StandardOutput::setup() 2 static
+stdout.cc:61:20:cc) 2 static
diff --git a/src/arch/msp430fr5994lp/driver/timer.cc b/src/arch/msp430fr5994lp/driver/timer.cc
new file mode 100644
index 0000000..4f2d6d1
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/timer.cc
@@ -0,0 +1,3 @@
+#include "driver/timer.h"
+
+Timer timer;
diff --git a/src/arch/msp430fr5994lp/driver/uptime.cc b/src/arch/msp430fr5994lp/driver/uptime.cc
new file mode 100644
index 0000000..05154f9
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/uptime.cc
@@ -0,0 +1,4 @@
+#include "driver/uptime.h"
+#include <msp430.h>
+
+Uptime uptime;
diff --git a/src/arch/msp430fr5994lp/driver/uptime.su b/src/arch/msp430fr5994lp/driver/uptime.su
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/arch/msp430fr5994lp/driver/uptime.su