Skip to content

Commit 7e7bd39

Browse files
author
Nathan Seidle
committed
Interim commit. Mostly working but need to refine how the PDM datra is stored.
1 parent 35f630a commit 7e7bd39

File tree

3 files changed

+323
-0
lines changed

3 files changed

+323
-0
lines changed

cores/arduino/ard_sup/Arduino.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ extern "C"
7878
#include "ap3_analog.h"
7979
#include "ap3_clock_sources.h"
8080
#include "ap3_shift.h"
81+
#include "ap3_pdm.h"
8182
#include "WMath.h"
8283
#include "WCharacter.h"
8384

cores/arduino/ard_sup/ap3_pdm.h

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
Copyright (c) 2019 SparkFun Electronics
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in all
12+
copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
SOFTWARE.
21+
*/
22+
#ifndef _AP3_PDM_H_
23+
#define _AP3_PDM_H_
24+
25+
#include "Arduino.h"
26+
27+
#define AP3_GPIO_DEFAULT_PINCFG AP3_GPIO_PINCFG_NULL
28+
29+
//#define AP3_NUM_PDM 1
30+
#define AP3_PDM_NUM_DATA_PADS 6
31+
#define AP3_PDM_NUM_CLOCK_PADS 6
32+
33+
typedef struct _ap3_pdm_pad_map_elem_t
34+
{
35+
ap3_gpio_pad_t pad;
36+
uint8_t funcsel;
37+
} ap3_pdm_pad_map_elem_t;
38+
39+
typedef enum
40+
{
41+
AP3_PDM_DATA = 0x00,
42+
AP3_PDM_CLOCK,
43+
} ap3_pdm_pad_type_e;
44+
45+
const ap3_pdm_pad_map_elem_t ap3_pdm_data_map[AP3_PDM_NUM_DATA_PADS] = {
46+
{.pad = 11, .funcsel = AM_HAL_PIN_11_PDMDATA},
47+
{.pad = 15, .funcsel = AM_HAL_PIN_15_PDMDATA},
48+
{.pad = 29, .funcsel = AM_HAL_PIN_29_PDMDATA},
49+
{.pad = 34, .funcsel = AM_HAL_PIN_34_PDMDATA},
50+
{.pad = 36, .funcsel = AM_HAL_PIN_36_PDMDATA},
51+
{.pad = 45, .funcsel = AM_HAL_PIN_45_PDMDATA},
52+
};
53+
54+
const ap3_pdm_pad_map_elem_t ap3_pdm_clock_map[AP3_PDM_NUM_CLOCK_PADS] = {
55+
{.pad = 10, .funcsel = AM_HAL_PIN_10_PDMCLK},
56+
{.pad = 12, .funcsel = AM_HAL_PIN_12_PDMCLK},
57+
{.pad = 14, .funcsel = AM_HAL_PIN_14_PDMCLK},
58+
{.pad = 22, .funcsel = AM_HAL_PIN_22_PDMCLK},
59+
{.pad = 37, .funcsel = AM_HAL_PIN_37_PDMCLK},
60+
{.pad = 46, .funcsel = AM_HAL_PIN_46_PDMCLK},
61+
};
62+
63+
ap3_err_t ap3_pdm_pad_funcsel(ap3_pdm_pad_type_e type, ap3_gpio_pad_t pad, uint8_t *funcsel);
64+
65+
const am_hal_pdm_config_t ap3_pdm_config_default = {
66+
//Basic PDM setup pulled from SDK PDM example
67+
.eClkDivider = AM_HAL_PDM_MCLKDIV_1,
68+
.eLeftGain = AM_HAL_PDM_GAIN_0DB,
69+
.eRightGain = AM_HAL_PDM_GAIN_0DB,
70+
.ui32DecimationRate = 64,
71+
.bHighPassEnable = 0,
72+
.ui32HighPassCutoff = 0xB,
73+
.ePDMClkSpeed = AM_HAL_PDM_CLK_6MHZ,
74+
.bInvertI2SBCLK = 0,
75+
.ePDMClkSource = AM_HAL_PDM_INTERNAL_CLK,
76+
.bPDMSampleDelay = 0,
77+
.bDataPacking = 1,
78+
.ePCMChannels = AM_HAL_PDM_CHANNEL_RIGHT,
79+
.ui32GainChangeDelay = 1,
80+
.bI2SEnable = 0,
81+
.bSoftMute = 0,
82+
.bLRSwap = 0,
83+
};
84+
85+
class AP3_PDM
86+
{
87+
public:
88+
// Uart(uint8_t instance, ap3_gpio_pin_t pinRX, ap3_gpio_pin_t pinTX, ap3_gpio_pin_t pinRTS = AP3_UART_PIN_UNUSED, ap3_gpio_pin_t pinCTS = AP3_UART_PIN_UNUSED);
89+
bool begin(ap3_gpio_pin_t pinPDMData, ap3_gpio_pin_t pinPDMClock);
90+
bool available(void); //Goes true once an interrupt has occured
91+
92+
//void begin(void);
93+
// void begin(unsigned long baudrate, uint16_t config);
94+
// void begin(unsigned long baudrate, am_hal_uart_config_t config);
95+
// void end();
96+
// int available();
97+
// int availableForWrite();
98+
// int peek();
99+
// int read();
100+
// void flush();
101+
// size_t write(const uint8_t data);
102+
// size_t write(const uint8_t *buffer, size_t size);
103+
// uint32_t printf(const char *pcFmt, ...);
104+
// using Print::write; // pull in write(str) and write(buf, size) from Print
105+
106+
void pdm_isr(void);
107+
108+
// operator bool() { return true; } // todo: wait for a serial terminal to be open... probably depends on RTS or CTS...
109+
110+
private:
111+
public: //temporary
112+
//AP3UartRingBuffer _rx_buffer; // These buffers guarantee the lifespan of the data to transmit
113+
//AP3UartRingBuffer _tx_buffer; // to allow for asynchronous tranfsers
114+
115+
//uint8_t _instance;
116+
void *_PDMhandle;
117+
am_hal_pdm_config_t _PDMconfig;
118+
ap3_gpio_pin_t _pinPDMData;
119+
ap3_gpio_pin_t _pinPDMClock;
120+
121+
//ap3_err_t set_config(HardwareSerial_Config_e HWSconfig);
122+
ap3_err_t _begin(void); // call once all members + config structure are set up
123+
124+
volatile bool _PDMdataReady = false;
125+
};
126+
127+
#endif //_AP3_PDM_H_

cores/arduino/ard_sup/pdm/ap3_pdm.cpp

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
/*
2+
Copyright (c) 2019 SparkFun Electronics
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in all
12+
copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
SOFTWARE.
21+
*/
22+
#include "ap3_pdm.h"
23+
24+
AP3_PDM *ap3_pdm_handle = 0;
25+
26+
bool AP3_PDM::begin(ap3_gpio_pin_t pinPDMData, ap3_gpio_pin_t pinPDMClock)
27+
{
28+
_PDMhandle = NULL;
29+
_PDMconfig = ap3_pdm_config_default;
30+
_pinPDMData = pinPDMData;
31+
_pinPDMClock = pinPDMClock;
32+
33+
//begin(baudrate, (uint16_t)SERIAL_8N1);
34+
if (_begin() != AP3_OK)
35+
{
36+
return (false);
37+
}
38+
return (true);
39+
}
40+
41+
bool AP3_PDM::available(void)
42+
{
43+
return (_PDMdataReady);
44+
}
45+
46+
ap3_err_t AP3_PDM::_begin(void)
47+
{
48+
ap3_err_t retval = AP3_OK;
49+
am_hal_gpio_pincfg_t pincfg = AP3_GPIO_DEFAULT_PINCFG;
50+
uint8_t funcsel = 0;
51+
52+
//Configure PDM pins
53+
retval = ap3_pdm_pad_funcsel(AP3_PDM_DATA, ap3_gpio_pin2pad(_pinPDMData), &funcsel);
54+
if (retval != AP3_OK)
55+
{
56+
return retval;
57+
}
58+
pincfg.uFuncSel = funcsel; // set the proper function select option for this instance/pin/type combination
59+
pinMode(_pinPDMData, pincfg, &retval);
60+
if (retval != AP3_OK)
61+
{
62+
return ap3_return(retval);
63+
}
64+
65+
retval = ap3_pdm_pad_funcsel(AP3_PDM_CLOCK, ap3_gpio_pin2pad(_pinPDMClock), &funcsel);
66+
if (retval != AP3_OK)
67+
{
68+
return retval;
69+
}
70+
pincfg.uFuncSel = funcsel; // set the proper function select option for this instance/pin/type combination
71+
pinMode(_pinPDMClock, pincfg, &retval);
72+
if (retval != AP3_OK)
73+
{
74+
return ap3_return(retval);
75+
}
76+
77+
// Initialize, power-up, and configure the PDM.
78+
79+
// //User may want to change settings mid-sketch. Only init PDM if it's new.
80+
if (_PDMhandle == NULL)
81+
{
82+
// Now that pins are initialized start the actual driver
83+
retval = (ap3_err_t)am_hal_pdm_initialize(0, &_PDMhandle);
84+
if (retval != AP3_OK)
85+
{
86+
return ap3_return(retval);
87+
}
88+
}
89+
retval = (ap3_err_t)am_hal_pdm_power_control(_PDMhandle, AM_HAL_PDM_POWER_ON, false);
90+
if (retval != AP3_OK)
91+
{
92+
return ap3_return(retval);
93+
}
94+
retval = (ap3_err_t)am_hal_pdm_configure(_PDMhandle, &_PDMconfig);
95+
if (retval != AP3_OK)
96+
{
97+
return ap3_return(retval);
98+
}
99+
retval = (ap3_err_t)am_hal_pdm_enable(_PDMhandle);
100+
if (retval != AP3_OK)
101+
{
102+
return ap3_return(retval);
103+
}
104+
105+
//
106+
// Configure and enable PDM interrupts (set up to trigger on DMA
107+
// completion).
108+
//
109+
am_hal_pdm_interrupt_enable(_PDMhandle, (AM_HAL_PDM_INT_DERR | AM_HAL_PDM_INT_DCMP | AM_HAL_PDM_INT_UNDFL | AM_HAL_PDM_INT_OVF));
110+
am_hal_interrupt_master_enable();
111+
NVIC_EnableIRQ(PDM_IRQn);
112+
113+
// Register the class into the local list
114+
ap3_pdm_handle = this;
115+
116+
return retval;
117+
}
118+
119+
ap3_err_t ap3_pdm_pad_funcsel(ap3_pdm_pad_type_e type, ap3_gpio_pad_t pad, uint8_t *funcsel)
120+
{
121+
ap3_err_t retval = AP3_ERR;
122+
123+
const ap3_pdm_pad_map_elem_t *map = NULL;
124+
uint8_t map_len = 0;
125+
126+
switch (type)
127+
{
128+
case AP3_PDM_CLOCK:
129+
map = ap3_pdm_clock_map;
130+
map_len = AP3_PDM_NUM_CLOCK_PADS;
131+
break;
132+
case AP3_PDM_DATA:
133+
map = ap3_pdm_data_map;
134+
map_len = AP3_PDM_NUM_DATA_PADS;
135+
break;
136+
default:
137+
goto invalid_args;
138+
break;
139+
}
140+
141+
if ((map == NULL) || (map_len == 0))
142+
{
143+
goto invalid_args;
144+
}
145+
146+
for (uint16_t indi = 0; indi < map_len; indi++)
147+
{
148+
if (map[indi].pad == pad)
149+
{
150+
*funcsel = map[indi].funcsel;
151+
return AP3_OK;
152+
}
153+
}
154+
return retval;
155+
156+
invalid_args:
157+
retval = AP3_INVALID_ARG;
158+
*funcsel = 0; // do not use
159+
return retval;
160+
}
161+
162+
inline void AP3_PDM::pdm_isr(void)
163+
{
164+
uint32_t ui32Status;
165+
166+
//
167+
// Read the interrupt status.
168+
//
169+
am_hal_pdm_interrupt_status_get(_PDMhandle, &ui32Status, true);
170+
am_hal_pdm_interrupt_clear(_PDMhandle, ui32Status);
171+
172+
//
173+
// Once our DMA transaction completes, we will disable the PDM and send a
174+
// flag back down to the main routine. Disabling the PDM is only necessary
175+
// because this example only implemented a single buffer for storing FFT
176+
// data. More complex programs could use a system of multiple buffers to
177+
// allow the CPU to run the FFT in one buffer while the DMA pulls PCM data
178+
// into another buffer.
179+
//
180+
if (ui32Status & AM_HAL_PDM_INT_DCMP)
181+
{
182+
am_hal_pdm_disable(_PDMhandle);
183+
_PDMdataReady = true;
184+
}
185+
}
186+
187+
//*****************************************************************************
188+
//
189+
// PDM interrupt handler.
190+
//
191+
//*****************************************************************************
192+
extern "C" void am_pdm_isr(void)
193+
{
194+
ap3_pdm_handle->pdm_isr();
195+
}

0 commit comments

Comments
 (0)