SSDA015 September 2026 MSPM0G5117 , MSPM0G5187
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;
}
}