X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=tos%2Fchips%2Fmsp430%2Fusci%2FMsp430SpiP.nc;h=0aaf9bd34c06c17784a526fa9c4d1aa7675d8537;hb=5592947363b1fa4dc67880c1d12d83866a49ddb9;hp=eb217b3f92068e3cc76d2f0f4999bfe87d534359;hpb=c1accd0c73c0dc3314b9de1dd1fefa643b45962e;p=tinyos-2.x.git diff --git a/tos/chips/msp430/usci/Msp430SpiP.nc b/tos/chips/msp430/usci/Msp430SpiP.nc index eb217b3f..0aaf9bd3 100644 --- a/tos/chips/msp430/usci/Msp430SpiP.nc +++ b/tos/chips/msp430/usci/Msp430SpiP.nc @@ -28,10 +28,14 @@ */ /** - * Spi implementation using a USCI device. + * 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 */ @@ -44,6 +48,7 @@ generic module Msp430SpiP(uint16_t blockSize) { 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; @@ -57,10 +62,13 @@ implementation { BLOCKSIZE_DEFAULT = 64, /* Bit positions in m_pins */ - PINS_STE = 1, + 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; @@ -69,12 +77,12 @@ implementation { uint16_t m_len; uint16_t m_pos; - inline bool is4pin() /* true if the SPI bus is in 4-pin mode */ + 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 */ + inline bool isBusy() /* TRUE if a SPI transaction is in progress */ { atomic return m_len != 0; } @@ -107,6 +115,26 @@ implementation { /* 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(); @@ -133,17 +161,31 @@ implementation { } } + task void signalSendDone() + { + atomic { + uint16_t len = m_len; + m_len = 0; + signal SpiPacket.sendDone(m_txBuf, m_rxBuf, len, SUCCESS); + } + } + 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)) @@ -152,6 +194,37 @@ implementation { 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; } } @@ -160,35 +233,32 @@ implementation { if (isBusy()) return 0; else { - while (!call Registers.getIfgTx() && !call Registers.getCtl1(UCSWRST)); + waitOnTx(); call Registers.setTxbuf(byte); - while(!call Registers.getIfgRx() && !call Registers.getCtl1(UCSWRST)); + waitOnRx(); return call Registers.getRxbuf(); } } - void sendData() + /* Return FALSE if we are in reset, so callers can clean up as appropriate. */ + bool sendData() { - /* We don't need to check Registers.getIfgTx() (aks UCxxTXIFG), as - * sendData() is only called after peripheral init or receipt of the rx() - * interrupt. SPI on msp430 guarantees UCxxTXIFG is asserted in both of - * these cases. - */ atomic { uint16_t end = m_pos + (blockSize ? blockSize : BLOCKSIZE_DEFAULT); uint8_t tmp; if (end > m_len) end = m_len; - call Registers.setTxbuf((m_txBuf) ? m_txBuf[m_pos] : 0); + call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0); while (++m_pos < end) { - while (!call Registers.getIfgRx()); + waitOnRx(); + tmp = call Registers.getRxbuf(); if (m_rxBuf) - m_rxBuf[m_pos - 1] = call Registers.getRxbuf(); - else - tmp = call Registers.getRxbuf(); - call Registers.setTxbuf((m_txBuf) ? m_txBuf[m_pos] : 0); + m_rxBuf[m_pos - 1] = tmp; + waitOnTx(); + call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0); } + return call CSn.get() ? FALSE : TRUE; } } @@ -203,36 +273,30 @@ implementation { m_rxBuf = rxBuf; m_len = len; m_pos = 0; - call Registers.setIeRx(); - sendData(); - return SUCCESS; + if (sendData()) { + call Registers.setIeRx(); + return SUCCESS; + } else { + m_len = 0; + return FAIL; + } } } } async event void Interrupts.tx() {} - task void signalSendDone() - { - atomic { - m_len = 0; - signal SpiPacket.sendDone(m_txBuf, m_rxBuf, m_len, SUCCESS); - } - } - async event void Interrupts.rx(uint8_t byte) { if (m_rxBuf) - m_rxBuf[m_pos - 1] = call Registers.getRxbuf(); - else - call Registers.getRxbuf(); + m_rxBuf[m_pos - 1] = byte; - if (m_pos < m_len) - sendData(); - else { - call Registers.clrIeRx(); - post signalSendDone(); /* Don't signal from ISR context */ + if (m_pos < m_len) { + if (sendData()) + return; } + call Registers.clrIeRx(); + post signalSendDone(); /* Don't signal from ISR context */ } default async event void SpiPacket.sendDone(uint8_t*, uint8_t*, uint16_t, @@ -256,4 +320,6 @@ implementation { async event void Interrupts.i2cCal() {} async event void Interrupts.brk() {} async event void Interrupts.i2cNak() {} + + default async command bool CSn.get() { return FALSE; } }