From: smckown Date: Sun, 7 Sep 2008 01:20:29 +0000 (+0000) Subject: MSP430 USCI peripheral X-Git-Tag: patchset/2.1.1-4.5~22 X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=commitdiff_plain;h=e05ad9499986a90f9d64cd943800c9b230501c99 MSP430 USCI peripheral Supports UART, SPI (slave and master), and I2C modes. Current I2C limitations and features: * Master mode only. * No multi-master bus configurations. * Will automatically reset a hung bus, if for example the master reset in the middle of a transaction and a slave currently is driving SDA low. * Repeated starts are supported and can be very time efficient. * An I2C transactions may be processed with multiple I2CPacket.read() or I2CPacket.write() commands, as appropriate. The first must include I2C_START and the last must include I2C_STOP. * Conditions exist during read where the hardware may clock out an extra byte from the slave before stop. This byte is not passed to the user. --- diff --git a/tos/chips/msp430/usci/AsyncConfigure.nc b/tos/chips/msp430/usci/AsyncConfigure.nc new file mode 100644 index 00000000..f1e343de --- /dev/null +++ b/tos/chips/msp430/usci/AsyncConfigure.nc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Generic async configuration interface. + * + * @author R. Steve McKown + */ + +interface AsyncConfigure { + async command val_t get(); +} diff --git a/tos/chips/msp430/usci/HplMsp430UsciC.nc b/tos/chips/msp430/usci/HplMsp430UsciC.nc new file mode 100644 index 00000000..05917df9 --- /dev/null +++ b/tos/chips/msp430/usci/HplMsp430UsciC.nc @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Provides HPL access to both registers and interrupts of all USCI devices on + * a supported msp430 processor. The interfaces available are created + * depending upon the type of msp430 for which the code is being compiled. + * Currently most parts with one or two USCI peripherals supported by mspgcc + * (msp430-gcc) should be supported. The most common will probably be the + * parts offering two USCI peripherals, which use names like these to describe + * their provided serial devices: + * + * USCI_A0 and USCI_B0, from the first USCI peripheral; and + * USCI_A1 and USCI_B1, from the second USCI peripheral. + * + * 'A' devices offer UART, LIN, IrDA and SPI modes of operation. 'B' devices + * are limited to SPI and I2C modes. + * + * @author R. Steve McKown + */ + +configuration HplMsp430UsciC { + provides { +#if defined(__MSP430_HAS_USCI_AB0__) || defined(__MSP430_HAS_USCI__) + interface HplMsp430UsciReg as RegA0; + interface HplMsp430UsciInt as IntA0; + interface HplMsp430UsciReg as RegB0; + interface HplMsp430UsciInt as IntB0; +#endif +#if defined(__MSP430_HAS_USCI_AB1__) + interface HplMsp430UsciReg as RegA1; + interface HplMsp430UsciInt as IntA1; + interface HplMsp430UsciReg as RegB1; + interface HplMsp430UsciInt as IntB1; +#endif + } +} +implementation { +#if defined(__MSP430_HAS_USCI_AB0__) || defined(__MSP430_HAS_USCI__) + components new HplMsp430UsciRegP(UCA0CTL0_, UCA0CTL1_, UCA0BR0_, UCA0BR1_, + UCA0MCTL_, 0/*UCA0I2CIE_*/, UCA0STAT_, UCA0RXBUF_, UCA0TXBUF_, UCA0ABCTL_, + UCA0IRTCTL_, UCA0IRRCTL_, 0/*UCA0I2COA_*/, 0/*UCA0I2CSA_*/, IE2_, IFG2_, + UCA0RXIFG, UCA0TXIFG) as RegA0P; + RegA0 = RegA0P.Registers; + + components new HplMsp430UsciRegP(UCB0CTL0_, UCB0CTL1_, UCB0BR0_, UCB0BR1_, + 0/*UCB0MCTL_*/, UCB0I2CIE_, UCB0STAT_, UCB0RXBUF_, UCB0TXBUF_, + 0/*UCB0ABCTL_*/, 0/*UCB0IRTCTL_*/, 0/*UCB0IRRCTL_*/, UCB0I2COA_, + UCB0I2CSA_, IE2_, IFG2_, UCB0RXIFG, UCB0TXIFG) as RegB0P; + RegB0 = RegB0P.Registers; + + components HplMsp430UsciInt0P as Int0P; + IntA0 = Int0P.IntA; + IntB0 = Int0P.IntB; +#endif + +#if defined(__MSP430_HAS_USCI_AB1__) + components new HplMsp430UsciRegP(UCA1CTL0_, UCA1CTL1_, UCA1BR0_, UCA1BR1_, + UCA1MCTL_, 0/*UCA1I2CIE_*/, UCA1STAT_, UCA1RXBUF_, UCA1TXBUF_, UCA1ABCTL_, + UCA1IRTCTL_, UCA1IRRCTL_, 0/*UCA1I2COA_*/, 0/*UCA1I2CSA_*/, UC1IE_, + UC1IFG_, UCA1RXIFG, UCA1TXIFG) as RegA1P; + RegA1 = RegA1P.Registers; + + components new HplMsp430UsciRegP(UCB1CTL0_, UCB1CTL1_, UCB1BR0_, UCB1BR1_, + 0/*UCB1MCTL_*/, UCB1I2CIE_, UCB1STAT_, UCB1RXBUF_, UCB1TXBUF_, + 0/*UCB1ABCTL_*/, 0/*UCB1IRTCTL_*/, 0/*UCB1IRRCTL_*/, UCB1I2COA_, + UCB1I2CSA_, UC1IE_, UC1IFG_, UCB1RXIFG, UCB1TXIFG) as RegB1P; + RegB1 = RegB1P.Registers; + + components HplMsp430UsciInt1P as Int1P; + IntA1 = Int1P.IntA; + IntB1 = Int1P.IntB; +#endif +} diff --git a/tos/chips/msp430/usci/HplMsp430UsciInt.nc b/tos/chips/msp430/usci/HplMsp430UsciInt.nc new file mode 100644 index 00000000..d0021cd6 --- /dev/null +++ b/tos/chips/msp430/usci/HplMsp430UsciInt.nc @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Interrupt interface for USCI peripherals. Although A and B devices have + * different interrupt sets since B only support I2C, we use a single set for + * both so that upper layers need not deal with the different sets. This is + * critical in the case of SPI communications, which is supported by both A + * and B devices. + * + * @author R. Steve McKown + */ + +#include "Msp430Usci.h" + +interface HplMsp430UsciInt { + /** + * Signals a break received in UART modes if UCBRKIE is enabled. The + * provider must reset the UCxIFG.UCxxRXIFG and UCxSTAT.UCBRK bits prior to + * signalling the event to the user. + */ + async event void brk(); + + /** + * Signals a character received for any USCI mode. The provider must reset + * UCxIFG.UCxxRXIFG before signalling the event to the user. + * + * @params byte The character received. + */ + async event void rx(uint8_t byte); + + /** + * Signals that the device's transmit buffer is empty and can accept + * another character. Note that the USCI device may still be in the + * process of transmitting the last character when this event is signalled. + * The UCxxTXIFG bit will automatically reset when the interface user writes + * a value to the related UCxxTXBUF register after receipt of this event. + */ + async event void tx(); + + /** + * I2C mode only. Indicates the device has lost arbitration. Valid only in + * multi-master contexts. + */ + async event void i2cCal(); + + /** + * I2C mode only. Indicates the device was expecting an ACK and it was not + * received. + */ + async event void i2cNack(); + + /** + * I2C mode only. Indicates the device has detected a start condition + * together with its own address while in slave mode. + */ + async event void i2cStart(); + + /** + * I2C mode only. Indicates the device has detected a stop condition while + * in slave mode. + */ + async event void i2cStop(); +} diff --git a/tos/chips/msp430/usci/HplMsp430UsciInt0P.nc b/tos/chips/msp430/usci/HplMsp430UsciInt0P.nc new file mode 100644 index 00000000..d802a0bf --- /dev/null +++ b/tos/chips/msp430/usci/HplMsp430UsciInt0P.nc @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * HPL interrupt interface for the USCI0 peripheral. + * + * @author R. Steve McKown + */ + +#include "Msp430Usci.h" +#include "msp430hardware.h" + +#if defined(USCIRX_VECTOR) /* odd def for MSP430G461 */ +#define USCIAB0RX_VECTOR USCIRX_VECTOR +#endif +#if defined(USCITX_VECTOR) /* odd def for MSP430G461 */ +#define USCIAB0TX_VECTOR USCITX_VECTOR +#endif + +module HplMsp430UsciInt0P @safe() { + provides { + interface HplMsp430UsciInt as IntA; + interface HplMsp430UsciInt as IntB; + } +} + +implementation +{ +#if 0 + MSP430REG_NORACE(UC0IFG); + MSP430REG_NORACE(UCA0CTL0); + MSP430REG_NORACE(UCA0CTL1); + MSP430REG_NORACE(UCA0RXBUF); + MSP430REG_NORACE(UCB0CTL0); + MSP430REG_NORACE(UCB0CTL1); + MSP430REG_NORACE(UCB0RXBUF); +#endif + + /* This interrupt vector signals receive events. USCI_A0 can receive events + * for UART and SPI modes, while USCI_B0 can receive events for I2C and SPI + * modes. + */ + TOSH_SIGNAL(USCIAB0RX_VECTOR) { + if (READ_FLAG(UC0IFG & UC0IE, UCA0RXIE)) { + volatile uint8_t c = UCA0RXBUF; /* read to clear UCA0RXIFG */ + if (READ_FLAG(UCA0CTL1, UCBRK)) { + CLR_FLAG(UCA0CTL1, UCBRK); + if (READ_FLAG(UCA0CTL0, UCMODE_3) == UCMODE_3) + CLR_FLAG(UCA0CTL1, UCDORM); + signal IntA.brk(); + } else + signal IntA.rx(c); + } else if (READ_FLAG(UC0IFG & UC0IE, UCB0RXIE)) { + signal IntB.rx(UCB0RXBUF); /* read clears UCB0RXIFG */ + + /* FIXME: the arbitration of I2C interrupts are not vetted. If, for example + * the UCALIFG bit gets set and neither it nor the corresponding interrupt + * enable bit is never unset, then an ISR configured for UCSTTIFG or + * UCSTPIFG will never be signalled. + */ + + } else if (READ_FLAG(UCB0STAT, UCALIFG)) { + CLR_FLAG(UCB0STAT, UCALIFG); + signal IntB.i2cCal(); + } else if (READ_FLAG(UCB0STAT, UCNACKIFG)) { + CLR_FLAG(UCB0STAT, UCNACKIFG); + CLR_FLAG(UC0IFG, UCB0TXIFG); /* Errata USCI25; 'reset' means clear? */ + signal IntB.i2cNack(); + } else if (READ_FLAG(UCB0STAT, UCSTTIFG)) { + CLR_FLAG(UCB0STAT, UCSTTIFG); + signal IntB.i2cStart(); + } else if (READ_FLAG(UCB0STAT, UCSTPIFG)) { + CLR_FLAG(UCB0STAT, UCSTPIFG); + signal IntB.i2cStop(); + } + } + + /* This interrupt vector signals transmit events. USCI_A0 can receive events + * for UART and SPI modes, while USCI_B0 can receive events for I2C and SPI + * modes. + */ + TOSH_SIGNAL(USCIAB0TX_VECTOR) { + if (READ_FLAG(UC0IFG & UC0IE, UCB0RXIE)) { + /* I2C receive. Do not read UCB0RXBUF here, as the code receiving + * IntB.rx() may first need to set stop and/or start bits. The receiver + * must read UCB0RXBUF. + */ + signal IntB.rx(0); + } else if (READ_FLAG(UC0IFG & UC0IE, UCA0TXIFG)) + signal IntA.tx(); + else if (READ_FLAG(UC0IFG & UC0IE, UCB0TXIFG)) + signal IntB.tx(); + } + + default async event void IntA.brk() {} + default async event void IntA.rx(uint8_t byte) {} + default async event void IntA.tx() {} + /* i2c is not available for A devices, so the below are never signalled */ + default async event void IntA.i2cCal() {} + default async event void IntA.i2cNack() {} + default async event void IntA.i2cStart() {} + default async event void IntA.i2cStop() {} + + /* UART is not available for B devices, so IntB.brk() is never sitnalled */ + default async event void IntB.brk() {} + default async event void IntB.rx(uint8_t byte) {} + default async event void IntB.tx() {} + default async event void IntB.i2cCal() {} + default async event void IntB.i2cNack() {} + default async event void IntB.i2cStart() {} + default async event void IntB.i2cStop() {} +} diff --git a/tos/chips/msp430/usci/HplMsp430UsciInt1P.nc b/tos/chips/msp430/usci/HplMsp430UsciInt1P.nc new file mode 100644 index 00000000..1e18eb70 --- /dev/null +++ b/tos/chips/msp430/usci/HplMsp430UsciInt1P.nc @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * HPL interrupt interface for the USCI1 peripheral. + * + * @author R. Steve McKown + */ + +#include "Msp430Usci.h" +#include "msp430hardware.h" + +module HplMsp430UsciInt1P @safe() { + provides { + interface HplMsp430UsciInt as IntA; + interface HplMsp430UsciInt as IntB; + } +} + +implementation +{ +#if 0 + MSP430REG_NORACE(UC1IFG); + MSP430REG_NORACE(UCA1CTL0); + MSP430REG_NORACE(UCA1CTL1); + MSP430REG_NORACE(UCA1RXBUF); + MSP430REG_NORACE(UCB1CTL0); + MSP430REG_NORACE(UCB1CTL1); + MSP430REG_NORACE(UCB1RXBUF); +#endif + + /* This interrupt vector signals receive events. USCI_A1 can receive events + * for UART and SPI modes, while USCI_B1 can receive events for I2C and SPI + * modes. + */ + TOSH_SIGNAL(USCIAB1RX_VECTOR) { + if (READ_FLAG(UC1IFG & UC1IE, UCA1RXIE)) { + volatile uint8_t c = UCA1RXBUF; /* read to clear UCA1RXIFG */ + if (READ_FLAG(UCA1CTL1, UCBRK)) { + CLR_FLAG(UCA1CTL1, UCBRK); + if (READ_FLAG(UCA1CTL0, UCMODE_3) == UCMODE_3) + CLR_FLAG(UCA1CTL1, UCDORM); + signal IntA.brk(); + } else + signal IntA.rx(c); + } else if (READ_FLAG(UC1IFG & UC1IE, UCB1RXIE)) { + signal IntB.rx(UCB1RXBUF); /* read clears UCB1RXIFG */ + + /* FIXME: the arbitration of I2C interrupts are not vetted. If, for example + * the UCALIFG bit gets set and neither it nor the corresponding interrupt + * enable bit is never unset, then an ISR configured for UCSTTIFG or + * UCSTPIFG will never be signalled. + */ + + } else if (READ_FLAG(UCB1STAT, UCALIFG)) { + CLR_FLAG(UCB1STAT, UCALIFG); + signal IntB.i2cCal(); + } else if (READ_FLAG(UCB1STAT, UCNACKIFG)) { + CLR_FLAG(UCB1STAT, UCNACKIFG); + CLR_FLAG(UC1IFG, UCB1TXIFG); /* Errata USCI25; 'reset' means clear? */ + signal IntB.i2cNack(); + } else if (READ_FLAG(UCB1STAT, UCSTTIFG)) { + CLR_FLAG(UCB1STAT, UCSTTIFG); + signal IntB.i2cStart(); + } else if (READ_FLAG(UCB1STAT, UCSTPIFG)) { + CLR_FLAG(UCB1STAT, UCSTPIFG); + signal IntB.i2cStop(); + } + } + + /* This interrupt vector signals transmit events. USCI_A1 can receive events + * for UART and SPI modes, while USCI_B1 can receive events for I2C and SPI + * modes. + */ + TOSH_SIGNAL(USCIAB1TX_VECTOR) { + if (READ_FLAG(UC1IFG & UC1IE, UCB1RXIE)) + /* I2C receive. Do not read UCB1RXBUF here, as the code receiving + * IntB.rx() may first need to set stop and/or start bits. The receiver + * must read UCB1RXBUF. + */ + signal IntB.rx(0); + else if (READ_FLAG(UC1IFG & UC1IE, UCA1TXIFG)) + signal IntA.tx(); + else if (READ_FLAG(UC1IFG & UC1IE, UCB1TXIFG)) + signal IntB.tx(); + } + + default async event void IntA.brk() {} + default async event void IntA.rx(uint8_t byte) {} + default async event void IntA.tx() {} + /* i2c is not available for A devices, so the below are never signalled */ + default async event void IntA.i2cCal() {} + default async event void IntA.i2cNack() {} + default async event void IntA.i2cStart() {} + default async event void IntA.i2cStop() {} + + /* UART is not available for B devices, so IntB.brk() is never sitnalled */ + default async event void IntB.brk() {} + default async event void IntB.rx(uint8_t byte) {} + default async event void IntB.tx() {} + default async event void IntB.i2cCal() {} + default async event void IntB.i2cNack() {} + default async event void IntB.i2cStart() {} + default async event void IntB.i2cStop() {} +} diff --git a/tos/chips/msp430/usci/HplMsp430UsciReg.nc b/tos/chips/msp430/usci/HplMsp430UsciReg.nc new file mode 100644 index 00000000..b3a876fc --- /dev/null +++ b/tos/chips/msp430/usci/HplMsp430UsciReg.nc @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * HPL interface to a USCI peripheral device in UART mode. + * + * @author R. Steve McKown + */ + +#include "Msp430Usci.h" + +interface HplMsp430UsciReg { + /** + * Return the current mode. + */ + async command msp430_usci_mode_t getMode(); + + /** + * Prepare to set the mode. If the device supports the requested mode, its + * UCxxCTL1.UCSWRST bit is set and TRUE is returned. If the device does not + * support the requested mode, no operations are performed and FALSE is + * returned. + * + * @param msp430usci_mode_t The desired USCI mode. + * @return bool TRUE if the device supports the requested mode, else FALSE. + */ + async command bool setMode(msp430_usci_mode_t mode); + + /** + * Get pointer to the UCxxCTL0 register associated with the USCI device. + * + * @return The pointer to the device's UCxxCTL0 register. + */ + async command volatile uint8_t* ptrCtl0(); + + /** + * Get bits from the UCxxCTL0 register associated with the USCI device. + * + * @parm mask The bits upon which the operation is to be performed must be + * set in mask. + * @return The value of the device's UCxxCTL0 register ANDed with + * mask. + */ + async command uint8_t getCtl0(uint8_t mask); + + /** + * Set bits in the UCxxCTL0 register associated with the USCI device. + * The operation is equivalent to: UCxxCTL0 |= mask. + * + * @parm mask The bits in set in mask to set in UCxxCTL0. + */ + async command void setCtl0(uint8_t mask); + + /** + * Clear bits in the UCxxCTL0 register associated with the USCI device. + * The operation is equivalent to: UCxxCTL0 &= ~mask. + * + * @parm mask The bits in set in mask to clear in UCxxCTL0. + */ + async command void clrCtl0(uint8_t mask); + + /** + * Assign the values of the bits in value, whose corresponding bits in + * mask are set, in the UCxxCTL0 register. The operation is + * equivalent to: UCxxCTL0 = (UCxxCTL0 & ~mask) | (value & mask). + */ + //async command void assignCtl0(uint8_t mask, uint8_t value); + async command void assignCtl0(uint8_t value); + + /** + * Manipulate bits in the UCxxCTL1 register. See the methods that manipulate + * UCxxCTL0 for more information. + */ + async command volatile uint8_t* ptrCtl1(); + async command uint8_t getCtl1(uint8_t mask); + async command void setCtl1(uint8_t mask); + async command void clrCtl1(uint8_t mask); + //async command void assignCtl1(uint8_t mask, uint8_t value); + async command void assignCtl1(uint8_t value); + + /** + * Manipulate bits in the UCxxBR0 register. See the methods that manipulate + * UCxxCTL0 for more information. + */ + async command volatile uint8_t* ptrBr0(); + async command uint8_t getBr0(uint8_t mask); + async command void setBr0(uint8_t mask); + async command void clrBr0(uint8_t mask); + //async command void assignBr0(uint8_t mask, uint8_t value); + async command void assignBr0(uint8_t value); + + /** + * Manipulate bits in the UCxxBR1 register. See the methods that manipulate + * UCxxCTL0 for more information. + */ + async command volatile uint8_t* ptrBr1(); + async command uint8_t getBr1(uint8_t mask); + async command void setBr1(uint8_t mask); + async command void clrBr1(uint8_t mask); + //async command void assignBr1(uint8_t mask, uint8_t value); + async command void assignBr1(uint8_t value); + + /** + * Manipulate bits in the UCxxMCTL register. See the methods that manipulate + * UCxxCTL0 for more information. These methods perform no operation on + * providers implementing a USCI_Bx device. + */ + async command volatile uint8_t* ptrMctl(); + async command uint8_t getMctl(uint8_t mask); + async command void setMctl(uint8_t mask); + async command void clrMctl(uint8_t mask); + //async command void assignMctl(uint8_t mask, uint8_t value); + async command void assignMctl(uint8_t value); + + /** + * Manipulate bits in the UCxxI2CIE register. See the methods that + * manipulate UCxxCTL0 for more information. These methods perform no + * operation on providers implementing a USCI_Ax device. + */ + async command volatile uint8_t* ptrI2Cie(); + async command uint8_t getI2Cie(uint8_t mask); + async command void setI2Cie(uint8_t mask); + async command void clrI2Cie(uint8_t mask); + //async command void assignI2Cie(uint8_t mask, uint8_t value); + async command void assignI2Cie(uint8_t value); + + /** + * Manipulate bits in the UCxxSTAT register. See the methods that manipulate + * UCxxCTL0 for more information. + */ + async command volatile uint8_t* ptrStat(); + async command uint8_t getStat(uint8_t mask); + async command void setStat(uint8_t mask); + async command void clrStat(uint8_t mask); + //async command void assignStat(uint8_t mask, uint8_t value); + async command void assignStat(uint8_t value); + + /** + * Return pointer to the UCAxxRXBUF register used by the USCI device. + */ + async command volatile uint8_t* ptrRxbuf(); + + /** + * Read the contents of the UCAxxRXBUF register. This register cannot be + * written. + */ + async command uint8_t getRxbuf(); + + /** + * Return pointer to the UCAxxTXBUF register used by the USCI device. + */ + async command volatile uint8_t* ptrTxbuf(); + + /** + * Read the contents of the UCAxxTXBUF register. + */ + async command uint8_t getTxbuf(); + + /** + * Write a byte to the UCAxxTXBUF register. + */ + async command void setTxbuf(uint8_t byte); + + /** + * Manipulate bits in the UCxxABCTL register. See the methods that + * manipulate UCxxCTL0 for more information. These methods perform no + * operation on providers implementing a USCI_Bx device. + */ + async command volatile uint8_t* ptrAbctl(); + async command uint8_t getAbctl(uint8_t mask); + async command void setAbctl(uint8_t mask); + async command void clrAbctl(uint8_t mask); + //async command void assignAbctl(uint8_t mask, uint8_t value); + async command void assignAbctl(uint8_t value); + + /** + * Manipulate bits in the UCxxIRTCTL register. See the methods that + * manipulate UCxxCTL0 for more information. These methods perform no + * operation on providers implementing a USCI_Bx device. + */ + async command volatile uint8_t* ptrIrtctl(); + async command uint8_t getIrtctl(uint8_t mask); + async command void setIrtctl(uint8_t mask); + async command void clrIrtctl(uint8_t mask); + //async command void assignIrtctl(uint8_t mask, uint8_t value); + async command void assignIrtctl(uint8_t value); + + /** + * Manipulate bits in the UCxxIRRCTL register. See the methods that + * manipulate UCxxCTL0 for more information. These methods perform no + * operation on providers implementing a USCI_Bx device. + */ + async command volatile uint8_t* ptrIrrctl(); + async command uint8_t getIrrctl(uint8_t mask); + async command void setIrrctl(uint8_t mask); + async command void clrIrrctl(uint8_t mask); + //async command void assignIrrctl(uint8_t mask, uint8_t value); + async command void assignIrrctl(uint8_t value); + + /** + * Access to the UCBxI2COA register. + */ + async command volatile uint8_t* ptrI2Coa(); + async command uint16_t readI2Coa(); + async command void assignI2Coa(uint16_t addr); + + /** + * Access to the UCBxI2SA register. + */ + async command volatile uint8_t* ptrI2Csa(); + async command uint16_t readI2Csa(); + async command void assignI2Csa(uint16_t addr); + + /** + * Manipulate bits in the UCxxIE register. See the methods that manipulate + * UCxxCTL0 for more information. + */ + async command bool getIeRx(); + async command void setIeRx(); + async command void clrIeRx(); + async command bool getIeTx(); + async command void setIeTx(); + async command void clrIeTx(); + + /** + * Manipulate bits in the UCxxIFG register. See the methods that manipulate + * UCxxCTL0 for more information. + */ + async command bool getIfgRx(); + async command void clrIfgRx(); + async command bool getIfgTx(); + async command void clrIfgTx(); +} diff --git a/tos/chips/msp430/usci/HplMsp430UsciRegP.nc b/tos/chips/msp430/usci/HplMsp430UsciRegP.nc new file mode 100644 index 00000000..32f3de12 --- /dev/null +++ b/tos/chips/msp430/usci/HplMsp430UsciRegP.nc @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * HPL register interface to USCI peripherals. The interface abstracts the + * differences between pysical devices (aka addresses) such that a user of + * the interface can equally use any USCI device, providing the device + * provides the necessary capabilities. For example, I2C is only available + * on USCI_Bx ports. + * + * @author R. Steve McKown + */ + +#include "Msp430Usci.h" +#include "msp430hardware.h" + +generic module HplMsp430UsciRegP( + uint16_t Ctl0_addr, + uint16_t Ctl1_addr, + uint16_t Br0_addr, + uint16_t Br1_addr, + uint16_t Mctl_addr, /* A devices only */ + uint16_t I2Cie_addr, /* B devices only */ + uint16_t Stat_addr, + uint16_t Rxbuf_addr, + uint16_t Txbuf_addr, + uint16_t Abctl_addr, /* A devices only */ + uint16_t Irtctl_addr, /* A devices only */ + uint16_t Irrctl_addr, /* A devices only */ + uint16_t I2Coa_addr, /* B devices only */ + uint16_t I2Csa_addr, /* B devices only */ + uint16_t Ie_addr, + uint16_t Ifg_addr, + uint16_t UCxxRXIFG, /* We rely on xIE and xIFG at same bit positions */ + uint16_t UCxxTXIFG + ) @safe() { + provides interface HplMsp430UsciReg as Registers; +} + +implementation +{ + #define IS_USCI_Ax (Mctl_addr != 0) + #define IS_USCI_Bx (I2Cie_addr != 0) + + #define UCxxCtl0 (*TCAST(volatile uint8_t* ONE, Ctl0_addr)) + #define UCxxCtl1 (*TCAST(volatile uint8_t* ONE, Ctl1_addr)) + #define UCxxBr0 (*TCAST(volatile uint8_t* ONE, Br0_addr)) + #define UCxxBr1 (*TCAST(volatile uint8_t* ONE, Br1_addr)) + #define UCAxMctl (*TCAST(volatile uint8_t* ONE, Mctl_addr)) + #define UCBxI2Cie (*TCAST(volatile uint8_t* ONE, I2Cie_addr)) + #define UCxxStat (*TCAST(volatile uint8_t* ONE, Stat_addr)) + #define UCxxRxbuf (*TCAST(volatile uint8_t* ONE, Rxbuf_addr)) + #define UCxxTxbuf (*TCAST(volatile uint8_t* ONE, Txbuf_addr)) + #define UCAxAbctl (*TCAST(volatile uint8_t* ONE, Abctl_addr)) + #define UCAxIrtctl (*TCAST(volatile uint8_t* ONE, Irtctl_addr)) + #define UCAxIrrctl (*TCAST(volatile uint8_t* ONE, Irrctl_addr)) + #define UCBxI2Coa (*TCAST(volatile uint8_t* ONE, I2Coa_addr)) + #define UCBxI2Csa (*TCAST(volatile uint8_t* ONE, I2Csa_addr)) + #define UCxxIe (*TCAST(volatile uint8_t* ONE, Ie_addr)) + #define UCxxIfg (*TCAST(volatile uint8_t* ONE, Ifg_addr)) + +#if 0 + #define ASSIGNBITS(reg, mask, value) \ + (reg = ((reg) & ~(mask)) | ((value) & (mask))) +#endif + + #define RENDER(name) \ + async command volatile uint8_t* Registers.ptr##name() { \ + return &UCxx##name; \ + } \ + async command uint8_t Registers.get##name(uint8_t mask) { \ + return READ_FLAG(UCxx##name, mask); \ + } \ + async command void Registers.set##name(uint8_t mask) { \ + SET_FLAG(UCxx##name, mask); \ + } \ + async command void Registers.clr##name(uint8_t mask) { \ + CLR_FLAG(UCxx##name, mask); \ + } \ + async command void Registers.assign##name(uint8_t value) { \ + UCxx##name = value; \ + } + + #define RENDER_A(name) \ + async command volatile uint8_t* Registers.ptr##name() { \ + return &UCAx##name; \ + } \ + async command uint8_t Registers.get##name(uint8_t mask) { \ + if (IS_USCI_Ax) \ + return READ_FLAG(UCAx##name, mask); \ + else \ + return 0; \ + } \ + async command void Registers.set##name(uint8_t mask) { \ + if (IS_USCI_Ax) \ + SET_FLAG(UCAx##name, mask); \ + } \ + async command void Registers.clr##name(uint8_t mask) { \ + if (IS_USCI_Ax) \ + CLR_FLAG(UCAx##name, mask); \ + } \ + async command void Registers.assign##name(uint8_t value) { \ + if (IS_USCI_Ax) \ + UCAx##name = value; \ + } + + #define RENDER_B(name) \ + async command volatile uint8_t* Registers.ptr##name() { \ + return &UCBx##name; \ + } \ + async command uint8_t Registers.get##name(uint8_t mask) { \ + if (IS_USCI_Bx) \ + return READ_FLAG(UCBx##name, mask); \ + else \ + return 0; \ + } \ + async command void Registers.set##name(uint8_t mask) { \ + if (IS_USCI_Bx) \ + SET_FLAG(UCBx##name, mask); \ + } \ + async command void Registers.clr##name(uint8_t mask) { \ + if (IS_USCI_Bx) \ + CLR_FLAG(UCBx##name, mask); \ + } \ + async command void Registers.assign##name(uint8_t value) { \ + if (IS_USCI_Bx) \ + UCBx##name = value; \ + } + +#if 0 + MSP430REG_NORACE(UCxxCtl0); + MSP430REG_NORACE(UCxxCtl0); + MSP430REG_NORACE(UCxxCtl1); + MSP430REG_NORACE(UCxxBr0); + MSP430REG_NORACE(UCxxBr1); + MSP430REG_NORACE(UCAxMctl); + MSP430REG_NORACE(UCBxI2Cie); + MSP430REG_NORACE(UCxxStat); + MSP430REG_NORACE(UCxxRxbuf); + MSP430REG_NORACE(UCxxTxbuf); + MSP430REG_NORACE(UCAxAbctl); + MSP430REG_NORACE(UCAxIrtctl); + MSP430REG_NORACE(UCAxIrrctl); + MSP430REG_NORACE(UCBxI2Coa); + MSP430REG_NORACE(UCBxI2Csa); + MSP430REG_NORACE(UCxIe); + MSP430REG_NORACE(UCxIfg); +#endif + + async command msp430_usci_mode_t Registers.getMode() + { + if (READ_FLAG(UCxxCtl0, UCSYNC)) { + if (READ_FLAG(UCxxCtl0, UCMODE_3) == UCMODE_3) + return USCI_I2C; + else + return USCI_SPI; + } else { + return USCI_UART; + } + } + + /* Doesn't really set the mode, but checks the mode for the device and inits + * the device. + */ + async command bool Registers.setMode(msp430_usci_mode_t mode) + { + if (mode == USCI_UART && IS_USCI_Bx) + return FALSE; + if (mode == USCI_I2C && IS_USCI_Ax) + return FALSE; + SET_FLAG(UCxxCtl1, UCSWRST); + return TRUE; + } + + RENDER(Ctl0); + RENDER(Ctl1); + RENDER(Br0); + RENDER(Br1); + RENDER_A(Mctl); + RENDER_B(I2Cie); + RENDER(Stat); + + /* RENDER(Rxbuf); */ + async command volatile uint8_t* Registers.ptrRxbuf() + { + return &UCxxRxbuf; + } + + async command uint8_t Registers.getRxbuf() + { + return UCxxRxbuf; + } + + /* RENDER(Txbuf); */ + async command volatile uint8_t* Registers.ptrTxbuf() + { + return &UCxxTxbuf; + } + + async command uint8_t Registers.getTxbuf() + { + return UCxxTxbuf; + } + + async command void Registers.setTxbuf(uint8_t byte) + { + UCxxTxbuf = byte; + } + + RENDER_A(Abctl); + RENDER_A(Irtctl); + RENDER_A(Irrctl); + + /* RENDER_B(I2Coa); */ + async command volatile uint8_t* Registers.ptrI2Coa() + { + return &UCBxI2Coa; + } + + async command uint16_t Registers.readI2Coa() + { + return UCBxI2Coa; + } + + async command void Registers.assignI2Coa(uint16_t addr) + { + UCBxI2Coa = addr; + } + + /* RENDER_B(I2Csa); */ + async command volatile uint8_t* Registers.ptrI2Csa() + { + return &UCBxI2Csa; + } + + async command uint16_t Registers.readI2Csa() + { + return UCBxI2Csa; + } + + async command void Registers.assignI2Csa(uint16_t addr) + { + UCBxI2Csa = addr; + } + + /* RENDER(Ie); */ + async command bool Registers.getIeRx() + { + return READ_FLAG(UCxxIe, UCxxRXIFG); + } + + async command void Registers.setIeRx() + { + SET_FLAG(UCxxIe, UCxxRXIFG); + } + + async command void Registers.clrIeRx() + { + CLR_FLAG(UCxxIe, UCxxRXIFG); + } + + async command bool Registers.getIeTx() + { + return READ_FLAG(UCxxIe, UCxxTXIFG); + } + + async command void Registers.setIeTx() + { + SET_FLAG(UCxxIe, UCxxTXIFG); + } + + async command void Registers.clrIeTx() + { + CLR_FLAG(UCxxIe, UCxxTXIFG); + } + + /* RENDER(Ifg); */ + async command bool Registers.getIfgRx() + { + return READ_FLAG(UCxxIfg, UCxxRXIFG); + } + + async command void Registers.clrIfgRx() + { + CLR_FLAG(UCxxIfg, UCxxRXIFG); + } + + async command bool Registers.getIfgTx() + { + return READ_FLAG(UCxxIfg, UCxxTXIFG); + } + + async command void Registers.clrIfgTx() + { + CLR_FLAG(UCxxIfg, UCxxTXIFG); + } +} diff --git a/tos/chips/msp430/usci/Msp430I2CB0C.nc b/tos/chips/msp430/usci/Msp430I2CB0C.nc new file mode 100644 index 00000000..9b76c0f3 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430I2CB0C.nc @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This configuration provides the interface for using USCI_B0 in its I2C + * mode. + * + * @author R. Steve McKown + */ + +#if !defined(__MSP430_HAS_USCI_AB0__) +#error "Target does not have a USCI_B0 peripheral (I2C)" +#endif + +#include "I2C.h" +#include "Msp430Usci.h" + +generic configuration Msp430I2CB0C() { + provides { + interface Resource; + interface ResourceRequested; + /* interface SomethingToSetOwnAddress */ + /* interface SomethingToDenoteMode */ + interface I2CPacket as I2CBasicPacket; + interface I2CPacket as I2CExtdPacket; + interface ArbiterInfo; /* ??? */ + } + uses interface AsyncConfigure as Configure; +} +implementation { + enum { + CLIENT_ID = unique(MSP430_USCIB0_RESOURCE) + }; + + components new Msp430I2CP() as I2CP; + I2CBasicPacket = I2CP; + I2CExtdPacket = I2CP; + Configure = I2CP; + + components Msp430UsciB0C as UsciC; + Resource = UsciC.Resource[CLIENT_ID]; + ResourceRequested = UsciC.ResourceRequested[CLIENT_ID]; + ArbiterInfo = UsciC.ArbiterInfo; + I2CP -> UsciC.Registers; + I2CP -> UsciC.Interrupts[CLIENT_ID]; + I2CP -> UsciC.ArbiterInfo; + UsciC.ResourceConfigure[CLIENT_ID] -> I2CP; + + components HplMsp430GeneralIOC as IOC; + I2CP.SCL -> IOC.UCB0SCL; + I2CP.SDA -> IOC.UCB0SDA; + +#if 0 /* FIXME: no virtualized alarm for msp430 */ + comonents new SomeVirtualizedAlarmClientC() as AlarmC; + I2CP.Alarm -> AlarmC; +#endif + + components BusyWaitMicroC; + I2CP.BusyWait -> BusyWaitMicroC; + + components Msp430CounterMicroC; + I2CP.Counter -> Msp430CounterMicroC; +} diff --git a/tos/chips/msp430/usci/Msp430I2CB1C.nc b/tos/chips/msp430/usci/Msp430I2CB1C.nc new file mode 100644 index 00000000..47cab8d0 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430I2CB1C.nc @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This configuration provides the interface for using USCI_B1 in its I2C + * mode. + * + * @author R. Steve McKown + */ + +#if !defined(__MSP430_HAS_USCI_AB1__) +#error "Target does not have a USCI_B1 peripheral (I2C)" +#endif + +#include "I2C.h" +#include "Msp430Usci.h" + +generic configuration Msp430I2CB1C() { + provides { + interface Resource; + interface ResourceRequested; + /* interface SomethingToSetOwnAddress */ + /* interface SomethingToDenoteMode */ + interface I2CPacket as I2CBasicPacket; + interface I2CPacket as I2CExtdPacket; + interface ArbiterInfo; /* ??? */ + } + uses interface AsyncConfigure as Configure; +} +implementation { + enum { + CLIENT_ID = unique(MSP430_USCIB1_RESOURCE) + }; + + components new Msp430I2CP() as I2CP; + I2CBasicPacket = I2CP; + I2CExtdPacket = I2CP; + Configure = I2CP; + + components Msp430UsciB1C as UsciC; + Resource = UsciC.Resource[CLIENT_ID]; + ResourceRequested = UsciC.ResourceRequested[CLIENT_ID]; + ArbiterInfo = UsciC.ArbiterInfo; + I2CP -> UsciC.Registers; + I2CP -> UsciC.Interrupts[CLIENT_ID]; + I2CP -> UsciC.ArbiterInfo; + UsciC.ResourceConfigure[CLIENT_ID] -> I2CP; + + components HplMsp430GeneralIOC as IOC; + I2CP.SCL -> IOC.UCB1SCL; + I2CP.SDA -> IOC.UCB1SDA; + +#if 0 /* FIXME: no virtualized alarm for msp430 */ + comonents new SomeVirtualizedAlarmClientC() as AlarmC; + I2CP.Alarm -> AlarmC; +#endif + + components BusyWaitMicroC; + I2CP.BusyWait -> BusyWaitMicroC; + + components Msp430CounterMicroC; + I2CP.Counter -> Msp430CounterMicroC; +} diff --git a/tos/chips/msp430/usci/Msp430I2CP.nc b/tos/chips/msp430/usci/Msp430I2CP.nc new file mode 100644 index 00000000..8ce827d0 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430I2CP.nc @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * USCI I2C implementation. Currently supports only single master operation. + * Repeated start operations are supported, as are using multiple I2CPacket + * read or write commands to satisfy a single I2C read or write transaction. + * + * @author R. Steve McKown + */ + +generic module Msp430I2CP() { + provides { + interface I2CPacket as I2CBasicPacket; + interface I2CPacket as I2CExtdPacket; + interface ResourceConfigure; + } + uses { + interface HplMsp430UsciReg as Registers; + interface HplMsp430UsciInt as Interrupts; + interface HplMsp430GeneralIO as SDA; + interface HplMsp430GeneralIO as SCL; + interface AsyncConfigure as Configure; + interface ArbiterInfo; + interface BusyWait; + interface Counter; + } +} +implementation { + enum { + /* Activity timing */ + SCL_WAIT_TIME = 1024, /* micros */ + BUSY_CHECK_TIME = 1024, /* micros */ + START_CHECK_TIME = 102, /* micros */ + STOP_CHECK_TIME = 102, /* micros */ + + /* Setting new I2C flags is dangerous; manually ensure the bit definitions + * below do not overlap with those defined in tos/types/I2C.h. + */ + I2C_EXTENDED = 0x10, + }; + + i2c_flags_t m_flags; + uint8_t* m_buf; + uint16_t m_len; + uint16_t m_pos; + + inline void setSDA() + { + call SDA.makeInput(); + } + + inline void clrSDA() + { + call SDA.makeOutput(); + } + + inline void setSCL() + { + call SCL.makeInput(); + } + + inline void clrSCL() + { + call SCL.makeOutput(); + } + + bool idleBus() + { + /* Look for bus idle when the I2C pins are in IO mode. */ + return (call SDA.get() && call SCL.get()); + } + + bool resetBus() + { + /* When the I2C pins are in IO mode, verify the I2C bus is idle or attempt + * to get the bus into an idle state. This code is only valid if we are + * the only master on the I2C bus and is not suitable for multi-master + * setups. + * + * Return TRUE if the bus was idle or was successfully brought to idle. + * Return FALSE if the bus could not be made idle in a reasonable time. + */ + if (idleBus()) + return TRUE; + else { + uint16_t i; + + /* Wait a bit if SCL is low. A save might be clock stretching. */ + i = call Counter.get(); + while (call Counter.get() - i <= SCL_WAIT_TIME) { + if (!(call SCL.get())) + return FALSE; + } + + /* If SDA is low, clock SCL in an attempt to release it. */ + for (i = 0; i < 10 && !call SDA.get(); i++) { + clrSCL(); + call BusyWait.wait(10); + setSCL(); + call BusyWait.wait(10); + } + if (!idleBus()) + return FALSE; + + /* Drive a stop condition on the bus to stop any active slaves. */ + clrSCL(); + clrSDA(); + call BusyWait.wait(10); + setSCL(); + call BusyWait.wait(10); + setSDA(); + call BusyWait.wait(10); + return idleBus(); + } + } + + bool isConfigured() + { + return !(call Registers.getCtl1(UCSWRST)); + } + + /* TRUE if a transaction (we initiated, single master) is in progress. */ + bool isBusy() + { + return m_len; + } + + /* Wait for an I2C start, if in progress, to complete. Return FALSE if a + * start is pending and did not finish within the allotted time. Return TRUE + * if no start was pending, or it finished within the allotted time. + */ + bool waitStart() + { + uint16_t t0 = call Counter.get(); + + do { + if (!(call Registers.getCtl1(UCTXSTT))) + return TRUE; + } while (call Counter.get() - t0 <= START_CHECK_TIME); + return FALSE; + } + + /* Wait for an I2C stop, if in progress, to complete. Return FALSE if a + * stop is pending and did not finish within the allotted time. Return TRUE + * if no stop was pending, or it finished within the allotted time. + */ + bool waitStop() + { + uint16_t t0 = call Counter.get(); + + do { + if (!(call Registers.getCtl1(UCTXSTP))) + return TRUE; + } while (call Counter.get() - t0 <= STOP_CHECK_TIME); + return FALSE; + } + + async command void ResourceConfigure.configure() + { + atomic { + const msp430_usci_i2c_t* config = call Configure.get(); + + call Registers.setCtl1(UCSWRST); + + /* Several conditions might find a slave driving the bus at this point. + * One such condition is a badly timed PUC of this slave. Use resetBus() + * to attempt rectification of such conditions. + */ + if (!resetBus()) + return; + + /* Configure USCI registers. I2C requires UCMODE_3 and UCSYNC */ + call Registers.assignCtl0(config->ctl0 | UCMODE_3 | UCSYNC); + call Registers.assignCtl1(config->ctl1 | UCSWRST); + call Registers.assignBr0(config->brx & 0xff); + call Registers.assignBr1(config->brx >> 8); + call Registers.assignMctl(0); + call Registers.assignI2Coa(config->i2coa); + call Registers.assignI2Csa(0); + + /* Configure pins for I2C */ + call SDA.selectModuleFunc(); + call SCL.selectModuleFunc(); + + /* Clear interrupts; we'll add them as needed */ + call Registers.assignI2Cie(0); + call Registers.clrIeRx(); + call Registers.clrIeTx(); + + /* Enable the device */ + call Registers.clrCtl1(UCSWRST); + } + } + + void signalDone() + { + error_t error = (m_pos == m_len) ? SUCCESS : FAIL; + uint16_t len = m_len; + uint16_t addr; + + /* No more I2C interrupts until the next I2C request arrives */ + call Registers.assignI2Cie(0); + call Registers.clrIeTx(); + call Registers.clrIeRx(); + + /* Wait for stop to finish, if it is in progress. */ + if (!waitStop()) + error = FAIL; + + m_len = 0; + addr = call Registers.readI2Csa(); + switch ((call Registers.getCtl0(UCSLA10) ? 2 : 0) + /* extended addr */ + (call Registers.getCtl1(UCTR) ? 1 : 0)) { /* write */ + case 0: + atomic signal I2CBasicPacket.readDone(error, addr, len, m_buf); + break; + case 1: + atomic signal I2CBasicPacket.writeDone(error, addr, len, m_buf); + break; + case 2: + atomic signal I2CExtdPacket.readDone(error, addr, len, m_buf); + break; + case 3: + atomic signal I2CExtdPacket.writeDone(error, addr, len, m_buf); + break; + } + } + + async command void ResourceConfigure.unconfigure() + { + atomic { + /* Signal done if a pending operation */ + if (isBusy()) + signalDone(); + + /* Disable the device */ + call Registers.setCtl1(UCSWRST); + + /* Clear interrupts and interrupt flags. */ + call Registers.assignI2Cie(0); + call Registers.clrIeRx(); + call Registers.clrIfgRx(); + + /* Restore I2C pins to IO function */ + call SDA.selectIOFunc(); + call SCL.selectIOFunc(); + } + } + + error_t read(i2c_flags_t flags, uint16_t addr, uint8_t len, uint8_t* rxBuf) + { + /* From the TI family guide SDAU144D, page 17-17: + * "Data is received from the slave as long as UCTXSTP or UCTXSTT is not + * set. If UCBxRXBUF is not read the master holds the bus during reception + * of the last data bit and until the UCBxRXBUF is read." + * + * Since the I2C bus can only be suspended during read by *not* reading a + * byte out of RXBUF, the only reasonable command after a read() that + * did not include I2C_STOP is a read that does not include I2C_START. A + * read that includes I2C_START, or a write (which by definition must + * include I2C_START) will effectively create the situation where the + * prior read caused the slave to send one more byte than was delivered via + * readDone() to the user code. In many cases, this won't be a problem, as + * triggering the slave to read an extra byte will do no harm. But this + * may not always be the case, if for example the slave maintains state + * that is changed upon the read of that final byte the user code never + * sees. + */ + if (!isConfigured() || isBusy() || len == 0 || !rxBuf) + return FAIL; + + m_flags = flags; + m_len = len; + m_buf = rxBuf; + m_pos = 0; + +#if 0 /* FIXME: No virtualized alarm for msp430 */ + /* We require an alarm because we aren't looking at UCALIFG, arbitration + * lost. If this were to happen, the state machine hangs. + */ + call Alarm.start(I2C_TIMEOUT); +#endif + if (m_flags & I2C_EXTENDED) + call Registers.setCtl0(UCSLA10); + else + call Registers.clrCtl0(UCSLA10); + call Registers.assignI2Csa(addr); + call Registers.clrCtl1(UCTR); + if (m_flags & I2C_START) { + call Registers.clrIfgRx(); /* see above re: suspending reads */ + call Registers.setCtl1(UCTXSTT); + } + if (m_len == 1 && (m_flags & I2C_STOP)) { + /* UCTXSTP must assert before hw finishes clocking in the last byte. + * FIXME: in reading a single I2C trx using multiple I2C...read() calls, + * too much time spent by the user processing the readDone() can cause + * the I2C hardware to clock an extra byte's worth of clocks, thereby + * issuing 1 byte more of read with the slave, before the stop event. + */ + waitStart(); + call Registers.setCtl1(UCTXSTP); + } + call Registers.setI2Cie(UCNACKIE); + call Registers.setIeRx(); + return SUCCESS; + } + + async command error_t I2CBasicPacket.read(i2c_flags_t flags, uint16_t addr, + uint8_t length, uint8_t* data) + { + atomic return read(flags & ~I2C_EXTENDED, addr, length, data); + } + + async command error_t I2CExtdPacket.read(i2c_flags_t flags, uint16_t addr, + uint8_t length, uint8_t* data) + { + atomic return read(flags | I2C_EXTENDED, addr, length, data); + } + + error_t write(i2c_flags_t flags, uint16_t addr, uint8_t len, uint8_t* txBuf) + { + if (!isConfigured() || isBusy() || len == 0 || !txBuf) + return FAIL; + + m_flags = flags; + m_len = len; + m_buf = txBuf; + m_pos = 0; + +#if 0 /* FIXME: No virtualized alarm for msp430 */ + /* We require an alarm because we aren't looking at UCALIFG, arbitration + * lost. If this were to happen, the state machine hangs. + */ + call Alarm.start(I2C_TIMEOUT); +#endif + if (m_flags & I2C_EXTENDED) + call Registers.setCtl0(UCSLA10); + else + call Registers.clrCtl0(UCSLA10); + call Registers.assignI2Csa(addr); + call Registers.setCtl1((m_flags & I2C_START) ? UCTR + UCTXSTT : UCTR); + call Registers.setI2Cie(UCNACKIE); + call Registers.setIeTx(); + return SUCCESS; + } + + async command error_t I2CBasicPacket.write(i2c_flags_t flags, uint16_t addr, + uint8_t length, uint8_t* data) + { + atomic return write(flags & ~I2C_EXTENDED, addr, length, data); + } + + async command error_t I2CExtdPacket.write(i2c_flags_t flags, uint16_t addr, + uint8_t length, uint8_t* data) + { + atomic return write(flags | I2C_EXTENDED, addr, length, data); + } + +#if 0 /* FIXME: need a virtualized alarm for msp430 */ + event void Alarm.fired() + { + if (m_flags & I2C_STOP) { + call Registers.setCtl1(UCTXSTP); + call Registers.clrIfgTx(); + } + signalDone(); + } +#endif + + async event void Interrupts.tx() + { + if (m_pos == m_len) { + if (m_flags & I2C_STOP) { + call Registers.setCtl1(UCTXSTP); + call Registers.clrIfgTx(); + } + signalDone(); + } else + call Registers.setTxbuf(m_buf[m_pos++]); + } + + async event void Interrupts.rx(uint8_t nobyte) + { + if (m_len - m_pos == 2 && (m_flags & I2C_STOP)) { + /* As soon as we read RXBUF, the hw will begin clocking in the next byte. + * To guarantee that a slow uC can still set UCTXSTP before the last + * byte is fully clocked, we set it before the second to last byte is + * read from RXBUF, when the hw has I2C communications suspended. + */ + call Registers.setCtl1(UCTXSTP); + } + m_buf[m_pos++] = call Registers.getRxbuf(); + if (m_pos == m_len) + signalDone(); + } + + async event void Interrupts.i2cNack() + { + call Registers.setCtl1(UCTXSTP); + call Registers.clrStat(UCNACKIFG); + signalDone(); + } + + default async event void I2CBasicPacket.readDone(error_t error, uint16_t addr, + uint8_t length, uint8_t* data) {} + default async event void I2CBasicPacket.writeDone(error_t error, + uint16_t addr, uint8_t length, uint8_t* data) {} + default async event void I2CExtdPacket.readDone(error_t error, uint16_t addr, + uint8_t length, uint8_t* data) {} + default async event void I2CExtdPacket.writeDone(error_t error, uint16_t addr, + uint8_t length, uint8_t* data) {} + + default async command const msp430_usci_i2c_t* Configure.get() + { + const static msp430_usci_i2c_t def = { + ctl0: UCSYNC | UCMODE_3 | UCMST, /* I2C master */ + ctl1: UCSWRST | UCSSEL_3, /* I2C clock source is SMCLK */ + brx: 10, /* I2C clock=SMCLK/10; ~95KHz if SMCLK=2^20Hz */ + ren: USCI_REN_NONE + }; + + return &def; + } + + async event void Interrupts.i2cStart() {} + async event void Interrupts.i2cStop() {} + async event void Interrupts.i2cCal() {} + async event void Interrupts.brk() {} + async event void Counter.overflow() {} +} diff --git a/tos/chips/msp430/usci/Msp430SpiA0C.nc b/tos/chips/msp430/usci/Msp430SpiA0C.nc new file mode 100644 index 00000000..b3c284f2 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430SpiA0C.nc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This configuration provides the interface for using USCI_A0 in its SPI + * mode. + * + * The instantiator should set the blockSize, which represents the maximum + * number of bytes the underlying SPI stack will transmit or receive in a + * single interrupt service. Increasing the block size decreases SPI + * communications time at the expense of reducing system responsiveness to + * other events. + * + * The blockSize is best set by considering the maximum time the SPI stack + * should be able to delay other events. A rule of thumb formula would be: + * + * block_time = block_size / (spi_bitclock/8) + * + * For example, using a 500KHZ SPI bitclock, a block size of 64 bytes + * equates to a block time of 1 ms. Note that this calculation is rough + * because it does not take into account ISR overhead and other factors. + * + * The implementation will use a default blockSize if set to 0 here. + * + * @author R. Steve McKown + */ + +#if !defined(__MSP430_HAS_USCI_AB0__) +#error "Target does not have a USCI_A0 peripheral (SPI)" +#endif + +#include "Msp430Usci.h" + +generic configuration Msp430SpiA0C(uint16_t blockSize) { + provides { + interface Resource; + interface ResourceRequested; + interface SpiByte; + interface SpiPacket; + interface ArbiterInfo; /* ??? */ + } + uses { + interface AsyncConfigure as Configure; + interface GeneralIO as CSn; /* wire only if a SPI slave only */ + } +} +implementation { + enum { + CLIENT_ID = unique(MSP430_USCIA0_RESOURCE) + }; + + components new Msp430SpiP(blockSize) as SpiP; + SpiByte = SpiP; + SpiPacket = SpiP; + Configure = SpiP; + CSn = SpiP; + + components Msp430UsciA0C as UsciC; + Resource = UsciC.Resource[CLIENT_ID]; + ResourceRequested = UsciC.ResourceRequested[CLIENT_ID]; + ArbiterInfo = UsciC.ArbiterInfo; + SpiP -> UsciC.Registers; + SpiP -> UsciC.Interrupts[CLIENT_ID]; + SpiP -> UsciC.ArbiterInfo; + UsciC.ResourceConfigure[CLIENT_ID] -> SpiP; + + components HplMsp430GeneralIOC as IOC; + SpiP.STE -> IOC.UCA0STE; + SpiP.SIMO -> IOC.UCA0SIMO; + SpiP.SOMI -> IOC.UCA0SOMI; + SpiP.CLK -> IOC.UCA0CLK; +} diff --git a/tos/chips/msp430/usci/Msp430SpiB0C.nc b/tos/chips/msp430/usci/Msp430SpiB0C.nc new file mode 100644 index 00000000..8da9619f --- /dev/null +++ b/tos/chips/msp430/usci/Msp430SpiB0C.nc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This configuration provides the interface for using USCI_B0 in its SPI + * mode. + * + * The instantiator should set the blockSize, which represents the maximum + * number of bytes the underlying SPI stack will transmit or receive in a + * single interrupt service. Increasing the block size decreases SPI + * communications time at the expense of reducing system responsiveness to + * other events. + * + * The blockSize is best set by considering the maximum time the SPI stack + * should be able to delay other events. A rule of thumb formula would be: + * + * block_time = block_size / (spi_bitclock/8) + * + * For example, using a 500KHZ SPI bitclock, a block size of 64 bytes + * equates to a block time of 1 ms. Note that this calculation is rough + * because it does not take into account ISR overhead and other factors. + * + * The implementation will use a default blockSize if set to 0 here. + * + * @author R. Steve McKown + */ + +#if !defined(__MSP430_HAS_USCI_AB0__) +#error "Target does not have a USCI_B0 peripheral (SPI)" +#endif + +#include "Msp430Usci.h" + +generic configuration Msp430SpiB0C(uint16_t blockSize) { + provides { + interface Resource; + interface ResourceRequested; + interface SpiByte; + interface SpiPacket; + interface ArbiterInfo; /* ??? */ + } + uses { + interface AsyncConfigure as Configure; + interface GeneralIO as CSn; /* wire only if a SPI slave only */ + } +} +implementation { + enum { + CLIENT_ID = unique(MSP430_USCIB0_RESOURCE) + }; + + components new Msp430SpiP(blockSize) as SpiP; + SpiByte = SpiP; + SpiPacket = SpiP; + Configure = SpiP; + CSn = SpiP; + + components Msp430UsciB0C as UsciC; + Resource = UsciC.Resource[CLIENT_ID]; + ResourceRequested = UsciC.ResourceRequested[CLIENT_ID]; + ArbiterInfo = UsciC.ArbiterInfo; + SpiP -> UsciC.Registers; + SpiP -> UsciC.Interrupts[CLIENT_ID]; + SpiP -> UsciC.ArbiterInfo; + UsciC.ResourceConfigure[CLIENT_ID] -> SpiP; + + components HplMsp430GeneralIOC as IOC; + SpiP.STE -> IOC.UCB0STE; + SpiP.SIMO -> IOC.UCB0SIMO; + SpiP.SOMI -> IOC.UCB0SOMI; + SpiP.CLK -> IOC.UCB0CLK; +} diff --git a/tos/chips/msp430/usci/Msp430SpiB1C.nc b/tos/chips/msp430/usci/Msp430SpiB1C.nc new file mode 100644 index 00000000..f06cc414 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430SpiB1C.nc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This configuration provides the interface for using USCI_B1 in its SPI + * mode. + * + * The instantiator should set the blockSize, which represents the maximum + * number of bytes the underlying SPI stack will transmit or receive in a + * single interrupt service. Increasing the block size decreases SPI + * communications time at the expense of reducing system responsiveness to + * other events. + * + * The blockSize is best set by considering the maximum time the SPI stack + * should be able to delay other events. A rule of thumb formula would be: + * + * block_time = block_size / (spi_bitclock/8) + * + * For example, using a 500KHZ SPI bitclock, a block size of 64 bytes + * equates to a block time of 1 ms. Note that this calculation is rough + * because it does not take into account ISR overhead and other factors. + * + * The implementation will use a default blockSize if set to 0 here. + * + * @author R. Steve McKown + */ + +#if !defined(__MSP430_HAS_USCI_AB1__) +#error "Target does not have a USCI_B1 peripheral (SPI)" +#endif + +#include "Msp430Usci.h" + +generic configuration Msp430SpiB1C(uint16_t blockSize) { + provides { + interface Resource; + interface ResourceRequested; + interface SpiByte; + interface SpiPacket; + interface ArbiterInfo; /* ??? */ + } + uses { + interface AsyncConfigure as Configure; + interface GeneralIO as CSn; /* wire only if a SPI slave only */ + } +} +implementation { + enum { + CLIENT_ID = unique(MSP430_USCIB1_RESOURCE) + }; + + components new Msp430SpiP(blockSize) as SpiP; + SpiByte = SpiP; + SpiPacket = SpiP; + Configure = SpiP; + CSn = SpiP; + + components Msp430UsciB1C as UsciC; + Resource = UsciC.Resource[CLIENT_ID]; + ResourceRequested = UsciC.ResourceRequested[CLIENT_ID]; + ArbiterInfo = UsciC.ArbiterInfo; + SpiP -> UsciC.Registers; + SpiP -> UsciC.Interrupts[CLIENT_ID]; + SpiP -> UsciC.ArbiterInfo; + UsciC.ResourceConfigure[CLIENT_ID] -> SpiP; + + components HplMsp430GeneralIOC as IOC; + SpiP.STE -> IOC.UCB1STE; + SpiP.SIMO -> IOC.UCB1SIMO; + SpiP.SOMI -> IOC.UCB1SOMI; + SpiP.CLK -> IOC.UCB1CLK; +} diff --git a/tos/chips/msp430/usci/Msp430SpiP.nc b/tos/chips/msp430/usci/Msp430SpiP.nc new file mode 100644 index 00000000..93b94222 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430SpiP.nc @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Spi implementation using a USCI device. When being used as a SPI slave, the + * CSn interface should be wired to the chip select driven by the SPI master so + * the module can know when a communications session is terminated unexpectedly. + * + * TODO: Implement error checking via UCxxSTAT + * + * NOTE: Define NO_REN_ON_SPI to disable PxREN bits when SPI is acquired. + * + * @author R. Steve McKown + */ + +generic module Msp430SpiP(uint16_t blockSize) { + provides { + interface SpiByte; + interface SpiPacket; + interface ResourceConfigure; + } + uses { + interface HplMsp430UsciReg as Registers; + interface HplMsp430UsciInt as Interrupts; + interface GeneralIO as CSn; + interface HplMsp430GeneralIO as STE; + interface HplMsp430GeneralIO as SIMO; + interface HplMsp430GeneralIO as SOMI; + interface HplMsp430GeneralIO as CLK; + interface AsyncConfigure as Configure; + interface ArbiterInfo; + } +} +implementation { + enum { + BLOCKSIZE_DEFAULT = 64, + + /* Bit positions in m_pins */ + PINS_STE = 0, + PINS_SOMI, + PINS_SIMO, + PINS_CLK, +#ifdef NO_REN_ON_SPI + PINS_RENADDR, /* This gets added to store the PxREN bit */ +#endif + }; + + uint8_t m_pins; + norace uint8_t* m_txBuf; + norace uint8_t* m_rxBuf; + norace uint16_t m_len; + norace uint16_t m_pos; + + inline bool is4pin() /* TRUE if the SPI bus is in 4-pin mode */ + { + return (call Registers.getCtl0(UCMODE_3)) != UCMODE_0; + } + + inline bool isBusy() /* TRUE if a SPI transaction is in progress */ + { + atomic return m_len != 0; + } + + async command void ResourceConfigure.configure() + { + atomic { + const msp430_usci_spi_t* config = call Configure.get(); + uint8_t ctl0; + + call Registers.setCtl1(UCSWRST); + + /* UCMODE_3 is invalid for SPI. Presume the configuration data + * are wrong and force 3-pin SPI as a minimially safe alternative. + */ + ctl0 = config->ctl0 | UCSYNC; + if ((ctl0 & UCMODE_3) == UCMODE_3) + ctl0 &= ~(UCMODE_3); + + /* Configure USCI registers */ + call Registers.assignCtl0(ctl0); + call Registers.assignCtl1(config->ctl1 | UCSWRST); + call Registers.assignBr0(config->brx & 0xff); + call Registers.assignBr1(config->brx >> 8); + call Registers.assignMctl(0); + if (config->uclisten) + call Registers.setStat(UCLISTEN); + else + call Registers.clrStat(UCLISTEN); + + /* Configure pins for SPI, saving prior pin states */ + m_pins = 0; +#ifdef NO_REN_ON_SPI + /* - First save off and disable PxREN bits */ + if (is4pin() && call STE.isRen()) { + m_pins |= (1 << (PINS_STE + PINS_RENADDR)); + call STE.disableRen(); + } + if (call SOMI.isRen()) { + m_pins |= (1 << (PINS_SOMI + PINS_RENADDR)); + call SOMI.disableRen(); + } + if (call SIMO.isRen()) { + m_pins |= (1 << (PINS_SIMO + PINS_RENADDR)); + call SIMO.disableRen(); + } + if (call CLK.isRen()) { + m_pins |= (1 << (PINS_CLK + PINS_RENADDR)); + call CLK.disableRen(); + } +#endif + /* - Then save off IOFunc state and enable ModuleFunc */ + if (is4pin() && call STE.isIOFunc()) { + m_pins |= (1 << PINS_STE); + call STE.selectModuleFunc(); + } + if (call SOMI.isIOFunc()) { + m_pins |= (1 << PINS_SOMI); + call SOMI.selectModuleFunc(); + } + if (call SIMO.isIOFunc()) { + m_pins |= (1 << PINS_SIMO); + call SIMO.selectModuleFunc(); + } + if (call CLK.isIOFunc()) { + m_pins |= (1 << PINS_CLK); + call CLK.selectModuleFunc(); + } + + /* Clear interrupts; we'll add them as needed */ + call Registers.clrIeRx(); + call Registers.clrIeTx(); + + /* Enable the device */ + call Registers.clrCtl1(UCSWRST); + } + } + + task void signalSendDone() + { + error_t error = (m_pos == m_len) ? SUCCESS : FAIL; + + m_len = 0; + atomic signal SpiPacket.sendDone(m_txBuf, m_rxBuf, m_pos, error); + } + + async command void ResourceConfigure.unconfigure() + { + atomic { + /* Disable the device */ + call Registers.setCtl1(UCSWRST); + + /* Ensure SpiPacket.sendDone is posted if a trx was in progress */ + if (m_len) + post signalSendDone(); + + /* Clear interrupts and interrupt flags. We only used Rx */ + call Registers.clrIeRx(); + call Registers.clrIfgRx(); + + /* Restore pins to their pre-configure state */ + /* - First restore IOFunc states */ + if (is4pin() && (m_pins & (1 << PINS_STE))) + call STE.selectIOFunc(); + if (m_pins & (1 << PINS_SIMO)) + call SIMO.selectIOFunc(); + if (m_pins & (1 << PINS_SOMI)) + call SOMI.selectIOFunc(); + if (m_pins & (1 << PINS_CLK)) + call CLK.selectIOFunc(); + /* - Then restore PxREN bits */ +#ifdef NO_REN_ON_SPI + if (is4pin() && (m_pins & (1 << (PINS_STE + PINS_RENADDR)))) + call STE.enableRen(); + if (m_pins & (1 << (PINS_SIMO + PINS_RENADDR))) + call SIMO.enableRen(); + if (m_pins & (1 << (PINS_SOMI + PINS_RENADDR))) + call SOMI.enableRen(); + if (m_pins & (1 << (PINS_CLK + PINS_RENADDR))) + call CLK.enableRen(); +#endif + } + } + + bool waitOnRx() + { + for (;;) { + if (call Registers.getIfgRx()) + return TRUE; + if (call CSn.get()) /* SPI master has unselected us */ + return FALSE; + } + } + + bool waitOnTx() + { + for (;;) { + if (call Registers.getIfgTx()) + return TRUE; + if (call CSn.get()) /* SPI master has unselected us */ + return FALSE; + } + } + + async command uint8_t SpiByte.write(uint8_t byte) + { + atomic { + if (isBusy()) + return 0; + else { + waitOnTx(); + call Registers.setTxbuf(byte); + waitOnRx(); + return call Registers.getRxbuf(); + } + } + } + + /* If we are a slave, return FALSE if the master has unasserted CSn. */ + bool sendData() + { + atomic { + uint16_t end = m_pos + (blockSize ? blockSize : BLOCKSIZE_DEFAULT); + uint8_t tmp; + + if (end > m_len) + end = m_len; + waitOnTx(); /* Don't assume that the last tx is done already */ + call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0); + while (++m_pos < end) { + waitOnRx(); + tmp = call Registers.getRxbuf(); + if (m_rxBuf) + m_rxBuf[m_pos - 1] = tmp; + waitOnTx(); + call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0); + } + return call CSn.get() ? FALSE : TRUE; + } + } + + async command error_t SpiPacket.send(uint8_t* txBuf, uint8_t* rxBuf, + uint16_t len) + { + if (isBusy() || (!txBuf && !rxBuf) || len == 0) + return FAIL; + else { + m_txBuf = txBuf; + m_rxBuf = rxBuf; + m_len = len; + m_pos = 0; + if (sendData()) + call Registers.setIeRx(); + else + post signalSendDone(); + return SUCCESS; + } + } + + async event void Interrupts.tx() {} + + async event void Interrupts.rx(uint8_t byte) + { + if (m_rxBuf) + m_rxBuf[m_pos - 1] = byte; + + if (m_pos < m_len) { + if (sendData()) + return; + } + call Registers.clrIeRx(); + post signalSendDone(); + } + + default async event void SpiPacket.sendDone(uint8_t*, uint8_t*, uint16_t, + error_t) {} + + default async command const msp430_usci_spi_t* Configure.get() + { + const static msp430_usci_spi_t def = { + ctl0: UCSYNC | UCMODE_0 | UCMST, /* 3-pin SPI mode 0, LSB first */ + ctl1: UCSWRST | UCSSEL_3, /* SPI clock source is SMCLK */ + brx: 10, /* SPI clock=SMCLK/10; ~105KHz if SMCLK=1MHz */ + uclisten: FALSE, + ren: USCI_REN_NONE + }; + + return &def; + } + + async event void Interrupts.i2cStart() {} + async event void Interrupts.i2cStop() {} + async event void Interrupts.i2cCal() {} + async event void Interrupts.brk() {} + async event void Interrupts.i2cNack() {} + + default async command bool CSn.get() { return FALSE; } +} diff --git a/tos/chips/msp430/usci/Msp430UartA0C.nc b/tos/chips/msp430/usci/Msp430UartA0C.nc new file mode 100644 index 00000000..bbdf8a45 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UartA0C.nc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This configuration provides the interface for using USCI_A0 in its UART + * mode. + * + * @author R. Steve McKown + */ + +#if !defined(__MSP430_HAS_USCI_AB0__) +#error "Target does not have a USCI_A0 peripheral (UART)" +#endif + +#include "Msp430Usci.h" + +generic configuration Msp430UartA0C() { + provides { + interface Resource; + interface ResourceRequested; + interface UartStream; + interface UartByte; + interface ArbiterInfo; /* ??? */ + } + uses interface AsyncConfigure as Configure; +} +implementation { + enum { + CLIENT_ID = unique(MSP430_USCIA0_RESOURCE) + }; + + components new Msp430UartP() as UartP; + UartStream = UartP; + UartByte = UartP; + Configure = UartP; + + components Msp430UsciA0C as UsciC; + Resource = UsciC.Resource[CLIENT_ID]; + ResourceRequested = UsciC.ResourceRequested[CLIENT_ID]; + ArbiterInfo = UsciC.ArbiterInfo; + UartP -> UsciC.Registers; + UartP -> UsciC.Interrupts[CLIENT_ID]; + UartP -> UsciC.ArbiterInfo; + UsciC.ResourceConfigure[CLIENT_ID] -> UartP; + + components HplMsp430GeneralIOC as IOC; + UartP.RXD -> IOC.UCA0RXD; + UartP.TXD -> IOC.UCA0TXD; +} diff --git a/tos/chips/msp430/usci/Msp430UartA1C.nc b/tos/chips/msp430/usci/Msp430UartA1C.nc new file mode 100644 index 00000000..67a917c3 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UartA1C.nc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This configuration provides the interface for using USCI_A1 in its UART + * mode. + * + * @author R. Steve McKown + */ + +#if !defined(__MSP430_HAS_USCI_AB0__) +#error "Target does not have a USCI_A1 peripheral (UART)" +#endif + +#include "Msp430Usci.h" + +generic configuration Msp430UartA1C() { + provides { + interface Resource; + interface ResourceRequested; + interface UartStream; + interface UartByte; + interface ArbiterInfo; /* ??? */ + } + uses interface AsyncConfigure as Configure; +} +implementation { + enum { + CLIENT_ID = unique(MSP430_USCIA1_RESOURCE) + }; + + components new Msp430UartP() as UartP; + UartStream = UartP; + UartByte = UartP; + Configure = UartP; + + components Msp430UsciA1C as UsciC; + Resource = UsciC.Resource[CLIENT_ID]; + ResourceRequested = UsciC.ResourceRequested[CLIENT_ID]; + ArbiterInfo = UsciC.ArbiterInfo; + UartP -> UsciC.Registers; + UartP -> UsciC.Interrupts[CLIENT_ID]; + UartP -> UsciC.ArbiterInfo; + UsciC.ResourceConfigure[CLIENT_ID] -> UartP; + + components HplMsp430GeneralIOC as IOC; + UartP.RXD -> IOC.UCA1RXD; + UartP.TXD -> IOC.UCA1TXD; +} diff --git a/tos/chips/msp430/usci/Msp430UartP.nc b/tos/chips/msp430/usci/Msp430UartP.nc new file mode 100644 index 00000000..4821f7b6 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UartP.nc @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Uart implementation using a USCI device. + * + * TODO: Implement blocking like in Msp430UartSpiP.nc. + * Implement error checking via UCAxSTAT. + * + * @author R. Steve McKown + */ + +generic module Msp430UartP() { + provides { + interface UartStream; + interface UartByte; + interface ResourceConfigure; + } + uses { + interface HplMsp430UsciReg as Registers; + interface HplMsp430UsciInt as Interrupts; + interface HplMsp430GeneralIO as RXD; + interface HplMsp430GeneralIO as TXD; + interface AsyncConfigure as Configure; + interface Counter; + interface ArbiterInfo; + } +} +implementation { + enum { + /* Bit positions in m_pins */ + PINS_RXD = 0, + PINS_TXD + }; + + uint8_t m_pins; + uint8_t* m_sobuf; /* Original buffer ptr from UartStream.send() */ + uint16_t m_solen; /* Original buffer len from UartStream.send() */ + uint8_t* m_sbuf; /* Position of next char to send */ + uint16_t m_slen; /* Len of chars in m_sbuf to send */ + bool m_rxie; /* Set if rxie has been enabled to UartStream.receive() */ + uint8_t* m_robuf; /* Original receive buffer */ + uint16_t m_rolen; /* Original (maximum) receive len */ + uint8_t* m_rbuf; /* Position of next byte in which to receive a char */ + uint16_t m_rlen; /* Remaining length in receive buffer */ + + sfrb(MYBRX, 219U); + + async command void ResourceConfigure.configure() + { + atomic { + const msp430_usci_uart_t* config = call Configure.get(); + + call Registers.setCtl1(UCSWRST); + + /* Configure USCI registers */ + call Registers.assignCtl0(config->ctl0 & ~UCSYNC); + call Registers.assignCtl1(config->ctl1 | UCSWRST); + call Registers.assignBr0(config->brx & 0xff); + call Registers.assignBr1(config->brx >> 8); + call Registers.assignMctl(config->mctl); + call Registers.assignIrtctl(config->irtctl); + call Registers.assignIrrctl(config->irrctl); + call Registers.assignAbctl(config->abctl); + if (config->uclisten) + call Registers.setStat(UCLISTEN); + else + call Registers.clrStat(UCLISTEN); + + /* Configure pins for UART, saving prior pin states */ + m_pins = 0; + if (call RXD.isIOFunc()) { + m_pins |= (1 << PINS_RXD); + call RXD.selectModuleFunc(); + } + if (call TXD.isIOFunc()) { + m_pins |= (1 << PINS_TXD); + call TXD.selectModuleFunc(); + } + + /* Reset important state variables */ + m_robuf = 0; + m_sobuf = 0; + + /* Clear interrupts; we'll add them as needed */ + call Registers.clrIeRx(); + call Registers.clrIeTx(); + + /* Enable the device */ + call Registers.clrCtl1(UCSWRST); + + /* TOS convention is for receive interrupts on by default. */ + call Registers.clrIfgRx(); + call Registers.setIeRx(); + } + } + + async command void ResourceConfigure.unconfigure() + { + atomic { + /* Disable the device */ + call Registers.setCtl1(UCSWRST); + + /* Clear interrupts and interrupt flags */ + call Registers.clrIeRx(); + call Registers.clrIeTx(); + call Registers.clrIfgRx(); + + /* Reset important state variables */ + m_robuf = 0; + m_sobuf = 0; + + /* Restore pins to their pre-configure state */ + if (m_pins & (1 << PINS_RXD)) + call RXD.selectIOFunc(); + if (m_pins & (1 << PINS_TXD)) + call TXD.selectIOFunc(); + } + } + + async command error_t UartByte.send(uint8_t byte) + { + atomic { + while (!call Registers.getIfgTx()); + call Registers.setTxbuf(byte); + return SUCCESS; + } + } + + async command error_t UartStream.send(uint8_t* buf, uint16_t len) + { + atomic { + if (m_sobuf || !buf || !len) + return FAIL; + m_sbuf = m_sobuf = buf; + m_slen = m_solen = len; + call Registers.setIeTx(); + return SUCCESS; + } + } + + async event void Interrupts.tx() + { + /* FIXME: this can cause an arbitrarily long ISR, if m_slen is large. + * But depending on timing, we may always only write 1 byte. + */ + if (m_sobuf) { + while (!call Registers.getIfgTx()); /* in case interleaved UB.send */ + while (m_slen && call Registers.getIfgTx()) { + call Registers.setTxbuf(*m_sbuf); + if (--m_slen) + m_sbuf++; + } + if (m_slen == 0) { + call Registers.clrIeTx(); + m_sobuf = 0; + signal UartStream.sendDone(m_sobuf, m_solen, SUCCESS); + } + } + } + + async command error_t UartStream.enableReceiveInterrupt() + { + atomic { + if (!m_robuf) + call Registers.clrIfgRx(); + call Registers.setIeRx(); + m_rxie = FALSE; + return SUCCESS; + } + } + + async command error_t UartStream.disableReceiveInterrupt() + { + atomic { + if (!m_robuf) { + call Registers.clrIeRx(); + call Registers.clrIfgRx(); + } else + m_rxie = TRUE; + return SUCCESS; + } + } + + async command error_t UartByte.receive(uint8_t* byte, uint8_t timeout) + { + atomic { + uint16_t t; + + /* FIXME: race with UartStream.receive() */ + if (m_robuf || !byte) + return FAIL; + /* TODO: implement timeout, byte-time units. For now, 1-2 sec */ + t = TBR; + while (t < TBR) { + if (call Registers.getIfgRx()) { + *byte = call Registers.getRxbuf(); + return SUCCESS; + } + } + return FAIL; + } + } + + async command error_t UartStream.receive(uint8_t* buf, uint16_t len) + { + atomic { + if (m_robuf || !buf || !len) + return FAIL; + m_robuf = m_rbuf = buf; + m_rolen = m_rlen = len; + if (!call Registers.getIeRx()) { + call Registers.clrIfgRx(); + call Registers.setIeRx(); + m_rxie = TRUE; + } else + m_rxie = FALSE; + } + } + + async event void Interrupts.rx(uint8_t byte) + { + if (m_robuf) { + /* receive() takes precedence if active */ + /* FIXME: an arbitrarily long ISR may occur if m_rlen is large. + * But depending on timing, we may always only read 1 byte. + */ + while (m_rlen && call Registers.getIfgRx()) { + *m_rbuf = byte; + if (--m_rlen) + m_rbuf++; + } + if (m_rlen == 0 && m_robuf) { + if (m_rxie) { + call Registers.clrIeRx(); + call Registers.clrIfgRx(); + } + m_robuf = 0; + signal UartStream.receiveDone(m_robuf, m_rolen, SUCCESS); + } + } else + signal UartStream.receivedByte(byte); + } + + default async command const msp430_usci_uart_t* Configure.get() + { + const static msp430_usci_uart_t def = { + ctl0: UCMODE_0, /* async, lsb first, 8N1 */ + ctl1: UCSWRST | UCSSEL_3, /* clock uart from SMCLK */ + brx: UBRX_1MHZ_115200, + mctl: UMCTL_1MHZ_115200, + irtctl: 0, + irrctl: 0, + abctl: 0, + uclisten: FALSE, + ren: USCI_REN_NONE + }; + + return &def; + } + + async event void Interrupts.i2cStart() {} + async event void Interrupts.i2cStop() {} + async event void Interrupts.i2cCal() {} + async event void Interrupts.brk() {} + async event void Interrupts.i2cNack() {} + async event void Counter.overflow() {} + + default async event void UartStream.sendDone( uint8_t* buf, uint16_t len, + error_t error ) {} + default async event void UartStream.receivedByte( uint8_t byte ) {} + default async event void UartStream.receiveDone( uint8_t* buf, uint16_t len, + error_t error ) {} +} diff --git a/tos/chips/msp430/usci/Msp430Usci.h b/tos/chips/msp430/usci/Msp430Usci.h new file mode 100644 index 00000000..575889d1 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430Usci.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Header definitions for the USCI peripheral in newer msp430 processors. + * A USCI peripheral provides two communications devices, denoted A and B. + * Many parts have 2 USCI peripherals, denoted by 0 and 1. Therefore, a + * part with 2 USCI peripherals has 4 communications devices: + * + * USCI_A0 and USCI_B0, from the first USCI peripheral; and + * USCI_A1 and USCI_B1, from the second USCI peripheral. + * + * A devices offer UART, LIN, IrDA and SPI modes of operation. B parts are + * limited to SPI and I2C modes. + * + * @author R. Steve McKown + */ + +#ifndef MSP430_USCI_h +#define MSP430_USCI_h + +#define MSP430_USCIA0_RESOURCE "Msp430UsciA0.Resource" +#define MSP430_USCIB0_RESOURCE "Msp430UsciB0.Resource" +#define MSP430_USCIA1_RESOURCE "Msp430UsciA1.Resource" +#define MSP430_USCIB1_RESOURCE "Msp430UsciB1.Resource" + +typedef enum +{ + USCI_UART = 0, + USCI_SPI, + USCI_I2C +} msp430_usci_mode_t; + +typedef enum { + USCI_REN_NONE = 0, + + /* For use in UART mode */ + USCI_REN_TX = 0x03, + USCI_REN_TX_PULLUP = 0x01, + USCI_REN_TX_PULLDOWN = 0x02, + USCI_REN_RX = 0x0c, + USCI_REN_RX_PULLUP = 0x04, + USCI_REN_RX_PULLDOWN = 0x08, + + /* For use in SPI mode */ + USCI_REN_STE = 0x30, + USCI_REN_STE_PULLUP = 0x10, + USCI_REN_STE_PULLDOWN = 0x20, + USCI_REN_SIMO = USCI_REN_TX, + USCI_REN_SIMO_PULLUP = USCI_REN_TX_PULLUP, + USCI_REN_SIMO_PULLDOWN = USCI_REN_TX_PULLDOWN, + USCI_REN_SOMI = USCI_REN_RX, + USCI_REN_SOMI_PULLUP = USCI_REN_RX_PULLUP, + USCI_REN_SOMI_PULLDOWN = USCI_REN_RX_PULLDOWN, + USCI_REN_CLK = 0xc0, + USCI_REN_CLK_PULLUP = 0x40, + USCI_REN_CLK_PULLDOWN = 0x80, + + /* For use in I2C mode */ + USCI_REN_SDA = USCI_REN_TX, + USCI_REN_SDA_PULLUP = USCI_REN_TX_PULLUP, + USCI_REN_SDA_PULLDOWN = USCI_REN_TX_PULLDOWN, + USCI_REN_SCL = USCI_REN_RX, + USCI_REN_SCL_PULLUP = USCI_REN_RX_PULLUP, + USCI_REN_SCL_PULLDOWN = USCI_REN_RX_PULLDOWN +} msp430_ren_t; + +/* Baud rates for UART mode. Only 32KHz modes work right now. */ +typedef enum { + /* UCOS16=0. UMCTL = UCBRFx << 4 + UCBRSx << 1 + UCOS16. + * 1MHZ = 1,048576HZ, 1E6MHZ = 1,000,000HZ. + */ + UBRX_32768HZ_9600=3, UMCTL_32768HZ_9600=(0 << 4) + (3 << 1) + 0, + UBRX_1MHZ_9600=109, UMCTL_1MHZ_9600=(0 << 4) + (2 << 1) + 0, + UBRX_1MHZ_19200=54, UMCTL_1MHZ_19200=(0 << 4) + (5 << 1) + 0, + UBRX_1MHZ_38400=27, UMCTL_1MHZ_38400=(0 << 4) + (2 << 1) + 0, + UBRX_1MHZ_115200=9, UMCTL_1MHZ_115200=(0 << 4) + (1 << 1) + 0, + UBRX_1E6HZ_9600=104, UMCTL_1E6HZ_9600=(0 << 4) + (1 << 1) + 0, + UBRX_1E6HZ_19200=52, UMCTL_1E6HZ_19200=(0 << 4) + (0 << 1) + 0, + UBRX_1E6HZ_115200=8, UMCTL_1E6HZ_115200=(0 << 4) + (6 << 1) + 0, +} msp430_usci_uart_rate_t; + +typedef struct { + uint8_t ctl0; + uint8_t ctl1; + uint16_t brx; + uint8_t mctl; + uint8_t irtctl; + uint8_t irrctl; + uint8_t abctl; + bool uclisten; + msp430_ren_t ren; +} msp430_usci_uart_t; + +typedef struct { + uint8_t ctl0; + uint8_t ctl1; + uint16_t brx; + bool uclisten; + msp430_ren_t ren; +} msp430_usci_spi_t; + +typedef struct { + uint8_t ctl0; + uint8_t ctl1; + uint16_t brx; + uint8_t i2coa; + msp430_ren_t ren; +} msp430_usci_i2c_t; + +#endif diff --git a/tos/chips/msp430/usci/Msp430UsciA0C.nc b/tos/chips/msp430/usci/Msp430UsciA0C.nc new file mode 100644 index 00000000..cf4ee6ee --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UsciA0C.nc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Defines the USCI_A0 peripheral. + * + * @author R. Steve McKown + */ + +configuration Msp430UsciA0C { + provides { + interface HplMsp430UsciReg as Registers; + interface HplMsp430UsciInt as Interrupts[uint8_t]; + interface Resource as Resource[uint8_t]; + interface ResourceRequested as ResourceRequested[uint8_t]; + interface ArbiterInfo; + } + uses interface ResourceConfigure as ResourceConfigure[uint8_t]; +} +implementation { + components new FcfsArbiterC(MSP430_USCIA0_RESOURCE) as ArbiterC; + Resource = ArbiterC; + ResourceRequested = ArbiterC; + ResourceConfigure = ArbiterC; + ArbiterInfo = ArbiterC; + + components new Msp430UsciIntDispatchP() as IntDispatchA0P; + Interrupts = IntDispatchA0P; + IntDispatchA0P.ArbiterInfo -> ArbiterC; + + components HplMsp430UsciC as UsciC; + Registers = UsciC.RegA0; + IntDispatchA0P.RawInt -> UsciC.IntA0; +} diff --git a/tos/chips/msp430/usci/Msp430UsciA1C.nc b/tos/chips/msp430/usci/Msp430UsciA1C.nc new file mode 100644 index 00000000..800300d3 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UsciA1C.nc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Defines the USCI_A1 peripheral. + * + * @author R. Steve McKown + */ + +configuration Msp430UsciA1C { + provides { + interface HplMsp430UsciReg as Registers; + interface HplMsp430UsciInt as Interrupts[uint8_t]; + interface Resource as Resource[uint8_t]; + interface ResourceRequested as ResourceRequested[uint8_t]; + interface ArbiterInfo; + } + uses interface ResourceConfigure as ResourceConfigure[uint8_t]; +} +implementation { + components new FcfsArbiterC(MSP430_USCIA1_RESOURCE) as ArbiterC; + Resource = ArbiterC; + ResourceRequested = ArbiterC; + ResourceConfigure = ArbiterC; + ArbiterInfo = ArbiterC; + + components new Msp430UsciIntDispatchP() as IntDispatchA1P; + Interrupts = IntDispatchA1P; + IntDispatchA1P.ArbiterInfo -> ArbiterC; + + components HplMsp430UsciC as UsciC; + Registers = UsciC.RegA1; + IntDispatchA1P.RawInt -> UsciC.IntA1; +} diff --git a/tos/chips/msp430/usci/Msp430UsciB0C.nc b/tos/chips/msp430/usci/Msp430UsciB0C.nc new file mode 100644 index 00000000..12f821ef --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UsciB0C.nc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Defines the USCI_B0 peripheral. + * + * @author R. Steve McKown + */ + +configuration Msp430UsciB0C { + provides { + interface HplMsp430UsciReg as Registers; + interface HplMsp430UsciInt as Interrupts[uint8_t]; + interface Resource as Resource[uint8_t]; + interface ResourceRequested as ResourceRequested[uint8_t]; + interface ArbiterInfo; + } + uses interface ResourceConfigure as ResourceConfigure[uint8_t]; +} +implementation { + components new FcfsArbiterC(MSP430_USCIB0_RESOURCE) as ArbiterC; + Resource = ArbiterC; + ResourceRequested = ArbiterC; + ResourceConfigure = ArbiterC; + ArbiterInfo = ArbiterC; + + components new Msp430UsciIntDispatchP() as IntDispatchB0P; + Interrupts = IntDispatchB0P; + IntDispatchB0P.ArbiterInfo -> ArbiterC; + + components HplMsp430UsciC as UsciC; + Registers = UsciC.RegB0; + IntDispatchB0P.RawInt -> UsciC.IntB0; +} diff --git a/tos/chips/msp430/usci/Msp430UsciB1C.nc b/tos/chips/msp430/usci/Msp430UsciB1C.nc new file mode 100644 index 00000000..81b5e607 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UsciB1C.nc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Defines the USCI_B1 peripheral. + * + * @author R. Steve McKown + */ + +configuration Msp430UsciB1C { + provides { + interface HplMsp430UsciReg as Registers; + interface HplMsp430UsciInt as Interrupts[uint8_t]; + interface Resource as Resource[uint8_t]; + interface ResourceRequested as ResourceRequested[uint8_t]; + interface ArbiterInfo; + } + uses interface ResourceConfigure as ResourceConfigure[uint8_t]; +} +implementation { + components new FcfsArbiterC(MSP430_USCIB1_RESOURCE) as ArbiterC; + Resource = ArbiterC; + ResourceRequested = ArbiterC; + ResourceConfigure = ArbiterC; + ArbiterInfo = ArbiterC; + + components new Msp430UsciIntDispatchP() as IntDispatchB1P; + Interrupts = IntDispatchB1P; + IntDispatchB1P.ArbiterInfo -> ArbiterC; + + components HplMsp430UsciC as UsciC; + Registers = UsciC.RegB1; + IntDispatchB1P.RawInt -> UsciC.IntB1; +} diff --git a/tos/chips/msp430/usci/Msp430UsciIntDispatchP.nc b/tos/chips/msp430/usci/Msp430UsciIntDispatchP.nc new file mode 100644 index 00000000..2312f6c6 --- /dev/null +++ b/tos/chips/msp430/usci/Msp430UsciIntDispatchP.nc @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2008, Titanium Mirror, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the Technische Universität Berlin nor the names + * of its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Interrupt dispatch for USCI_Ax and USCI_Bx devices. + * + * @author R. Steve McKown + */ + +generic module Msp430UsciIntDispatchP() @safe() { + provides interface HplMsp430UsciInt as Interrupts[uint8_t id]; + uses { + interface HplMsp430UsciInt as RawInt; + interface ArbiterInfo; + } +} + +implementation { + async event void RawInt.brk() + { + if (call ArbiterInfo.inUse()) + signal Interrupts.brk[call ArbiterInfo.userId()](); + } + + async event void RawInt.rx(uint8_t byte) + { + if (call ArbiterInfo.inUse()) + signal Interrupts.rx[call ArbiterInfo.userId()](byte); + } + + async event void RawInt.tx() + { + if (call ArbiterInfo.inUse()) + signal Interrupts.tx[call ArbiterInfo.userId()](); + } + + async event void RawInt.i2cCal() + { + if (call ArbiterInfo.inUse()) + signal Interrupts.i2cCal[call ArbiterInfo.userId()](); + } + + async event void RawInt.i2cNack() + { + if (call ArbiterInfo.inUse()) + signal Interrupts.i2cNack[call ArbiterInfo.userId()](); + } + + async event void RawInt.i2cStart() + { + if (call ArbiterInfo.inUse()) + signal Interrupts.i2cStart[call ArbiterInfo.userId()](); + } + + async event void RawInt.i2cStop() + { + if (call ArbiterInfo.inUse()) + signal Interrupts.i2cStop[call ArbiterInfo.userId()](); + } + + default async event void Interrupts.brk[uint8_t id]() {} + default async event void Interrupts.rx[uint8_t id](uint8_t byte) {} + default async event void Interrupts.tx[uint8_t id]() {} + default async event void Interrupts.i2cCal[uint8_t id]() {} + default async event void Interrupts.i2cNack[uint8_t id]() {} + default async event void Interrupts.i2cStart[uint8_t id]() {} + default async event void Interrupts.i2cStop[uint8_t id]() {} +}