Hi guys!
Thanks in part to Hugh's recent interrupt context-save fixes and in part to discovering my own dumb circuit mistake, I now have my multiple interrupts system running (see "Multiple Interrupts Problem" and "INT Interrupts Problems").
The next problem seems related to the previous, but in regards to the LCD. I'm using a 4-bit device with no R/W line connection. I had a problem with the device coming up blank after a CPU reset, but I fixed that by disabling interrupts until the initialization part of my code finished and back on just before entering the main loop. Now the LCD comes up, but about every other reset, it just spews out all display data on one long line, despite the proper use of LOCATEs. When it does come up properly, all works fine until the next CPU reset. If I turn off interrupts, the LCD seems to work properly.
My suspicion is that the interrupts are interfering with the LCD timing, but I can't prove it yet. I tried INTOFFs at various points in the application code, but nothing conclusive came of it.
Suggestions ?
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This is pretty normal behaviour for an HD44780 in 4 bit mode.
Normally, when first powered up the LCD will be in 8 bit mode. The PIC code will set the DB7:4 bits, then pulse Enable once. As long as the DB3:0 lines are tied down, the LCD will receive the byte b'xxxx0000', where xxxx is the DB7:4 bits. This will generally be the command to switch the LCD to 4 bit mode. Every transfer after this will involve the PIC setting DB7:4 to the contents of the first nibble of the byte it needs to send, then pulsing enable, then setting DB7:4 to the lower nibble of the byte, and pulsing Enable again.
If the LCD is not completely powered down, and is sent the initialisation codes again, it will become confused. It will interpret the command to change to 4 bit mode as being the high nibble of an initialisation command, and then the high nibble of the next byte as the low nibble of the initialisation command. It will then end up 4 bits out of step for every command it's sent.
If initialised a third time, the LCD will end up reading the initial 8 bit mode command as the low nibble of the previous byte, then will be back in step. GCBASIC will then send the clear screen command, and it will go back to normal.
The best solution to this is to make sure that the LCD is reset when the PIC resets, but if this is not possible you can probably get away with initialising the LCD a third time to return it to normal.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Notice those variable assignments up in the 430-450 range of bank 3. Now notice that the LCD display variables are in the range of about 55-63 in bank 0. These bank 0 variables would directly underlay the bank 3 variable addresses if the bank pointer were set wrong. Now look at the asm code for part of the LCD stuff:
ENDIF25
movlw 198
subwf DESIREDFREQ,W
movwf SysTemp1
movlw 47
btfss STATUS,C
addlw 1
subwf DESIREDFREQ_H,W
movwf SysTemp1_H
movwf SysCalcTempA_H
movf SysTemp1,W
movwf SysCalcTempA
movlw 82
movwf SysCalcTempB
movlw 6
movwf SysCalcTempB_H
call SysDivSub16
movf SysCalcTempA_H,W
movwf GPWORDVARIABLE2_H
movf SysCalcTempA,W
movwf GPWORDVARIABLE2
movlw 1
movwf LCDPUTLINE
movf GPWORDVARIABLE2,W
movwf LCDPUTCOLUMN
movlw 94
movwf LCDCHAR
call PUT
There are references to a bunch of variables located in bank 0, then some writes to the LCD variables which are located in bank, with no intervening "banksel" to point to bank3.
I think that the code is pointing to an address in bank 3 while the bank pointer is still pointing to bank 0, causing the LCD variables to get overwritten.
Comments?
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I may have mis-analyzed the presumed banksel problem above, but it sure seems more than coincidental that variables up in bank3 directly overlay the LCD variables down in bank 0 that would cause the problem I'm seeing.
BTW, the chip is a 16F877A @ 20MHz.
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The array and string variables that are placed at the end of the last bank are all quite large, so there's a good chance they'll overlap some variables in bank 0. Arrays and strings are generally dealt with using indirect addressing, which has a different bank select bit (STATUS.IRP) to the direct addressing used for normal variables (which uses STATUS.RP0 and STATUS.RP1 for bank select).
What causes the reset?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Sorry, I didn't see your post above before I made my log-winded post.
The PIC and the LCD are powered from the same supply, and the problem occurs even at power-on. I tried putting in extra INITLCD's, but that didn't seem to help either.
Joe
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi guys!
Thanks in part to Hugh's recent interrupt context-save fixes and in part to discovering my own dumb circuit mistake, I now have my multiple interrupts system running (see "Multiple Interrupts Problem" and "INT Interrupts Problems").
The next problem seems related to the previous, but in regards to the LCD. I'm using a 4-bit device with no R/W line connection. I had a problem with the device coming up blank after a CPU reset, but I fixed that by disabling interrupts until the initialization part of my code finished and back on just before entering the main loop. Now the LCD comes up, but about every other reset, it just spews out all display data on one long line, despite the proper use of LOCATEs. When it does come up properly, all works fine until the next CPU reset. If I turn off interrupts, the LCD seems to work properly.
My suspicion is that the interrupts are interfering with the LCD timing, but I can't prove it yet. I tried INTOFFs at various points in the application code, but nothing conclusive came of it.
Suggestions ?
Joe
This is pretty normal behaviour for an HD44780 in 4 bit mode.
Normally, when first powered up the LCD will be in 8 bit mode. The PIC code will set the DB7:4 bits, then pulse Enable once. As long as the DB3:0 lines are tied down, the LCD will receive the byte b'xxxx0000', where xxxx is the DB7:4 bits. This will generally be the command to switch the LCD to 4 bit mode. Every transfer after this will involve the PIC setting DB7:4 to the contents of the first nibble of the byte it needs to send, then pulsing enable, then setting DB7:4 to the lower nibble of the byte, and pulsing Enable again.
If the LCD is not completely powered down, and is sent the initialisation codes again, it will become confused. It will interpret the command to change to 4 bit mode as being the high nibble of an initialisation command, and then the high nibble of the next byte as the low nibble of the initialisation command. It will then end up 4 bits out of step for every command it's sent.
If initialised a third time, the LCD will end up reading the initial 8 bit mode command as the low nibble of the previous byte, then will be back in step. GCBASIC will then send the clear screen command, and it will go back to normal.
The best solution to this is to make sure that the LCD is reset when the PIC resets, but if this is not possible you can probably get away with initialising the LCD a third time to return it to normal.
I think I see what's causing this problem and it seems to be related to an invalid SFR bank pointer. First, look at the EQU table from the .asm file:
;Set aside memory locations for variables
DELAYTEMP EQU 112
DELAYTEMP2 EQU 113
SYSDIVLOOP EQU 116
SYSDIVMULTA EQU 119
SYSDIVMULTA_H EQU 120
SYSDIVMULTB EQU 123
SYSDIVMULTB_H EQU 124
SYSDIVMULTX EQU 114
SYSDIVMULTX_H EQU 115
SYSSTRINGLENGTH EQU 118
SysCalcTempA EQU 117
SysCalcTempA_H EQU 118
SysCalcTempB EQU 121
SysCalcTempB_H EQU 122
SysCalcTempX EQU 112
SysCalcTempX_H EQU 113
SysSTATUS EQU 127
SysStringA EQU 119
SysStringA_H EQU 120
SysStringB EQU 114
SysStringB_H EQU 115
SysW EQU 126
SysWaitTemp10US EQU 117
SysWaitTempMS EQU 114
SysWaitTempMS_H EQU 115
SysWaitTempS EQU 116
SysWaitTempUS EQU 117
SysWaitTempUS_H EQU 118
SYSSTRINGPARAM1 EQU 453
DIGITS EQU 443
DIGIT EQU 436
BINARYBYTES EQU 431
BWORD EQU 422
ADREADPORT EQU 32
CARRYBYTE EQU 33
COUNTERVALUE EQU 34
DELTA1 EQU 35
DELTA2 EQU 36
DESIREDFREQ EQU 37
DESIREDFREQ_H EQU 38
ENCODER EQU 40
FREQCOUNTER EQU 41
FREQCOUNTER_H EQU 42
FREQERROR EQU 43
FREQERROR_H EQU 44
FREQH EQU 45
GATECAL EQU 46
GPBYTE EQU 47
GPWORDVARIABLE1 EQU 48
GPWORDVARIABLE1_H EQU 49
GPWORDVARIABLE2 EQU 50
GPWORDVARIABLE2_H EQU 51
I EQU 52
J EQU 53
K EQU 54
LCDBYTE EQU 55
LCDCHAR EQU 56
LCDCOLUMN EQU 57
LCDLINE EQU 58
LCDPUTCOLUMN EQU 59
LCDPUTLINE EQU 60
LCDREADY EQU 61
LCDVALUE EQU 62
LCDVALUETEMP EQU 63
MODE EQU 64
NEWCOUNTAVAILABLE EQU 65
PORT EQU 66
PRINTLEN EQU 67
PRODUCT EQU 68
PRODUCT_H EQU 69
PULSECONSTANT1 EQU 71
PULSECONSTANT2 EQU 72
PULSEWIDTH EQU 73
PULSEWIDTH_H EQU 74
READAD10 EQU 75
READAD10_H EQU 76
STARTUPCOUNTER EQU 78
STARTUPFINISHED EQU 79
SYSBITVAR0 EQU 80
SYSPRINTTEMP EQU 81
StringPointer EQU 82
SysIFTemp EQU 83
SysIntOffCount EQU 84
SysPRINTDATAHandler EQU 85
SysPRINTDATAHandler_H EQU 86
SysTemp1 EQU 87
SysTemp1_H EQU 88
SysTemp2 EQU 89
T1H EQU 90
T1L EQU 91
TEMP EQU 92
TMR0OVERFLOWS EQU 93
TMR0PRES EQU 94
TMR0SOURCE EQU 95
TMR1OVERFLOWS EQU 96
TMR1PRES EQU 97
TMR1SOURCE EQU 98
TMR2PRES EQU 99
TMRNUMBER EQU 100
TUNINGVOLTS EQU 101
TUNINGVOLTS_H EQU 102
VOLTS EQU 103
VOLTS_H EQU 104
Notice those variable assignments up in the 430-450 range of bank 3. Now notice that the LCD display variables are in the range of about 55-63 in bank 0. These bank 0 variables would directly underlay the bank 3 variable addresses if the bank pointer were set wrong. Now look at the asm code for part of the LCD stuff:
ENDIF25
movlw 198
subwf DESIREDFREQ,W
movwf SysTemp1
movlw 47
btfss STATUS,C
addlw 1
subwf DESIREDFREQ_H,W
movwf SysTemp1_H
movwf SysCalcTempA_H
movf SysTemp1,W
movwf SysCalcTempA
movlw 82
movwf SysCalcTempB
movlw 6
movwf SysCalcTempB_H
call SysDivSub16
movf SysCalcTempA_H,W
movwf GPWORDVARIABLE2_H
movf SysCalcTempA,W
movwf GPWORDVARIABLE2
movlw 1
movwf LCDPUTLINE
movf GPWORDVARIABLE2,W
movwf LCDPUTCOLUMN
movlw 94
movwf LCDCHAR
call PUT
There are references to a bunch of variables located in bank 0, then some writes to the LCD variables which are located in bank, with no intervening "banksel" to point to bank3.
I think that the code is pointing to an address in bank 3 while the bank pointer is still pointing to bank 0, causing the LCD variables to get overwritten.
Comments?
Joe
I may have mis-analyzed the presumed banksel problem above, but it sure seems more than coincidental that variables up in bank3 directly overlay the LCD variables down in bank 0 that would cause the problem I'm seeing.
BTW, the chip is a 16F877A @ 20MHz.
Joe
The array and string variables that are placed at the end of the last bank are all quite large, so there's a good chance they'll overlap some variables in bank 0. Arrays and strings are generally dealt with using indirect addressing, which has a different bank select bit (STATUS.IRP) to the direct addressing used for normal variables (which uses STATUS.RP0 and STATUS.RP1 for bank select).
What causes the reset?
Hugh,
Sorry, I didn't see your post above before I made my log-winded post.
The PIC and the LCD are powered from the same supply, and the problem occurs even at power-on. I tried putting in extra INITLCD's, but that didn't seem to help either.
Joe