µTasker Forum
µTasker Forum => µTasker general => Topic started by: jharvey on April 27, 2008, 06:48:06 PM
-
Hey Mark,
I've checked through the documentation but haven't been able to find the answer to whether or not there is an easy way to use a different UART channel for sending and receiving.
With the default implementation, it looks like both use the SerialPortID which gets set to DEMO_UART in fnSetNewSerialMode.
It looks as if I will have to create a new SerialPortID using a different channel, that way I will have one for input and one for output.
Then I will have to replace all references to SerialPortID that are used in reads with SerialPortIDIn and all that are used in outs with SerialPortIDOut.
Is there an easier way to do this?
Thanks,
Jesse
-
Hi Jesse
For each UART you need a handle. This is allocated when the UART is opened and then used to change the UART state (eg. enable TX or RX) and then send and receive over it.
Each UART has a channel number starting at 0 for UART0, continuing with 1, 2, 3 etc. for UARTs 1, 2, 3 etc. (the limit depends on the processor hardware).
This means that an open will configure one UART and afterwards the handle corresponds to this HW UART. This one UART handle can be used for input and output via this UART (it is not necessary to have one handle for input and one for output).
eg. fnWrite(SerialPortID, buffer, length); and fnRead(SerialPortID, buffer, length;
Assuming the processor has 3 UARTs the open can be repeated 3 times (with same or different paremeters) and then there are 3 handles (say, SerialPortID, SerialPortID1 and SerialPortID2 for UARTs 0, 1 and 2).
To send something over UART 1 use fnWrite(SerialPortID1, buffer, length); and to send something over UART2 use fnWrite(SerialPortID2, buffer, length);, etc.
When opening the serial port you pass the task responsible for handling receptions from it:
(eg. tInterfaceParameters.Task_to_wake = OWN_TASK;).
There can be one task for each UART input or one single task can handle all inputs.
To handle all inputs in one task, the task has to simply check each one when it is worken (eg.):
while (fnMsgs(SerialPortID)) {
// read reception from this UART
}
while (fnMsgs(SerialPortID1)) {
// read reception from this UART
}
while (fnMsgs(SerialPortID2)) {
// read reception from this UART
}
If there is one task for each input it is a little more efficient since the task only has to check one serial port input.
Since Rx and Tx of a UART are actually independent (apart from Baud and configuration settings) it is possible to implement a connection with Tx from UART0 and Rx from UART1. In this case writes use SerialPortID and reads use SerialPortID1, however usually the RX and TX lines of a physical UART are used together.
To send the same data to all UARTs is very simple:
fnWrite(SerialPortID, buffer, length);
fnWrite(SerialPortID1, buffer, length);
fnWrite(SerialPortID2, buffer, length);
The same message is sent to all three outputs.
The following thread is possibly the best overview for using the serial interface:
http://www.utasker.com/forum/index.php?topic=54.msg220#msg220
Regards
Mark
-
Thanks for the reply Mark, that is what I figured....
I've done the following:
1) Made global variables for the interface parameters:
TTYTABLE tInterfaceParametersIn;
TTYTABLE tInterfaceParametersOut;
2) Modified fnSetNewSerialMode to set up the appropriate channel based on the additional param:
#ifdef SERIAL_INTERFACE
// After changes, we set up the new serial configuration
//
extern QUEUE_HANDLE fnSetNewSerialMode(unsigned char ucDriverMode, unsigned int uiUartChannel)
{
//TTYTABLE tInterfaceParameters; // table for passing information to driver
//Jesse //tInterfaceParameters.Channel = DEMO_UART; // set UART channel for serial use
if(uiUartChannel == 1)
{
tInterfaceParametersIn.Channel = uiUartChannel; // set UART channel for serial use
tInterfaceParametersIn.ucSpeed = temp_pars->temp_parameters.ucSerialSpeed; // baud rate
tInterfaceParametersIn.Rx_tx_sizes.RxQueueSize = RX_BUFFER_SIZE; // input buffer size
tInterfaceParametersIn.Rx_tx_sizes.TxQueueSize = TX_BUFFER_SIZE; // output buffer size
tInterfaceParametersIn.Task_to_wake = OWN_TASK; // wake self when messages have been received
#ifdef SUPPORT_FLOW_HIGH_LOW
tInterfaceParametersIn.ucFlowHighWater = temp_pars->temp_parameters.ucFlowHigh;// set the flow control high and low water levels in %
tInterfaceParametersIn.ucFlowLowWater = temp_pars->temp_parameters.ucFlowLow;
#endif
tInterfaceParametersIn.usConfig = temp_pars->temp_parameters.usSerialMode;
#ifdef TEST_MSG_MODE
tInterfaceParametersIn.usConfig |= (MSG_MODE);
#if defined (TEST_MSG_CNT_MODE) && defined (SUPPORT_MSG_CNT)
tInterfaceParametersIn.usConfig |= (MSG_MODE_RX_CNT);
#endif
tInterfaceParametersIn.usConfig &= ~USE_XON_OFF;
tInterfaceParametersIn.ucMessageTerminator = '\r';
#endif
#ifdef SERIAL_SUPPORT_DMA
tInterfaceParametersIn.ucDMAConfig = UART_TX_DMA; // activate DMA on transmission
#endif
if (SerialPortIDIn = fnOpen( TYPE_TTY, ucDriverMode, &tInterfaceParametersIn )) { // open or change the channel with defined configurations (initially inactive)
fnDriver( SerialPortIDIn, ( RX_ON ), 0 ); // enable rx and tx
}
return SerialPortIDIn;
}
else if( uiUartChannel == 0 )
{
tInterfaceParametersOut.Channel = uiUartChannel; // set UART channel for serial use
tInterfaceParametersOut.ucSpeed = temp_pars->temp_parameters.ucSerialSpeed; // baud rate
tInterfaceParametersOut.Rx_tx_sizes.RxQueueSize = RX_BUFFER_SIZE; // input buffer size
tInterfaceParametersOut.Rx_tx_sizes.TxQueueSize = TX_BUFFER_SIZE; // output buffer size
tInterfaceParametersOut.Task_to_wake = OWN_TASK; // wake self when messages have been received
#ifdef SUPPORT_FLOW_HIGH_LOW
tInterfaceParametersOut.ucFlowHighWater = temp_pars->temp_parameters.ucFlowHigh;// set the flow control high and low water levels in %
tInterfaceParametersOut.ucFlowLowWater = temp_pars->temp_parameters.ucFlowLow;
#endif
tInterfaceParametersOut.usConfig = temp_pars->temp_parameters.usSerialMode;
#ifdef TEST_MSG_MODE
tInterfaceParametersOut.usConfig |= (MSG_MODE);
#if defined (TEST_MSG_CNT_MODE) && defined (SUPPORT_MSG_CNT)
tInterfaceParametersOut.usConfig |= (MSG_MODE_RX_CNT);
#endif
tInterfaceParametersOut.usConfig &= ~USE_XON_OFF;
tInterfaceParametersOut.ucMessageTerminator = '\r';
#endif
#ifdef SERIAL_SUPPORT_DMA
tInterfaceParametersOut.ucDMAConfig = UART_TX_DMA; // activate DMA on transmission
#endif
if (SerialPortIDOut = fnOpen( TYPE_TTY, ucDriverMode, &tInterfaceParametersOut )) { // open or change the channel with defined configurations (initially inactive)
fnDriver( SerialPortIDOut, ( TX_ON ), 0 ); // enable rx and tx
}
return SerialPortIDOut;
}
}
#endif
It may not be the cleanest approach, but it's working for me....
-
Hi Jesse
That is good.
You know what they say - "If it works, don't try to fix it!!"
However, ....
I think that you only actually need to put the following in the if..else
if (uiUartChannel == 1) {
fnDriver( SerialPortIDIn, ( RX_ON ), 0 ); // enable rx
}
else {
fnDriver( SerialPortIDOut, ( TX_ON ), 0 ); // enable tx
}
If you are using only rx or tx of each channel you could also leave the other (tx/rx) buffer size at 0 to optimise RAM.
Regards
Mark