Searching \ for '[PIC] Allocating large buffer in linear memory are' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: piclist.com/techref/microchip/memory.htm?key=memory
Search entire site for: 'Allocating large buffer in linear memory are'.

Exact match. Not showing close matches.
PICList Thread
'[PIC] Allocating large buffer in linear memory are'
2012\07\24@141718 by Jan-Erik Soderholm

face picon face
Hi.

I'm loooking at starting up my first 16F1xxx project.
It will be the 16F1938 (on the "PICkit 28-pin demo board").

Now, these PICs has something called "linear memory" where
GPR from the (up to) 32 banks are combined into one linear
area without holes or jumps. Fine so far. But how do I "use"
this area? I know of the usual UDATA and UDATA_SHR but I
expected something like UDATA_LIN to specificaly allocate
memory from that area.

Normal UDATA allocation will not cross banks, right?

Maybe using UDATA together with a hardcoded adress in the
linear area ? But that defeets the automatic allocation.

Anyone who has used this memory area for (e.g.) buffers
larger then one single bank?

Jan-Erik.

2012\07\24@153931 by Brendan Gillatt

flavicon
face
Hi,

IIRC (and it's been a while since I've done this) you set up a new
section in the linker script as large as you would like. You then use
a pragma directive in the C code to put your large array into that new
huge linker section. C18 will handle the rest.

Regards,
Brendan

On 24 July 2012 19:17, Jan-Erik Soderholm <spam_OUTjan-erik.soderholmTakeThisOuTspamtelia.com> wrote:
{Quote hidden}

>

2012\07\24@155726 by Byron Jeff

flavicon
face
Jan-Eric,

I think you may have a perception problem with this memory space. The key
element to understand that the space is only accessible via the FSR
registers. There is no direct addressing mechanism.

BAJ

On Tue, Jul 24, 2012 at 08:17:17PM +0200, Jan-Erik Soderholm wrote:
{Quote hidden}

> -

2012\07\24@172058 by Jan-Erik Soderholm

face picon face
Yes, I do know how this works on PIC *18* !
And C18 doesn't work against PIC16, AFAIK.

Jan-Erik.

Brendan Gillatt wrote 2012-07-24 21:39:
{Quote hidden}

>> -

2012\07\24@183723 by Jan-Erik Soderholm

face picon face
Hi.

> I think you may have a perception problem with this memory space.

No, I have not. :-)
I know very well that it is a remapping of regular GPR space.

My "problem" was how to allocate a continous 100 byte
buffer accessable as one part via FSR's in the linear area.
Without hard coded addresses, of course. I thought that
calculating the "real" addresses by hand and allocate them
directly from the banks seemed a bit silly.

Anyway, I created a project and did some experiments.

I first checked the LKR for the 16F1938. Anyone can open their
own copy of 16f1938_g.lkrm but here are the critical parts:

-----------------------------------------------------------------
DATABANK  NAME=gpr0  START=0x20  END=0x6F  SHADOW=linear0:0x2000
DATABANK  NAME=gpr1  START=0xA0  END=0xEF  SHADOW=linear0:0x2050
....
DATABANK  NAME=gpr11 START=0x5A0 END=0x5EF SHADOW=linear0:0x2370
....
....
SECTION   NAME=LINEAR0 RAM=linear0         // Linear Memory
-----------------------------------------------------------------

Note the "shadow=" parts and the new special LINEAR0 section !

Now, "linear0" can by used directly by UDATA for allocations :

-----------------------------------------------------------------
; Allocate one "normal" GPR...
GPR_VAR1        UDATA
MYVAR1          RES        1

; Allocate two buffers 100 and 200 bytes in "linear" memory.
LINEAR0         UDATA
mybuff1         RES        d'100'
mybuff2         RES        d'200'

; An additional GPR.
GPR_VAR2        UDATA
MYVAR2          RES        1
-----------------------------------------------------------------

The two mybuffx symbols are created as expected (from the MAP file):

-----------------------------------------------------------------
 MYBUFF1   0x002000       data     static D:\DATA\proj\CDS\CDS.ASM
 MYBUFF2   0x002064       data     static D:\DATA\proj\CDS\CDS.ASM
-----------------------------------------------------------------

This writes "ABCD" to the first four positions of mybuff2 :

-----------------------------------------------------------------
    movlw   high    mybuff2
    movwf   fsr0h
    movlw   low     mybuff2
    movwf   fsr0l

; FSR0 now points to h'2064'.

    movlw   a'A'
    movwi   indf0++
    movlw   a'B'
    movwi   indf0++
    movlw   a'C'
    movwi   indf0++
    movlw   a'D'
    movwi   indf0++
-----------------------------------------------------------------

SIMulating the code above shows an "ABCD" in the expected place.
And the regular variables MYVAR1 and MYVAR2 are allocated
after the two buffers in bank 4, just as one want.

Then it is "only" the usual handling of the FSR including, of
course, the new automatic post/pre dec/inc of the FSR...

Nice ! :-)

Jan-Erik.



Byron Jeff wrote 2012-07-24 21:57:
{Quote hidden}

>> -

2012\07\25@021842 by Brendan Gillatt

flavicon
face
Oops I missed that bit!

Brendan

On 24 July 2012 22:20, Jan-Erik Soderholm <jan-erik.soderholmspamKILLspamtelia.com> wrote:
{Quote hidden}

>>> --

2012\07\25@071913 by Byron Jeff

flavicon
face
I have definitely learned something today.

Question: is the SHADOW important below because of the mapping between the
linear memory and the gprs? How is it different than having a single
extra linear line with a start of 0x2000 and end of 0x23EF?

I started to write an example and I thought I had it. Then I looked at your
example and I am confused again. The only reason to have shadow is so that
the linker understands that linear memory and the gpr memory overlap. So
when allocating space in each they won't try to occupy the same actual
space. But it doesn't happen below, so I'm confused. Here are the
allocations:

{Quote hidden}

Now my expectation is because of the SHADOW directives, the linker should
understand that MYVAR1 and MYVAR2 are allocated from the same memory pool
as mybuff1 and mybuff2. You show the addresses of mybuff1 and mybuff2 as
0x2000 and 0x2064. But what are the addresses of MYVAR1 and MYVAR2? Are
they allocated after the buffers? Or are they overlayed?

My projects are small enough that I just haven't taken the time really
learn how to build relocatable modules and link them together. Maybe it's
finally time to do so.

BAJ

On Wed, Jul 25, 2012 at 12:37:23AM +0200, Jan-Erik Soderholm wrote:
{Quote hidden}

2012\07\25@074030 by Jan-Erik Soderholm

face picon face


Byron Jeff wrote 2012-07-25 13:19:
{Quote hidden}

They are h'1dd' and h'1dc", which is after mybuffer2, but expressed
as regular banked memory addresses. Seems just fine. :-)

 MYBUFF1  0x002000  data  static D:\DATA\proj\CDS\CDS.ASM
 MYBUFF2  0x002064  data  static D:\DATA\proj\CDS\CDS.ASM
 MYVAR1   0x0001dd  data  static D:\DATA\proj\CDS\CDS.ASM
 MYVAR2   0x0001dc  data  static D:\DATA\proj\CDS\CDS.ASM

Nad yes, it seems as MPASM keeps tracks of allocations
over banked/linear memory. Perfect ! :-)

This is actualy better then I thought before testing it.

The two buffers of 100 and 200 bytes are allocated from bank0
(first 80 bytes of mybuffer1), bank1 (last 20 bytes of mybuffer1
and first 60 bytes from mybuffer2), bank2 (byte 61 to 140 of
mybufer2) and bank3 (last 60 bytes of mybuffr2).

Remaining allocations are done after that.

A "BANKSEL MYVAR1" will generate a "MOVLB h'03'" to switch to bank3
(fourth bank).


{Quote hidden}

2012\07\25@080418 by Jan-Erik Soderholm

face picon face
Another small demo.
In this case copying a smal 6 character string from
flash to start of "mybuff2".

The flash data is created with :

txt_sect    code
txt_tab1    dt      "HIJKLM"


This created 6 RETLW instructions, but the indexed access only
reads the "low" part of the 14-bit program word anyway...

From the MAP file :

 TXT_TAB1 0x00001b    program     static D:\DATA\proj\CDS\CDS.ASM
....
 MYBUFF2  0x002064       data     static D:\DATA\proj\CDS\CDS.ASM


Then to copy this 6-byte constant from flash to mybuff2:


    movlw   high    mybuff2
    movwf   fsr0h
    movlw   low     mybuff2
    movwf   fsr0l
; FSR0 loaded with h'2064'

    movlw   high    txt_tab1
    movwf   fsr1h
    movlw   low     txt_tab1
    movwf   fsr1l
; FSR1 loaded with h'801B'

    moviw   indf1++
    movwi   indf0++
    moviw   indf1++
    movwi   indf0++
    moviw   indf1++
    movwi   indf0++
    moviw   indf1++
    movwi   indf0++
    moviw   indf1++
    movwi   indf0++
    moviw   indf1++
    movwi   indf0++

Note that the highest bit of FSR1 is set to indicate that
the address ppoints to flash memory.

Could just as well use a decsfz-loop of course...

Jan-Erik.


Jan-Erik Soderholm


wrote 2012-07-25 13:40:
{Quote hidden}

>

2012\07\25@103834 by Jan-Erik Soderholm

face picon face
A few additional notes... :-)

Byron Jeff wrote 2012-07-25 13:19:
> I have definitely learned something today.
>
> Question: is the SHADOW important...

I noticed that the "shadow" param in the LKR files is
*not* documented (yet ?) in the usual documentation
"ASSEMBLER/LINKER/LIBRARIAN USER’S GUIDE" (33014K.PDF).

> below because of the mapping between the
> linear memory and the gprs? How is it different than having a single
> extra linear line with a start of 0x2000 and end of 0x23EF?

I guess that it is the "shadow" parameter in the LKR that enables
MPASM/MPLINK to "know" that these two memory areas are the same.

Jan-Erik


'[PIC] Allocating large buffer in linear memory are'
2012\08\17@094539 by Jan-Erik Soderholm
face picon face
Hi again...

I've done a few additional work on the 16F1xxx.

In this case it is a simple demo-app to drive a
64x8 LED matrix display (the one that is built from
8x8 LED matrises and usualy shows "rolling text" in
a shop window or similar.

I have a 384 byte buffer allocated in linear memory
(3 display lengths and red/green bits, 64x3x2=384).

The first 128 positions in the buffer are then used
for the actual display. The display is dynamic and has
to be multiplexed continues. One new row of 128 bits
will be written each 1 ms.

To get rolling text this 384 byte buffer has to be "shifted"
2 positions regulary. I now have that code ready, and it
shifts all 384 bytes two positions (since there are two
bits per dot) in 126 us on a 16F1938 @ 32MHz INTOSC).
That is OK and well within the multiplex timer of 1 ms.

I made a quick check using a 16F88x and it would take
something like 440 us (@ 20 MHz) if I'm right.

Now, a 17F88x can't have a continues buffer of that
size anyway... :-) But the rellative performane would be
similar for doing the same operation on a smaller buffer.

Jan-Erik.


The actual code as it looks right now is :

---------------------------------------------------------
; Rotate 384 byte buffer 2 steps to the left.

; Load FSR0 with start adress of buffer.
    movlw   high    out_buff
    movwf   fsr0h
    movlw   low     out_buff
    movwf   fsr0l

; Number of loops.
; 5 bytes are moved each loop, 76x5 = 380.
; 2 bytes are saved for later restore = 382.
; 2 bytes are moved before of the loop = 384.

    movlw   d'76'
    movwf   loop_cnt

; Save the first two positions for later restore ("rotated").
    moviw   [fsr0]      ; First pos...
    movwf   roll_tmp1
    moviw   1[fsr0]     ; Second pos...
    movwf   roll_tmp2

; Move two positions before the loop to get an "even" loop.
    moviw   2[fsr0]     ; Move FSR0+2 => W
    movwi   fsr0++      ; Move W => FSR0 and incr FSR0
    moviw   2[fsr0]
    movwi   fsr0++

; Now loop through the rest of the buffer.
; Move 5 bytes each time to save on looping logic.

roll_loop
    moviw   2[fsr0]
    movwi   fsr0++
    moviw   2[fsr0]
    movwi   fsr0++
    moviw   2[fsr0]
    movwi   fsr0++
    moviw   2[fsr0]
    movwi   fsr0++
    moviw   2[fsr0]
    movwi   fsr0++
    decfsz  loop_cnt, f     ; All of buffer?
    goto    roll_loop       ; No, continue.

    movf    roll_tmp1, w    ; Restore the two saved bytes
    movwi   [fsr0]          ; At the end of buffer, the
    movf    roll_tmp2, w    ; "rotate" part of it...
    movwi   1[fsr0]

; 384 byte buffer shifted 2 pos to the left!
---------------------------------------------------------


It is also easy to initialize the RAM buffer from data from
flash at startup. Two positions are copied each loop to keep
the loop counter within 8 bits.

---------------------------------------------------------
; Copy buffer data from flash to GPR.
; Load FSR0 with adress of GPR buffer

    movlw   high    out_buff
    movwf   fsr0h
    movlw   low     out_buff
    movwf   fsr0l

; Load FSR1 with adress of flash data
; txt_tab1 points to a number of "dt" statements
; defining 384 bytes (as RETLW instructions, but
; MOVIW only reads the low 8 bits anyway...).

    movlw   high    txt_tab1
    movwf   fsr1h
    movlw   low     txt_tab1
    movwf   fsr1l

; Number of loops, 192x2 = 384.
    movlw   d'192'
    movwf   loop_cnt

copy_buff_loop
    moviw   indf1++
    nop                 ; Reading from flash takes one extra cyc.
    movwi   indf0++
    moviw   indf1++
    nop
    movwi   indf0++

    decfsz  loop_cnt
    goto    copy_buff_loop

; Ready!

---------------------------------------------------------

Note that the processor automaticly switches between flash
and GPR depending on the adress on FSR0/FSR1 (bit 15).

---------------------------------------------------------


Jan-Erik Soderholm wrote 2012-07-25 16:38:
{Quote hidden}

2012\08\17@104214 by Harold Hallikainen

face
flavicon
face
Sorry to jump into this thread late, but the comment about shifting a 384
bit buffer two bits caught my attention. Would it be possible to shift a
pointer into the buffer by two bits instead? That'd be a whole lot faster!
>From what I understand (and this may not be correct), the idea is to send
stuff to a multiplexed LED array. An FSR could point to the byte to be
sent, and a byte of RAM could serve as a bitmask to determine which bits
to send. I see this as a bit like a FIFO buffer. When we take a byte out
of a FIFO, we don't shift all the remaining bytes over to fill the now
empty space. We just move the output pointer.

Good luck!

Harold



-- FCC Rules Updated Daily at http://www.hallikainen.com - Advertising
opportunities available!
Not sent from an iPhone

2012\08\17@152156 by Walter Banks

picon face


Jan-Erik Soderholm wrote:

{Quote hidden}

This is another late answer. When we implimentated support
for the extended 14bit ISA we assumed we had linear memory
only and then used the optimizer to sort out how to access
the banked memory or linear memory based on generated
code and execution time.

This approach solved most of the problems of address holes.

Regards


Walter Banks
Byte Craft Limited

2012\08\17@162016 by Jan-Erik Soderholm

face picon face
Harold Hallikainen wrote 2012-08-17 16:42:

> Sorry to jump into this thread late, but the comment about shifting a 384
> bit buffer two bits caught my attention. Would it be possible to shift a
> pointer into the buffer by two bits instead? That'd be a whole lot faster!

A 384 *byte* buffer rotated 2 *bytes*.

Yes, I put priority in the "other" part of the code, the part
that does the multiplexing to the display. That code runs 100
times for each rotate of the buffer.

That is, TMR0 interrups with 1 ms intervalls and that is
when the multiplexing runs. Then, at 100 ms intervalls, the
buffer is roteted.

I decided that the multiplexing routing could be written more
efficent if it always sent the first 128 bytes of the 384
byte buffer using fixed addresses, no need to save/restore
of the pointerns.

And there is also extra complexity when the "moving window"
"wraps around", there have to be an address check in the middle
of the multiplexing routine to check for "end-of-buffer". That
part will run 128 times each 1 ms and I want as little
code as possible in there.

It will be enough to have 128 data bits sent to the DATA pin
and the CLOCK pin toggled for each pin each 1 ms interrupt.


If I can think out a clever way of checking for end-of-buffer.
Or maybe some calculations to calculate the number of bytes
until end-of-buffer and then reset the FSR register and
read the rest of the bytes from the start-of-buffer.

Anyway, what my code did, was to show the use of the new
indexed addressing modes together with the linear memory.

This is nothing serious, just to put some "text" on a
display I will sell on an auction site... :-)

But yes, you have a valid point!
And I'll give it a second though...


>>From what I understand (and this may not be correct), the idea is to send
> stuff to a multiplexed LED array. An FSR could point to the byte to be
> sent, and a byte of RAM could serve as a bitmask to determine which bits
> to send. I see this as a bit like a FIFO buffer. When we take a byte out
> of a FIFO, we don't shift all the remaining bytes over to fill the now
> empty space. We just move the output pointer.
>

The display only have storage (shift registers) for *one*
64 pixel row (128 red/green bits) at a time. You send
128 bits for the topmost row (as fast as possible) and
enable the ROW_ENABLE, COL_ENABLE, then wait a little and
then send 128 bits for row 2 and so on. By having a 1 ms
interrupt, the frequency of the individual LED dots will
be around 100 Hz, which is just on the edge for beeing OK
without flickering.

There is also a 3 bit ROW_SEL input that select which row
of the eight possible that will be lit. That also have
to be updated together with each 128 bit load.

Another guy write a PIC program some years ago for this
display using a dsPIC30 at full speed (in C). I would like
to see if I could do it with one of the PIC161xxx models.
I think so. :-)

Jan-Erik.



> Good luck!
>
> Harold
>
>

More... (looser matching)
- Last day of these posts
- In 2012 , 2013 only
- Today
- New search...