]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/msp430/usci/Msp430SpiP.nc
Implement chip select query for SPI peripheral.
[tinyos-2.x.git] / tos / chips / msp430 / usci / Msp430SpiP.nc
index dad8e824bd420bf37f8f2c511e83ae57d603714a..0aaf9bd34c06c17784a526fa9c4d1aa7675d8537 100644 (file)
@@ -28,7 +28,9 @@
  */
  
 /**
- * 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
  *
@@ -46,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;
@@ -74,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;
   }
@@ -158,12 +161,25 @@ 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();
@@ -192,25 +208,41 @@ implementation {
     }
   }
 
+  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)
   {
     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;
@@ -219,13 +251,14 @@ implementation {
        end = m_len;
       call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0);
       while (++m_pos < end) {
-       while (!call Registers.getIfgRx() && !call Registers.getCtl1(UCSWRST));
+       waitOnRx();
        tmp = call Registers.getRxbuf();
        if (m_rxBuf)
-         m_rxBuf[m_pos - 1] = call Registers.getRxbuf();
-       while (!call Registers.getIfgTx() && !call Registers.getCtl1(UCSWRST));
+         m_rxBuf[m_pos - 1] = tmp;
+       waitOnTx();
        call Registers.setTxbuf(m_txBuf ? m_txBuf[m_pos] : 0);
       }
+      return call CSn.get() ? FALSE : TRUE;
     }
   }
 
@@ -240,35 +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 {
-      uint16_t len = m_len;
-      m_len = 0;
-      signal SpiPacket.sendDone(m_txBuf, m_rxBuf, len, SUCCESS);
-    }
-  }
-
   async event void Interrupts.rx(uint8_t byte)
   {
     if (m_rxBuf)
       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,
@@ -292,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; }
 }