Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Replaced subtracting average sample value with a simple single pole IIR high pass filter rolling off at 20Hz. Added mechanism for dumping scaled 8-bit PCM samples to the UART for analysis on the PC. Tested with recording of room audio. |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
5218c33e381dc904512840778a2f57fb |
User & Date: | rberteig 2015-03-10 22:54:18 |
Context
2015-03-17
| ||
00:48 | Added a mu-Law codec to the record over UART feature to provide for 14-bit effective dynamic range in the captured recordings, which matches the dynamic range actually produced by the PDM to PCM conversion as implemented. check-in: 1d38441bbc user: rberteig tags: trunk | |
2015-03-10
| ||
22:54 | Replaced subtracting average sample value with a simple single pole IIR high pass filter rolling off at 20Hz. Added mechanism for dumping scaled 8-bit PCM samples to the UART for analysis on the PC. Tested with recording of room audio. check-in: 5218c33e38 user: rberteig tags: trunk | |
2015-03-06
| ||
00:24 | Merged latest demo board documentation improvements. check-in: 8de46c10f4 user: rberteig tags: trunk | |
Changes
Changes to LPCWorkspace/PDMSPL/src/main.c.
︙ | ︙ | |||
30 31 32 33 34 35 36 | /* Systick timer tick rate, to change duty cycle */ #define TICKRATE_HZ 1000 /* 1 ms Tick rate */ /* * SPL parameters */ | > > > > > > > > > > > | | > > > > > > > > > > > > > > | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | /* Systick timer tick rate, to change duty cycle */ #define TICKRATE_HZ 1000 /* 1 ms Tick rate */ /* * SPL parameters */ /* SPL Window Size * * Given PCM Fs=7812.5 Hz * Window SPL Fs 8*log2(Window) * 781 10.0032 Hz 76.88 * 789 9.9018 Hz 76.9987 * 938 8.3289 Hz 78. * 976 8.0046 Hz * 1327 5.8873 Hz 82.99989 */ #define WINDOWSIZE 789 // 9.9 Hz given Fs=7812.5 Hz #define LG2WINDOWSIZE 77 // nominally == 8*log2(WINDOWSIZE) /* * Ceiling(8*log2(PCM_MAGNITUDE)) is the largest possible scaled SPL value. * Note the dependence on the CIC filter structure's bit growth. As presently * configured, the CIC filter produces PCM ranging from -8192 to +8192. * * Scaling the PWM to clip at this value makes 100% PWM modulation from a near * physically impossible 100% FS square wave input. */ #define MAXLG2SPL 104 /* * SPL monitor interval, and SPL peak interval, in SPL samples */ #define WINDOWSPERPRINT 20 // TODO: insert other definitions and declarations here extern void initUART(void); #if 0 caddr_t _sbrk_r ( int incr ) { |
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 | * @return Nothing */ void SysTick_Handler(void) { ++ticks; } int main(void) { uint8_t pcount = WINDOWSPERPRINT; uint32_t n = 0; uint32_t sabs = 0; | > > > > > > > > > > | | | > > > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | * @return Nothing */ void SysTick_Handler(void) { ++ticks; } #define PRINT_NOTHING 0 #define PRINT_MONITOR_SPL 1 #define PRINT_SCARED 2 #define PRINT_SAMPLES 4 /** * @brief Main Loop * @return Does not return. */ int main(void) { uint8_t pcount = WINDOWSPERPRINT; uint32_t n = 0; uint32_t sabs = 0; //float ssq = 0.; int32_t sum = 0; int avg = 0; int peak = 0; int last = 0; volatile int monitor = PRINT_MONITOR_SPL; static uint8_t sbuf[64]; #if defined (__USE_LPCOPEN) #if !defined(NO_BOARD_LIB) // Read clock settings and update SystemCoreClock variable SystemCoreClockUpdate(); // Set up and initialize all required blocks and // functions related to the board hardware |
︙ | ︙ | |||
143 144 145 146 147 148 149 | pwmInit(); pwmSet_LED(50,100); pwmSet_OUT(50,100); pdmspi_init(); while(1) { | | > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > | > | < | | | > > > > > > > > > > > > > > > > > > > < < < < | | | > | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | pwmInit(); pwmSet_LED(50,100); pwmSet_OUT(50,100); pdmspi_init(); while(1) { static int16_t pcm; static int pcm0, pcm1; // block for a PCM sample pdmspi_wait_sample(&pcm); // High pass filter to remove DC, roll-off at alpha=63/64 and 7812.5 Hz // implies RC=16.256 ms, or Fc=9.79 Hz // alpha at 7812.5 Hz Fcut // 255/256 32.64 ms 4.876 Hz // 127/128 16.256 ms 9.79 Hz // 63/64 8.064 ms 19.74 Hz // 31/32 3.968 ms 40.1 Hz pcm1 = 63 * (pcm1 + pcm - pcm0) / 64; pcm0 = pcm; pcm = pcm1; // accumulate PCM and |PCM| to compute DC offset and SPL sum += pcm; //ssq += (pcm-avg)*(pcm-avg); sabs += pcm > 0 ? pcm : -pcm; // Finish SPL and apply it at each complete SPL window interval ++n; if (monitor & PRINT_SAMPLES) { extern void putLineUARTn(const uint8_t *, size_t); int s = (pcm + 8192) >> 6; //s = n & 0xff; sbuf[n & 63] = s <= 0 ? 0 : s >=255 ? 255 : s; if ((n&31) == 31) putLineUARTn(sbuf + (n & 32), 32); } if (n == WINDOWSIZE) { int spl; // Compute the SPL over the window that just finished. spl = (lg2(sabs) - LG2WINDOWSIZE); // set the PWM pwmSet_LED(MAXLG2SPL-spl,MAXLG2SPL); pwmSet_OUT(spl,MAXLG2SPL); // track peak level if (peak < spl) { peak = spl; } // jump on large change if ((monitor & PRINT_SCARED) && last && last < spl && spl - last >= 8) printf("Eek! %d, %d, %d\r\n", spl, last, peak); last = spl; // compute mean sample for DC offset removal avg = sum / WINDOWSIZE; // monitor SPL occasionally, reset peak level if (!--pcount) { pcount = WINDOWSPERPRINT; if (monitor & PRINT_MONITOR_SPL) printf("%d %d %d\r\n", peak, spl, avg); peak = 0; } // reset accumulators and counters for the next iteration sum = 0; sabs = 0; n = 0; } } // Not reached return 0 ; } |
Changes to LPCWorkspace/PDMSPL/src/pdmspi.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | * 4 206 192 488.28125 * 5 208 194 244.140625 * 6 208 194 122.0703125 * 7 208 194 61.03515625 * 8 210 194 30.517578125 * 9 210 196 15.2587890625 */ | | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | * 4 206 192 488.28125 * 5 208 194 244.140625 * 6 208 194 122.0703125 * 7 208 194 61.03515625 * 8 210 194 30.517578125 * 9 210 196 15.2587890625 */ 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, // 100%FS // 0x5555, 0xf5f5, 0xffff, 0x5f5f, 0x5555, 0x5050, 0x0000, 0x0505, // Aztec }; uint8_t TESTSHIFT=3; #define TESTMASK (((sizeof testsamples) / (sizeof testsamples[0]))-1) #endif /* CIC filter state */ #define CIC2_R 16 |
︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 | do { if (status & SPI_STAT_RXRDY) { uint16_t pdm = LPC_SPI0->RXDAT; #ifdef PDMTEST pdm = testsamples[((++testcount)>>TESTSHIFT) & TESTMASK]; #endif // First stage of PDM to PCM is to count the set bits in each of the // captured bytes, with each bit rescaled to a signed +/- 1 range. // This is the equivalent of an order-1 CIC filter with R=8, M=1, N=1. // // The bit growth of the output of this filter is then N*log2(R*M) // or 3, for 4 total significant bits out from the single bit in. | > > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | do { if (status & SPI_STAT_RXRDY) { uint16_t pdm = LPC_SPI0->RXDAT; #ifdef PDMTEST pdm = testsamples[((++testcount)>>TESTSHIFT) & TESTMASK]; #endif SONARSET; // First stage of PDM to PCM is to count the set bits in each of the // captured bytes, with each bit rescaled to a signed +/- 1 range. // This is the equivalent of an order-1 CIC filter with R=8, M=1, N=1. // // The bit growth of the output of this filter is then N*log2(R*M) // or 3, for 4 total significant bits out from the single bit in. |
︙ | ︙ | |||
154 155 156 157 158 159 160 | s2_comb1_2 = s2_comb1_1; s2_comb1_1 = Rout2; stage2 = stage1 - s2_comb2_2; s2_comb2_2 = s2_comb2_1; s2_comb2_1 = stage1; | < < > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | s2_comb1_2 = s2_comb1_1; s2_comb1_1 = Rout2; stage2 = stage1 - s2_comb2_2; s2_comb2_2 = s2_comb2_1; s2_comb2_1 = stage1; // queue the finished PCM sample RingBuffer_Insert(&pcmring, &stage2); } SONARCLR; } if (status & SPI_STAT_TXRDY) { /* keep the mic clock active by always transmitting another 16 bits when possible. */ LPC_SPI0->TXDATCTL = SPI_TXDATCTL_FLEN(15) | SPI_TXDATCTL_DATA(0); } if (status & (SPI_STAT_SSA|SPI_STAT_SSD)) { Chip_SPI_ClearStatus(LPC_SPI0, SPI_STAT_SSA|SPI_STAT_SSD); |
︙ | ︙ |
Changes to LPCWorkspace/PDMSPL/src/uart_rom_int.c.
︙ | ︙ | |||
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | /* Interrupt mode, do not append CR/LF to sent data */ param.transfer_mode = TX_MODE_SZERO; param.driver_mode = DRIVER_MODE_INTERRUPT; /* Setup the transmit callback, this will get called when the transfer is complete */ param.callback_func_pt = (UART_CALLBK_T) waitCallback; /* Transmit the data using interrupt mode, the function will return */ gotCallback = false; if (LPC_UARTD_API->uart_put_line(uartHandle, ¶m)) { errorUART(); } | > > > > < < < | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | /* Interrupt mode, do not append CR/LF to sent data */ param.transfer_mode = TX_MODE_SZERO; param.driver_mode = DRIVER_MODE_INTERRUPT; /* Setup the transmit callback, this will get called when the transfer is complete */ param.callback_func_pt = (UART_CALLBK_T) waitCallback; /* Wait until the previous transmit callback occurs. When it hits, that transfer is complete. */ sleepUntilCB(); /* Transmit the data using interrupt mode, the function will return */ gotCallback = false; if (LPC_UARTD_API->uart_put_line(uartHandle, ¶m)) { errorUART(); } } /*static*/ void putLineUART(const char *send_data) { return putLineUARTn(send_data, strlen(send_data)); |
︙ | ︙ | |||
239 240 241 242 243 244 245 246 247 248 249 250 251 252 | /* Allocate UART handle, setup UART parameters, and initialize UART clocking */ setupUART(); /* Enable the IRQ for the UART */ NVIC_EnableIRQ(UART0_IRQn); } /** * @brief Hook stdio output. * * Supply a low-level system call stub to hook newlib-nano stdio output to the UART. | > > > | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | /* Allocate UART handle, setup UART parameters, and initialize UART clocking */ setupUART(); /* Enable the IRQ for the UART */ NVIC_EnableIRQ(UART0_IRQn); gotCallback = true; } /** * @brief Hook stdio output. * * Supply a low-level system call stub to hook newlib-nano stdio output to the UART. |
︙ | ︙ |