2008-11-05 01:02 PM
UART TX finished interrupt needed
2011-05-17 12:45 AM
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 low2011-05-17 12:45 AM
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.2011-05-17 12:45 AM
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