# Indirect Data Addressing: When done?

Status
Not open for further replies.

#### jpanhalt

##### Well-Known Member
I am using the PIC12F509. Its FSR register is only 5 bits. My data bytes start at 0x07 and go to 0x16 (in this example). As I cycle through the data, I increment FSR and need to know when it reaches 0x16.

I can do it like this:
Code:
btfss	fsr,4
goto	Byte_plus ;a sequence that increments FSR and loads next data byte
btfss	fsr,2
goto	Byte_plus
btfss	fsr,1
goto	Byte_plus
call  	delays	; sets a flash rate
goto	set_FSR	;starts data loading again
But going at it bit wise is cumbersom. So, I tried:

Code:
bcf	status,z
movlw	b'10110'
xorwf	fsr,w
btfss	status,z	;looking for zero
goto 	Byte_plus
call	delays
goto	set_FSR
The second method doesn't work at all. Its designed advantage is that I can simply make the xorwf with the last register location I want loaded and not have to go at it bit by bit as in the first method.

What is wrong with the second method? Is there another alternative that would allow me to do the same thing?

Thanks,

John

#### Diver300

##### Well-Known Member
Bits 7 and 6 of FSR are not used for addressing, but they read as 1s, so you need to either:-

read FSR and "AND" the result with 0b00111111, then compare with 0b00010110

or

compare FSR with 0b11010110 which is simpler, but relies on the FSR reading like that.

#### jpanhalt

##### Well-Known Member
@Diver300

It worked! Used xorwf with B'11010110' I will have to remember not to just ignore those bits that aren't discussed. Thanks.

John

#### Diver300

##### Well-Known Member
It's outlined in section 4.9.1 of the data sheet.

I've done a lot of work with 16 bit micros, so I am used to working with registers that often have spare bits.

#### jpanhalt

##### Well-Known Member
You got me there.

There are a lot of words in those datasheets that I skimmed over at one time, but don't seem to remember them when I need to. I am still a beginner, and this is my first project since 2008. Nevertheless, getting stuck like this provides a lesson I won't soon forget.

John

#### jpanhalt

##### Well-Known Member
Stumped Again

This is close to working code to print 32 characters on a Parallax serial LCD using a PIC12F509 as mentioned at the start of this thread. The complete code is attached. I commented out all the delays so I could step through it easily.

The intended message is:
HAPPY BABY BABY
123456789abcdefg

The actual printed message is:
HAPPY BABY BABY
123456789\bc\\fg

I am pretty much a novice with debugging, but I was able to watch the data registers as I stepped through the code. I did not catch which step affected the lower case "a". I was able to locate the steps that changed the "d" and "e" characters. The registers change in Ser_Loop at the two steps indicated with asterisks.

Code:
Ser_Loop
rrf		W_Byte,f
btfss	status,c
bcf		B_Out
** 	btfsc	status,c
bsf		B_Out
;	call	dly_417
decfsz	B_count,f
**	goto	Ser_Loop
bsf		B_out		;Stop bit
;	call	dly_417		;stop bit
At the first asterisk, register 0x3D changes, and at the second, register 0x3C changes. Those registers contain "Byte_1D" and "Byte_1C," respectively, which correspond to characters "e" and "d" in the intended message.

Now, if the screen is refreshed by clearing CTS with a push button, "b" and "c" are replaced with slashes, so the second line reads:

123456789\\\\\fg

The fact that the last two characters remain OK really stumps me.

I realize this is a lengthy question, and I don't really expect anyone to put the time in to resolve it, if the problem is subtle. However, is there a way in MPLab to look more deeply into why only those characters in the data memory registers are affected, but not the rest of the line?

Regards,

John

View attachment Parallax LCD MSG generator.asm

#### jpanhalt

##### Well-Known Member
I think I know the cause, but not the cure. I noted that the affected display bytes were in registers 0x39, 0x3A, 0x3C, and 0x3D. And note that the delay constants went to 0x19, 0x1A, and 0x1B; registers used in the sending loops were B_count at 0x1C and W_byte at 0x1D.

As a test, I commented out d3 and used that register for d2. That fixed a part of the problem that was related to using the only delay that needed d3.

So, it seems to be a memory bank problem. Instead of going to 0x1C, it is going to 0x3C when working with data in that bank (bank1), which is explained somewhat in the datasheet.

I will try forcing it to always go to bank0 for the counts, after lunch. Other suggestions would be much appreciated.

John

UPDATE

If I just make the second line 12 characters and reassign some of the equates, it works great. I am now working with toggling FSR <5> to extend the second line to 16 characters.
John

Last edited:

#### Mike - K8LH

##### Well-Known Member
What's the serial baud rate Jon? 2400 baud?

Did you know you can send 'constant' characters (they don't have to be in RAM memory)?

Code:
        movlw   'H'             ;
call    PutSer          ;
movlw   'a'             ;
call    PutSer          ;
movlw   'p'             ;
call    PutSer          ;
movlw   'p'             ;
call    PutSer          ;
movlw   'y'             ;
call    PutSer          ;
movlw   ' '             ;
call    PutSer          ;

Last edited:

#### jpanhalt

##### Well-Known Member
Hi Mike,

Yes, the baud is now 2400, which was set awhile ago when I thought some of my problems might be in the timings. I haven't bothered to change it back to 9600. I am using an external crystal for now, and 9600 actually works too.

More to your point, I did not know I could just call constant ascii characters like that. I will have to try it. Where is it described?

John

#### Nigel Goodwin

##### Super Moderator
More to your point, I did not know I could just call constant ascii characters like that. I will have to try it. Where is it described?
There's nothing really to be 'described' - it's just a crude, nasty, brute strength method (it's OK for very short strings, but wasteful for large ones).

It's really as simple as programming gets - some of my tutorials do it that way.

#### Diver300

##### Well-Known Member
Being able to avoid banking is why I try to avoid the less capable PICs. They certainly get difficult when you are trying to use most of the memory.

In the 12F509, the commands only have space for a 5 bit register address, so they can only address 0x00 - 0x1F. So a last bit, that makes a command address 0x20 - 0x3F instead of 0x00 - 0x1f, is needed. That happens to be bit 5 of FSR. So manipulating FSR will affect subsequent instructions if bit 5 is changed.

Notes:-
0x00 - 0x0F and 0x20 - 0x2f map to the same registers, so for any command that accesses these, bit 5 of FSR does not matter.

Many PICs have the bank bits in the status register. Some have more than 256 bytes of memory so that some of the banking bits are used in conjunction with the FSR register

There is a page bit to allow access to the top of memory. That needs to be set to access the top half of memory with call or goto instructions.

#### Diver300

##### Well-Known Member
For fixed numbers you can use a lookup table.

The basic form is:-

Code:
lookup_table
mov		index_reg, w
retlw	0x48		;H
retlw	0x41		;A
retlw	0x50		;P
retlw	0x50		;P
retlw	0x59		;Y
You have to make sure that you don't ever have index_reg larger than the length of the table (so it has to be 0 - 4 in this case)

Also you have to keep it with one 256 line long section of memory.

There are various routines that allow larger lookup tables or ones that straddle pages.

Last edited:

#### jpanhalt

##### Well-Known Member
@Mike,K8LH
Now I understand, having looked at: http://www.microchip.com/forums/tm.aspx?m=291733&settheme=Mobile
I did not know such characters could be used as literals.

@Diver
Thanks for the advice. Actually, I have used the 12F509 before for a few projects such as driving servos and as timers. In fact, I have only done a few projects.

In this case, my long-term goal is a wireless, remote inclinometer. I will be using the 12F683 or similar chip with A/D, or maybe even a 16F with more pins, but I needed some experience in serial data communication first. I had absolutely no experience in that before. The 12F509 was just a simple learning device, and I have learned loads. I think I will give it another day until I am comfortable with its banking system and see if I can solve the problem presented here with something other than brute force before moving to the meat of the project.

Finally, the program comments reference Nigel's tutorial, and the serial loop is from that tutorial. Thanks to all of you.

John

#### Mike - K8LH

##### Well-Known Member
Hi Jon,

Sorry, don't know where to point you for examples. Nigel's tutorials maybe?

Here's an unsolicited (and untested) example that might be worth studying.

Have fun...

Cheerful regards, Mike

Code:
;******************************************************************
;                                                                 *
;   Filename: 12F509 Serial.asm                                   *
;     Author: Mike McLaren, K8LH                                  *
;       Date: 04-Jan-12                                           *
;                                                                 *
;   bit banged serial example                                     *
;                                                                 *
;      MPLab: 8.80    (tabs=8)                                    *
;      MPAsm: 5.43                                                *
;                                                                 *
;******************************************************************

include "p12f509.inc"

errorlevel -302, -224
list st=off

__CONFIG   _MCLRE_ON & _CP_OFF & _WDT_OFF & _XT_OSC

;--< variables >---------------------------------------------------

delaylo equ     0x07            ;
delayhi equ     0x08            ;
txbyte  equ     0x09            ;
bitctr  equ     0x0A            ;

;--< defines >-----------------------------------------------------

CTS     equ     0               ; GP0 = serial CTS
TXD     equ     1               ; GP1 = serial TXD

;******************************************************************
;  DelayCy() subsystem macro generates five instructions          *
;******************************************************************

clock   equ     4               ; 4, 8, 12, 16, or 20 MHz clock
usecs   equ     clock/4         ; cycles/microsecond multiplier
msecs   equ     clock/4*1000    ; cycles/millisecond multiplier

DelayCy macro   delay           ; 12..327690 cycle range
movlw   high((delay-12)/5)+1
movwf   delayhi
movlw   low ((delay-12)/5)+1
movwf   delaylo
call    uDelay-((delay-12)%5)
endm

;******************************************************************
;                                                                 *
;******************************************************************

org     0x000
Init
movwf   OSCCAL          ; factory calibration value       |B0
movlw   b'001001'       ;                                 |B0
tris    GPIO            ; GP0 & GP3 inputs                |B0
movlw   b'10000000'     ;                                 |B0
option                  ; enable weak pull-ups            |B0
;
DelayCy(100*msecs)      ; delay 100 msecs                 |B0
;
;  turn on LCD and print string
;
movlw   0x18            ;                                 |B0
call    Put232          ; turn on display                 |B0
DelayCy(5*msecs)        ; delay 5 msecs                   |B0
movlw   'H'             ;                                 |B0
call    Put232          ;                                 |B0
movlw   'e'             ;                                 |B0
call    Put232          ;                                 |B0
movlw   'l'             ;                                 |B0
call    Put232          ;                                 |B0
movlw   'l'             ;                                 |B0
call    Put232          ;                                 |B0
movlw   'o'             ;                                 |B0
call    Put232          ;                                 |B0

goto    \$               ; loop forever                    |B0

;******************************************************************
;  Put232 (9600 baud)                                             *
;******************************************************************

Put232
movwf   txbyte          ; save Tx data byte               |B0
movlw   10              ; 1 start + 8 data + 1 stop bit   |B0
movwf   bitctr          ; setup bit counter               |B0
clrc                    ; C = 0 (start bit)               |B0
goto    SendBit         ; send start bit                  |B0
NextBit
DelayCy(104*usecs-10)   ; 104 usecs minus 10 cycles       |B0
setc                    ; always shift in a 'stop' bit    |B0
rrf     txbyte,F        ; put data bit in Carry           |B0
SendBit
movf    GPIO,W          ; read port                       |B0
iorlw   1<<TXD          ; set TXD pin bit to 1            |B0
skpc                    ; if data bit = 1 skip, else      |B0
xorlw   1<<TXD          ; set TXD pin bit to 0            |B0
movwf   GPIO            ; precise update intervals        |B0
decfsz  bitctr,F        ; done? yes, skip, else           |B0
goto    NextBit         ; send next bit                   |B0
retlw   0               ;

;******************************************************************
;  DelayCy() subsystem "uDelay" subroutine                        *
;******************************************************************

nop                     ; entry for (delay-12)%5 == 4     |B0
nop                     ; entry for (delay-12)%5 == 3     |B0
nop                     ; entry for (delay-12)%5 == 2     |B0
nop                     ; entry for (delay-12)%5 == 1     |B0
uDelay  decf    delaylo,F       ; 5 cycle loop                    |B0
skpnz                   ;                                 |B0
decfsz  delayhi,F       ;                                 |B0
goto    uDelay          ;                                 |B0
retlw   0               ;                                 |B0

;******************************************************************
end

Last edited:

#### Diver300

##### Well-Known Member
When sensing things like tilt or temperature and connecting to a microcontroller, I've generally found it easier to use sensors that output in a serial form. It means that you don't have to worry about any analogue conditioning at all.

I used a MXC6202G which has an I2C output. It works very well, but you have to use high value pull up resistors as the digital output is only rated to 100µA and the tilt sensor is less accurate if you ignore that.

I have also used LM95071 temperature sensors, and the DS1820 range.

Last edited:

#### jpanhalt

##### Well-Known Member
I am using the Memsic MXD2020E, not because of the cost, but because I scavenged it from a Sears Craftsman digital level and wanted the challenge. I also find its heat-based technology clever. It probably does not need temperature correction for just a leveling device, but it is a good excuse to learn how to do it.

One of my early experiments was to receive and send serial data. That was relatively easy to do for just 8 bytes. For my application, however, I felt I would need to store more data, manipulate it, and then send in packets. That is why I got into this whole memory bank thing. I'm using a pair of XBees for the wireless link.

John

#### Diver300

##### Well-Known Member
The MXC6202G which has an I2C output, uses the same heat-based technology as the MXD2020E.

I prefer the I2C signal, as capturing mark-space ratios can be quite tricky. You can run into timing issues if you are trying to do other time-critical things at the same time.

I would certainly suggest a PIC with more memory, so you have fewer issues with banking. The 12F629 gives you a lot more memory and there will be far less need to use banking. It is pin-compatible with the 12F509.

The 12F509 uses 12 bit instructions, while the 12F629 uses 14 bit instructions. The longer instructions allow for a larger addressing field, so all the memory can be accessed without banking. The 12F509 is only really made as a reprogrammable version of the very old 12CE509 and it is really not worth saving a few cents to use it.

#### jpanhalt

##### Well-Known Member
Update

@Mike,

The program almost worked from the start. I needed to read up on the pseudo-instructions (black ops?) to begin to figure it out. On the oscilloscope, the start bit was showing as a very short blip, so I added another delay right after the "clrc" instruction to get the result shown.

As a hint to other newbies, I assembled and then printed a Disassembly Listing to convert the pseudo-instructions to the ones that were more familiar.

@Diver,

Thanks for the suggestions. I am going to look into getting that chip, but it was not at Newark, DigiKey, or Mouser. I am waiting for a call back from Memsic.

Regards, John

#### Attachments

• 5.8 KB Views: 82

#### Mike - K8LH

##### Well-Known Member
@Mike,

The program almost worked from the start. I needed to read up on the pseudo-instructions (black ops?) to begin to figure it out. On the oscilloscope, the start bit was showing as a very short blip, so I added another delay right after the "clrc" instruction to get the result shown.
Sorry about that John... I wonder if you need a small delay for the internal oscillator to stabilize? Also, I wonder if we should add a pair of missing instructions in the init section to set the GPIO output latches to 1<<TXD to put the TXD pin in the '1' (stop) state before we start sending serial data?

Cheerful regards, Mike

Code:
Init
movwf   OSCCAL          ; factory calibration value       |B0
movlw   1<<TXD          ;                                 |B0
movwf   GPIO            ; set TXD output to '1' (stop)    |B0
movlw   b'001001'       ;                                 |B0
tris    GPIO            ; GP0 & GP3 inputs                |B0
movlw   b'10000000'     ;                                 |B0
option                  ; enable GP0 & GP3 weak pull-ups  |B0

Last edited:
Status
Not open for further replies.