Hi
To use the serial interface(s) first ensure that the define SERIAL_INTERFACE is active in config.h. This will include UART driver support. It will also include use of the UART in the uTasker demo project.
It is best to start with the demo since it shows how to configure and open a UART. It will receive and actively echo characters back and it will serve a menu when the Entery key is pressed. The setup of the UART is additionally controllable via the menu, TELNET or Web Browser, where the configuration can be changed 'on-the-fly'.
1. Configuring and opening
TTYTABLE tInterfaceParameters; // table for passing information to driver
tInterfaceParameters.Channel = DEMO_UART; // set UART channel for serial use
tInterfaceParameters.ucSpeed = temp_pars->temp_parameters.ucSerialSpeed; // baud rate
tInterfaceParameters.Rx_tx_sizes.RxQueueSize = RX_BUFFER_SIZE; // input buffer size
tInterfaceParameters.Rx_tx_sizes.TxQueueSize = TX_BUFFER_SIZE; // output buffer size
tInterfaceParameters.Task_to_wake = OWN_TASK; // wake self when messages have been received
#ifdef SUPPORT_FLOW_HIGH_LOW
tInterfaceParameters.ucFlowHighWater = temp_pars->temp_parameters.ucFlowHigh;// set the flow control high and low water levels in %
tInterfaceParameters.ucFlowLowWater = temp_pars->temp_parameters.ucFlowLow;
#endif
tInterfaceParameters.usConfig = temp_pars->temp_parameters.usSerialMode;
#ifdef TEST_MSG_MODE
tInterfaceParameters.usConfig |= (MSG_MODE);
#if defined (TEST_MSG_CNT_MODE) && defined (SUPPORT_MSG_CNT)
tInterfaceParameters.usConfig |= (MSG_MODE_RX_CNT);
#endif
tInterfaceParameters.usConfig &= ~USE_XON_OFF;
tInterfaceParameters.ucMessageTerminator = '\r';
#endif
#ifdef SERIAL_SUPPORT_DMA
tInterfaceParameters.ucDMAConfig = UART_TX_DMA; // activate DMA on transmission
#endif
if ((SerialPortID = fnOpen( TYPE_TTY, FOR_I_O, &tInterfaceParameters )) != 0) { // open the channel with defined configurations (initially inactive)
fnDriver( SerialPortID, ( TX_ON | RX_ON ), 0 ); // enable rx and tx
}
All interfaces are opened using fnOpen and the parameters are passed in a table - in this example some parameters are fixed and some are set from the user parameters. Note that DEMO_UART is the UART number (0, 1, 2 etc. depending on what the used processor supports) which can be defined in app_hw_xxx.h to suit your board or project.
SerialPortID is a handle to the UART which is then used for communication.
The demo can test also different reception modes:
TEST_MSG_MODE - the receiver task is woken only when a complete line of data, terminated by the defined character, is received.
TEST_MSG_CNT_MODE - the same as TEST_MSG_MODE but the message length is also returned in the rx buffer.
There are various other mode details, like ECHO_RX_CHARS to automatically echo received characters, USE_XON_OFF to enable XON/XOFF flow control. See driver.h for a list.
2. Sending messages
static const CHAR ucCOMMAND_MODE_TIMEOUT[] = "Connection timed out\r\n";
fnWrite(SerialPortID, (unsigned char *)ucCOMMAND_MODE_TIMEOUT, sizeof(ucCOMMAND_MODE_TIMEOUT));
A write to the UART handle will cause data to be transmitted.
For sending strings - eg. for debug purposes - fnDebugMsg("Test"); is typically used. Before using for the first time, divert the debug output to the required UART by setting the following global variable:
DebugHandle = SerialPortID;
(As a side note, when not set for UART output, debug data will be sent to the routine fnNetworkTx, which can also be a TELNET connection - the demo project also support this)
3. Receiving data
Generally the UART is configured to wake the receiving task on reception.
[tInterfaceParameters.Task_to_wake = OWN_TASK;]
Depending on the exact operating mode, this can be on each received character or each received terminated line of input. The demo project shows how to receive correctly in each mode:
fnMsgs(SerialPortID); This is called to return the number of waiting messages. In character mode this is equal to the number of characters but in message mode it will indicate the number of complete messages and not individual characters.
Length = fnRead( SerialPortID, ucInputMessage, MEDIUM_MESSAGE); This will return as many waiting characters in the input buffer, up to the limit MEDIUM_MESSAGE. The number of characters actually copied to the buffer ucInputMessage is returned.
4. Simulating UARTs in the uTasker simulator
By mapping the UART(s) to COM ports on the local PC, the simulator sends and receives data as on the real target and can enable efficient testing and project development.
In app_hw_xxxx.h you can set these defines:
#define SERIAL_PORT_0 '1' // if we open UART channel 0 we simulate using com1 on the PC
#define SERIAL_PORT_1 '2' // if we open UART channel 1 we simulate using com2 on the PC
#define SERIAL_PORT_2 '3' // if we open UART channel 2 we simulate using com3 on the PC
etc. depending how many UARTs are available
If you set ‘0’ no com port will be mapped. Eg. if you instead set ‘5’ COM5. will be mapped, etc. Don’t map 2 simultaneously used UARTS to the same COM since only the first will actually work. Mapping to a non-existent or already used COM port has no detrimental effects but it will of course not be abl eto use the port.
This is only a brief introduction because the UART support has quite a lot of different configurations and there are various extra details about using DMA, flow control etc.
It should however be possible to start working with the UARTs base do this and the uTasker demo example, in the simulator and on the target. We can use this thread for extra discussion details as work progresses.
Good luck
Regards
Mark