Hello,
I'm using TMS570LS3137 with CCStudio 6.0.1 and Compiler 5.1.9.
I've configured channel 11 of DMA for SPI Tx and cannel 12 for SPI Rx. Before I start DMA I send the header (WriteEnable, WriteCommand, Address) manually. Also I've enabeld DMA BTC interrupt on channel 12 to know when the transfer is over. In the BTC ISR I set the CS of the FRAM/MRAM to high again. (I'm using SPI 3pin mode and set/reset CS manually)
This works good but sometimes a receiver overrun interrupt occurs. I don't know why.
Does that mean that DMA is too slow to copy the data? (I can't believe that, although more DMA channels for other SPI ports are configured and running perfectly)
I've attached the function in which I configure DMA and SPI. Are there any errors in configuration? Is there a better way to do this?
#define MAX_DATA_CNT 8187 uint8_t FRAMDrv_WriteDMA(uint32_t Address, uint8_t *pDataToWrite, uint32_t Length) { uint32_t RestLength = Length; uint8_t SPITxBuffer[4], i, RetVal = 0; g_dmaCTRL dmaSPITxCTRLPKT, dmaSPIRxCTRLPKT; portBASE_TYPE xRunningPrivileged; xSemaphoreTake(xFRAMMutex, portMAX_DELAY); xSemaphoreTakeRecursive(xSPI4Mutex, portMAX_DELAY); xRunningPrivileged = prvRaisePrivilege(); memcpy(&FRAMMirror[Address], pDataToWrite, Length); while (RestLength > 0) { if (RestLength >= MAX_DATA_CNT) { Length = MAX_DATA_CNT; RestLength -= MAX_DATA_CNT; } else { Length = RestLength; RestLength = 0; } SPITxBuffer[0] = FRAM_CMD_WRITE; SPITxBuffer[1] = (uint8_t)((Address >> 16) & 0x000000FF); SPITxBuffer[2] = (uint8_t)((Address >> 8) & 0x000000FF); SPITxBuffer[3] = (uint8_t)(Address & 0x000000FF); SetTransferMode(WRITE); // Clear RXINT flag. spiREG4->FLG |= 0x100; /* Set CS for FRAM to 0 */ gioSetBit(spiPORT3, 0, 0); // Send Write Enable command. spiREG4->DAT1 = (0x00000000 | (uint8_t)FRAM_CMD_WREN); /* Wait for transmission to complete */ while ((spiREG4->FLG & 0x100) == 0) ; /* Set CS for FRAM to 1 */ gioSetBit(spiPORT3, 0, 1); // Clear RXINT flag. spiREG4->FLG |= 0x100; /* Set CS for FRAM to 0 */ gioSetBit(spiPORT3, 0, 0); /* Send Write Command and Address to FRAM */ for (i = 0; i < sizeof(SPITxBuffer); i++) { spiREG4->DAT1 = (0x00000000 | (uint8_t)SPITxBuffer[i]); /* Wait for transmission to complete */ while ((spiREG4->FLG & 0x100) == 0) ; // Clear RXINT flag. spiREG4->FLG |= 0x100; } /* Configuring SPI Tx DMA channel */ /* - assigning dma request: channel-11 with request line - 25 */ dmaReqAssign(DMA_CH11, 25); /* - configuring dma control packets */ dmaSPITxCTRLPKT.SADD = (uint32_t)(pDataToWrite); /* source address */ dmaSPITxCTRLPKT.DADD = (uint32_t)(&(spiREG4->DAT1)) + 3; /* destination address */ dmaSPITxCTRLPKT.CHCTRL = 0; /* channel control */ dmaSPITxCTRLPKT.FRCNT = Length; /* frame count */ dmaSPITxCTRLPKT.ELCNT = 1; /* element count */ dmaSPITxCTRLPKT.ELDOFFSET = 0; /* element destination offset */ dmaSPITxCTRLPKT.ELSOFFSET = 0; /* element source offset */ dmaSPITxCTRLPKT.FRDOFFSET = 0; /* frame destination offset */ dmaSPITxCTRLPKT.FRSOFFSET = 0; /* frame source offset */ dmaSPITxCTRLPKT.PORTASGN = 4; /* port b */ dmaSPITxCTRLPKT.RDSIZE = ACCESS_8_BIT; /* read size */ dmaSPITxCTRLPKT.WRSIZE = ACCESS_8_BIT; /* write size */ dmaSPITxCTRLPKT.TTYPE = FRAME_TRANSFER; /* transfer type */ dmaSPITxCTRLPKT.ADDMODERD = ADDR_INC1; /* address mode read */ dmaSPITxCTRLPKT.ADDMODEWR = ADDR_FIXED; /* address mode write */ dmaSPITxCTRLPKT.AUTOINIT = AUTOINIT_OFF; /* autoinit */ /* - setting dma control packets */ dmaSetCtrlPacket(DMA_CH11, dmaSPITxCTRLPKT); /* - set channel 11 to high priority queue */ dmaSetPriority(DMA_CH11, HIGHPRIORITY); /* - setting the dma channel to trigger on h/w request */ dmaSetChEnable(DMA_CH11, DMA_HW); // The DMA Rx channel is used to determine if the transmit is already over. // This is necessary because the Tx DMA throws the BTC interrupt already // when the last transfer to the TXDAT1 register was done. But the SPI // interface needs some time to shift the data out. /* Configuring SPI Rx DMA channel */ /* - assigning dma request: channel-12 with request line - 24 */ dmaReqAssign(DMA_CH12, 24); /* - configuring dma control packets */ dmaSPIRxCTRLPKT.SADD = (uint32_t)(&(spiREG4->BUF)) + 3; /* source address */ dmaSPIRxCTRLPKT.DADD = (uint32_t)FRAMRxBuffer; /* destination address */ dmaSPIRxCTRLPKT.CHCTRL = 0; /* channel control */ dmaSPIRxCTRLPKT.FRCNT = Length; /* frame count */ dmaSPIRxCTRLPKT.ELCNT = 1; /* element count */ dmaSPIRxCTRLPKT.ELDOFFSET = 0; /* element destination offset */ dmaSPIRxCTRLPKT.ELSOFFSET = 0; /* element source offset */ dmaSPIRxCTRLPKT.FRDOFFSET = 0; /* frame destination offset */ dmaSPIRxCTRLPKT.FRSOFFSET = 0; /* frame source offset */ dmaSPIRxCTRLPKT.PORTASGN = 4; /* port b */ dmaSPIRxCTRLPKT.RDSIZE = ACCESS_8_BIT; /* read size */ dmaSPIRxCTRLPKT.WRSIZE = ACCESS_8_BIT; /* write size */ dmaSPIRxCTRLPKT.TTYPE = FRAME_TRANSFER; /* transfer type */ dmaSPIRxCTRLPKT.ADDMODERD = ADDR_FIXED; /* address mode read */ dmaSPIRxCTRLPKT.ADDMODEWR = ADDR_FIXED; /* address mode write */ dmaSPIRxCTRLPKT.AUTOINIT = AUTOINIT_OFF; /* autoinit */ /* - setting dma control packets */ dmaSetCtrlPacket(DMA_CH12, dmaSPIRxCTRLPKT); /* - set channel 12 to high priority queue */ dmaSetPriority(DMA_CH12, HIGHPRIORITY); /* - setting the dma channel to trigger on h/w request */ dmaSetChEnable(DMA_CH12, DMA_HW); // enable Interrupt for BTC on channel 12 dmaEnableInterrupt(DMA_CH12, BTC); // configuring MPU for DMA access. dmaDefineRegion(DMA_REGION0, (uint32_t)(FRAMRxBuffer), (uint32_t)(FRAMRxBuffer)); dmaEnableRegion(DMA_REGION0, FULLACCESS, INTERRUPT_ENABLE); // Set current device to FRAM SetCurrentSPI4Device(FRAM); // enable DMA for SPI transfer spiREG4->INT0 |= 0x10000; // Correct FRAM Address and data to write pointer Address += Length; pDataToWrite += Length; if (xSemaphoreTake(xFRAMWriteSem, 1000 / portTICK_RATE_MS) == pdFALSE) { // timeout error RetVal = 0xFF; } } portRESET_PRIVILEGE(xRunningPrivileged); xSemaphoreGiveRecursive(xSPI4Mutex); xSemaphoreGive(xFRAMMutex); return RetVal; }
Thanks and best regards
Christian