5 Data Integrity
The serial IO with GPIO pins is quite versatile as illustrated in earlier examples - including for communications - be it for a command language interface or for transmission of logs. It is but a small step to leverage this for transmission of sensor data out or setpoint data in - mostly as binary data. As the criticality of the data increases, the need for data integrity increases correspondingly. A fairly simple approach is to use cyclic redundancy check with the sender computing a CRC for the data transmitted and the receiver computing the CRC for the data received. When both match, the message can be considered to have been received correctly. Any differences will imply a corruption of some kind and thus the message can be discarded.
Depending on the nature of the data, the polynomial used in the CRC calculation, it is highly likely to catch any single bit errors. Further analysis of error detection and correction is beyond the scope of this book.
CRC calculations could become compute intensive and such overhead could be minimized using the CRC calculator available in the hardware. This will be the focus of this chapter.
5.1 CRC support
The STM32F4 - used for this book features a CRC peripheral that can be leveraged for communication needs. In this project, an interface is provided for applications as follows:
File : support-crc.ads
0008 | function Calculate ( Data : in Unsigned_32 ) return Unsigned_32 ;
0009 | function Calculate ( Data : in Block_32 ) return Unsigned_32 ;
0010 | function Calculate ( Data : in Block_16 ) return Unsigned_32 ;
0011 | function Calculate ( Data : in Block_8 ) return Unsigned_32 ;
0012 | function Calculate ( Data : in System.Storage_Elements.Storage_Array ) return Unsigned_32 ;
0013 | function Calculate ( DataPtr : System.Address ; Length : System.Storage_Elements.Storage_Offset ) return Unsigned_32 ;Primary hardware input is 32 bit unsigned numbers which is leveraged for other data block lengths as seen above. The adaptation in terms of extending say an 8 bit input into a 32 bit unsigned is left to the application. Little endian, Big endian approaches call for zero padding in different ways. A functional implementation is as shown:
File : support-crc.adb
0066 | function Calculate ( DataPtr : System.Address ; Length : System.Storage_Elements.Storage_Offset ) return Unsigned_32 is
0067 | use System.Storage_Elements ;
0068 | Data : Storage_Array (1..Length) ;
0069 | for Data'Address use DataPtr ;
0070 |
0071 | use System.Storage_Elements ;
0072 | longwords : System.Storage_Elements.Storage_Offset := Length / 4;
0073 | byte : System.Storage_Elements.Storage_Offset ;
0074 | lastword : Unsigned_32 := 0;
0075 | Shift_Count : Integer := 0;
0076 | begin
0077 | Reset_Calculator;
0078 | for i in 1..longwords loop
0079 | byte := (i-1)*4 + 1 ;
0080 | Feed_Word ( Shift_Left(Unsigned_32(Data(byte+3)),24) +
0081 | Shift_Left(Unsigned_32(Data(byte+2)),16) +
0082 | Shift_Left(Unsigned_32(Data(byte+1)),8) +
0083 | Unsigned_32(Data(byte)) ) ;
0084 | end loop;
0085 | if longwords * 4 < Data'Length then
0086 | for i in longwords*4 + 1 .. Data'Last loop
0087 | if Shift_Count > 0 then
0088 | lastword := Shift_Left( Unsigned_32(Data(i)) , Shift_Count ) + lastword ;
0089 | else
0090 | lastword := Unsigned_32(Data(i)) ;
0091 | end if ;
0092 | Shift_Count := Shift_Count + 8 ;
0093 | end loop;
0094 | Feed_Word (lastword);
0095 | end if ;
0096 |
0097 | return Current_Value;
0098 | end Calculate ;5.1.1 cli session with crc of test vectors
Since we have to ability to incorporate arbitrary cli interactions, a set of test vectors are used to illustrate the support. Of course an implementation on a host is needed typically where the transmitted messages - logs or sensor feedback or whatever are captured so the results can be compared.
CRC of
[ 305419896, 3735928559] is d92b271b
CRC of
[ 1, 2, 3, 4] is 955ae3fd
d92b271b
955ae3fd
Test Vectors
1 => c3c5c0cc
2 => 63375ec3
3 => 615eab4a
4 => 1dabe74f
5 => ba237be3
6 => 5ff5c445
7 => 5afe83d0
8 => a3141bda
cli> help
help - Display this help message
version - Display version information
random - Display a random number
date - Display the date or set it with args: yy mm dd dayname. use . to indicate same
time - Display the time or set it with args: hh mm ss. use . to indicate same
led - [blue|green|red|orange|ext] toggles the led
crc - calculate the crc of test vectors or supplied string
cli> crc "Hello"
3cd1eec9
cli> crc "Ada"
9f64d6df
cli>
5.1.2 Application loop
The main loop itself is a trivial application repeating the same CRC calculation ad infinitum:
File : crc.adb
0034 | loop
0035 | support.logs.Put( support.rtclsi.Get_Time & " ") ;
0036 | while wordend < test'Last and test(wordend) /= ' ' loop
0037 | wordend := wordend + 1 ;
0038 | end loop ;
0039 |
0040 | if wordend = test'Last then
0041 | support.logs.Put( "CRC: " & test(wordbegin .. wordend) & " is: " );
0042 | else
0043 | support.logs.Put( "CRC: " & test(wordbegin .. wordend - 1) & " is: " );
0044 | end if ;
0045 |
0046 | crc_value := support.crc.Calculate( test(wordbegin)'Address , Storage_Offset(wordend - wordbegin ) ) ;
0047 | support.logs.Put_Line( hex.Image( crc_value ) ) ;
0048 |
0049 | if wordend >= test'Last then
0050 | wordbegin := test'First ;
0051 | else
0052 | wordbegin := wordend + 1 ;
0053 | end if ;
0054 | wordend := wordbegin ;
0055 | delay 2.0 ;
0056 | end loop ;The output in this case is captured as a log on a different interface from the board. A minicom session of the log capture is :
17:51:14 CRC: The is: 0cbeb623
17:51:16 CRC: quick is: 35243e17
17:51:18 CRC: brown is: 5b50750a
17:51:20 CRC: fox is: f3342c74
17:51:22 CRC: jumps is: 3eb7d624
17:51:24 CRC: over is: fcfca4eb
17:51:27 CRC: the is: 949d00c3
17:51:29 CRC: lazy is: 59f8a6e2
17:51:31 CRC: dog is: a4c70a72
17:51:33 CRC: The is: 0cbeb623
17:51:35 CRC: quick is: 35243e17
17:51:37 CRC: brown is: 5b50750a
17:51:39 CRC: fox is: f3342c74
17:51:41 CRC: jumps is: 3eb7d624
17:51:43 CRC: over is: fcfca4eb
17:51:45 CRC: the is: 949d00c3
17:51:47 CRC: lazy is: 59f8a6e2
17:51:49 CRC: dog is: a4c70a72
5.2 Implementation
The only additional feature of this project being the CRC computation, a new package support.crc is added to our library. However instead of replicating the entire library to this project, the earlier project’s source code is directly included as follows:
File : crc.gpr
0009 | for Source_Dirs use ("src/", "config/", "../03_logger/src/", "../03_logger/imports/");
In later projects, a full fledged library will be developed.