Divide by 16 boxcar averaging not working properly - 9SO8 assembly - Page 1
Forum section: electronics / general

author: Circlotron
author_rank: Super Contributor
timestamp: February 09, 2021, 01:12:28 am
content: Got a little project going where I want to set or clear a bit depending on whether an input trigger pulse is above or below 120Hz. I grab the 1.25MHz counter reading every trigger pulse and take the average of the last 16 readings and compare it to a value. The thing is, if Idon'tuse the averaged value it sets or clears as good as dead on 120Hz, no problem, but if I use the averaged value it sets or clears at 119.09Hz. Sure, I lose the the 4 LSBs when I right shift 4 times, but this is an error approaching 1%, way more than those 4 bits would account for. Pretty sure the lost bits are all zeros anyway. I just can't figure out what's happening. This is the relevant portion of the code. And, yeah, it's hardly optimal, I know, but it should work. Any ideas? assembly suggestions only, not C.Code:********************************************************************************WAIT_TRIGBRSETTRIG,PORTB,WAIT_TRIG;inverted trigger from coilLDHXTCNTH;get current counter value (1.25MHz)STATCNTH;reset counterSTHXTEMP_CTR_MSBJSRPUSH_DOWN;push previous counter readings down one placeLDHXTEMP_CTR_MSB;latest countSTHXMSB_1;put latest on the pileBCLRTOF,TSC;just in caseJSRADD_UP;add up last 16 timer periodsJSRDIV_16;average = MSB_TOT:LSB_TOT*********************************************LDHXMSB_TOT;averaged countCPHX#10417;1800rpm or less, 120Hz, 8.333mSBHSCLR_BIT;clear if < 120HzBSET0,PORTA;set if > 120HzJMPWAIT_TRIGCLR_BITBCLR0,PORTA;JMPWAIT_TRIG********************************************************************************;push last 16 counter readings down one placePUSH_DOWNLDHXMSB_15STHXMSB_16LDHXMSB_14STHXMSB_15LDHXMSB_13STHXMSB_14LDHXMSB_12STHXMSB_13LDHXMSB_11STHXMSB_12LDHXMSB_10STHXMSB_11LDHXMSB_9STHXMSB_10LDHXMSB_8STHXMSB_9LDHXMSB_7STHXMSB_8LDHXMSB_6STHXMSB_7LDHXMSB_5STHXMSB_6LDHXMSB_4STHXMSB_5LDHXMSB_3STHXMSB_4LDHXMSB_2STHXMSB_3LDHXMSB_1STHXMSB_2RTS*************************************;Add up latest 16 counter readingsADD_UPCLR LSB_TOTCLR MSB_TOTCLR EXT_TOTLDA LSB_TOTADD LSB_1STA LSB_TOTLDA MSB_TOTADC MSB_1STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_2STA LSB_TOTLDA MSB_TOTADC MSB_2STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_3STA LSB_TOTLDA MSB_TOTADC MSB_3STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_4STA LSB_TOTLDA MSB_TOTADC MSB_4STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_5STA LSB_TOTLDA MSB_TOTADC MSB_5STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_6STA LSB_TOTLDA MSB_TOTADC MSB_6STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_7STA LSB_TOTLDA MSB_TOTADC MSB_7STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_8STA LSB_TOTLDA MSB_TOTADC MSB_8STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_9STA LSB_TOTLDA MSB_TOTADC MSB_9STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_10STA LSB_TOTLDA MSB_TOTADC MSB_10STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_11STA LSB_TOTLDA MSB_TOTADC MSB_11STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_12STA LSB_TOTLDA MSB_TOTADC MSB_12STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_13STA LSB_TOTLDA MSB_TOTADC MSB_13STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_14STA LSB_TOTLDA MSB_TOTADC MSB_14STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_15STA LSB_TOTLDA MSB_TOTADC MSB_15STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTLDA LSB_TOTADD LSB_16STA LSB_TOTLDA MSB_TOTADC MSB_16STA MSB_TOTLDA EXT_TOTADC #0STA EXT_TOTRTS*************************************;divide total of last 16 counter readings by 16DIV_16LSR EXT_TOTROR MSB_TOTROR LSB_TOTLSR EXT_TOTROR MSB_TOTROR LSB_TOTLSR EXT_TOTROR MSB_TOTROR LSB_TOTLSR EXT_TOTROR MSB_TOTROR LSB_TOTRTS****************************************************************************************************************************************************************ORG $FFFEFDB START********************************************************************************

author: fourtytwo42
author_rank: Super Contributor
timestamp: February 09, 2021, 10:18:24 am
content: Not being an expert in your particular instruction set (I am more ARM & PIC) something that has gotten me several times in assembly arithmetic is not bounds checking properly and getting random errors as a result. I have even before convinced myself that an overflow is impossible only to discover it happening

author: Circlotron
author_rank: Super Contributor
timestamp: February 09, 2021, 11:35:59 am
content: The counter rollover value is set to #46875 (37.5mS) so that fits fine into 16 bits. In any case the value we are looking for is #10417 and we are right close to it (but not close enough!) when dithering on the threshold. We have 24 bits available for the 16 16-bit counter values summed so heaps of space there too. In any case, #10417 is 14 bits and the total is an 18 bit value which of course goes back down to 14 bits when right-shifted. It's just weird.

author: ozcar
author_rank: Frequent Contributor
timestamp: February 09, 2021, 06:44:35 pm
content: I don't see any obvious typos or??I'd be inclined to test it by loading a constant value (in the vicinity of 10417) instead of the counter, and see what comes out. Or maybe you already did something like that?Edit:...and, presumably you have checked that your 1.25MHz really is, well, 1.25MHz?

author: Circlotron
author_rank: Super Contributor
timestamp: February 09, 2021, 11:08:40 pm
content: Okay, I’ll try that. The thing runs off a 10MHz oscillator module that measures about 9Hz low so that’s pretty right. The counter rate must presumably be 1.25MHz as expected because the thing works just fine if I don’t use the averaging.

author: Circlotron
author_rank: Super Contributor
timestamp: February 10, 2021, 12:49:24 am
content: Soooo.... after a bit more investigation it appears that the problem is noise on the input trigger signal. If I apply an artificial trigger signal straight from the function generator the detection threshold is 119.989Hz, plenty close enough for me. There is a small amount of latency because I’m using a polling loop. Why it worked okay without the averaging is still a mystery though. That will have to do for now. Maybe I’ll investigate it further later.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 10, 2021, 01:22:59 am
content: How do you define MSB_nand LSB_n? Your PUSH_DOWN subroutine assumes MSB_nhas smaller address than the corresponding LSB_n(big-endian byte order), but if they are in the wrong order, PUSH_DOWN will mangle the data.

author: ozcar
author_rank: Frequent Contributor
timestamp: February 10, 2021, 01:35:24 am
content: Looking at it again, I can't figure how it is supposed to work. You spin at WAIT_TRIG until the signal goes low before grabbing the count value. If you get back to WAIT_TRIG before the signal has gone high again, don't you drop straight through and end up inadvertently measuring how long it took you to do your calculations? I must be missing something really obvious, or it would not work at all.Also, you don't seem to do anything to prevent trying to calculate average of last 16 samples, before you have that many? That would quickly resolve itself, but could cause initial glitch.

author: Circlotron
author_rank: Super Contributor
timestamp: February 10, 2021, 01:52:39 am
content: Quote from: Nominal Animal on February 10, 2021, 01:22:59 amYep, that is correct. From the databook regarding STHX:Quote

author: Circlotron
author_rank: Super Contributor
timestamp: February 10, 2021, 01:57:28 am
content: Quote from: ozcar on February 10, 2021, 01:35:24 amYou are certainly right, but in this particular case the trigger pulse is only about 10us wide so it is finished before the code is done executing. As for less then 16 samples while starting up, the averaged value will ratchet up from zero which is fine in this particular case. Thanks for your observations.