树莓派瑞士军刀扩展版saks库0.1.1版发布!

吴翱翔 40cm2021-07-111018 次点击
最新saks库API文档链接: https://docs.rs/saks/0.1.1/saks/struct.Saks.html

0.1.1 版的改动如下:
1. 修复crates.io包管理平台CI/CD跑挂的问题
2. 去掉所有第三方库的依赖(libc是rustc私有API,不算第三方库),仅用标准库+系统调用mmap函数实现
3. 新增74HC595的支持和部分I2C的支持

我把 BCM2711 芯片文档的 datasheet 的60-70页的GPIO部分看了好几遍终于算对了内存地址偏移,以下是mmap部分的核心代码

```
let fd = unsafe {‌‌‌‌‌ libc::open("/dev/gpiomem\0".as_ptr().cast(), libc::O_RDWR) };
if fd == -1 {‌‌‌‌‌
panic!("{‌‌‌‌‌}", std::io::Error::last_os_error());
}
let mapped_addr = unsafe {‌‌‌‌‌
libc::mmap(
std::ptr::null_mut(),
GPIO_MMAP_LEN,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
fd,
0, // /dev/gpiomem doesn't need offset
)
};
```

除了mmap,另一个巨大的困难就是找到合适的寄存器内存地址,位运算修改寄存器,让某一个GPIO引脚的工作模式改变:

```rust
fn set_mode(&self, pin: SaksPins, pin_mode: PinMode) {‌‌‌‌‌
let bcm_pin_num = u32::from(pin);
// bcm2711-peripherals.pdf page 66, each GPFSEL${‌‌‌‌‌N} register every 3 bit manage a GPIO's pin_mode
// eg. Buzzer=12 need register GPFSEL1 to set pin_mode, offset to mmap is 1
let gpfsel_index = bcm_pin_num / 10;
// eg. GPFSEL1 bit [6..=8] is the bit_mask to set Buzzer=12 pin_mode
let pin_mode_shift = (bcm_pin_num % 10) * 3;

let reg_ptr = unsafe {‌‌‌‌‌
self.mapped_addr
.add(GPFSEL0 + gpfsel_index as usize)
};

let mut reg_val = unsafe {‌‌‌‌‌ *reg_ptr };
// eg. bit_mask to set GPFSEL1's [6..=8] bit to zero
let bit_mask_to_clear_bcm_pin_num_pin_mode = !(0b111 << pin_mode_shift);
reg_val &= bit_mask_to_clear_bcm_pin_num_pin_mode;
// eg. set GPFSEL1's [6..=8] bit to pin_mode arg
reg_val |= (u32::from(pin_mode)) << pin_mode_shift;

unsafe {‌‌‌‌‌
*reg_ptr = reg_val;
}
}
```

## 有个小问题想请教版主: 析构函数中蜂鸣器该如何析构?

```
self.clear_all();
self.set_level(SaksPins::Buzzer, VoltageLevel::High);
```

我析构函数中 clear_all 会把全部引脚设置成低电平,所以程序退出后蜂鸣器一直在响

我被迫在析构函数的clear_all后面加上一行让蜂鸣器的输出变成高电平,好像只能这样「析构」蜂鸣器了
收藏 ♥ 感谢
Spoony 小组长 2021-07-12 
「在析构函数的clear_all后面加上一行让蜂鸣器的输出变成高电平」

你用的这个方法是对的。多谢分享这份 SDK 和文档。
相逢已是初识 156.95m 2021-07-13 
哇呜

登录注册 后可回复。




› 相关内容关注微信公众号