SSDA015 September   2026 MSPM0G5117 , MSPM0G5187

 

  1.   1
  2. Description
  3. Required Peripherals
  4. Compatible Devices
  5. Design Steps
  6. Design Considerations
  7. Software Flowchart
  8. Application Code
  9. Data Flow Examples
  10. Additional Resources
  11. 10Trademarks

Application Code

USB to SPI:

/********************************************************
* Function name  : usb2spi_popTask
* Description    : USB -> SPI. Pop task from queue and transmit data through
*                  SPI to slave device. Waits if SPI TX already in progress.
*                  Called from main loop when fifoCount > 0.
* Parameter      : None (modifies gUSB2SPITask, spiInProgress)
* Return         : None
**********************************************************/
void usb2spi_popTask(void)
{
    if(spiInProgress) return;
    if(gUSB2SPITask.fifoCount == 0) return;

    // Current process task
    TxElement_t *pTask = &gUSB2SPITask.fifoPointer[gUSB2SPITask.fifoOut];
    
    //Flush TXFIFO
    DL_SPI_flushTXFIFO(SPI_0_INST);
    
    /* Setup DMA and start SPI write */
    DL_SPI_clearInterruptStatus(SPI_0_INST, DL_SPI_INTERRUPT_DMA_DONE_TX);
    DL_SPI_enableInterrupt(SPI_0_INST, DL_SPI_INTERRUPT_DMA_DONE_TX);
    DL_DMA_setSrcAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(pTask->buffer));
    DL_DMA_setDestAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(&SPI_0_INST->spi->TXDATA));
    DL_DMA_setTransferSize(DMA, DMA_CH1_CHAN_ID, pTask->length); 
    DL_DMA_enableChannel(DMA, DMA_CH1_CHAN_ID);

    spiInProgress = true;
}
/* ===== USB RX -> SPI TX ===== */

/********************************************************
* Function name  : usb2spi_pushTask
* Description    : USB -> SPI. Read data from USB CDC interface and push
*                  into gUSB2SPITask queue. Each task holds one USB frame
*                  (up to 64 bytes). Called from tud_cdc_rx_cb callback.
* Parameter      : None (modifies gUSB2SPITask)
* Return         : None
**********************************************************/
void usb2spi_pushTask(void)
{
    // Check space for new task
    if(gUSB2SPITask.fifoCount >= SPI_TX_BUF_SIZE) return;

    // Get current task slot in queue
    TxElement_t *pTask = &gUSB2SPITask.fifoPointer[gUSB2SPITask.fifoIn];

    // Read up to 64 bytes from USB CDC
    uint32_t cnt = tud_cdc_n_read(0, pTask->buffer, 64);
    if(cnt == 0) return;                    // Skip if no data

    pTask->length = cnt;

    // Advance queue pointer and mark task as ready
    fifoCompleteWrite(&gUSB2SPITask, SPI_TX_BUF_SIZE);
}

SPI to USB:

/* ===== SPI RX -> USB TX ===== */

/********************************************************
* Function name  : spi2usb_pushTask
* Description    : SPI -> USB. Read data from SPI slave and queue for USB transmission
*                  Triggered when target device signals data ready via GPIO pin.
*                  Called from GPIO interrupt handler.
* Parameter      : None (modifies gSPI2USBTask)
* Return         : None
**********************************************************/
void spi2usb_pushTask(void)
{
    // Check if SPI→USB queue has space for new task
    if (gSPI2USBTask.fifoCount >= USB_TX_BUF_SIZE) return;
    if(spiInProgress) return;

    // Get current task buffer
    TxElement_t *pTask = &gSPI2USBTask.fifoPointer[gSPI2USBTask.fifoIn];

    // Pre-set length since SPI master reads fixed 64 bytes per transaction
    pTask->length = USB_FRAME_PACKAGE;

    //Flush RXFIFO
    DL_SPI_flushRXFIFO(SPI_0_INST);

    //Flush TXFIFO
    DL_SPI_flushTXFIFO(SPI_0_INST);
    
    // Transmit dummy data 
    DL_SPI_disableInterrupt(SPI_0_INST, DL_SPI_INTERRUPT_DMA_DONE_TX);
    DL_DMA_setSrcAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(pTask->buffer));
    DL_DMA_setDestAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(&SPI_0_INST->spi->TXDATA));
    DL_DMA_setTransferSize(DMA, DMA_CH1_CHAN_ID, USB_FRAME_PACKAGE); 
    DL_DMA_enableChannel(DMA, DMA_CH1_CHAN_ID);

    /* DMA to receive data */
    DL_SPI_flushRXFIFO(SPI_0_INST);

    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(&SPI_0_INST->spi->RXDATA));
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(pTask->buffer));
    DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, USB_FRAME_PACKAGE);
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    spiInProgress = true;
}
/********************************************************
* Function name  : spi2usb_popTask
* Description    : SPI -> USB. Pop task from queue and transmit data through
*                  USB CDC interface. All data in one task is sent in same USB
*                  frame. Checks if USB TX buffer has space. Called from main
*                  loop when fifoCount > 0.
* Parameter      : None (modifies gSPI2USBTask)
* Return         : None
**********************************************************/
void spi2usb_popTask(void)
{
    if(gSPI2USBTask.fifoCount == 0) return;

    TxElement_t *pTask = &gSPI2USBTask.fifoPointer[gSPI2USBTask.fifoOut];

    if(tud_cdc_n_write_available(0) >= pTask->length){
        uint32_t written = tud_cdc_n_write(0, pTask->buffer, pTask->length);

        if(written == pTask->length){
            tud_cdc_n_write_flush(0);
            fifoCompleteRead(&gSPI2USBTask, USB_TX_BUF_SIZE);
        }
    }
}

SPI Interrupt Handler:

//--------------------------------------------------------------------+
// SPI Interrupt Handler
//--------------------------------------------------------------------+
void SPI_0_INST_IRQHandler(void) {
    switch(DL_SPI_getPendingInterrupt(SPI_0_INST)) {
        case DL_SPI_IIDX_DMA_DONE_TX:
            // TX: DMA transfer to SPI FIFO complete
            DL_SPI_clearInterruptStatus(SPI_0_INST, DL_SPI_INTERRUPT_TX_EMPTY);
            DL_SPI_enableInterrupt(SPI_0_INST, DL_SPI_INTERRUPT_TX_EMPTY);
            break;

        case DL_SPI_IIDX_DMA_DONE_RX:
            // RX complete: DMA received 64 bytes from SPI slave
            fifoCompleteWrite(&gSPI2USBTask, USB_TX_BUF_SIZE);
            SPISlaveDataReady = false;  // Clear slave notification flag
            spiInProgress = false;
            break;

            // TX complete
        case DL_SPI_IIDX_TX_EMPTY:
            DL_SPI_disableInterrupt(SPI_0_INST, DL_SPI_INTERRUPT_TX_EMPTY);
            fifoCompleteRead(&gUSB2SPITask, SPI_TX_BUF_SIZE);
            spiInProgress = false;
            break;

        default:
            break;
    }
}