Author Topic: PIC18F26K22 Unexpected file register behaviour  (Read 4475 times)

0 Members and 1 Guest are viewing this topic.

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
PIC18F26K22 Unexpected file register behaviour
« on: November 21, 2016, 12:37:00 pm »
Hello everybody.
I have a problem and I can't solve it myself, but tried really hard.
I am programming PIC18F26K22 in assembler using Mplab and PicKIT3.
In my program i use temporary values, which need to be stored on location 070h.
So I use this command to link RXTEMP to location 070h:

RXTEMP      EQU   070h   ; temporary USART received char register.

Everything works fine, I can put any value to RXTEMP. For example I can do "INCF  RXTEMP" and it's value increases (as expected)
But IF I run some code (which is from PIC18F26K22 datasheet) before working with 070h register, then it starts to behave unexpectedly.
The code is this:

MOVLB       0xF          ; Set BSR for banked SFRs
CLRF       PORTA                       ; Initialize PORTA by
                        ; clearing output
                        ; data latches
   
CLRF       LATA                       ; Alternate method
                        ; to clear output
                        ; data latches
   
MOVLW       0E0h               ; Configure I/O
MOVWF       ANSELA               ; for digital inputs
   
MOVLW       B'00000000'       ; Value used to
                        ; initialize data
MOVWF       TRISA          ; direction


For example, in the beginning RXTEMP value is 00h.
The command "INCF  RXTEMP" does not work (it does not increases RXTEMP value as expected).
Also I can't write any value to RXTEMP using MOVFF command. So it's value stays 00h.
But if I change RXTEMP location to any other for example 071h it starts working as expected.
And i also noticed if i remove folowing line from the initialization code above:

MOVLB       0xF          ; Set BSR for banked SFRs

Then register RXTEMP at location 070h also starts working as expected. But Then another problem happens (USARTdoes not receive characters)
So what kind of black hole is 070h location in RAM?
I can change RXTEMP location to 071h or any other it is not a problem to me, but I want to understand what is wrong here, should I avoid 070h ?

Thank You for any information.
Best regards,
 

Online AndyC_772

  • Super Contributor
  • ***
  • Posts: 4228
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #1 on: November 21, 2016, 12:54:09 pm »
http://ww1.microchip.com/downloads/en/DeviceDoc/40001412G.pdf

Section 5.4.1, Bank Select Register. I'm willing to bet you're not setting it correctly before each RAM or SFR access.
 
The following users thanked this post: rollingstone

Offline zzattack

  • Regular Contributor
  • *
  • Posts: 126
  • Country: nl
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #2 on: November 21, 2016, 01:13:44 pm »
I believe 0x70 is still in access RAM so it's not as much a matter of incorrect BSR as selecting the correct mode for the instruction.

Code: [Select]
INCF RXTEMP,F,ACCESS

^should work, but it is very important you are aware of banked registers and common RAM!
 
The following users thanked this post: rollingstone

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #3 on: November 21, 2016, 06:52:50 pm »
Quote
Section 5.4.1, Bank Select Register. I'm willing to bet you're not setting it correctly before each RAM or SFR access.
Thank you,  I'm really not setting it correctly. Tried to put "MOVLB 0x0" command and it started working as expected. :)

Quote
I believe 0x70 is still in access RAM
Well it should be in access RAM, but debugger shows something different.
Quote
so it's not as much a matter of incorrect BSR as selecting the correct mode for the instruction.
INCF RXTEMP,F,ACCESS
^should work, but it is very important you are aware of banked registers and common RAM!
It still doesn't work. But it does work when I use "MOVLB 0x0" command before, and "INCF RXTEMP" starts to work, as well as "INCF   RXTEMP,1,1" ... strange... ???
So I guess I should rewrite all my code and add "MOVLB" instructions everywhere?
 

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #4 on: November 21, 2016, 07:01:51 pm »
Quote
Well it should be in access RAM, but debugger shows something different.
Correction: if I understood datasheet corectly then 070h is not in access ram.
 

Online Andy Watson

  • Super Contributor
  • ***
  • Posts: 2084
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #5 on: November 21, 2016, 08:04:01 pm »
Then register RXTEMP at location 070h also starts working as expected. But Then another problem happens (USARTdoes not receive characters)
So what kind of black hole is 070h location in RAM?
Are you using interrupts ?
 

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #6 on: November 21, 2016, 09:30:34 pm »
Yes, i am
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #7 on: November 21, 2016, 11:01:17 pm »
i remove folowing line from the initialization code above:

MOVLB       0xF          ; Set BSR for banked SFRs

Then register RXTEMP at location 070h also starts working as expected. But Then another problem happens (USARTdoes not receive characters)
There is a conflict between this code and your UART routines. It may be due to the UART code not setting BSR, or trying to use the same memory location for some other purpose (can't tell without seeing all your code).

In any case, assigning RAM locations with EQU is not good practice. You should use CBLOCK and ENDC to allocate RAM space, that way each variable automatically gets its own address and there is less chance of a conflict between different parts of your program. For example:-
Code: [Select]
; initialization
  CBLOCK 0x70         ; my variables start at 0x70
      RXTEMP          ; RXTEMP at 0x70 (1 byte)
      TMP16:2         ; TMP16 at 0x71 (2 bytes)
  ENDC                ; next CBLOCK starts at 0x73
      .
      .
      .
; UART variables
  CBLOCK              ; continues from last CBLOCK
      UART_VAR        ; UART_VAR at 0x73 (1 byte)
      UART_BUFFER:8   ; buffer at 0x74 (8 bytes)
  ENDC

Instead of MOVLB use the directive BANKSEL {SFR name or bank#}, which avoids having to remember which bank an SFR is in and is more portable between different PICs.

RAM below 0x60 can be accessed directly by instructions that have the 'ACCESS' option, so you should allocate your variables in this area if possible. SFRs between 0x60 and 0xFF are also in the 'access' bank (unfortunately this does not include certain UART registers). The less you fiddle with the BSR the more efficient your code will be. However in assembler it is easy to lose track of which bank you are in, so for safety it is best to set it before any SFR access except when you need the tightest possible code.
 
Avoid using 'magic' numbers, and write your code so that it can be easily modified without the risk of making silly mistakes. For example, instead of:-
Code: [Select]
MOVLW       0E0h             ; Configure I/O
MOVWF       ANSELA           ; for digital inputs

MOVLW       B'00100100'      ; Value used to
                             ; initialize data
MOVWF       TRISA            ; direction

do this:-
Code: [Select]
#define LED_1  RA0           ; pin 2   Red LED output
#define LED_2  RA1           ; pin 3   Green LED output
#define SW_1   RA2           ; pin 4   switch input
;              RA3           ; pin 5   (unused output)
;              RA4           ; pin 6   (unused output)
#define ADC_IN RA5           ; pin 7   battery voltage input

MOVLW   (1<<ADC_IN)          ; bit = 1 for analog input, else digital
BANKSEL ANSELA
MOVWF   ANSELA               ; set PORTA analog inputs

MOVLW   (1<<SW1)|(1<<ADC_IN) ; bit = 1 for input, else output
BANKSEL TRISA
MOVWF   TRISA                ; set PORTA digital I/O


It may seem like a lot more work initially, but will make your program a lot easier to expand and maintain. You can easily reallocate pin functions without having to hunt down and change a bunch of 'magic' numbers, and the code is much easier to read and understand.
 
 



« Last Edit: November 21, 2016, 11:08:50 pm by Bruce Abbott »
 
The following users thanked this post: rollingstone

Offline rollingstoneTopic starter

  • Contributor
  • Posts: 19
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #8 on: November 28, 2016, 12:06:31 pm »
Quote
There is a conflict between this code and your UART routines.
Yes, it looks like it was. I used BANKSEL before each variable and SFR and then everything worked fine.
Thank you for such valuable information, I changed my code according to Your suggestions. However I would like to ask one more question. Sorry if question is too long but I am still confused and can't sort it myself.
If I am declaring variable like this:
Code: [Select]
UART_BUFFER:8   ; buffer at 0x74 (8 bytes)Is it possible to access this variable (each byte) somehow in simple way? for example not using file select registers and doing table reads and writes?
But if not, If I must use
Code: [Select]
LFSR FSR, F command to load address and
Code: [Select]
TBLRD*+ command to read or command
Code: [Select]
PLUSW0 to write, then how can my program automatically can get this variable star and end address before doing LFSR? The point is that I want to declare for ex.
Code: [Select]
UART_buffer:32 variable using CBLOCK directive and then be able to access it in program automatically without having to LFSR manually. For now I do it like this:
Code: [Select]
RAM_WRT_CHR ; put received char to ram
BANKSEL RXINDEX ; select bank
MOVFF RXINDEX, WREG ; load RXINDEX value to W
LFSR    FSR0, 090h ; load UART buffer adress
BANKSEL RXTEMP_BYTE ; select bank
MOVFF    RXTEMP_BYTE, PLUSW0 ; write received char from temp reg. to location 90h + W (W is offset)
MOVFF    RXTEMP_BYTE, TXREG1 ; echo char back
BANKSEL RXINDEX ; select bank
INCF    RXINDEX ; increase UART buffer index
And here I must load UART buffer beginning address manually (090h). If I decide to change it's location address in RAM, then I must change it everywhere in program where it is being accessed. :(
« Last Edit: November 28, 2016, 01:47:21 pm by rollingstone »
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: PIC18F26K22 Unexpected file register behaviour
« Reply #9 on: November 28, 2016, 05:18:32 pm »
Is it possible to access this variable (each byte) somehow in simple way? for example not using file select registers and doing table reads and writes?
Table read/write is only for program memory (ROM).

Quote
I want to declare for ex.
Code: [Select]
UART_buffer:32 variable using CBLOCK directive and then be able to access it in program automatically without having to LFSR manually.
It's assembly code, so of course you have to load the FSR 'manually'. But only once. 

Quote
If I decide to change it's location address in RAM, then I must change it everywhere in program where it is being accessed. :(
That's what symbolic names are for! Don't hard-code the address, instead do this:-
Code: [Select]
    CLBOCK
       UART_BUFFER:32
    ENDC   

    LFSR  FSR0,UART_BUFFER
    .
    .
    LFSR  FSR1,UART_BUFFER
Now the assembler 'automatically' knows the address of the buffer, and you don't have to change it everywhere in your program.

Quote
For now I do it like this:
That code should work OK, but it's not the most efficient way to do it. If you don't need to do arithmetic on the index then you can just post-increment the FSR itself. Of course you still need to make sure it stays within the buffer RAM area, so you can either check for the buffer end by comparing it with UART_BUFFER+32, or for the ultimate brevity and speed do this:-
Code: [Select]
    CLBOCK 0x90             ; must be aligned on 32 byte boundary with bit 5 clear!
       UART_BUFFER:32       ; 32 byte UART receive buffer   
    ENDC   

; init FSR0
    LFSR  FSR0,UART_BUFFER
   
   
; receive character
    MOVFF  RCREG1,POSTINC0  ; receive character, increment pointer
    BCF    FSR0,5           ; force pointer to stay inside 0x90~0xAF
     
To save a few cycles I copy the received byte directly from the UART into the buffer. The buffer is aligned on a 32 byte boundary, so to stop the FSR from going beyond it I simply stop bit 5 from changing. Resetting bit 5 forces the FSR back to 0x90 when it increments  to 0xB0. A circular buffer in just two instructions!

 
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf