The first time my PIC30F code reads a word from Data EEPROM, it reads 0xFFFF instead of the data actually in EEPROM. It reads fine afterward.
After a bad read, I checked W1 and it does have the correct address
There are no words in data EEPROM with a value of 0xFFFF
I checked the supply: it's 5.13 V
If I break right before the table read instruction, and step through it, it woks fine
I know that NVMADRU and NVMADR are not involved in reading, but I checked them, and their value doesn't change between good reads and bad reads
It's a dsPIC30F5011
I checked the Errata, and did not find any reference to such issue
I am working through the debug function of MPLAB 8, with a PICkit II
I am working through the debug function of MPLAB 8, with a PICkit II: I reset, then run, and it fails
If I place the code in a tight loop until the value is correct, and counting the number of iterations, I see that it takes 2339 times through the loop until it reads correctly
EEPROM read code:
_ReadEEWord:
;--------------------------------------------------------------------------------
; Read a word from Data EEPROM
; Entry W0 Word address relative to the start of Data EEPROM
; Exit W0 Word at that location
; Uses W1, Table pointer
;--------------------------------------------------------------------------------
; Start address of Data EEPROM
#define DATAEE_START 0x7FFC00
; Setup pointer to EEPROM memory
mov #0x7F,W1 ; Set the table pointer
mov W1,TBLPAG ; to the page with the EEPROM
add W0,W0,W0 ; Convert the word address to a byte address
mov #0xFC00,W1 ; Add the start of EEPROM
add W1,W0,W1 ; to the address
nop
nop
nop
; Return the EEPROM data
tblrdl [W1],W0 ; Read the EEPROM data
nop
nop
nop
return
Any suggestions of what may be causing that?
SOLVED
The documentation doesn't say so, but, before you can read data EEPROM, you must wait for any previous EEPROM operations to be done.
You can do it in one of these ways:
1) In C:
#include <libpic30.h> // Includes EEPROM utilities
_wait_eedata(); // Wait for the erase to be done
2) In C, no lib import
while (NVMCONbits.WR);
3) In assembly:
btsc NVMCON,#15 ; If busy (WR bit s set)
bra $-2 ; Go back and wait
Related
How do I resolve obtaining the wrong value in the W-register after a MOVF operation?
I am debugging a code which builds & programs successfully, but does not have the desired result when powered up as part of the circuit and I have noticed that the working register does not contain the right value after a MOVF operation, whilst debugging.
If the value that is being copied to the W-reg is manually written in during debugging, then the code functions as it should.
The following images, I believe, illustrate the my issue quite well.
1. Port definition.
2. LEDportA value of 0x02 is to be moved to the W-reg.
3. After the operation, W-reg contains 0x00, instead of 0x02.
4. Final image shows that LEDportA is the same as LATA, as it is cleared after the "clrf LEDportA instruction.
I am totally bewildered as to what could be causing it and any insights or advice that anyone can provide will be very much appreciated.
Please note that the PIC MCU in use is the PIC16F1829.
Since you don't provide enough information like PIC model you are using and the rest of the code, as far as I see, your problem is because of wrong bank selection. Your TempC register is located 0x70 in bank 0, and the LATA register is located at 0x10C bank 2 in memory. Thus when you attempt to read the LATA, actually you read the corresponding 0C addres location in bank0. You have to switch the correct bank before you attempt to read or write from any register in RAM. Check the code snippet that has right way to access to the registers. You can switch to a bank either using the BANKSEL directive which is more convenient for programmers or loading a bank value to the BSR (Bank Select Register).
UpdateDisplay:
BANKSEL LEDportA ; Switch to LEDportA bank before any access
MOVF LEDportA, w
andlw 0x0f
BANKSEL TempC ; Switch to TempC bank before any access
movwf TempC
bsf TempC, 4
rrf TempC, F
btfss STATUS, C
bcf TempC, 3
btfsc TempC, 0
....
The code must output 'ccb',but output only 'c', LOOP is done only one time, i have calibrated in TD, but why LOOP is done only one time?
I THINK THAT I MUST TO DECREMENT STRING_LENGTH, SO I WROTE
DEC STRING_LENGTH
BUT IT NOT WORK, SO I WROTE LIKE THAT
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
I KNOW WHAT ARE YOU THINKING RIGHT NOW, THAT IS SO INCORRECT, YOU ARE RIGHT)))
I CAN USE C++, BUT I WANT TO DO IT ONLY IN ASSEMBLY,
DOSSEG
.MODEL SMALL
.STACK 200H
.DATA
STRING DB 'cScbd$'
STRING_LENGTH EQU $-STRING
STRING1 DB STRING_LENGTH DUP (?) , '$'
.CODE
MOV AX,#DATA
MOV DS,AX
XOR SI,SI
XOR DI,DI
MOV CX,STRING_LENGTH
S:
MOV BL,STRING[DI]
AND STRING[DI],01111100B
CMP STRING[DI],01100000B
JNE L1
MOV AL,BL
MOV STRING1[SI],AL
ADD SI,2
L1:
ADD DI,2
LOOP S
MOV DL,STRING1
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
END
In Turbo Debugger (TD.EXE) the F8 "F8 step" will execute the loop completely, until the cx becomes zero (you can even create infinite loop by updating cx back to some value, preventing it from reaching the 1 -> 0 step).
To get "single-step" out of the loop instruction, use the F7 "F7 trace" - that will cause the cx to go from 6 to 5, and the code pointer will follow the jump back on the start of the loop.
About some other issues of your code:
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
sp is not general purpose register, don't use it for calculation like this. Whenever some instruction does use stack implicitly (push, pop, call, ret, ...), the values are being written and read in memory area addressed by the ss:sp register pair, so by manipulating the sp value you are modifying the current "stack".
Also in 16 bit x86 real mode all the interrupts (keyboard, timer, ...), when they occur, the current state of flag register and code address is stored into stack, before giving the control to the interrupt handler code, which usually will push additional values to the stack, so whatever is in memory on addresses below current ss:sp is not safe in 16 bit x86 real mode, and the memory content keeps "randomly" changing there by all the interrupts being executed meanwhile (the TD.EXE itself does use part of this stack memory after every single step).
For arithmetic use other registers, not sp. Once you will know enough about "stack", you will understand what kind of sp manipulation is common and why (like sub sp,40 at beginning of function which needs additional "local" memory space), and how to restore stack back into expected state.
One more thing about that:
MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP
The STRING_LENGTH is defined by EQU, which makes it compile time constant, and only compile time. It's not "variable" (memory allocation), contrary to the things like someLabel dw 1345, which cause the assembler to emit two bytes with values 0100_0001B, 0000_0101B (when read as 16 bit word in little-endian way, that's value 1345 encoded), and the first byte address has symbolic name someLabel, which can be used in further instructions, like dec word ptr [someLabel] to decrement that value in memory from 1345 to 1344 during runtime.
But EQU is different, it assigns the symbol STRING_LENGTH final value, like 14.
So your code can be read as:
mov sp,14 ; makes almost sense, (practically destroys stack setup)
dec sp ; still valid
mov 14,sp ; doesn't make any sense, constant can't be destination for MOV
As beginner in PIC programming under ASM I do not understand why in the examples a register is cleared prior to setting a new value. In an actual running programm this is not done and everything works fine.
Example with CRLF
CRLF PORTB ; Init PORTB by clearing output data latches
BSF STATUS, RP0 ; Select Bank 1
MOVLW 0xCF ; Value used to initialize data direction
MOVWF TRISB ; Set RB<3:0> as inputs
; RB<5-4> as outputs
; RB <7-6> as inputs
Example without CRLF
BSF STATUS, RP0 ; Select Bank 1
MOVLW 0xCF ; Value used to initialize data direction
MOVWF TRISB ; Set RB<3:0> as inputs
; RB<5-4> as outputs
; RB <7-6> as inputs
Both parts work fine so why to clear?
A common pitfall with microchip controllers is writing to the PORTx registers. You should never do this. If you want to change the state of output pins, you should write directly to the output latches (LATx). This is because writing to the PORTx registers involves a read/modify/write process that can cause issues if pins are changing state at the same time. Use PORTx only to read the values of input pins (and, of course, output pins).
As has been mentioned in comments, the TRISx registers set the direction of pins (0= output, 1=input). Note that this is opposite to the settings for some other processors (e.g. Motorola HC12) which use 0=input, 1=output.
I just start to program IA-32 assemble and boot loader and I can't understand one command: mov [bootdrv], dl.
dl is the low 8 bits of data register, but I dont know what is [bootdrv]. Is it a variable or something? How could a register be placed in [bootdrv]?
start:
mov ax,0x7c0 ; BIOS puts us at 0:07C00h, so set DS accordinly
mov ds,ax ; Therefore, we don't have to add 07C00h to all our data
mov [bootdrv], dl ; quickly save what drive we booted from
This is the beginning 3 line of a boot loader and [bootdrv] just appear without any definition, I couldn't understand.
Any information would be helpful and appreciated, thank you!
[bootdrv] is a specification of an absolute memory address. The code:
mov [bootdrv], dl
copies the contents of the 8-bit DL register into a byte in memory, at the address resulting of multiplying the current value of DS by 16, then add the value bootdrv. bootdrv itself is a label, which a value that represents where in the current data segment is the memory position located.
On the other hand, the symbol bootdrv must be defined somewhere. Otherwise, the assembler will stop with a "symbol not defined" error. Maybe it's defined past the code (assemblers do two passes through the source code in order to get all symbols so they can be used even if they are defined after the code sequence that uses them). Maybe it's in a separate .INC file.
mov [bootdrv], dl indicates a segment:offset memory access. In the previous instruction, you configured the Data Segment register with an address, so the mov [bootdrv], dl instruction writes to the segment:offset address 0x7c0:bootdrv, whatever bootdrv might be.
I have a PE file and I try to disassemble it in order to get it's instructions. However I noticed that .text segment contains not only instructions but also some data (I used IDA to notice that). Here's the example:
.text:004037E4 jmp ds:__CxxFrameHandler3
.text:004037EA ; [00000006 BYTES: COLLAPSED FUNCTION _CxxThrowException. PRESS KEYPAD "+" TO EXPAND]
.text:004037F0 ;
.text:004037F0 mov ecx, [ebp-10h]
.text:004037F3 jmp ds:??1exception#std##UAE#XZ ; std::exception::~exception(void)
.text:004037F3 ;
.text:004037F9 byte_4037F9 db 8Bh, 54h, 24h ; DATA XREF: sub_401440+2o
.text:004037FC dd 0F4428D08h, 33F04A8Bh, 0F6B2E8C8h, 0C4B8FFFFh, 0E9004047h
.text:004037FC dd 0FFFFFFD0h, 3 dup(0CCCCCCCCh), 0E904458Bh, 0FFFFD9B8h
.text:00403828 dword_403828 dd 824548Bh, 8BFC428Dh, 0C833F84Ah, 0FFF683E8h, 47F0B8FFh
.text:00403828 ; DATA XREF: sub_4010D0+2o
.text:00403828 ; .text:00401162o
.text:00403828 dd 0A1E90040h, 0CCFFFFFFh, 3 dup(0CCCCCCCCh), 50E0458Dh
.text:00403828 dd 0FFD907E8h, 458DC3FFh, 0D97EE9E0h
.text:00403860 db 2 dup(0FFh)
.text:00403862 word_403862 dw 548Bh
How can I distinct such data from instructions? My solution to this problem was to find simply the first instruction (enter address) and visit each instruction and all called functions. Unfortunatelly it occured that there are some blocks of code which are not directly called but their addresses are in .rdata segment among some data and I have no idea how distinct valid instruction addresses from data.
To sum up: is there any way to decide whether some address in .text segment contains data or instructions? Or maybe is there any way to decide which potential addresses in .rdata should be interpreted as instructions addresses and which as data?
You cannot, in general. The .text section of a PE file can mix up code and constants any way the author likes. Programs like IDA try to make sense of this by starting with the entrypoints and then disassembling, and seeing which addresses are targets of jumps, and which of reads. But devious programs can 'pun' between instructions and data.