PIC Memory Addressing

Discussion in 'Programmer's Corner' started by Tobytyke, Oct 20, 2013.

  1. Tobytyke

    Thread Starter New Member

    Oct 20, 2013

    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

    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


    ; 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.
    btfss PORTA,0 ; skip next instruction if bit=1
    goto m1
    rlf PORTB,f ; rotate port B bits to left
    goto m2
    rrf PORTB,f ; rotate port B bits to right
    ; 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
  2. MaxHeadRoom


    Jul 18, 2013
    There is good site here to get into Pic assembly http://www.winpicprog.co.uk/pic_tutorial.htm
    But I found it an advantage after learning the Picmicro on the 16F628 to graduate after to the 18F series, no page switching etc and quite a few other pluses.
    Lots of app notes on the PIC site also.
  3. MaxHeadRoom


    Jul 18, 2013
    I prefer the older traditional format for program code implementation.

    Code ( (Unknown Language)):
    3. ; '__CONFIG' directive is used to embed configuration word within .asm file.
    4. ; The lables following the directive are located in the respective .inc file.
    5. ; See data sheet for additional information on configuration word settings.
    11. w_temp        EQU     0x7E        ; variable used for context saving
    12. status_temp   EQU     0x7F        ; variable used for context saving
    18. ;**********************************************************************
    19.         ORG     0x000             ; processor reset vector
    20.         goto    Main              ; go to beginning of program
    23.         ORG     0x004             ; interrupt vector location
    24.         movwf   w_temp            ; save off current W register contents
    25.         movf    STATUS, W          ; move status register into W register
    26.         movwf    status_temp       ; save off contents of STATUS register
    28. ; isr code can go here or be located as a call subroutine elsewhere
    30.         movf    status_temp, W     ; retrieve copy of STATUS register
    31.         movwf    STATUS            ; restore pre-isr STATUS register contents
    32.         swapf   w_temp, F
    33.         swapf   w_temp, W          ; restore pre-isr W register contents
    34.         retfie                    ; return from interrupt
    37. Main:
    38.         bcf        STATUS, RP0    
    39.         movlw    b'00001011'
    40.         movwf    t1con
    41.         movlw    0x07
    42.         movwf    CMCON
    44. ; remaining code goes here
    45. Main2:
    47.         goto    Main2          ;loop forever, remove this instruction, for test only
    50. ; initialize eeprom locations
    52.         ORG    0x2100
    53.         DE    0x00, 0x01, 0x02, 0x03
    56.     END                       ; directive 'end of program'
  4. Tobytyke

    Thread Starter New Member

    Oct 20, 2013

    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

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

    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

    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
    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
    decfsz counta, f
    goto $+2
    decfsz countb, f
    goto Delay_0
    decfsz count1 ,f
    goto d1
    retlw 0x00
  5. MaxHeadRoom


    Jul 18, 2013
    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.
    The $+2 is where the $ sign represents the current address counter position with $+2 being the current position plus an increment of two locations.
  6. Art

    Distinguished Member

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

    Thread Starter New Member

    Oct 20, 2013
    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
  8. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    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).
  9. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    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.
  10. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    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. :)
  11. Art

    Distinguished Member

    Sep 10, 2007
    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: Nov 4, 2013
  12. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    Generally agreeing, just adding in a specific free compiler.

    Though on a re-read seems the OP is more comfortable (!!!) with assembler.
  13. Art

    Distinguished Member

    Sep 10, 2007
    Yes he has hit the ground running for sure
  14. MrChips


    Oct 2, 2009
    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.
  15. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    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. :)
  16. Art

    Distinguished Member

    Sep 10, 2007
    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
  17. John P

    AAC Fanatic!

    Oct 14, 2008
    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".
  18. MaxHeadRoom


    Jul 18, 2013
    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.
  19. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    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.