From PIC16F690 to PIC18F26K20 + The big function!

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I will have to read the above post carefully before posting...

As for assembling before posting...I will make an effort but I'm working under hard condition as my laptop broke down...will have a brand new one in 2 weeks!!

I love your macro file!!!

Thanks very much indeed!
 

joeyd999

Joined Jun 6, 2011
5,283
Attached is part of the 'filter1_IIR4' fuction that uses a couple of macros...the algorithm of this fuction is described in post #32

I only wrote the code for the first two coefficients because I need to know if I'm writing it well so I can carry on to the end.

So basically, the coefficient is loaded into two 8-bit registers, the sample is loaded in another two 8-bit registers then the 'mult_accum' macro multiply them and accumulate the product result.

My first concern is about the 'current' sample from ADC (ADRESH:ADRESL), this needs to be temporarely stored somewhere so that the different filter functions can process it...so i was wondering if storing it in a two 8-bit registers (like i did in the code) is the way of doing it or there's a best way?

Also, the loading of the coefficient from the program space into the registers and... is the programming ok?

regards !
Let N = number of samples you are filtering. Therefore, you need to compute:

f=C(n)*SAMP(t(n)) + C(n-1)*SAMP(t(n-1)) + ... + C0*SAMP(t0)

where n=N-1, and SAMP(t0) is the current A/D sample.

You can set up a round-robin queue for the samples, and your coefficients as an array in program ROM.

For each sample, store the new value at the head of the queue (it is round-robin, so you don't need to shift any positions). Use one of your FSRs to always point to the current head of the queue.

Then, in one loop, iterate through the math N times, using an FSR to point to your history of samples, and TBLPTR to point to your coefficients.

If I have time, I will put some code together as a (rough) sample. To make your queue easier to manage, it will help if your history is 2^x samples long, so 2, 4, 8, etc.

Also, remember that your math will only work if you used signed integers (or floats). This will have an impact on execution time.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Thanks for this post...

May I ask you to have a look at my post #31 and especially post#32 where I describe my algorithm? Actually I'm creating a 4th order filter by cascading two 2nd order filter...

I will provide the coefficients of the first function in hexadecimal if this is ok I will show all my working how I got to this!

Regards, Eric
 

joeyd999

Joined Jun 6, 2011
5,283
May I ask you to have a look at my post #31 and especially post#32 where I describe my algorithm? Actually I'm creating a 4th order filter by cascading two 2nd order filter...
Pardon my ignorance, but you cannot create the response you desire with a single filter?
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I just need help with the programming part...

The math behind is not bad...just multiplying 2 arrays (one from Program space and one from RAM) then update the samples array ie x-2=x-1, x-1=x, y-2=y-1, y-1=y

Where x is current sample, y output of current sample, y-2 output of x-2, etc...
Then use y (output of 1st filter) as input of second filter and do the same...

I'll try posting a flowchart maybe it will be much better...if it not then I'll try to hardcode it so you can see what I'm trying to do...

Thanks again
 

joeyd999

Joined Jun 6, 2011
5,283
I just need help with the programming part...

The math behind is not bad...just multiplying 2 arrays (one from Program space and one from RAM) then update the samples array ie x-2=x-1, x-1=x, y-2=y-1, y-1=y

Where x is current sample, y output of current sample, y-2 output of x-2, etc...
Then use y (output of 1st filter) as input of second filter and do the same...

I'll try posting a flowchart maybe it will be much better...if it not then I'll try to hardcode it so you can see what I'm trying to do...

Thanks again
Yes, you are trying to create an IIR filter...sorry, originally I thought you were trying to cascade two FIR filters. OK, I understand. Like I said, I will try to cobble some code together for you. But don't hold your breath, I've got to find some time. Perhaps someone else will beat me to it.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Yes, you are trying to create an IIR filter...sorry, originally I thought you were trying to cascade two FIR filters.
That's correct I'm trying to create an IIR filter BUT a 4th order one by using two 'direct form II transposed difference equation' as shown below:

y1(n) = b11*x1(n) + b12*x1(n-1) + b13*x1(n-2) – a11*y1(n-1) – a12*y1(n-2)
y2(n) = b21*x2(n) + b22*x2(n-1) + b23*x2(n-2) – a21*y2(n-1) – a22*y2(n-2)

As you can see there are 10 coefficients since it is a 4th order...if I was implementing a 2nd order I would have 5 coefficients only!

And the output will be Yout = y*gain

I will try my best to post a flowchart...

I can can also try to code it but I need a code with a reduce instruction cycle...
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Attached is the flowchart...

I've drawn it too quickly...hope there's no mistake...
I will explain later if it's not self explanatory!!

Well I have combined everyting in the filter function to reduce instruction cycles instead of making 3 functions
Will post coefficient values later...

Eric!
 

Attachments

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I'm trying to cobble some code for my flowchart but have a quick lil question...

Assume you have a an array of words in the program space:
array dw 0x--, 0x--,...

Now you need put lower byte and higher byte of an element into two register then increment pointer, how to do that?

Coz if it was an array of 'bytes', I'll do the following:
- first place address of array in TBLPTR registers then do this

tblrd*+ ;
movf TABLAT, w ;
movwf templ ; copy lower byte
tblrd*+ ;
movf TABLAT, w ;
movwf templ ; copy higher byte

Etc...

How about 'words'?

Thanks!
 

joeyd999

Joined Jun 6, 2011
5,283
I'm trying to cobble some code for my flowchart but have a quick lil question...

Assume you have a an array of words in the program space:
array dw 0x--, 0x--,...

Now you need put lower byte and higher byte of an element into two register then increment pointer, how to do that?

Coz if it was an array of 'bytes', I'll do the following:
- first place address of array in TBLPTR registers then do this

tblrd*+ ;
movf TABLAT, w ;
movwf templ ; copy lower byte
tblrd*+ ;
movf TABLAT, w ;
movwf templ ; copy higher byte

Etc...

How about 'words'?

Thanks!
You can use MOVFF, but you may want to try working right out of TABLAT.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Sorry! I'm a bit lost...coz TABLAT is an 8-bit register and each element of array is 16-bit so I still don't see how to split the 16-bit into two registers?

I made a lil mistake, actually in the above post the register should be temph:templ

Maybe if you provide a conversion of the above code for 'word elements' or explain more I'll be OK...I really wana get this coz I don't want to store coefficients into RAM!

Pardon my ignorance...

Thanks!
 

joeyd999

Joined Jun 6, 2011
5,283
Sorry! I'm a bit lost...coz TABLAT is an 8-bit register and each element of array is 16-bit so I still don't see how to split the 16-bit into two registers?

I made a lil mistake, actually in the above post the register should be temph:templ

Maybe if you provide a conversion of the above code for 'word elements' or explain more I'll be OK...I really wana get this coz I don't want to store coefficients into RAM!

Pardon my ignorance...

Thanks!
A 16 bit multiply, in the PIC, must be preformed as 4 8 bit multiplies & additions. Since you need to address the high & low bytes seperately anyway, rather than copy them, do two multiplies with the low byte followed by 2 multiplies with the high byte.

BTW, this assumes all your coefficients are *positive* numbers. If not, then you will need to copy them out and perform a 2s compliment prior to any multiplication.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
It alright! I'm gona stop a bit with the coding and work all the coefficients!
There are 4 negative coefficients and 6 positive ones!

I will generate them for all 7 filters, ie 10 x 7 = 70 coefficients...and see what they look like...I will also cobble and post a code for the accumulator (ie a macro that multiply values stored in two 8_bit registets and store/accumulate their product result in a 24 bit register)

Thanks!
 
Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Attached are the coefficients and gain for each filter...
If any is interrested in how I came with that I can still explain...
Also note I could implement less or more filters even the interval can be altered...

I first need to have a complete system (code) and will modify accordingly based on its behaviour...

I think I will store those arrays in ARAM as it will make my coding much easier...

Now I'm thinking should I make 7 arrays or just a big array of 70 elements? Or it doesn't really matter?

I attached the coefficients so you can the nature of those numbers...

Thanks if any comments!
 

Attachments

joeyd999

Joined Jun 6, 2011
5,283
I've been swamped the last few days, so I haven't been able to even think about your code. But here are some ideas (considering that execution speed is the primary goal):

1. Since your constants are predefined, I suggest storing them all as positive integers, and having two mul/acc routines: muladd and mulsub. Select the appropriate routine depending on whether the coefficient is positive or negative.

2. Since the input (a/d values) are always going to be positive, no sign testing will need to be done on these prior to multiplication.

3. OTOH, the output value fed back into the equation *may* be negative, you will need to sign test & convert. I suggest keeping all output values as positive integers, and using a separate flag to denote positive or negative. This way, you only need a single 2's complement for each output value per sample.

I am sure I'll think of more...
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Eric, may I suggest in the future that you try to assemble your code prior to posting. You will then see things like:
*
RETFIE,FAST
*
will give you an error and
*
RETFIE FAST
*
will not.
*
I’ll try my best…my laptop is dead! So it kinda Hard for now…

Also, read the datasheet! It is your best friend. For instance:
*
Therefore, you do not need to save Status, WREG, or BSR at the start of your high priority interrupt! This will save you some instruction cycles.
*
Also, I am going to assume you only need one hi-p interrupt (the A/D), so get rid of the interrupt flag checking and the GOTO ADC_int code. Just run the A/D int processing immediately. As long as you have the ADIP bit set, *and no other*, flag checking does nothing for you except waste instruction cycles. (But you still need to clear the flag!)
Ok! I fixed that…but reading the datasheet is not always easy…it different from reading magazines or whatever…sometimes you (I’m actually talking about myself here) can read the datasheet and think you’ve understood it but not…LOL
*
Please go back to the 'fourled' code and consider using my example of using a system clock driven by TMR0. There is no need to do pushbutton processing inside an interrupt. Your main loop can do this easily by checking the timer change flag that indicates about 16ms. One instruction, done.
I agree with you BUT that code of yours has been written in a *fancy* and *sophisticated* way…and I still don’t understand how the ‘gettim’ and ‘getkey’ routines work…
OK gimme another chance to read it again and if I still have a problem with that I’ll address it in this thread since ima use it!

*
Like I said in an earlier post, use macros and operators to make your code easier to read and maintain, for example:
*
Rich (BB code):
****movlf****CCPR2L,low 4000
****movlf****CCPR2H,high 4000
*
You can even make a 'double literal' macro, and simplify this even further:
*
Rich (BB code):
movdf****macro****reglo,literal
*
****movlw****low literal
****movwf****reglo
****movlw****high literal
****movwf****reglo+1
*
****endm
*
...
*
****movdf****CCPR2L,4000
Nice one! I have fixed that…


I've attached a file of a set of standard macros I use for each 18F project.
I’ve checked that and I love it!

T3CON is self-explanatory. Take a guess, and see if it works.
Ok! I think I’m only interested in bit 6 and 4 only!
Here’s what I got:

Rich (BB code):
movlw     b’01010000’
andwf      T3CON, 1
I’m not too sure about the above code…I was going to use two ‘bcf’ instruction but nah!
*






*
May I suggest you use 2048 conversions instead of 2000? This way, you only need to test bit 4 of the high byte of the counter (counting up from zero) to determine when you're done. Two benefits: saves instruction cycles and, later, when your trying to compute an FFT (which I know you will!), an FFT generally works with datasets of 2^n samples.
Well, FFT is one of the method but I’m not going to use it since I’m not familiar with it yet and this will require too much reading/learning if I have to use it…I’ll use ‘bandpass filter method’ instead…

Unless you have power issues, don't bother starting/stopping timer 1. Let it free run, and let the A/D run continuously. Use a flag triggered by the push button in the main loop to activate the DSP code in the A/D interrupt, and let the A/D interrupt clear the flag when the number of required samples are complete. This is *much* easier and less prone to problems in the long run.
*
Also, you must *guarantee* that your signal processing completes its task for each sample prior to the next sample. I strongly recommend doing your DSP *within* the A/D interrupt code. Generally, this is a *bad* idea, but in this case it will be necessary! Just make sure you have enough "daylight", as ErnieM calls it, to process your main loop often enough.
I like this paragraph…have done just as suggested…
**
*
For now, don't worry about the WDT, BOR, Code Protection, etc.. Just turn them off. Theses are 'production' features, and you don't need them for firmware development.
OK

If you are going to use the internal oscillator, remember that there will be variation in your clock, and therefore, sampling rate. This *may* cause issues wrt speech recognition if that is what your are still trying to do.
What will cause these variations in the clock? What would you suggest?
But this is just the first prototype being implemented…
*
**
Thanks so much!!!
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
What do you think of the T3CON configuration? (Timer1 assignment to CCP2 module)
Is my code correct? If not please show me how to do it!

Sometimes doing simple stuff gets more complicated than doing complicated stuff...
 
Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
... But here are some ideas (considering that execution speed is the primary goal):

1. Since your constants are predefined, I suggest storing them all as positive integers, and having two mul/acc routines: muladd and mulsub. Select the appropriate routine depending on whether the coefficient is positive or negative.
OK! I can do that...but what would be the problem or the difficulty by storing those coefficients as they are and having only one mult_accum routine?

2. Since the input (a/d values) are always going to be positive, no sign testing will need to be done on these prior to multiplication.
OK!

3. OTOH, the output value fed back into the equation *may* be negative, you will need to sign test & convert. I suggest keeping all output values as positive integers, and using a separate flag to denote positive or negative. This way, you only need a single 2's complement for each output value per sample.
Do you mean the output will have to be sign tested first then a flag will indicate wheter it positve or negative and if negative then that value will be converted into its 2s complement, right? Lemme know if I got that right please...


Thanks!
 
Top