From PIC16F690 to PIC18F26K20 + The big function!

Markd77

Joined Sep 7, 2009
2,806
Looking at the code in post 119, you seem to be having trouble with org.
It's only for program memory, so don't use it in cblock for variables. If you really want a 2 byte gap, either add a couple of bytes of dummy variable (dummy:2), extend an existing variable (filcof1:10*2+2) or use
endc
cblock 0x118

for the actual program, if you don't put org 0x00 at the start, it turns out that that is the default anyway.
Your: filter1 dw 17,-25,17,-460,246,2498,-4900,2498,-469,247
ends up starting in program location 0x00 and as the PIC doesn't know any better it will try to execute the data, which usually isn't a great idea.
Either put it somewhere high up where the program won't reach eg.
org 0xff00
filter1 dw 17,-25,17,-460,246,2498,-4900,2498,-469,247
org 0x00
normal code goes here

or put it somewhere impossible for execution to get to, eg.
org 0x00
goto init
org 0x04
interrupt
...
retfie
filter1 dw 17,-25,17,-460,246,2498,-4900,2498,-469,247
init
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Looking at the code in post 119, you seem to be having trouble with org.
It's only for program memory, so don't use it in cblock for variables.
If you really want a 2 byte gap, either add a couple of bytes of dummy variable (dummy:2), extend an existing variable (filcof1:10*2+2) or use
endc
cblock 0x118

for the actual program, if you don't put org 0x00 at the start, it turns out that that is the default anyway.
My bad...Will remove those "org" thought of using {cblock ...endc } but didn't. Anyway do you thinking having a 2 bytes gap is a good idea?

Your: filter1 dw 17,-25,17,-460,246,2498,-4900,2498,-469,247
ends up starting in program location 0x00 and as the PIC doesn't know any better it will try to execute the data, which usually isn't a great idea.
Either put it somewhere high up where the program won't reach eg.
org 0xff00
filter1 dw 17,-25,17,-460,246,2498,-4900,2498,-469,247
org 0x00
normal code goes here

or put it somewhere impossible for execution to get to, eg.
org 0x00
goto init
org 0x04
interrupt
...
retfie
filter1 dw 17,-25,17,-460,246,2498,-4900,2498,-469,247
init
Yes, actually I have different bits of code that I ll combine properly as I progress...I just wanted to simulate that part of the code to see the contents of those registers above...

Will fix it now...
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I mistakenly deleted the whole post #119 so here's it is and the code attached:

I have added "filter2 ... filter7" (will add values later) in ROM, the flags registers and arrays for these filters all in bank1 to make things easier.

I am thinking of turning that code that "load filter constants into RAM and setting sign flags" into a routine that will do the job for the seven filters at once (intead of writing that code 7 times) in a loop I guess. That's why I am now clearing the flags outside.

All critics are welcome while I'm thinking.

Maybe you can spot what makes it not to simulate...
I removed the org and will space them later...for now I am trying to make a routine out of it.

Any simulation help??
 

Attachments

Markd77

Joined Sep 7, 2009
2,806
Have another look at the listing you just posted, what program memory location is the start instruction at?
Normally you would put the cblock at the top, above any code, not sure if it makes any difference to the actual operation.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I'm having a little build problem (since i made a few changes) that I am fixing...as soon as i do I ll have a look at the listing.

what do you think about creating a single routine for these seven filters? I'm asking coz I might make it more complicated...

coz this:

Rich (BB code):
movlf tblptrl,low filter1 ;tablat points to constants in ROM
movlf tblptrh,high filter1
 
lfsr 0,filcof1-1  ;fsr0->byte before coefficient table for filter 1
and this:

Rich (BB code):
movfw temp0   ;set negative flag for this coefficient
iorwf f1flags,f,1
movfw temp1
iorwf f1flags+1,f,1
will have to be changed for the different (actually seven) filters.

I have idea but don't want to make it complicated
 

Markd77

Joined Sep 7, 2009
2,806
Yes, I tried to build it without much success. Is your version of MPlab not case sensitive? Mine gives me errors when I try to compile something with "status" instead of "STATUS", etc.
You seem to have plenty of program memory, so may as well copy and paste the code 7 times, it will run slightly faster and be easier.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Yes, I tried to build it without much success. Is your version of MPlab not case sensitive? Mine gives me errors when I try to compile something with "status" instead of "STATUS", etc.
Yes it is case sensitive...I always disable it first

You seem to have plenty of program memory, so may as well copy and paste the code 7 times, it will run slightly faster and be easier.
Ok. Will copy and paste for now and move on...Can still refine there and there later...

Thanks!
 

Markd77

Joined Sep 7, 2009
2,806
Ah, it's in the build options. Got it to compile now and looked at the disassembly listing:


There's your problem!
When that was in the first program memory location it didn't have much choice, a stack underflow was inevitable.
 

Attachments

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I added the filters values initially computed (will change them...) to simulate the whole thing and see if everything is Ok and I can see, as shown attached, that there's a problem with the coefficients' signs.

The first simulation on post #95 worked ok because the signs are symetric relative to the coefficients, ie the signs are in the same order wheter you look at them from the 1st coefficient or from the last coefficient.

When you look at the signs of filter2 to filter7, you can see the two flag bytes are swaped (it's an easy fix tho). So I think I should change the code as suggested in my post #118

what's your thought on that?

Thanks!
 

Attachments

Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Now it's time for me to work, while fixing the above signs thingy, on implementing the 2nd block of my flowchart on post #68 and post #75.

Will refresh my mind and give it a go tomorrow.
 
Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Attached is the routine I'll be using to multiply *positive* coefficients (2bytes) with the samples (10 bits ->2bytes) that are always +ve.
I worked out my own code and came up with the same routine but I used different order that results in the same code. I don't know if someone will come up with a code with less line (I doubt it:)) for this same job. This code only takes 2.8us @ 40Mhz and I will running @ 64Mhz so I have plenty of time to compute other stuff as I ll be sampling @ 250us.

Tomorrow I'll investigate about the routine "mulsub" that will multiply *-ve coefficients* with the samples. I don't know yet if I'll come up with the same routine as the datasheet.
 

Attachments

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Hi!

If you wondering what I'm doing at the moment...well trying to make some $$$ and at the same time reading about *digital filters*, especially the cascaded part of it, coz I want to make sure that the flowchart I came up with in post #68 is correct. Once I start coding it I do not want to spot a mistake in the algorithm/flowchart and have to start over again.

As for the two multiply functions I save it for a bit later as they kinda trivial...

Here's the link I am reading (5 parts): http://www.eetimes.com/document.asp?doc_id=1272177

Thanks!
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
i love assembly more too he he
Yeah assembly is the way to go...just use macros when/where necessary and you won't have large code. Will never ever use C when playing with PICs and AVRs (This might upset some here...:))

Here's how I see Assembly and C when it comes to MCUs:

It's like you see an attractive girl that you are interested in and you ask your friend to call her for you instead of chasing her yourself...That's how C works!:D. And you have no idea how your friend might do it.

Assembly is like the real player and does not need anyone to get girls..."Hey wassup girl lemme talk to you real quick..." lol you get the picture...
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
I didn't get what I was looking for in post #132... anyway...

I'm currently trying to implement two highlighted part of the flowchart and once done will do the rest. To better implement it I worked it out as shown attached.

The first equation is :
y(n) = b11*x(n) + b12*x(n-1) + b13*x(n-2) - a11*y1(n-1) - a12*y1(n-2)

The above equation will only be executed on the 3rd ADC iteration (see attached) and we get: EDIT: Why?? it does not matter if the others are zero initially.

y(n) = b11*x(n) + b12*x(n-1) + b13*x(n-2), where y1(n-1) = y1(n-2) = 0 (c)

then from (4) in attachment:
y(n) = b11*x(n) + b12*x(n-1) + b13*x(n-2) - a11*y1(n-1) (d) ; where y1(n-2) = 0 and y1(n-1) is y(n) from (c)

then from (5):
y(n) = b11*x(n) + b12*x(n-1) + b13*x(n-2) - a11*y1(n-1) - a12*y1(n-2) (e) ; where y1(n-2) is y(n) from (c) and y(n-1) is y(n) from (d)

From (5) on we get a complete equation with all xs and ys.

I am a bit stuck/confused and I need a little push in the right direction (Not help with the coding as I'll post it here and if any error or better coding you can still mention it).

I have two different way of implement it but as previous samples (x and y) will be needed I think its best to proceed the following way...

As suggested in earlier post "It's best to store the current sample at the head of the queue..." which is very simple to do BUT now I'm not too sure how to pick up ....

Should I store all samples in RAM first (1st sample ... last sample) and then working in reverse order?

I need 2000 samples at 250us giving half a second word.
Selecting coefficient is no problem!

Another idea I had was to not save all 2000 samples...but using them 3 at the time as we only need [ x(n), x(n-1) and x(n-2)] per equation

I'll stop here to not make it long... Looks like I'll have different array for x's and y's...coz samples coming out from ADC are all X's...

Thanks for your comment
 

Attachments

Last edited:

Markd77

Joined Sep 7, 2009
2,806
You can either store the samples with the most recent sample always at one end of the array and keep moving the samples along every time, or you can store the samples as they come in and have a variable that is the location of the most recent sample.
eg
n-3 n-2 n-1 n-0 n-7 n-6 n-5 n-4
your variable would contain 3 (for a 0 indexed array), and when the next sample comes in the array becomes:
n-4 n-3 n-2 n-1 n-0 n-7 n-6 n-5
and your variable contains 4 - note that nothing has been moved, just the new sample (n-0) overwrites the old n-7
It's useful to keep the array length a power of 2, because if you wanted to get the variable n-4 in the top line, you can use 3 (the pointer variable) - 4, so you get b'11111111' , but then AND that with b'00000111', then you get 7 which is the location of the variable you were after.

The first method is probably better for a few samples, but with a lot of samples the second method is faster.
 

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
You can either store the samples with the most recent sample always at one end of the array and keep moving the samples along every time, or you can store the samples as they come in and have a variable that is the location of the most recent sample.
eg
n-3 n-2 n-1 n-0 n-7 n-6 n-5 n-4
your variable would contain 3 (for a 0 indexed array), and when the next sample comes in the array becomes:
n-4 n-3 n-2 n-1 n-0 n-7 n-6 n-5
and your variable contains 4 - note that nothing has been moved, just the new sample (n-0) overwrites the old n-7

It's useful to keep the array length a power of 2, because if you wanted to get the variable n-4 in the top line, you can use 3 (the pointer variable) - 4, so you get b'11111111' , but then AND that with b'00000111', then you get 7 which is the location of the variable you were after.

The first method is probably better for a few samples, but with a lot of samples the second method is faster.
I love AAC coz I have lots of brilliant friends here and since I got here my level of stupidity has significantly decreased...:)

I like the second method as there's no need to save all samples and clear the array and as you mentioned its quicker.

So when we reach end of array : n-7 n-6 n-5 n-4 n-3 n-2 n-1 n-0 we reset pointer to start of array : n-0 n-7 n-6 n-5 n-4 n-3 n-2 n-1.

I don't understand that math coz '11111111' AND '00000111' = '11111111' which is not 7.??

Pardon my ignorance!

And how about making the array of 4 elements? still power of 2 we'll have a loop:

n-0 n-3 n-2 n-1
n-1 n-0 n-3 n-2
n-2 n-1 n-0 n-3
n-3 n-2 n-1 n-0

And on the very first ADC I'll use n-2 = n-1 = 0 and on the 2nd n-2 =0 and from the 3rd we'll always get all values till we get all the 2000 samples.

I have no deadline for this project as its personal so I'm doing that comfortable with no pressure and at the same time I can't wait to finish and move on to the next one...

Edit: I have done enough talking...Time to post some code! Will do in 3 days time as I'm busy with something but I'll keep an eye on this thread...

Thanks!
 
Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Hi!

I wrote a bit of code for the high isr. Its job is *only* to copy the ADC incoming samples into an array in RAM as show in the previous post.

Please let me know if it makes sense and is well written.
Note: I have not assembled this code as yet. This code will be assembled and added in the existing code if it is approved by the *big boyz* here.

Then I'll write and post the code that does the actual multiplication of the samples with the coefficients.

*10 bit ADC resolution -> 2 bytes *

Thanks for your comment.

Rich (BB code):
; in Access RAM
; sample_cnt0 initialized to '250' and sample_cnt1 to '8', 250*8 = 2000.
 
 
 sample_cnt0    ;general purpose sample counter 
 sample_cnt1 
 
 flags            ;flags register  
 
; in bank1
 
 cblock 0x1B0
 samples_x:4*2    ;ADC samples array [7]
                  ;x(n),x(n-1),x(n-2),x(n-3)
 endc
 
;ignore the samples_y for now
 
 samples_y:--    ;samples output array [--]
                  ;y(n), y(n-1),y(n-2),y(n-3)
 
; This line of code will be put in the variables initialization
 
 lfsr  2,samples_x   ;fsr2-> samples_x (0)
;-----------------------------------------------------------------------
; high priority interrupt service routine
; Context Saving for High ISR
 
 movff    adresl,postinc2  ;copy low byte ADC result to RAM
 movff    adresh,postinc2  ;copy high byte ADC result to RAM
 
 movlw    b'10110111'    ;sample_x (7) reached?
 xorwf    fsr2l,0,0      ;W <-result, Access RAM
 skpz
 goto      $+2            ;count the sample
 movlw    -7              ;yes then reset pointer fsr2  
 addwf    indf2,1,1       ;fsr2-> samples_x (0)
 
 decfsz   sample_cnt0         ;count 2000 samples (250*8=2000) 
 goto     exit_high_isr           ;exit
 movlf    sample_cnt0, d'250'  ;reset sample counter
 decfsz   sample_cnt1
 goto     exit_high_isr            ;exit
 movlf    sample_cnt1, d'8'       ;reset sample counter
 
bsf  flags,smplflag,0             ;set 2000 samples flags
 
exit_high_isr
 
retfie  fast    ;get out fast

Edit: Any comments? better suggestion/coding? I'll carry on while waiting for your comments...
 
Last edited:

Thread Starter

Eric007

Joined Aug 5, 2011
1,158
Hi!

I am writing/editing a piece of code to be posted soon...

I need to know if I can write, as there's no *predec* instruction:

Rich (BB code):
movlw   -1
addwf   indfn,f,0
 
or
 
movlw   -1
pluswn
where n= 0,1,2.

Correct? Well I used the first option in the previously posted code...
 

Markd77

Joined Sep 7, 2009
2,806
I don't know much about this pic18 code.
You can use
movlw samples_x+8 ;sample_x (8) reached?
instead of
movlw b'10110111' ;sample_x (7) reached?
(I think you probably want to check for 8 not 7)

using W and F instead of 1 and 0 makes it easier to read.

Maybe it should be goto $+3 (if the next two instructions are single word instructions).
 
Top