cancel
Showing results for 
Search instead for 
Did you mean: 

UART TX finished interrupt needed

d_steffen
Associate II
Posted on November 05, 2008 at 22:02

UART TX finished interrupt needed

12 REPLIES 12
rgreenthal
Associate II
Posted on May 17, 2011 at 09:45

Hi

We are using RS-485 & the enable is on P6.3

And some Macros we use are:

// P6.3

// RS-485 Direction

// Actually taken care of by the OCMP2 used as a One-Shot

#define m_RS485BitDirOut() GPIO6->DR[GPIO_Pin_3 BitAddr] = GPIO_Pin_3

#define m_RS485BitDirIn() GPIO6->DR[GPIO_Pin_3 BitAddr] = 0

In the Init do

// P6.3 AltOut2 Timer1 OutComp2

// P6.3 is the RS-485 Direction Pin

SCU->GPIOOUT[6] |= 0x0080;

GPIO6->DDR |= 0x08; // P6.3 Output

m_RS485BitDirIn(); // Enable UART1 RS-485 to Rx

Then in the Tx do

__disable_interrupt();

TIM1->CR1 |= 0xA80; // force high (FLV2 + OLV2 + OC2E)

// maybe should be using UART_Mode_Tx (0x0100) and not UART_Enable_Mask (0x0001)

UART1->CR &= ~0x00000001; // disable UART1

UART1->LCR |= 0x00000004; // set even parity for local mode

UART1->DR = cData; // Load single Character to output

// Used to control an output waveform (RS-485 Direction)

// P6.3 AltOut2 Timer1 OutComp2

// P6.3 is the RS-485 Direction Pin

// At a Baud rate of 625000, we get 16 usec for a character

// For this Function we need a Minimum or 16 usec (1 char)

// Force low for 28 usec (16 usec/char)

TIM1->OC2R = TIM1->CNTRX + (18 + 10);

TIM1->CR1 &= ~0xA00; // remove (FLV2 + OLV2) force make comapare level low

UART1->CR |= 0x00000001; // enable

__enable_interrupt();

For more than One byte

// Calc number of Usec needed for the number of char Tx'ed

lTimerCounts = (lLength * 176)+120;

lTimerCounts /= 10;

// lTimerCounts = (lLength * 18) + 12; // This maybe faster REG 07/31/2008

__disable_interrupt();

TIM1->CR1 |= 0xA80; // force high (FLV2 + OLV2 + OC2E)

UART1->CR &= ~0x00000001; // disable

UART1->LCR |= 0x00000004; // set even parity for local mode

UART1->CR |= 0x00000001; // enable

// Used to control an output waveform (RS-485 Direction)

// P6.3 AltOut2 Timer1 OutComp2

// P6.3 is the RS-485 Direction Pin

// At a Baud rate of 625000, we get 16 usec for a character

// For this Function we need a Minimum or 16 usec * lLength

// Force low for ?? usec (16 usec/char)

TIM1->OC2R = TIM1->CNTRX + (short)lTimerCounts;

TIM1->CR1 &= ~0xA00; // remove (FLV2 + OLV2) force make comapare level low

paulsmitton9
Associate III
Posted on May 17, 2011 at 09:45

Thanks rgreenthal!

I did think about using a timer and calculating the transmit time, but in the end I opted for the following:

Set up DMA to transmit. Put the Uart in loopback mode

Set up DMA to recieve the same length as transmitted, and then interrupt.

Set up DMA linked list to then recieve any subsequent response.

In the interrupt after the first recieve (i.e the looped back transmit),

I poll the uart until it is idle (i.e. for the duration of the stop bit)

and then turn of the transmit enable.

mark9
Associate II
Posted on May 17, 2011 at 09:45

Thank you all for the discussion. I've been tearing my hair out trying to figure out how to do it. I did the BUSY-polling method, but that didn't work, since the latency was too high and the peer on the RS485 was replying before I could turn the bus direction around. I was about to use a timer (that would trigger after the last TX interrupt), but that seemed messy.

I believe that the best solution is just to use the Loop Back (as Paul Smitton figured out) and basically use the RX interrupt to deal with the problem of the TX interrupt. I am not using DMA, but just normal interrupts. This works great!

Basically, turn on UART0->CR |= LBE, set a counter for the number of bytes in the outgoing packet, set a flag meaning ''write'' mode is asserted, and finally enable TX mode on the RS485 bus.

Then in the ISR, check if ''write'' mode is asserted, and if it is, then decrement the counter. When it hits 0, then disable LBE, disable TX mode and unset the flag meaning ''read'' mode.

Works great! Thanks Paul.

-Mark