This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129 UART0 UDMA RX done is not triggering

Other Parts Discussed in Thread: TM4C129XNCZAD

Hi,

I'm using TM4C129XNCZAD evaluation board and I'm having trouble getting the UART0 UDMA RX done to trigger.

Rx interrupts is received and I"m able to schedule the UART0 Rx task that configures and starts the uDMA read. The data is read from the UART FIFO but I fail to get the UDMA RX done trigger so I can process the received data.

I checked my code against the demo code and I'm not able to see a difference that could explain the problem.

Could you please take a look at the attached code (removed all non essential sections) and let me know what I'm doing wrong?

thanks.

//define the uDMA control table
#if defined(ewarm)
#pragma data_alignment=1024
unsigned char ucControlTable[1024];
#elif defined(ccs)
#pragma DATA_ALIGN(ucControlTable, 1024)
tDMAControlTable ucControlTable[1024];
#else
unsigned char ucControlTable[1024] __attribute__ ((aligned(1024)));
#endif

OS_TID gTaskUART0Tx_ID;         //RS232 Tx Task ID
OS_TID gTaskUART0Rx_ID;         //RS232 Rx Task ID

uint8_t rxBuffer[100];			//RS232 received data
uint8_t txBuffer[100];			//RS232 transmit data

/**************************************************************************
**************************************************************************/
__task void taskInit(void) {
	gTaskUART0Tx_ID	= os_tsk_create(taskUART0Tx,		TASK_UART0_TX_PRIORITY);
	gTaskUART0Rx_ID	= os_tsk_create(taskUART0Rx,		TASK_UART0_RX_PRIORITY);
	os_tsk_delete_self();
}

/**************************************************************************
**************************************************************************/
__task void taskUART0Rx(void) {

	for( ; ; ) {

		//wait on the Rx event
		eventStatus = os_evt_wait_or(TASK_EVENT_RX_FLAG, 0xFFFF);

		transferSize = 100;
		uDMAChannelTransferSet(	UDMA_CHANNEL_UART0RX,
								UDMA_MODE_BASIC,
								(void *)(UART0_BASE + UART_O_DR),
								(void *) rxBuffer,
								transferSize);
		uDMAChannelEnable(UDMA_CHANNEL_UART0RX);
	}//forever loop
}
/**************************************************************************
**************************************************************************/
__task void taskUART0Tx(void) {

	for( ; ; ) {

		os_evt_wait_or(TASK_EVENT_TX_FLAG, 0xFFFF);

		transferSize = 100;
		uDMAChannelTransferSet(	UDMA_CHANNEL_UART0TX,
								UDMA_MODE_BASIC,
								(void *)txBuffer,
								(void *)(UART0_BASE + UART_O_DR),
								transferSize);
		uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
	}//forever loop
}

/**************************************************************************
**************************************************************************/
void SystemInit (void) {
	SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ);

	gSysCtlClock = SysCtlClockFreqSet(
						SYSCTL_USE_PLL    |
						SYSCTL_OSC_MAIN   |
						SYSCTL_XTAL_25MHZ |
						SYSCTL_CFG_VCO_480,
						120000000);		//desired system frequency
}

/**************************************************************************
**************************************************************************/
void GPIO_Init(void) {

	SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);	//Ethernet
	SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
	SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
	SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);	//RS232
	SysCtlPeripheralReset(SYSCTL_PERIPH_UART0);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA);

	//configure UART pins for RS232
	GPIOPinConfigure(GPIO_PA0_U0RX);	//RS232 Com 0 Rx
	GPIOPinConfigure(GPIO_PA1_U0TX);	//RS232 Com 0 Tx

	//for each function pin, select the type
	GPIOPinTypeUART(GPIO_PORTA_BASE,GPIO_PIN_0 |	//RS232 Com0 Rx
									GPIO_PIN_1);	//RS232 Com0 Tx
}
/**************************************************************************
**************************************************************************/
void uDMA_Init(void) {
    //set the control table
    uDMAControlBaseSet(ucControlTable);
    //enable uDMA
    uDMAEnable();
    //setup the uDMA interrupts
    IntEnable(INT_UDMA | INT_UDMAERR);
}
/**************************************************************************
**************************************************************************/
void UART0_Init(void) {

    UARTConfigSetExpClk(UART0_BASE,
                        gSysCtlClock,
                        UART0_BAUDRATE,
                        UART_CONFIG_WLEN_8   |
                        UART_CONFIG_STOP_ONE |
                        UART_CONFIG_PAR_NONE);

    //configure the fifo's trigger level.
    UARTFIFOEnable(UART0_BASE);
    UARTFIFOLevelSet(UART0_BASE,
                     UART_FIFO_TX4_8,   //4 words threshold
                     UART_FIFO_RX4_8);  //4 words threshold

    UARTDisableSIR(UART0_BASE);
    UARTEnable(UART0_BASE);
    UARTTxIntModeSet(UART0_BASE, UART_TXINT_MODE_EOT);
    UARTIntEnable(	UART0_BASE,
					UART_INT_TX |     //transmit done (flush the tx task)
					UART_INT_RX |     //Rx fifo level reached
					UART_INT_OE |     //overrun
					UART_INT_BE |     //break
					UART_INT_PE |     //parity
					UART_INT_FE |     //framing
					UART_INT_RT);     //receiver timeout
    IntEnable(INT_UART0);

    // Configure the uDMA for UART0 read and write
    UARTDMAEnable(UART0_BASE, UART_DMA_RX | UART_DMA_TX);
	uDMAChannelAssign(UDMA_CH8_UART0RX);
	uDMAChannelAssign(UDMA_CH9_UART0TX);

    uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0RX, UDMA_ATTR_ALL);
    uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_ALL);

//	uDMAChannelAttributeEnable(	UDMA_CHANNEL_UART0RX,
//								UDMA_ATTR_USEBURST);
	uDMAChannelAttributeEnable(	UDMA_CHANNEL_UART0TX,
								UDMA_ATTR_USEBURST);

    uDMAChannelControlSet(UDMA_CHANNEL_UART0RX,     //NBRFIFO
                          UDMA_SIZE_8        |      //data size
                          UDMA_SRC_INC_NONE  |      //no source address increment
                          UDMA_DST_INC_8     |      //destination address increment
                          UDMA_ARB_4);              //arbitration size
    uDMAChannelControlSet(UDMA_CHANNEL_UART0TX,     //WFIFO
                          UDMA_SIZE_8        |      //data size
                          UDMA_SRC_INC_8     |      //source address increment
                          UDMA_DST_INC_NONE  |      //no destination address increment
                          UDMA_ARB_4);              //arbitration size
}

/**************************************************************************
**************************************************************************/
void UART0_Handler(void) {        // A 16x12 bit receive FIFO

	uint32_t IntStatus;         //ISR status

	IntStatus = UARTIntStatus(UART0_BASE, true);
	UARTIntClear(UART0_BASE, IntStatus);

	//if its an Rx
	if(IntStatus & UART_INT_RX) {
		isr_evt_set(TASK_EVENT_RX_FLAG, gTaskUART0Rx_ID);
	} //if its an Rx interrupt

    //Check for Rx DMA done
    if(uDMAChannelModeGet(UDMA_CHANNEL_UART0RX) == UDMA_MODE_STOP) {

       	// CODE TO PROCESS THE rxBuffer CONTENT
    }

	//Check for Tx DMA done
	if(	(IntStatus & UART_INT_TX)	||
		(uDMAChannelModeGet(UDMA_CHANNEL_UART0TX) == UDMA_MODE_STOP)) {

		//CODE TO CLEAR THE txBuffer
    }
}


/**************************************************************************
**************************************************************************/
void main() {

	SystemInit();  					//system setup
	GPIO_Init();   					//setup GPIO
	uDMA_Init();   					//setup the uDMA
	UART0_Init(); 					//setup RS232

	os_sys_init(taskInit);
}

Khaled.

  • Hello Khaled,

    Which demo code are you referring to? Does this demo work without using the RTOS?

    Thanks,
    Sai
  • Hi,

    I was refering to udma_demo.c
     C:\ti\TivaWare_C_Series-2.1.2.111\examples\boards\dk-tm4c129x\udma_demo\udma_demo.c.

    After I sent my first e-mail, I tried different combination of uDMA arbitration sizes and UART fifo level trigger values.
     The behavior was not consistent. In some cases I get receiver Time out error (UART_INT_RT), in other cases I don't get the time out error. But it all cases, it never worked.

    Khaled.

  • Hi,
    I'm still working on the same problem and I noticed that if I send 2 messages back to back to the UART Rx fifo, I get both of them successfully.
    All is pointing to a problem with the UART FIFO trigger level but I'm not able to find what it is and how to fix it.
    Do you know of any issues related to the FIFO trigger level and uDMA?

    Khaled.
  • Hello Khaled,

    Sorry for my delay in response.

    khaled saab said:
    I'm using TM4C129XNCZAD evaluation board and I'm having trouble getting the UART0 UDMA RX done to trigger.

    Rx interrupts is received and I"m able to schedule the UART0 Rx task that configures and starts the uDMA read. The data is read from the UART FIFO but I fail to get the UDMA RX done trigger so I can process the received data.

    What do you mean by "UART0 UDMA RX" and "UDMA RX done trigger"? Do you mean the interrupt that should be generated when the transfer is complete? If yes then the "udma_demo" code already handles this part.

    You post is a little confusing, so taking a step back, here is what I understand so far. Please correct if I got it wrong.

    • You want to build an application that receives data over UART using uDMA.
    • As reference, you have used the TivaWare example "./examples/boards/dk-tm4c129x/udma_demo". 

    If yes, then were you able to use this demo successfully? Since you are using the DK-TM4C129x board (I got it from your first line of your first post), you should be able to run this example without any changes.

    I would recommend running the demo successfully and only then remove the unnecessary parts of the code.

    I understand that this demo uses the Software uDMA channel to do memory to memory transfer, which can be removed. At this point the "udam_demo" would have been modified to only use the uDMA in ping-pong mode for UART receive.

    Ensure that the modifications to this point are working fine before making any changes to the uDMA or UART configuration. Once you have a code working with all the necessary configuration, only then start using the RTOS/OS.

    Thanks,

    Sai

  • Hi Sai,
    Yes you are correct in your understanding of the problem: I want to receive data over UART using uDMA.
    and Yes I have the uDMA_demo running.
    and Yes I used the uDMA_demo to build my code by removing the loop back and the software uDMA channel to do memory to memory.

    At this point, I got it to work intermittently. There is a problem with the number o bytes received by the UART FIFO and how many bytes are transferred by the uDMA engine.

    My obervation:
    If the UART FIFO receive a single message, the uDMA done interrupt doesn't trigger.
    If the UART FIFO receive 2 messages back to back, the uDMA done interrupt triggers and both messages are received properly.

    As far as I can tell, its an issue with the arbitration size vs the fifo trigger level!
    I checked my code 100 times and I don't see a code problem. I was hoping that you could take a look and point me to the solution.

    thanks.
    Khaled.
  • Hello Khaled,

    I still don't understand what you mean by "uDMA done interrupt" (I asked this question in my previous post too). Which specific interrupt are you waiting for? Is that interrupt enabled in the code? How is it different from what is already present in "uDMA_demo" example?

    If there is a problem with FIFO level trigger, would not the "uDMA_demo" example that configures the UART for internal loopback have the same issue?

    Have you changed the arbitration size? I would recommend not modifying the the UART and uDMA configuration from what is provided in the uDMA_demo code until you have a working code.

    The code you have provided has snippets of RTOS and that adds additional complexity. Best to first test/debug code that is not using RTOS. I would again recommend modifying the "uart_echo" example (instead of writing your own code from scratch), atleast till the debug is complete, as it will help in reviewing the code sooner.

    Thanks,
    Sai
  • Hi Sai,
    I want to test if(uDMAChannelModeGet(UDMA_CHANNEL_UART0RX) == UDMA_MODE_STOP) but the UART0_Handler( ) is not being called.

    The uDMA_demo has a loopback, the data is STREAMED and the data length is fixed. In my case, the message are of variables sizes and the size of the first message that I receive from the PC is of specific size (I have little control on it right now) that I'm not able to receive in full unless if I send a second message right after it i.e. 2 messages back to back.

    As for the arbitration size, the uDMA_demo.c uses 2 different arbitration sizes (UDMA_ARB_8 and UDMA_ARB_4). In my case I'm using UDMA_ARB_4 only.

    I'm using RTOS, but I stripped it out of the code that I have sent to you to make it more compact.

    COULD YOU PLEASE TAKE A LOOK at the code that I have sent? There is no point in telling me to go back and check against the examples that are provided by TI. I already done that many time and the code that I have is working IF I SEND 2 MESSAGES BACK TO BACK.

    thanks.
    Khaled.
  • Hello Sai,
    Not to be pushy, but time is in short supply. Did you have time to take a look at the code?
    thanks.
    Khaled.
  • Hi Sai,

    Your silence is disturbing. Are you still supporting me on this problem?

    I'm still working on this issue and I found the following comment:

    "If you only send one character, then the RX interrupt will never fire, since the FIFO will never achieve 1/8 full, but the RT interrupt will fire 22 bit times after receiving that character."

    Could this explain the problem that I'm having? and if yes, how should I modify the code to get over it?

    thanks.

    Khaled.

  • We seem to have a rash of people invoking DMA complexity w/o appearing to have a need for it.

    khaled saab said:

    I'm still working on this issue and I found the following comment:

    "If you only send one character, then the RX interrupt will never fire, since the FIFO will never achieve 1/8 full, but the RT interrupt will fire 22 bit times after receiving that character."

    If you are only sending single characters why on earth would you even consider adding DMA to the mix? At the size of transmission and reception you are suggesting DMA is probably a net loss compared with interrupts.

    Do you have this working with interrupts? What baud rate are you operating at? how large are you packets? How frequently do they occur?

    Robert

  • Hi Robert,
    Thanks for getting back to me so quickly.

    I'm not sending a single character. The messages could be of variable length and could be up to 1000Bytes long.
    I have it working with interrupts, baud rate is 19200 and there is no set time between the frames.

    In my test it happens that the frame is 42Bytes.
    If I send a single frame, the UART0_Handler( ) is not triggering at the end of the frame.
    If I send 2 messages back to back, the UART0_Handler( ) is triggering and I'm able to retrieve BOTH messages.

    On passible explanation, is that the data is in the UART RX FIFO, but its not retrieved by the uDMA engine.
    This got me to think that there could be an issue synchronizing the UART FIFO trigger level with the uDMA Arbitration size. That where this comment about the single character comes into play.
    I change every single parameter that I could think of in order to get that last byte with no success.

    Khaled.
  • Hi Robert,
    Thanks for getting back to me so quickly.

    I'm not sending a single character. The messages could be of variable length and could be up to 1000Bytes long.
    I have it working with interrupts, baud rate is 19200 and there is no set time between the frames.

    In my test it happens that the frame is 42Bytes.
    If I send a single frame, the UART0_Handler( ) is not triggering at the end of the frame.
    If I send 2 messages back to back, the UART0_Handler( ) is triggering and I'm able to retrieve BOTH messages.

    On passible explanation, is that the data is in the UART RX FIFO, but its not retrieved by the uDMA engine.
    This got me to think that there could be an issue synchronizing the UART FIFO trigger level with the uDMA Arbitration size. That where this comment about the single character comes into play.
    I change every single parameter that I could think of in order to get that last byte with no success.

    Khaled.

  • khaled saab said:
    I have it working with interrupts, baud rate is 19200

    Good, and that's a reasonable low baud rate

    khaled saab said:
    The messages could be of variable length and could be up to 1000Bytes long.

    So worst case interrupt load is around 125 interrupts at 240Hz or about 4mS period. Interrupt load should not be an issue

    We are left with my remaining question. Why do you need DMA? I see no advantage and you've already seen that it's far more complex.

    Just because a feature exists does not mean you are compelled to use it.

    Robert

  • Robert,
    When I said that I have it working with interrupts, I meant partially working with uDMA interrupts: I'm not able to receive a single message. I have to send 2 messages back to back so that the UART0_Handler( ) triggers so I can process both messages. This is not good enough for me.
    I did not implement the FIFO interrupt without the uDMA version.

    Now why I would like to have uDMA, because it will relieve the CPU from all of those interrupts. More than 50% of the time, the CPU will be close to max usages. Every bit count. So if this feature is available, I would like to use it.
    In addition, most of the uDMA code is working. As I have mentioned it works if I send 2 messages back to back. In addition, Ihave working on the Cortex M3 (LM3S9B96). Its not rocket science. But I'm missing something and I need your help to figure it out.

    Khaled.
  • khaled saab said:
    When I said that I have it working with interrupts, I meant partially working with uDMA interrupts: I'm not able to receive a single message.

    Oh-Oh back to my worst case assumptions. Get it working with interrupts first. Then measure the overhead. Only then consider DMA if and only if the extra complexity can be justified. Given what you've shown so far I expect DMA gains to be a round-off error.

    khaled saab said:
    Now why I would like to have uDMA, because it will relieve the CPU from all of those interrupts.

    You've replaced interrupt overhead with DMA overhead. The DMA will steal processor time but it will be harder to measure. The extra setup costs of DMA are measureable at least.

    khaled saab said:
    More than 50% of the time, the CPU will be close to max usages. Every bit count

    I don't think it's likely DMA will be a significant enough gain to matter. If you are that close you have bigger problems and need to really think hard about your processing.

    Robert

  • Robert,
    There is no point pitching the vertues of using interrupts. My mind is set to go with uDMA even if its a wash.
    I need help figuring out why UART0_Handler is triggering (uDMA Rx done) when I send 2 messages back to back and its not working when a single message is send.
    Are you going to help me out or not?
    Khaled.
  • Robert,
    I was thinking more about using the interrupt and concluded that, to read 1000Bytes, it will not take 125 interrupt, it will take 1000 interrupts. The reason is that I will have to set the FIFO trigger level to 1Byte to read every last Byte.

    Even if I go with 1000 interrupt, another problem will need to be addressed: the UART FIFO has a 1/8th threshold which equate to 2Bytes minimum threshold (16Byte FIFO depth).
    All to say that using interrupt is not a better solution than using uDMA.

    Khaled.
  • khaled saab said:
    I was thinking more about using the interrupt and concluded that, to read 1000Bytes, it will not take 125 interrupt, it will take 1000 interrupts. The reason is that I will have to set the FIFO trigger level to 1Byte to read every last Byte.

    No, not true. But more later when I've a little time.

    Robert

  • Hello Khaled,

    khaled saab said:
    Your silence is disturbing. Are you still supporting me on this problem?

    In my previous post, I asked a number of questions and recommended using the "udma_demo" example as the base project and change the bare minimum required configuration for UART and uDMA. I did not see any follow-up on my recommendations. Also I did not see any reply to the following question, that I asked in one of my previous post.

    Stellaris Sai said:
    Which specific interrupt are you waiting for? Is that interrupt enabled in the code? How is it different from what is already present in "uDMA_demo" example?

    I think I am able to modify the "udam_demo" (like I recommended) to cover your use case. I followed the steps below:

    • Removed unnecessary code blocks like
      • Code related to the Software uDMA channel configuration that does the memory to memory transfer (including the interrupt handler in startup file)
      • The CPU usage logic along with the function call ROM_SysCtlSleep().
    • Modified the code to run forever, instead of just 10 seconds.
    • Modified UART configuration to
      • Configure UART0 in internal loopback mode. Now UART0 can communicate over the "Debug" port on the DK-TM4C129X board.
      • Interrupt on an event on uDMA RX channel using the macro "UART_INT_DMARX".

    • Modified the uDMA configuration to
      • Allow uDMA operation only on the UART RX channel. Removed all code related to UART TX channel configuration, including the Interrupt handler.
    • Build and run the application.

    For test, I placed a break point in the ISR. Then, open a terminal window, with the necessary UART configuration and sent a file of 512 bytes. I do get an interrupt.

    Then I removed the breakpoint and restarted the test, that is restart code and using a terminal window, send files of varying length (from 512 bytes to 5KB). On the display on the DK-TM4C129X", I can see the "uDMA UART Transfers" value changing (from 0) each time I send a file. The code in the while(1) can be modified to better handle the received data. But this test demonstrates that the uDMA UART RX is generating the interrupt and receiving data.

    Thanks,

    Sai

  • khaled saab said:
    There is no point pitching the vertues of using interrupts. My mind is set to go with uDMA even if its a wash.

    I rather suspect a wash is the best case scenario.

    Have you considered how to handle missing or added serial characters?  They will occur and are relatively transparently handled with interrupts but DMA runs on fixed sized transfers.

    Robert

  • khaled saab said:
    I was thinking more about using the interrupt and concluded that, to read 1000Bytes, it will not take 125 interrupt, it will take 1000 interrupts. The reason is that I will have to set the FIFO trigger level to 1Byte to read every last Byte.

    I take it you've not used UARTs much (or at all) previously? Receive FIFOs have a receive timeout for this very reason. Unfortunately TI's implementation separates that from the receive interrupt (for no good reason that I can see). If you respond to that just as you do the a receive interrupt you will get all the characters and not need many interrupts.

    A quick back of the envelope calculation shows with a 16 bytes FIFO, 7/8's Receive level trigger, 1000 byte packet --> 72 interrupts. I'd estimate around 0.5uS for the copy per interrupt, maybe 1uS. Assuming you are using the FPU you can add 0.4uS for interrupt entry and similar for exit for a total per interrupt of 1.3uS. Round that up to 3uS per interrupt so 72 interrupts takes 216uS in overhead. The transmit time of 1000bytes at 19.2kbaud is a little over 0.5s.  So the expected percentage of time spent in interrupt overhead is 216uS/0.5s --> < 0.05%. And that's assuming you have to do all of your processing while the packet is being received.

    Even if DMA took zero time it will make no difference to your performance.

    Robert

  • Hello Sai,

    Could you send me that code?

    thanks.

    Khaled.

  • Hello Robert,

    As I mentioned before, my mind is set on using uDMA and I'm not going back unless if there is no way in fixing that bug.

    And Yes I have used the UART many times before even with uDMA on the Cortex M3 and its working. All what I want to do is to port the code from the CortexM3 to the CortexM4 with a little modification as possible to minimize the FUTURE code support.

    I'm aware of the URART RT timeout, and I'm currently using it to get that last byte out of the UART FIFO. That is why I put that note: "If you only send one character, then the RX interrupt will never fire, since the FIFO will never achieve 1/8 full, but the RT interrupt will fire 22 bit times after receiving that character."

    But this is puting extra delay of several seconds on the HOST side. Initially I was thinking that 22 bit time should delay the Host by few msec, but I'm getting seconds in delay and its too much.

    All to say, that I want that uDMA to work and even if its a wash now, it might give me some benefit if the customer want higher baud rate.

    This piece of code took a lot of my time and it should have been a simple strait forward "copy" of the CortexM3 code that I already have!!!!!!!

    Khaled.

  • khaled saab said:
    And Yes I have used the UART many times before .... I'm aware of the URART RT timeout, and I'm currently using it to get that last byte out of the UART FIFO.

    khaled saab said:
    I was thinking more about using the interrupt and concluded that, to read 1000Bytes, it will not take 125 interrupt, it will take 1000 interrupts. The reason is that I will have to set the FIFO trigger level to 1Byte to read every last Byte.

    Hopefully you can see why I find those two statements contradictory.

    khaled saab said:
    But this is puting extra delay of several seconds on the HOST side. Initially I was thinking that 22 bit time should delay the Host by few msec, but I'm getting seconds in delay and its too much.

    Wait, I thought you said you didn't have an interrupt version working. BTW I can confirm the receive timeout works as advertised, seconds are not required.

    khaled saab said:
    And Yes I have used the UART many times before even with uDMA on the Cortex M3 and its working

    I'm curious, how do you deal with missing and extra characters?

    khaled saab said:
    This piece of code took a lot of my time

    That's the sunk cost fallacy. You should always be on guard against it. It's a very easy trap.

    Even if you remain stuck on DMA there is a lot to be said for getting an interrupt version running. It may give you insight and having a backup is not a bad idea. Of course some people avoid backtracking and doing something simpler for just that reason. If the simple approach works they lose an argument to continue with the more complicated approach they've become emotionally invested in.

    Robert

  • Robert,

    I'm not getting any help from you. I'm wasting your time and mine! Most likely you would have found the problem by now instead of lecturing me on the how bad the uDMA is and how its beyond my capacity to understand it and get to work!!!!!!!

    But a quick responses: 1) the M3 has 8Bytes FIFO and 1/8 of the FIFO correspond to 1Byte. I believe that is why it worked. 2) I got to work using RT interrupt instead of uDMA done interrupt. This cause several seconds latency on the Host side. I did not try to understand why, I wanted to see if I can solve it without using the RT interrupt.

    Thanks for all of your advices.

    Khaled.

  • Hello Sai,

    Could you send me the UART code that you have modified?

    thanks.

    Khaled.

  • Actually, I did provide a solution. I am using the solution myself without any ill-effect so far noted. You just don't like it even though it solves your problem. And BTW, I never said uDMA was beyond your capacity.

    As far as wasting my time, it's a way of paying back the help I've had in the past and learning from other experiences. If you share your method of dealing with extra and missing characters when using DMA with a UART my time spent will be more than paid back.

    Robert
  • I found the problem: uDMA was triggering but I had too many receiver timeout (RT) interrupts coming in and I got stuck in the UART0_HANDLER( ) servicing all of the RT interrupts.

    The fix was to call UARTDMAEnable( ) AFTER the uDMA has been setup and call UARTDMADisable( ) after we are done receiving the data.

    I have attached a skeleton code in case anyone has to solve similar problem in the future.

    Khaled.

    //define the uDMA control table
    #if defined(ewarm)
    #pragma data_alignment=1024
    unsigned char ucControlTable[1024];
    #elif defined(ccs)
    #pragma DATA_ALIGN(ucControlTable, 1024)
    tDMAControlTable ucControlTable[1024];
    #else
    unsigned char ucControlTable[1024] __attribute__ ((aligned(1024)));
    #endif
    
    OS_TID gTaskUART0Tx_ID;         //RS232 Tx Task ID
    OS_TID gTaskUART0Rx_ID;         //RS232 Rx Task ID
    
    uint8_t rxBuffer[100];			//RS232 received data
    uint8_t txBuffer[100];			//RS232 transmit data
    
    #define UART_STATE_IDLE		1
    #define UART_STATE_START	2
    #define UART_STATE_STOP		3
    /**************************************************************************
    **************************************************************************/
    __task void taskInit(void) {
    	gTaskUART0Tx_ID	= os_tsk_create(taskUART0Tx,		TASK_UART0_TX_PRIORITY);
    	gTaskUART0Rx_ID	= os_tsk_create(taskUART0Rx,		TASK_UART0_RX_PRIORITY);
    	os_tsk_delete_self();
    }
    
    /**************************************************************************
    **************************************************************************/
    __task void taskUART0Rx(void) {
    
    	uint16_t state = UART_STATE_IDLE;
    
    	for( ; ; ) {
    
    		//wait on the Rx event
    		eventStatus = os_evt_wait_or(TASK_EVENT_RX_FLAG, 0xFFFF);
    
    		//get the number of bytes to read.
    		if(state == UART_STATE_IDLE) {
    			transferSize = 100;		//hard coded
    			state = UART_STATE_START;
    		}
    
    		if(state == UART_STATE_START) {
    			uDMAChannelTransferSet(	UDMA_CHANNEL_UART0RX,
    									UDMA_MODE_BASIC,
    									(void *)(UART0_BASE + UART_O_DR),
    									(void *) rxBuffer,
    									transferSize);
    			uDMAChannelEnable(UDMA_CHANNEL_UART0RX);		//enable channel
    			UARTDMAEnable(UART0_BASE, UART_DMA_RX);			//start uDMA
    			state = UART_STATE_STOP;
    		}
    		
    		else if(state == UART_STATE_STOP) {
    			UARTDMADisable(UART0_BASE, UART_DMA_RX);		//stop uDMA
    			state = UART_STATE_IDLE;
    
    			// CODE TO PROCESS THE rxBuffer CONTENT
    		}
    	}//forever loop
    }
    /**************************************************************************
    **************************************************************************/
    __task void taskUART0Tx(void) {
    	uint16_t state = UART_STATE_IDLE;
    
    	for( ; ; ) {
    
    		os_evt_wait_or(TASK_EVENT_TX_FLAG, 0xFFFF);
    
    		//get the number of bytes to read.
    		if(state == UART_STATE_IDLE) {
    			transferSize = 100;		//hard coded
    			state = UART_STATE_START;
    		}
    		if(state == UART_STATE_START) {
    			uDMAChannelTransferSet(	UDMA_CHANNEL_UART0TX,
    									UDMA_MODE_BASIC,
    									(void *)txBuffer,
    									(void *)(UART0_BASE + UART_O_DR),
    									transferSize);
    			uDMAChannelEnable(UDMA_CHANNEL_UART0TX);		//enable channel
    			UARTDMAEnable(UART0_BASE, UART_DMA_TX);			//start uDMA
    			state = UART_STATE_STOP;
    		}
    		else if(state == UART_STATE_STOP) {
    			UARTDMADisable(UART0_BASE, UART_DMA_TX);		//stop uDMA
    			state = UART_STATE_IDLE;
    
    			//CODE TO CLEAR THE txBuffer
    		}
    	}//forever loop
    }
    /**************************************************************************
    **************************************************************************/
    void SystemInit (void) {
    	SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ);
    
    	gSysCtlClock = SysCtlClockFreqSet(
    						SYSCTL_USE_PLL    |
    						SYSCTL_OSC_MAIN   |
    						SYSCTL_XTAL_25MHZ |
    						SYSCTL_CFG_VCO_480,
    						120000000);		//desired system frequency
    }
    
    /**************************************************************************
    **************************************************************************/
    void GPIO_Init(void) {
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);	//Ethernet
    	SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
    	SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);	//RS232
    	SysCtlPeripheralReset(SYSCTL_PERIPH_UART0);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA);
    
    	//configure UART pins for RS232
    	GPIOPinConfigure(GPIO_PA0_U0RX);	//RS232 Com 0 Rx
    	GPIOPinConfigure(GPIO_PA1_U0TX);	//RS232 Com 0 Tx
    
    	//for each function pin, select the type
    	GPIOPinTypeUART(GPIO_PORTA_BASE,GPIO_PIN_0 |	//RS232 Com0 Rx
    									GPIO_PIN_1);	//RS232 Com0 Tx
    }
    /**************************************************************************
    **************************************************************************/
    void uDMA_Init(void) {
        //set the control table
        uDMAControlBaseSet(ucControlTable);
        //enable uDMA
        uDMAEnable();
        //setup the uDMA interrupts
        IntEnable(INT_UDMA | INT_UDMAERR);
    }
    /**************************************************************************
    **************************************************************************/
    void UART0_Init(void) {
    
        UARTConfigSetExpClk(UART0_BASE,
                            gSysCtlClock,
                            UART0_BAUDRATE,
                            UART_CONFIG_WLEN_8   |
                            UART_CONFIG_STOP_ONE |
                            UART_CONFIG_PAR_NONE);
    
        //configure the fifo's trigger level.
        UARTFIFOEnable(UART0_BASE);
        UARTFIFOLevelSet(UART0_BASE,
                         UART_FIFO_TX4_8,   //4 words threshold
                         UART_FIFO_RX4_8);  //4 words threshold
    
        UARTDisableSIR(UART0_BASE);
        UARTEnable(UART0_BASE);
        UARTTxIntModeSet(UART0_BASE, UART_TXINT_MODE_EOT);
    									//trigger INT_TX when the last bit
    									//has been transmitted
        UARTIntEnable(	UART0_BASE,
    					UART_INT_DMARX |
    //					UART_INT_OE    |	//overrun
    //					UART_INT_BE    |	//break
    //					UART_INT_PE    |	//parity
    //					UART_INT_FE    |	//framing
    //					UART_INT_RT    |    //receiver timeout
    					UART_INT_TX    |	//last bit transmitted (flush tx task)
    					UART_INT_RX    );	//Rx fifo level reached
        IntEnable(INT_UART0);
    
        // Configure the uDMA for UART0 read and write
    	UARTDMADisable(UART0_BASE, UART_DMA_RX | UART_DMA_TX | UART_DMA_ERR_RXSTOP);
    	uDMAChannelAssign(UDMA_CH8_UART0RX);
    	uDMAChannelAssign(UDMA_CH9_UART0TX);
    
        uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0RX, UDMA_ATTR_ALL);
        uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_ALL);
    
    	uDMAChannelAttributeEnable(	UDMA_CHANNEL_UART0RX,
    								UDMA_ATTR_USEBURST);
    	uDMAChannelAttributeEnable(	UDMA_CHANNEL_UART0TX,
    								UDMA_ATTR_USEBURST);
    
        uDMAChannelControlSet(UDMA_CHANNEL_UART0RX,     //NBRFIFO
                              UDMA_SIZE_8        |      //data size
                              UDMA_SRC_INC_NONE  |      //no source address increment
                              UDMA_DST_INC_8     |      //destination address increment
                              UDMA_ARB_8);              //arbitration size (match FIFO level)
        uDMAChannelControlSet(UDMA_CHANNEL_UART0TX,     //WFIFO
                              UDMA_SIZE_8        |      //data size
                              UDMA_SRC_INC_8     |      //source address increment
                              UDMA_DST_INC_NONE  |      //no destination address increment
                              UDMA_ARB_8);              //arbitration size (match FIFO level)
    
    	//flush the rx buffer
    	while(UARTCharsAvail(UART0_BASE))
    		UARTCharGetNonBlocking(UART0_BASE);
    }
    /**************************************************************************
    **************************************************************************/
    void UART0_Handler(void) {        // A 16x12 bit receive FIFO
    
    	uint32_t IntStatus;         //ISR status
    
    	IntStatus = UARTIntStatus(UART0_BASE, true);
    	UARTIntClear(UART0_BASE, IntStatus);
    
    	//if its an Rx
    	if(IntStatus & UART_INT_RX) {
    		isr_evt_set(TASK_EVENT_RX_FLAG, gTaskUART0Rx_ID);
    	} //if its an Rx interrupt
    
        //Check for Rx DMA done
        if(uDMAChannelModeGet(UDMA_CHANNEL_UART0RX) == UDMA_MODE_STOP) {
           	isr_evt_set(TASK_EVENT_RX_FLAG, gTaskUART0Rx_ID);
        }
    
    	//Check for Tx DMA done
    	if(	(IntStatus & UART_INT_TX)	||
    		(uDMAChannelModeGet(UDMA_CHANNEL_UART0TX) == UDMA_MODE_STOP)) {
    		isr_evt_set(TASK_EVENT_TX_FLAG, gTaskUART0Tx_ID);
        }
    }
    /**************************************************************************
    **************************************************************************/
    void main() {
    
    	SystemInit();  					//system setup
    	GPIO_Init();   					//setup GPIO
    	uDMA_Init();   					//setup the uDMA
    	UART0_Init(); 					//setup RS232
    
    	os_sys_init(taskInit);
    }