diff --git a/src/Makefile b/src/Makefile index 7122512..7eed940 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,6 +18,7 @@ LDFLAGS = -L $(MSP430PATH)/msp430-elf/lib/430 \ objects = \ digital-io.o \ timer.o \ + usci.o \ usci-spi.o \ watchdog.o @@ -28,6 +29,8 @@ digital-io.o: timer.o: +usci.o: + usci-spi.o: watchdog.o: diff --git a/src/digital-io.cpp b/src/digital-io.cpp index 4aad368..3233599 100644 --- a/src/digital-io.cpp +++ b/src/digital-io.cpp @@ -13,6 +13,8 @@ namespace mardev::msp430::digital_io volatile uint8_t* const port_select_2[] = { registers::P1SEL2, registers::P2SEL2 }; volatile uint8_t* const port_resistor_enable[] = { registers::P1REN, registers::P2REN }; + + // 0 = pin is not attached to a digital IO port. const uint8_t pin_port[] = { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, @@ -45,7 +47,8 @@ namespace mardev::msp430::digital_io }; void set_pin_mode(const uint8_t pin_number, - const pin_mode mode) + const pin_mode mode, + const Function func) { const uint8_t port = pin_port[pin_number-1] - 1; const uint8_t port_mask = pin_port_mask[pin_number-1]; @@ -64,15 +67,24 @@ namespace mardev::msp430::digital_io else *port_resistor_enable[port] &= ~port_mask; - // Select the digital IO function. - *port_select[port] &= ~port_mask; - *port_select_2[port] &= ~port_mask; - - // Set output value. - if(mode == pin_mode::input_pullup) - *port_output[port] |= port_mask; - else // Pull-down or set output to low. - *port_output[port] &= ~port_mask; + // Set pin function. + switch(func) + { + case Function::IO: // Select the digital IO function. + *port_select[port] &= ~port_mask; + *port_select_2[port] &= ~port_mask; + break; + case Function::Primary: // Select primary peripheral module function. + *port_select[port] &= ~port_mask; + *port_select_2[port] |= port_mask; + break; + case Function::Special: // Reserved. This is a device-specific setting. + break; + case Function::Secondary: // Select secondary peripheral module function. + *port_select[port] |= port_mask; + *port_select_2[port] |= port_mask; + break; + } return; } diff --git a/src/digital-io.h b/src/digital-io.h index 0f11e23..112466c 100644 --- a/src/digital-io.h +++ b/src/digital-io.h @@ -39,8 +39,15 @@ namespace mardev::msp430::digital_io enum class pin_mode { output, - input_pullup, - input_pulldown + input + }; + + enum class Function : uint8_t + { + IO = 0, + Primary = 1, + Special = 2, + Secondary = 3 }; enum class logic @@ -53,9 +60,17 @@ namespace mardev::msp430::digital_io * * \param pin_number Pin number. * \param mode Desired mode. + * \param func Selected module function. */ void set_pin_mode(const uint8_t pin_number, - const pin_mode mode); + const pin_mode mode, + const Function func); + + inline void set_pin_mode(const uint8_t pin_number, + const pin_mode mode) + { + set_pin_mode(pin_number, mode, Function::IO); + } /** Read the digital signal on a pin. * diff --git a/src/interrupt.h b/src/interrupt.h index 646d0ea..0cc2495 100644 --- a/src/interrupt.h +++ b/src/interrupt.h @@ -5,6 +5,12 @@ namespace mardev::msp430::interrupt { + namespace registers + { + volatile uint8_t* const IE2 = (uint8_t* const) 0x01; + volatile uint8_t* const IFG2 = (uint8_t* const) 0x03; + } + // Digital I/O const uint16_t* const digital_io_port_1 = (uint16_t* const) 0xFFE4; // P1IFG const uint16_t* const digital_io_port_2 = (uint16_t* const) 0xFFE6; // P2IFG diff --git a/src/usci-spi.cpp b/src/usci-spi.cpp index 1c04bcd..5d9af0d 100644 --- a/src/usci-spi.cpp +++ b/src/usci-spi.cpp @@ -1,8 +1,17 @@ +#include "digital-io.h" +#include "interrupt.h" #include "usci.h" #include "usci-spi.h" +namespace dio = mardev::msp430::digital_io; +namespace interrupt = mardev::msp430::interrupt; + namespace mardev::msp430::usci::spi { + const uint8_t SCLK[] = { 6, 7 }; + const uint8_t MOSI[] = { 4, 15 }; + const uint8_t MISO[] = { 3, 14 }; + void initialize(const usci::Module module, const usci::UCMODE spi_mode, const UCSSELx clock_source, @@ -11,20 +20,52 @@ namespace mardev::msp430::usci::spi const UCMSB first_bit, const UC7BIT character_length) { - volatile uint8_t* const ctl0 = usci::registers::CTL0[(uint8_t)module], + volatile uint8_t* const + ctl0 = usci::registers::CTL0[(uint8_t)module], * ctl1 = usci::registers::CTL1[(uint8_t)module]; - *ctl0 = (uint8_t) clock_phase + *ctl1 |= usci::UCSWRST; + + const uint8_t pin_clock = SCLK[(uint8_t) module], + pin_mosi = SCLK[(uint8_t) module], + pin_miso = SCLK[(uint8_t) module]; + + // Configure pins. + dio::set_pin_mode(pin_clock, dio::pin_mode::output, dio::Function::Secondary); + dio::set_pin_mode(pin_mosi, dio::pin_mode::output, dio::Function::Secondary); + dio::set_pin_mode(pin_miso, dio::pin_mode::input, dio::Function::Secondary); + + *ctl1 |= (uint8_t) clock_source; + + const uint8_t settings = (uint8_t) clock_phase | (uint8_t) clock_polarity | (uint8_t) first_bit | (uint8_t) character_length - | 1 << 4 // Assume master mode + | (uint8_t) UCMST::Master // Assume master mode | (uint8_t) spi_mode | 1; // Synchronous mode enable + *ctl0 = settings; - *ctl1 = (uint8_t) clock_source - | usci::UCSWRST; + *ctl1 &= ~usci::UCSWRST; return; } + + uint8_t write(const usci::Module module, + const uint8_t data) + { + // Wait for the buffer to be ready. + const uint8_t tx_flag = usci::TXIFG[(uint8_t) module]; + while(*interrupt::registers::IFG2 & tx_flag); + + // Write data out. + volatile uint8_t* const tx_buffer = usci::registers::TXBUF[(uint8_t) module]; + *tx_buffer = data; + + // Wait for data to be ready. + const uint8_t rx_flag = usci::RXIFG[(uint8_t) module]; + while(*interrupt::registers::IFG2 & rx_flag); + volatile const uint8_t* const rx_buffer = usci::registers::RXBUF[(uint8_t) module]; + return *rx_buffer; + } } diff --git a/src/usci-spi.h b/src/usci-spi.h index 308bac1..61eb2d7 100644 --- a/src/usci-spi.h +++ b/src/usci-spi.h @@ -49,7 +49,7 @@ namespace mardev::msp430::usci::spi enum class UCMST : uint8_t { Slave = 0x00, - Master = 0x04 + Master = 0x08 }; /** Clock source select */ @@ -60,16 +60,11 @@ namespace mardev::msp430::usci::spi SMCLK = 0x80 }; - /* initialize() - * optionally set 3- or 4-pin mode? - * set clock phase - * set clock polarity - * set bit direction - * set character length: 7- or 8-bit - * enable synchronous mode (required = 1) - * set clock - * clear the software reset enable bit - */ + // Mapping module -> pin number + extern const uint8_t SCLK[]; + extern const uint8_t MOSI[]; + extern const uint8_t MISO[]; + void initialize(const usci::Module module, const usci::UCMODE spi_mode, const UCSSELx clock_source, @@ -77,6 +72,9 @@ namespace mardev::msp430::usci::spi const UCCKPL clock_polarity, const UCMSB first_bit, const UC7BIT character_length); + + uint8_t write(const usci::Module, + const uint8_t data); } #endif diff --git a/src/usci.cpp b/src/usci.cpp index 09be25b..8e43e11 100644 --- a/src/usci.cpp +++ b/src/usci.cpp @@ -4,15 +4,20 @@ namespace mardev::msp430::usci { namespace registers { - uint8_t* const CTL0[] = { UCA0CTL0, UCB0CTL0 }; - uint8_t* const CTL1[] = { UCA0CTL1, UCB0CTL1 }; + volatile uint8_t* const CTL0[] = { UCA0CTL0, UCB0CTL0 }; + volatile uint8_t* const CTL1[] = { UCA0CTL1, UCB0CTL1 }; - uint8_t* const BR0[] = { UCA0BR0, UCB0BR0 }; - uint8_t* const BR1[] = { UCA0BR1, UCB0BR1 }; + volatile uint8_t* const BR0[] = { UCA0BR0, UCB0BR0 }; + volatile uint8_t* const BR1[] = { UCA0BR1, UCB0BR1 }; - uint8_t* const STAT[] = { UCA0STAT, UCB0STAT }; + volatile uint8_t* const STAT[] = { UCA0STAT, UCB0STAT }; - const uint8_t* const RXBUF[] = { UCA0RXBUF, UCB0RXBUF }; - uint8_t* const TXBUF[] = { UCA0TXBUF, UCB0TXBUF }; + const volatile uint8_t* const RXBUF[] = { UCA0RXBUF, UCB0RXBUF }; + volatile uint8_t* const TXBUF[] = { UCA0TXBUF, UCB0TXBUF }; } + + const uint8_t RXIE[] = { UCA0RXIE, UCB0RXIE }; + const uint8_t TXIE[] = { UCA0TXIE, UCB0TXIE }; + const uint8_t RXIFG[] = { UCA0RXIFG, UCB0RXIFG }; + const uint8_t TXIFG[] = { UCA0TXIFG, UCB0TXIFG }; } diff --git a/src/usci.h b/src/usci.h index 08c1afd..d16f6f5 100644 --- a/src/usci.h +++ b/src/usci.h @@ -43,18 +43,23 @@ namespace mardev::msp430::usci volatile uint8_t* const UCB0TXBUF = (uint8_t* const) 0x6F; // ===== Module-Register mapping - extern volatile uint8_t* const CTL0[] = { UCA0CTL0, UCB0CTL0 }; - extern volatile uint8_t* const CTL1[] = { UCA0CTL1, UCB0CTL1 }; + extern volatile uint8_t* const CTL0[]; + extern volatile uint8_t* const CTL1[]; - extern volatile uint8_t* const BR0[] = { UCA0BR0, UCB0BR0 }; - extern volatile uint8_t* const BR1[] = { UCA0BR1, UCB0BR1 }; + extern volatile uint8_t* const BR0[]; + extern volatile uint8_t* const BR1[]; - extern volatile uint8_t* const STAT[] = { UCA0STAT, UCB0STAT }; + extern volatile uint8_t* const STAT[]; - extern volatile const uint8_t* const RXBUF[] = { UCA0RXBUF, UCB0RXBUF }; - extern volatile uint8_t* const TXBUF[] = { UCA0TXBUF, UCB0TXBUF }; + extern volatile const uint8_t* const RXBUF[]; + extern volatile uint8_t* const TXBUF[]; } + extern uint8_t const RXIE[]; + extern uint8_t const TXIE[]; + extern uint8_t const RXIFG[]; + extern uint8_t const TXIFG[]; + // USCI control register 0 masks const uint8_t UCMODEx = 0x06; @@ -62,6 +67,18 @@ namespace mardev::msp430::usci const uint8_t UCSSELx = 0xC0; const uint8_t UCSWRST = 0x01; + // Interrupt Enable register masks + const uint8_t UCB0TXIE = 0x08; + const uint8_t UCB0RXIE = 0x04; + const uint8_t UCA0TXIE = 0x02; + const uint8_t UCA0RXIE = 0x01; + + // Interrupt Flag 2 register masks + const uint8_t UCB0TXIFG = 0x08; + const uint8_t UCB0RXIFG = 0x04; + const uint8_t UCA0TXIFG = 0x02; + const uint8_t UCA0RXIFG = 0x01; + enum class Module : uint8_t { A0 = 0,