* - 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
+ * - Neither the name of the Titanium Mirror, Inc. nor the names
* of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* (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.
+ * 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
*
*
* @author R. Steve McKown <rsmckown@gmail.com>
*/
-
+
generic module Msp430SpiP(uint16_t blockSize) {
provides {
interface SpiByte;
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;
};
uint8_t m_pins;
- uint8_t* m_txBuf;
- uint8_t* m_rxBuf;
- uint16_t m_len;
- uint16_t m_pos;
+ 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 */
+ 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;
}
task void signalSendDone()
{
- atomic {
- uint16_t len = m_len;
- m_len = 0;
- signal SpiPacket.sendDone(m_txBuf, m_rxBuf, len, SUCCESS);
- }
+ 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()
}
}
- async command uint8_t SpiByte.write(uint8_t byte)
+ bool waitOnRx()
{
- if (isBusy())
- return 0;
- else {
- while (!call Registers.getIfgTx() && !call Registers.getCtl1(UCSWRST));
- call Registers.setTxbuf(byte);
- while(!call Registers.getIfgRx() && !call Registers.getCtl1(UCSWRST));
- return call Registers.getRxbuf();
+ for (;;) {
+ if (call Registers.getIfgRx())
+ return TRUE;
+ if (call CSn.get()) /* SPI master has unselected us */
+ return FALSE;
}
}
- bool waitOnRx()
+ bool waitOnTx()
{
- if (call Registers.getCtl0(UCMST)) {
- while (!call Registers.getIfgRx() && !call Registers.getCtl1(UCSWRST));
- return TRUE;
- } else {
- /* If SPI slave, the host could quit clocking any time, so we need a
- * timeout.
- */
- unsigned i = 0;
-
- while (++i) {
- if (call Registers.getIfgRx())
- return TRUE;
- if (call Registers.getCtl1(UCSWRST))
- return FALSE;
- }
- return FALSE;
+ for (;;) {
+ if (call Registers.getIfgTx())
+ return TRUE;
+ if (call CSn.get()) /* SPI master has unselected us */
+ return FALSE;
}
}
- bool waitOnTx()
+ async command uint8_t SpiByte.write(uint8_t byte)
{
- if (call Registers.getCtl0(UCMST)) {
- while (!call Registers.getIfgTx() && !call Registers.getCtl1(UCSWRST));
- return TRUE;
- } else {
- /* If SPI slave, the host could quit clocking any time, so we need a
- * timeout.
- */
- unsigned i = 0;
-
- while (++i) {
- if (call Registers.getIfgTx())
- return TRUE;
- if (call Registers.getCtl1(UCSWRST))
- return FALSE;
+ atomic {
+ if (isBusy())
+ return 0;
+ else {
+ waitOnTx();
+ call Registers.setTxbuf(byte);
+ waitOnRx();
+ return call Registers.getRxbuf();
}
- return FALSE;
}
}
- /* Return FALSE if we are in reset, so callers can clean up as appropriate. */
+ /* If we are a slave, return FALSE if the master has unasserted CSn. */
bool sendData()
{
atomic {
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();
waitOnTx();
call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0);
}
- return call Registers.getCtl1(UCSWRST) ? FALSE : TRUE;
+ return call CSn.get() ? FALSE : TRUE;
}
}
if (isBusy() || (!txBuf && !rxBuf) || len == 0)
return FAIL;
else {
- atomic {
- m_txBuf = txBuf;
- m_rxBuf = rxBuf;
- m_len = len;
- m_pos = 0;
- if (sendData()) {
- call Registers.setIeRx();
- return SUCCESS;
- } else {
- m_len = 0;
- return FAIL;
- }
- }
+ m_txBuf = txBuf;
+ m_rxBuf = rxBuf;
+ m_len = len;
+ m_pos = 0;
+ if (sendData())
+ call Registers.setIeRx();
+ else
+ post signalSendDone();
+ return SUCCESS;
}
}
return;
}
call Registers.clrIeRx();
- post signalSendDone(); /* Don't signal from ISR context */
+ post signalSendDone();
}
default async event void SpiPacket.sendDone(uint8_t*, uint8_t*, uint16_t,
default async command const msp430_usci_spi_t* Configure.get()
{
- const static msp430_usci_spi_t def = {
+ 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 */
async event void Interrupts.i2cStop() {}
async event void Interrupts.i2cCal() {}
async event void Interrupts.brk() {}
- async event void Interrupts.i2cNak() {}
+ async event void Interrupts.i2cNack() {}
+
+ default async command bool CSn.get() { return FALSE; }
}