Hard to say without looking at your actual code, the devil is always in the details. Nothing is obviously wrong as far as I can tell.
There are a few potential problems
- Fixed point processing is hard. Doing this in floating point would me much easier.
- Taking the square of an
int32
results in an int64
. You need to make sure you are not clipping.
- There is some superfluous stuff in there. Instead of taking the root and doing $20 \cdot \log()$ you can just leave it squared an do $10 \cdot \log(\frac{x_{RMS}^2}{2^{46}})$
- The last step is clearly wrong. You need to average in energy not in dB. However that should result in such large an error if your test signal is reasonably stationary.
The buffering scheme seems awkward. I would just get a sample, square it and apply a low-pass filter for whatever time constant you want your $L_{EQ}$ to have. Turn this into to dB only when you need an output reading. But this depends a bit on what exactly you want to do with the $L_{EQ}$. For example, if you want this as a "dosimeter" you would need a star and a stop button as well.
General debugging rules apply (as they always). Start with a known test signal with known answer. Verify each block using one or more test signals. Don't both writing the next block before all previous blocks have been verified and unit tested.
In your case you can simply start with a 1kHz sine wave at 94 dB, (or if you can't isolate the setup yourself, use a lower level).
- Put your mems mic next to a speaker and play a 1kHz sine wave.
- Use a known good SPL meter to adjust the level to 94 dB SPL next to
the mems
- verify your algorithm step by step. For example, your input should be a sine wave with an amplitude of of 420000 or thereabouts and the RMS should be around 300000.
Once you have this up and running, try different frequencies, amplitudes, signal types, etc. Always verify against a good meter.