pic18f, question regarding data memory bank

Thread Starter

bug13

Joined Feb 13, 2012
2,002
Hi guys

In the following codes, it says:
Due to the bank limitation in PIC18 MCU architecture, the size of
CONNECTION_ENTRY must be dividable by 256 in case the array is across
the bank.
What exactly does it mean? According to my count,the size of __CONNECTION_ENTRY is 14 bytes, how is that dividable by 256?

Thanks guys!

PS: the following code is part of demo code from Microchip MAL library, I can link in the full code if required.
PS2: I am coming from AVR, but new in PIC

Code:
   /***************************************************************************
     * Peer Device Information in Connection Table
     *
     *      This structure contains device information about the peer device
     *      of current node. It is the element structure for connection table.
     *      Due to the bank limitation in PIC18 MCU architecture, the size of
     *      CONNECTION_ENTRY must be dividable by 256 in case the array is across
     *      the bank. In this case, the user need to make sure that there is no
     *      problem
     **************************************************************************/
    typedef struct __CONNECTION_ENTRY
    {
        #if !defined(PROTOCOL_P2P)
            API_UINT16_UNION    PANID;                            //2 bytes
            API_UINT16_UNION    AltAddress;                      //2 bytes
        #endif
        uint8_t        Address[MY_ADDRESS_LENGTH];     // 8 bytes
     
        CONNECTION_STATUS status;                                //1 byte
     
        #if ADDITIONAL_NODE_ID_SIZE > 0
            uint8_t        PeerInfo[ADDITIONAL_NODE_ID_SIZE];  // 1 byte
        #endif
    } CONNECTION_ENTRY;
 

ErnieM

Joined Apr 24, 2011
8,377
__CONNECTION_ENTRY is just one element of the CONNECTION_ENTRY Table.

How many 14 byte elements in the whole table?
 

JohnInTX

Joined Jun 26, 2012
4,787
They probably mean that the size of each element (struct in this case) is an integral factor of 256. The compiler tries to use direct addressing i.e. within the same RAM bank as a default for compact code. That means it doesn't want to span banks to access a variable. Structs and arrays can easily get big enough to make this a problem.

If the compound type is a integral factor of 256, it can pack nicely into banks and the compiler can generate bank switching and direct addressing for each complete element without having part of one element in one bank and another part in another. If you imagine what the standard helper routines (that access elements of a struct for example) would look like, you can see why an individual element spanning banks would be a problem.

The attached text file is from an old PICC-18 FAQ which describes the limitations of that compiler and the banked architecture that I found when I too ran into the dreaded 'cant find space for psect.. problem'.

Good Luck.
 

Attachments

Last edited:

Thread Starter

bug13

Joined Feb 13, 2012
2,002
They probably mean that the size of each element (struct in this case) is an integral factor of 256. The compiler tries to use direct addressing i.e. within the same RAM bank as a default for compact code. That means it doesn't want to span banks to access a variable. Structs and arrays can easily get big enough to make this a problem.

If the compound type is a integral factor of 256, it can pack nicely into banks and the compiler can generate bank switching and direct addressing for each complete element without having part of one element in one bank and another part in another. If you imagine what the standard helper routines (that access elements of a struct for example) would look like, you can see why an individual element spanning banks would be a problem.

The attached text file is from an old PICC-18 FAQ which describes the limitations of that compiler and the banked architecture that I found when I too ran into the dreaded 'cant find space for psect.. problem'.

Good Luck.
A couple of questions:
  • What are bss and data psect?
From what I can understand from the FAQ is, if I do these, the compiler will not compile:
Code:
//can't do these
uint8_t foo1[256];
uint8_t foo2[1];
but if I do these, it will be ok?
Code:
//ok to do?
uint8_t foo1[300];
uint8_t foo2[1];
 

ErnieM

Joined Apr 24, 2011
8,377
AFAIK how large data segments are handles is compiler specific. I recall the C18 compiler needing assistance by manually editing the link script to set aside a large (>256) RAM block, then only being able to access it thru a pointer in the code.

YMMV with other compilers.
 

Thread Starter

bug13

Joined Feb 13, 2012
2,002
Interesting, it doesn't seem to stop me doing anything like that. I declared the following 2 different variables and compile them separately. I have no error message.

I am using XC8 - free mode, pic18f46j50

Here are my 2 tests:

Before my foo and foo2:
Memory Summary:
Program space used 687Ah ( 26746) of FFF8h bytes ( 40.8%)
Data space used 38Dh ( 909) of EC0h bytes ( 24.1%)
Configuration bits used 4h ( 4) of 4h words (100.0%)
Data stack space used 0h ( 0) of 57Ah bytes ( 0.0%)
Now add something greater that 256 bytes;
Code:
uint8_t foo[256];
uint8_t foo2;
Memory Summary:
Program space used 688Eh ( 26766) of FFF8h bytes ( 40.8%)
Data space used 48Dh ( 1165) of EC0h bytes ( 30.9%)
Configuration bits used 4h ( 4) of 4h words (100.0%)
Data stack space used 0h ( 0) of 4C0h bytes ( 0.0%)
New add something even bigger.
Code:
uint8_t foo[1024]
uint8_t foo2;
Memory Summary:
Program space used 688Eh ( 26766) of FFF8h bytes ( 40.8%)
Data space used 78Dh ( 1933) of EC0h bytes ( 51.2%)
Configuration bits used 4h ( 4) of 4h words (100.0%)
Data stack space used 0h ( 0) of 4C0h bytes ( 0.0%)
 

JohnInTX

Joined Jun 26, 2012
4,787
Your two code segments allocate variables bigger that 256 bytes from the get-go compiling a source file yes? ..so the compiler puts them into a psect called bigbss which uses various extended addressing methods. The FAQs described the case when the first variable allocated was less than 256 bytes (an int for example) which started things out in bss which uses direct (banked) addressing. When this happens, if the total bytes needed by the variables in a single file >=256, direct addressing as generated by the compiler won't work and the link fails. The solution in the FAQs (and what I used) was to declare arrays of struct that needed >256 bytes first to force the compiler to use extended addressing then declare any small values from there - or split into several source files.

I don't know if XC8 still has those issues. It may since XC8 derives from HiTech and presumably the new MAL libraries are recently written and still call out bank limitations.

BTW: psect, bss from the HiTech manual (too lazy to type..)

2.2 Psects and the linker
This tutorial explains how the compiler breaks up the code and data objects in a C program into different
parts and then how the linker is instructed to position these into the ROM and RAM on the target.
2.2.1 Psects
As the code generator progresses it generates an assembler file for each C source file that is compiled.
The contents of these assembly files include different sections: some containing assembler instructions
that represent the C source; others contain assembler directives that reserve space for variables in RAM;
others containing ROM-based constants that have been defined in the C source; and others which hold
data for special objects such as variables to be placed in non-volatile areas, interrupt vectors and
configuration words used by the processor. Since there can be more than one input source file there will
be similar sections of assembler spread over multiple assembler files which need to be grouped together
after all the code generation is complete.
These different sections of assembler need to be grouped in special ways: It makes sense to have all the
initialised data values together in contiguous blocks so they can be copied to RAM in one block move
rather than having them scattered in-between sections of code; the same applies to uninitialised global
objects which have to be allocated a space which is then cleared before the program starts; some code
or objects have to be positioned in certain areas of memory to conform to requirements in the processor’s
addressing capability; and at times the user needs to be able to position code or data at specific absolute
addresses to meet special software requirements. The code generator must therefore include information
which indicates how the different assembler sections should be handled and positioned by the linker later
in the compilation process.
The method used by the HI-TECH compiler to group and position different parts of a program is to place
all assembler instructions and directives into individual, relocatable sections. These sections of a
program are known as psects - short for program sections. The linker is then passed a series of options
which indicate the memory that is available on the target system and how all the psects in the program
should be positioned in this memory space.
Uninitialised objects are placed in psects whose name is "bss" or a name based on "bss". Again, rbss
would indicate uninitialised objects that are near. The PIC compiler uses names like rbss_0, where the
digit is a bank number. The abreviation "bss" stands for block started by symbol and was a assembler
pseudo-op used in IBM systems back in the days when computers were coal-fired. The continued usage
of this term is still appropriate as there are some similarities in the way these schemes worked.
 
Top