Tool/software: TI-RTOS
Hi,
Code:
void task()
{
DmaInit()
While(1){
Semaphore_pend();
}
}
void DmaInit(){
SPIRX(); //in ping pong mode
SPITX(); //in ping pong mode
SPIDMAInterrupt(); //dma tx and rx interrupt;
}
IniHandler(){
//ping pong reconfigure for tx and rx
count++;
semaphore_post();
}
int main()
{
Task_init();
return 0;
}
The above is the outline of the code and the device configured as slave device.
The problem I am getting is I cannot post a semaphore inside the SPI dma handler.
Each ping and pong buffer size is 64 bytes. if I send minimum to 128bytes of data, the semaphore post working fine.
if I send more than 128 bytes(adding ping and pong) I am getting the below error.
assertion failure: A_overflow: Count has exceeded 65535 and rolled over.
xdc.runtime.Error.raise: terminating execution
The error says that the semaphore post is keep on posting, but if I disable the semaphore post and check the count value is giving 2 multiples each time I initiate a transfer.
That means without semaphore post, N number of data's are received and transmitted.
Question:
1. Why after posting semaphore post, the above error is triggering?
2.Once the semaphore post is enabled, the count value is also incrementing N times. But without semaphore, it increasing in multiples of 2.
which means that working fine.
3. Can you give any suggestions to handle the DMA received data's in ping and pong buffers.
I have attached the code for reference.
/* * analog_input.c * * Created on: 14-Jul-2017 * Author: Balasubramani.C */ #include <ioc_main.h> #define SSI_TXBUF_SIZE 1024 #define SSI_RXBUF_SIZE 64 uint8_t pui8ControlTable[1024]; uint8_t ui8DMATxBufferpri[SSI_TXBUF_SIZE]; uint8_t ui8DMATxBufferalt[SSI_TXBUF_SIZE]; uint8_t ui8DMAPrimary_Buffer[SSI_RXBUF_SIZE]; uint8_t ui8DMASecondary_Buffer[SSI_RXBUF_SIZE]; uint8_t ui8SendBuf[SSI_TXBUF_SIZE]; uint8_t ui8ReceivedBuf[SSI_RXBUF_SIZE]; uint32_t ui8counter = 0; uint32_t receivebuffCount = 0; uint32_t receiveadded[2]; //***************************************************************************** // // The interrupt handler for uDMA errors. This interrupt will occur if the // uDMA encounters a bus error while trying to perform a transfer. This // handler just increments a counter if an error occurs. // //***************************************************************************** void uDMAErrorHandler(void) { uint32_t ui32Status; // // Check for uDMA error bit // ui32Status = uDMAErrorStatusGet(); // // If there is a uDMA error, then clear the error and increment // the error counter. // if(ui32Status) { uDMAErrorStatusClear(); } } /** ******************************************************************************* * @file analog_input.c * @ingroup analog_input * * @handler ioc_RxBufferProcessing(uint8_t *ui8buffer) * * @brief * This function will get a buffer from the task and add the entire * buffer data's and print in the CCS console. This function is used * to verify the received data to SPI DMA. * * @param ui8buffer Pointer to array * * @return NULL * ******************************************************************************/ uint32_t ioc_RxBufferProcessing(uint8_t *ui8buffer) { uint8_t i; uint32_t ui32AddedData = 0; for(i = 0; i < SSI_RXBUF_SIZE; i++) { ui32AddedData = ui32AddedData + *(ui8buffer+i); } return ui32AddedData; // System_printf("Added received data : %d\n", ui32AddedData); // System_flush(); } /** ******************************************************************************* * @file analog_input.c * @ingroup analog_input * * @handler AnalogInputADCISRHandler(void) * * @brief * This ISR will be invoked from DMA interrupt whenever DMA data * buffer gets filled by analog input channel data. It will * generate SPI DMA interrupt for processing analog input data. * Interrupt source vector number TBD * depend on Hardware design document. * To validate this ISR handler in Eval Board, currently vector * number 23 is assigned as interrupt source. * * @param NULL * * @return NULL * ******************************************************************************/ uint32_t ulMode; uint32_t ui32Status; uint32_t ui32IntStatus; void AnalogInputADCISRHandler(void) { // // Read the interrupt status of the SSI. // ui32Status = SSIIntStatus(SSI0_BASE, TRUE); SSIIntClear(SSI0_BASE, ui32Status); ui32IntStatus = SSIIntStatus(SSI0_BASE, FALSE); // *(volatile uint32_t *)(SSI0_BASE + SSI_O_ICR) = SSI_DMARX; /* if((uiInt32Status & SSI_RXFF) && (!uDMAChannelIsEnabled(UDMA_CHANNEL_SSI0RX))){ uDMAChannelEnable(UDMA_CHANNEL_SSI0RX); uDMAChannelEnable(UDMA_CHANNEL_SSI0TX); } */ // // Clear any pending status, even though there should be none since no SSI // interrupts were enabled. If SSI error interrupts were enabled, then // those interrupts could occur here and should be handled. Since uDMA is // used for both the RX and TX, then neither of those interrupts should be // enabled. // if(ui32Status & SSI_DMARX) { SSIIntClear(SSI0_BASE, SSI_DMARX); //check primary Rx channel ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT); if(ulMode == UDMA_MODE_STOP) { memcpy(ui8ReceivedBuf, ui8DMAPrimary_Buffer, SSI_RXBUF_SIZE); uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), ui8DMAPrimary_Buffer, sizeof(ui8DMAPrimary_Buffer)); } //check Alternate Rx channel ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT); if(ulMode == UDMA_MODE_STOP) { memcpy(ui8ReceivedBuf, ui8DMASecondary_Buffer, SSI_RXBUF_SIZE); uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), ui8DMASecondary_Buffer, sizeof(ui8DMASecondary_Buffer)); } ui8counter++; /* receiveadded[receivebuffCount] = ioc_RxBufferProcessing(ui8ReceivedBuf); receivebuffCount++; */ // if(ui8counter % 8 == 0){ // receivebuffCount = 0; Semaphore_post(Sem_dma_Handle); // } } if(ui32Status & SSI_DMATX) { SSIIntClear(SSI0_BASE, SSI_DMATX); //check primary Tx channel ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT); if(ulMode == UDMA_MODE_STOP) { GPIO_toggle(Board_LED0); uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, ui8DMATxBufferpri, (void *)(SSI0_BASE + SSI_O_DR), sizeof(ui8DMATxBufferpri)); } //check alternate Tx channel ulMode = uDMAChannelModeGet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT); if(ulMode == UDMA_MODE_STOP) { GPIO_toggle(Board_LED1); uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, ui8DMATxBufferalt, (void *)(SSI0_BASE + SSI_O_DR), sizeof(ui8DMATxBufferalt)); } } // TODO memcopy from DMA buffer to Analog input processing buffer } /* void DmaTxSwi() { } void DmaRxSwi() { ui8counter++; receiveadded[receivebuffCount] = ioc_RxBufferProcessing(ui8ReceivedBuf); receivebuffCount++; if((ui8counter % 4) == 0) { receivebuffCount = 0; Event_post(Event_ADC_ISR_Handler, Event_Id_00); } }*/ /** ******************************************************************************* * @file analog_input.c * @ingroup analog_input * * @handler ioc_DmaAdcInit(void) * * @brief * This function will initialize the SPI0 as DMA peripheral * Create the control table for both Tx and Rx in Ping Pong mode * to have a continuous data flow. * * @param NULL * * @return NULL * ******************************************************************************/ void ioc_DmaAdcInit(void) { uint16_t ui8Idx = 0; uint8_t i = 0; // // Fill the TX buffer with a simple data pattern. // for(ui8Idx = 0; ui8Idx < SSI_TXBUF_SIZE; ui8Idx++) { if((ui8Idx % 64) != 0) { ui8SendBuf[ui8Idx] = i+1; i++; } else { i = 0; ui8SendBuf[ui8Idx] = i+1; i++; } } memcpy(ui8DMATxBufferpri, ui8SendBuf, SSI_TXBUF_SIZE); memcpy(ui8DMATxBufferalt, ui8SendBuf, SSI_TXBUF_SIZE); /* SSI 0 Configuration */ SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI0); // // Configure the SSI communication parameters. // SSIConfigSetExpClk(SSI0_BASE, 120000000 /* SysCtlClockGet() */, SSI_FRF_MOTO_MODE_0, SSI_MODE_SLAVE, 4000000, 8); // // Enable the SSI for operation, and enable the uDMA interface for both TX // and RX channels. // SSIEnable(SSI0_BASE); SSIDMAEnable(SSI0_BASE, SSI_DMA_TX | SSI_DMA_RX ); SSIClockSourceSet(SSI0_BASE, SSI_CLOCK_SYSTEM); IntEnable(INT_UDMAERR); IntRegister(INT_UDMAERR, uDMAErrorHandler); // // Enable the SSI peripheral, and configure it to operate even if the CPU // is in sleep. // SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA); // // Enable the uDMA controller. // uDMAEnable(); // // Point at the control table to use for channel control structures. // uDMAControlBaseSet(pui8ControlTable); // // Put the attributes in a known state for the uDMA SSI1RX channel. These // should already be disabled by default. // uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX,UDMA_ATTR_USEBURST | UDMA_ATTR_REQMASK ); uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX, (UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | UDMA_ATTR_REQMASK)); // uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0RX,UDMA_ATTR_USEBURST ); // uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0RX,UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST ); // // Configure the control parameters for the primary control structure for // the SSI RX channel. The primary contol 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 4 to match the RX FIFO trigger threshold. // The uDMA controller will use a 4 byte burst transfer if possible. This // will be somewhat more effecient that single byte transfers. // uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); // // Set up the transfer parameters for the SSI RX primary control // structure. The mode is set to ping-pong, the transfer source is the // SSI data register, and the destination is the receive "A" buffer. The // transfer size is set to match the size of the buffer. // uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), ui8DMAPrimary_Buffer, sizeof(ui8DMAPrimary_Buffer)); // // Configure the control parameters for the alternate control structure for // the SSI RX channel. The alternate contol structure is used for the "B" // part of the ping-pong receive. The configuration is identical to the // primary/A control structure. // uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); // // 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. // uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(SSI0_BASE + SSI_O_DR), ui8DMASecondary_Buffer, sizeof(ui8DMASecondary_Buffer)); // // Put the attributes in a known state for the uDMA SSI1RX channel. These // should already be disabled by default. // uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX,UDMA_ATTR_USEBURST | UDMA_ATTR_REQMASK ); uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX, (UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | UDMA_ATTR_REQMASK)); // uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX,UDMA_ATTR_USEBURST ); // uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX,UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST ); // // Configure the control parameters for the SSI 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 8-bit bytes // since the data is coming from a buffer. The destination increment is // none since the data is to be written to the SSI data register. The // arbitration size is set to 4, which matches the SSI TX FIFO trigger // threshold. // uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4); // // 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. // uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, ui8DMATxBufferpri, (void *)(SSI0_BASE + SSI_O_DR), sizeof(ui8DMATxBufferpri)); // // Configure the control parameters for the SSI 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 8-bit bytes // since the data is coming from a buffer. The destination increment is // none since the data is to be written to the SSI data register. The // arbitration size is set to 4, which matches the SSI TX FIFO trigger // threshold. // uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4); // // 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. // uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, ui8DMATxBufferalt, (void *)(SSI0_BASE + SSI_O_DR), sizeof(ui8DMATxBufferalt)); // // Now both the uDMA SSI TX and RX channels are primed to start a // transfer. As soon as the channels are enabled, the peripheral will // issue a transfer request and the data transfers will begin. // uDMAChannelEnable(UDMA_CHANNEL_SSI0RX); uDMAChannelEnable(UDMA_CHANNEL_SSI0TX); // // Enable the SSI DMA TX/RX interrupts. // SSIIntEnable(SSI0_BASE, SSI_DMARX | SSI_DMATX); } /** ******************************************************************************* * @file analog_input.c * @ingroup analog_input * * @task AnalogInputProcessingFunc() * * @brief * This task will be invoked from DMA ISR handler for processing * analog input channel data. This will apply median and CIC filter * depending upon the configurable median/CIC filter value and * store output values into analog input local buffer. * * @param NULL * * @return NULL * ******************************************************************************/ void AnalogInputProcessingFunc() { #ifdef DMA_ADC_TEST ioc_DmaAdcInit(); #endif while(1) { // Event_pend(Event_ADC_ISR_Handler, Event_Id_00, Event_Id_NONE, // BIOS_WAIT_FOREVER); Semaphore_pend(Sem_dma_Handle, BIOS_WAIT_FOREVER); System_printf("Post count %d\n", ui8counter); System_flush(); IOC_DEBUG_APP("In Analog Input Processing task\n"); IOC_DEBUG_APP_FLUSH(); // TODO Memcopy from DMA buffer to Analog input processing buffer // TODO Median Filter/ CIC filter implementation /* event post for task monitor task */ //Event_post(Event_Task_Monitor, Event_Id_00); } }
Below is the snapshot of receiving 256 bytes of data with 64bytes of ping pong buffer, with disabling the semaphore_post in ISR function. The count is captured in Expression in runtime.
Below is the snapshot of Enabling the samephore_post in same code inside ISR
Regards,
Manohar