SAMV7 SPI slave: Loop in the interrupt handler; RDRF and TXNE events should occur very closely in time
This commit is contained in:
parent
27733a6731
commit
f3d1c19965
@ -419,132 +419,152 @@ static int spi_interrupt(struct sam_spidev_s *priv)
|
|||||||
uint32_t pending;
|
uint32_t pending;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
/* Get the current set of pending/enabled interrupts */
|
/* We loop because the TDRE interrupt will probably immediately follow the
|
||||||
|
* RDRF interrupt and we might be able to catch it in this handler
|
||||||
sr = spi_getreg(priv, SAM_SPI_SR_OFFSET);
|
* execution.
|
||||||
imr = spi_getreg(priv, SAM_SPI_IMR_OFFSET);
|
|
||||||
pending = sr & imr;
|
|
||||||
|
|
||||||
/* TThe SPI waits until NSS goes active before receiving the serial clock
|
|
||||||
* from an external master. When NSS falls, the clock is validated and the
|
|
||||||
* data is loaded in the SPI_RDR depending on the BITS field configured in
|
|
||||||
* the SPI_CSR0. These bits are processed following a phase and a polarity
|
|
||||||
* defined respectively by the NCPHA and CPOL bits in the SPI_CSR0.
|
|
||||||
*
|
|
||||||
* When all bits are processed, the received data is transferred in the
|
|
||||||
* SPI_RDR and the RDRF bit rises. If the SPI_RDR has not been read before
|
|
||||||
* new data is received, the Overrun Error Status (OVRES) bit in the SPI_SR
|
|
||||||
* is set. As long as this flag is set, data is loaded in the SPI_RDR. The
|
|
||||||
* user must read SPI_SR to clear the OVRES bit.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_SPI
|
for (;;)
|
||||||
/* Check the RX data overflow condition */
|
|
||||||
|
|
||||||
if ((pending & SPI_INT_OVRES) != 0)
|
|
||||||
{
|
{
|
||||||
/* If debug is enabled, report any overrun errors */
|
/* Get the current set of pending/enabled interrupts */
|
||||||
|
|
||||||
spidbg("Error: Overrun (OVRES): %08x\n", pending);
|
sr = spi_getreg(priv, SAM_SPI_SR_OFFSET);
|
||||||
|
imr = spi_getreg(priv, SAM_SPI_IMR_OFFSET);
|
||||||
|
pending = sr & imr;
|
||||||
|
|
||||||
/* OVRES was cleared by the status read. */
|
/* Return from the interrupt handler when all pending interrupts have
|
||||||
}
|
* been processed.
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Check for the availability of RX data */
|
|
||||||
|
|
||||||
if ((pending & SPI_INT_RDRF) != 0)
|
|
||||||
{
|
|
||||||
uint16_t data;
|
|
||||||
|
|
||||||
/* We get no indication of the falling edge of NSS. But if we are
|
|
||||||
* here then it must have fallen.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (priv->nss)
|
if (pending == 0)
|
||||||
{
|
{
|
||||||
priv->nss = false;
|
return OK;
|
||||||
SPI_SDEV_SELECT(priv->sdev, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the RDR to get the data and to clear the pending RDRF
|
/* TThe SPI waits until NSS goes active before receiving the serial
|
||||||
* interrupt.
|
* clock from an external master. When NSS falls, the clock is
|
||||||
|
* validated and the data is loaded in the SPI_RDR depending on the
|
||||||
|
* BITS field configured in the SPI_CSR0. These bits are processed
|
||||||
|
* following a phase and a polarity defined respectively by the NCPHA
|
||||||
|
* and CPOL bits in the SPI_CSR0.
|
||||||
|
*
|
||||||
|
* When all bits are processed, the received data is transferred in
|
||||||
|
* the SPI_RDR and the RDRF bit rises. If the SPI_RDR has not been
|
||||||
|
* read before new data is received, the Overrun Error Status (OVRES)
|
||||||
|
* bit in the SPI_SR is set. As long as this flag is set, data is
|
||||||
|
* loaded in the SPI_RDR. The user must read SPI_SR to clear the OVRES
|
||||||
|
* bit.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regval = spi_getreg(priv, SAM_SPI_RDR_OFFSET);
|
|
||||||
data = (uint16_t)((regval & SPI_RDR_RD_MASK) >> SPI_RDR_RD_SHIFT);
|
|
||||||
|
|
||||||
/* Enable TXDR/OVRE interrupts */
|
|
||||||
|
|
||||||
regval = (SPI_INT_TDRE | SPI_INT_UNDES);
|
|
||||||
spi_putreg(priv, regval, SAM_SPI_IER_OFFSET);
|
|
||||||
|
|
||||||
/* Report the receipt of data to the SPI device driver */
|
|
||||||
|
|
||||||
SPI_SDEV_RECEIVE(priv->sdev, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When a transfer starts, the data shifted out is the data present in the
|
|
||||||
* Shift register. If no data has been written in the SPI_TDR, the last
|
|
||||||
* data received is transferred. If no data has been received since the last
|
|
||||||
* reset, all bits are transmitted low, as the Shift register resets to 0.
|
|
||||||
*
|
|
||||||
* When a first data is written in the SPI_TDR, it is transferred immediately
|
|
||||||
* in the Shift register and the TDRE flag rises. If new data is written, it
|
|
||||||
* remains in the SPI_TDR until a transfer occurs, i.e., NSS falls and there
|
|
||||||
* is a valid clock on the SPCK pin. When the transfer occurs, the last data
|
|
||||||
* written in the SPI_TDR is transferred in the Shift register and the TDRE
|
|
||||||
* flag rises. This enables frequent updates of critical variables with single
|
|
||||||
* transfers.
|
|
||||||
*
|
|
||||||
* Then, new data is loaded in the Shift register from the SPI_TDR. If no
|
|
||||||
* character is ready to be transmitted, i.e., no character has been written in
|
|
||||||
* the SPI_TDR since the last load from the SPI_TDR to the Shift register, the
|
|
||||||
* SPI_TDR is retransmitted. In this case the Underrun Error Status Flag
|
|
||||||
* (UNDES) is set in the SPI_SR.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_SPI
|
#ifdef CONFIG_DEBUG_SPI
|
||||||
/* Check the TX data underflow condition */
|
/* Check the RX data overflow condition */
|
||||||
|
|
||||||
if ((pending & SPI_INT_UNDES) != 0)
|
if ((pending & SPI_INT_OVRES) != 0)
|
||||||
{
|
{
|
||||||
/* If debug is enabled, report any overrun errors */
|
/* If debug is enabled, report any overrun errors */
|
||||||
|
|
||||||
spidbg("Error: Underrun (UNDEX): %08x\n", pending);
|
spidbg("Error: Overrun (OVRES): %08x\n", pending);
|
||||||
|
|
||||||
/* UNDES was cleared by the status read. */
|
/* OVRES was cleared by the status read. */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Output the next TX data */
|
/* Check for the availability of RX data */
|
||||||
|
|
||||||
if ((pending & SPI_INT_TDRE) != 0)
|
if ((pending & SPI_INT_RDRF) != 0)
|
||||||
{
|
{
|
||||||
/* Get the next output value and write it to the TDR
|
uint16_t data;
|
||||||
* The TDRE interrupt is cleared by writing to the from RDR.
|
|
||||||
|
/* We get no indication of the falling edge of NSS. But if we are
|
||||||
|
* here then it must have fallen.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (priv->nss)
|
||||||
|
{
|
||||||
|
priv->nss = false;
|
||||||
|
SPI_SDEV_SELECT(priv->sdev, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the RDR to get the data and to clear the pending RDRF
|
||||||
|
* interrupt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
regval = spi_getreg(priv, SAM_SPI_RDR_OFFSET);
|
||||||
|
data = (uint16_t)((regval & SPI_RDR_RD_MASK) >> SPI_RDR_RD_SHIFT);
|
||||||
|
|
||||||
|
/* Enable TXDR/OVRE interrupts */
|
||||||
|
|
||||||
|
regval = (SPI_INT_TDRE | SPI_INT_UNDES);
|
||||||
|
spi_putreg(priv, regval, SAM_SPI_IER_OFFSET);
|
||||||
|
|
||||||
|
/* Report the receipt of data to the SPI device driver */
|
||||||
|
|
||||||
|
SPI_SDEV_RECEIVE(priv->sdev, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When a transfer starts, the data shifted out is the data present
|
||||||
|
* in the Shift register. If no data has been written in the SPI_TDR,
|
||||||
|
* the last data received is transferred. If no data has been received
|
||||||
|
* since the last reset, all bits are transmitted low, as the Shift
|
||||||
|
* register resets to 0.
|
||||||
|
*
|
||||||
|
* When a first data is written in the SPI_TDR, it is transferred
|
||||||
|
* immediately in the Shift register and the TDRE flag rises. If new
|
||||||
|
* data is written, it remains in the SPI_TDR until a transfer occurs,
|
||||||
|
* i.e., NSS falls and there is a valid clock on the SPCK pin. When
|
||||||
|
* the transfer occurs, the last data written in the SPI_TDR is
|
||||||
|
* transferred in the Shift register and the TDRE flag rises. This
|
||||||
|
* enables frequent updates of critical variables with single transfers.
|
||||||
|
*
|
||||||
|
* Then, new data is loaded in the Shift register from the SPI_TDR. If
|
||||||
|
* no character is ready to be transmitted, i.e., no character has been
|
||||||
|
* written in the SPI_TDR since the last load from the SPI_TDR to the
|
||||||
|
* Shift register, the SPI_TDR is retransmitted. In this case the
|
||||||
|
* Underrun Error Status Flag (UNDES) is set in the SPI_SR.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regval = spi_dequeue(priv);
|
#ifdef CONFIG_DEBUG_SPI
|
||||||
spi_putreg(priv, regval, SAM_SPI_TDR_OFFSET);
|
/* Check the TX data underflow condition */
|
||||||
}
|
|
||||||
|
|
||||||
/* The SPI slave hardware provides only an event when NSS rises
|
if ((pending & SPI_INT_UNDES) != 0)
|
||||||
* which may or many not happen at the end of a transfer. NSSR was
|
{
|
||||||
* cleared by the status read.
|
/* If debug is enabled, report any overrun errors */
|
||||||
*/
|
|
||||||
|
|
||||||
if ((pending & SPI_INT_NSSR) != 0)
|
spidbg("Error: Underrun (UNDEX): %08x\n", pending);
|
||||||
{
|
|
||||||
/* Disable further TXDR/OVRE interrupts */
|
|
||||||
|
|
||||||
regval = (SPI_INT_TDRE | SPI_INT_UNDES);
|
/* UNDES was cleared by the status read. */
|
||||||
spi_putreg(priv, regval, SAM_SPI_IDR_OFFSET);
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Report the state change to the SPI device driver */
|
/* Output the next TX data */
|
||||||
|
|
||||||
priv->nss = true;
|
if ((pending & SPI_INT_TDRE) != 0)
|
||||||
SPI_SDEV_SELECT(priv->sdev, false);
|
{
|
||||||
|
/* Get the next output value and write it to the TDR
|
||||||
|
* The TDRE interrupt is cleared by writing to the from RDR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
regval = spi_dequeue(priv);
|
||||||
|
spi_putreg(priv, regval, SAM_SPI_TDR_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The SPI slave hardware provides only an event when NSS rises
|
||||||
|
* which may or many not happen at the end of a transfer. NSSR was
|
||||||
|
* cleared by the status read.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((pending & SPI_INT_NSSR) != 0)
|
||||||
|
{
|
||||||
|
/* Disable further TXDR/OVRE interrupts */
|
||||||
|
|
||||||
|
regval = (SPI_INT_TDRE | SPI_INT_UNDES);
|
||||||
|
spi_putreg(priv, regval, SAM_SPI_IDR_OFFSET);
|
||||||
|
|
||||||
|
/* Report the state change to the SPI device driver */
|
||||||
|
|
||||||
|
priv->nss = true;
|
||||||
|
SPI_SDEV_SELECT(priv->sdev, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user