//***************************************************************************** // // The spi1 slaver interrupt handler. // //***************************************************************************** void SPI_spi0_int_handler(void) { unsigned long status; unsigned long buf; status = SSIIntStatus(SSI0_BASE, true); // »ñÈ¡ÖжÏ״̬ #if 0 // for test if (status) { SSIIntClear(SSI0_BASE, status); UARTSend((unsigned char *)"\r\nSSI0", 6); return; } #else if (!status) { return; } SSIIntClear(SSI0_BASE, status); switch (status) { case SSI_RXFF: case SSI_RXOR: while (1) { if (SSIDataGetNonBlocking(SSI0_BASE, &buf)) { spi_rx_buf[spi_rx_idx++] = (unsigned char)buf; UARTSend(&spi_rx_buf[spi_rx_idx-1], 1); // test } else { spi_rx_len = spi_rx_idx; spi_rx_idx = 0; //OSSemPost(); UARTSend("\r\n", 2); // test break; } } break; case SSI_RXTO: // do something for timeout break; default: break; } #endif }
/* * ======== SPICC26XXDMA_hwInit ======== * This functions initializes the SPI hardware module. * * @pre Function assumes that the SPI handle is pointing to a hardware * module which has already been opened. */ static void SPICC26XXDMA_initHw(SPI_Handle handle) { SPICC26XX_Object *object; SPICC26XX_HWAttrs const *hwAttrs; Types_FreqHz freq; /* Get the pointer to the object and hwAttrs */ object = handle->object; hwAttrs = handle->hwAttrs; /* Disable SSI operation */ SSIDisable(hwAttrs->baseAddr); /* Disable SPI module interrupts */ SSIIntDisable(hwAttrs->baseAddr, SSI_RXOR | SSI_RXFF | SSI_RXTO | SSI_TXFF); SSIIntClear(hwAttrs->baseAddr, SSI_RXOR | SSI_RXTO); /* Set the SPI configuration */ BIOS_getCpuFreq(&freq); SSIConfigSetExpClk(hwAttrs->baseAddr, freq.lo, frameFormat[object->frameFormat], mode[object->mode], object->bitRate, object->dataSize); /* Print the configuration */ Log_print3(Diags_USER1, "SPI:(%p) CPU freq: %d; SPI freq to %d", hwAttrs->baseAddr, freq.lo, object->bitRate); }
//-------------------------------- void ssi_peripheral::Initialize() { MAP_SysCtlPeripheralEnable(m_rSpecification.m_nSSIPeripheral); MAP_SysCtlPeripheralEnable(m_rSpecification.m_nGPIOPeripheral); // Assign the SSI signals to the appropriate pins MAP_GPIOPinConfigure(m_rSpecification.m_nSSIPinRx); MAP_GPIOPinConfigure(m_rSpecification.m_nSSIPinClk); MAP_GPIOPinConfigure(m_rSpecification.m_nSSIPinTx); if (m_rSpecification.m_nSSIPinFss) { MAP_GPIOPinConfigure(m_rSpecification.m_nSSIPinFss); } // Set the GPIO AFSEL bits for the appropriate pins MAP_GPIOPinTypeSSI(m_rSpecification.m_nGPIOBase, m_rSpecification.m_nGPIOPins); // Set pull-up on the SSI Rx pin GPIOPadConfigSet(m_rSpecification.m_nGPIOBase, m_rSpecification.m_nGPIOInputPin, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); // Set standard on the SSI output pins GPIOPadConfigSet(m_rSpecification.m_nGPIOBase, m_rSpecification.m_nGPIOOutputPins, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); // Configure the SSI peripheral SSIConfigSetExpClk(m_rSpecification.m_nSSIBase, SysCtlClockGet(), m_nProtocol, SSI_MODE_MASTER, m_nBitRate, 16); // Enable the SSI module. MAP_SSIEnable(m_rSpecification.m_nSSIBase); // Read any residual data from the SSI port. while (MAP_SSIDataGetNonBlocking(m_rSpecification.m_nSSIBase, &m_nDataRx[0])) { } m_bEmpty = true; // Enable the SSI interrupt switch (m_nDevice) { case ssi_peripheral::SSI0: g_pTheSSI0 = this; break; case ssi_peripheral::SSI1: g_pTheSSI1 = this; break; case ssi_peripheral::SSI2: g_pTheSSI2 = this; break; case ssi_peripheral::SSI3: g_pTheSSI3 = this; break; default: break; } SSIIntDisable(m_rSpecification.m_nSSIBase, SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR); SSIIntClear(m_rSpecification.m_nSSIBase, SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR); (*((volatile uint32_t *) m_rSpecification.m_nSSI_CR1_R)) |= SSI_CR1_EOT; /* switch tx interrupt to eot int */ if (m_bNonBlocking) { SSIIntEnable(m_rSpecification.m_nSSIBase, SSI_TXFF); /* SSI_TXFF | SSI_RXFF | SSI_RXTO | SSI_RXOR */ MAP_IntEnable(m_rSpecification.m_nInterrupt); } }
/* * This configures the SSI. * Setups only the TX and configures the SSI to work at 6.4Mhz and 8bit packets. * It's 6.4Mhz because 6.4Mhz/8 is about 800Khz, the frequency needed for the WS2812B * */ void SPIInit() { // put your setup code here, to run once: SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); SysCtlDelay(3); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); SysCtlDelay(3); GPIOPinConfigure(GPIO_PA5_SSI0TX); GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5); SSIIntClear(SSI0_BASE,SSI_TXEOT); SSIConfigSetExpClk(SSI0_BASE, 80000000, SSI_FRF_MOTO_MODE_0,SSI_MODE_MASTER, 6400000, 8); SSIEnable(SSI0_BASE); }
//-------------------------------- void ssi_peripheral::OnInterrupt() { uint32_t nIntStatus = SSIIntStatus(m_rSpecification.m_nSSIBase, false); uint32_t nSsiStatus = (HWREG(m_rSpecification.m_nSSIBase + SSI_O_SR)); SSIIntClear(m_rSpecification.m_nSSIBase, nIntStatus); if (SSI_SR_TFE & nSsiStatus) { // SSI Transmit FIFO Empty (status) m_nSRTFE++; OnTx(); } if ( SSI_TXFF & nIntStatus) { // TX FIFO half full or less m_nTXFF++; } if ( SSI_RXFF & nIntStatus) { // RX FIFO half full or more m_nRXFF++; UnloadRxFIFO(); } if ( SSI_RXTO & nIntStatus) { // RX timeout m_nRXTO++; } if ( SSI_RXOR & nIntStatus) { // RX overrun m_nRXOR++; } }
/*! * @brief Function that cancels a SPI transfer. Will disable SPI and UDMA modules * and allow standby. * * @pre SPICC26XXDMA_open() has to be called first. * Calling context: Task * * @param handle The SPI_Handle for ongoing transaction. */ void SPICC26XXDMA_transferCancel(SPI_Handle handle) { SPICC26XX_Object *object; SPI_Transaction *msg; SPICC26XX_HWAttrs const *hwAttrs; volatile tDMAControlTable *dmaControlTableEntry; unsigned int key; /* Get the pointer to the object and hwAttrs */ object = handle->object; hwAttrs = handle->hwAttrs; /* Check if a transfer is in progress */ key = Hwi_disable(); /* Check if there is an active transaction */ if(!(object->currentTransaction)) { Hwi_restore(key); return; } Hwi_restore(key); /* Disable the SPI module */ SSIDisable(hwAttrs->baseAddr); /* Disable SPI TX/RX DMA and clear DMA done interrupt just in case it finished */ SSIDMADisable(hwAttrs->baseAddr, SSI_DMA_TX | SSI_DMA_RX); UDMACC26XX_clearInterrupt(object->udmaHandle, (hwAttrs->rxChannelBitMask) | (hwAttrs->txChannelBitMask)); /* Disable and clear any pending interrupts */ SSIIntDisable(hwAttrs->baseAddr, SSI_RXOR); SSIIntClear(hwAttrs->baseAddr, SSI_RXOR); /* Clear out the FIFO by resetting SPI module and re-initting */ HapiResetPeripheral(hwAttrs->baseAddr == SSI0_BASE ? PRCM_PERIPH_SSI0 : PRCM_PERIPH_SSI1); SPICC26XXDMA_initHw(handle); /* Release constraint since transaction is done */ threadSafeConstraintRelease((uint32_t)(object->currentTransaction->txBuf)); /* Mark the transaction as failed if we didn't end up here due to a CSN deassertion */ if (object->currentTransaction->status != SPI_TRANSFER_CSN_DEASSERT) { object->currentTransaction->status = SPI_TRANSFER_FAILED; } /* Disable the UDMA channels */ UDMACC26XX_channelDisable(object->udmaHandle, (hwAttrs->rxChannelBitMask) | (hwAttrs->txChannelBitMask)); /* Update the SPI_Transaction.count parameter */ /* rxChannel always finishes after txChannel so remaining bytes of the rxChannel is used to update count */ dmaControlTableEntry = (hwAttrs->baseAddr == SSI0_BASE ? &dmaRxControlTableEntry0 : &dmaRxControlTableEntry1); object->currentTransaction->count -= UDMACC26XX_GET_TRANSFER_SIZE(dmaControlTableEntry->ui32Control); /* Use a temporary transaction pointer in case the callback function * attempts to perform another SPI_transfer call */ msg = object->currentTransaction; /* Indicate we are done with this transfer */ object->currentTransaction = NULL; Log_print2(Diags_USER1,"SPI:(%p) DMA transaction: %p cancelled", hwAttrs->baseAddr, (UArg)msg); /* Perform callback */ object->transferCallbackFxn(handle, msg); /* Transaction was successfully canceled */ return; }
/* * ======== SPICC26XXDMA_hwiFxn ======== * ISR for the SPI when we use the UDMA */ static void SPICC26XXDMA_hwiFxn (UArg arg) { SPI_Transaction *msg; SPICC26XX_Object *object; SPICC26XX_HWAttrs const *hwAttrs; uint32_t intStatus; /* Get the pointer to the object and hwAttrs */ object = ((SPI_Handle)arg)->object; hwAttrs = ((SPI_Handle)arg)->hwAttrs; Log_print1(Diags_USER2, "SPI:(%p) interrupt context start", hwAttrs->baseAddr); /* Get the interrupt status of the SPI controller */ intStatus = SSIIntStatus(hwAttrs->baseAddr, true); SSIIntClear(hwAttrs->baseAddr, intStatus); /* Error handling: * Overrun in the RX Fifo -> at least one sample in the shift * register has been discarded */ if (intStatus & SSI_RXOR) { /* disable the interrupt */ SSIIntDisable(hwAttrs->baseAddr, SSI_RXOR); /* If the RX overrun occurred during a transfer */ if (object->currentTransaction) { /* Then cancel the ongoing transfer */ SPICC26XXDMA_transferCancel((SPI_Handle)arg); } else { /* Otherwise disable the SPI and DMA modules and flush FIFOs */ SSIDisable(hwAttrs->baseAddr); /* Disable SPI TX/RX DMA and clear DMA done interrupt just in case it finished */ SSIDMADisable(hwAttrs->baseAddr, SSI_DMA_TX | SSI_DMA_RX); UDMACC26XX_clearInterrupt(object->udmaHandle, (hwAttrs->rxChannelBitMask) | (hwAttrs->txChannelBitMask)); /* Clear out the FIFO by resetting SPI module and re-initting */ HapiResetPeripheral(hwAttrs->baseAddr == SSI0_BASE ? PRCM_PERIPH_SSI0 : PRCM_PERIPH_SSI1); SPICC26XXDMA_initHw((SPI_Handle)arg); } Log_print1(Diags_USER1, "RX FIFO overrun occurred in SPI: (%p) !\n", hwAttrs->baseAddr); } else { /* Determine if the TX DMA channel has completed... */ if (UDMACC26XX_channelDone(object->udmaHandle, hwAttrs->txChannelBitMask)) { /* Disable SPI TX DMA and clear DMA done interrupt. */ SSIDMADisable(hwAttrs->baseAddr, SSI_DMA_TX); UDMACC26XX_clearInterrupt(object->udmaHandle, hwAttrs->txChannelBitMask); /* All transfers will set up both TX and RX DMA channels and both will finish. * Even if the transaction->rxBuf == NULL, it will setup a dummy RX transfer to * a scratch memory location which is then discarded. * Therefore all cleanup is only done when the RX DMA channel has completed, * since it will always run at some point after the TX DMA channel has completed. */ } /* Determine if the RX DMA channel has completed... */ if(UDMACC26XX_channelDone(object->udmaHandle, hwAttrs->rxChannelBitMask)) { /* Disable SPI RX DMA and clear DMA done interrupt. */ SSIDMADisable(hwAttrs->baseAddr, SSI_DMA_RX); UDMACC26XX_clearInterrupt(object->udmaHandle, hwAttrs->rxChannelBitMask); /* Transaction is complete */ object->currentTransaction->status = SPI_TRANSFER_COMPLETED; /* Use a temporary transaction pointer in case the callback function * attempts to perform another SPI_transfer call */ msg = object->currentTransaction; Log_print2(Diags_USER1,"SPI:(%p) DMA transaction: %p complete", hwAttrs->baseAddr, (UArg)msg); /* Release constraint since transaction is done */ threadSafeConstraintRelease((uint32_t)(object->currentTransaction->txBuf)); /* Indicate we are done with this transfer */ object->currentTransaction = NULL; /* Perform callback */ object->transferCallbackFxn((SPI_Handle)arg, msg); } } Log_print1(Diags_USER2, "SPI:(%p) interrupt context end", hwAttrs->baseAddr); }