[quote user="Robert Adsett"]Maybe time for uDMA?
More complex to set up[/quote]As an example modified the code to use uDMA. Had to add some buffers:
// Buffer used to transmit by DMA one LED module refresh uint32_t ledModuleDMATxBuffer[NUM_LED_MODULES]; //***************************************************************************** // // The control table used by the uDMA controller. This table must be aligned // to a 1024 byte boundary. // //***************************************************************************** #if defined(ewarm) #pragma data_alignment=1024 uint8_t ui8ControlTable[1024]; #elif defined(ccs) #pragma DATA_ALIGN(ui8ControlTable, 1024) uint8_t ui8ControlTable[1024]; #else uint8_t ui8ControlTable[1024] __attribute__ ((aligned(1024))); #endif
The initialisation code changed to:
MAP_SysCtlPeripheralEnable (SYSCTL_PERIPH_UDMA); MAP_uDMAEnable(); MAP_uDMAControlBaseSet (ui8ControlTable); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // Initialise the SSI we will use for communication with the LED Matrix: // PB4 - SR_SCLK // PB5 - SR_LATCH // PB7 - SR_DATA MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2); MAP_GPIOPinConfigure(GPIO_PB4_SSI2CLK); MAP_GPIOPinConfigure(GPIO_PB5_SSI2FSS); MAP_GPIOPinConfigure(GPIO_PB7_SSI2TX); MAP_GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7); // Configure the hardware SSI module. // SSI_FRF_MOTO_MODE_3 is used so that the FSS is used to latch the data in the // display automatically at the end of the transfer. MAP_SSIClockSourceSet (SSI2_BASE, SSI_CLOCK_SYSTEM); MAP_SSIConfigSetExpClk (SSI2_BASE, MAP_SysCtlClockGet(), SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER, 4000000, 16); MAP_SSIEnable (SSI2_BASE); // Configure DMA to perform the SSI Tx so that a back-to-back transfer occurs with FSS asserted for the entire transfer MAP_SSIDMAEnable (SSI2_BASE, SSI_DMA_TX); MAP_uDMAChannelAssign (UDMA_CH13_SSI2TX); MAP_uDMAChannelControlSet (UDMA_CH13_SSI2TX, UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_NONE | UDMA_ARB_1); MAP_uDMAChannelTransferSet (UDMA_CH13_SSI2TX, UDMA_MODE_BASIC, ledModuleDMATxBuffer, (void *)(SSI2_BASE + SSI_O_DR), NUM_LED_MODULES);
And the code to generate one transmission changed to update the DMA Tx buffer and then trigger the DMA:
// Write update to DMA Tx buffer for (moduleIndex = 0; moduleIndex < NUM_LED_MODULES ; moduleIndex++) { ledModuleDMATxBuffer[moduleIndex] = (128 >> ledModuleColumnIndex) | (ledModuleData[bufferIndex][moduleIndex][ledModuleColumnIndex] << 8); } // Trigger a DMA Tx. As the update rate is slower than the time to transmit the buffer // don't wait for the Tx to complete. MAP_uDMAChannelTransferSet (UDMA_CH13_SSI2TX, UDMA_MODE_BASIC, ledModuleDMATxBuffer, (void *)(SSI2_BASE + SSI_O_DR), NUM_LED_MODULES); MAP_uDMAChannelEnable (UDMA_CH13_SSI2TX);
[quote user="Robert Adsett"]That's a trifle fragile. A good reason to avoid using FSS IMO. [/quote]Agree. With the uDMA used to perform the "back-to-back" transfers the SSI transmission "appears" to operate without any obvious glitches. However, as the SSI is just used to refresh a LED matrix if the FSS did de-assert during a transfer you wouldn't know unless happened to notice a "flicker" on the display.
The datasheet for a Tiva device states that:
[quote]When the uDMA controller arbitrates for the bus, the processor always takes priority. Furthermore, the uDMA controller is held off whenever the processor must perform a bus transaction on the same bus, even in the middle of a burst transfer.[/quote]It is not obvious if there are some conditions where the processor could prevent the uDMA controller from obtaining access to the bus for long enough to cause a SSI Tx to fail to perform a back-to-back transfer. I would be wary against using the back-to-back SSI with uDMA to implement a transfer which needed a reliable transfer without some idea of the available bus-bandwidth to the uDMA controller channel.