How to copy a 8 byte array from non banked ram to banked ram

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to copy a 8 byte array from non banked ram to banked ram

1,843 Views
AndersJ
Contributor IV

Which is the preferred and most efficent way to copy a byte array

from non banked ram to banked, and vice versa?

 

Thanks,

Anders J

Labels (1)
Tags (1)
0 Kudos
16 Replies

1,279 Views
kef
Specialist I

It helps when you specify what MCU are you using. Also, what memory model is used?

 

Assuming you are talking about S12X and banked or small memory models, I think it is the best to set up RPAGE and use library defined memcpy or strcpy routines. memcpy is CW libs is well optimised. So

 

#pragma DATA_SEG __RPAGE_SEG PAGED_RAM
char bankedstr[100];
#pragma DATA_SEG DEFAULT

 

char normalstr[100];

 

 

{

   // copy from nonbanked to bankedstr

   RPAGE = (unsigned long)&bankedstr / 0x10000;
   (void)strcpy(bankedstr, "sfjkhjhkjhjkhsjfhjdhhfjhhskjhdfjhskjh");

   // copy from banked to nonbankedstr

   RPAGE = (unsigned long)&bankedstr / 0x10000;
   (void)strcpy(normalstr, bankedstr);

}

 

You may need to suppress C1860 warning: pointer conversion: possible loss of data.

 

0 Kudos

1,279 Views
AndersJ
Contributor IV

Sorry about being unclear about the environment.

I use the S12X and the banked memory model.

 

Do I need to save the current RPAGE and restore it after the copy procedure?

 

Is the 0x10000 "define"d somewhere so magic numbers can be avoided,

and hopefully improving portability to another MCU?

 

Thanks for your assistance, much appreciated.

AJ

 

 

 

 

 

 

 

 

0 Kudos

1,279 Views
kef
Specialist I

It looks like compiler isn't assuming that RPAGE is preserved over function calls. Try disassembling following code

 

#pragma DATA_SEG __RPAGE_SEG PAGED_RAM
char bankedstr[100];
char uu;
int cc;
#pragma DATA_SEG DEFAULT

void foo(void)

{

   uu = 5;  // RPAGE is set up before write to uu

  RPAGE = (unsigned long)&bankedstr / 0x10000;
  (void)strcpy(bankedstr, "sfjkhjhkjhjkhsjfhjdhhfjhhskjhdfjhskjh");

 

  cc = 9; // RPAGE is set up before write to cc
  uu = 3; // RPAGE is NOT set up before write to uu
}

 

 

Banked RAM pointers are of the form 0xXXYYYY, where XX is RPAGE and YYYY is offset. Dividing by / 0x10000 allows to calculate RPAGE of object in R-banked RAM. Inline assembly has predefined macro for this. PAGE(object). I don't know what is equivalent C macro for this, so you see this magic 0x10000.

Any way it won't be portable to other architectures, unless they are using the same banking schemes.

0 Kudos

1,279 Views
AndersJ
Contributor IV

I have written this segment definition in *.prm:

  SEG_BANKED_RAM = READ_WRITE 0xF01000 TO 0xF01FFF;

My RAM allocation error message is now gone.

BUT,

it that the correct way to do it?

 

If I want more 4K pages how are those definitions made, and how many can I have?

 

In TN238 page 4 it this described as follows:

  RAM_FB  = READ_WRITE 0xFB1000 to 0xFB1FFF

  RAM_FC = etc

To me this implies that 16 4K pages RAM_F0 to RAM_FF is available. Is this true?

Or is it RAM_F0 to RAM_FE = 15 4K pages?

 

What would an entire list of pages look like?

How should they be named to follow the best conventions?

 

0 Kudos

1,279 Views
kef
Specialist I

Your questions are surprising me. Haven't you ever tried to create new empty project using project wizard? By default you should see all banked segments defined in PRM file and combined to one logical placement called PAGED_RAM. If you need some special settings in your PRM, then I think you should edit project wizard crated PRM file.

 

Be careful about banked RAM and standard startup file. Since you are allocating some variables in banked RAM, you should add -D__FAR_DATA to compiler switches, else startup file most likely will initialize wrong RAM segments.

 

Also, since you are going to use more than just one RAM page, you need to change compiler option "Assume objects are in same page for" from default  setting "all objects in same non default segment" to "never for different objects". Either do right mouse clicks or add -PSegObj to compiler switches string. Here example demonstrating compiler behaviour:

 

#pragma DATA_SEG __RPAGE_SEG PAGED_RAM
int d[2048];  // d is big enough to fill 4k RAM page, so linker
int g[5];        //    will allocate g in different RAM page
#pragma DATA_SEG DEFAULT

void main(void) {
   d[0] = 4;
   d[3] = 4;
   g[3] = 5;
 

  d[7] = 4;

   d[8] = 4;
  
   g[0] = 5;
   g[2] = 5;
}

 

Try compiling this with and without  -PSegObj switch. Without switch, instead of write to g[i], you will see d[i] updated.

 

 

You may safely take benefits of faster operation without -PSegObj . But you need to edit PRM file to define separate placement records to allocate objects in specific RAM pages instead of allocating in collection of RAM paged (PAGED_RAM):

 

PLACEMENT

  PAGED_RAM_FC INTO RAM_FC;

  PAGED_RAM_FD INTO RAM_FD;

 ...

END

 

Then you could start allocating variables first to PAGED_RAM_FC until linker tells you there's no room in PAGED_RAM_FC. Then you could start filling PAGED_RAM_FD etc. Compiler will handle all accesses fine without -PSegObj.

You decide what's better for you. There's a number of ways to use paged RAM on S12X. For example for better portability at a cost of slower operation you may switch to using large memory model and forget about pages.

0 Kudos

1,279 Views
AndersJ
Contributor IV

Yes Kef, I have created empty projects before.

I created one a few minutes ago, in response to CrasyCat, and attached the newly created prm file,

to show that banked ram segments are NOT created.

 

Had they been, I'm sure I would not have been asking so many questions.

 

I must be doing something wrong when I create new projects.

Any sugggestion that explain where I go wrong is most welcome.

 

Thanks for your patience.

 

 

 

 

 

 

0 Kudos

1,279 Views
kef
Specialist I

Hm. I've no idea. Project wizard does right files at least for S12XD512 and S12XEP100. Which derivative are you using?

0 Kudos

1,279 Views
AndersJ
Contributor IV

I use S12XEP100

 

Procedure

* Select MC9S12XEP100

* Single core

* C

* Yes (Processor Expert)

* No (Lint)

* ANSI

* None (Floating point)

* Banked

* P&E Multilink

 

But,

saying NO to Processor Expert creates an entirely different prm file,

including the PAGED RAM segments.

 

I guess PE is the explananation.

Why does PE create such a different prm file?

 

Do you have any comment to my RPAGE statement usage above,

where I say that the RPAGE statement seems unneccessary?

 

 

 

 

 

 

 

0 Kudos

1,279 Views
kef
Specialist I

Ah, PE. I'm not using it.

 

Regarding necessity of RPAGE= before memcpy. It is necessary. RPAGE is 0xFD by default out of reset. I guess this matched page of your data, right? Memcpy/strcpy in banked and small memory models take only nonbanked 16bit pointers, they can't handle switching of RPAGE and you need to switch them by hand or write your own routines, that will take some kind of far data pointer.

0 Kudos

1,279 Views
AndersJ
Contributor IV

My original data was in non banked 0x2nnn.

According to the now correctly generated prm, RAM 0x2000 would be in PAGE_FE, not FD.

If this matches, I still do not understand this.

 

 

 

 

 

0 Kudos

1,279 Views
kef
Specialist I

0x2000 is not banked RAM, which doesn't require anything smart like RPAGE switching. You original request was about banked RAM, isn't it?

0 Kudos

1,279 Views
CrasyCat
Specialist III

Hello

 

You can take a look at the generic .prm file for your MCU.

 

Open a Windows Explorer and browse to {Install}\lib\hc12c\prm. You should find a .prm file for your derivative there.

Additionally the generic .prm file will also indicate which of the RAM pages are equivalent to the non-banked RAM area.

 

You should be able to add the necessary RAM pages to the .prm generated by Processor Expert in the CPU component inspector view in tab "Build options".

 

CrasyCat

0 Kudos

1,279 Views
AndersJ
Contributor IV

Hi,

 

It would be nice if PE could handle it all,

to avoid needing to keep track of what is lost when PE is used to regenerate the .prm.

 

If I add RAM pages in PE, will PE also define the new segment name(s)

and the new placement entries?

 

Anders J

 

 

 

 

0 Kudos

1,279 Views
CrasyCat
Specialist III

Hello

 

If you add a new memory area in PE Build Options Tab you will have to specify the memory area name, qualifier as well as the start and end address.

 

In order to place some sections in the newly created segment you need to set generate PRM file to no and update the .prm file manually.

 

CrasyCat

0 Kudos

1,279 Views
CrasyCat
Specialist III

Hello

 

Number of RAM pages available depends on the MCU you are targeting.

Please refer to the MCU reference manual for more info on the number of RAM page available.

 

Otherwise create a project for your MCU using the project wizard. 

The generated .prm file should define all the RAM page memory areas.

 

CrasyCat

0 Kudos

1,279 Views
AndersJ
Contributor IV

The only ram segment created by the wizard is: "RAM           = READ_WRITE    0x2000 TO   0x3FFF;"

I see no banked ram segments.

Please give me a hint me on what I am doing wrong.

The prm-file is attached.

 

In addition to that I have tested the RPAGE statement above before doing a memcpy.

To eliminate the possible loss of data warning I typecasted the result of the division

to a unsigned char before assigning it to RPAGE.

Is there anything wrong with that?

 

This works fine,

BUT,

it works equally well WITHOUT the RPAGE statement.

Am I just lucky or does the compiler silently handle this?

 

0 Kudos