20.5 构建目标板代码

本文详细介绍了如何为Mini2440开发板移植Linux内核,包括处理器初始化、端口映射、中断处理和定时器设置等步骤,并提供了具体的代码实例。

20.5  构建目标板代码

Linux内核已经为ARM处理器设计好了代码框架,只要按照这个框架加入针对某种开发板和处理器的代码即可工作。加入代码还是按照前面提到的原则,能使用已有的通用代码尽量使用,并且尽可能地参考现有开发板代码的处理方法。

20.5.1  处理器初始化

首先在mach-mini2440.c文件中加入处理器初始化代码如下:

 

56 void __init mini2440_init(void)

57 {

58   set_s3c2410ts_info(&mini2440_ts_cfg);        // 注册触摸屏结构

59   set_s3c2410udc_info(&mini2440_udc_cfg); // 注册UDC结构

60   set_s3c2410fb_info(&mini2440_lcdcfg);        // 注册LCD结构

61 }

 

mini2440_init()函数中注册了3个结构,分别用于初始化触摸屏、UDCLCD,这3个结构都是针对三星ARM9处理器的。接下来定义这三个结构代码如下:

 

53 static struct s3c2410_ts_mach_info mini2440_ts_cfg __initdata = {

54   .delay = 20000,

55   .presc = 55,

56   .oversampling_shift = 2,

57 };

58

59

60 static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = {

61   .udc_command = pullup,     // 设置udc处理函数

62 }; 

63

64

65 static struct s3c2410fb_mach_info mini2440_lcdcfg __initdata = {

66   .regs = {                 // 设置控制寄存器

67     .lcdcon1 =  S3C2410_LCDCON1_TFT16BPP | /

68         S3C2410_LCDCON1_TFT | /

69         S3C2410_LCDCON1_CLKVAL(0x04),

70        

71     .lcdcon2 =  S3C2410_LCDCON2_VBPD(1) | /

72         S3C2410_LCDCON2_LINEVAL(319) | /

73         S3C2410_LCDCON2_VFPD(5) | /

74         S3C2410_LCDCON2_VSPW(1),

75

76     .lcdcon3 =  S3C2410_LCDCON3_HBPD(36) | /

77         S3C2410_LCDCON3_HOZVAL(239) | /

78         S3C2410_LCDCON3_HFPD(19),

79

80     .lcdcon4 =  S3C2410_LCDCON4_MVAL(13) | /

81         S3C2410_LCDCON4_HSPW(5),

82

83     .lcdcon5 =  S3C2410_LCDCON5_FRM565 |

84         S3C2410_LCDCON5_INVVLINE |

85         S3C2410_LCDCON5_INVVFRAME |

86         S3C2410_LCDCON5_PWREN |

87         S3C2410_LCDCON5_HWSWP,

88   },

89

90   .lpcsel = 0xf82,

91

92   .gpccon = 0xaa955699,

93   .gpccon_mask =  0xffc003cc,

94   .gpcup =  0x0000ffff,

95   .gpcup_mask = 0xffffffff,

96

97   .gpdcon = 0xaa95aaa1,          // 设置通用控制寄存器

98   .gpdcon_mask =  0xffc0fff0,  // 通用控制寄存器掩码

99   .gpdup =  0x0000faff,          // 设置通用控制寄存器

100   .gpdup_mask = 0xffffffff,      // 通用控制寄存器掩码

101

102   .fixed_syncs =  1,              // 同步

103   .width  = 240,                    // 设置屏幕宽度像素值

104   .height = 320,                // 设置屏幕高度像素值

105

106   .xres = {                       // 设置LCD屏幕横向像素值

107     .min =    240,                // 最小值

108     .max =    240,                // 最大值

109     .defval = 240,                // 默认值

110   },

111

112   .yres = {                       // 设置LCD屏幕纵向像素值

113     .max =    320,                // 最大值

114     .min =    320,                // 最小值

115     .defval = 320,                // 默认值

116   },

117

118   .bpp  = {                     // 颜色位数

119     .min =    16,                // 最小值

120     .max =    16,                // 最大值

121     .defval = 16,                // 默认值

122   },

123 };

 

mini2440_ts_cfg结构定义了触摸屏相关参数;mini2440_lcdcfg结构定义了LCD控制器相关参数,S3C2440提供了一组LCD控制器,用于设置LCD的颜色、像素值、数据传输方式、同步方式等结构。读者可以参考S3C2440处理器手册,对照代码中的值得到配置的方式。

%提示:LCD控制器的配置比较复杂,S3C2440提供的LCD控制器仅支持数字信号输入的液晶屏,在连接液晶屏之前需要参考液晶屏的手册。

mini2440_udc_cfg结构中使用了一个pullup回调函数,定义如下:

 

52 static void pullup(unsigned char cmd)

53 {

54   switch (cmd)

55   {

56     case S3C2410_UDC_P_ENABLE :    // 打开UDC

57       break;

58     case S3C2410_UDC_P_DISABLE :    // 关闭UDC

59       break;

60     case S3C2410_UDC_P_RESET : // 重启UDC

61       break;

62     default: break;

63   }

64 }

 

pullup()函数不做任何处理,如果以后需要添加对UDC的处理可以在pullup()函数中加入处理代码。

20.5.2  端口映射

端口映射函数设置S3C2440处理器的I/O端口描述结构、时钟频率、串口等,代码       如下:

 

150 void __init mini2440_map_io(void)

151 {

152   s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc));                                                      // 初始化I/O结构

153   s3c24xx_init_clocks(12000000);             // 设置时钟频率

154   s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartc
fgs));                                              //
设置串口结构

155   s3c24xx_set_board(&mini2440_board);            // 设置开发板结构

156   s3c_device_nand.dev.platform_data = &bit_nand_info;

157 }

 

mini2440_map_io()函数中,初始化了3个结构,定义如下:

 

66 static struct map_desc mini2440_iodesc[] __initdata = {

67   {vSMDK2410_ETH_IO, pSMDK2410_ETH_IO, SZ_1M, MT_DEVICE},
                                                    //
网卡接口映射

68   {0xe0000000, 0x08000000, 0x00100000, MT_DEVICE},

69   {0xe0100000, 0x10000000, 0x00100000, MT_DEVICE},

70   { (unsigned long)S3C24XX_VA_IIS, S3C2410_PA_IIS, S3C24XX_SZ_IIS, MT_      DEVICE },

71 };

72

73 static struct s3c2410_uartcfg mini2440_uartcfgs[] = {

74   [0] = {

75     .hwport          = 0,    // 串口0

76     .flags           = 0,

77     .ucon            = 0x3c5,

78     .ulcon           = 0x03,

79     .ufcon           = 0x51,

80   },

81   [1] = {

82     .hwport        = 1,    // 串口1

83     .flags     = 0,

84     .ucon           = 0x3c5,

85     .ulcon     = 0x03,

86     .ufcon           = 0x51,

87   },

88   [2] = {

89     .hwport          = 2,    // 红外线接口

90     .flags           = 0,

91     .uart_flags      = 0,

92     .ucon      = 0x3c5,

93     .ulcon           = 0x03,

94     .ufcon           = 0x51,

95   }

96 };

97

98 static struct s3c24xx_board mini2440_board __initdata = {

99   .devices          = mini2440_devices,                    // 开发板设备列表

100   .devices_count = ARRAY_SIZE(mini2440_devices)    // 结构大小

101 };

map_desc结构描述了内存虚拟地址和物理地址之间的关系,供配置MMU使用。mini2440_uartcfgs[]结构描述了开发板上两个串口和一个红外线接口的定义。mini2440_ board结构描述了开发板上存在的设备列表mini2440_devices,定义如下:

 

66 static struct platform_device *mini2440_devices[] __initdata = {

67   &s3c_device_lcd,     // LCD控制器

68   &s3c_device_wdt,     // 看门狗控制器

69   &s3c_device_i2c,     // I2C控制器

70   &s3c_device_ts,      // 触摸屏控制器

71   &s3c_device_nand,        // NAND Flash控制器

72   &s3c_device_rtc,     // RTC控制器

73 };

 

mini2440_devices结构中定义了LCD控制器、看门狗控制器、I2C控制器、触摸屏控制器等结构,这些结构的定义都是使用内核提供的标准结构,定义在devs.c文件中。

20.5.3  中断处理

内核提供了一个s3c24xx_init_irq()处理函数,因此中断处理函数直接引用即可。

 

186 void __init mini2440_init_irq(void)

187 {

188   s3c24xx_init_irq();    // 调用系统提供的中断处理函数

189 }

20.5.4  定时器处理

内核提供了一个定时器处理函数结构如下。

 

struct sys_timer s3c24xx_timer = {

    .init        = s3c2410_timer_init,            // 定时器初始化函数

    .offset      = s3c2410_gettimeoffset,        // 获取定时器值

    .resume      = s3c2410_timer_setup           // 恢复定时器设置

};

 

在代码中直接使用s3c24xx_timer结构即可。

20.5.5  编译最终代码

到目前为止,已经添加了所有与mini2440开发板有关的代码,保存文件后,可以开始编译内核。回到内核代码根目录,执行“make ARCH=arm CROSS_COMPILE=arm-linux- bzImage”重新编译代码,最终在arch/arm/boot目录下生成bzImage文件,针对开发板的内核代码编译成功。

通过U-Boot或者其他的Bootloader工具可以把代码烧写到开发板的Flash存储器上,然后重新启动开发板,可以从液晶屏看到启动过程打印的提示信息。

%提示:由于没有设置USB控制器和声音控制器,因此开发板上和USB及声音相关的功能都无法使用。

%% ======================================================== % SD-OCT 仿真框架(激光焊接专用)—— 高保真物理模型 + ZPD对齐 + 熔深提取 % 特点: % - ZPD 居中,表面对齐 z≈0 % - 真实噪声模型(散粒+读出+漂移) % - 包络检波、k空间重采样、Hanning窗 % - 熔深提取基于末尾显著峰 % - 输出统计 + 数据保存 %% ======================================================== clear; clc; close all; %% ==================== 系统参数 ==================== lambda_center = 840e-9; % 中心波长 (m) bandwidth_FWHM = 40e-9; % FWHM 带宽 (m) sigma_lambda = bandwidth_FWHM / (2 * sqrt(2 * log(2))); % 高斯标准差 N_pixels = 2048; % 光谱仪像素数 lateral_range = 40e-3; % 扫描总长度 (m) lateral_resolution = 20.5e-6; % 单步分辨率 lateral_step = 2 * lateral_resolution; % 采样间隔 ~41 μm N_AScans = max(1, round(lateral_range / lateral_step)); % 构造波长向量 lambda_min = lambda_center - 3 * sigma_lambda; lambda_max = lambda_center + 3 * sigma_lambda; lambda = linspace(lambda_min, lambda_max, N_pixels)'; % k空间基础 k_vec = 2 * pi ./ lambda; % 添加轻微非线性畸变(模拟 spectrometer 色散不均) distortion = 1e4 * (k_vec - mean(k_vec)).^2 / max(k_vec)^2; k_vec = k_vec + distortion; % 深度轴(对称,ZPD 在中心) c = 3e8; n_eff = 1.0; dz = pi / (n_eff * (max(k_vec) - min(k_vec))); z_axis_full = (-N_pixels/2 : N_pixels/2 - 1)' * dz; z_mm = z_axis_full * 1e3; % mm x_mm = (0:N_AScans-1)' * lateral_step * 1e3; % 噪声参数 read_noise_std = 0.01; shot_noise_factor = 1.0; % 控制散粒噪声强度 source_instability = 0.03; min_peak_height_ratio = 0.05; min_peak_distance_base = round(N_pixels / 50); fprintf('🔍 波长范围: %.2f ~ %.2f nm\n', min(lambda)*1e9, max(lambda)*1e9); fprintf('📏 轴向分辨率: %.2f μm\n', (2*log(2)/pi) * lambda_center^2 / bandwidth_FWHM * 1e6); fprintf('🔄 正在模拟 %d 条 A-scan...\n', N_AScans); %% ==================== 初始化变量 ==================== bscan_intensity = zeros(N_pixels, N_AScans); all_detected_points = cell(1, N_AScans); example_spectrum_raw = []; example_spectrum_proc = []; example_ascan = []; %% ==================== 主循环:模拟采集 ==================== for idx = 1:N_AScans try %% Step 1: 构建物理结构 surface_depth = -25e-6 + 50e-6 * rand(); % ±25μm 浮动 % 熔池散射点:密度随深度递减(指数分布) num_scatterers = randi([5, 12]); depths_norm = exprnd(1.8e-3, [num_scatterers, 1]); depths_pool = surface_depth + 1.0e-3 + depths_norm; reflections_pool = 0.08 + 0.07 * rand(num_scatterers, 1); bottom_depth = surface_depth + 2.8e-3 + 0.4e-3*rand(); depths_all = [surface_depth; depths_pool; bottom_depth]; reflections_all = [0.35; reflections_pool; 0.4]; % 表面强反射 % 5%概率添加虚假深层点 if rand() < 0.05 fake_deep = bottom_depth + 0.1e-3 + 0.3e-3*rand(); depths_all = [depths_all; fake_deep]; reflections_all = [reflections_all; 0.05]; end %% Step 2: 生成光谱 raw_spectrum = generate_spectrum(lambda, k_vec, lambda_center, sigma_lambda, ... depths_all, reflections_all, read_noise_std, shot_noise_factor, source_instability); if isempty(example_spectrum_raw) example_spectrum_raw = raw_spectrum; end %% Step 3: 处理链 dc_removed = remove_dc(raw_spectrum); [k_uniform, spec_resampled] = resample_to_uniform_k(k_vec, dc_removed); if any(isnan(spec_resampled)) error('NaN detected in resampling'); end spec_shaped = apply_window(spec_resampled, 'hanning'); ascan_envelope = compute_ascan(k_uniform, spec_shaped); if isempty(example_spectrum_proc) example_spectrum_proc = spec_resampled; example_ascan = ascan_envelope; end bscan_intensity(:, idx) = ascan_envelope; %% Step 4: 提取反射点(仅 z ≥ 0) valid_positive = (z_mm >= 0); z_pos = z_mm(valid_positive); a_pos = ascan_envelope(valid_positive); min_dist = max(5, round(length(z_pos)/50)); [peaks, locs] = findpeaks(a_pos, 'MinPeakHeight', max(a_pos)*0.05, 'MinPeakDistance', min_dist); detected_z = z_pos(locs); detected_z = detected_z(detected_z <= max(z_mm)*0.95); % 截断边缘 all_detected_points{idx} = detected_z; catch ME fprintf('❌ A-scan %d 失败: %s\n', idx, ME.message); bscan_intensity(:, idx) = eps; all_detected_points{idx} = []; end end fprintf('✅ 采集完成!\n'); %% ==================== 数据后处理:构建 pts_clean ==================== valid_mask = ~cellfun(@isempty, all_detected_points); if any(valid_mask) pts_cat = vertcat(all_detected_points{valid_mask}); pts_clean = pts_cat(pts_cat >= 0 & pts_cat <= max(z_mm)); else pts_clean = []; end %% ==================== 图1:五阶段处理链 ==================== figure('Name', '图1:五阶段处理链', 'Position', [100, 100, 1100, 700]); subplot(3,2,1); plot(lambda*1e9, example_spectrum_raw); title('① 原始光谱'); xlabel('\lambda (nm)'); subplot(3,2,2); plot(k_vec, example_spectrum_raw); title('② k空间'); xlabel('k (rad/m)'); dc_removed = remove_dc(example_spectrum_raw); subplot(3,2,3); plot(k_vec, dc_removed); title('③ 去DC'); [k_uni, spec_r] = resample_to_uniform_k(k_vec, dc_removed); subplot(3,2,4); plot(k_uni, spec_r); title('④ 均匀k'); w_spec = apply_window(spec_r, 'hanning'); subplot(3,2,5); plot(k_uni, w_spec); title('⑤ 加窗'); env = compute_ascan(k_uni, w_spec); subplot(3,2,6); plot(z_mm, env, 'c'); ax = gca; ax.XAxisLocation='origin'; grid on; title('⑥ A-scan包络'); try exportgraphics(gcf, 'figure1_chain.png', 'Resolution', 300); end %% ==================== 图2:A-scan 分析 ==================== figure('Name', '图2:反射密度分析', 'Position', [200, 200, 900, 500]); valid_region = (z_mm >= 0); z_pos = z_mm(valid_region); a_pos = example_ascan(valid_region); min_peak_height = max(a_pos) * 0.1; [~, pk_idx] = findpeaks(a_pos, 'MinPeakHeight', min_peak_height, 'MinPeakDistance', 5); yyaxis left plot(z_mm, example_ascan, 'b', 'LineWidth', 1.2); hold on; if ~isempty(pk_idx) plot(z_pos(pk_idx), a_pos(pk_idx), 'ro', 'MarkerFaceColor', 'r', 'MarkerSize', 6); end ylabel('反射强度'); ylim auto; bin_width = 0.05; bins = 0:bin_width:max(z_mm); [den, ~] = histcounts(pts_clean, bins); den_smooth = smoothdata(den, 'gaussian', 5); bin_centers = bins(1:end-1) + bin_width/2; yyaxis right plot(bin_centers, den_smooth, 'k--', 'LineWidth', 2); ylabel('反射点密度(平滑)'); title('A-scan 包络 + 检测峰值 + 空间密度分布'); xlabel('深度 z (mm)'); legend('A-scan包络', '检测到的峰', '空间密度趋势', 'Location', 'best'); grid on; hold off; %% ==================== 图3:B-scan 与 熔深 ==================== figure('Name', '图3:B-scan 与 熔深提取', 'Position', [100, 100, 1200, 800]); img_log = log10(bscan_intensity + 1e-10); subplot(2,1,1); imagesc(x_mm, z_mm, img_log); axis image; colorbar; colormap(flipud(gray)); title('B-scan: 对数反射强度'); ylabel('深度 z (mm)'); hold on; for idx = 1:N_AScans x = x_mm(idx); pts = all_detected_points{idx}; if ~isempty(pts) plot(repmat(x, length(pts), 1), pts, 'y.', 'MarkerSize', 3); end end % 提取熔深:取每个 A-scan 最深的有效峰 melt_depth_curve = NaN(size(x_mm)); for idx = 1:N_AScans pts = all_detected_points{idx}; if isempty(pts), continue; end [vals, ~] = sort(pts, 'descend'); for v = vals' if v > 1.0 && v < max(z_mm)*0.95 melt_depth_curve(idx) = v; break; end end end % 插值修复 NaN valid_md = ~isnan(melt_depth_curve); if sum(valid_md) >= 2 melt_depth_curve = interp1(x_mm(valid_md), melt_depth_curve(valid_md), x_mm, 'linear'); else melt_depth_curve = fillmissing(melt_depth_curve, 'nearest'); end plot(x_mm, melt_depth_curve, 'r-', 'LineWidth', 2.5); legend('反射点', '估计熔深', 'Location', 'best'); hold off; subplot(2,1,2); plot(x_mm, melt_depth_curve, 'b-', 'LineWidth', 2); xlabel('x (mm)'); ylabel('熔深 (mm)'); title('熔深曲线'); grid on; % 安全设置 ylim valid_vals = melt_depth_curve(~isnan(melt_depth_curve)); if isempty(valid_vals) ylim([0, 1]); % 默认范围 else ylim([0, max(valid_vals)*1.1]); end sgtitle('📌 B-scan 与 熔深提取:ZPD对齐表面,熔深为正'); %% ==================== 输出统计与保存 ==================== fprintf('\n📊 统计信息:\n'); fprintf(' 总A-scan数量: %d\n', N_AScans); avg_pts = mean(cellfun(@numel, all_detected_points)); fprintf(' 平均每A-scan检测到 %.1f 个反射点\n', avg_pts); if all(isnan(melt_depth_curve)) fprintf('⚠️ 未能提取任何有效熔深!\n'); else range_md = [min(melt_depth_curve, [], 'omitnan'), max(melt_depth_curve, [], 'omitnan')]; fprintf(' 提取熔深范围: %.2f ~ %.2f mm\n', range_md(1), range_md(2)); fprintf(' 平均熔深: %.2f mm\n', mean(melt_depth_curve, 'omitnan')); end save('sd_oct_simulation_result.mat', 'bscan_intensity', 'melt_depth_curve', 'x_mm', 'z_mm', 'all_detected_points'); fprintf('💾 结果已保存至 sd_oct_simulation_result.mat\n'); disp('🎉 SD-OCT 高保真仿真完成!'); %% ========== 子函数1:生成光谱 ========== function spectrum = generate_spectrum(lambda, k_vec, lambda_center, sigma_lambda, depths, reflections, noise_std, shot_factor, instability) N = length(lambda); I0 = exp(-(lambda - lambda_center).^2 / (2*sigma_lambda^2)); interference = zeros(N,1); for i = 1:length(depths) phase = 2 * k_vec * depths(i); interference = interference + reflections(i) * cos(phase); end I_total = I0 + interference; I_total = max(I_total, 0); noise_readout = noise_std * randn(N,1); noise_shot = shot_factor * sqrt(I_total) .* randn(N,1); noise_drift = instability * I0 * randn(); spectrum = I_total + noise_readout + noise_shot + noise_drift; end %% ========== 子函数2:去直流 ========== function y = remove_dc(x) background = mean(x(1:2048)); y = x - background; end %% ========== 子函数3:k空间重采样 ========== function [k_new, y_new] = resample_to_uniform_k(k, y) k_new = linspace(min(k), max(k), length(k))'; y_new = interp1(k, y, k_new, 'pchip', 'extrap'); end %% ========== 子函数4:加窗 ========== function y = apply_window(x, type_str) w = window(@hann, length(x)); y = x .* w(:); end %% ========== 子函数5:计算A-scan包络 ========== function envelope = compute_ascan(k_uniform, spectrum) spec_shifted = ifftshift(spectrum(:)); ascan_complex = fft(spec_shifted); envelope = abs(ascan_complex); end 上述整个代码的功能是用于实现对SD-OCT原始光谱数据的处理,并最终生成了B-scan信号;但是对于过程中具体的细节处理,我不是很明白;请你首先解释清楚每一步的物理含义,其次再从代码解释的角度出发,解释清楚代码的含义; 关于物理意义的解释,不仅仅需要文字解释,最好是通过公式的角度清晰的说明白,我需要明白整个数据处理的流程与原理
最新发布
10-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值