Hi John
You are right about the difficulty getting a trigger for RS485. See the following for how it is done:
http://www.utasker.com/docs/uTasker/uTaskerUART.PDF (chapter 8 ). This does indeed use a timer as you suggested but, as long as you have a DMA timer available for each UART you need, it does work well. The timing depending on Baud and whether working in interrupt or DMA driven mode (plus stop bits).
Here is a table used by the MODBUS extension module to set the correct timer value for the M522XX (note that for each Baud there are values in 7 bit and 8 bit mode - because these use 1 and 2 stop bits - and interrupt/DMA):
#define REFERENCE_BIT_TIME (float)8.681 // bit period at 115200 Baud in us
#define RTS_BIT_DELAY_8BIT_INT (float)10.9 // the last transmit character interrupt arrives this many bit periods before the RTS should be negated
#define RTS_BIT_DELAY_7BIT_INT (float)9.9
#define RTS_BIT_DELAY_8BIT_DMA (float)21.7
#define RTS_BIT_DELAY_7BIT_DMA (float)20.7
static const unsigned short usRTSTimes[SERIAL_BAUD_115200 - SERIAL_BAUD_600][RTS_TIMES] = { // this table holds the required delay from the last interrupt in us for each speed/character length/int/dma combination
{ // 1200 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 1200)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 1200)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 1200)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 1200))
#endif
},
{ // 2400 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 2400)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 2400)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 2400)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 2400))
#endif
},
{ // 4800 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 4800)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 4800)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 4800)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 4800))
#endif
},
{ // 9600 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 9600)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 9600)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 9600)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 9600))
#endif
},
{ // 14400 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 14400)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 14400)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 14400)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 14400))
#endif
},
{ // 19200 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 19200)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 19200)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 19200)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 19200))
#endif
},
{ // 38400 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 38400)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 38400)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 38400)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 38400))
#endif
},
{ // 57600 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 57600)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 57600)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 57600)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 57600))
#endif
},
{ // 115200 Baud time
(unsigned short)((RTS_BIT_DELAY_8BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 115200)),
(unsigned short)((RTS_BIT_DELAY_7BIT_INT * REFERENCE_BIT_TIME) * (float)(115200 / 115200)),
#ifdef SERIAL_SUPPORT_DMA
(unsigned short)((RTS_BIT_DELAY_8BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 115200)),
(unsigned short)((RTS_BIT_DELAY_7BIT_DMA * REFERENCE_BIT_TIME) * (float)(115200 / 115200))
#endif
},
};
The defines above were tuned for the M522XX (other chips have their own tuned set).
To chose the value is then easy:
ptrSetupRTS->timer_us_value = usRTSTimes[ucSpeed][ucType];I find that the USART in the ATMEL SAM7X (and AVR32) are very nice to use. They have RS485 mode so will automatically set the RTS line at the correct time without SW interaction, plus inter-character space timers (very useful for generating interrupts when a certain gap is detected - perfect for MODBUS RTU mode) and more.
Now I don't want you to defect from the Freescale chips but it is worth noting that they have up to 128k RAM and 512k FLASH (although they need an external PHY). Also the uTasker project is compatible between all (supported) chips so moving around between them and using the one which suits best for each project doesn't involve a lot of effort and learning. Moving existing projects (or half developed ones) from one to another is usually no major job so helps keep flexible....
Regards
Mark