PDMmic provides a simple PDM microphone interface.
The implementation of PDM to PCM filter pipeline is based on Tom Verbeure's articles for PDM to PCM conversion.
Each filter in the pipeline is implemented with the Amaranth HDL as an amlib library.
examples/gsd_butterstick.py is a running example using LiteX on Greg Davill's ButterStick board. It consumes 12 multipliers when 24-bit width arithmetic is specified. To make this example work, you need to add a few lines for the microphone like
--- a/litex_boards/platforms/gsd_butterstick.py
+++ b/litex_boards/platforms/gsd_butterstick.py
@@ -128,7 +128,14 @@ _io_r1_0 = [
Subsignal("stp", Pins("C8")),
Subsignal("rst", Pins("C9")),
IOStandard("LVCMOS18"),Misc("SLEWRATE=FAST")
- ),
+ ),
+
+ # PDM mic
+ ("pdmmic", 0,
+ Subsignal("data", Pins("L5")),
+ Subsignal("clk", Pins("M4")),
+ IOStandard("LVCMOS33")
+ ),
]
# Connectors ---------------------------------------------------------------------------------------
to the litex platform description file platform/gsd_butterstick.py.
The following code snippet added to litex bios will send 1M samples to host udp 6000 port.
unsigned int test_pdmmic()
{
unsigned int ip;
printf("Generate packets with PCM (%dM samples)\n", mb);
printf("Local IP : %d.%d.%d.%d\n", LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4);
printf("Remote IP: %d.%d.%d.%d\n", REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
ip = IPTOINT(REMOTEIP1, REMOTEIP2, REMOTEIP3, REMOTEIP4);
udp_start(macadr, IPTOINT(LOCALIP1, LOCALIP2, LOCALIP3, LOCALIP4));
if(!udp_arp_resolve(ip)) {
printf("arp resolve fail\n");
return -1;
}
int i, j;
unsigned short rdat[512];
char *buf;
for (i = 0; i < 2*1024; i++) {
for (j = 0; j < 512; j++) {
while (*(volatile char *)CSR_PDMMIC_READY_ADDR == 0) ;
rdat[j] = *(volatile short *)CSR_PDMMIC_DATA_ADDR;
}
buf = udp_get_tx_buffer();
for (j = 0; j < 512*2; j++)
buf[j] = ((char *)rdat)[j];
udp_send(6001, 6000, 512*2);
}
return 0;
}
- [2022-01-16] External PDM clock support (experimental): PDM2PCM: Add pdm_clock_in and pdm_clock_in_en inputs which can be used as the external PDM clock signal and its enable switch.
TODO
TODO
PDMMic module is writen with Amaranth and its verilog output is needed to use it from LiteX. The command below will generate the verilog file.
pushd pdmmic/verilog
make
popd
TODO
[1] Tom Verbeure, articles
- An Intuitive Look at Moving Average and CIC Filters
- PDM Microphones and Sigma-Delta A/D Conversion
- Designing Generic FIR Filters with pyFDA and NumPy
- From Microphone Datasheet to Filter Design Specification
- Half-Band Filters, a Workhorse of Decimation Filters
- Design of a Multi-Stage PDM to PCM Decimation Pipeline