Accelerating the pace of engineering and science

# HDL Coder

## 2D FIR Filter

This example shows how to generate HDL code from a MATLAB® design that unsharps an image using 2D FIR filtering.

Algorithm

The image unsharp technique filters images with a 2D unsharp kernel so the contrast of the image is enhanced. The following MATLAB code shows the effects of unsharping.

```image_in = imread('mlhdlc_cameraman.tif'); H = fspecial('unsharp'); filt_image = imfilter(image_in,H); figure; subplot(1,2,1); imshow(image_in); title('Original'); subplot(1,2,2); imshow(filt_image); title('Sharpened'); ```

MATLAB Design

The following example shows how to implement the image processing algorithm for HDL code generation.

```design_name = 'mlhdlc_2DFIR'; testbench_name = 'mlhdlc_2DFIR_tb'; ```

Let us take a look at the MATLAB design

```type(design_name); ```
```%#codegen function [pixel_out] = mlhdlc_2DFIR(pixel_in) % % The 2D FIR algorithm maintains three line buffers. Each iteration the % input pixel is pushed into the current line buffer that is being written to. % The control logic rotates between these three buffers when it reaches the % column boundary. % % Each buffer is followed by a shift register and data at the current % column index is pushed into the shift register. % % At each iteration a 3x3 kernel of pixels is formed from the pixel input, shift % registers and line buffer outputs. % % The kernel is multiplied by a 3x3 filter coefficient mask and the sum of % the resultant values is computed as the pixel output. nRows = 260; nCols = 260; mask = [-0.1667 -0.6667 -0.1667 -0.6667 4.3333 -0.6667 -0.1667 -0.6667 -0.1667]; persistent row_count; persistent col_count; persistent t_minus_1_pixel; persistent t_minus_2_pixel; persistent t_minus_1_memrow1; persistent t_minus_2_memrow1; persistent t_minus_1_memrow2; persistent t_minus_2_memrow2; persistent t_minus_1_memrow3; persistent t_minus_2_memrow3; persistent mem_row_idx; persistent mem_row1; persistent mem_row2; persistent mem_row3; if isempty(t_minus_1_memrow3) t_minus_1_memrow3 = 0; t_minus_2_memrow3 = 0; t_minus_1_memrow2 = 0; t_minus_2_memrow2 = 0; t_minus_1_memrow1 = 0; t_minus_2_memrow1 = 0; row_count = 1; col_count = 1; t_minus_1_pixel = 0; t_minus_2_pixel = 0; mem_row_idx = 1; mem_row1 = zeros(1,nCols); mem_row2 = zeros(1,nCols); mem_row3 = zeros(1,nCols); end row_count_r=row_count; col_count_r=col_count; t_minus_1_pixel_r=t_minus_1_pixel; t_minus_2_pixel_r=t_minus_2_pixel; t_minus_1_memrow1_r=t_minus_1_memrow1; t_minus_2_memrow1_r=t_minus_2_memrow1; t_minus_1_memrow2_r=t_minus_1_memrow2; t_minus_2_memrow2_r=t_minus_2_memrow2; t_minus_1_memrow3_r=t_minus_1_memrow3; t_minus_2_memrow3_r=t_minus_2_memrow3; mem_row_idx_r = mem_row_idx; write_col_idx = col_count_r; current_mem_row1_data = mem_row1(write_col_idx); current_mem_row2_data = mem_row2(write_col_idx); current_mem_row3_data = mem_row3(write_col_idx); if mem_row_idx_r==1 top_row= [t_minus_2_memrow2_r t_minus_1_memrow2_r current_mem_row2_data]; middle_row= [t_minus_2_memrow3_r t_minus_1_memrow3_r current_mem_row3_data]; elseif mem_row_idx_r==2 top_row= [t_minus_2_memrow3_r t_minus_1_memrow3_r current_mem_row3_data]; middle_row= [t_minus_2_memrow1_r t_minus_1_memrow1_r current_mem_row1_data]; else top_row= [t_minus_2_memrow1_r t_minus_1_memrow1_r current_mem_row1_data]; middle_row= [t_minus_2_memrow2_r t_minus_1_memrow2_r current_mem_row2_data]; end bottom_row = [ t_minus_2_pixel_r t_minus_1_pixel_r pixel_in]; kernel = [top_row middle_row bottom_row]; if col_count_r>=3 && row_count_r>=3 %pixel_out=sum(operand.*mask); m1 = kernel(1) * mask(1); m2 = kernel(2) * mask(2); m3 = kernel(3) * mask(3); m4 = kernel(4) * mask(4); m5 = kernel(5) * mask(5); m6 = kernel(6) * mask(6); m7 = kernel(7) * mask(7); m8 = kernel(8) * mask(8); m9 = kernel(9) * mask(9); % tree of adders s1 = m1 + m2; s2 = m3 + m4; s3 = m5 + m6; s4 = m7 + m8; s21 = s1 + s2; s22 = s3 + s4; s31 = s21 + s22; pixel_out = s31 + m9; else pixel_out=0; end if mem_row_idx_r==1 mem_row1_write_data = pixel_in; mem_row2_write_data = current_mem_row2_data; mem_row3_write_data = current_mem_row3_data; elseif mem_row_idx_r==2 mem_row1_write_data = current_mem_row1_data; mem_row2_write_data = pixel_in; mem_row3_write_data = current_mem_row3_data; else mem_row1_write_data = current_mem_row1_data; mem_row2_write_data = current_mem_row2_data; mem_row3_write_data = pixel_in; end mem_row1(write_col_idx)=mem_row1_write_data; mem_row2(write_col_idx)=mem_row2_write_data; mem_row3(write_col_idx)=mem_row3_write_data; if col_count_r==nCols %toggle memrow if mem_row_idx_r ==1; mem_row_idx=2; elseif mem_row_idx_r ==2; mem_row_idx=3; else mem_row_idx=1; end end t_minus_1_pixel = pixel_in; t_minus_2_pixel = t_minus_1_pixel_r; t_minus_1_memrow1=current_mem_row1_data; t_minus_2_memrow1=t_minus_1_memrow1_r; t_minus_1_memrow2=current_mem_row2_data; t_minus_2_memrow2=t_minus_1_memrow2_r; t_minus_1_memrow3=current_mem_row3_data; t_minus_2_memrow3=t_minus_1_memrow3_r; if col_count_r+1<=nCols col_count = col_count_r+1; else col_count = 1; if row_count_r<nRows row_count = row_count_r+1; else row_count = 1; end end end ```
```type(testbench_name); ```
```clear mlhdlc_2DFIR; TOL = 1e-6; % Read the image image_in = double(imread('mlhdlc_cameraman.tif')); H = fspecial('unsharp'); % Pad the image [rows pixels] = size(image_in); pad_vert_im = [ zeros(1,pixels);zeros(1,pixels);image_in;... zeros(1,pixels);zeros(1,pixels)]; pad_horiz_im = [ zeros(rows+4,2) pad_vert_im zeros(rows+4,2)]; % Reshape the image as a vector [rows pixels] = size(pad_horiz_im); image_vector_length = rows*pixels; image_in_vector = reshape(pad_horiz_im',1,image_vector_length); % Pre-allocating y for simulation performance y = zeros(1,length(image_in_vector)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Streaming loop calling the design %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% for i = 1:length(image_in_vector) y(i) = mlhdlc_2DFIR(image_in_vector(i)); end % Reshape the output back to a 2D matrix image_out = reshape(y,pixels,rows)'; filt_image = imfilter(image_in,H,0); err = filt_image-image_out(4:end-1,4:end-1); err = (err > TOL) .* err; figure('Name', [mfilename, '_plot']); subplot(1,2,1); imshow(int8(image_out(4:end-1,4:end-1)));title('HDL Output'); subplot(1,2,2); imshow(err);title('Difference'); ```

Simulate the Design

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

```mlhdlc_2DFIR_tb ```

Setup for the Example

Executing the following lines of code copies the necessary example files into a temporary folder

```mlhdlc_demo_dir = fullfile(matlabroot, 'toolbox', 'hdlcoder', 'hdlcoderdemos', 'matlabhdlcoderdemos'); mlhdlc_temp_dir = [tempdir 'mlhdlc_sobel']; % create a temporary folder and copy the MATLAB files [~, ~, ~] = rmdir(mlhdlc_temp_dir, 's'); mkdir(mlhdlc_temp_dir); cd(mlhdlc_temp_dir); % copy the design files to the temporary directory copyfile(fullfile(mlhdlc_demo_dir, [design_name,'.m*']), mlhdlc_temp_dir); copyfile(fullfile(mlhdlc_demo_dir, [testbench_name,'.m*']), mlhdlc_temp_dir); ```

Create a New HDL Coder™ Project

```coder -hdlcoder -new mlhdlc_2dfir_prj ```

Next, add the file 'mlhdlc_2DFIR.m' to the project as the MATLAB Function and 'mlhdlc_2DFIR_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 HDL Advisor 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.

Enable Distributed Pipelining Option

To improve clock frequency of the synthesized circuit you can use the distributed pipelining option to pipeline the multipliers inferred in the design.

1. Choose the option 'Output Pipeline: 10'

2. Enable the option 'Distribute Pipeline Registers'

3. Reset the 'Code Generation' task

4. Rerun the code generation and synthesis steps and examine the synthesis results.

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_sobel']; clear mex; cd (mlhdlc_demo_dir); rmdir(mlhdlc_temp_dir, 's'); ```