Skip to content

Commit d3f3b34

Browse files
author
Ladyada
committed
add digitalPinToPinName(P) (arduino/mbed has it) and the adapted PDM library
1 parent 8628008 commit d3f3b34

File tree

9 files changed

+575
-1
lines changed

9 files changed

+575
-1
lines changed

cores/nRF5/Arduino.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,15 @@ void suspendLoop(void);
114114
#endif
115115

116116
#define digitalPinToBitMask(P) ( 1UL << ( g_ADigitalPinMap[P] < 32 ? g_ADigitalPinMap[P] : (g_ADigitalPinMap[P]-32) ) )
117+
118+
#define digitalPinToPinName(P) g_ADigitalPinMap[P]
119+
117120
//#define analogInPinToBit(P) ( )
118121
#define portOutputRegister(port) ( &(port->OUT) )
119122
#define portInputRegister(port) ( (volatile uint32_t*) &(port->IN) )
120123
#define portModeRegister(port) ( &(port->DIR) )
121124
#define digitalPinHasPWM(P) ( g_ADigitalPinMap[P] > 1 )
125+
122126
/*
123127
* digitalPinToTimer(..) is AVR-specific and is not defined for nRF52
124128
* architecture. If you need to check if a pin supports PWM you must
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
This example reads audio data from the on-board PDM microphones, and prints
3+
out the samples to the Serial console. The Serial Plotter built into the
4+
Arduino IDE can be used to plot the audio data (Tools -> Serial Plotter)
5+
6+
Please try with the Circuit Playground Bluefruit
7+
8+
This example code is in the public domain.
9+
*/
10+
11+
#include <PDM.h>
12+
13+
// The default Circuit Playground Bluefruit pins
14+
// data pin, clock pin, power pin (-1 if not used)
15+
PDMClass PDM(33, 34, -1);
16+
17+
// buffer to read samples into, each sample is 16-bits
18+
short sampleBuffer[256];
19+
20+
// number of samples read
21+
volatile int samplesRead;
22+
23+
void setup() {
24+
Serial.begin(9600);
25+
while (!Serial);
26+
27+
// configure the data receive callback
28+
PDM.onReceive(onPDMdata);
29+
30+
// optionally set the gain, defaults to 20
31+
// PDM.setGain(30);
32+
33+
// initialize PDM with:
34+
// - one channel (mono mode)
35+
// - a 16 kHz sample rate
36+
if (!PDM.begin(1, 16000)) {
37+
Serial.println("Failed to start PDM!");
38+
while (1);
39+
}
40+
}
41+
42+
void loop() {
43+
// wait for samples to be read
44+
if (samplesRead) {
45+
46+
// print samples to the serial monitor or plotter
47+
for (int i = 0; i < samplesRead; i++) {
48+
Serial.println(sampleBuffer[i]);
49+
}
50+
51+
// clear the read count
52+
samplesRead = 0;
53+
}
54+
}
55+
56+
void onPDMdata() {
57+
// query the number of bytes available
58+
int bytesAvailable = PDM.available();
59+
60+
// read into the sample buffer
61+
PDM.read(sampleBuffer, bytesAvailable);
62+
63+
// 16-bit, 2 bytes per sample
64+
samplesRead = bytesAvailable / 2;
65+
}

libraries/PDM/keywords.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#######################################
2+
# Syntax Coloring Map PDM
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
PDM KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
begin KEYWORD2
15+
end KEYWORD2
16+
17+
available KEYWORD2
18+
read KEYWORD2
19+
20+
onReceive KEYWORD2
21+
22+
setGain KEYWORD2
23+
setBufferSize KEYWORD2
24+
25+
#######################################
26+
# Constants (LITERAL1)
27+
#######################################

libraries/PDM/library.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=nRF52840 PDM - Adafruit Fork
2+
version=1.0
3+
author=Arduino
4+
maintainer=Adafruit <support@adafruit.com>
5+
sentence=Enables the communication with devices that use the PDM Bus. Specific implementation for nRF52.
6+
paragraph=
7+
category=Communication
8+
url=
9+
architectures=*

libraries/PDM/src/PDM.cpp

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/*
2+
PDM.cpp - library to interface with nRF52840 PDM peripheral
3+
Part of Arduino - http://www.arduino.cc/
4+
5+
Copyright (c) 2019 Arduino SA
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General
18+
Public License along with this library; if not, write to the
19+
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20+
Boston, MA 02111-1307 USA
21+
*/
22+
23+
#include "PDM.h"
24+
#include <hal/nrf_pdm.h>
25+
26+
#define DEFAULT_PDM_GAIN 20
27+
#define PDM_IRQ_PRIORITY 7
28+
29+
#define NRF_PDM_FREQ_1280K (nrf_pdm_freq_t)(0x0A000000UL) ///< PDM_CLK= 1.280 MHz (32 MHz / 25) => Fs= 20000 Hz
30+
#define NRF_PDM_FREQ_2000K (nrf_pdm_freq_t)(0x10000000UL) ///< PDM_CLK= 2.000 MHz (32 MHz / 16) => Fs= 31250 Hz
31+
#define NRF_PDM_FREQ_2667K (nrf_pdm_freq_t)(0x15000000UL) ///< PDM_CLK= 2.667 MHz (32 MHz / 12) => Fs= 41667 Hz
32+
#define NRF_PDM_FREQ_3200K (nrf_pdm_freq_t)(0x19000000UL) ///< PDM_CLK= 3.200 MHz (32 MHz / 10) => Fs= 50000 Hz
33+
#define NRF_PDM_FREQ_4000K (nrf_pdm_freq_t)(0x20000000UL) ///< PDM_CLK= 4.000 MHz (32 MHz / 8) => Fs= 62500 Hz
34+
35+
PDMClass::PDMClass(int dinPin, int clkPin, int pwrPin) :
36+
_dinPin(dinPin),
37+
_clkPin(clkPin),
38+
_pwrPin(pwrPin),
39+
_onReceive(NULL)
40+
{
41+
}
42+
43+
PDMClass::~PDMClass()
44+
{
45+
}
46+
47+
int PDMClass::begin(int channels, long sampleRate)
48+
{
49+
_channels = channels;
50+
51+
/*
52+
// configure the sample rate and channels
53+
switch (sampleRate) {
54+
case 16000:
55+
nrf_pdm_clock_set(NRF_PDM_FREQ_1032K);
56+
break;
57+
case 41667:
58+
nrf_pdm_clock_set(NRF_PDM_FREQ_2667K);
59+
break;
60+
default:
61+
return 0; // unsupported
62+
}
63+
*/
64+
65+
switch (channels) {
66+
case 2:
67+
nrf_pdm_mode_set(NRF_PDM_MODE_STEREO, NRF_PDM_EDGE_LEFTFALLING);
68+
break;
69+
70+
case 1:
71+
nrf_pdm_mode_set(NRF_PDM_MODE_MONO, NRF_PDM_EDGE_LEFTFALLING);
72+
break;
73+
74+
default:
75+
return 0; // unsupported
76+
}
77+
setGain(DEFAULT_PDM_GAIN);
78+
79+
// configure the I/O and mux
80+
pinMode(_clkPin, OUTPUT);
81+
digitalWrite(_clkPin, LOW);
82+
83+
pinMode(_dinPin, INPUT);
84+
85+
Serial.printf("Clock P %d Data P %d\n", digitalPinToPinName(_clkPin), digitalPinToPinName(_dinPin));
86+
87+
nrf_pdm_psel_connect(digitalPinToPinName(_clkPin), digitalPinToPinName(_dinPin));
88+
89+
// clear events and enable PDM interrupts
90+
nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED);
91+
nrf_pdm_event_clear(NRF_PDM_EVENT_END);
92+
nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED);
93+
nrf_pdm_int_enable(NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED);
94+
95+
if (_pwrPin > -1) {
96+
// power the mic on
97+
pinMode(_pwrPin, OUTPUT);
98+
digitalWrite(_pwrPin, HIGH);
99+
}
100+
101+
102+
// clear the buffer
103+
_doubleBuffer.reset();
104+
// set the PDM IRQ priority and enable
105+
NVIC_SetPriority(PDM_IRQn, PDM_IRQ_PRIORITY);
106+
NVIC_ClearPendingIRQ(PDM_IRQn);
107+
NVIC_EnableIRQ(PDM_IRQn);
108+
109+
110+
// set the buffer for transfer
111+
// nrf_pdm_buffer_set((uint32_t*)_doubleBuffer.data(), _doubleBuffer.availableForWrite() / (sizeof(int16_t) * _channels));
112+
// _doubleBuffer.swap();
113+
114+
// enable and trigger start task
115+
nrf_pdm_enable();
116+
nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED);
117+
nrf_pdm_task_trigger(NRF_PDM_TASK_START);
118+
119+
120+
return 1;
121+
}
122+
123+
void PDMClass::end()
124+
{
125+
// disable PDM and IRQ
126+
nrf_pdm_disable();
127+
128+
NVIC_DisableIRQ(PDM_IRQn);
129+
130+
if (_pwrPin > -1) {
131+
// power the mic off
132+
digitalWrite(_pwrPin, LOW);
133+
pinMode(_pwrPin, INPUT);
134+
}
135+
136+
// unconfigure the I/O and un-mux
137+
nrf_pdm_psel_disconnect();
138+
139+
pinMode(_clkPin, INPUT);
140+
}
141+
142+
int PDMClass::available()
143+
{
144+
NVIC_DisableIRQ(PDM_IRQn);
145+
146+
size_t avail = _doubleBuffer.available();
147+
148+
//NVIC_EnableIRQ(PDM_IRQn);
149+
150+
return avail;
151+
}
152+
153+
int PDMClass::read(void* buffer, size_t size)
154+
{
155+
NVIC_DisableIRQ(PDM_IRQn);
156+
157+
int read = _doubleBuffer.read(buffer, size);
158+
159+
//NVIC_EnableIRQ(PDM_IRQn);
160+
161+
return read;
162+
}
163+
164+
void PDMClass::onReceive(void(*function)(void))
165+
{
166+
_onReceive = function;
167+
}
168+
169+
void PDMClass::setGain(int gain)
170+
{
171+
nrf_pdm_gain_set(gain, gain);
172+
}
173+
174+
void PDMClass::setBufferSize(int bufferSize)
175+
{
176+
_doubleBuffer.setSize(bufferSize);
177+
}
178+
179+
void PDMClass::IrqHandler()
180+
{
181+
if (nrf_pdm_event_check(NRF_PDM_EVENT_STARTED)) {
182+
nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED);
183+
184+
if (_doubleBuffer.available() == 0) {
185+
// switch to the next buffer
186+
nrf_pdm_buffer_set((uint32_t*)_doubleBuffer.data(), _doubleBuffer.availableForWrite() / (sizeof(int16_t) * _channels));
187+
188+
// make the current one available for reading
189+
_doubleBuffer.swap(_doubleBuffer.availableForWrite());
190+
191+
// call receive callback if provided
192+
if (_onReceive) {
193+
_onReceive();
194+
}
195+
} else {
196+
// buffer overflow, stop
197+
nrf_pdm_disable();
198+
}
199+
} else if (nrf_pdm_event_check(NRF_PDM_EVENT_STOPPED)) {
200+
nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED);
201+
} else if (nrf_pdm_event_check(NRF_PDM_EVENT_END)) {
202+
nrf_pdm_event_clear(NRF_PDM_EVENT_END);
203+
}
204+
}
205+
206+
extern "C" {
207+
void PDM_IRQHandler(void);
208+
}
209+
210+
void PDM_IRQHandler(void)
211+
{
212+
PDM.IrqHandler();
213+
}
214+
215+
extern PDMClass PDM;

0 commit comments

Comments
 (0)