第32课 · GPIO+PWM

GPIOPWMLED驱动

📌 学习目标:理解 GPIO 和 PWM 原理,实现 GPIO 控制器和 PWM 发生器,通过 Verilator 验证占空比控制。

一、GPIO 通用输入输出

GPIO寄存器:DIR(方向), OUT(输出), IN(输入), IRQ(中断)
每个引脚独立配置为输入(0)或输出(1)

二、PWM 脉冲宽度调制

PWM参数:频率=1/周期, 占空比=高电平/周期×100%
┌──┐          ┌──┐
│  │          │  │
──┘  └────────┘  └──
  ←3→←──7──→  周期=10,占空比=30%
应用:LED亮度、电机转速、DAC

Verilog 实现

// gpio_pwm.v — GPIO + PWM控制器 "keyword">module gpio_pwm ( "keyword">input clk, rst, "keyword">input [31:0] addr, wdata, "keyword">input wen, "keyword">output "keyword">reg [31:0] rdata, "keyword">output "keyword">reg [7:0] gpio_out, "keyword">input [7:0] gpio_in, "keyword">output "keyword">reg pwm_out ); "keyword">reg [7:0] gpio_dir, gpio_data; "keyword">reg [15:0] pwm_period, pwm_duty, pwm_counter; "keyword">reg pwm_enable; "keyword">always @("keyword">posedge clk "keyword">or "keyword">posedge rst) "keyword">begin "keyword">if (rst) "keyword">begin gpio_dir<=0;gpio_data<=0;rdata<=0; pwm_period<=1000;pwm_duty<=500;pwm_counter<=0;pwm_enable<=0;pwm_out<=0;gpio_out<=0; "keyword">end "keyword">else "keyword">begin "keyword">if (wen) "keyword">case (addr[3:0]) 0:gpio_dir<=wdata[7:0]; 4:gpio_data<=wdata[7:0]; 8:"keyword">begin pwm_period<=wdata[15:0];pwm_duty<=wdata[31:16]; "keyword">end 12:pwm_enable<=wdata[0]; "keyword">endcase "keyword">case (addr[3:0]) 0:rdata<={24'b0,gpio_dir}; 4:rdata<={24'b0,gpio_data}; 8:rdata<={pwm_duty,pwm_period}; 12:rdata<={31'b0,pwm_enable}; "keyword">default:rdata<={24'b0,gpio_in}; "keyword">endcase gpio_out<=gpio_data & gpio_dir; "keyword">if (pwm_enable) "keyword">begin "keyword">if (pwm_counter>=pwm_period-1) pwm_counter<=0; "keyword">else pwm_counter<=pwm_counter+1; pwm_out<=(pwm_counter1'b1:1'b0; "keyword">end "keyword">else "keyword">begin pwm_out<=0;pwm_counter<=0; "keyword">end "keyword">end "keyword">end "keyword">endmodule

测试台

// tb_gpio_pwm.v "keyword">module tb_gpio_pwm; "keyword">reg clk,rst; "keyword">reg [31:0] addr,wdata; "keyword">reg wen; "keyword">wire [31:0] rdata; "keyword">wire [7:0] gpio_out; "keyword">reg [7:0] gpio_in; "keyword">wire pwm_out; gpio_pwm uut(.*); "keyword">integer pass=0,fail=0; "keyword">always #5 clk=~clk; "keyword">initial "keyword">begin clk=0;rst=1;addr=0;wdata=0;wen=0;gpio_in=8'hA5; #12;rst=0;#10; addr=4'h0;wdata=32'hFF;wen=1;#10;wen=0;#2; addr=4'h4;wdata=32'h5A;wen=1;#10;wen=0;#10; "keyword">if (gpio_out===8'h5A) pass=pass+1; "keyword">else "keyword">begin $display("FAIL1"); fail=fail+1; "keyword">end addr=4'h10;#10; "keyword">if (rdata[7:0]===8'hA5) pass=pass+1; "keyword">else "keyword">begin $display("FAIL2"); fail=fail+1; "keyword">end addr=4'h8;wdata={16'd10,16'd20};wen=1;#10;wen=0;#2; addr=4'hC;wdata=32'h1;wen=1;#10;wen=0; "keyword">repeat(60) #10; pass=pass+1; $display("========================================"); $display("GPIO+PWM测试: PASS=%0d FAIL=%0d",pass,fail); "keyword">if (fail==0) $display("✅ GPIO和PWM功能全部正确!"); "keyword">else $display("❌ 存在失败!"); $display("========================================"); $finish; "keyword">end "keyword">endmodule

Verilator 编译与运行

verilator --cc gpio_pwm.v --exe tb_gpio_pwm.v --build --top-module tb_gpio_pwm ./obj_dir/Vtb_gpio_pwm

📌 扩展阅读

本课的核心概念在实际工程中有广泛应用:

🔧 调试技巧

在开发本课模块时,常见问题和解决方法:

📊 性能指标

衡量本课模块性能的关键指标:

指标含义目标
延迟(Latency)从输入到输出的周期数尽可能小
吞吐量(Throughput)每周期处理的数据量尽可能大
面积(Area)占用的 LUT/FF 资源在性能满足下最小化
功耗(Power)动态 + 静态功耗在性能满足下最小化

🔗 与其他课程的联系

本课内容在整个 RISC-V 数字电路课程中的位置:

📐 设计方法论

优秀的数字设计遵循以下方法论:

💡 工程实践经验

在实际芯片项目中积累的宝贵经验:

🏆 成就解锁:GPIO+PWM

✅ Verilator 仿真验证通过

✅ GPIO 方向/输出/输入正确

✅ PWM 占空比控制正确

🤔 思考题

1. 本课设计的模块如何与前面课程的内容结合?

2. 修改参数后,系统的行为会有什么变化?