AnsweredAssumed Answered

UART RX via DMA works to internal memory, but not to SDRAM

Question asked by Eabin on Mar 25, 2011
Latest reply on Mar 28, 2011 by Eabin

Hello all,

 

I want to set up a transfer from UART0 RX via DMA to external SDRAM. The code posted below works already very well with ring_buffer=0xff90009C (location of a global variable, not in SDRAM) and ring_buffer_size=0x100.

 

But when I try to write to SDRAM by e.g. setting ring_buffer=0x01300000, I only receive around 1 out of 100 bytes. The curr_addr and curr_x registers are incremented correctly, but the value in memory is 0. So when i send "Hello World" from an external device to the bfin UART, i may receive just a list of 0x00 bytes, or maybe something along the lines of 0x00 0x00 0x00 'l' 'l' 'o' 0x00 0x00 0x00 0x00 0x00.

 

This is very weird behaviour, and I'm running out of ideas, so any help is highly appreciated.

 

Things I already checked: The SDRAM is ok, i can read and write manually to the whole section. No error interrupts are raised, neither from UART nor from DMA. I changed the baud rate of the UART down to 115k. I tried different word lengths, descriptor lists, and FLOW=STOP without any success.

 

EDIT: Also checked: setting DMA0 to UART and use DMA0 instead. Usually, I use DMA0 to read from the PPI interface to SDRAM which works without any problems. But even using DMA0 results in the same weird behaviour.

 

CODE:

--------

/**
* Initialize UART0 Port
* Setup a DMA buffer; UART0 is connected to RX=DMA8 on bf537
*/
void uart0_init(unsigned char* ring_buffer, unsigned int ring_buffer_size)
{
*pPORTF_FER |= 0x0003;  // enable UART0 pins

 

*pUART0_GCTL = UCEN;
*pUART0_LCR = DLAB;
unsigned int speed = UART0_DIVIDER;
*pUART0_DLL = speed;
*pUART0_DLH = speed >> 8;
*pUART0_LCR = WLS(8); // 8 bit, no parity, one stop bit

 

// dummy reads to clear possible pending errors / irqs
char dummy = *pUART0_RBR;
dummy = *pUART0_LSR;
dummy = *pUART0_IIR;
SSYNC;

 

//disable DMA
*pDMA8_CONFIG = 0;
SSYNC;

 

//clear DMA done bit, and error bit (W1C)
*pDMA8_IRQ_STATUS = DMA_DONE;
SSYNC;
*pDMA8_IRQ_STATUS = DMA_ERR;
SSYNC;

 

//re-route interrupt 10
*pEVT10 = (void*) uart_handle_buffer_switch;

 

//enable interrupt 10 (3rd system interrupt, dma buffer full)
*pIMASK |= EVT_IVG10;

 

//enable interrupt 7 (sic_iar 0, uart errors) + unmask error interrupts
*pIMASK |= EVT_IVG7; *pSIC_IMASK |= IRQ_ERROR2;

 

//enable UART0 rx interrupt so that DMA can see new data
*pSIC_IMASK |= IRQ_DMA8;
SSYNC;

 

//setup and start DMA
*pDMA8_X_COUNT = ring_buffer_size;
*pDMA8_X_MODIFY = 1;
SSYNC;

 

*pDMA8_START_ADDR = *pDMA8_CURR_ADDR = ring_buffer;
SSYNC;

 

// start DMA transfer in autobuffer mode (cyclic write to our buffer with interrupt after each flip)
*pDMA8_CONFIG = DMA_FLOW_AUTOBUFFER
| DMA_WORD_SIZE_8 | DMA_WRITE_MEMORY | DMA_ENABLE | DMA_DATA_INTERRUPT;
SSYNC;

 

//enable UART0 interrupts so that UART0 buffer full event will trigger a DMA transfer
*pUART0_IER = ERBFI | ELSI; //DEBUG ONLY: enable line status interrupt ELSI

 

}

Outcomes