Large Array on PIC16 using C

Discussion in 'Embedded Systems and Microcontrollers' started by AfdhalAtiffTan, Apr 22, 2014.

  1. AfdhalAtiffTan

    Thread Starter Active Member

    Nov 20, 2010
    117
    11
    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?
     
  2. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Perhaps you should say more about what you want your application to do
     
  3. fernan82

    New Member

    Apr 19, 2014
    26
    9
    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.
     
    AfdhalAtiffTan likes this.
  4. Brownout

    Well-Known Member

    Jan 10, 2012
    2,375
    998
    Actually, you can. Look at bank "big" in the example below.


    Code ( (Unknown Language)):
    1.  
    2. DATABANK   NAME=gpr0       START=0x60              END=0xFF
    3. DATABANK   NAME=gpr1       START=0x100             END=0x1FF
    4. DATABANK   NAME=gpr2       START=0x200             END=0x2ff
    5. DATABANK   NAME=big       START=0x300             END=0x48f
    6. DATABANK   NAME=gpr4       START=0x490             END=0x4FF
    7. DATABANK   NAME=gpr5       START=0x500             END=0x5FF
    8.  
    9.  
    10. SECTION NAME=buffer_log RAM=big
    11.  
     
    Last edited: Apr 22, 2014
  5. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    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.
     
    AfdhalAtiffTan, fernan82 and Brownout like this.
  6. fernan82

    New Member

    Apr 19, 2014
    26
    9
    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.
     
    ErnieM and AfdhalAtiffTan like this.
  7. AfdhalAtiffTan

    Thread Starter Active Member

    Nov 20, 2010
    117
    11
    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. :)
     
  8. Brownout

    Well-Known Member

    Jan 10, 2012
    2,375
    998
    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.
     
    AfdhalAtiffTan and JohnInTX like this.
  9. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,692
    2,756
    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?
     
    AfdhalAtiffTan likes this.
  10. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    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.
     
    Art and AfdhalAtiffTan like this.
  11. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    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: Apr 22, 2014
    AfdhalAtiffTan likes this.
  12. Art

    Distinguished Member

    Sep 10, 2007
    785
    61
    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.

     
  13. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    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.
     
  14. AfdhalAtiffTan

    Thread Starter Active Member

    Nov 20, 2010
    117
    11
    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. :)
     
  15. fernan82

    New Member

    Apr 19, 2014
    26
    9
    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.
     
  16. Art

    Distinguished Member

    Sep 10, 2007
    785
    61
    Hi RB, If you had an array of bytes, and felt like doing this:
    Code ( (Unknown Language)):
    1.  
    2. RotateArray:                            ' bitwise rotate array right
    3.   @ rlf     _dis+50     ,F              ; ditching the first bit
    4.   @ rlf     _dis+49     ,F              ;
    5.   @ rlf     _dis+48     ,F              ;
    6.   @ rlf     _dis+47     ,F              ;
    7.   @ rlf     _dis+46     ,F              ;
    8.   @ rlf     _dis+45     ,F              ;
    9.   @ rlf     _dis+44     ,F              ;
    10.   @ rlf     _dis+43     ,F              ;
    11.   @ rlf     _dis+42     ,F              ;
    12.   @ rlf     _dis+41     ,F              ;
    13.   @ rlf     _dis+40     ,F              ;
    14.   @ rlf     _dis+39     ,F              ;
    15.   @ rlf     _dis+38     ,F              ;
    16.   @ rlf     _dis+37     ,F              ;
    17.   @ rlf     _dis+36     ,F              ;
    18.   @ rlf     _dis+35     ,F              ;
    19.   @ rlf     _dis+34     ,F              ;
    20.   @ rlf     _dis+33     ,F              ;
    21.   @ rlf     _dis+32     ,F              ;
    22.   @ rlf     _dis+31     ,F              ;
    23.   @ rlf     _dis+30     ,F              ;
    24.   @ rlf     _dis+29     ,F              ;
    25.   @ rlf     _dis+28     ,F              ;
    26.   @ rlf     _dis+27     ,F              ;
    27.   @ rlf     _dis+26     ,F              ;
    28.   @ rlf     _dis+25     ,F              ;
    29.   @ rlf     _dis+24     ,F              ;
    30.   @ rlf     _dis+23     ,F              ;
    31.   @ rlf     _dis+22     ,F              ;
    32.   @ rlf     _dis+21     ,F              ;
    33.   @ rlf     _dis+20     ,F              ;
    34.   @ rlf     _dis+19     ,F              ;
    35.   @ rlf     _dis+18     ,F              ;
    36.   @ rlf     _dis+17     ,F              ;
    37.   @ rlf     _dis+16     ,F              ;
    38.   @ rlf     _dis+15     ,F              ;
    39.   @ rlf     _dis+14     ,F              ;
    40.   @ rlf     _dis+13     ,F              ;
    41.   @ rlf     _dis+12     ,F              ;
    42.   @ rlf     _dis+11     ,F              ;
    43.   @ rlf     _dis+10     ,F              ;
    44.   @ rlf     _dis+9      ,F              ;
    45.   @ rlf     _dis+8      ,F              ;
    46.   @ rlf     _dis+7      ,F              ;
    47.   @ rlf     _dis+6      ,F              ;
    48.   @ rlf     _dis+5      ,F              ;
    49.   @ rlf     _dis+4      ,F              ;
    50.   @ rlf     _dis+3      ,F              ;
    51.   @ rlf     _dis+2      ,F              ;
    52.   @ rlf     _dis+1      ,F              ;
    53.   @ rlf     _dis+0      ,F              ;
    54.   @ bcf     _dis+50     ,0              ;clear MSB
    55. return
    56.  
    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.







     
    AfdhalAtiffTan likes this.
  17. AfdhalAtiffTan

    Thread Starter Active Member

    Nov 20, 2010
    117
    11
    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.

    Code ( (Unknown Language)):
    1.  
    2. while(1)
    3.     {
    4.         GO = 1;
    5.         while(GO);
    6.        
    7.         MSB[x] = ADRESH;
    8.         LSB[x] = ADRESL;
    9.  
    10.         x++;
    11.  
    12.         if (x>=97)
    13.         {
    14.             x = 0;
    15.         }
    16.  
    17.         CCPR1L = MSB[x];
    18.         CCP1CON = ((LSB[x]<<4)|(0xff));
    19.     }
    20.  
    [​IMG]
     
  18. John P

    AAC Fanatic!

    Oct 14, 2008
    1,634
    224
    The |(0xff) part of this line
    Code ( (Unknown Language)):
    1.  
    2.  CCP1CON = ((LSB[x]<<4)|(0xff));
    3.  
    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.
     
    AfdhalAtiffTan likes this.
  19. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    AfdhalAtiffTan likes this.
  20. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    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. :)
     
Loading...