Serial Communication
Serial communication involves the transfer of data over a single wire for each direction. All serial interfaces convert parallel data to a serial bit stream, and vice versa. The simplest form of serial interface is that of the Universal Asynchronous Receiver Transmitter, or simply just UART for short. They are termed asynchronous because no clock is transmitted with the serial data. The receiver must lock onto the data and detect individual bits without the luxury of a clock for synchronization. Because of this, UARTs are somewhat forgiving of timing errors.
In asynchronous transmission, one character is sent at a time, and the interval of time between each byte transmission may vary. The transmission format uses one start bit at the beginning and one or two stop bits end of each character. The receiver synchronizes its clock upon receiving the start bit, and then samples the data bits (either seven or eight, depending on the system configuration). In this example, the byte %01101010 ($6A) is transmitted:
In asynchronous transmission, one character is sent at a time, and the interval of time between each byte transmission may vary. The transmission format uses one start bit at the beginning and one or two stop bits end of each character. The receiver synchronizes its clock upon receiving the start bit, and then samples the data bits (either seven or eight, depending on the system configuration). In this example, the byte %01101010 ($6A) is transmitted:
Upon receiving the stop bit(s) in the correct sequence, the receiver assumes that the transfer was successful and that it has a valid character. If it did not receive an appropriate stop sequence, the receiver assumes that its clock drifted out of phase and a framing error or bit-misalignment error is declared. It’s up to the application software to check for such errors, and take appropriate action.
Setting The Baud Rate
UART baud rates are controlled by baud rate generators. A 16-bit unsigned value, BRG, generates the appropriate baud rate based on the following equation:
Baud = FCY / (4 * (BRG + 1))
where FCY is the oscillator frequency of the PIC24 processor (in MHz). Since BRG is an 16-bit integer, there may be a small error between the desired baud rate and the actual baud rate. (This is common to all serial communication devices.) Generally, UART-based systems are very tolerant of small variations in baud rate.
The word baud will calculate the BRG value from a desired baud rate. Baud rates can range from 61 bps to 4,000,000 bps. Since this range exceeds a 16-bit number, the baud rate must be specified as a double number (appended with a dot). To calculate the BRG for 9600 bps:
The word baud will calculate the BRG value from a desired baud rate. Baud rates can range from 61 bps to 4,000,000 bps. Since this range exceeds a 16-bit number, the baud rate must be specified as a double number (appended with a dot). To calculate the BRG for 9600 bps:
9600. baud
will give a BRG value of 415 on the stack. To calculate the BRG value for the maximum rate of 4 Mbps:
4000000. baud
will give a BRG value of 0 on the stack.
The word brg will take a BRG value and work out the actual baud rate used. It will return a double to the stack representing the real baud rate generated by the BRG value. For example,
The word brg will take a BRG value and work out the actual baud rate used. It will return a double to the stack representing the real baud rate generated by the BRG value. For example,
9600. baud brg d.
will calculate that the actual baud rate is 9615 bps, which has an acceptable error of only 0.16%.
The word u1baud places the address of UART1's baud rate register on the stack. To set the baud rate, for UART1, enter the desired baud rate as a double, then call the word baud to convert it to an appropriate setting value. u1baud places the address of the register on the stack and ! (store) writes the baud setting to that register.
The word u1baud places the address of UART1's baud rate register on the stack. To set the baud rate, for UART1, enter the desired baud rate as a double, then call the word baud to convert it to an appropriate setting value. u1baud places the address of the register on the stack and ! (store) writes the baud setting to that register.
115200. baud u1baud !
To recall the current setting baud setting for UART1, and output it as a meaningful baud rate:
u1baud @ brg d.
For UART2, use u2baud in the same way.
Mapping UARTs to Pins (Scamp1 and Scamp2)
On a Scamp1 or Scamp2 (only) the UARTs must be mapped to a pin on the connector. This page shows you how to do it.
On a Scamp3 or Scamp2e , the UARTs are already mapped to dedicated pins, so pin allocation is unnecessary.
Sending and Receiving data with the UARTs
Once mapped, chars can be sent and received from UART1 with the words tx1 and rx1. For example, to receive a char with UART1 and echo it to the console:
rx1 emit
Similarly, to transmit an asterisk (ASCII 42) with UART1:
42 tx1
The word rx1? checks to see if a char has been received, and tx1? checks if UART1's transmitter is free or transmitting.
Use rx2pin, tx2pin, rx2, rx2?, tx2? and tx2 for UART2. The USB console has corresponding words rxu, rxu? and txu.
Testing your UART Connection
Sometimes it's a useful test to confirm that your serial comms are working as expected. Wire the transmitter directly to the receiver (in this case Tx1 to Rx1), so that whatever is sent is also received by the same UART.
: echo
9600. baud u1baud ! \ set the baud rate for UART1 to be 9600
begin
key \ read a key from the console
dup tx1 \ send it via UART1
rx1 emit \ read from UART1 and print out the char
$1b = \ if the char was ESC then exit
until
;
Redirecting the Forth Console
By default, FlashForth uses the USB port for its console, with the words rxu and txu for receiving and sending characters, respectively. However, it is possible to use one of the UARTs for the console. Connected to this UART could be a serial terminal, a USB bridge, a Bluetooth or WiFi module.
Forth uses the word emit to transmit a char, the word key? to see if a char has arrived, and the word key to receive a char. These are simply calls to txu, rxu? and rxu, respectively. By remapping emit, key? and key to a UART, the console is is redirected. The address of these words are stored in the variables 'key?, 'key and 'emit.
You can see this for yourself. If you fetch the value stored in 'emit:
Forth uses the word emit to transmit a char, the word key? to see if a char has arrived, and the word key to receive a char. These are simply calls to txu, rxu? and rxu, respectively. By remapping emit, key? and key to a UART, the console is is redirected. The address of these words are stored in the variables 'key?, 'key and 'emit.
You can see this for yourself. If you fetch the value stored in 'emit:
'emit @
and look up the address of txu
' txu
you will see they are the same address. 'emit points to txu. By storing the address of a UART tx word to the variable 'emit, emit is mapped to that UART. The address of a Forth word in the dictionary may be fetched using the ' (tick) word.
So to change the Forth console to UART1:
So to change the Forth console to UART1:
' tx1 'emit ! ' rx1 'key ! ' rx1? 'key? !
Be sure to get the spaces correct, and execute these words in one line (or within a word) so that the console is remapped all at once.
Caution: only try this if you have a working communication device attached to the UART, otherwise you won't be able to access the Forth console once it has been remapped.
A reset of your Scamp will restore the console back to the USB port. If you want to make the remapping permanent for a deployed system, be sure to include the above in your turnkey word.
Adding LoRa to a Scamp
Ken Merk has done a great video on adding a LoRa module to a Scamp.
Learn : Interfacing : Serial Communication