Large Array on PIC16 using C

Thread Starter

AfdhalAtiffTan

Joined Nov 20, 2010
120
Hi y'all,

So, I've been working on a project which uses PIC16F877A and XC8 compiler, but my array is limited to 30 or so.

I need at least like 255 or close. The PIC ram is capable of holding it, it just the compiler I believe.

i.e.
if unsigned int RAM[30] is ok, but not RAM[255].

Is there tips and tricks?
Pointer maybe?
 

fernan82

Joined Apr 19, 2014
26
Each bank of memory is 256 bytes, int RAM[256] is 512 bytes so it won't fit in one bank. I don't think so but you may be able to declare a 2 bank section on your linker script and allocate on that section. If not you may have to split the array into two chunks and allocate each on it's own bank. Then you can use an accessor function to access it.
 

Brownout

Joined Jan 10, 2012
2,390
I don't think so but you may be able to declare a 2 bank section on your linker script and allocate on that section.
Actually, you can. Look at bank "big" in the example below.


Rich (BB code):
DATABANK   NAME=gpr0       START=0x60              END=0xFF
DATABANK   NAME=gpr1       START=0x100             END=0x1FF
DATABANK   NAME=gpr2       START=0x200             END=0x2ff
DATABANK   NAME=big       START=0x300             END=0x48f
DATABANK   NAME=gpr4       START=0x490             END=0x4FF
DATABANK   NAME=gpr5       START=0x500             END=0x5FF
  
 
SECTION NAME=buffer_log RAM=big
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Actually, you can. Look at bank "big" in the example below.


Rich (BB code):
DATABANK   NAME=gpr0       START=0x60              END=0xFF
DATABANK   NAME=gpr1       START=0x100             END=0x1FF
DATABANK   NAME=gpr2       START=0x200             END=0x2ff
DATABANK   NAME=big       START=0x300             END=0x48f
DATABANK   NAME=gpr4       START=0x490             END=0x4FF
DATABANK   NAME=gpr5       START=0x500             END=0x5FF
  
 
SECTION NAME=buffer_log RAM=big
That looks like its for an 18F with contiguous banks of RAM. The 16F has 368 bytes of RAM hacked up into 4 banks. The compiler may be able to so something like Brownout's 'big' segment (which uses FSRs in the 18F to address the RAM) but I don't know, you may be sunk with the 16F as spanning fragmented banks is not pleasant.

Consider an array of 30 ints is 60 bytes, that's a big chunk of one RAM bank in the 16F877. Don't forget that the compiler will use some of the RAM for its internals and any static variables.

Check to see if XC8's help says anything about limits on banked RAM. At any rate, you are not going to get 256 ints to fit in that PIC.

Good luck.
 

fernan82

Joined Apr 19, 2014
26
The compiler may be able to so something like Brownout's 'big' segment (which uses FSRs in the 18F to address the RAM) but I don't know, you may be sunk with the 16F as spanning fragmented banks is not pleasant.
I don't think there's anything the compiler can do to allocate 510 bytes if the chip only has 368 :) I was thinking about the 18F as well.
 

Thread Starter

AfdhalAtiffTan

Joined Nov 20, 2010
120
Thanks for the replies. :)
I'm working on analog signal phase shifting, which samples via the adc.

My intention is to devise a 10-bit "parallel in - parallel out" fifo shift register.
I need large array so that I can introduce delay in real time.

i.e. 10-bit data -> 255byte shift register -> pwm

This is like a long conveyor belt carrying object will introduce delay of arrival if that make sense.

It doesn't necessarily 255bytes, as long as it is enough to shift the phase.

I read somewhere it is really is the compiler that is incapable of handling multiple bank in one array.

Hence I eager for y'all tips and tricks. :)
 

Brownout

Joined Jan 10, 2012
2,390
Well, I think the PIC is probably the wrong tool for this. You probably need a high-speed processor or to do it right, you need DSP processor. But if you're still determined to use the hardware, I think the amount of memory will depend on how much phase shift you're trying to achieve. In other words, how long a record length is required to hold the signal to be shifted. For example, if you're only looking to shift a couple uS you'll need SampleSize=delay(uS)*SampleFrequency. You may find your device just wont' have enough data memory, and you'll need to search for another device, or else augment your data memory. Keep in mind, you'll have a natural delay due to conversion time, processing delay, etc.
 

joeyd999

Joined Jun 6, 2011
5,237
i.e. 10-bit data -> 255byte shift register -> pwm
If you do proceed with a PIC, don't physically shift the data through RAM. This will take an unnecessarily long time. Instead, use head and tail pointers. Push data at the head and pop from the tail. Increment the appropriate pointer after each operation modulo buffer size.

Also, what you want to do, while maybe difficult in C, is easy in asm. Perhaps some inline asm code is in order?
 

THE_RB

Joined Feb 11, 2008
5,438
i.e. 10-bit data -> 255byte shift register -> pwm

This is like a long conveyor belt carrying object will introduce delay of arrival if that make sense.
...
It's called a "bucket brigade delay" and was common in early digital audio delays (ie sound effects).

Generally you do it by cheating and using two moving pointers (circular buffer style), rather than by shifting the entire delay with every sample.

I would go straight to a PIC 18F, then get it up and running using 8bit data so you don't need multiple bytes for each sample.

Once it is running you can decide if it is worth the effort going to multiple bytes per sample, and if/how you might do data compression or just use two bytes per 10bit sample.
 

JohnInTX

Joined Jun 26, 2012
4,787
Thanks for the replies. :)
I'm working on analog signal phase shifting, which samples via the adc.

My intention is to devise a 10-bit "parallel in - parallel out" fifo shift register.
I need large array so that I can introduce delay in real time.

i.e. 10-bit data -> 255byte shift register -> pwm

This is like a long conveyor belt carrying object will introduce delay of arrival if that make sense.

It doesn't necessarily 255bytes, as long as it is enough to shift the phase.

I read somewhere it is really is the compiler that is incapable of handling multiple bank in one array.

Hence I eager for y'all tips and tricks. :)
With deference to the other good suggestions, I'd consider going straight to the dsPIC (or something with some DSP capabilities). My rationale is that the time you spend coercing things to fit the lesser devices could be spent in getting up to speed on DSP and when done, your acquired skills would be more in line with where you are going instead of finding creative ways to get around the limitations of the PIC. IF you really must do it yourself, at least pick a PIC with a data length that accommodates your ADC readings i.e. if you need 10 bits, go for the 24F. Processing multibyte values in real time is completely do-able but.. why? Just my .02

EDIT: Brownout in post #8 is on to it as well. Agreed.
 
Last edited:

Art

Joined Sep 10, 2007
806
I've had a bit of inspiration to do with bitwise rotating a large array
from start to finish with repeated rotate commands.
You should only have to bitwise rotate the array a maximum of 7 times
to bitwise align bytes and with the remainder divisible by 8,
do the rest of the rotation by adding to the index for the array.

It's called a "bucket brigade delay" and was common in early digital audio delays (ie sound effects).

Generally you do it by cheating and using two moving pointers (circular buffer style), rather than by shifting the entire delay with every sample.

I would go straight to a PIC 18F, then get it up and running using 8bit data so you don't need multiple bytes for each sample.

Once it is running you can decide if it is worth the effort going to multiple bytes per sample, and if/how you might do data compression or just use two bytes per 10bit sample.
 

THE_RB

Joined Feb 11, 2008
5,438
I've had a bit of inspiration to do with bitwise rotating a large array
from start to finish with repeated rotate commands.
You should only have to bitwise rotate the array a maximum of 7 times
to bitwise align bytes and with the remainder divisible by 8,
do the rest of the rotation by adding to the index for the array.
I'm not sure I'm getting you. That only lets you work with 1 bit of data (not 8 or 10 bits that the OP needs).

And if you bit-rotate a multibyte array then all rotates need to be done by bit-rotation?

10000000 start
01000000 1 rotation
00100000 2
00010000 3
00001000 4
00000100 5
00000010 6
00000001 7
00000000 10000000 8

At what point would you stop doing bit rotation and change the byte index? :eek:

I have done another method with bit storage, using a bit-rotation of one byte only (to store 8 bits) followed by a increment in the array byte index. That's pretty much a standard way to store bits into a multibyte array.
 

Thread Starter

AfdhalAtiffTan

Joined Nov 20, 2010
120
Thanks again all for the advice.

I do thought about dsPIC, but it is new for me, I could learn, it might takes a long time.

I never knew there's "bucket brigade delay" before, thanks THE_RB! :)
Your algorithm is brilliant. :D

As joeyd999 suggested, I guess I will go with ASM first as it is the most appealing to me at the time.

Thanks again all. :)
 

fernan82

Joined Apr 19, 2014
26
I think dsPIC would be overkill. The only DSP feature that you'll be using is no overhead modulo addressing. PIC24 may make it easier if you're coding in assembly but it's still overkill. I would suggest PIC18 as well.
 

Art

Joined Sep 10, 2007
806
Hi RB, If you had an array of bytes, and felt like doing this:
Rich (BB code):
RotateArray:							' bitwise rotate array right
  @ rlf 	_dis+50		,F				; ditching the first bit
  @ rlf 	_dis+49		,F				;
  @ rlf		_dis+48		,F				;
  @ rlf		_dis+47		,F				;
  @ rlf		_dis+46		,F				;
  @ rlf		_dis+45		,F				;
  @ rlf		_dis+44		,F				;
  @ rlf		_dis+43		,F				;
  @ rlf		_dis+42		,F				;
  @ rlf		_dis+41		,F				;
  @ rlf		_dis+40		,F				;
  @ rlf		_dis+39		,F				;
  @ rlf		_dis+38		,F				;
  @ rlf		_dis+37		,F				;
  @ rlf		_dis+36		,F				;
  @ rlf		_dis+35		,F				;
  @ rlf		_dis+34		,F				;
  @ rlf		_dis+33		,F				;
  @ rlf		_dis+32		,F				;
  @ rlf		_dis+31		,F				;
  @ rlf		_dis+30		,F				;
  @ rlf		_dis+29		,F				;
  @ rlf		_dis+28		,F				;
  @ rlf		_dis+27		,F				;
  @ rlf		_dis+26		,F				;
  @ rlf		_dis+25		,F				;
  @ rlf		_dis+24		,F				;
  @ rlf		_dis+23		,F				;
  @ rlf		_dis+22		,F				;
  @ rlf		_dis+21		,F				;
  @ rlf		_dis+20		,F				;
  @ rlf		_dis+19		,F				;
  @ rlf		_dis+18		,F				;
  @ rlf		_dis+17		,F				;
  @ rlf		_dis+16		,F				;
  @ rlf		_dis+15		,F				;
  @ rlf		_dis+14		,F				;
  @ rlf		_dis+13		,F				;
  @ rlf		_dis+12		,F				;
  @ rlf		_dis+11		,F				;
  @ rlf		_dis+10		,F				;
  @ rlf		_dis+9		,F				;
  @ rlf		_dis+8		,F				;
  @ rlf		_dis+7		,F				;
  @ rlf		_dis+6		,F				;
  @ rlf		_dis+5		,F				;
  @ rlf		_dis+4		,F				;
  @ rlf		_dis+3		,F				;
  @ rlf		_dis+2		,F				;
  @ rlf		_dis+1		,F				;
  @ rlf		_dis+0		,F				;
  @ bcf		_dis+50		,0				;clear MSB
return
If you wanted to rotate the array 36 times bitwise, instead of doing the above
36 times,and perhaps having to copy the last bit back into the front of the array each time,
you could just increment the byte index of the array 4 times (32 divided by 8)
which would effectively look to the program like rotating the array bitwise 32 times,
and then you'd still need to do the above for the remaining 4 rotations to complete the 36.

Not what the poster needs,
but the relevance is you can use the same thing you mentioned to handle bitwise rotates cheaply as well.
I did this verbose to be fast, but it's not faster than incrementing bytes.







I'm not sure I'm getting you. That only lets you work with 1 bit of data (not 8 or 10 bits that the OP needs).

And if you bit-rotate a multibyte array then all rotates need to be done by bit-rotation?

10000000 start
01000000 1 rotation
00100000 2
00010000 3
00001000 4
00000100 5
00000010 6
00000001 7
00000000 10000000 8

At what point would you stop doing bit rotation and change the byte index? :eek:

I have done another method with bit storage, using a bit-rotation of one byte only (to store 8 bits) followed by a increment in the array byte index. That's pretty much a standard way to store bits into a multibyte array.
 

Thread Starter

AfdhalAtiffTan

Joined Nov 20, 2010
120
Hi all,
This is what I've come out with.
Apparently it does shift the phase, but with excessive distortion.
The array maximum size allowed by the compiler is somehow 96.

Rich (BB code):
while(1)
    {
        GO = 1;
        while(GO);
        
        MSB[x] = ADRESH;
        LSB[x] = ADRESL;

        x++;

        if (x>=97)
        {
            x = 0;
        }

        CCPR1L = MSB[x];
        CCP1CON = ((LSB[x]<<4)|(0xff));
    }
 

John P

Joined Oct 14, 2008
2,025
The |(0xff) part of this line
Rich (BB code):
 CCP1CON = ((LSB[x]<<4)|(0xff));
looks like a mistake. In fact loading anything to CCP1CON that you've read in via an A/D converter seems very odd.

You need to be careful about this 96 element array. The RAM banks of the PIC16F877A do have 96 bytes each, but the top 16 bytes are set up to access the same data regardless of which bank is set, so the total amount of ram is actually 80+80+80+80+16, or 336. So if any array has 96 bytes, you'd better not be using that top 16 bytes anywhere else in the program.

If you need lots of memory, you might consider one of the newer PIC16 parts like the PIC16F1459. It has many more banks, with 1024 bytes available, and it has the ability to access the RAM in linear (not banked!) mode, though maybe the compiler won't make any use of that feature and you'd have to do it yourself in assembly.
 

THE_RB

Joined Feb 11, 2008
5,438
...
If you wanted to rotate the array 36 times bitwise, instead of doing the above
36 times,and perhaps having to copy the last bit back into the front of the array each time,
you could just increment the byte index of the array 4 times (32 divided by 8)
which would effectively look to the program like rotating the array bitwise 32 times,
and then you'd still need to do the above for the remaining 4 rotations to complete the 36.
...
Thanks for explaining Art, I understand you now.

I thought we were rotating the array one bit as every new sample is added. Similar to the bucket brigade or circular buffer with pointers examples. :)
 
Top