Hi,
I am trying to setup SSI in quad mode with DMA TX/RX, but am having issues with the interrupt handler. As soon as I call SSIIntEnable(SSI1_BASE, SSI_DMATX), my interrupt handler will endlessly go off.
I have found what seems to be the exact same issue in this other thread:
https://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/361916
and have tried everything suggested in that thread to the best of my knowledge, and also referred to the errata which said to do this:
Here is my initialization code:
void Board_initQSSI(uint32_t SysClk_Freq, uint32_t baud_rate) { // Enable QSSI Peripherals (using ports B, D, E on QSSI1) MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); // Pin function via mux setting. This macro is mapped to GPIOPinConfigure in rom_map.h. // GPIOPinConfigure is def in gpio.c MAP_GPIOPinConfigure(GPIO_PB5_SSI1CLK); MAP_GPIOPinConfigure(GPIO_PB4_SSI1FSS); MAP_GPIOPinConfigure(GPIO_PE4_SSI1XDAT0); MAP_GPIOPinConfigure(GPIO_PE5_SSI1XDAT1); MAP_GPIOPinConfigure(GPIO_PD4_SSI1XDAT2); MAP_GPIOPinConfigure(GPIO_PD5_SSI1XDAT3); // Pin operation settings. This macro is mapped to GPIOPinTypeSSI in rom_map.h. // GPIOPinTypeSSI is def in gpio.c MAP_GPIOPinTypeSSI(GPIO_PORTB_AHB_BASE, GPIO_PIN_4 | GPIO_PIN_5); MAP_GPIOPinTypeSSI(GPIO_PORTD_AHB_BASE, GPIO_PIN_4 | GPIO_PIN_5); MAP_GPIOPinTypeSSI(GPIO_PORTE_AHB_BASE, GPIO_PIN_4 | GPIO_PIN_5); // Disable QSSI MAP_SSIDisable(SSI1_BASE); // Set to SPI Mode0 for QSSI (Advanced) mode; set master mode MAP_SSIConfigSetExpClk(SSI1_BASE, SysClk_Freq, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, baud_rate, 8); // Enable advanced mode MAP_SSIAdvModeSet(SSI1_BASE, SSI_ADV_MODE_QUAD_READ); // Fill the TX buffer with a dummy data pattern g_ui8TxBuf[0] = 0xAB; // Enable the uDMA controller at the system level. MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); // Enable the uDMA controller. MAP_uDMAEnable(); // Point at the control table to use for channel control structures. MAP_uDMAControlBaseSet(dmaControlTable); //MAP_uDMAChannelAssign(UDMA_CHANNEL_SSI1RX); //MAP_uDMAChannelAssign(UDMA_CHANNEL_SSI1TX); // Put the attributes in a known state for the uDMA SSI1TX channel. MAP_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI1TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); MAP_uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI1TX, UDMA_ATTR_USEBURST); // Configure the control parameters for the SSI1 TX. The uDMA SSI TX // channel is used to transfer a block of data from a buffer to the SSI. // The data size is 8 bits. The source address increment is none since // the data is dummy write to generate clocks. The destination increment is // none since the data is to be written to the SSI data register. The // arbitration size is set to 1024. //1. MAP_uDMAChannelControlSet(UDMA_CHANNEL_SSI1TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_NONE | UDMA_ARB_1024); // Set up the transfer parameters for the uDMA SSI TX channel. This will // configure the transfer source and destination and the transfer size. // Basic mode is used because the peripheral is making the uDMA transfer // request. The source is the TX buffer and the destination is the SSI // data register. // // Commented out because we do not want to set up the transfer parameters yet // until we are ready to start the transmit /*MAP_uDMAChannelTransferSet(UDMA_CHANNEL_SSI1TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8TxBuf, (void *) SSI1_BASE, sizeof(g_ui8TxBuf));*/ // Put the attributes in a known state for the uDMA SSI1RX channel. MAP_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI1RX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); MAP_uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI1RX, UDMA_ATTR_USEBURST); // Configure the control parameters for the primary control structure for // the SSI1 RX channel. The primary control structure is used for the "A" // part of the ping-pong receive. The transfer data size is 8 bits, the // source address does not increment since it will be reading from a // register. The destination address increment is byte 8-bit bytes. The // arbitration size is set to 1024. //1. MAP_uDMAChannelControlSet(UDMA_CHANNEL_SSI1RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1024); // Configure the control parameters for the alternate control structure for // the SSI1 RX channel. The alternate control structure is used for the "B" // part of the ping-pong receive. The configuration is identical to the // primary/A control structure. MAP_uDMAChannelControlSet(UDMA_CHANNEL_SSI1RX | UDMA_ALT_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_1024); // Set up the transfer parameters for the SSI RX primary control // structure. The mode is set to ping-pong, the transfer source is the // SSI1 data register, and the destination is the receive "A" buffer. The // transfer size is set to match the size of the buffer. MAP_uDMAChannelTransferSet(UDMA_CHANNEL_SSI1RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *) SSI1_BASE, g_ui8RxBufA, sizeof(g_ui8RxBufA)); // Set up the transfer parameters for the SSI RX alternate control // structure. The mode is set to ping-pong, the transfer source is the // SSI data register, and the destination is the receive "B" buffer. The // transfer size is set to match the size of the buffer. MAP_uDMAChannelTransferSet(UDMA_CHANNEL_SSI1RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *) SSI1_BASE, g_ui8RxBufB, sizeof(g_ui8RxBufB)); // Enable the uDMA SSI1RX channel MAP_uDMAChannelEnable(UDMA_CHANNEL_SSI1RX); // Enable SSI uDMA MAP_SSIDMADisable(SSI1_BASE, SSI_DMA_RX | SSI_DMA_TX); MAP_SSIIntClear(SSI1_BASE, SSI_DMA_RX | SSI_DMA_TX); MAP_SSIDMAEnable(SSI1_BASE, SSI_DMA_RX | SSI_DMA_TX); // Setup the SSI1 DMA interrupts. MAP_SSIIntEnable(SSI1_BASE, SSI_DMARX); //MAP_SSIIntEnable(SSI1_BASE, SSI_DMATX); // commenting this out because as soon as I enable this, interrupt goes off MAP_SSIIntDisable(SSI1_BASE, SSI_DMATX); // From errata: SSI must be initialized with SSICR1.EOT bit clear. HWREG(SSI1_BASE + SSI_O_CR1) &= ~(SSI_CR1_EOT); // Enable QSSI MAP_SSIEnable(SSI1_BASE); // Enable the SSI1 peripheral interrupts. //MAP_IntEnable(INT_SSI1); }
As you can see, I have to comment out MAP_SSIIntEnable(SSI1_BASE, SSI_DMATX). I have tried re-enabling it in my main thread when I need to actually start the transfer, which looks like this:
FBB_RETURN_CODE GetSpiLine(Uint16* destinationBuffer) { uint32_t bytesRead = 0; // Start a DMA transfer to SSII TX. MAP_uDMAChannelTransferSet(UDMA_CHANNEL_SSI1TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8TxBuf, (void *)SSI1_BASE, sizeof(g_ui8TxBuf)); // The uDMA TX channel must be enabled. MAP_uDMAChannelEnable(UDMA_CHANNEL_SSI1TX); MAP_SSIIntEnable(SSI1_BASE, SSI_DMATX); while (bytesRead < TOTAL_BYTES_PER_LINE) { //process data here } MAP_uDMAChannelDisable(UDMA_CHANNEL_SSI1TX); MAP_SSIIntDisable(SSI1_BASE, SSI_DMATX); return FBB_SUCCESS; }
and my TX/RX buffers and dmaControlTable initialization looks like this:
#define SSI1_TXBUF_SIZE 1024 #define SSI1_RXBUF_SIZE 1024 #pragma DATA_SECTION(dmaControlTable, "extram_alloc") #pragma DATA_ALIGN(dmaControlTable, 1024) uint8_t dmaControlTable[1024]; // The transmit and receive buffers used for the SSI1 transfers. // One transmit buffer and a pair of ping-pong receive buffers #pragma DATA_SECTION(g_ui8TxBuf, "extram_alloc") uint8_t g_ui8TxBuf[SSI1_TXBUF_SIZE]; #pragma DATA_SECTION(g_ui8RxBufA, "extram_alloc") uint8_t g_ui8RxBufA[SSI1_RXBUF_SIZE]; #pragma DATA_SECTION(g_ui8RxBufB, "extram_alloc") uint8_t g_ui8RxBufB[SSI1_RXBUF_SIZE];
I think it is important to note that I am registering my interrupt handler via my project .cfg file and adding an instance under the Hwi module with the SSI1IntHandler with interrupt number 50. I have tried both basic mode and burst for both TX and RX. Thank you anyone for your help/input.