编译:陈拓 chentuo@ms.xab.ac.cn 2018.06.07/2018.07.14

原文:Adding Basic Audio Ouput to Raspberry Pi Zero
https://learn.adafruit.com/adding-basic-audio-ouput-to-raspberry-pi-zero

0.  概述

为了保持树莓派Zero W低成本和尽可能小,Pi Zero W不包括3.5mm音频插座。也没有音频输出端子。下面我们为Pi Zero W添加基本的音频输出。

1. 原理

在其他的树莓派上音频是怎样工作的呢?用于PI的Broadcom芯片组没有真正的模拟输出。作为替代,用两个PWM引脚(脉宽调制)以非常高的速度工作,并且有滤波。PWM频率至少10倍于我们想要重现的音频最高频率。然后,通过调整PWM的占空比,我们就可以“伪造”音频信号。

音频是20Hz到20kHz,从PI输出的PWM是50MHz,所以我们可以很容易地过滤高50MHz输出(无论如何都听不到)。

看其他树莓派音频输出示意图,我们可以看到PWM0OUT和PWM1OUT是左右通道。R21和R20是分压器,使3.3V信号下降到约1.1V MAX(这是音频线路电平所需的最大峰值到峰值电压)。

C20/C26与R21/R27一起工作,产生一个“RC低通滤波器”。你可以用1/(2*pi*RC) = 1/(2*pi*270*33*10-9) = 17865 Hz计算截止频率,这非常接近20kHz。

C48/C34作为直流滤波电容器,它只允许交流通过扬声器和耳机。

BAV99 是ESD保护二极管。保护树莓派防止来自PWM引脚的静电。

2. Pi Zero W音频

[https://learn.adafruit.com/adding-basic-audio-ouput-to-raspberry-pi-zero/pi-zero-pwm-audio]

2.1 BCM2835 GPIO功能

在PI Zero W的PCB板上,没有引出PIN PWM0(引脚#40)和PWM1(引脚#45)。但是可以通过GPIO#18(ALT5)访问PWM0,通过GPIO#13(ALT0)或GPIO#19(ALT5)访问PWM1,请参阅下面的引脚和备用功能的完整列表:https://elinux.org/RPi_BCM2835_GPIOs

BCM2835 GPIO功能

GPIO ALT就像单片机的引脚复用。

2.2 在PI Zero W上实现PWM

  • 用ssh登录到命令行控制台。

用putty连接电脑和Pi Zero W,看本文最后的参考文档。Host Name填,用户名pi,密码raspberry。

注意:boot分区有一个名为ssh的空文本文件,这个ssh文件容易丢失,如果ssh不能登录了,先检查ssh是否丢失。

  • 设置引脚和PWM的方法

有两种选择,简单的方法是使用DTO来设置所有引脚和PWM,但是,我们还没有测试过。另一种方法是手动设置引脚GPIO alt功能,我们已经测试过了,但难度更大!

选择1. 使用设备树覆盖(Device Tree Overlay - DTO)

有两个建议的DTO选项,第一个使用了最近加入的DTO:

1)  有一种简单的方法来配置PWM音频的PI GPIO引脚。只需将以下行添加到/boot/config.txt,即可在引导是重新配置引脚,无需任何外部软件或服务:

dtoverlay=pwm-2chan,pin=18,func=2,pin2=13,func2=4

将左通道映射到引脚33(BCM = 13),将右通道映射到引脚12(BCM = 18)。

我们先用这个方法试试:

命令: sudo nano /boot/config.txt

输入后,使用组合键“Ctrl + X”,然后输入“Y”,回车保存修改。

设置好/boot/config.txt以后,跳转到2.3 低通滤波器接线。

2)  或者,你可以制作自己的DTO,参考下面的文章

嗨,使用dtoValay,我让PWM音频工作在我的pi-zero上:

https://hackaday.io/project/9467-pigrrl-zero/log/35090-pi-zero-pwm-audio-device-tree-overlay

无论哪种方式使用DTO,下一步就是低通滤波器(看本文后面):[https://learn.adafruit.com/adding-basic-audio-ouput-to-raspberry-pi-zero/pi-zero-pwm-audio#low-pass-filter-wiring]

选择2. 手动分配PWM引脚

如果您想设置单独的引脚和用途,则可以手动设置引脚功能。

  • 恢复做选择1时修改的/boot/config.txt

pi@raspberrypi:~ $ sudo nano /boot/config.txt

  • 重新启动Pi Zero W

pi@raspberrypi:~ $ sudo shutdown -h now

等待电源指示灯熄灭后,关闭电源

重新上电,登录ssh。

  • 使用wiringpi的GPIO实用工具

在我们开始之前,先使用wiringpi的GPIO实用工具列出所有GPIO引脚和它们的当前功能/替代设置,请看: http://wiringpi.com/download-and-install/

上的文章:Wiring Pi -GPIO Interface library for the Raspberry Pi。

下载和安装Wiring Pi请看我的《树莓派ZeroW的GPIO控制》一文。

读取所有引脚的状态

pi@raspberrypi:~ $ gpio readall

这两个引脚的MODE类型为IN - 这意味着它们只是简单的输入。

  • 下载更改GPIO ALT的工具

我们可以在Pi论坛中使用TimG的一个非常方便的工具来手动调整GPIO ALT(https://www.raspberrypi.org/forums/viewtopic.php?f=44&t=39138)。下载地址:https://learn.adafruit.com/pages/6577/elements/1960154/download

以下是完整的代码:

/*

Utility to switch Raspberry-Pi GPIO pin functions

Tim Giles 01/04/2013

Usage:

$ gpio_alt -p PIN_NUMBER -f ALT_NUMBER

Based on RPi code from Dom and Gert, 15-Feb-2013, <http://elinux.org/RPi_Low-level_peripherals#C_2>

and Gnu getopt() example <http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html#Example-of-Getopt>

*/

#include <ctype.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <fcntl.h>

#include <sys/mman.h>

#define BCM2708_PERI_BASE        0x20000000

#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */

#define PAGE_SIZE (4*1024)

#define BLOCK_SIZE (4*1024)

int  mem_fd;

void *gpio_map;

volatile unsigned *gpio;

void setup_io();

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)

#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))

#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))

#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0

#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

int main (int argc, char **argv) {

int opt, flag, n_pin, n_alt;

flag=0;

while ((opt = getopt (argc, argv, "hp:f:")) != -1) {

switch (opt) {

case 'h':

break;

case 'p':

n_pin = atoi(optarg); flag |= 0b0001; break;

case 'f':

n_alt = atoi(optarg); flag |= 0b0010; break;

case '?':

// getopt() prints error messages, so don't need to repeat them here

return 1;

default:

abort ();

}

}

if (flag != 0b0011) {

fprintf (stderr, "Usage:\n$ gpio_alt -p PIN_NUM -f FUNC_NUM\n");

return 1;

}

setup_io(); // Set up gpi pointer for direct register access

INP_GPIO(n_pin);  // Always use INP_GPIO(x) before using SET_GPIO_ALT(x,y)

SET_GPIO_ALT(n_pin, n_alt);

printf("Set pin %i to alternative-function %i\n", n_pin, n_alt);

return 0;

}

void setup_io() {

/* open /dev/mem */

if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {

printf("can't open /dev/mem \n");

exit(-1);

}

/* mmap GPIO */

gpio_map = mmap(

NULL,             //Any adddress in our space will do

BLOCK_SIZE,       //Map length

PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory

MAP_SHARED,       //Shared with other processes

mem_fd,           //File to map

GPIO_BASE         //Offset to GPIO peripheral

);

close(mem_fd); //No need to keep mem_fd open after mmap

if (gpio_map == MAP_FAILED) {

printf("mmap error %d\n", (int)gpio_map);//errno also set!

exit(-1);

}

// Always use volatile pointer!

gpio = (volatile unsigned *)gpio_map;

}

在Pi ZeroW上,创建一个新文件并进行编辑(不管在什么目录):

pi@raspberrypi:~ $ nano gpio_alt.c

然后粘贴上面的整个代码。保存...

  • 编译并安装

编译

pi@raspberrypi:~ $ gcc -o gpio_alt gpio_alt.c

改变所有者

pi@raspberrypi:~ $ sudo chown root:root gpio_alt

给gpio_alt以suid权限,可以像root用户一样操作

pi@raspberrypi:~ $ sudo chmod u+s gpio_alt

将gpio_alt移动到/usr/local/bin/

pi@raspberrypi:~ $ sudo mv gpio_alt /usr/local/bin/

  • 现在你可以设置两个GPIO 的ALT功能了!

pi@raspberrypi:~ $ gpio_alt -p 13 -f 0

pi@raspberrypi:~ $ gpio_alt -p 18 -f 5

现在回到wiringPi检查我们是否做到了!

pi@raspberrypi:~ $ gpio readall

你可以看到新的ALT设置。当然,用选择1,设置/boot/config.txt的方法也可以看到这张图,殊途同归嘛。

2.3 低通滤波器接线

现在按照第1节的电路原理图,将低通滤波电路连接到GPIO#13和GPIO#18上,作为PWM1和PWM0。4个二极管可以忽略,跳过二极管。元件的参数不用太严格。

不必做的这么正规,我利用手头的元件,用用洞洞板焊了一个低通滤波器,用起来挺好。看,就是这个:

3.5mm音频插座,左右声道和地接线。

用杜邦线和Pi Zero W连接起来,插上耳机:

2.4 设置音频输出

你还需要设置Pi Zero W,这样音频才会通过“耳机插孔”(PWM输出)流出,而不是HDMI。从控制台运行:

pi@raspberrypi:~ $ sudo raspi-config

转到Advanced Options

然后是音频

强制3.5mm耳机

选择OK,回车,然后Finish退出。这个过程你只需要做一次。

2.5 测试

你现在可以播放音频了!要重新启动一下Pi Zero W,注意,不要用reboot命令重启,容易丢失ssh文件!

关机:

  • pi@raspberrypi:~ $ sudo shutdown -h now
  • 等待电源指示灯熄灭后,关闭电源

插入有源扬声器或耳机,重新上电,登录ssh。

我们将使用内置的aplay音频播放器播放内置的音频文件。运行:

pi@raspberrypi:~ $ aplay /usr/share/sounds/alsa/Front_Center.wav

你听到声音了吗,音质还不错哦。

2.6 调整音量

你可能会注意到一点点嗡嗡声,或者可能只是声音不大。要获得最佳音质,你需要调节音频电平。你可以用alsamixer或amixer调节音量,但我认为alsamixer更容易。

运行pi@raspberrypi:~ $ alsamixer

在终端上,音量是用ascii字符排列的图像界面来表现的,用4个方向箭头键调节,点击Esc保存并退出。

现在我们再回过头去试试第二种方法,虽然有点麻烦,但是对于机制的理解更好。

3. 自动化

如果你希望在启动时自动设置alt,我可以这样做。

  • 首先创建一个shell脚本pwmaudio.sh

pi@raspberrypi:~ $ sudo nano /root/pwmaudio.sh

内容:

#!/bin/bash

/usr/local/bin/gpio_alt -p 13 -f 0

/usr/local/bin/gpio_alt -p 18 -f 5

  • 修改权限

运行:

pi@raspberrypi:~ $ sudo chmod +x /root/pwmaudio.sh

  • 创建另一个脚本pwmaudio.service

sudo nano /lib/systemd/system/pwmaudio.service

内容:

[Unit]

Description=PWM Audio Service

[Service]

ExecStart=/root/pwmaudio.sh

StandardOutput=null

[Install]

WantedBy=multi-user.target

Alias=pwmaudio.service

保存文件。

  • 启用该服务enable

pi@raspberrypi:~ $ sudo systemctl enable pwmaudio.service

  • 启动该服务start

pi@raspberrypi:~ $ sudo systemctl start pwmaudio.service

  • 重新启动pi

注意:慎用sudo reboot,容易丢失文件,ssh文件很容易丢失。

pi@raspberrypi:~ $ sudo shutdown -h now

等待电源指示灯熄灭后,重新上电。

  • 测试

重新登录。运行gpio readall命令来验证是否已设置了alts

成功!

参考文档

    1. 树莓派介绍
    2. 电脑连接树莓派PiZeroW
    3. 树莓派ZeroW的GPIO控制
    4. 树莓派 Zero W+温度传感器DS18B20
    5. Adding Basic Audio Ouput to Raspberry Pi Zero
      https://learn.adafruit.com/adding-basic-audio-ouput-to-raspberry-pi-zero

树莓派Zero W添加音频输出的更多相关文章

  1. 树莓派3b配置耳机音频输出

    耳机输出 amixer cset numid=3 1 然后,播放既可,有杂音. hdmi输出 amixer cset numid=3 2

  2. Windows 10 IoT Serials 5 - 如何为树莓派应用程序添加语音识别与交互功能

    都说语音是人机交互的重要手段,虽然个人觉得在大庭广众之下,对着手机发号施令会显得有些尴尬.但是在资源受限的物联网应用场景下(无法外接鼠标键盘显示器),如果能够通过语音来控制设备,与设备进行交互,那还是 ...

  3. 树莓派Zero W GPIO控制

    作者:陈拓 chentuo@ms.xab.ac.cn 2018.06.09/2018.07.05 0.  概述 本文介绍树莓派 Zero W的GPIO控制,并用LED看效果. 0.1 树莓派GPIO编 ...

  4. windows下一根数据线玩转树莓派zero(w)

    买了个树莓派zero w,想着用一根普通micro数据线达成 供电+ssh+通过usb共享网络+远程桌面 的目标 通过用静态ip免去了用benjour的连接不稳定方法,下面开始细说 需要的硬件: 树莓 ...

  5. 树莓派 Zero W+温度传感器DS18B20

    树莓派 Zero W+温度传感器DS18B20 作者:陈拓chentuo@ms.xab.ac.cn 2018.05.28/2018.06.01 0.  概述 用树莓派 Zero W读取DS18B20温 ...

  6. 树莓派Zero W无键盘无屏幕初始化

    买了个树莓派Zero W,结果发现没mini hdmi线 淘宝了一根mini hdmi,等了5天,拿到手后发现zero还没地接键盘,这下脑袋大了 查了下资料,发现树莓的系统,可以这boot分区中加入一 ...

  7. 无显示器安装raspberry zero w树莓派 zero w

    笔者的环境 1. Macbook 电脑用于烧录树莓派系统到SD卡 2. 树莓派 zero w 把SD卡放进读卡器,插到Mac电脑上, 打开命令行工具Terminal diskutil list列出di ...

  8. 手把手教你修改pcduino系统默认的音频输出

    最近要搞个小玩意儿,要用到pcduino的音频输出,但是系统默认的是输出到hdmi的音频,我的显示器上没有喇叭,只能搞个USB声卡.但是系统默认又不是输出到USB,这里我手把手叫你怎么设置系统默认声卡 ...

  9. 解决:编辑一条彩信,附件选择添加音频,返回到编辑界面选择play,不能播放,没有声音

    [操作步骤]:编辑一条彩信,附件选择添加音频(外部音频),返回到编辑界面选择play,菜单键选择view slideshow [测试结果]:不能播放,没有声音 [预期结果]:可以播放 根据以往的经验( ...

随机推荐

  1. TS流的解析

    个字节不一定都是有效数据,有一些可能为填充数据). 工作形式: 因为在TS流里可以填入很多种东西,所以有必要有一种机制来确定怎么来标识这些数据.制定TS流标准的机构就规定了一些数据结构来定义.比如: ...

  2. sql server 2008数据库 降为 sql server 2005数据库 最终方案总结

    由于xx原因,sql server 要降级,所以有了下文.... 一 直接 通过sql server 自带工具 生成脚本即可,具体操作方法如下: 1.打开 Microsoft Sql Server M ...

  3. bzoj 4930: 棋盘

    Description 给定一个n×n的棋盘,棋盘上每个位置要么为空要么为障碍.定义棋盘上两个位置(x,y),(u,v)能互相攻击当前仅 当满足以下两个条件: 1:x=u或y=v 2:对于(x,y)与 ...

  4. jmeter监控服务器的方法

    先下载Jmeter资源监控插件,我的百度云jmeter视频里面有说. 地址如下: JMeterPlugins-Standard-1.3.1.zip  下载 https://jmeter-plugins ...

  5. Find substring with K-1 distinct characters

    参考 Find substring with K distinct characters Find substring with K distinct characters(http://www.cn ...

  6. [UE4]编程师外挂Visual Assist X

    Visual Assist X是一款非常好的Microsoft Visual Studio插件,可以支持Microsoft Visual Studio 2003,Microsoft Visual St ...

  7. uploadify是通过flash上传,服务器获取type为application/octet-stream

    uploadify是通过flash上传,服务器获取type为application/octet-stream,因此允许上传的类型要加上application/octet-stream

  8. CSS border边框属性教程(color style)

    CSS 边框即CSS border-border边框样式颜色.边框样式.边框宽度的语法结构与应用案例教程篇 一.CSS 边框基础知识 CSS 边框即CSS border是控制对象的边框边线宽度.颜色. ...

  9. C# window Service实现调用有UI的应用程序(关于win xp以后的window系统)

    我开发的系统中有一接口程序(这里就称Task,是一个C#的Console Application)经常无故的死掉,导致第二天的数据不能正常解析,所以,我写了一个window service去监视Tas ...

  10. mysql开启查询日志功能

    1.开启查询日志  https://www.cnblogs.com/kerrycode/p/7130403.html MYsql 查询日志配置    mysql> show variables ...