Communicate via UART
Motivation
There are certain scenarios, when the simulator needs to communicate with the device-under-test via a UART interface, for example to exchange control commands.
The following tutorial shows how to implement a UART sender on the simulator side. For the sake of simplicity the simulator will also act as UART receiver.
Pre-requisites
For the miniHIL to be able to talk to itself a physical connection between the RX and TX pins need to be established. In our case both are I/Os of the H7 processor. For this HowTo the pin PD5 acts as TX and PD6 as RX.
Connect them using a wire jumper as shown in the picture below:
To prepare the SW create a new project as described in the "Creating a new project" How-To.
Finally, to be able to see some output, make sure you can log as described in here. Note that in this case you only need the USB connection. Log messages will be generated by the UART tester below.
The contents of this How-To is also part of the miniHIL Examples project. Look there for a fully functional sample in model-user/examples/uart.room. |
Instantiate the UART in SW
To run the UART and add the ability to test it we need two actors: one that represents the UART and one that represents the testing code. Both of them need to be instantiated and connected to each other.
As a container we will use the Application contained in MiniHILApplication.room. So open the file in your newly created project and go to the Structure Section of the Application actor.
There, create an instance of the AUart2Adapter as shown below.
RoomModel MiniHilProject {
//...
import minihil.api.adapters.uart2.AUart2Adapter
ActorClass Application {
Structure {
// ...
ActorRef uartAdapter: AUart2Adapter
}
}
Add the appropriate import for the adapter | |
Instantiate the adapter |
The AUart2Adapter is an abstraction for the miniHIL hardware, freeing you from the specifics of pin assignment and such.
In this case the adapter is configured to use the PD5/PD6 pins for TX/RX and uses a DMA for transfer. If you are interested in details set the cursor on AUart2Adapter and press F3.
In the miniHIL Examples project this setup is contained in model-user/examples/uart.room. Here, instead of using the application, a separate container actor called AUartExampleContainer is used. The general approach is the same, though. |
Create a test actor
Now it is time to create the test actor in the MiniHilProject ROOM model. First we create the hull for it and connect it to the UART adapter as show below.
RoomModel MiniHilProject {
//...
import etrice.api.timer.PTimer
import etrice.api.logger.PLogger
import minihil.api.adapters.uart.*
import minihil.api.adapters.uart2.AUart2Adapter
ActorClass AUartTester {
Interface {
conjugated Port config: PUartControl
conjugated Port comm: PFixedSizePacketCommunication
}
Structure {
external Port config
external Port comm
SAP timer: PTimer
SAP logger: PLogger
}
Behavior {
}
}
}
ActorClass Application {
// ...
ActorRef uartAdapter: AUart2Adapter
ActorRef uartTester: AUartTester
Binding uartTester.comm and uartAdapter.comm
Binding uartTester.config and uartAdapter.config
}
}
Port for controlling the UART adapter | |
Port for communication | |
To be able to do periodic actions we need the timer service | |
We will need to do some logging to see what is going on | |
UART tester instance | |
Connect the communication port | |
Connect the configuration port |
With this you should see the following inside the structure diagram of the Application actor (use ALT-S to open it):
Making the tester behave
To have the tester do something useful we now create a state machine as behavior. The idea is that the test will wait for a second, then send a "Hello" message, try to receive the "Hello" message and then start over again.
This can be done using the state machine shown below:
The code for initializing the UART is contained in the init transition. Sending is done in the sendTransition. When receiving the data we simply print it in the receiveTransition.
The full code should look as shown below:
ActorClass AUartTester {
// ...
Behavior {
StateMachine {
State WaitingForReceivePacket {
}
State WaitingForASecond {
entry '''
// starting timeout to send a uart packet after a second
timer.startTimeout(1000); // 1000 milliseconds'''
}
Transition init: initial -> WaitingForASecond {
action '''
// creating instance of uart configuration data class
DUartConfiguration conf;
// setting the parameters
conf.baudrate = 115200;
conf.databits = 8; // only 8 is currently supported
conf.parity = EParity_NONE;
conf.stopbits = EStopBits_STOPBITS_1;
conf.packet_size = 6;
// sending configuration to uart actor via config port
config.configureUart(&conf);
config.enableReceiveData();
'''
}
Transition sendTransition: WaitingForASecond -> WaitingForReceivePacket {
triggers {
<timeout: timer>
}
action '''
// creating a packet to send
DFixedSizePacket32Byte packet;
packet.len = 5; // length
// fill buffer with data
packet.buffer[0] = 'H';
packet.buffer[1] = 'E';
packet.buffer[2] = 'L';
packet.buffer[3] = 'L';
packet.buffer[4] = 'O';
// sending packet via comm port
comm.sendPacket(&packet);'''
}
Transition receiveTransition: WaitingForReceivePacket -> WaitingForASecond {
triggers {
<receivedPacket: comm>
}
action '''
// transitionDate->len contains the configured package size. The payload size is currently not available
if (transitionData->len == 6) {
transitionData->buffer[6] = (char)0; // terminating the received buffer to be used as string for logging
logger.logF("received packet[0] = %d", transitionData->buffer[0]);
logger.logF("received packet[1] = %d", transitionData->buffer[1]);
logger.logF("received packet[2] = %d", transitionData->buffer[2]);
logger.logF("received packet[3] = %d", transitionData->buffer[3]);
logger.logF("received packet[4] = %d", transitionData->buffer[4]);
logger.logF("received packet[5] = %d", transitionData->buffer[5]);
logger.logF("received packet[6] = %d", transitionData->buffer[6]);
logger.logF("complete packet = %s", &transitionData->buffer[0]);
logger.log("------------------------");
}
'''
}
}
}
}
Running the example
Now it is time to flash the example and see what it is doing. Once you have flashed and started the target you should see output like this in your terminal.
received packet[0] = 72 received packet[1] = 69 received packet[2] = 76 received packet[3] = 76 received packet[4] = 79 received packet[5] = 0 received packet[6] = 0 complete packet = HELLO ------------------------ received packet[0] = 72 received packet[1] = 69 received packet[2] = 76 received packet[3] = 76 received packet[4] = 79 received packet[5] = 0 received packet[6] = 0 complete packet = HELLO ------------------------ received packet[0] = 72 received packet[1] = 69 received packet[2] = 76 received packet[3] = 76 received packet[4] = 79 received packet[5] = 0 received packet[6] = 0 complete packet = HELLO ------------------------
HTerm requires you to disconnect and reconnect each timer you flash the target. Otherwise you might not see output. |
Summary
-
Instantiate a UART adapter from the miniHIL library
-
Create your own UART application
-
Connect it to the UART adapter
-
Have fun!