Contents

Data Packetization

This example shows how to generate HDL code from a MATLAB® design that packetizes a transmit sequence.

Introduction

In wireless communication systems receive data is oversampled at the RF front end. This serves several purposes, including providing sufficient sampling rates for receive filtering.

% However, one of the most important
% functions is to provide multiple sampling points on the received
% waveform such that data can be sampled near the maximum amplitude point
% in the received waveform. This example illustrates a basic lead-lag time
% offset estimation core, operating recursively.

% The generated hardware core for this design operates at 1/os_rate
% where os_rate is the oversampled rate. That is, for 8 oversampled clock cycles
% this core iterates once. The output is at the symbol rate.

design_name = 'mlhdlc_comms_data_packet';
testbench_name = 'mlhdlc_comms_data_packet_tb';

Let us take a look at the MATLAB design.

type(design_name);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MATLAB design: Data packetization
%
% Introduction: 
%
% This core is meant to illustrate packetization of a transmit sequence.
% There is a "pad" data section, which allows for the transmit amplifier to
% settle. This is then followed by a 65-bit training sequence. This is
% followed by the number of symbols beginning encoded into two bytes or
% 16-bits. This is then followed by a variable length data sequence and a
% CRC. All bits can optionally be differentially encoded.
%
% Key design pattern covered in this example:
% (1) Design illustrates the us of binary operands, such as bitxor
% (2) Shows how to properly segment persistent variables for register an
% BRAM access
% (3) Illustrates the use of fi math
% (4) Shows how to properly format and store ROM data, e.g., padData

%#codegen
function [symbolOut, reByte] = ...
    mlhdlc_comms_data_packet(emptyFlag, byteValue, numberSymbols, diffOn, Nts, Npad)

persistent trainBits1 padData
persistent valueCRC crcVector bitPrev
persistent inPacketFlag  bitOfByteIndex symbolCount

fm = hdlfimath;
if isempty(symbolCount)
    symbolCount = 1;
    inPacketFlag = 0;
    valueCRC = fi(1, 0,16,0, fm);
    bitOfByteIndex = 1; 
    bitPrev = fi(1, 0,1,0, fm);
    crcVector = zeros(1,16);
end
if isempty(trainBits1)
    trainBits1 = TRAIN_DATA;
    padData = PAD_DATA;
end

%genPoly = 69665;
genPoly = fi(65535, 0,16,0, fm);
byteUint8 = uint8(byteValue);

reByte = 0;
symbolOut = fi(0, 0,1,0, fm);

%the first condition is whether or not we're currently processing a packet
if inPacketFlag == 1
    bitOut = fi(0, 0,1,0, fm);
    if symbolCount <= Npad,
        bitOut(:) = padData(symbolCount);
    elseif symbolCount <= Npad+Nts
        bitOut(:) = trainBits1(symbolCount-Npad);
    elseif symbolCount <= Npad+Nts+numberSymbols
        bitOut(:) = bitget(byteUint8,9-bitOfByteIndex);
        bitOfByteIndex = bitOfByteIndex + 1;
        if bitOfByteIndex == 9 && symbolCount < Npad+Nts+numberSymbols
            bitOfByteIndex = 1;
            reByte = 1; % we've exhausted this one so pop new one off
        end
    elseif symbolCount <= Npad+Nts+numberSymbols+16
        bitOut(:) = 0;
    elseif symbolCount <= Npad+Nts+numberSymbols+32
        bitOut(:) = crcVector(symbolCount-(Npad+Nts+numberSymbols+16));
    else
        inPacketFlag = 0; %we're done
    end
    
    %leadValue = 0;
    % here we have the bit going out so if past Nts+Npad then form CRC.
    % Note that we throw 16 zeros on the end in order to flush the CRC
    if symbolCount > Npad+Nts && symbolCount <= Npad+Nts+numberSymbols+16
        
        valueCRCsh1 = bitsll(valueCRC, 1);
        valueCRCadd1 = bitor(valueCRCsh1, fi(bitOut, 0,16,0, fm));
        leadValue = bitget(valueCRCadd1,16);
        if leadValue == 1
            valueCRCxor = bitxor(valueCRCadd1, genPoly);
        else
            valueCRCxor = valueCRCadd1;
        end
        valueCRC = valueCRCxor;
        if symbolCount == Npad+Nts+numberSymbols+16,
            crcVector(:) = bitget( valueCRC, 16:-1:1);
        end
    end

    if diffOn == 0 || symbolCount <= Npad+Nts
        symbolOut(:) = bitOut;
    else
        if bitPrev == bitOut
            symbolOut(:) = 1;
        else
            symbolOut(:) = 0;
        end
    end
    bitPrev(:) = symbolOut;

    symbolCount = symbolCount + 1; %total number of symbols transmitted
else
    % we're not processing a packet and waiting for a new packet to arrive
    if emptyFlag == 0
        % reset everything
        inPacketFlag = 1;
        % toggle re to grab data
        reByte = 1;
        symbolCount = 1;
        bitOfByteIndex = 1;
        valueCRC(:) = 65535;
        bitPrev(:) = 0;
    end
end
	  
end


type(testbench_name);
function mlhdlc_comms_data_packet_tb

% generate transmit data, note the first two bytes are the data length
numberBytes = 8; % this is total number of symbols
numberSymbols = numberBytes*8;
rng(1); % always default to known state
data = [floor(numberBytes/2^8) mod(numberBytes,2^8) ...
    round(rand(1,numberBytes-2)*255)];

% generate training data helper function
make_train_data('TRAIN_DATA');

% make sure training data is generated
pause(2)
[~] = which('TRAIN_DATA');

trainBits1 = TRAIN_DATA;
Nts = length(trainBits1);

make_pad_data('PAD_DATA');
pause(2)
[~] = which('PAD_DATA');
Npad = 2^9;

% Give number of samples, where the start of the sequence flag will be
% (indicated by a zero), as well as an output buffer for generated symbols
Nsamp = 1000;
Noffset = 20;
emptyFlagHold = ones(1,Nsamp); emptyFlagHold(Noffset) = 0;
symbolOutHold = zeros(1,Nsamp);

dataIndex = 1;
byteValue = 0;
diffOn = 1; % 0 - regular encoding, 1 - differential encoding
for i1 = 1:Nsamp,
    emptyFlag = emptyFlagHold(i1);
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Call to the design
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    [symbolOut, reByte] = ...
        mlhdlc_comms_data_packet(emptyFlag, byteValue, numberSymbols, diffOn, Nts, Npad);
    
    % This set of code emulates the external FIFO interface
    if reByte == 1 % when high, pop a value off the input FIFO
        byteValue = data(dataIndex);
        dataIndex = dataIndex + 1;
    end
    symbolOutHold(i1) = symbolOut;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This is all code to verify we did the encoding properly
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% grad training data - not differentially encoded
symbolTrain = symbolOutHold(1+Noffset+Npad:Noffset+Npad+Nts);

% grab user data and decode if necessary
symbolEst = zeros(1,numberSymbols);
symbolPrev = trainBits1(end);
if diffOn == 0
    symbolData = ...
        symbolOutHold(1+Noffset+Npad+Nts:Noffset+Npad+Nts+numberSymbols); %#ok<NASGU>
else
    % decoding is simply comparing adjacent received symbols
    symbolTemp = ...
       symbolOutHold(1+Noffset+Npad+Nts:Noffset+Npad+Nts+numberSymbols+32);
    for i1 = 1:length(symbolTemp)
        if symbolTemp(i1) == symbolPrev
            symbolEst(i1) = 1;
        else
            symbolEst(i1) = 0;
        end
        symbolPrev = symbolTemp(i1);
    end
end

% training data
trainDataEst = symbolTrain(1:Nts);
trainDiff = abs(trainDataEst-trainBits1');

% user data
userDataEst = symbolEst(1:numberSymbols);
dataEst = zeros(1,numberBytes);
for i1 = 1:numberBytes
    y = userDataEst((i1-1)*8+1:i1*8);
    dataEst(i1) = bin2dec(char(y+48));
end
userDiff = abs(dataEst-data);    

disp(['Training Difference: ',num2str(sum(trainDiff)), ...
    ' User Data Difference: ',num2str(sum(userDiff))]);

% run it through and check CRC
genPoly = 69665;
c = symbolEst;
cEst = c(1,:);
cEst2 = [cEst(1:end-32) cEst(end-15:end)];
cEst = cEst2;

valueCRCc = 65535;
for i1 = 1:length(cEst),
    valueCRCsh1 = bitsll(uint16(valueCRCc), 1);
    valueCRCadd1 = bitor(uint16(valueCRCsh1), cEst(i1));
    leadValue = bitget( valueCRCadd1, 16);
    if (leadValue == 1)
        valueCRCxor = bitxor(uint16(valueCRCadd1), uint16(genPoly));
    else
        valueCRCxor = bitxor(uint16(valueCRCadd1), 0);
    end
    valueCRCc = valueCRCxor;
end
if valueCRCc == 0
    disp('CRC decoded correctly');
else
    disp('CRC check failed');
end

function make_train_data(filename)
x  = load('mlhdlc_dpack_train_data.txt');
fid = fopen([filename,'.m'],'w+');
fprintf(fid,['function y = ' filename '\n']);
fprintf(fid,'%%#codegen\n');
fprintf(fid,'y = [\n');
fprintf(fid,'%1.0e\n',x);
fprintf(fid,'];\n');
fclose(fid);

function make_pad_data(filename) 
rng(1);
x = round(rand(1,2^9));
fid = fopen([filename,'.m'],'w+');
fprintf(fid,['function y = ' filename '\n']);
fprintf(fid,'%%#codegen\n');
fprintf(fid,'y = [\n');
fprintf(fid,'%1.0e\n',x);
fprintf(fid,'];\n');
fclose(fid);


Create a New Folder and Copy Relevant Files

Execute the following lines of code to copy the necessary example files into a temporary folder.

mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos');
mlhdlc_temp_dir = [tempdir 'mlhdlc_dpack'];

% Create a temporary folder and copy the MATLAB files.
cd(tempdir);
[~, ~, ~] = rmdir(mlhdlc_temp_dir, 's');
mkdir(mlhdlc_temp_dir);
cd(mlhdlc_temp_dir);

copyfile(fullfile(mlhdlc_demo_dir, [design_name,'.m*']), mlhdlc_temp_dir);
copyfile(fullfile(mlhdlc_demo_dir, [testbench_name,'.m*']), mlhdlc_temp_dir);

Simulate the Design

It is always a good practice to simulate the design with the testbench prior to code generation to make sure there are no runtime errors.

mlhdlc_comms_data_packet_tb
Training Difference: 0 User Data Difference: 0
CRC decoded correctly

Create a New HDL Coder™ Project

coder -hdlcoder -new mlhdlc_dpack

Next, add the file 'mlhdlc_comms_data_packet.m' to the project as the MATLAB Function and 'mlhdlc_comms_data_packet_tb.m' as the MATLAB Test Bench.

You can refer to Getting Started with MATLAB to HDL Workflow tutorial for a more complete tutorial on creating and populating MATLAB HDL Coder projects.

Run Fixed-Point Conversion and HDL Code Generation

Launch the Workflow Advisor from the Build tab and right click on the 'Code Generation' step and choose the option 'Run to selected task' to run all the steps from the beginning through the HDL code generation.

Examine the generated HDL code by clicking on the hyperlinks in the Code Generation Log window.

Clean up the Generated Files

You can run the following commands to clean up the temporary project folder.

mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos');
mlhdlc_temp_dir = [tempdir 'mlhdlc_dpack'];
clear mex;
cd (mlhdlc_demo_dir);
rmdir(mlhdlc_temp_dir, 's');
Was this topic helpful?