PIC Memory Addressing

Thread Starter

Tobytyke

Joined Oct 20, 2013
5
Hi,

I am completely new to PIC programming (I did COBOL some years ago and did some Assembly at college)

I want to design and build a small project with two PIC's

PIC 1 - Monitors 12 Digital Inputs and sends the data to PIC 2

PIC 2 - Is remote and will light a LED or LED(s) depending on the status of the 12 Digital inputs the interface has sent to PIC 1

PIC 2 meanwhile is looking for the operator pressing a button

It then detects the button press and sends the data to PIC 1

PIC 1 I guess would then perform a quick interupt routine where it sets the appropriate pin of the port corresponding to the button pressed to Ground (As the interface is looking for a Ground) before returning to the main program, monitoring the 12 Digital Inputs

So that is the grand plan

However, first I need to walk before I can run and need to learn PIC programming for dummies

I have been spending lots of time reading very helpful tutorials and I know a lot of people write in "C" or "Basic" but I want to stick to assembler because for me (at the moment) it is easier to follow

The gist of what I understand so far is this

1) The PIC has several banks of memory (depending on which one you use)

2)On powerup the PIC defaults to BANK 0

3)In order to write to the correct BANK, you must set the RP0 or RP1 flag

so far so good

4)Memory is like a set of drawers and several of them are available to store stuff in

5)In order to store something you must first put it into temporary storage AKA the W register (I think also called the accumulator)

You can then move it to another draw which will overwrite the current content of that drawer

Now it gets really confusing for me

A lot of tutorials say that memory starts at 20h (20 Hex)

In the EXAMPLE A (I assume written in Assembly) It looks like you are able to assign meaningful names to the areas of memory (I hope)

So for example it looks like they equate timera to memory location 20(hex)

Hex 20 = 32 in Decimal or 00100000 Binary

Next they equate timerb to 21(hex)

Hex 21 = 33 in Decimal or 00100001 Binary

In decimal the difference between 32 and 33 is 1 and it should also be the same in Binary eg 0000 = 0 0001 = 1

For a PIC16F873A (The one I am using) BANK 0 has 96 BYTES of GPR from address 20h to 7Fh

So from 32 to 127 in decimal (The difference is 95 although as it states 96 BYTES I guess maybe 20h starts at 0 then 21h is 1, 22h is 2 and so on up to 7F)

In EXAMPLE B it looks like again some variable names have been set up J & K

Part way through the program it looks like they move Decimal 50 to the W Register

As 50 Decimal equates to 32 HEX and 00110010 Binary this is more than just a single BIT because further down the program they then move 50 to J

My assumption at first was that as the memory locations were sequential 20h,21h,22h and that this equated to 32,33,34 decimal, that they must be 1 BIT.

But this does not make sense given that there is no way decimal 50 will fit into 1 BIT

Also the fact that the data sheet says 96 BYTES implies that each memory location (or drawer) consists of 8 BITS (as there are 8 BITS in a BYTE)

I just want to confirm my suspicion that this is true and if so ask the following

A)Is it possible to define areas of memory in advance e.g Fred is at 20h (which occupies 8 BITS), Joe is at 21h(which occupies 8 BITS) etc

B) Say you are storing some data at 20h Fred which is 8 BITS long, can you pick 1 BIT of this data out to either send somewhere else or compare against another BIT in another memory location, and if so how?

c)Lastly I read somewhere that the BANKS shared memory and that address 20h in BANK0 is the same as say 80h in BANK1

Does that mean that I only still have 96 BYTES of available storage

I ssumed it might be like this to save instructions so that if you are in BANK 1 and want to read data from memory in BANK 0, instead of having so first switch back to BANK 0 then read the data, you could say read data at address 80h

I had the idea of making up an EXCEL spreadsheet from 32 - 127 x 8 and then I have a visual idea of what is being stored where as I can use colours as an easy reference KEY


Anyway hopefully some kind person can advise and I can make a start

Thanks in anticipation
------------------------------------------------------------------
EXAMPLE A

You can then send some data to 20h
;Files for F628 start at 20h but to make programs easily
; convertible from F84A to F628, we start at 20h.

timera equ 0x20 ;general purpose timer
timerb equ 0x21 ;general purpose timer
timerc equ 0x22 ;general purpose timer
timerd equ 0x23 ;general purpose timer
-------------------------------------------------------------

EXAMPLE B

; File CHASER.ASM
; Blinks LEDs on outputs (Port B) in a rotating pattern.
; Reverses direction if port A, Bit 0, is high.
processor 16f84
include <p16f84.inc>
__config _RC_OSC & _WDT_OFF & _PWRTE_ON
; Give names to 2 memory locations (registers)
J equ H’1F’ ; J = address hex 1F
K equ H’1E’ ; K = address hex 1E
; Program
org 0 ; start at address 0
; Set Port B to output and initialize it.
movlw B’00000000’ ; w := binary 00000000
tris PORTB ; copy w to port B control reg
movlw B’00000001’ ; w := binary 00000001
movwf PORTB ; copy w to port B itself
bcf STATUS,C ; clear the carry bit
; Main loop. Check Port A, Bit 0, and rotate either left
; or right through the carry register.
mloop:
btfss PORTA,0 ; skip next instruction if bit=1
goto m1
rlf PORTB,f ; rotate port B bits to left
goto m2
m1:
rrf PORTB,f ; rotate port B bits to right
m2:
; Waste some time by executing nested loops
movlw D’50’ ; w := 50 decimal
movwf J ; J := w
jloop: movwf K ; K := w
kloop: decfsz K,f ; K := K-1, skip next if zero
goto kloop
decfsz J,f ; J := J-1, skip next if zero
goto jloop
goto mloop ; do it all again
end ; program ends here
 

MaxHeadRoom

Joined Jul 18, 2013
28,702
I prefer the older traditional format for program code implementation.
e.g.

Rich (BB code):
; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.




;***** VARIABLE DEFINITIONS
w_temp        EQU     0x7E        ; variable used for context saving 
status_temp   EQU     0x7F        ; variable used for context saving





;**********************************************************************
        ORG     0x000             ; processor reset vector
        goto    Main              ; go to beginning of program
    

        ORG     0x004             ; interrupt vector location
        movwf   w_temp            ; save off current W register contents
        movf    STATUS, W          ; move status register into W register
        movwf    status_temp       ; save off contents of STATUS register

; isr code can go here or be located as a call subroutine elsewhere

        movf    status_temp, W     ; retrieve copy of STATUS register
        movwf    STATUS            ; restore pre-isr STATUS register contents
        swapf   w_temp, F
        swapf   w_temp, W          ; restore pre-isr W register contents
        retfie                    ; return from interrupt


Main:
        bcf        STATUS, RP0    
        movlw    b'00001011'
        movwf    t1con
        movlw    0x07
        movwf    CMCON
    
; remaining code goes here
Main2:

        goto    Main2          ;loop forever, remove this instruction, for test only


; initialize eeprom locations

        ORG    0x2100
        DE    0x00, 0x01, 0x02, 0x03


    END                       ; directive 'end of program'
Max.
 

Thread Starter

Tobytyke

Joined Oct 20, 2013
5
Hi,

Thanks for the advice

I have already been to this tutorial and while very good there were a few things that were not explained in some of the program notes + I still did not fully understand the memory side of things (Don't get me wrong it is a very good site)

Probably me being thick as I have been to lots of sites and none of them have actually explained how may BITS each memory address contains

I have come across a "Cblock" command in EXAMPLE C which I looks like it defines labels at sequential addresses - This could be very useful as I only need to know the start address of the memory block !!

So again I guess that it starts at 20h for count1 then counta will be 21h etc

But part of my question was are these addresses 8 BITS

In other words can I write FF or 00 (hex) or 11111111 or 00000000 (binary) to one of these pre assigned variables then send the entire contents to the W Register or a PORT or Transmit Register (which I think are all 8 BITS)

As I am working with 12 Inputs I was going to split them in to either two banks of 6 or perhaps 3 banks of 4 would be easier

That way I am looking at a 1/2 word and dont need the first 4 BITS

So for example I poll PORT A BITS 0,1,2 & 3 looking for a change in status

Nothing happens so I write 00000000 to variable LED1 (say 20h)

I poll the PORT B BITS 0,1,2 & 3 looking for a change in status

This time BIT 0 is set so I write 00000001 to LED2 (say 21h)

Lastly I poll PORT C BITS 0,1,2 & 3

This time all of them are set so I write 00001111 to LED3 (say 22h)

As I am hoping these are 8 BIT locations I can then send the 8 BITS of LED1 to the other PIC and send the data from the receive register to LED1 area of memory on the other PIC

This hopefully makes things simpler + I can understand what I am doing

I am just using these PORTS and BITS as an example as I am aware that only certain BITS on the PORTS can be used

Re the choice of PIC - I chose this merely because of the number of OUTPUT / INPUT's I needed, but I also have the 16F628 as it is used in the tutorial you recommended and can use it to input some of the programs he posted

EXAMPLE C
----------------------------------------------------
cblock 0x20 ;start of general purpose registers
count1 ;used in delay routine
counta ;used in delay routine
countb ;used in delay routine
endc
---------------------------------------------------------------------

Incidently the bit I did not understand on Nigels Pic tutorial was the GOTO $+2 statement

The rest I think I was ok with

-----------------------------------------------------
Tutorial 1.3 - Nigel Goodwin 2002
LIST p=16F628 ;tell assembler what chip we are using
include "P16F628.inc" ;include the defaults for the chip
__config 0x3D18 ;sets the configuration settings (oscillator type etc.)
cblock 0x20 ;start of general purpose registers
count1 ;used in delay routine
counta ;used in delay routine
countb ;used in delay routine
endc

org 0x0000 ;org sets the origin, 0x0000 for the 16F628,
;this is where the program starts running
movlw 0x07
movwf CMCON ;turn comparators off (make it like a 16F84)
bsf STATUS, RP0 ;select bank 1
movlw b'00000000' ;set PortB all outputs
movwf TRISB
movwf TRISA ;set PortA all outputs
bcf STATUS, RP0 ;select bank 0
clrf PORTA
clrf PORTB ;set all outputs low
Loop
bsf PORTB, 7 ;turn on RB7 only!
call Delay ;this waits for a while!
bcf PORTB, 7 ;turn off RB7 only!.
call Delay
goto Loop ;go back and do it again
Delay movlw d'250' ;delay 250 ms (4 MHz clock)
movwf count1
d1 movlw 0xC7 ;delay 1mS
movwf counta
movlw 0x01
movwf countb
Delay_0
decfsz counta, f
goto $+2
decfsz countb, f
goto Delay_0
decfsz count1 ,f
goto d1
retlw 0x00
end
 

MaxHeadRoom

Joined Jul 18, 2013
28,702
The processor operates on an 8 bit word, outputs can be addressed in a bit fashion or in nibbles if you wish.
I would suggest studying the MPLAB user guides for details on the using programming in assembly as well as the relevant Pic manual.
Incidently the bit I did not understand on Nigels Pic tutorial was the GOTO $+2 statement
The $+2 is where the $ sign represents the current address counter position with $+2 being the current position plus an increment of two locations.
Max.
 

Art

Joined Sep 10, 2007
806
Your Qs are a bit long to easily help.
You should keep them simpler.

You can move bytes at a time, yes,
Typically, if portb (8bits) were all inputs, you'd read portb into a byte,
and shift the byte out to check all pins.
Depending on the implementation, and what the inputs are, you might
check them all with an xor mask.

Yes the compiler allows you to give labels, registers, and RAM meaningful names to Humans.
As far as I can tell, all a RISC asm compiler has to do is reference a lookup table to
convert instructions to opcodes, and replace your names for RAM, registers, and labels
with real memory locations.
 

Thread Starter

Tobytyke

Joined Oct 20, 2013
5
Hopefully I will be able to get my head round the struture and rules

Start by trying to understand simple programs from some of the tutorials and build some of the test circuits

Also following the advice, start with a simpler PIC and work up from there

I have not played with MPLAB other than starting a template from a tutorial

I need to see what it can do and also if it has a simulator to show what is happening with your program

I will start by trying to program the PIC to monitor the 12 inputs,then I thought I could then send the data to the TX register and then on to another register called RESULT

This proves to me that I can manipulate data + can get it in the right place ready to send to the 2nd PIC

Thanks for all the input, I now have a better understanding of the memory structure

I will have to read up on sending a nibble etc as it will be useful
 

THE_RB

Joined Feb 11, 2008
5,438
Since nobody has said it, I'll throw it in the mix.

Why not start with C code for the PIC? It will handle all the memory banks and a LOT of the PIC-specific weird stuff, and let you get down to programming.

It also gives you access to a lot more code examples for things that connect to PICs, and a lot more people will be able to help you with your code (compared to the people using PIC assembler).
 

ErnieM

Joined Apr 24, 2011
8,377
Why not start with C code for the PIC? It will handle all the memory banks and a LOT of the PIC-specific weird stuff, and let you get down to programming.
Microchip gives away the basic version of their compilers, why not take advantage of that?

When I started doing PICs assembly was the only way, as soon as inexpensive (now free) compilers came along I jumped at them.
 

THE_RB

Joined Feb 11, 2008
5,438
Sorry ErnieM I am not sure if you are asking me a question or generally agreeing?

I didn't specify any particular compiler. However it does seem the teething problems Tobytyke is encountering are mainly issues in assembler coding and would no longer be a problem if coding in C (as the compiler does that fussy bank switching stuff).

So it seemed worthwhile to suggest starting in C before he has invested too much time starting in assembler. :)
 

Art

Joined Sep 10, 2007
806
You won't be doing any page or bank switching for the program described.
On a 16F628, you get 64 bytes in bank0 alone, and the entire 2K chip is page0.
On the larger pics in the same family, nothing is different for the same program.
You'll only be dealing with RAM bank 0, and code page 0.
So you'd be needing to set bank 0 and page 0 once, and that's it.

It also too early to bother with interrupts.
The properly written cyclic program can check your button pushes much faster than you can
press and release a button. In fact, you will need code to prevent a button push registering many times.

The +2 is to jump the interrupt vector at startup.
 
Last edited:

MrChips

Joined Oct 2, 2009
30,824
I presume you have been going at this on your own for a while.

This site is good for help and answering your immediate questions. The turn-around time for responses is usually very short.

I suggest you start over from square one and tackle one question at a time in order to
clear any doubts in your mind.

PIC memory is organized in 8-bit chunks or bytes. Sequential memory addresses refer to memory storage of 8 bits not 1 bit.

You do not necessarily have to mentally convert from hexadecimal to decimal and vice versa. There are times when it is best to think in decimal and other times when it is best to think in binary (or hexadecimal). The distinction will become obvious with experience.

Let's take one question at a time.
 

THE_RB

Joined Feb 11, 2008
5,438
You won't be doing any page or bank switching for the program described.
On a 16F628, you get 64 bytes in bank0 alone, and the entire 2K chip is page0.
On the larger pics in the same family, nothing is different for the same program.
You'll only be dealing with RAM bank 0, and code page 0.
So you'd be needing to set bank 0 and page 0 once, and that's it.
...
That's true enough, but all the hardware registers are in different banks, which can be a major stumbling block for beginner ASM coders.

Also, if needing to use any data storage arrays etc in ASM using PCLATH requires bank selecting and also that the arrays are stored in exact known locations for indirect addressing etc, another difficult task. :)
 

Art

Joined Sep 10, 2007
806
He's still not going to have to worry about that yet (with the LED project).
I've always tried to limit myself to the first bank of ram and single code page
just to make cyclic programs faster, because you avoid switching.. as far as that goes anyhow.

I was tempted to do an example because the 16F84 example should be forgotten about,
as the chip is obsolete, but do you think I can do it in asm now, just because I could a
few years back? No! It would end up being a disassembly of a high level compiler,
optimised and commented not to look stupid.

I think it was ICprog that has the built in 16F84 family disassembler?

OP could have sorted it out and ditched this thread :D
 

John P

Joined Oct 14, 2008
2,026
Microchip is encouraging people to use the PIC16F628A, which implies that the plain 628 has itself become obsolete.

The PIC16F628A has 2 banks with 80 bytes of RAM each, a third bank with 48 bytes, and an additional 16 bytes of "wild card" RAM where the same registers are accessed regardless of which bank is set. As a great man once said, "That ought to be enough for anyone".
 

MaxHeadRoom

Joined Jul 18, 2013
28,702
Microchip is encouraging people to use the PIC16F628A, .
I know there is quite a bit more out there in assembly for the 16F series, but I am surprised that more don't take in the 18F, no bank switching like the 16F apart from all other features the 18F has.
And pricing is around the same.
Max.
 

THE_RB

Joined Feb 11, 2008
5,438
...
I was tempted to do an example because the 16F84 example should be forgotten about,
as the chip is obsolete, but do you think I can do it in asm now, just because I could a
few years back? No! It would end up being a disassembly of a high level compiler,
optimised and commented not to look stupid.

I think it was ICprog that has the built in 16F84 family disassembler?
...
Hi Art, most compilers will compile first then generate an .ASM file, then will assemble that to machine code (HEX).

If you compile a C project in your compiler, look for "assembly listing" in the "View" menu, or just look in the folder for a 'ASM or .LST file.

All the heavy lifting is done for you, the ASM will be ready to view or use. :)

It's a VERY good idea to check the ASM output of your compiler especially on small or slow PICs as with a few small changes to the way you write code you can work with the compiler to really improve the size and speed of the final ASM result.
 
Top